- 1 How to make a property or parameter optional?
- 2 How to make a property unique?
- 3 How to make a property be editable on creation but not updateable?
- 4 How to assign a default value to a property or parameter?
- 5 How to ensure an action is only executable in some circumstances?
- 6 How to ensure an action is only available in some states but not others?
- 7 How to make a property have its value computed based on another property?
- 8 How to prevent child objects from being added directly?
- 9 How to declare an entity as representing a user role in the system?
- 10 How to find the currently logged in user?
- 11 How to make an action only available to a specific role?
- 12 How to link two objects together?
- 13 Have your own how-to question?
How to make a property or parameter optional?
Specify a multiplicity with 0 as lower bound. In the example below, name is required but dateOfBirth is optional.
attribute name : String;
attribute dateOfBirth : Date[0,1];
end;
How to make a property unique?
Use the id modifier. That makes a property require unique values. Make sure to make it required as well or else the modifier is ignored.
id attribute email : String;
end;
How to make a property be editable on creation but not updateable?
Use the readonly modifier. In the example below, the user/client can set the date an issue was reported when the issue is initially created, but not afterwards.
readonly attribute reportedOn : Date;
end;
How to assign a default value to a property or parameter?
Use an initialization expression. In the example below, the severity and reportedOn properties have default values. Note that a default value for a property can be set as a simple literal value, or using a block, any kind of expression. Parameters currently only admit literals as initialization expressions.
attribute severity : Severity := Normal;
attribute reportedOn : Date := { Date#today() };
end;
How to ensure an action is only executable in some circumstances?
Use a precondition constraint. You can declare as many preconditions you want for an operation, and they all need to be satisfied for the operation to valid.
In the example below, a user/client can only reject an expense if the amount of the expense is higher than 50.
attribute amount : Double;
operation reject(reason : Memo);
precondition UnderAutoApprovalLimit { self.amount > 50 }
begin
...
end;
end;
How to ensure an action is only available in some states but not others?
Declare an action as triggering a state transition off some state. If an action appears as triggering a state transition, the only states it will be allowed are those with transitions having it as the trigger condition.
In the example below, review can only be invoked in the Submitted state, submit can only be invoked in the Draft state, etc.
class Expense
...
(* The current status of this expense. *)
attribute status : Status;
...
(*
The different statuses an expense can go through.
*)
statemachine Status
initial state Draft
(*
If amount is under automatic approval limit,
the expense is automaticaly approved.
*)
transition on call(submit) to Approved when {
self.automaticApproval
};
transition on call(submit) to Submitted when {
not self.automaticApproval
};
end;
state Submitted
transition on call(approve) to Approved;
transition on call(review) to Draft;
transition on call(reject) to Rejected;
end;
state Approved
entry {
self.processed := Date#today();
self.reportApproved();
};
end;
state Rejected
entry {
self.rejections := self.rejections + 1;
self.processed := Date#today();
};
transition on call(reconsider) to Submitted do {
self.rejectionReason := null;
};
end;
end;
...
end;
How to make a property have its value computed based on another property?
You use derived properties. Derived properties are not modifiable by users/clients and are defined via a function that produces a value in terms of other properties. Derived properties are not stored in the database.
The example shows a property isAvailable is defined in terms of the assignee relationship. If an assignee does not exist, the issue is available.
attribute assignee : User[0,1];
derived attribute isAvailable : Boolean := { self.assignee == null };
...
end;
How to prevent child objects from being added directly?
You can prevent create/delete behavior on related collection of objects by marking a collection as readonly. In the example, comments cannot be directly added/removed from an issue. That is handy when you want addition of related objects to be through an action.
readonly attribute comments : Comment[*];
/* This action is the only way to add comments */
operation comment(text : Memo);
begin
var comment : Comment;
comment := new Comment;
comment.commented := text;
link IssueComments(issue := self, comments := comment);
end;
end;
How to declare an entity as representing a user role in the system?
Apply the role class modifier.
attribute name : String;
end;
You can have multiple User entities in an application, and then establish different permissions for each role.
How to find the currently logged in user?
Invoke System#user(). Example:
operation addComment(text : Memo);
begin
var comment : Comment;
comment := new Comment;
comment.user := System#user() as User;
end;
end;
The cast is required as System#user() has no type.
How to make an action only available to a specific role?
Declare an access constraint based on the role of the logged in user. In the example below, there are two kinds of users. Only company personnel can complete an order.
attribute name : String;
end;
role class Customer
attribute name : String;
end;
class Order
operation complete()
allow Personnel call;
begin
/* order completion behavior */
end;
end;
The System#user() call returns the logged in user.
How to link two objects together?
Declare an association between the entities:
navigable role watchers : User[*];
navigable role issuesWatched : Issue[*];
end;
then establish the relationship using the link command:
operation addWatcher(userToAdd : User);
begin
link WatchedIssues (issuesWatched := self, watchers := userToAdd);
end;
end;
Tip: you can use the unlink command to break a relationship.
Have your own how-to question?
We will be glad to answer it. Tweet to @abstratt. See also the REST API and SimpleUI how-tos.