Skip to content

ConnectionBase

Wyatt Greenway edited this page Nov 24, 2022 · 36 revisions

class ConnectionBase extends EventEmitter 📜

ConnectionBase is the base class that all connection classes should inherit from. It provides common functionality to all connections, and converts literals and types into their native database representation.

A "connection" in Mythix ORM is essentially the "application" for the ORM. It stores all models used by the connection, stores and defines the query generator (if any), converts literals and types, and also provides the query engine.

Multiple connections can be used at the same time in Mythix ORM. It is also planned that someday Mythix ORM (or the community) will provide a multiplex connection, to mix multiple connections into a single connection for the entire application.

For now you can use multiple connections at once. Just know that you should read and fully understand Connection Binding if you plan on using more than one connection for your application.

ConnectionBase is also an Event Emitter, so you can bind events to a connection instance with .on, and unbind with .off. Events are connection specific, but common events that can be bound to are:

  1. connect - Commonly fired when a connection is successfully established
  2. acquire - Commonly fired when a connection is acquired from a connection pool
  3. error - Commonly fired when a database level error occurs
  4. disconnect - Commonly fired when a connection is disconnected

This is just an example of common connection driver events. Please see documentation for your specific database connection for the proper events.

static property ConnectionBase::_isMythixConnection: boolean 📜

Helper for type checking methods. Should always be true.


static property ConnectionBase::DefaultQueryGenerator = QueryGeneratorBase 📜


property ConnectionBase::dialect: string = "none" 📜

The dialect of the database, i.e. 'sqlite', or 'postgresql'.


static property ConnectionBase::Literals: Literals = Literals 📜

All default Mythix ORM literal classes, provided for convenient access.


method ConnectionBase::_averageLiteralToString(literal: AverageLiteral, options?: object): string 📜

Convert the provided AverageLiteral to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

Notes:

  • This method is a proxy method for QueryGenerator._averageLiteralToString. If the connection has no instance of a queryGenerator available to it, then this method will simply return undefined.
  • Generally speaking, Literal "options" are literal (and connection) specific. They often aren't needed or used directly by the user, but instead are used by the underlying connection itself, to define context specific options. For example, the underlying connection might have an option to tell a literal that it is the "DEFAULT" value of a field, instead of just a raw value to inject in the generated query stream, and this might change the output of the literal when converted to a string.

Arguments:

  • literal: AverageLiteral

    The literal to convert to a string for the database.

  • options?: object

    Optional options to pass to the QueryGenerator._averageLiteralToString method.

Return value: string

The provided AverageLiteral converted to a string for the underlying database driver.


method ConnectionBase::_bigintTypeToString(type: Type): string 📜

Convert a "BIGINT" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be BIGINT, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_blobTypeToString(type: Type): string 📜

Convert a "BLOB" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be BLOB, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_booleanTypeToString(type: Type): string 📜

Convert a "BOOLEAN" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be BOOLEAN, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_charTypeToString(type: Type): string 📜

Convert a "CHAR" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be CHAR, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_countLiteralToString(literal: CountLiteral, options?: object): string 📜

Convert the provided CountLiteral to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

Notes:

  • This method is a proxy method for QueryGenerator._countLiteralToString. If the connection has no instance of a queryGenerator available to it, then this method will simply return undefined.
  • Generally speaking, Literal "options" are literal (and connection) specific. They often aren't needed or used directly by the user, but instead are used by the underlying connection itself, to define context specific options. For example, the underlying connection might have an option to tell a literal that it is the "DEFAULT" value of a field, instead of just a raw value to inject in the generated query stream, and this might change the output of the literal when converted to a string.

Arguments:

  • literal: CountLiteral

    The literal to convert to a string for the database.

  • options?: object

    Optional options to pass to the QueryGenerator._countLiteralToString method.

Return value: string

The provided CountLiteral converted to a string for the underlying database driver.


method ConnectionBase::_datetimeTypeToString(type: Type): string 📜

Convert a "DATETIME" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be BIGINT, however, it may be different based on what database you are using.

Notes:

  • Mythix ORM always stores DATE and DATETIME types as a timestamp (in milliseconds from the UNIX Epoch) whenever it is able to. This is why the default type for most connection drivers is BIGINT. Another common type for this conversion is TIMESTAMP.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_dateTypeToString(type: Type): string 📜

Convert a "DATE" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be BIGINT, however, it may be different based on what database you are using.

Notes:

  • Mythix ORM always stores DATE and DATETIME types as a timestamp (in milliseconds from the UNIX Epoch) whenever it is able to. This is why the default type for most connection drivers is BIGINT. Another common type for this conversion is TIMESTAMP.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_distinctLiteralToString(literal: DistinctLiteral, options?: object): string 📜

Convert the provided DistinctLiteral to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

Notes:

  • This method is a proxy method for QueryGenerator._distinctLiteralToString. If the connection has no instance of a queryGenerator available to it, then this method will simply return undefined.
  • Generally speaking, Literal "options" are literal (and connection) specific. They often aren't needed or used directly by the user, but instead are used by the underlying connection itself, to define context specific options. For example, the underlying connection might have an option to tell a literal that it is the "DEFAULT" value of a field, instead of just a raw value to inject in the generated query stream, and this might change the output of the literal when converted to a string.

Arguments:

  • literal: DistinctLiteral

    The literal to convert to a string for the database.

  • options?: object

    Optional options to pass to the QueryGenerator._distinctLiteralToString method.

Return value: string

The provided DistinctLiteral converted to a string for the underlying database driver.


method ConnectionBase::_escape(value: any): string 📜

The low-level DB interface for escaping a value. By default this function uses the sqlstring module to escape values. However, the escape method for whatever database the connection is using should be used instead of this. This is a "default implementation" that is meant as a fallback when a connection doesn't provide its own, but each connection should provide its own when it is able.

Notes:

  • This method escapes "values" that are given in the underlying query language of the database. To escape identifiers, use the ConnectionBase._escapeID instead.

Arguments:

  • value: any

    The value to escape. This could be a number, a boolean, a string, or anything else that can be provided to your specific database.

Return value: string

The value provided, escaped for the specific underlying database driver.


method ConnectionBase::_escapeID(value: string): string 📜

Low-level database method for escaping an identifier. Each database driver should provide its own version of this method. This is the "default" method Mythix ORM provides as a "fallback" to database drivers that don't supply their own.

It works by first stripping all quotes (single ', double ", and backtick `) from the provided value. After this, it will split on the period (dot) character ., and then will map each resulting part through sqlstring escapeId method, finally re-joining the parts with a period . character.

The extra processing is to allow for already escaped identifiers to not be double-escaped.

Arguments:

  • value: string

    The identifier to escape.

Return value: string

The provided identifier, escaped for the underlying database.


method ConnectionBase::_fieldLiteralToString(literal: FieldLiteral, options?: object): string 📜

Convert the provided FieldLiteral to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

Notes:

  • This method is a proxy method for QueryGenerator._fieldLiteralToString. If the connection has no instance of a queryGenerator available to it, then this method will simply return undefined.
  • Generally speaking, Literal "options" are literal (and connection) specific. They often aren't needed or used directly by the user, but instead are used by the underlying connection itself, to define context specific options. For example, the underlying connection might have an option to tell a literal that it is the "DEFAULT" value of a field, instead of just a raw value to inject in the generated query stream, and this might change the output of the literal when converted to a string.

Arguments:

  • literal: FieldLiteral

    The literal to convert to a string for the database.

  • options?: object

    Optional options to pass to the QueryGenerator._fieldLiteralToString method.

Return value: string

The provided FieldLiteral converted to a string for the underlying database driver.


method ConnectionBase::_getFromModelCache(Model: class Model, key: any, defaultValue?: any): any 📜

A convenience method to get from "model cache".

Model Cache is a simple system to cache random results from model methods. This is used for things that should never change, for example the models fields, the models name, the table name for the model, etc... Some of these values are initially computed, and then cached using this system so operations later on return much quicker.

Notes:

  • The underlying cache system uses the Map type, so any value can be used as a cache key.
  • This cache is never cleared or marked as stale, so if using dynamic cache keys, make sure that you properly remove them later to prevent memory leaks.

Arguments:

  • Model: class Model

    The model class we a caching for.

  • key: any

    The key to use for our cache.

  • defaultValue?: any

    The default value to return if no cache entry was found.

Return value: any

Any value found in the cache.


method ConnectionBase::_integerTypeToString(type: Type): string 📜

Convert a "INTEGER" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be INTEGER, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_maxLiteralToString(literal: MaxLiteral, options?: object): string 📜

Convert the provided MaxLiteral to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

Notes:

  • This method is a proxy method for QueryGenerator._maxLiteralToString. If the connection has no instance of a queryGenerator available to it, then this method will simply return undefined.
  • Generally speaking, Literal "options" are literal (and connection) specific. They often aren't needed or used directly by the user, but instead are used by the underlying connection itself, to define context specific options. For example, the underlying connection might have an option to tell a literal that it is the "DEFAULT" value of a field, instead of just a raw value to inject in the generated query stream, and this might change the output of the literal when converted to a string.

Arguments:

  • literal: MaxLiteral

    The literal to convert to a string for the database.

  • options?: object

    Optional options to pass to the QueryGenerator._maxLiteralToString method.

Return value: string

The provided MaxLiteral converted to a string for the underlying database driver.


method ConnectionBase::_minLiteralToString(literal: MinLiteral, options?: object): string 📜

Convert the provided MinLiteral to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

Notes:

  • This method is a proxy method for QueryGenerator._minLiteralToString. If the connection has no instance of a queryGenerator available to it, then this method will simply return undefined.
  • Generally speaking, Literal "options" are literal (and connection) specific. They often aren't needed or used directly by the user, but instead are used by the underlying connection itself, to define context specific options. For example, the underlying connection might have an option to tell a literal that it is the "DEFAULT" value of a field, instead of just a raw value to inject in the generated query stream, and this might change the output of the literal when converted to a string.

Arguments:

  • literal: MinLiteral

    The literal to convert to a string for the database.

  • options?: object

    Optional options to pass to the QueryGenerator._minLiteralToString method.

Return value: string

The provided MinLiteral converted to a string for the underlying database driver.


method ConnectionBase::_numericTypeToString(type: Type): string 📜

Convert a "NUMERIC" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be NUMERIC, DECIMAL, or NUMBER, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_realTypeToString(type: Type): string 📜

Convert a "REAL" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be FLOAT, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_setToModelCache(Model: class Model, key: any, value: any): any 📜

A convenience method to set to the "model cache".

Model Cache is a simple system to cache random results from model methods. This is used for things that should never change, for example the models fields, the models name, the table name for the model, etc... Some of these values are initially computed, and then cached using this system so operations later on return much quicker.

Notes:

  • The underlying cache system uses the Map type, so any value can be used as a cache key.
  • This cache is never cleared or marked as stale, so if using dynamic cache keys, make sure that you properly remove them later to prevent memory leaks.

Arguments:

  • Model: class Model

    The model class we a caching for.

  • key: any

    The key to use for our cache.

  • value: any

    The value to cache.

Return value: any

The value provided.


method ConnectionBase::_stringTypeToString(type: Type): string 📜

Convert a "STRING" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be VARCHAR, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_sumLiteralToString(literal: SumLiteral, options?: object): string 📜

Convert the provided SumLiteral to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

Notes:

  • This method is a proxy method for QueryGenerator._sumLiteralToString. If the connection has no instance of a queryGenerator available to it, then this method will simply return undefined.
  • Generally speaking, Literal "options" are literal (and connection) specific. They often aren't needed or used directly by the user, but instead are used by the underlying connection itself, to define context specific options. For example, the underlying connection might have an option to tell a literal that it is the "DEFAULT" value of a field, instead of just a raw value to inject in the generated query stream, and this might change the output of the literal when converted to a string.

Arguments:

  • literal: SumLiteral

    The literal to convert to a string for the database.

  • options?: object

    Optional options to pass to the QueryGenerator._sumLiteralToString method.

Return value: string

The provided SumLiteral converted to a string for the underlying database driver.


method ConnectionBase::_textTypeToString(type: Type): string 📜

Convert a "TEXT" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be TEXT, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_uuidV1TypeToString(type: Type): string 📜

Convert a "UUIDV1" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be VARCHAR, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_uuidV3TypeToString(type: Type): string 📜

Convert a "UUIDV3" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be VARCHAR, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_uuidV4TypeToString(type: Type): string 📜

Convert a "UUIDV4" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be VARCHAR, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_uuidV5TypeToString(type: Type): string 📜

Convert a "UUIDV5" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be VARCHAR, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::_xidTypeToString(type: Type): string 📜

Convert a "XID" field type to a type acceptable by the underlying database driver.

For most SQL connections this would be VARCHAR, however, it may be different based on what database you are using.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::addColumn(Field: Field, options?: object): Promise<void> 📜

Add the column/field specified to the database.

The table/bucket to add the field to is fetched from the Model property on the supplied field.

Arguments:

  • Field: Field

    The new field to add to the underlying database.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<void>


method ConnectionBase::addIndex(Model: class Model, indexFields: Array<string>, options?: object): Promise<void> 📜

Create an index (or combo index) in the database.

This will create a new index for the field(s) specified. The indexFields argument must be an array of field names as strings. It can contain more than one field. If it does contain more than one field, then a combo index will be created for all specified fields (if the database you are using supports combined indexes).

All the provided field names must exist on the provided Model. If they don't, then an exception will be thrown. The field names can be fully qualified, but they don't need to be. If they are fully qualified, then they must all still be owned by the provided Model. You can not for example use a fully qualified field name from another model.

Combo indexes are created by combining two or more fields to create the index. For example, you could create a combo index for Users like [ 'firstName', 'lastName', 'email' ] if it is common for your application to query on all three of these fields at once.

If you just want to index a single column/field, simply provide only one field name, i.e. [ 'firstName' ].

Arguments:

  • Model: class Model

    The model that owns the specified fields.

  • indexFields: Array<string>

    The field names to use to create the index. One field name is valid if you only wish to index a single field. These are used to generate the index name, along with which fields to index.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<void>


method ConnectionBase::aggregate(query: QueryEngine, literal: LiteralBase, options?: object): Promise<number> 📜

Aggregate data across rows.

Though this method can be called directly, it is generally called from one of ConnectionBase.average, ConnectionBase.sum, ConnectionBase.count, ConnectionBase.min, or ConnectionBase.max, or one of the other aggregate methods provided by the connection.

It takes a query which is used to generate a query for the underlying database, and sets the query PROJECTION to the aggregate literal provided. For example, a sum method call would call this method with a SumLiteral, which would change the query projection to the expanded result of the SumLiteral, returning the "sum" of all column values targeted by the literal field. The results will then be collected, and always returned as a number primitive to the caller.

Arguments:

  • query: QueryEngine

    The query used to select which rows to aggregate across.

  • literal: LiteralBase

    A literal, used as the aggregate function. For example, if a CountLiteral is provided, then the count of all rows matching the provided query will be the result.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<number>

The result of the aggregate operation, as a number.


method ConnectionBase::alterColumn(Field: Field, NewField: Field | object, options?: object): Promise<void> 📜

Alter the specified column/field in the database.

This will take the two fields, Field and NewField, and will compare them. It will generate multiple alter table statements internally, and will alter the column/field based on the differences it detects between the two fields.

If NewField is provided as a raw object, then it will be converted into a Field.

This method will check for the following differences between the two fields, in this order:

  1. allowNull
  2. type
  3. defaultValue
  4. primaryKey
  5. unique
  6. index (will calculate index differences, and do the minimum work required)
  7. columnName

Arguments:

  • Field: Field

    The current column/field (as it is in the database) that we are changing.

  • NewField: Field | object

    The new field properties to compare. Only the provided properties will be compared. For example, if you only supply a defaultValue property, then only that will be altered (if it differs from Field).

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<void>


method ConnectionBase::alterTable(Model: class Model, newAttributes: object): Promise<void> 📜

Alter a table/bucket based on the provided attributes for the model.

For SQL based drivers this might run a statement like the following ALTER TABLE "users" RENAME TO "old_users";

Please refer to the documentation of the database driver you are using for more information.

Arguments:

  • Model: class Model

    The model to alter. This is used to alter the underlying table/bucket in the database.

  • newAttributes: object

    The attributes to alter. Please refer to the documentation of the database driver you are using for more information.

Return value: Promise<void>


method ConnectionBase::average(query: QueryEngine, field: Field | string, options?: object): Promise<number> 📜

Get the average for a single column, spanning all matching rows.

This will return the average of all values in a column, across all matching rows, as a number primitive.

Arguments:

  • query: QueryEngine

    The query used to select which rows are used to calculate the average.

  • field: Field | string

    A field instance, or a fully qualified field name, used as the target column in the underlying database to calculate an average across all matching values.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<number>

The average of all matching columns.


method ConnectionBase::buildConnectionContext(connection?: Connection = this): Map<any, any> 📜

This builds a "connection context" to provide to the AsyncLocalStorage context of a Connection.createContext call.

By default, this will set a connection property on the context, which will be the value of this connection instance. It also sets a connection property on the sub-contexts for each model. This is because models might have different connections, and so need a context per-model to work properly.

"How could a model have different connections?" you ask? Well, it probably won't. But being as this is an AsyncLocalStorage context, it provides the connection to every model inside the context. Your application might be using other models that aren't part of this connection, and we wouldn't want those to get the wrong connection for those models.

Arguments:

  • connection?: Connection (Default: this)

    The connection to create the context for. This can be provided, and is used in place of this instance, for example, in the case of transactions. Transactions generally are the "same" connection, but not the same instance.

Return value: Map<any, any>

The new context that will be used for Connection.createContext.


method ConnectionBase::bulkModelOperation(Model: class Model, models: Array<Model>, options?: object, beforeCallback?: (Model: typeof Model, batchModelInstances: Array, options: object, queryGenerator: QueryGenerator) => Promise, callback: (Model: typeof Model, preparedModels: PreparedModels, options: object, queryGenerator: QueryGenerator) => Promise, afterCallback?: (Model: typeof Model, models: Array, options: object, queryGenerator: QueryGenerator) => Promise, afterOperationCallback?: (Model: typeof Model, dirtyModels: Set, options: object, queryGenerator: QueryGenerator) => Promise): Array<Model> 📜

This is a low-level "helper" method that is used by all "bulk operations", such as insert, upsert, update, or destroyModels. It prepares all provided models for operation, splits out sub-models provided, skips already persisted models, and also calls the model hooks onBeforeSave, onAfterSave, etc... This method will also always operate in batches, as defined by the batchSize option (default is 500 if not provided).

Lastly, when it is all done running the "batch operation" on all models, it will update any foreign keys on each model, and if any model has again been marked dirty from this update it will finally persist those updated models.

When it is fully complete, this method will return all "primary" models supplied to the method (i.e. if saving User models, then all supplied users will be returned and if any sub models were involved those won't be returned). The "primary model" is the model whose model class was specified as the Model argument on invocation of this method, and should match the type of the input models.

Arguments:

  • Model: class Model

    The model class for the input models being provided.

  • models: Array<Model>

    The models to bulk operate on. All of them must be instances of the class provided as the Model argument.

  • options?: object

    Options to supply to the method. Refer to the following table for a list of possible options.

    Option Type Default Value Description
    batchSize number 500 The number of models for each batch
    isInsertOperation boolean false true if this is an insert operation. If this is an insert operation, then dirty models will be collected post-insert, and re-saved if any are re-marked dirty after foreign key updates.
    isDeleteOperation boolean false true if this is a delete operation. If this is a delete operation, then model preparation and splitting is skipped, and the models are processed directly.
  • beforeCallback?: (Model: typeof Model, batchModelInstances: Array, options: object, queryGenerator: QueryGenerator) => Promise

    Callback that is called for each batch of models, before the current operation (i.e. insert) operates on them. It is generally in this callback that onBefore* model hooks are called.

  • callback: (Model: typeof Model, preparedModels: PreparedModels, options: object, queryGenerator: QueryGenerator) => Promise

    Callback to call to process each batch of models. The models are in "prepared model" format, meaning they are supplied as an object with models, dirtyFields, and dirtyModels properties.

  • afterCallback?: (Model: typeof Model, models: Array, options: object, queryGenerator: QueryGenerator) => Promise

    Callback that is called for each entire model set (not in batches). For example, if you bulk insert 1000 users, and your batchSize is 100, then this will be called once, with all 1000 processed users, not 10 times with 100 users each. It is generally in this callback that onAfter* model hooks are called.

  • afterOperationCallback?: (Model: typeof Model, dirtyModels: Set, options: object, queryGenerator: QueryGenerator) => Promise

    Callback that is called after the entire operation completes successfully. This will only be called if dirtyModels is not empty. This method generally will re-save any models that got dirty during the operation... for example, when foreign keys have been updated on the models being processed. Models won't be added to the dirtyModels set if they are marked dirty in onAfter* model hooks, but only if the foreign key update process marked the model as dirty.

Return value: Array<Model>

Return all input models, converted to model instances, and updated. How they are updated depends on the operation being performed.


method ConnectionBase::constructor(options: object): Connection 📜

Create a connection.

The options argument is generally connection specific. However, there are a few generic options, which you will find listed in the table below:

Option Type Default Value Description
bindModels boolean true If true, then bind the provided models to this connection. Models are bound to a connection by setting a static _mythixBoundConnection property on each model class to this connection instance.
forceConnectionBinding boolean false Normally attempting to bind a connection to a model more than once will result in an exception being thrown. However, if you set this property to true, then Mythix ORM will rebind the connection without complaint, even if a connection is already bound to your models. Make sure you know what you are doing if you use this option.
models Array or Object of Models undefined Models to provide to this connection. This can be either an array of Models, or an Object where each value is a Model
QueryEngine class QueryEngine QueryEngine The QueryEngine class to use for this connection and all this connection's models. You can provide your own class if you wish to add onto the query interface.
queryGenerator QueryGenerator Connection specific The query generator for this connection. If a QueryGenerator instance is provided (the correct one for the connection you are using), then this provided query generator will be used. If one isn't provided, then the connection will create its own query generator that is specific to the connection type.

Arguments:

  • options: object

    Connection specific options to supply to your connection. These will commonly include things like a hostname to connect to, a user name and password, and any connection specific parameters.

Return value: Connection


method ConnectionBase::convertDateToDBTime(value: any, type: Type): any 📜

Convert a given "time" type object to the value needed by the underlying database.

By default this method will take a Luxon DateTime instance, or a Date instance, and convert it to the value needed by the underlying field in the database. This is generally a BIGINT, or TIMESTAMP value, as Mythix ORM will always try to store dates and times as millisecond timestamps (number of milliseconds since the UNIX Epoch).

If a number, bigint, or a string type is provided, then Mythix ORM will use Luxon to try and parse the provided value. If the value is parsed correctly, it will then be converted to the proper value as needed by the underlying field in the database.

Arguments:

  • value: any

    The incoming date/time type to convert to the proper database value for the underlying field.

  • type: Type

    The field type that this conversion is for. This will generally be a DATE or DATETIME type.

Return value: any

Return the value needed by the underlying database field. Generally this will be a bigint type that is returned, but may be something different depending on the field and the database itself.


method ConnectionBase::count(query: QueryEngine, field: Field | string, options?: object): Promise<number> 📜

Get the number of rows matching the query.

This will return the number of rows matching the provided query, as a number primitive.

Notes:

  • In most databases, if the field argument is not specified, then the count operation will be across all table columns (COUNT(*)).

Arguments:

  • query: QueryEngine

    The query used to select which rows to count.

  • field: Field | string

    A field instance, or a fully qualified field name, used as the target column in the underlying database to count the rows. If not specified, then most database drivers will count across all columns (i.e. COUNT(*)).

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<number>

The count (number) of all rows matching the provided query.


method ConnectionBase::createContext(callback: async Function, connection?: Connection = this, thisArg?: any = this): any 📜

Create a connection context to serve all code running inside it this connection.

This uses AsyncLocalStorage to create a context that is passed through the entire call stack of the callback. In this way, a connection can be provided to every model and every operation within the call.

Arguments:

  • callback: async Function

    The method to provide the context to. Every call inside this call stack will be provided the connection.

  • connection?: Connection (Default: this)

    The connection to provide. Generally this will just be this connection instance, however, it can be specified, and is for example inside transactions.

  • thisArg?: any (Default: this)

    The this value to provide to the given callback.

Return value: any

The return value of the given callback.


method ConnectionBase::createQueryGenerator(options) 📜

This method will create the default query generator.

Arguments:

  • options

method ConnectionBase::createTable(Model: class Model, options?: object): any 📜

Create a table/bucket using the provided model class.

The provided options are database specific, but might contain things like ifExists, for example.

Arguments:

  • Model: class Model

    The model class used to create the table/bucket. The Model.getTableName method will be called to get the table/bucket name to create. Then the static fields property on the model class is used to create the columns/fields for the table/bucket. Only "concrete" fields are created in the underlying database. Any "virtual" or "relational" fields will be skipped.

  • options?: object

    Database specific operations for creating the table/bucket. Please refer to the documentation of the driver you are using for further information.

Return value: any

A connection specific return value for the operation.


method ConnectionBase::createTables(Models: Array<class Model>, options?: object): any 📜

Create all specified tables/buckets in the database.

This uses the provided Models classes to create the tables/buckets specified.

The options argument is database specific, but might contain options such as ifNotExists, for example.

The model classes provided are first sorted in "creation order" using the Utils.sortModelNamesByCreationOrder method, and then the tables/buckets are created in the that order. This is to ensure that any foreign key constraints in play will play nicely with the operation and not throw errors.

This method simply calls ConnectionBase.createTable for every model provided--after sorting the models based on their foreign keys.

Arguments:

  • Models: Array<class Model>

    The model classes used to create the tables/buckets. The Model.getTableName method will be called for each model to get the table/bucket name to create. Then the static fields property on each model class is used to create the columns/fields for the table/bucket. Only "concrete" fields are created in the underlying database. Any "virtual" or "relational" fields will be skipped.

  • options?: object

    Database specific operations for dropping the table/bucket. Please refer to the documentation of the driver you are using for further information.

Return value: any

A database specific return value for the create tables operation.


method ConnectionBase::destroy(queryOrModel: class Model | QueryEngine, modelsOrOptions: Array<Model> | Model | object, options?: object | undefined): Promise<Array<Models> | Model | number> 📜

Destroy multiple models by query, or by the provided models themselves. If models are provided, then each model must have a valid primary key field, or an exception will be thrown.

If models are provided as the second argument, then it is required that the first argument be a Model class. In this case, this method simply calls ConnectionBase.destroyModels to complete the operation.

If the first argument is a QueryEngine instance, then rows will be deleted from the database using the provided query. In this case, it is expected that the second argument will be the "options" for this operation instead of an array of models.

Arguments:

  • queryOrModel: class Model | QueryEngine

    A QueryEngine instance to specify which models to delete via a query, or a Model class if models are being provided to be deleted.

  • modelsOrOptions: Array<Model> | Model | object

    If a QueryEngine instance is provided as the first argument then this is expected to be the "options" for the operation. If however a Model class is provided as the first argument, then this should be a Model instance, or an array of Model instances.

  • options?: object | undefined

    Most of these options are database/driver specific. The batchSize option is ignored if a QueryEngine instance is provided as the first argument to the call. If a Model class is provided as the first argument to the call, then this options object will be at argument index 1 instead (the second argument, modelsOrOptions). The following options are common across all database drivers (skipHooks is not supported in this context):

    Option Type Default Value Description
    batchSize number 500 The size of each batch during a multi-model destroy operation.

Return value: Promise<Array<Models> | Model | number>

Return the models deleted (if models were provided), or the number of rows deleted (if a query was provided).


method ConnectionBase::destroyModels(Model: class Model, models: Array<Model | object> | object | Model, options?: object): Promise<Array<Model> | Model> 📜

Destroy the provided models.

This method will bulk-iterate the specified models and will destroy each one. A primary key field is required for every model, or this method will throw an exception.

The skipHooks option (see ConnectionBase.runSaveHooks) won't do anything here, because Mythix ORM doesn't have any on*Destroy hooks. Mythix ORM doesn't have any destroy hooks for performance reasons. However, the batchSize option is still useful for this method.

Notes:

  • WARNING!!!: If you supply null or undefined as the models argument then this method will silently return. If you also supply the option { truncate: true } then the entire table will be truncated. This option is an "opt-in", to make sure you don't truncate an entire table on accident.
  • Some databases (i.e. SQLite) don't support a TRUNCATE statement, and so will deliberately call this method with null for the models argument for truncate operations. When doing so they will also deliberately supply the { truncate: true } option.

Arguments:

  • Model: class Model

    The model class used for the operation. This defines what table/bucket to delete from.

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

    The model(s) to delete from the database. If raw objects are provided, then they must contain a primaryKey for each model. If any of the models provided don't contain a primaryKey field, then an exception will be thrown. If you have a table/bucket that has no primary key column, then you will need to destroy rows manually yourself using a manual query with ConnectionBase.query, or by using the ConnectionBase.destroy method.

  • options?: object

    Most of these options are database/driver specific. However, the following options are common across all database drivers (skipHooks is not supported in this context):

    Option Type Default Value Description
    batchSize number 500 The size of each batch during a multi-model destroy operation.

Return value: Promise<Array<Model> | Model>

If you provide an array of models, then an array of models will be returned. If you provide only a single model, then a single model will be returned.


method ConnectionBase::dirtyFieldHelper(context: DefaultValueContext): any 📜

A connection specific "helper" to force "dirty" fields for all models.

This method, when present on a connection, will assist in defining which fields are "dirty" for a model. It is used, for example, by Types.DATETIME.Defaults.NOW.UPDATED default values. In the case presented, DATETIME fields that should always be updated are always marked dirty by this method, even though they might not actually be "dirty" client-side.

If this method returns any value other than undefined, then the field being operated upon will be marked "dirty" with the value returned, even if the field would otherwise not be marked "dirty".

Arguments:

  • context: DefaultValueContext

    See Field for documentation on the DefaultValueContext interface.

Return value: any

If any value is returned that is not undefined, then the field will be marked "dirty" with the value returned. Return undefined if you do not wish to mark a specific field as "dirty". Note however that the field might actually still be dirty because the user modified the field, in which case this method will not even be called for that field. In short, this method is only called for fields that are not already marked as dirty, and will force a field to be marked dirty if any value other than undefined is returned.


method ConnectionBase::dropColumn(Field: Field, options?: object): any 📜

Drop the specified column/field from the database.

The table/bucket to drop the field from is known by the Model property (model class) on the field itself.

The provided options are specific to the database you are using. Please refer to the documentation of the database driver you are using for more information.

Arguments:

  • Field: Field

    The column/field to drop from the database.

  • options?: object

    Database specific option for the operation. Please refer to the documentation of the database driver you are using for more information.

Return value: any

A database specific return value for the operation completed.


method ConnectionBase::dropIndex(Model: class Model, indexFields: Array<string>, options?: object): Promise<void> 📜

Drop the index from the database based on the specified fields.

This is the exact inverse of ConnectionBase.addIndex, and it functions nearly identically, except that it will drop the specified index instead of creating it.

Arguments:

  • Model: class Model

    The model that owns the specified fields.

  • indexFields: Array<string>

    The field names to used to drop the index. These are used to generate the index name, which will then be dropped.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<void>


method ConnectionBase::dropTable(Model: class Model, options?: object): any 📜

Drop a table/bucket from the database.

This uses the provided Model class to find the table/bucket name to drop, and then will drop it from the underlying database.

The options argument is database specific, but might contain options such as ifExists, or cascade, for example.

Arguments:

  • Model: class Model

    The model to drop from the database. The method Model.getTableName is called on the model class to figure out what table/bucket to drop from the database.

  • options?: object

    Database specific operations for dropping the table/bucket. Please refer to the documentation of the driver you are using for further information.

Return value: any

A database specific return value for the drop table operation.


method ConnectionBase::dropTables(Models: Array<class Model>, options?: object): any 📜

Drop all specified tables/buckets from the database.

This uses the provided Models classes to find the table/bucket names to drop, and then will drop all of them from the underlying database.

The options argument is database specific, but might contain options such as ifExists, or cascade, for example.

The model classes provided are first sorted in "creation order" using the Utils.sortModelNamesByCreationOrder method, and then the tables/buckets are dropped in the reverse order. This is to ensure that any foreign key constraints in play will play nicely with the operation and not throw errors.

This method simply calls ConnectionBase.dropTable for every model provided--after sorting the models based on their foreign keys.

Arguments:

  • Models: Array<class Model>

    All the models to drop from the database. The method Model.getTableName is called on each model class to figure out what table/bucket to drop from the database.

  • options?: object

    Database specific operations for dropping the table/bucket. Please refer to the documentation of the driver you are using for further information.

Return value: any

A database specific return value for the drop tables operation.


method ConnectionBase::ensureAllModelsAreInstances(Model: class Model, models: object | Model | Array<Model | object>, options: object): Array<Model> 📜

This method will ensure all provided "models" are instances of the provided model class.

This method is used by the insert, upsert, and update methods of the connection to ensure every model provided by the user is an actual model instance.

For example, it is perfectly valid to create a model like await Model.create({ ...attributes }). As you can see, the provided "model" is actually just a raw object. Nearly any call in Mythix ORM will accept a raw object in-place of a model instance, and this method is used to ensure all provided "models" are actually model instances.

Arguments:

  • Model: class Model

    The model class to use for instantiating models.

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

    The models to convert to model instances (if needed).

  • options: object

    Options for the operation. This options object is used to pass the startIndex and endIndex (or batchSize) as provided by the user when calling insert, upsert, or update.

Return value: Array<Model>

Return all provided models, converted to model instances. Any provided model that is already a model instance will not be modified, and instead will simply be returned.


method ConnectionBase::escape(field: Field, value: any, options?: object): string 📜

Unlike ConnectionBase._escape --which is a low-level interface for the database-- this method will escape specific values in specific ways needed by Mythix ORM. Said another way, whereas ConnectionBase._escape is a "low level database method", this is a "high level Mythix ORM" method.

If this method is provided a literal, then it will convert the literal into a string, and return the resulting string. This is the purpose of the options argument. The options argument will be passed to the literal's toString method.

For any non-literal value, it is first passed through the field's serialize method, for example value = field.type.serialize(value, thisConnection);. This generally won't modify the incoming value, but it might, for example, with DATE, or DATETIME types, that are modified to match an acceptable format for the underlying database.

If this method is provided a boolean, then it will return an upper-cased version of the boolean as a string, i.e. true will be returned as 'TRUE', and false will be returned as 'FALSE'.

If this method is provided a BigInt, then it will convert the bigint into a string representation of the number, i.e. 42n will be returned as '42'.

If this method is provided an Array value, then the array is processed by the connection-specific prepareArrayValuesForSQL method. By default, this method will complete the following operations on the provided array:

  1. It will flatten the provided array into a 1D array
  2. It will filter the array, such that it removes undefined, and any value that isn't a LiteralBase, a null, a string, a boolean, a number, or a bigint
  3. It will further filter out duplicate values from the array, such that the processed array only contains unique values

After the array is processed with the prepareArrayValuesForSQL method, it will then be mapped such that each value is passed through this escape method, and then all remaining values in the array will be joined with a , character between each element. The idea here is that if you are providing an array to the underlying database, it is usually for an IN or NOT IN operator, so the result will generally be used for one of these. Keep in mind however that each connection driver might escape values (including arrays) differently.

All other provided values are simply handed off to ConnectionBase._escape.

Arguments:

  • field: Field

    The field this value is coming from.

  • value: any

    The value to escape.

  • options?: object

    The options to provide to a Literal's toString method. This options object is only ever used if the provided value is a Literal.

Return value: string

The escaped value, as a string.


method ConnectionBase::escapeID(value: string, options?: object): string 📜

This method is very similar to ConnectionBase._escapeID, except that instead of being a "low level database method" that the database driver itself provides, this is the "Mythix ORM" implementation of escaping identifiers. The only difference from ConnectionBase._escapeID is that if the provided value is a Literal, it will be converted to a string and returned without being escaped. Literals are never modified, and are always provided to the underlying database exactly as they were defined.

Arguments:

  • value: string

    The identifier to escape. If this is a Literal instead of a string, then the Literal will be converted to a string and returned.

  • options?: object

    The options to pass to Literal.toString. This options object is only used if the provided value is a Literal instance.

Return value: string

The escaped identifier, or if value is a Literal, the Literal converted to a string.


method ConnectionBase::exists(query: QueryEngine, options?: object): boolean 📜

Check if any rows match the provided query.

Arguments:

  • query: QueryEngine

    The query used to select rows, to check if said rows exist in the database.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: boolean

true if one or more rows match the provided query, or false otherwise.


method ConnectionBase::finalizeQuery(crudOperation: 'create' | 'read' | 'update' | 'delete', query: QueryEngine, options?: object): QueryEngine 📜

Finalize a query before using it for database operations.

finalizeQuery is called on every query immediately before it is used for a database operation. Its only purpose is to potentially modify the query before the database operation occurs. This can be extremely useful for things like "row level permissions", or ensuring that a certain type of query always has certain conditions.

Because it is asynchronous by design, it is possible to finalize the query using other asynchronous operations; for example validating authentication tokens, or fetching user roles from the database.

It works by walking the provided query, and calling Model.static finalizeQuery on every model it encounters that is used in the query. It will also recursively call itself for every new query it encounters that is part of the query, for example sub-queries. In this way, you can take on extra conditions to any part of a query, throw a "Forbidden" exception if the user is disallowed from querying certain data, or whatever you want.

Notes:

  • "With great power comes great responsibility." Use finalizeQuery intelligently. It can cause a noticeable performance hit, and can really make things hard to debug and understand if you don't clearly document.
  • 'create' isn't actually currently supported, since no queries are ever used in an INSERT operation. It is reserved for future use.

Arguments:

  • crudOperation: 'create' | 'read' | 'update' | 'delete'

    The Mythix ORM reports what "type" of operation is being executed using this argument. This is used so one can know if the operation that is about to be executed is a read, update, or delete operation.

  • query: QueryEngine

    The query to operate upon. This will be walked, calling Model.static finalizeQuery for each unique model encountered, and also recursively walking any sub-queries.

  • options?: object

    Random options for the operation. These are not used by this method, but instead are the options provided to the database operation when it was requested, and are also available for use for any user needs.

Return value: QueryEngine

The query provided, possibly altered.

See also: static Model.finalizeQuery


method ConnectionBase::findModelField(finder: Function): Field | undefined 📜

Find a specific field across all registered models.

This method is similar to Array.find, except that the arguments to this finder method are those provided by Model.iterateFields. If this finder method returns a truthy value for a given field, then that is the field that will be returned.

Notes:

  • This will search for the field across all models registered to the connection. To find a specific field for a known model use Connection.getField instead.

Arguments:

  • finder: Function

    A function to assist in finding the specified field. The signature for this function must match that used by Model.iterateFields.

Return value: Field | undefined

The field found, if any.


method ConnectionBase::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


method ConnectionBase::getDefaultFieldValue(type: Type, context: DefaultValueContext): any 📜

Translate the defaultValue as provided by each models field's into a DEFAULT value for the underlying database.

For example, if you were to specify a defaultValue for one of your models field's, such as defaultValue: Types.INTEGER.Defaults.AUTOINCREMENT, then this method would return a database specific autoincrement default for the column defined by your field. For date/time fields, this might be a database specific NOW() default. For non-database specific "defaults", the default value as defined by your defaultValue on your fields is simply returned.

Arguments:

  • type: Type

    The field's type instance, as defined by the field itself.

  • context: DefaultValueContext

    A DefaultValueContext as is normally provided to all defaultValue methods defined on fields. See the documentation for the defaultValue property of Field for more information.

Return value: any

Your defined field's defaultValue, intercepted, and possibly translated to a proper value for the underlying database. It is common for many database drivers that only date/time and auto-increment default values are intercepted and translated. Most other "default values" are simply returned.


method ConnectionBase::getDefaultOrder(Model: class Model, options: object): Array<string> 📜

Get the default order for selecting rows from the database. The connection driver itself might specify a default order for each table, if one isn't specified by the user.

Notes:

Arguments:

  • Model: class Model

    The model/table to fetch the default order for.

  • options: object

    Operation specific options (i.e. options for a "select" call)

Return value: Array<string>

An array of fully qualified field names for this model should be returned by this method. An empty array, null, or undefined are also valid return values (in which case no order will be applied to the given operation).


method ConnectionBase::getField(fieldName: string, modelName?: string): Field 📜

Get a field by its fully qualified name, or by a fieldName + a modelName.

Arguments:

  • fieldName: string

    Fully qualified field name. If a fully qualified field name isn't provided, then you must provide the modelName argument.

  • modelName?: string

    The name of the model that the field exists on. This argument is optional if the provided fieldName is a fully qualified name.

Return value: Field

The field found, or undefined if the specified field is not found.


method ConnectionBase::getLockMode(options: any): object 📜

This method is an internal method that parses the "lock mode" options passed to a call to Connection.transaction.

These might be different depending on the connection driver you are using. Please refer to the documentation for your connection driver for more details.

Arguments:

  • options: any

    Possibly connection specific lock options for a connection's Connection.transaction method. Generally this will either be a true value, a Model name (for which table to lock), or a complete lock options object, which generally will look something like: { lock: boolean; modelName: string; read: boolean; write: boolean }

    lock - If true, then lock the transaction
    modelName - The name of the table(s) to lock
    read - If true, then lock for reads
    write - If true, then lock for writes.

Return value: object

Return the lock options for a transaction. These might change based on the connection driver you are using, but will generally look like { lock: boolean; modelName: string; read: boolean; write: boolean }.

  1. lock - If true, then lock the transaction
  2. modelName - The name of the table(s) to lock
  3. read - If true, then lock for reads
  4. write - If true, then lock for writes.

method ConnectionBase::getModel(modelName: string): class Model 📜

Retrieve a single model by its name. The model must be registered with this connection to be found.

Models can be registered to a connection with the ConnectionBase.registerModel or ConnectionBase.registerModels methods.

This method is "fully qualified aware", meaning you can pass a fully qualified name, such as "User:id" and it will fetch the "User" model.

Arguments:

  • modelName: string

    The model's name, or a fully qualified field name.

Return value: class Model

The model class found by the model's name, or undefined if no model is found.


method ConnectionBase::getModels(): object 📜

Get all models known to this connection. Models are returned as a raw Object, and so can be destructured. The keys of the returned object are the model's names.

Models can be registered to a connection with the ConnectionBase.registerModel or ConnectionBase.registerModels methods.

Return value: object

An object of all models known to the connection, where each key is a model name, and each property value is the model's class.


method ConnectionBase::getOptions(): object 📜

Get the options for this connection.

These will be the options provided to the connection during creation, plus any other options the connection driver itself internally sets.

Return value: object

The options for this connection.


method ConnectionBase::getQueryEngineClass(): class QueryEngine 📜

Return the QueryEngine class used for this connection, all its models, and all query operations. By default this is just the built-in QueryEngine that Mythix ORM provides. You can create your own, and provide it as the QueryEngine option to the connection when you create the connection.

Return value: class QueryEngine

The QueryEngine to use for this connection, all its models, and all query operations for this connection.


method ConnectionBase::getQueryGenerator(): QueryGenerator | null 📜

Get the QueryGenerator instance for this connection, if it has one.

All connection drivers may not have a query generator. The query generator is the class that takes care of generating queries for the underlying database (i.e. SQL). If a query generator exists on a connection, it is very likely to be unique to the connection (i.e. PostgreSQL and MySQL have different query generators).

Return value: QueryGenerator | null

Return the QueryGenerator for this connection, or return null if none is defined for this connection.


method ConnectionBase::insert(Model: class Model, models: Array<Model | object> | object | Model, options?: object): Promise<Array<Model> | Model> 📜

Insert the specified models into the specified table/bucket (based on the provided Model).

This will insert one or more models into the database. Like nearly all such Mythix ORM methods, bulk operations are supported out-of-the-box. You can provide a single model to models, or you can provide an array of models.

The provided "models" can be either an object, an array of objects, a model instance, or an array of model instances, or a mix of both. Mythix ORM will ensure any provided raw objects are first converted into model instances using the provided Model before it inserts anything.

You can also supply "sub models", and those will also be inserted in the correct order (and any foreign keys will also be updated for you). For example, if you have a User model that has a virtual Type.Model primaryRole field, then you can supply a new Role model upon insertion and Mythix ORM will handle this properly for you. For example: await connection.insert(User, new User({ primaryRole: new Role({ ... }) })). This type of sub model save also works on through-tables. If primaryRole was targeting a Role model, but through another table(s), then Mythix ORM will also create the through-table relationships (if it is able to).

This will not work for Types.Models (multi-relations). Mythix ORM doesn't know what you intend for multi-relations (overwrite the set? add to the set? what?) so it will deliberately skip multi-relational fields. "sub models on insert" only work for single-relation fields defined with Types.Model. For multi-relation fields you must manually work through the relation yourself. For example, if our user instead had a Types.Models roles field (plural), then you would instead need to:

Example:

  • let user = await connection.insert(User, new User({ ... }));
    let role = await connection.insert(Role, { ... }); // model instance is not required
    await user.addToRoles(role);

Arguments:

  • Model: class Model

    The model class used for the operation. This defines what table/bucket to insert the specified models into.

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

    The model(s) to insert into the database. If raw objects are provided, then the properties of each object must match the required attributes for the model class.

  • options?: object

    Most of these options are database/driver specific. However, the following options are common across all database drivers:

    Option Type Default Value Description
    skipHooks boolean | object undefined Skip specific hooks. See ConnectionBase.runSaveHooks for more information.
    batchSize number 500 The size of each batch during a multi-model insert operation.

Return value: Promise<Array<Model> | Model>

If you provide an array of models, then an array of models will be returned. If you provide only a single model, then a single model will be returned. If you provided "sub models" then those will be returned as "related models" on the primary model. For example, using the above User example, the newly created Role model that was stored for the primaryRole would be available on the returned User model as user.Roles[0], or you could also access it via the field you set it on user.primaryRole.


method ConnectionBase::isLimitSupportedInContext(options: object): boolean 📜

This method is called (and often provided) by the underlying database driver to see if a LIMIT clause is allowed to appear in a given context/operation.

Arguments:

  • options: object

    Driver specific options for the context.

Return value: boolean


method ConnectionBase::isOrderSupportedInContext(options: object): boolean 📜

This method is called (and often provided) by the underlying database driver to see if an ORDER BY clause is allowed to appear in a given context/operation.

Arguments:

  • options: object

    Driver specific options for the context.

Return value: boolean


method ConnectionBase::isStarted(): boolean 📜

Check to see if start has already been called on this connection. This is used to know if a connection is "active" or not.

Return value: boolean


method ConnectionBase::literalToString(literal: LiteralBase, options?: object): string 📜

Convert the provided Literal to a string for the underlying database driver. The conversion will be database specific. The database driver connection is free to override this method.

This method will convert a AverageLiteral, a CountLiteral, a DistinctLiteral, a FieldLiteral, a MaxLiteral, a MinLiteral, a SumLiteral, or a Literal to a string. If the provided literal is not one of these types, than an exception will be thrown.

If you want to add custom literals to your application, then you will need to overload this method, and handle those custom literals manually (or simply stick to using Literal).

Arguments:

  • literal: LiteralBase

    The literal to convert.

  • options?: object

    Optional options that can be passed to the literal conversion method. These are generally not provided by the user, but rather are often provided by the connection itself, for context-specific literal conversions. These options can and will changed based on the literal being converted, and the underlying connection.

Return value: string

The provided literal, converted to a string for the underlying database driver.


method ConnectionBase::max(query: QueryEngine, field: Field | string, options?: object): Promise<number> 📜

Get the maximum value for a column, spanning all matching rows.

This will return the maximum of all values in a column, across all matching rows, as a number primitive.

Arguments:

  • query: QueryEngine

    The query used to select which rows are used to calculate the maximum.

  • field: Field | string

    A field instance, or a fully qualified field name, used as the target column in the underlying database to find the maximum across all matching values.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<number>

The maximum value found across all matching rows.


method ConnectionBase::min(query: QueryEngine, field: Field | string, options?: object): Promise<number> 📜

Get the minimum value for a column, spanning all matching rows.

This will return the minimum of all values in a column, across all matching rows, as a number primitive.

Arguments:

  • query: QueryEngine

    The query used to select which rows are used to calculate the minimum.

  • field: Field | string

    A field instance, or a fully qualified field name, used as the target column in the underlying database to find the minimum across all matching values.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<number>

The minimum value found across all matching rows.


method ConnectionBase::parseQualifiedName(fieldName: string): object 📜

This is simply a convenience method that calls ModelUtils.parseQualifiedName.

Arguments:

Return value: object

The result. See ModelUtils.parseQualifiedName for more information.

See also: ModelUtils.parseQualifiedName


method ConnectionBase::pluck(query: QueryEngine, fields: Field | string | Array<Field> | Array<string>, options?: object): Array<any> | Array<Array<any>> | Array<object> 📜

Pluck only specific columns/fields from the underlying database, using the provided query.

This method will return only the specified fields from the database--as raw values--from rows matched on by the provided query.

This method is often much faster than a normal select operation, in that only the data requested will be transmitted from the database, and models won't be constructed and stitched together on load. Use this when you just need an "array of values" across certain columns from a table.

Arguments:

  • query: QueryEngine

    The query used to select rows from which columns will be plucked.

  • fields: Field | string | Array<Field> | Array<string>

    Which fields to "pluck" from the matching rows. If an array is provided (even if it only contains a single field), then an array of arrays will be returned as the result. If a single field is provided (not an array), then an array of raw plucked column values will be returned instead.

  • options?: object

    Operation specified options. These might change based on the database driver you are using, so please refer to your specific database driver documentation. One option that is common across all drivers is the mapToObjects boolean option. If true, then each row in the returned array will be an object instead of raw column values, where the property of each "row object" will be the fully qualified names of each field provided as the fields argument.

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

If the provided fields argument is an array of fields (fully qualified field names, or Field instances), then the result will be an array of arrays, where each item in the top-level array is a "row", and each sub-array is the values for the columns (fields) specified. If a single field is specified, then an one dimensional array is returned, where each item is the column value for each row fetched. For example, if we call pluck like: let result = await connection.pluck(User.where.firstName.EQ('Bob'), 'User:id') then the result would look like [ 'USER_id_1, USER_id_2, ... ]where each value in the array is a user id. If however we call pluck like:let result = await connection.pluck(User.where.firstName.EQ('Bob'), [ 'User:id', 'User:firstName' ])then theresultwould look like[ [ 'USER_id_1', 'Bob' ], [ 'USER_id_2', 'Bob' ], ... ], because the provided fieldsis an array, an array of field values will be returned from each row. If theoption mapToObjectsistrue, then an array of objects will be returned, where each object is a "row", and each property one of the specified fields. Note that the properties of each returned object will be the fully qualified field name of each field specified. So, for example, specifying a pluck field of User:idmeans that each returned object in the array will look like[ { 'User:id': 'USER_id_1' }, { 'User:id': 'USER_id_2' }, ... ]`.


method ConnectionBase::prepareAllModelsAndSubModelsForOperation(Model: class Model, models: object | Model | Array<Model | object>, options?: object): Map<string, Set<Model>> 📜

Recursively prepare all models for a persisting operation while also splitting each model out into its own separate list, and finally sorting the models based on insertion order.

This method will use ConnectionBase.splitModelAndSubModels to split provided models out into their own separate space. See this method for a better explanation of what this means.

It will also assign any foreign key values across models that it is able to. For example, in the example provided in the documentation for ConnectionBase.splitModelAndSubModels, we had new User({ primaryRole: new Role({ name: 'admin' }) }), where the Role model is being persisted (as a child of User) at the same time the User is being persisted. If Role has a generated id, such as one of the UUID or XID types, then in our example here the primaryRoleID of the User could be set before User is persisted, saving an extra query to the database to update this foreign key after Role is persisted. In short, this method will also assign any foreign key values that it already has before persisting any models.

Finally, after it has "prepared" the models, and split all models into their own space, it will sort the resulting Map such that the models are in the correct order for insertion. In the example we have been using, if User has a primaryRoleID that is a foreign key, then it might require a non-null value before the User model can be persisted. Because of this, it is important that the Role model is stored first, so that we have the value we need for this primaryRoleID foreign key. This is why the models are sorted in what is known as "creation order", or "insertion order". This order is defined by the foreign keys themselves. Mythix ORM will walk all foreign keys involved in the operation, and decide based on these what the "creation order" should be. If you have two models that both have foreign keys pointing to each other, then the sort order is undefined. If this is the case, the work-around is to simply manually persist your models in the correct order (i.e. save Role first, and then supply the foreign key to User yourself from the result).

Arguments:

  • Model: class Model

    The model class of the primary model being persisted. The primary model could also be called the "root model". In our example above the primary model is User.

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

    The models to prepare. Any model that is a "raw object" will be instantiated into the Model class provided. Any "sub models" will be split into their own space in the resulting Map.

  • options?: object

    Optional options to supply to this operation. This options object isn't used by Mythix ORM, but is provided in case any driver specific connection needs them when overloading this model. These options come from the options provided to a database operation, such as the options provided to an insert, upsert, or update call.

Return value: Map<string, Set<Model>>

The models processed, and put into their own named Set. The keys for the Map are the names of the models themselves.


method ConnectionBase::prepareAllModelsForOperation(Model: class Model, models: object | Model | Array<Model | object>, options: object): PreparedModels 📜

This method will prepare all provided models for an insert, upsert, or update operation.

What it does is ensure every provided model is a model instance, checks if the model is persisted, and if each model has dirty fields.

Models that are persisted and not dirty will be filtered out, so that proceeding operations will "ignore" them entirely.

All dirty fields across all models are combined into a unified list of dirty fields. This unified list is then used for the list of columns in an insert, upsert, or updateAll operation.

Arguments:

  • Model: class Model

    The model class to use for preparing the provided models. All models provided must be of this model type.

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

    The models to prepare. Any model that is a "raw object" will be instantiated into the Model class provided.

  • options: object

    Options for the operation. These include startIndex, endIndex (or batchSize) for batch operations, and skipPersisted, isUpdateOperation, or isInsertOperation for other context-specific operations.

Return value: PreparedModels

Return an object with the shape { models: Array<Model>, dirtyFields: Array<Field>, dirtyModels: Array<Model> } which is known to Mythix ORM as "prepared models". Mythix ORM can understand "prepared models" verses simple "models" in most contexts. PreparedModels are often passed around after first receiving models from the user, so as not to "prepare" them more than once.


method ConnectionBase::query(sql, options): database specific 📜

"raw" database/driver specific query interface.

For SQL based databases, this would send a direct query string to the database. For other drivers, the arguments and operations that are executed might change.

Use this method to directly interact with the underlying database, in its own native query language.

The arguments and return value from this method is database/driver specific. Any options argument the database provides are also specific to the underlying database driver. However, one option is common across all drivers, and this is the logger option. If set, it is expected to have a log method in the provided logger object. Oftentimes, this will simply be { logger: console }, but you can provided any custom logger instance you want, as long as it has a log method that can be called to log the results of the query. Most drivers also support a { logger } option as a connection option when the connection is first instantiated, which will provided logging to every query that goes through the connection.

Arguments:

  • sql
  • options

Return value: database specific

A database/driver specific return value, based on the query provided.


method ConnectionBase::registerModel(Model: class Model, options?: object): class Model 📜

Register the provided model class.

This will register the provided model class with this connection. The model must not already be bound to another connection, or you must specify the option { forceConnectionBinding: true } if it is. You can specify the option of { bindModels: false } if you don't wish to bind this model to this connection.

Any options provided are optional, and will override the same options provided to the connection itself when it was created.

Arguments:

  • Model: class Model

    The model class to register with this connection. If not bound, then it will simply exist in the model pool for this connection. If bound, then this connection will bind itself to the model being registered.

  • options?: object

    Options looks like { forceConnectionBinding: boolean; bindModels: boolean; }. This is an optional argument. Both options will default to the same options provided to the connection when it was created. If you specify either of these options they simply override the connection's default.

Return value: class Model

The registered model class, which may have changed during registration. It is not uncommon for the connection driver itself to modify the model class, or to return a new model class that inherits from your model class. The class that is returned should be the class that you use for this connection, and will be the same class returned by a call to Connection.getModel, or Connection.getModels.


method ConnectionBase::registerModels(Model: Array<class Model> | { [key: string]: class Model }, options?: object): class Model 📜

Register multiple models at the same time.

This will register the provided models with this connection. The models provided must not already be bound to another connection, or you must specify the option { forceConnectionBinding: true } if any of them are. You can specify the option of { bindModels: false } if you don't wish to bind these models to this connection.

Any options provided are optional, and will override the same options provided to the connection itself when it was created.

Arguments:

  • Model: Array<class Model> | { [key: string]: class Model }

    The model classes to register with this connection. If no models are bound, then they will simply exist in the model pool for this connection. If bound, then this connection will bind itself to every model being registered.

  • options?: object

    Options looks like { forceConnectionBinding: boolean; bindModels: boolean; }. This is an optional argument. Both options will default to the same options provided to the connection when it was created. If you specify either of these options they simply override the connection's default.

Return value: class Model

The registered model classes, which may have changed during registration. It is not uncommon for the connection driver itself to modify the model classes, or to return a new model classes that inherit from your model classes. The classes that are returned should be the classes that you use for this connection, and will be the same classes returned by a call to Connection.getModel, or Connection.getModels.


method ConnectionBase::runSaveHooks(Model: class Model, models: Array<Model>, operationHookName: 'onBeforeCreate' | 'onBeforeUpdate' | 'onAfterCreate' | 'onAfterUpdate', saveHookName: 'onBeforeSave' | 'onAfterSave', options: object): Promise<Array<any>> 📜

Run model hooks by name.

This method will run the hooks for a model instance. operationHookName will be one of onBeforeCreate, onBeforeUpdate, onAfterCreate, or onAfterUpdate.

operationHookName will be one of onBeforeSave, or onAfterSave. The idea is that any of the onBefore* operations will always be followed by an onBeforeSave, whereas the onAfter* operations are all followed by an onAfterSave.

Notes:

  • Hooks for models are run serially for a given model, but all model hooks are run in parallel across all models.
  • The onValidate hook is called from the onBeforeSave hook itself. This is so that the user can decide if model validations should be ran or not (simply by calling this.onValidate themselves... or not). If you overload the onBeforeSave method, make certain you call super.onBeforeSave.apply(this, arguments) (or this.onValidate.apply(this, arguments) directly), because if you don't your model validations will be skipped.

Arguments:

  • Model: class Model

    The model class we are running hooks for. All models provided should be instances of this class.

  • models: Array<Model>

    All model instances to run hooks on. These should all be instances of the provided Model class.

  • operationHookName: 'onBeforeCreate' | 'onBeforeUpdate' | 'onAfterCreate' | 'onAfterUpdate'

    The hook to call (if not skipped by the skipHooks option).

  • saveHookName: 'onBeforeSave' | 'onAfterSave'

    The name of the save hook to call after the operation hook has completed (if not skipped by the skipHooks option).

  • options: object

    Options for the operation being completed. For example, if this is an insert operation, then these "options" will be the options for the insert operation. One other useful option that can be supplied here is the skipHooks: boolean | { [key: 'onBeforeCreate' | 'onBeforeUpdate' | 'onAfterCreate' | 'onAfterUpdate' | 'onBeforeSave' | 'onAfterSave' ]: boolean; } option. If this is true, then all hooks will be bypassed (not called). If this is an object, then each key should be a hook name, and if it has a true value, then that specific hook will be bypassed (not called). This allows the caller of an operation such as insert, or update to request that specific hooks not be called.

Return value: Promise<Array<any>>

The result of all model hooks. Mythix ORM ignores the return value from model hooks, but it collects them and returns them for the user.


method ConnectionBase::select(query: QueryEngine, options?: object): AsyncGenerator<Model> 📜

Select data from the underlying database.

To select data from the database you will use this method, providing a query as a QueryEngine instance. The provided query will be used to generate the underlying request to the database, will collect the response, and return the results to the caller.

This method is an async generator method, and is designed for "streaming" results from the database, one "row" at a time. Many methods that call this method (such as QueryEngine.all) collect all the results from the async generator to return an array of results to the caller. This is because it is often tedious to collect the results yourself from the async generator, and often the caller simply wants a small amount of data from the database. However, if you intend to fetch large amounts of data from your database, it is a good idea to call this method directly, and iterate the results of the async generator manually. All methods that in-turn call this method (such as QueryEngine.all) will generally have a { stream: true } option that can be provided, causing the method to return the async generator, instead of the collected results.

Arguments:

  • query: QueryEngine

    The query to run against the underlying database. This is generated from a QueryEngine interface. The result of this QueryEngine instance will then be converted to a query, or generated code to interact with the underlying database.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: AsyncGenerator<Model>


method ConnectionBase::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


method ConnectionBase::setPersisted(models: Array<Model> | PreparedModels, value): undefined 📜

Mark all models provided as "persisted".

Every Mythix ORM model instance has a non-enumerable property _persisted. If this is true, then Mythix ORM will treat the model as persisted.

This method iterates all provided models, and marks each as persisted by setting this _persisted property to true. For each model iterated, this method checks if the instance property _mythixModelInstance is true. If this is not the case, then that instance (whatever it is) will be silently skipped.

Arguments:

  • models: Array<Model> | PreparedModels

    Models to mark as persisted.

  • value

    If true, models will be marked as persisted. If false, models will be marked as not-persisted.

Return value: undefined

This method modifies models directly, and returns nothing.


method ConnectionBase::setQueryGenerator(queryGenerator: QueryGenerator | null): undefined 📜

Set the QueryGenerator instance for this connection. This is rarely used as the QueryGenerator is often supplied as connection options when creating the connection (as the queryGenerator option). However, it can be set to a new instance at any time with this method.

Arguments:

  • queryGenerator: QueryGenerator | null

    The new QueryGenerator instance to use for generating underlying database queries. Set to null to specify no query generator (note: this might break whatever connection you are using as most connections require their query generator).

Return value: undefined


method ConnectionBase::splitModelAndSubModels(Model: class Model, primaryModel: Model, _relationMap?: Map<string, Set<Model>>): Map<string, Set<Model>> 📜

Recursively walk all provided models and split models into a map of model name and model instances.

This method is used to split apart provided models by the user. For example, it is fully valid to provide "sub models" during most persisting operations, such as new User({ primaryRole: new Role({ name: 'admin' }) }).

This method would find the sub model "Role" in the above example, and split it out to be processed separately in the persisting operation.

Arguments:

  • Model: class Model

    The model class of the primary model being scanned. The primary model could also be called the "root model". In our example above the primary model is User.

  • primaryModel: Model

    The model instance to scan for "sub models". In the example above this would be User (though Role itself will also be passed through this method to check if it also has any sub models).

  • _relationMap?: Map<string, Set<Model>>

    This argument is provided internally while recursing, and should not be provided unless you know exactly what you are doing.

Return value: Map<string, Set<Model>>

Return a map of all models found, where the model name is the key for the Map, and each model instance is added to the Set for that key. Using the above example, the return value would be: new Map({ User: new Set([ user ]), Role: new Set([ role ]) }).


method ConnectionBase::stackAssign(obj: object): object 📜

An Object.assign type of operation... with a twist.

stackAssign works kinda like Object.assign. It has the same interface, and accomplishes the same result. What it does differently however is that it uses Object.create on the first argument to create a new object, using the first argument as a prototype. It then merges all remaining object arguments into this newly created object.

This is used quite heavily in the underlying Mythix ORM engine. It's purpose is to modify options arguments as they pass through the engine. For example, a destroy operation might want to inform the projection engine that we don't want any field aliases... and so it will stackAssign the options, setting noProjectionAliases: true for the "stacked options" object. Javascript--being the prototypical language that it is--will behave like the objects in question have been passed through Object.assign, because all the original options to any operation are still accessible in the prototype, but may have been overridden like in our example of a destroy operation. This allows the engine to easily and quickly override options without mutating the original options object provided, and still be able to access provided options, even if they are not enumerable.

Arguments:

  • obj: object

    The object to set as the prototype of the newly created object, using Object.create on it. ...args: Array The other objects to merge into this object, using Object.assign.

Return value: object

The newly "stacked" and merged object.


method ConnectionBase::start(): Promise<void> 📜

Start this connection.

The default implementation will throw an exception.

Every connection is expected to overload this and provide connection specific startup code (such as connecting to the database).

Return value: Promise<void>


static method ConnectionBase::getLiteralClassByName(name: string): class LiteralBase 📜

Fetch a literal class by its name.

The following is a table that displays the name argument that can be provided, and the resulting Literal class that would be returned for that name.

name Resulting literal class
'Average' AverageLiteral
'Base' LiteralBase
'Count' CountLiteral
'Distinct' DistinctLiteral
'Field' FieldLiteral
'FieldBase' LiteralFieldBase
'Literal' Literal
'Max' MaxLiteral
'Min' MinLiteral
'Sum' SumLiteral

Arguments:

  • name: string

    The name of the literal class to return.

Return value: class LiteralBase

Return the literal class requested.


static method ConnectionBase::isConnection(value: any): boolean 📜

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

Arguments:

  • value: any

    Value to check.

Return value: boolean


static method ConnectionBase::isConnectionClass(value: Function): boolean 📜

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

Arguments:

  • value: Function

    Value to check.

Return value: boolean


static method ConnectionBase::Literal(name: string): LiteralBase 📜

Create the literal specified by name.

Whereas ConnectionBase.static getLiteralClassByName will simply return the literal class specified, this will create the specified literal, with the provided arguments.

Please see ConnectionBase.static getLiteralClassByName for possible names that can be provided as the name argument.

Arguments:

Return value: LiteralBase

Return an instance the literal requested, using the arguments specified.

See also: static ConnectionBase.getLiteralClassByName


method ConnectionBase::stop(): Promise<void> 📜

Stop (shutdown) this connection.

The default implementation will throw an exception.

Every connection is expected to overload this and provide connection specific shutdown code (such as disconnecting from the database).

Return value: Promise<void>


method ConnectionBase::sum(query: QueryEngine, field: Field | string, options?: object): Promise<number> 📜

Get the sum of all values for a column, spanning all matching rows.

This will return the sum of all values in a column, across all matching rows, as a number primitive.

Arguments:

  • query: QueryEngine

    The query used to select which rows are used to calculate the sum.

  • field: Field | string

    A field instance, or a fully qualified field name, used as the target column in the underlying database to find the sum of all matching values.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<number>

The sum of all values found across all matching rows.


method ConnectionBase::toQueryEngine(value: any): QueryEngine | undefined 📜

This will take something that can be turned into a query and turn it into a query.

If a QueryEngine instance is provided, it will simply be returned.

If a Model is provided, then Model.where will be returned, returning a QueryEngine for the model provided.

In the future this may also accept other possible values that could be turned into a query.

This is often internally called by methods of the connection on a given argument provided by the user, which could validly be either a model or a query. Connection.destroyModels is one example of this.

Arguments:

  • value: any

    The value to attempt to turn into a QueryEngine.

Return value: QueryEngine | undefined


method ConnectionBase::transaction(callback: (connection: Connection) => any, options?: object): Promise<any> 📜

Initiate a transaction (or snapshot/sub-transaction) if the database driver supports transactions.

This will initiate a transaction in the underlying database, if the database supports it. For SQL type databases this would be a BEGIN/COMMIT/ROLLBACK block. If this method is called when a transaction is already in-progress, then a snapshot/sub-transaction will be started instead.

This method will start a transaction in the underlying database, and call the provided asynchronous callback. If the callback throws an error, then the transaction (or snapshot) will be automatically rolled-back. There is a single connection argument that will be provided to the callback function when called. This connection argument will be the transaction connection itself, which for many database drivers is simply the same connection the transaction was started from. At a lower-level, Mythix ORM will use an AsyncLocalStorage context to provide the transaction connection to all code executed inside the callback, so the provided connection argument can generally be ignored. However, if AsyncLocalStorage isn't supported in your environment, or the specific driver you are using requires that you use the supplied connection argument, then you must use the supplied connection for all your operations, and provide it as the { connection } option to all Mythix ORM calls made inside the callback.

Arguments:

  • callback: (connection: Connection) => any

    The async callback to call for the transaction operation. This should return as quickly as possible to avoid deadlocks in the underlying database. Whatever value this method returns will be the return value from the transaction call itself. If an exception is thrown in this method, then the transaction will be automatically rolled-back. If no exception is thrown from this method, then when done executing, a COMMIT will be sent to the underlying database automatically for you.

  • options?: object

    Optional database specific options to supply for the transaction operation. There are two options that are supported across most database drivers, and those are connection and lock. The connection option supplies the the connection to initiate the transaction from, which for example might be another transaction connection (initiating a sub-transaction). If no connection option is supplied, then the connection this method was called from is used instead. The second common option is lock, which specifies how/if to lock the table for the transaction. See ConnectionBase.getLockMode for your specific driver for more information on this lock option.

Return value: Promise<any>

Return whatever return value is returned from the provided callback.


method ConnectionBase::truncate(Model: class Model, options?: object): Promise<void> 📜

Truncate (erase/clear) the entire table/bucket defined by the provided Model. All rows/objects from the underlying table/bucket will be destroyed, leaving you with an empty table/bucket.

Arguments:

  • Model: class Model

    The model class that defines the underlying table/bucket to wipe clean/erase.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<void>


method ConnectionBase::typeToString(type: Type, options?: object): string 📜

Convert any field type to the type needed for the underlying database driver. Only built-in Mythix ORM fields are supported. If a custom field type that is not supported is provided then an exception will be thrown.

If you need to support a custom field type, simply subclass the connection you are using, and overload this method to handle your custom field types.

Arguments:

  • type: Type

    The field type to convert to use in the underlying database.

  • options?: object

    Optional options to pass to the underlying conversion method.

Return value: string

The field type needed by the underlying database driver.


method ConnectionBase::update(Model: class Model, models: Array<Model | object> | object | Model, options?: object): Promise<Array<Model> | Model> 📜

Update the specified models in the database.

Many databases don't have good (or even decent) support for bulk updates, so unfortunately this method is fairly slow, and will usually make a query to the database for each model updated.

If you want to update many models at the same time (using the same attributes across all models), then consider using the ConnectionBase.updateAll method instead.

Notes:

  • Models will only be updated if they are dirty. Also, only the dirty attributes for each model will be updated (some attributes are always dirty, for example updatedAt fields are forced to always be dirty based on the configuration of their defaultValue).

Arguments:

  • Model: class Model

    The model class used for the operation. This defines what table/bucket to update.

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

    The model(s) to update in the database. If raw objects are provided, then the properties of each object must match the required attributes for the model class.

  • options?: object

    Most of these options are database/driver specific. However, the following options are common across all database drivers:

    Option Type Default Value Description
    skipHooks boolean | object undefined Skip specific hooks. See ConnectionBase.runSaveHooks for more information.
    batchSize number 500 The size of each batch during a multi-model update operation.

Return value: Promise<Array<Model> | Model>

If you provide an array of models, then an array of models will be returned. If you provide only a single model, then a single model will be returned.


method ConnectionBase::updateAll(query: QueryEngine, attributes: object | Model, options?: object): Promise<any> 📜

Update multiple models at the same time (bulk update).

This will update multiple models at the same time using the provided query to select which models to update. All matching rows will set the provided attributes upon them.

The provided attributes can be a model instance, or a raw object. If a raw object is provided, then they will be converted into a model instance using the provided Model class. This also means that you can only bulk update columns/fields that exist on the model itself (i.e. you might have other columns in your table not related to this model, and those can not be updated using this method).

Notes:

  • As always with Mythix ORM, you will never supply raw column names as the attributes. You must always provide model field names in Mythix ORM.
  • This will be an update operation across all matching rows, using the data provided. This method is really only useful when you want to update multiple rows to the same values. If you need to update each row to different values per-row, then use the ConnectionBase.update method instead.

Arguments:

  • query: QueryEngine

    The query used to select which models/rows to update. The "root model" of the query is the table/bucket that will be updated.

  • attributes: object | Model

    The attributes to set across all updated rows.

  • options?: object

    Operation specific options. These will change depending on the database driver you are using. Please refer to the documentation for your specific driver for more information.

Return value: Promise<any>

A database specific result from the UPDATE statement. In the future all "database specific" results will be abstracted away. So in the future, this will likely return the number of rows updated as a number (HELP WANTED).


method ConnectionBase::upsert(Model: class Model, models: Array<Model | object> | object | Model, options?: object): Promise<Array<Model> | Model> 📜

Insert or update (upsert) models into the database.

This method is only supported by some databases. Database drivers that don't support upsert natively may attempt to emulate the operation (at the cost of speed).

This method should function identically to ConnectionBase.insert, with the exception that it should update rows that already exist in the database instead of inserting new rows.

Arguments:

  • Model: class Model

    The model class used for the operation. This defines what table/bucket to insert the specified models into.

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

    The model(s) to insert into the database. If raw objects are provided, then the properties of each object must match the required attributes for the model class.

  • options?: object

    Most of these options are database/driver specific. However, the following options are common across all database drivers:

    Option Type Default Value Description
    skipHooks boolean | object undefined Skip specific hooks. See ConnectionBase.runSaveHooks for more information.
    batchSize number 500 The size of each batch during a multi-model upsert operation.

Return value: Promise<Array<Model> | Model>

If you provide an array of models, then an array of models will be returned. If you provide only a single model, then a single model will be returned. If you provided "sub models" then those will be returned as "related models" on the primary model. For example, using the above User example, the newly created Role model that was stored for the primaryRole would be available on the returned User model as user.Roles[0], or you could also access it via the field you set it on user.primaryRole.

See also: ConnectionBase.insert



Clone this wiki locally