Skip to content
Wyatt Greenway edited this page Aug 28, 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 as well as an instance. For example, Model 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 = true

This property assists with type checking.


method Model::_getConnection(connection?: Connection)

See static _getConnection.

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 static _getConnection to get the bound connection, if any is available.

Return value: Connection

Notes:

  • Pay attention that unlike 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 }).

static method Model::_getConnection(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).

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)

Fetch all models from the database for this model type.

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.

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).

static method Model::bindConnection(connection?: Connection)

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(options?: object)

Count the rows in the database for this model.

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.

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)

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)

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. 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:

Examples:

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

Arguments:

  • query: QueryEngine

    The query that you should add onto.

Return value: QueryEngine


static method Model::first(limit?: number = 1, options?: object)

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

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.

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)

static method Model::getConcreteFieldCount()

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::getConnection(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.

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::getDefaultOrder(options)

Specify the default SELECT "ORDER" for the model. This method will be called if no "ORDER" was specified for any given query. This method should return an Array of fully qualified field names. The options argument is the current options for the specific query being operated on.

Arguments:

  • options

Return value: Array<string> | null

An array of fully qualified field names to specify the ORDER. Prefix a field name with + to specify ASCending order, i.e. [ "+User:id" ]. Prefix the field name with - to specify DESCending order, i.e. [ "-User:id" ].

Notes:

  • Internally, Mythix ORM will call this.connection.getDefaultOrder(options), which--if not overloaded--will simply call this method from the model itself.
  • A "fully qualified field name" in Mythix ORM means a full field definition, including the model name. An example of a fully qualified field name might be "User:id". The model name is separated from the field name by a colon :. A short hand, not fully qualified field name example would be simply "id". Since this contains no model prefix, this is "short hand", and is not a fully qualified field name.

static method Model::getField(fieldName: string)

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.

Arguments:

  • fieldName: string

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

Return value: Field

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.

static method Model::getFields(fieldNames?: Array<string>)

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).

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>

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.

static method Model::getForeignKeyFieldsMap(connection?: Connection)

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)

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 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)

Return all the foreign key target field names. This will return the target field names 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>

The format is Array[] = modelName


static method Model::getForeignKeysTargetModelNames(connection?: Connection)

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)

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()

Get the Model class for this model.

Return value: class Model


static method Model::getModelName()

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()

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.

Return value: string

The name the model in plural form.

Notes:

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

See also: static getSingularName


static method Model::getPrimaryKeyField()

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()

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)

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 static getUnscopedQueryEngine to get the root query for the model, and then it will call 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)

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()

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 static getModelName to provide your own model name, instead of overloading this method.

Return value: string

The name the model in singular form.

Notes:

See also: static getPluralModelName, static getModelName


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

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

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>

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.

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

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)

This method is called any time a query.unscoped() call is made. It will return the query's "root class" where with no 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 })

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)

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.

Arguments:

  • fieldName: string

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

Return value: boolean

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.

static method Model::hasRemoteFieldValues()

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>)

Initialize all fields for the model. This will be called anytime a 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.

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 static getFields, then this argument will be static Model.fields.

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

Notes:

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

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

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)

Check to see if the provided value is an instance of a Mythix ORM Model. Unlike 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)

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)

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. This context object has the following shape:

IterationContext = {
  // The Field instance itself.
  field,
  // The name of the field.
  fieldName,
  // All the model's fields.
  fields,
  // The current index into the list of fields.
  // This will be set even if the fields are
  // `object` or `Map` types.
  index,
  // A method that when called will halt
  // iteration and immediately return.
  stop,
  // A method that you can call to see
  // if `stop` has been called... meaning the
  // iteration process is about to halt.
  isStopped,
}

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.

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)

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

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.

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.

static method Model::mergeFields(mergeFields?: Array<Field> | Set<Field> | Object<string, Field> | Map<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,>.

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>

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.

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

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

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.

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.

static method Model::primaryKeyHasRemoteValue()

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::toString(showFields?: boolean)

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



Clone this wiki locally