Creating a Sealious application consists mainly of composing various declarations and letting Sealious take care of interactions between each one of them. Below are listed and describe all the declaration syntaxes you need to know in order to be a productive Selious developer.
Note: we'll be using the jsig notation for describing the various syntaxes.
type AcceptCallback: () => void;
type RejectCallback: (errorMessage: String) => void;
type Params: Object<String, Any>;
-
Syntax
type FieldType: { name?: String, is_proper_value: ( context: Context, params: Params, new_value: Any, old_value?: Any ) => Promise, encode?: ( context: Context, params: Params, value_in_code: Any ) => Promise<encoded_value: Any> & Any, decode?: ( context: Context, params: Params, value_in_db: Any ) => Promise<decoded_value: Any> & Any, extends?: FieldType, has_index?: (params: Any) => false | index_type: String | Promise<false | index_type: String> format?: ( context: Context, params: Any, decoded_value: Any, format: String ) => formatted_value: Any | Promise<formatted_value: Any> } | FieldTypeName
-
Explanation
You can notice that there are two possible syntaxes (separated above with a
|
character). When creating a new FieldType, one has to describe it's behavior with the former notation. When only referencing an already described FieldType, one can use it's unique name.name
: optional. The name of the FieldType. Please note that this is the name of the type of a field, not a name of a field. Has to be unique amongst all other registred FieldTypes. When provided, the FieldType created by this declaration can be referenced withFieldTypeName
.is_proper_value
: a function that takes a value (new_value
) and decides whether that value is accepted. Can takeold_value
into consideration.params
are parameters for the particular field that uses this field type. Shouldreturn Promise.resolve()
to accept, andreturn Promise.reject("Reason")
to reject.encode
: optional. Takes the value for a field from client's input and transforms it into something else. The result of calling that function for the client's input is what will be stored in the database.decode
: optional. A function reverse toencode
. If declared, the value in the database will be run through that function before being returned to the client.extends
: optional. Must be a properFieldType
declaration. When specified, the field-type being declared will inherit behavior from the type it is extending. All specified methods will obscure the parent's methods. The unspecified will be inherited.has_index
: optional. Whether or not to instruct the Datastore to create an index on that field. In order to include the contents of the fields of this type in full-text-search, return "text" here.format
: optional. The user viewing a resource or a list of resources might specify a string for each of the fields in a collection that tells Sealious how the user wants the values to be displayed. That string is then passed to theformat
method of a given field type, if it exists. The method will be given the current context and the decoded value of the field. The method is supposed to format thedecoded_value
according to the specifiedformat
.
-
Usage
To create a new FieldType instance, call the
Sealious.FieldType
constructor.var my_field_type = new Sealious.FieldType({ name: "text", //... });
-
Example
```javascript var Sealious = require("sealious"); var Promise = require("bluebird"); var Color = require("color");var field_type_color = new Sealious.FieldType({ name: "color", is_proper_value: function(context, params, new_value){ try { if (typeof (new_value) === "string"){ Color(new_value.toLowerCase()); } else { Color(new_value); } } catch (e){ return Promise.reject("Value
" + new_value + "
could not be parsed as a color."); } return Promise.resolve(); }, encode: function(context, params, value_in_code){ var color = Color(value_in_code); return color.hexString(); } });</div>
Fields are the most important part of a Collection. They describe it's behavior and structure.
-
Syntax
-
Explanation
type
: required. A FieldType declaration. It's more comfortable to use the "short" FieldType notation here (that is: just entering the name of the registered FieldType).name
: the name of the field. Has to be unique within the Collection.required
: optional. Defaults tofalse
. If set totrue
, Sealious won't allow modifications of the resource that would result in removing a value from that field.params
: optional. A set of parameters that configure the behavior of the FieldType for that particular field.
-
Usage
Use it when describing a Collection.
-
Example
{"name": "full-name", "type": "text", "required": true}
AccessStrategyType describes a type of an access strategy that can be parametrized, instantiated, and, for example, assigned to a Collection.
-
Syntax
type AccessStrategyType: { name?: String, checker_function: ( context: Context, params: Params, item?: Any ) => Promise | Boolean, item_sensitive?: Boolean | (params: Any) => (Boolean | Promise) } | AccessStrategyName
-
Explanation
name
: optional. If specified, the AccessStrategyType will be registered and will be accessible by it's name. Useful when the type is used many times.checker_function
: required. Takes acontext
,params
, and decides whether or not to allow access. If access is denied, the function should returnPromise.reject("reason")
. The function can also returntrue
andfalse
to accept and deny access, respectively. If the access strategy is defined asitem_sensitive
, it will receive a third parameter - an object representing the item to which access is being decided.item_sensitive
: optional. Default tofalse
. If set totrue
(or a resolving function, or a function that returnstrue
), thechecker_function
will be provided with the item to which access is decided by the access strategy of this type. Loading the item data might by costly - that's why by default thechecker_function
will not receive it as argument.
-
Usage
To create a new AccessStrategyType, call the AccessStrategyType constructor:
var new_access_str_type = new Sealious.AccessStrategyType({ name: "only_on_tuesdays", //... });
-
Examples
-
declaring a new Access Strategy Type
{ name: "only_on_tuesdays", checker_function: function(context, params, item){ var d = new Date(context.timestamp); var wd = d.getDay(); if(wd == 2){ return Promise.resolve(); }else{ return Promise.reject("Come back on a Tuesday!"); } } }
-
pointing at an already existing Strategy Type
"only_on_tuesdays"
-
-
Syntax
type AccessStrategy: AccessStrategyType | [type: AccessStrategyType, params:Any]
-
Explanation
If the shorter notation is used (
AccessStrategyType
), you cannot specify any parameters to the AccessStrategyType assigned to that particular Access strategy. If you need to customize the behavior of the AccessStrategyType for that particular AccessStrategy, you have to use the longer syntax ([type: AccessStrategyType, params:Any]
). -
Usage
Currently this declaration is only being used when describing access strategies to resource actions in Collection declaration.
-
Examples
"only_on_tuesdays"
"logged_in"
["and", ["only_on_tuesdays", "logged_in"]]
-
Syntax
``` type ResourceActionName: "default" | "create" | "retrieve" | "update" | "delete" ``` -
Usage
It does not have it's own constructor, as it doesn't do anything by itself. It can be used when describing access strategies in Collection declaration.
-
Syntax
type Collection: { name: String, fields: Array<Field>, access_strategy: AccessStrategy | Object<ResourceActionName, AccessStrategy> }
-
Explanation
name
: required. The name of the resource-type.fields
: required. An array of Fields declarations.access_strategy
: required. Describes what access strategies will be used for granting access to calling various resource actions. When a single AccessStrategy is specified, it will be used for all of the actions. If theObject<ResourceActionName, AccessStrategy>
notation is being used, then each action can have a different access_strategy assigned. If an action does not have an AccessStrategy assigned, it will use thedefault
one.
-
Usage
To create a new Collection, call the
Collection
constructor:var Person = new Sealious.Collection({ name: "person", fields: //... });
-
Examples
{ name: "person", fields: [ {name: "full-name", type: "text", required: true}, {name: "age", type: "int"} ], access_strategy: { default: "owner", view: "public", create: "logged_in" } }