Skip to content

ConnectionBase

Wyatt Greenway edited this page Oct 12, 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.


property ConnectionBase::dialect: string

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


static property ConnectionBase::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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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)[https://www.npmjs.com/package/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::_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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

Return value: string

The field type needed by the underlying database driver.


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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

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. eslint-disable-next-line no-unused-vars.

Return value: string

The field type needed by the underlying database driver.


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 destroyAll. 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::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::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::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::getDefaultOrder(Model: class Model, options: object): Array<string>

Get the default order for selecting rows from the database. This will call the Model's Model.defaultOrder method first to see if the model specifies a default order for itself. If it doesn't, then the connection driver itself might specify a default order for each table.

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::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::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::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. eslint-disable-next-line no-unused-vars.

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::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::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::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::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.destroyAll is one example of this.

Arguments:

  • value: any

    The value to attempt to turn into a QueryEngine.

Return value: QueryEngine | undefined


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.



Clone this wiki locally