Skip to content
Wyatt Greenway edited this page Nov 24, 2022 · 49 revisions

class Model

The base Model class for Mythix ORM. Every Mythix ORM model should inherit from this class. This class provides support for all model operations in Mythix ORM. 📜


Notes:

  • Many model methods have both static and instance methods of the same name that do the same thing. This is because it is common to access Model methods directly on the model class as well as an instance. For example, Model.static getModelName is both a static method, and an instance method. Nearly all the methods listed here have both a static and and instance version. We are only listing the static versions because the instance versions generally will just be proxies to these static methods.
  • An underscore prefix on a method in Mythix ORM implies that this method should not be overloaded unless you know exactly what you are doing. It also implies that there is another method that can and should be overloaded instead.

static property Model::_isMythixModel: boolean 📜

This property assists with type checking.


method Model::_castFieldValue(field: Field, value: any): any 📜

This casts a field value to its type, by calling the field's field.type.castValue method for the type.

Arguments:

  • field: Field

    The field to use to cast the value. The type property on the field will be accessed, and the type properties castValue method will be called on the provided value argument.

  • value: any

    The value to cast to the field's type. null is a valid value, and all castValue methods on types should properly handle it.

Return value: any

The value provided, cast to the type of the field.


method Model::_constructField(fieldName, field) 📜

This method simply creates the getters/setters for fields as described by Model._constructFields.

Arguments:

  • fieldName
  • field

method Model::_constructFields() 📜

Construct the model's fields on the model instance. This method will iterate the static Model.fields fields for the model. For each field (except virtual fields), it will call field.type.exposeToModel(). If this method returns true, then the field will be added as a getter/setter to the model instance, with the name defined as the field's fieldName. For example, if a User model had a field named fieldName: 'firstName', then the firstName property will be added to the model instance, as a getter/setter property on the instance. The getter/ setter provide the functionality of sending data in and out of get and set methods on the field itself, and through each field.type.castValue method on set. The setter will also mark a field as dirty if it is set to a value that is different from the current value of the field. The Model.getDataValue and Model.setDataValue instance methods will bypass the getter/setter of each field, allowing direct access to the underlying attribute value.


method Model::_constructor(data?: object): undefined 📜

This is the final call the constructor makes before it finalizes instantiating the model. It calls Model._constructFields to construct the model's fields, and then it calls Model._initializeModelData to initialize the field values for the model.

Arguments:

  • data?: object

    Attributes provided to the model through the constructor call.

Return value: undefined


method Model::_getConnection(connection?: Connection): Connection 📜

See Model.static _getConnection

Notes:

  • Pay attention that unlike Model.static _getConnection this checks the model's instance for ._connection property. If that is a valid connection, then it will be returned before the bound connection. This is helpful when you have chosen not to bind a connection to your models. This will allow you to provide a connection directly when you create the model, which can make interacting with the model less tiresome. i.e. new Model(null, { connection }).

Arguments:

  • connection?: Connection

    An optional connection that can be provided. If provided, it will simply be returned. Otherwise, if not provided, or a falsy value, then attempt to fallback to modelInstance._connection, if that also fails to find a connection, the finally the method will call Model.static _getConnection to get the bound connection, if any is available.

Return value: Connection


method Model::_getDirtyFields(options?: DirtyFieldOptions): DirtyFieldChangeList 📜

Get the dirty fields of the model instance. The model instance property Model.changes calls this method to get the list of dirty fields for the model instance. Unlike Model.changes, which is a getter, you can pass options to this method, which can change its behavior.

If this method is provided a Connection via the connection options value, then it will assume it is being used in a connection method to fetch the dirty fields for a database operation (update, or insert). If it has a Connection then it will behave a little differently.

The first difference is that if a model field is not marked as dirty, then it will be passed through Connection.dirtyFieldHelper. If this method returns any value other than undefined, then that value will be used as the "dirty" value for the field, and the field will be marked as dirty. This can be used when you want the connection itself to control the dirty state of a field. This is what is done with SQLite BigInt AUTOINCREMENT emulation. Any time an autoincrementing BigInt is being stored to a SQLite database with the emulateBigIntAutoIncrement option enabled, an internal counter for this field is incremented, and the field is automatically updated as "dirty" (on insert only, if the field has and undefined value).

The next difference when using a connection in this method is that it will check if this is an "update" or an "insert" operation by checking the update and insert "option" keys respectively. If one of these is true, then it will invoke defaultValue property on the field, if said defaultValue has the onUpdate, or onInsert flags set to true. This can be used for example on created_at, and updated_at fields, which will only be marked dirty and given a value on an insert or update operation through the connection.

Without a connection provided to this method, it will simply return the "change list" of all dirty fields on the model. The "change list" is an object, where each key is the name of the field, and each value is another object, with previous and current keys describe the change that took place to the field. For example:

DirtyFieldChangeList = {
  firstName: {
    previous: undefined,
    current: 'Bob',
  },
}

If no fields on the model are dirty, then an empty object will be returned. A field is considered "dirty" if its value is different from what it was when the model was first instantiated, or since the last time the Model.clearDirty method was called.

The options argument has the following shape:

Interface:

  • interface DirtyFieldOptions {
      connection: Connection; // The connection for this operation.
      update: boolean;        // If `true`, then this is an update operation.
      insert: boolean;        // If `true`, then this is an insert operation.
      // ... any options you wish to pass to `connection.dirtyFieldHelper`
    }

Notes:

  • If this is an "update" or "insert" operation, as defined by the update or insert "options", then the default value for the field will be fetched via the QueryGenerator.getFieldDefaultValue method through the provided connection.

Arguments:

  • options?: DirtyFieldOptions

    Options to provide to the method.

Return value: DirtyFieldChangeList


method Model::_getFieldValue(fieldName: string, field: Field): any 📜

Get a field's value. Calling this is no different from accessing the field directly on the model instance itself. For example, userInstance.firstName is identical to calling userInstance._getFieldValue('firstName', User.fields.firstName).

This will call the get method defined on the field, if any is defined. If a get method is defined, then whatever value it returns will be the result of this method. If no get method is defined on the field, then this.getDataValue(fieldName) is called instead, and will provide the resulting return value for this method.

Notes:

  • Never call this method (or the model attribute by name), while inside a field's get method. If you do, you will enter an infinite recursive loop. Instead, call the provided get method (as provided by the context), or call Model.getDataValue.

Arguments:

  • fieldName: string

    The name of the field whose value we wish to get.

  • field: Field

    The field definition itself for the value we wish to get.

Return value: any

See also: Field


method Model::_initializeFieldData(fieldName: string, field: Field, fieldValue: any, data: object) 📜

Set each field's initial value. Each field's value will first be fetched from the data argument given to the constructor--if any was given. After all field attributes have been set this way, then this method is called, being provided that value (if any) via the fieldValue argument. If fieldValue is undefined, then call the defaultValue property of the field to get the field's initial value.

Arguments:

  • fieldName: string

    The name of the field we are initializing.

  • field: Field

    The field definition itself for the field we are initializing.

  • fieldValue: any

    The field value as provided by the data argument to the model constructor, if any was provided.

  • data: object

    The data argument, as provided to the constructor of the model.


method Model::_initializeModelData(data?: object) 📜

Initialize the field value for each field/attribute. If no data argument is passed to the constructor, then each field will be initialized to its default value, as defined by the defaultValue property on each field. A null value is a valid value, and though it will still be piped through each field's field.type.castValue method, it will discount the need to call defaultValue on the field. This method calls Model._initializeFieldData to actually set the value of each field. Field values are set from the provided data object to the constructor first, for all fields, before any defaultValue calls for any fields are attempted.

Notes:

  • All fields have already been constructed before this method is called via Model._constructFields.
  • Virtual fields are not constructed against the model instance, however, field types can modify the instance, and some do. For example, the Types.Model and Types.Models virtual field types inject relational methods on the model.
  • Only concrete fields are considered "attributes" of the model, and can have an initial value provided via the data argument to the constructor, or via a defaultValue property on the field.

Arguments:

  • data?: object

    Attributes values for fields. Can be nothing, in which case the defaultValue property for each field will be used instead. null is a valid value, and if an attribute has a null value, it will not be given a default value from defaultValue.


method Model::_setFieldValue(fieldName: string, field: Field): undefined 📜

Set a field's value. Calling this is no different from setting the field directly on the model instance itself. For example, userInstance.firstName = 'Bob' is identical to calling userInstance._setFieldValue('firstName', User.fields.firstName, 'Bob').

This will call the set method defined on the field, if any is defined. If a set method is defined, then it is entirely up to the set method to call this.setDataValue to set the field's value. If no set method is defined on the field, then this.setDataValue(fieldName, value) is called instead, and will set the value on the field.

Notes:

  • This method will mark the field as dirty if the value provided differs from the current value the field has.
  • Never call this method (or set the model attribute by name), while inside a field's set method. If you do, you will enter an infinite recursive loop. Instead, call the provided set method (as provided by the context), or call Model.setDataValue.

Arguments:

  • fieldName: string

    The name of the field whose value we wish to get.

  • field: Field

    The field definition itself for the value we wish to get.

Return value: undefined

See also: Field


method Model::clearDirty(fieldName?: string): boolean 📜

Clear the dirty state of the model, or of a single field. If a fieldName argument is provided, then only the specified field's "dirty" status will be cleared. If no fieldName argument is provided, then all field's on the model will have their "dirty" status cleared, and the model will no longer be "dirty".

The "dirty" status of a field is cleared by 1) setting the real underlying field value (this._fieldData) to the dirty field value, and 2) removing the entry in this._dirtyFieldData on the model for the field.

Arguments:

  • fieldName?: string

    If specified, clear only this field's "dirty" status. If not specified, clear all fields on the model, making the entire model no longer dirty.

Return value: boolean


method Model::constructor(data?: object, options?: object): Model 📜

Construct a new Model instance.

Arguments:

  • data?: object

    Attributes to provide to the new model instance. The key names should be a fieldName, not a columnName. Any model attribute missing from data, or whose value is undefined, will be given a default value from the defaultValue, field property for the field. If the defaultValue for the field is marked as a "remote" value (a value provided by the database) or if defaultValue is not marked with the flag FLAG_ON_INITIALIZE, then the field will remain with a value of undefined, at least until the model is stored to the database. The default for all methods provided to the defaultValue key of the field is to have the FLAG_ON_INITIALIZE flag, so the value will be created on model instantiation. Some default value methods however, such as AUTOINCREMENT, do not have the FLAG_ON_INITIALIZE set, because the defaultValue is provided by the database. null is a valid value, and if provided for an attribute, then the defaultValue will not be used. Any attribute value provided will go through field.type.castValue from the field type property (this includes null values). Any attributes provided will immediately be marked as "dirty" as soon as the model is instantiated.

  • options?: object

    Options for the model. The only property Mythix ORM will use is the connection key. If provided, it will set this as the _connection property on the instance. Otherwise, these options are intended to be used by you, the developer, to do with as you please on your models. They can be fetched from any model instance simply by calling Model.getOptions.

Return value: Model


method Model::destroy(options?: object): number 📜

Destroy this model instance.

Calling this method will destroy this model from the database. If the model is not persisted, then nothing will happen, and 0 will be returned. If the model is persisted, the result of Connection.destroy is returned, which is the number of rows modified in the database, which in this case should always be 1.

If the model has no primary key field defined, then an exception will be thrown.

Notes:

  • A primary key is required on the model for this method to work. If you don't have a primary key defined, then you will need to create your own "destroy" operation.

Arguments:

  • options?: object

    Options to pass to the underlying QueryEngine.destroy call. If a connection property is present on this options object, then it will be used as the connection for this operation.

Return value: number

The number of rows modified in the database.


method Model::getAttributes(): object 📜

Get all the models current raw attributes. This will return an object, where each key is the fieldName of each non-virtual (concrete) field on the model, and each value is the "current" value of the field on the model. The "current" value for each field could either be a dirty field value, or a clean (or raw) field value.

This method is nearly identical to Model.toJSON except that Model.toJSON always adds the primary key to the result first, which only matters for JavaScript engines that honor the insertion order of keys in native Objects, which is never guaranteed. Model.toJSON also differs from this method by calling field.type.serialize for every attribute on the model.

Notes:

  • Field's with undefined values will not be included in the resulting object.

Return value: object

All models attributes (field values).


method Model::getConnection(connection?: Connection): Connection 📜

Get the underlying connection bound to the model's class. Connection binding is optional, so this method can also be provided a connection. If a connection is provided, then it will simply be returned. Because Mythix ORM has no globals, this is a design pattern to supply a connection if you have one available, or fallback to a "bound" connection (if one can be found). This method should be overloaded if you wish to provide your own model specific connection.

This method will also search for a modelInstance.connection, and return that connection if found.

Notes:

  • static getConnection is simply a proxy for static _getConnection, whereas this instance method will also attempt to find a connection on the model instance itself.

Arguments:

  • connection?: Connection

    An optional connection that can be provided. If provided, it will simply be returned. Otherwise, if not provided, or a falsy value, then attempt to fallback to the bound connection, if any is available.

Return value: Connection


method Model::getDataValue(fieldName: string): any 📜

Get the current value of any field on the model. The "current" value will be the dirty value if the field is dirty, or it will be the clean value of the field if the field isn't dirty.

This method is a "raw" get of the field's value in that it won't call get on the field descriptor, if any is defined. Instead it will first attempt to fetch the current value of the field from this._dirtyFieldData, if there is an entry for the field in the this._dirtyFieldData property of the model instance. If there is no "dirty" entry for the field, then its "clean value" (or raw value) will be fetched from the underlying this._fieldData storage area for field values.

Arguments:

  • fieldName: string

    The name of the field whose value you wish to fetch.

Return value: any


method Model::getDirtyFields(options?: object): Array<Field> 📜

Get the dirty field descriptors themselves for all fields that are dirty.

Whereas Model._getDirtyFields returns a "change list" of dirty fields, this method will return the field descriptors themselves. An array of Field will be returned for each dirty field, or an empty array if no fields are dirty.

Arguments:

Return value: Array<Field>

The dirty fields of the model.


method Model::getOptions(): object 📜

Get the options provided to the model, if any. This will always return an object, even if no options were provided, in which case the object will simply be an empty object.

Return value: object

Options object provided by the user to the model when the model was constructed.


method Model::hasValidPrimaryKey(): boolean 📜

Checks if the primary key's value is valid. Validity checks are handled by the field's type. When this method is called, the primary key field for the model is fetched, and if found, the field.type.isValidValue method will be called and provided with the current value of the primary key field.

Type.isValidValue is commonly implemented to be a strict check against the type. null will generally return false for an isValidValue call, however implementation details are entirely left up to the isValidValue method defined on the type.

Return value: boolean


method Model::isDirty(fieldName?: string): boolean 📜

Check if the model is dirty or not. If a fieldName is provided as an argument, it will only check if the specified field is dirty or not. If not provided, then the entire model will be considered "dirty" if one or more fields are marked as "dirty".

Arguments:

  • fieldName?: string

    If provided, check if this one field is dirty. If not provided, then check if any field on the model is dirty.

Return value: boolean


method Model::isPersisted(): boolean 📜

Check if the model is persisted or not. This has nothing to do with the model's "dirty" state. if the model is dirty, then this will still report true if the model was initially loaded from the database.

Return value: boolean

true if the model was loaded from the database, false otherwise.


method Model::onAfterCreate(context: object) 📜

After insert model hook.

This method will be called on each model instance after it has been inserted into the database. This method is called after each model instance has been fully stored, marked as persisted, and marked as not dirty. If you set any model fields in this method, then the model will be marked as dirty, and will be re-saved at the end of the insert operation.

Notes:

  • Use care when updating model attributes in this method. At the end of each insert operation, the models just stored are scanned to see if any of them are dirty. If they are dirty they will be re-stored to the database using an update operation. This can happen for example if foreign keys are in use. We might not be able to update a foreign key field value until after the insert operation is completed. When a foreign key value is updated post-insert, then the model might again become dirty, and be updated post-insert. Because of this, you should be careful about making your model dirty in any "after" hooks, as you might unintentionally incur the cost of a post-insert update.

Arguments:

  • context: object

    A context object that is provided to all model hooks. The shape of this object is { connection, Model, options }. It will contain the current connection for the operation (which might be a transaction connection), the Model for the operation, which is the "root model" of the operation, not necessarily "this" model (the model whose hook is being called), and the "options" defined for the current operation.


method Model::onAfterSave(context: object) 📜

After insert or update model hook.

This method will be called on each model instance after it has been inserted or updated in the database. This method is called after each model instance has been fully stored, marked as persisted, and marked as not dirty. If this is an insert operation, and if you set any model fields in this method, then the model will be marked as dirty, and will be re-saved at the end of the insert operation.

Notes:

  • Use care when updating model attributes in this method. At the end of each insert operation, the models just stored are scanned to see if any of them are dirty. If they are dirty they will be re-stored to the database using an update operation. This can happen for example if foreign keys are in use. We might not be able to update a foreign key field value until after the insert operation is completed. When a foreign key value is updated post-insert, then the model might again become dirty, and be updated post-insert. Because of this, you should be careful about making your model dirty in any "after" hooks, as you might unintentionally incur the cost of a post-insert update.

Arguments:

  • context: object

    A context object that is provided to all model hooks. The shape of this object is { connection, Model, options }. It will contain the current connection for the operation (which might be a transaction connection), the Model for the operation, which is the "root model" of the operation, not necessarily "this" model (the model whose hook is being called), and the "options" defined for the current operation.


method Model::onAfterUpdate(context: object) 📜

After update model hook.

This method will be called on each model instance after it has been update in the database. This method is called after each model instance has been fully stored, marked as persisted, and marked as not dirty. Unlike an insert operation, update operations do not have a post-operation dirty model scan and re-update. You can safely update model attributes in this method without the worry of incurring the cost of an extra store operation. However, if you do set model attributes in this method, then the model will be marked dirty when the update operation is complete.

Arguments:

  • context: object

    A context object that is provided to all model hooks. The shape of this object is { connection, Model, options }. It will contain the current connection for the operation (which might be a transaction connection), the Model for the operation, which is the "root model" of the operation, not necessarily "this" model (the model whose hook is being called), and the "options" defined for the current operation.


method Model::onBeforeCreate(context: object) 📜

Before insert model hook.

This method will be called on each model instance before it is inserted into the database. This method is called before dirty fields are calculated for the insert operation, so you can set field values here before insert, and they will be captured and inserted into the database.

Arguments:

  • context: object

    A context object that is provided to all model hooks. The shape of this object is { connection, Model, options }. It will contain the current connection for the operation (which might be a transaction connection), the Model for the operation, which is the "root model" of the operation, not necessarily "this" model (the model whose hook is being called), and the "options" defined for the current operation.


method Model::onBeforeSave(context: object) 📜

Before save model hook.

This method will be called on each model instance before it is inserted or updated in the database. This method is called before dirty fields are calculated for the insert or update operation, so you can set field values here before update, and they will be captured and updated in the database.

Notes:

  • This is the final hook call before the insert or update operation sends your data off to the database.

Arguments:

  • context: object

    A context object that is provided to all model hooks. The shape of this object is { connection, Model, options }. It will contain the current connection for the operation (which might be a transaction connection), the Model for the operation, which is the "root model" of the operation, not necessarily "this" model (the model whose hook is being called), and the "options" defined for the current operation.


method Model::onBeforeUpdate(context: object) 📜

Before update model hook.

This method will be called on each model instance before it is updated in the database. This method is called before dirty fields are calculated for the update operation, so you can set field values here before update, and they will be captured and updated in the database.

Arguments:

  • context: object

    A context object that is provided to all model hooks. The shape of this object is { connection, Model, options }. It will contain the current connection for the operation (which might be a transaction connection), the Model for the operation, which is the "root model" of the operation, not necessarily "this" model (the model whose hook is being called), and the "options" defined for the current operation.


method Model::onValidate(context: object): Array<any> 📜

Validate all concrete fields on the model. This method is called before any "insert" or "update" operation happens for the model. It will iterate all the fields of the model, and call the validate method defined on each field descriptor (Field), if any is defined. Each validate method is asynchronous, so all promises will be collected from all validate method calls, and will be awaited upon via await Promise.all(validatePromises);.

Model validation will fail if any validate method throws an exception.

onValidate is called directly from Model.onBeforeSave, so make certain you call super.onBeforeSave(...args) if you overload onBeforeSave. If you don't, your validation hooks won't be called. This design was deliberate, so the developer could choose to bypass model validation on purpose simply by not calling super.onBeforeSave(...args) should they choose not to.

Feel free to overload onValidate to provide your own implementation.

Notes:

  • validate properties on fields must always be methods. Unlike other ORMs, we don't allow a pattern, a RegExp, or anything else. You must provide the implementation of each validate method directly yourself (which could for example use a RegExp to check the field's value).

Arguments:

  • context: object

    A context object that is provided to all model hooks. The shape of this object is { connection, Model, options }. It will contain the current connection for the operation (which might be a transaction connection), the Model for the operation, which is the "root model" of the operation, not necessarily "this" model (the model whose hook is being called), and the "options" defined for the current operation.

Return value: Array<any>

Results of each validate call from each field. Will generally be undefined for each call. The validation for a field will only fail if an exception is thrown. false or null as a return value from a validate call is meaningless (unless you yourself wish to do something with it).


method Model::reload(options?: object): undefined 📜

Reload the model in-place.

This method will create a query selecting this model from the database by its primary key. It will then take the columns from the select operation, and will apply the values to the model's fields in-place.

If a row is returned from the database, then the model's fields will be updated, this.clearDirty() will be called to clear the dirty status of the model, and finally the model will be marked as persisted.

If no row is returned from the database, then this method will immediately return, and the model won't be updated.

If the model has no primary key field defined, then an exception will be thrown.

Notes:

  • A primary key is required on the model for this method to work. If you don't have a primary key defined, then you will need to create your own "reload" operation.

Arguments:

  • options?: object

    Options to pass to the underlying QueryEngine.first call. If a connection property is present on this options object, then it will be used as the connection for this operation.

Return value: undefined


method Model::save(options?: object): boolean 📜

Persist the model to the database.

This method will either initiate an insert operation against the model (if this.isPersisted() returns false), or initiate an update operation ( if this.isPersisted() returns true).

This method will do nothing, and immediately return false if the model is not dirty. If you provide the option force: true as a property in the options argument, then all fields will forcefully be marked as dirty, using the current field's value as the "dirty" value for each field, and then the model will be either inserted or updated, based on the result from isPersisted. Using force: true will essentially send and insert or update operation through the connection that will update ALL columns for the model row in the database, regardless of if they were actually dirty or not.

At the end of this method--assuming the operation was successful-- this.clearDirty() will be called on the model instance to clear its dirty state, and then the model will be marked as persisted. Finally, true will be returned, letting the caller know the operation completed successfully.

Arguments:

  • options?: object

    Options to pass to the underlying connection Connection.insert or Connection.update call. If a connection property is present on this options object, then it will be used as the connection for this operation.

Return value: boolean

true if the model was persisted through the database, or false otherwise. false doesn't mean there was an error. Errors will be thrown. false simply means that the model had no dirty fields, so it was never sent to the database.


method Model::setAttributes(attributes: object | Model, noPrimaryKey: boolean): undefined 📜

Set attributes on the model via the provided object. The provided object should contain keys that are field names for each field you wish to set. The value of each key will be what is set onto the field. This method ignores virtual fields, so if any virtual field names are supplied, then will be silently skipped. This method is identical to calling modelInstance[fieldName] = value on every key in the object provided.

Notes:

  • Any undefined value in the provided object will be ignored, and no update will occur for the field.
  • If a raw object instead of a model instance is provided, then hasOwnProperty is called for each field name, and if the provided object doesn't contain its "own" property matching the field name, the field will be silently skipped, and not set.

Arguments:

  • attributes: object | Model

    The attributes to set on the model. The keys of the model should be field names.

  • noPrimaryKey: boolean

    If true, then the primary key of the model (if any is defined) will be skipped, and won't be set, even if the provided attributes argument contains a value for the primary key.

Return value: undefined


method Model::setDataValue(fieldName: string, value: any): undefined 📜

Set the current value of any field on the model. The "current" value will be the dirty value if the field is dirty, or it will be the clean value of the field if the field isn't dirty.

This method is a "raw" set of the field's value in that it won't call set on the field descriptor, if any is defined. Instead, it will mark the field as dirty by setting the value provided as an entry for the field in the this._dirtyFieldData property of the model instance. If the value set is equal to the "clean value" of the field, as found in this._fieldData, then the dirty entry for the field will be cleared (deleted) instead.

Notes:

  • This method will always call Model.updateDirtyID, invalidating all down-stream cache for this model instance.

Arguments:

  • fieldName: string

    The name of the field whose value you wish to set.

  • value: any

    Value to set the field to. The will be sent through field.type.castValue to cast the incoming value to the field's type.

Return value: undefined


static method Model::_getConnection(connection?: Connection): Connection 📜

Get the underlying connection bound to the model's class. Connection binding is optional, so this method can also be provided a connection. If a connection is provided, then it will simply be returned. Because Mythix ORM has no globals, this is a design pattern to supply a connection if you have one available, or fallback to a "bound" connection (if one can be found).

This method will return a connection in the following order: 1) The provided connection argument, if supplied, 2) The connection property on the "model context" from Model.getModelContext from AsyncLocalStorage, if one is available, and 3) Finally the bound connection, if available, which is found by searching the static Model._mythixBoundConnection property of the class.

Notes:

  • This is a low-level "global fallback" method. Any connection for a model will first be searched by calling Model.getConnection, which will call this static method if no connection can be found. The Model.getConnection will also search the model instance for a connection property, which can be supplied to any model when it is instantiated.
  • or via the provided connection argument to the Model.getConnection method (and eventually this method) will take priority over any connection provided by the "model context" from AsyncLocalStorage. This can be an important detail when using Connection.transaction or Connection.createContext, because if a connection is directly specified by the user, the transaction connection will not take priority. So if you are using transactions or a connection context, be careful how you directly specify connections.

Arguments:

  • connection?: Connection

    An optional connection that can be provided. If provided, it will simply be returned. Otherwise, if not provided, or a falsy value, then attempt to fallback to the bound connection, if any is available.

Return value: Connection


static method Model::all(options?: object): Array<Model> 📜

Fetch all models from the database for this model type.

Notes:

  • This will fetch ALL rows for the model. If this is not what you want, then construct a query first, and call all from the query itself, i.e. User.where.firstName.EQ('Bob').all(options).

Arguments:

  • options?: object

    An "options" object to pass off to the underlying Connection methods. If a connection key is specified in this object, then that will be used as the connection for the operation. This can be important if for example you are calling this from a transaction, in which case you most certainly would want to provide the connection for the transaction. If a stream: true option is provided, then an async generator will be returned, allowing you to "stream" the rows from the database in batches. The default batchSize is 500, but can be overridden by setting the batchSize option to some valid positive number, or Infinity to pull everything at once. If the stream option is not specified, or is false, then all rows will be fetched from the database in batches, collected into an array, and returned only once all rows have been fetched. This is the default behavior.

Return value: Array<Model>

Return all models of this type from the database.


static method Model::bindConnection(connection?: Connection): class extends Model 📜

A Connection instance will call this method on a Model class to bind the model to the connection. Overload this to change the behavior of binding connections to models. This method should return a model class. The default behavior is to return this class. However, you might return a different class for example if you generated a new class that inherited from this class.

Arguments:

  • connection?: Connection

    The connection instance to bind to this model class.

Return value: class extends Model


static method Model::count(field?: string | Field, options?: object): number 📜

Count the rows in the database for this model.

Arguments:

  • field?: string | Field

    A fully qualified field name, or a Field instance. If supplied, this is the column in the table that will be counted (i.e. COUNT(column)). If not supplied, then a COUNT(*) type operation will be carried out.

  • options?: object

    An "options" object to pass off to the underlying Connection methods. If a connection key is specified in this object, then that will be used as the connection for the operation. This can be important if for example you are calling this from a transaction, in which case you most certainly would want to provide the connection for the transaction.

Return value: number

Return the number of models stored in the database for this model type.


static method Model::create(models: Array<Model> | Model | Array<object> | object, options?: object): Model 📜

Create (insert) new models into the database. The models argument can be a single model instance, a single object containing model attributes, an array of model instances, or an array of objects containing model attributes. This is a "bulk" create method, though it can be used to create a single model.

Arguments:

  • models: Array<Model> | Model | Array<object> | object

    Specify the model(s) to create.

  • options?: object

    An "options" object to pass off to the underlying Connection methods. If a connection key is specified in this object, then that will be used as the connection for the operation. This can be important if for example you are calling this from a transaction, in which case you most certainly would want to provide the connection for the transaction.

Return value: Model

Return the model instance(s) created.


static method Model::defaultScope(query: QueryEngine): QueryEngine 📜

One can apply a "default scope" to any model simply by providing this static method on the model. By default it will simply return the QueryEngine instance (a query) that it was provided.

The way this works is simple. The caller provides the query as the first and only argument. The user, by overloading this method can then easily modify this provided query, changing the "default scope" whenever the model is used for queries. This can be used to set a default order for a model, or to set default conditions to apply to any query for the model. For example, let's say you have a User model, and by default, you only want to query against Users that have their active column set to true. In order to do this, you could easily provide a static defaultScope method on your model class that would modify the base query. See the following example:

Example:

  • class User extends Model {
      static defaultScope(baseQuery) {
        // `baseQuery` is equal to `User.where`
        // without a default scope.
        return baseQuery.active.EQ(true).ORDER.ASC('User:createdAt');
      }
    }

Arguments:

  • query: QueryEngine

    The query that you should add onto.

Return value: QueryEngine


static method Model::first(limit?: number = 1, options?: object): Model | Array<Model> 📜

Get the first (limit) rows from the database for this model type.

Notes:

  • This will fetch the first rows for the model, in database order. If you wish to filter, and specify the order, then construct a query first, and call the first method from the query itself, i.e. User.where.firstName.EQ('Bob').ORDER('+User:firstName').first(options)

Arguments:

  • limit?: number (Default: 1)

    The number of model instances to fetch from the database.

  • options?: object

    An "options" object to pass off to the underlying Connection methods. If a connection key is specified in this object, then that will be used as the connection for the operation. This can be important if for example you are calling this from a transaction, in which case you most certainly would want to provide the connection for the transaction.

Return value: Model | Array<Model>

Return limit models of this type from the database. If limit is null, undefined, or 1, then a single model instance will be returned (or undefined if nothing is found). If the limit argument is more than 1, then an array of model instances will be returned, or an empty array if nothing is found.


static method Model::getConcreteFieldCount(): number 📜

Count the number of concrete fields on the model. "concrete" fields are non-virtual fields that are backed by the database. A FOREIGN_KEY field is a concrete field, so FOREIGN_KEY fields will be counted.

Return value: number

The number of concrete fields the model has.


static method Model::getContextValue(key: any, defaultValue?: any): any 📜

Get a value from the AsyncLocalStorage context.

AsyncLocalStorage is used primarily for two purposes: 1) to provide a connection to models, and 2) to pass a transaction connection down through the call stack. However, it can also be used for any "context" level values the user wishes to store.

Notes:

  • An AsyncLocalStorage context might not exist when this call is made, in which case this method will return undefined, or the defaultValue if any was provided.

Arguments:

  • key: any

    The key for the value you wish to fetch. The underlying "context" provided by AsyncLocalStorage is a Map, so the "key" can be any value.

  • defaultValue?: any

    The default value to return if there is no current AsyncLocalStorage context, or if the requested key is not found.

Return value: any


static method Model::getField(fieldName: string): Field 📜

Get a specific model field by field name. This method will return undefined if the specified field can not be found on the model. This will find both concrete and virtual fields that are defined on the model.

Notes:

  • In Mythix ORM you never specify a field via its columnName. You always use a field's defined fieldName to match against a field. Using a columnName simply won't work, unless columnName and fieldName just happen to have the same value.

Arguments:

  • fieldName: string

    The specified field name to find. This is not the columnName of the field.

Return value: Field


static method Model::getFields(fieldNames?: Array<string>): Array<Field> | Object<string, Field> 📜

Get the fields for this model. You can optionally specify the fieldNames argument, which will cause the method to return only the fields specified by name. If the fieldNames argument is provided, then the return value will always be an array of fields. If the fieldNames argument is not provided, then the return value could be either an Array of fields, or an object of fields, keyed by field name (depending on how you defined your model fields).

Notes:

  • The first time this method is called the model's fields will be built, and possibly modified. All fields will be turned into Field instances, and each field will be properly constructed to include required attributes, such as their parent Model, their fieldName, and their columnName. A model's fields are always initialized when the model is first bound to a connection, or when this method is first called.
  • In Mythix ORM you never specify a field via its columnName. You always use a field's defined fieldName to match against a field. Using a columnName simply won't work, unless columnName and fieldName just happen to have the same value.

Arguments:

  • fieldNames?: Array<string>

    An array of field names to fetch. If not provided then all model fields will be returned, including virtual fields.

Return value: Array<Field> | Object<string, Field>


static method Model::getForeignKeyFieldsMap(connection?: Connection): Map<string, array<object>> 📜

Return the foreign key relationships for the model.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

Return value: Map<string, array<object>>

The format is Map[modelName] = [ { targetFieldName, sourceFieldName }, ... ]


static method Model::getForeignKeysTargetField(connection?: Connection, modelName: string, fieldName: string): object<{ targetFieldName, sourceFieldName }> 📜

Get a specific foreign key field's relationship information. This will be what is stored in the relationship field map for the specified target field. See Model.static getForeignKeyFieldsMap for more information.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

  • modelName: string

    The model name for which you wish to fetch foreign key fields from.

  • fieldName: string

    The field name for which you wish to fetch foreign key relational information about.

Return value: object<{ targetFieldName, sourceFieldName }>

This will be the relationship info for this foreign key field which will be an object of the shape { targetFieldName, sourceFieldName }.


static method Model::getForeignKeysTargetFieldNames(connection?: Connection, modelName: string): Array<string> 📜

Return all the foreign key target fields. This will return the target fields of all foreign key fields specified on the model.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

  • modelName: string

    The model name for which you wish to fetch foreign key fields from.

Return value: Array<string>

An array of all foreign key field info Array<{ targetFieldName: string, sourceFieldName: string }>


static method Model::getForeignKeysTargetModelNames(connection?: Connection): Array<string> 📜

Return all the foreign key target model names. This will be all models targeted by all foreign keys defined by foreign key fields on this model. This will only return the models name's.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

Return value: Array<string>

The format is Array[] = modelName


static method Model::getForeignKeysTargetModels(connection?: Connection): Map<string, Model> 📜

Return all the foreign key target models. This will be all models targeted by all foreign keys defined by foreign key fields on this model.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

Return value: Map<string, Model>

The format is Map[modelName] = Model


static method Model::getModel(modelName): class Model 📜

Get the Model class for this model.

Arguments:

  • modelName

Return value: class Model


static method Model::getModelContext(): object 📜

Get this Model class's "model context" from the AsyncLocalStorage context.

AsyncLocalStorage is used primarily for two purposes: 1) to provide a connection to models, and 2) to pass a transaction connection down through the call stack. However, it can also be used for any "context" level values the user wishes to store.

When a Connection.createContext or Connection.transaction call is made, a "model context" (that is just an Object instance) is created for each model the connection is aware of, and the connection instance is added to this context, allowing models to lookup the "context connection" when a call to Model._getConnection is made. By default, these "model contexts" that are stored inside the AsyncLocalStorage context only contain a "connection" property. However, these model contexts were designed as Object instances so that the user may also use them, or so they can be used for future features. Each model also has its own "model context" so that if the application is using more than one connection, then a different connection can be specified for each model and stored in the same AsyncLocalStorage context.

Notes:

  • An AsyncLocalStorage context might not exist when this call is made, in which case this method will simply return an empty object.

Return value: object

The model class's "model context" stored in AsyncLocalStorage. This will be an empty object if no AsyncLocalStorage context is available.


static method Model::getModelName(): string 📜

Get the model name for this model. By default this will be the name of the class itself, i.e. this.name. Overload this method to provide your own model name (singular name).

Return value: string

The name the model.


static method Model::getPluralModelName(): string 📜

Get the plural model name for this model. By default this will be the singular name of the model, converted to plural using the Inflection library. Overload this method to provide your own plural name for the model.

Notes:

  • This will return the "plural" name of the model.

Return value: string

The name the model in plural form.

See also: static Model.getSingularName


static method Model::getPrimaryKeyField(): Field 📜

Get the primary key field of the model, if any is defined. If no primary key field is defined, then this will return undefined. A primary key is specified per-model by using primaryKey: true on one (and only one) of the model's fields.

Return value: Field


static method Model::getPrimaryKeyFieldName(): string 📜

Get the name of the primary key field of the model, if any is defined. If no primary key field is defined, then this will return undefined. A primary key is specified per-model by using primaryKey: true on one (and only one) of the model's fields.

Return value: string


static method Model::getQueryEngine(connection?: Connection, options?: object): QueryEngine 📜

This method is called any time a Model.where or Model.$ property is accessed. It returns a query, based off this model class (as the root model). It will first call Model.static getUnscopedQueryEngine to get the root query for the model, and then it will call Model.static defaultScope to apply any default scope to the root query. Finally, it will return the query to the user to start interacting with.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

  • options?: object

    Any extra options to pass to the QueryEngine constructor.

Return value: QueryEngine


static method Model::getQueryEngineClass(connection?: Connection): class QueryEngine 📜

This method is called every time a Model.where or Model.$ property is accessed. It should return a class that inherits from (or is) QueryEngine. By default, it will call this.getConnection().getQueryEngineClass() to get the query class defined in the connection options. Though this can be overloaded per-model (creating a different type of QueryEngine per-model), the QueryEngine class to instantiate to use for queries will generally be supplied by the connection.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

Return value: class QueryEngine


static method Model::getSingularName(): string 📜

Get the singular model name for this model. By default this will be the name of the class itself, i.e. this.name. You should probably overload Model.static getModelName to provide your own model name, instead of overloading this method.

Notes:

Return value: string

The name the model in singular form.

See also: static Model.getPluralModelName, static Model.getModelName


static method Model::getSortedFields(fieldNames?: Array<string>): Array<Field> 📜

This method is identical to Model.static getFields except that it will always return an Array of fields, and the fields will always be sorted by their fieldName.

Notes:

  • In Mythix ORM you never specify a field via its columnName. You always use a field's defined fieldName to match against a field. Using a columnName simply won't work, unless columnName and fieldName just happen to have the same value.

Arguments:

  • fieldNames?: Array<string>

    An array of field names to fetch. If not provided then all model fields will be returned, including virtual fields.

Return value: Array<Field>


static method Model::getTableName(connection?: Connection): string 📜

Get the table name for this model. By default Mythix ORM will take the model's name, and convert it to snake_case.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

Return value: string

The name of the table for this model.


static method Model::getUnscopedQueryEngine(connection?: Connection, options?: object): QueryEngine 📜

This method is called any time a query.unscoped() call is made. It will return the query's "root class" where with no Model.static defaultScope scope applied. Calling "unscoped()" will reset the query, so make sure you always call it first: Model.where.unscoped()...

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

  • options?: object

    Any extra options to pass to the QueryEngine constructor.

Return value: QueryEngine


static method Model::getWhereWithConnection(options?: object { connection: Connection }): QueryEngine 📜

This method is called anytime a Model.where or Model.$ attribute is accessed. It will provide the instantiated QueryEngine with the connection specified (if any). A connection can be specified for example by doing Model.where(connection) or Model.$(connection). This is generally only useful if you have chosen not to bind your models to a connection.

Arguments:

  • options?: object { connection: Connection }

    An object, which if supplied, should contain a connection key, specifying the connection. If no connection is provided, then this will fallback to this.getConnection() to try and find the connection itself.

Return value: QueryEngine

A QueryEngine instance (a query) for this model.


static method Model::hasField(fieldName: string): boolean 📜

Check if the model has the specified field by name. If the specified field is found on the model, then return true, otherwise false will be returned.

Notes:

  • In Mythix ORM you never specify a field via its columnName. You always use a field's defined fieldName to match against a field. Using a columnName simply won't work, unless columnName and fieldName just happen to have the same value.

Arguments:

  • fieldName: string

    The specified field name to find. This is not the columnName of the field.

Return value: boolean


static method Model::hasRemoteFieldValues(): boolean 📜

Check if any of the model's fields have a "remote value" as a defaultValue. A defaultValue method can itself report that it is "remote", meaning it is a value provided by the database itself. This method simply iterates all the model's fields, and calls field.type.isRemote() on each field. If field.type.isRemote() returns true for any field, then this method will return true, otherwise it will return false. Use this method to know if the model contains any fields whose value is obtained directly from the database itself (i.e. primary key date fields, etc...).

Return value: boolean


static method Model::initializeFields(fields: Array<Field> | Set<Field> | Object<string, Field> | Map<string, Field>): Array<Field> | object<string, Field> 📜

Initialize all fields for the model. This will be called anytime a Model.static getFields call is made. However, it caches its results, so it will immediately return if the model's fields have already been initialized.

This method does a number of things in the process of "initializing" model fields. It first ensures that every field is an instance of Field. Second, it ensures that the Type of the field is initialized (properly instantiated). Third, it ensures that all required attributes of each field is present. Required attributes are Model (the parent model), fieldName (the name of this field), and columnName (the column name for the DB). columnName, if not provided, will simply become fieldName.

Notes:

  • The cache for built fields is stored directly on the input fields argument, under a non-enumerable _mythixFieldsInitialized cache key.

Arguments:

  • fields: Array<Field> | Set<Field> | Object<string, Field> | Map<string, Field>

    A list of fields to work off of. When this method is called by Model.static getFields, then this argument will be static Model.fields.

Return value: Array<Field> | object<string, Field>


static method Model::isForeignKeyTargetModel(connection?: Connection, modelName: string): boolean 📜

Check if the specified model is a model pointed to by a foreign key field.

Arguments:

  • connection?: Connection

    An optional connection to pass through. This is needed if your models are not bound to a connection.

  • modelName: string

    The model name for which you wish to fetch foreign key fields from.

Return value: boolean

true if the specified modelName model is pointed to by one of the foreign key fields, false otherwise.


static method Model::isModel(value: any): boolean 📜

Check to see if the provided value is an instance of a Mythix ORM Model. Unlike Model.static isModelClass, which checks if a class is a Model, this will check to see if an instance is an instance of a Mythix ORM Model. It will return true if the provided value is an instanceof Model, or if the value's constructor property has a truthy _isMythixModel property (value.constructor._isMythixModel)

Arguments:

  • value: any

    Value to check.

Return value: boolean


static method Model::isModelClass(value: Function): boolean 📜

Use this method to check if a class is a Mythix ORM model. It will return true if the provided value is a class that inherits from Model, or if the provided value has an attribute named _isMythixModel that is truthy.

Arguments:

  • value: Function

    Value to check.

Return value: boolean


static method Model::iterateFields(callback: Function(context: IterationContext), fields?: Array<Field> | Set<Field> | Object<string, Field> | Map<string, Field> = null, sorted?: boolean = false): Array<any> 📜

Iterate all model fields. This is a convenience method to iterate static Model.fields, and is needed as the fields of a model can be an Array, an object, a Map, or a Set. This method works a lot like Array.prototype.map. Any return value from the provided callback will be pushed into an array just like Array.prototype.map. The callback provided, when called, will be provided a context object, as the single argument to the callback.

At any time you can call the stop method provided via the context. When called, iterateFields will stop iterating, and immediately return an array of results returned by all calls to callback.

The provided context object has the following shape:

Interface:

  • interface IterationContext {
      field: Field;           // The Field instance itself.
      fieldName: string;      // The name of the field.
      fields:                 // All the model's fields.
        Array<Field> |
        Set<Field> |
        Object<string, Field> |
      index: string | number; // The current index into the list of fields.
      stop: Function;         // A method that when called will halt iteration.
      isStopped: Function;    // Call this method to see if iteration is about to be halted.
    }

Arguments:

  • callback: Function(context: IterationContext)

    A callback method that will be called for every field on the model.

  • fields?: Array<Field> | Set<Field> | Object<string, Field> | Map<string, Field> (Default: null)

    An optional list of fields to use instead of static Model.fields. This is handy if, for example, you want to iterate a sub-set of the model's fields, such as the "dirty" fields reported by the model.

  • sorted?: boolean (Default: false)

    If true, then sort the model fields before iterating. If false, simply iterate the model's fields in their defined order.

Return value: Array<any>


static method Model::last(limit?: number = 1, options?: object): Model | Array<Model> 📜

Get the last (limit) rows from the database for this model type.

Notes:

  • This will fetch the last rows for the model, in database order. If you wish to filter, and specify the order, then construct a query first, and call the last method from the query itself, i.e. User.where.firstName.EQ('Bob').ORDER('+User:firstName').last(options)
  • This works by telling the underlying query generator to invert the specified ORDER of the query, and then it selects the first limit rows from the result.

Arguments:

  • limit?: number (Default: 1)

    The number of model instances to fetch from the database.

  • options?: object

    An "options" object to pass off to the underlying Connection methods. If a connection key is specified in this object, then that will be used as the connection for the operation. This can be important if for example you are calling this from a transaction, in which case you most certainly would want to provide the connection for the transaction.

Return value: Model | Array<Model>

Return limit models of this type from the database. If limit is null, undefined, or 1, then a single model instance will be returned (or undefined if nothing is found). If the limit argument is more than 1, then an array of model instances will be returned, or an empty array if nothing is found.


static method Model::mergeFields(mergeFields?: Array<Field> | Set<Field> | Object<string, Field> | Map<string, Field>): Array<Field> | object<string, Field> 📜

Merge specified fields into this model's fields. The mergeFields argument is optional. If not provided, then this method will simply clone the model's fields. If specified, then the fields provided will be merged into the existing fields. Merging takes place based on each field's fieldName attribute. The mergeFields argument can be an Array, an object, a Map, or a Set. Fields are matched based on fieldName, but when a match is found, it is completely overridden by what is found in the mergeFields argument. In short, the list of fields itself is merged, but the fields themselves are not merged (a shallow merge). All input objects that have keys (Object<string, Field> | Map<string, Field>) must specify the fieldName of the field as the key. If the input is an Array type (Array<Field> | Set<Field>) then each field must contain a fieldName attribute, or an exception will be thrown.</string,></string,>

Notes:

  • Anywhere you see Field as an input in this documentation, you can also simply provide a raw object with the same shape, and it will be automatically converted to a Field instance for you.

Arguments:

  • mergeFields?: Array<Field> | Set<Field> | Object<string, Field> | Map<string, Field>

    A list of fields to merge into the current model fields. The field list, as well as all fields will be cloned.

Return value: Array<Field> | object<string, Field>


static method Model::pluck(fields?: Array<string>, options?: object): Array<any> | Array<Array<any>> 📜

Pluck specific fields (columns) from the database for this model type.

Notes:

  • This will pluck across ALL rows for the model, in database order. If you wish to filter and limit, and specify the order, then construct a query first, and call the pluck method from the query itself, i.e. User.where.firstName.EQ('Bob').LIMIT(50).ORDER('+User:firstName').pluck([ 'User:firstName' ], options)
  • In Mythix ORM you never specify a field via its columnName. You always use a field's defined fieldName to match against a field. Using a columnName simply won't work, unless columnName and fieldName just happen to have the same value.

Arguments:

  • fields?: Array<string>

    An array of fully qualified field names to pluck from the underlying database table for this model. Do not use column names here... these must be fully qualified field names.

  • options?: object

    An "options" object to pass off to the underlying Connection methods. If a connection key is specified in this object, then that will be used as the connection for the operation. This can be important if for example you are calling this from a transaction, in which case you most certainly would want to provide the connection for the transaction.

Return value: Array<any> | Array<Array<any>>

If only a single field is specified, then a flat array of values will be returned across all rows. If more than one field is specified, then an array of arrays (rows) will be returned for the fields specified.


static method Model::primaryKeyHasRemoteValue(): boolean 📜

Check to see if the primary key field (if any is defined) has a "remote" default value. For example, an autoincrementing primary key field would return true from this method, because an autoincrementing field value is retrieved directly from the database. This could return false, if for example, you were using UUIDs, or XIDs for your primary key.

Return value: boolean

true if the primary key field of the model has a "remote" defaultValue, false otherwise. Remoteness is checked via this.getPrimaryKeyField().type.isRemote().


static method Model::setContextValue(key: any, value: any): any 📜

Set a value onto the AsyncLocalStorage context.

AsyncLocalStorage is used primarily for two purposes: 1) to provide a connection to models, and 2) to pass a transaction connection down through the call stack. However, it can also be used for any "context" level values the user wishes to store.

Notes:

  • An AsyncLocalStorage context might not exist when this call is made, in which case this method will do nothing, and silently return.

Arguments:

  • key: any

    The key for the value you wish to set. The underlying "context" provided by AsyncLocalStorage is a Map, so the "key" can be any value.

  • value: any

    The value to set to the specified key.

Return value: any


static method Model::toString(showFields?: boolean): string 📜

Like everywhere in Javascript, we can call .toString() to a get a string representation of our Model class. The optional showFields argument, if true, will list the models fields as well. Without the showFields argument, the model name alone will be returned as a string.

Arguments:

  • showFields?: boolean

    If true, then list the models fields.

Return value: string


static method Model::updateModelContext(value: object): undefined 📜

Update this Model class's "model context" from the AsyncLocalStorage context.

AsyncLocalStorage is used primarily for two purposes: 1) to provide a connection to models, and 2) to pass a transaction connection down through the call stack. However, it can also be used for any "context" level values the user wishes to store.

When a Connection.createContext or Connection.transaction call is made, a "model context" (that is just an Object instance) is created for each model the connection is aware of, and the connection instance is added to this context, allowing models to lookup the "context connection" when a call to Model._getConnection is made. By default, these "model contexts" that are stored inside the AsyncLocalStorage context only contain a "connection" property. However, these model contexts were designed as Object instances so that the user may also use them, or so they can be used for future features. Each model also has its own "model context" so that if the application is using more than one connection, then a different connection can be specified for each model and stored in the same AsyncLocalStorage context.

This method allows you to update this "model context" for the model. The value argument must be an Object instance. You can specify any properties you want. Just be cautious if you set a connection property, as you might overwrite any connection currently set on the context. Any properties you set here will be available in any child function calls (inside this context scope), and can be accessed via a call to Model.getModelContext.

Notes:

  • An AsyncLocalStorage context might not exist when this call is made, in which case this method will simply return an empty object.

Arguments:

  • value: object

    The new properties you wish to merge with the current "model context".

Return value: undefined


method Model::toJSON(): object 📜

Return a raw Object of the model's attributes, ready to be passed through JSON.stringify. This method is nearly identical to Model.getAttributes except that it always inserts the primary key of the model (if the model has one) first. The other difference between this method and Model.getAttributes is that this method will call field.type.serialize on each field value.

Return value: object

All model attributes, ready to be serialized.

See also: Type.serialize


method Model::toString(): string 📜

Get a string representation of this model.

Return value: string

The model's name and attributes as a string.


method Model::updateDirtyID() 📜

Update the this._dirtyID cache key of the model. This is called any time a field is marked as "dirty" on the model. The _dirtyID property of a model is an instance of a CacheKey that is intended to be used for caching systems. The CacheKey instance can be used for a key into a WeakMap, which can cache things. Because this is updated to a new instance of a CacheKey any time any field on the model is marked as dirty, any cache for this model will be invalidated as soon as any field on the model is dirty.



Clone this wiki locally