#+TITLE: Apparts-Model
#+DATE: [2020-08-06 Thu]
#+AUTHOR: Philipp Uhl
Create model classes like this:
#+BEGIN_SRC js
import { useModel, BaseModel, ConstructorParams } from "@apparts/model";
import * as types from "@apparts/types";
const modelSchema = types.obj({
id: types
/* Types as defined by @apparts/types /
.id()
/ Auto increment this field /
.auto()
/ Will be shown in output of getPublic*/
.public()
/* This is a key. Combined keys are possible, too, by calling
key() on multiple fields. /
.key(),
optionalVal: types.string()
/ This field can be undefined /
.optional(),
derivedValue: types.string().public()
/ This field will not be persisted. It's value is derived from
other values and will be generated on the fly. When using the
getPublic method, while having derived values, you must first
call generateDerived. For fields with derived you must call the
derive method within the constructor of the model to specify
how the values are derived. /
.derived(),
createdOn: types.time().public()
/ This field will be set to the functions result, if the field is
NULL. The function recieves the element as parameter. /
.default((c) => c.optionalVal || Date.now()),
fixedDefault: types.int().public(),
.default(7)
/ This field will be set to the given value, if the field is
NULL. /
.mapped("someNumber"),
/ This field will be named "someNumber" in the output of
getPublic */
});
export class User extends BaseModel {
// Constructor not always needed. In this case we have to define the
// derived functions, though
constructor(...args: ConstructorParams<typeof derivedType>) {
super(...args);
this.derived({
derivedValue: async (c) => {
/* c is the content of the model */
return (await this._dbs._getSomeRelation()).text;
}
});
}
}
// Activate the model:
useModel(
User,
// The name of the collection in the database
"user",
// The schema of the model
modelSchema
);
#+END_SRC
The extended classes can then be used:
#+BEGIN_SRC js
// get dbs from "@apparts/db" somehow
const peter = await new User(dbs, [{ optionalVal: "Peter"}]).store();
console.log(peter.content);
// => { id: 1, optionalVal: "Peter", createdOn: 12345, fixedDefault: 7 }
#+END_SRC
** Model functions
Values:
content :: Object, that contains the values. The values can be edited. To
save the changes, call update. Can only be used if =loadOne= is used
or the constructor was called with an array of length 1.
contents :: Array, that contains the values. The values can be edited. To
save the changes, call update.
Functions:
constructor(dbs, ?[contents]) :: Constructor
async load(filter, ?limit, ?offset, ?order) :: Load data, filter grammar
is as defined by the =find= function of the =dbs=. For more information,
see below at in the section "Filter Grammar".
async loadOne(filter, ?limit, ?offset, ?order) :: Load data, filter
grammar is as defined by the =find= function of the =dbs=. For more
information, see below at in the section "Filter Grammar". Throws
=NotUnique= if more than one object was found or =NotFound= exceptions
if no object was found.
async loadNone(filter) :: Throws an DoesExist error, if something was
loaded, does nothing if nothing was loaded. The filter grammar
is as defined by the =find= function of the =dbs=. For more information,
see below at in the section "Filter Grammar".
async loadByKeys(ids, ?limit, ?offset) :: Load data by IDs. For models with
only one key, you can use [, , ...], for a model with
multiple keys, you have to use { : [ , ...], :
[, ...], ...}.
async store() :: Saves to the database
async update() :: Updates the values, if you updated the contents.
async updateWithConcurrencyCheckOn(unchanged: string[]) :: Updates
the values, if you updated the contents and if the contents of the
fields, specified as a list of keys in =unchanged= are the same in the
database since loading the model. If the content is different a
=ConcurrencyError= is thrown.
length() :: Length of contents
set(field, val) :: Set a field on all elements
setF(field, f) :: Set a field on all elements through a function,
that receives the element and returns the new value
async deleteAll() :: Delete all from the loaded collection from the
database. If any of the items is referenced by another item,
=IsReference= will be thrown.
getPublic() :: Get the public representation (marked as public in
the types definition by the key public (bool)). If there are derived
values in the type, =generateDerived= must be called first!
- =async generateDerived()= :: Generate derived values. The derived
values will be saved in =_derived=. This function must be called
before =getPublic= is called, if derived values exist in the type.
- =static getTypes()= :: Returns the type of the model
- =derived(derivedFunctions)= :: Specifies how derived fields are
calculated. The parameter is an object where each key is the key of
a derived field, the value is a function that accepts the model
content and returns the derived value.
** Errors
DoesExist
NotFound
NotUnique
- =IsReference=
- =ConstraintFailed=
- =ConcurrencyError=
#+BEGIN_SRC js
import {
NotUnique,
NotFound,
DoesExist,
IsReference,
ConstraintFailed,
ConcurrencyError
} from "@apparts/model";
#+END_SRC
** Filter Grammar
The filter syntax is like this:
#+BEGIN_SRC js
const filter = { : , ...};
// where is a key from the type and
// where matcher is
=
| { op: , val: }
| { op: , val: }
| { op: "and", val: } // logical and for all subconditions
= lte // less than or equals
| lt // less than
| gte // greater than or equals
| gt // greater than
= like // sql like, a string comparison where the "%" character
// will be matched against anything. E.g. "bread%crumb"
// matches "bread crumb" or "bread eating crumb".
=
|
|
| null
#+END_SRC