@adonisjs/lucid
Version:
SQL ORM built on top of Active Record pattern
551 lines (550 loc) • 20.2 kB
TypeScript
/// <reference path="../../../adonis-typings/index.d.ts" />
import { Hooks } from '@poppinss/hooks';
import { IocContract } from '@ioc:Adonis/Core/Application';
import { QueryClientContract, TransactionClientContract } from '@ioc:Adonis/Lucid/Database';
import { LucidRow, CacheNode, LucidModel, CherryPick, EventsList, ModelObject, HooksHandler, ModelOptions, ColumnOptions, ComputedOptions, AdapterContract, CherryPickFields, ModelColumnOptions, ModelKeysContract, ModelAssignOptions, ModelAdapterOptions, ModelRelationOptions, ModelRelations, RelationOptions, RelationshipsContract, ThroughRelationOptions, ManyToManyRelationOptions } from '@ioc:Adonis/Lucid/Orm';
import { SnakeCaseNamingStrategy } from '../NamingStrategies/SnakeCase';
import { LazyLoadAggregates } from '../Relations/AggregatesLoader/LazyLoad';
/**
* Abstract class to define fully fledged data models
*/
export declare class BaseModel implements LucidRow {
/**
* The adapter to be used for persisting and fetching data.
*
* NOTE: Adapter is a singleton and share among all the models, unless
* a user wants to swap the adapter for a given model
*/
static $adapter: AdapterContract;
/**
* Naming strategy for model properties
*/
static namingStrategy: SnakeCaseNamingStrategy;
/**
* The container required to resolve hooks
*
* NOTE: Container is a singleton and share among all the models, unless
* a user wants to swap the container for a given model
*/
static $container: IocContract;
/**
* Primary key is required to build relationships across models
*/
static primaryKey: string;
/**
* Whether or not the model has been booted. Booting the model initializes it's
* static properties. Base models must not be initialized.
*/
static booted: boolean;
/**
* Query scopes defined on the model
*/
static $queryScopes: any;
/**
* A set of properties marked as computed. Computed properties are included in
* the `toJSON` result, else they behave the same way as any other instance
* property.
*/
static $computedDefinitions: Map<string, ComputedOptions>;
/**
* Columns makes it easier to define extra props on the model
* and distinguish them with the attributes to be sent
* over to the adapter
*/
static $columnsDefinitions: Map<string, ModelColumnOptions>;
/**
* Registered relationships for the given model
*/
static $relationsDefinitions: Map<string, RelationshipsContract>;
/**
* The name of database table. It is auto generated from the model name, unless
* specified
*/
static table: string;
/**
* Self assign the primary instead of relying on the database to
* return it back
*/
static selfAssignPrimaryKey: boolean;
/**
* A custom connection to use for queries. The connection defined on
* query builder is preferred over the model connection
*/
static connection?: string;
/**
* Storing model hooks
*/
static $hooks: Hooks;
/**
* Keys mappings to make the lookups easy
*/
static $keys: {
attributesToColumns: ModelKeysContract;
attributesToSerialized: ModelKeysContract;
columnsToAttributes: ModelKeysContract;
columnsToSerialized: ModelKeysContract;
serializedToColumns: ModelKeysContract;
serializedToAttributes: ModelKeysContract;
};
/**
* Creates a new model instance with payload and adapter options
*/
private static newUpWithOptions;
/**
* Helper method for `fetchOrNewUpMany`, `fetchOrCreateMany` and `createOrUpdate`
* many.
*/
private static newUpIfMissing;
/**
* Returns the model query instance for the given model
*/
static query(options?: ModelAdapterOptions): any;
/**
* Create a model instance from the adapter result. The result value must
* be a valid object, otherwise `null` is returned.
*/
static $createFromAdapterResult(adapterResult: ModelObject, sideloadAttributes?: ModelObject, options?: ModelAdapterOptions): any | null;
/**
* Creates an array of models from the adapter results. The `adapterResults`
* must be an array with valid Javascript objects.
*
* 1. If top level value is not an array, then an empty array is returned.
* 2. If row is not an object, then it will be ignored.
*/
static $createMultipleFromAdapterResult<T extends LucidModel>(this: T, adapterResults: ModelObject[], sideloadAttributes?: ModelObject, options?: ModelAdapterOptions): InstanceType<T>[];
/**
* Define a new column on the model. This is required, so that
* we differentiate between plain properties vs model attributes.
*/
static $addColumn(name: string, options: Partial<ColumnOptions>): ModelColumnOptions;
/**
* Returns a boolean telling if column exists on the model
*/
static $hasColumn(name: string): boolean;
/**
* Returns the column for a given name
*/
static $getColumn(name: string): ModelColumnOptions | undefined;
/**
* Adds a computed node
*/
static $addComputed(name: string, options: Partial<ComputedOptions>): ComputedOptions;
/**
* Find if some property is marked as computed
*/
static $hasComputed(name: string): boolean;
/**
* Get computed node
*/
static $getComputed(name: string): ComputedOptions | undefined;
/**
* Register has one relationship
*/
protected static $addHasOne(name: string, relatedModel: () => LucidModel, options: RelationOptions<ModelRelations>): void;
/**
* Register has many relationship
*/
protected static $addHasMany(name: string, relatedModel: () => LucidModel, options: RelationOptions<ModelRelations>): void;
/**
* Register belongs to relationship
*/
protected static $addBelongsTo(name: string, relatedModel: () => LucidModel, options: RelationOptions<ModelRelations>): void;
/**
* Register many to many relationship
*/
protected static $addManyToMany(name: string, relatedModel: () => LucidModel, options: ManyToManyRelationOptions<ModelRelations>): void;
/**
* Register many to many relationship
*/
protected static $addHasManyThrough(name: string, relatedModel: () => LucidModel, options: ThroughRelationOptions<ModelRelations>): void;
/**
* Adds a relationship
*/
static $addRelation(name: string, type: ModelRelations['__opaque_type'], relatedModel: () => LucidModel, options: ModelRelationOptions): void;
/**
* Find if some property is marked as a relation or not
*/
static $hasRelation(name: any): boolean;
/**
* Returns relationship node for a given relation
*/
static $getRelation(name: any): any;
/**
* Define a static property on the model using the inherit or
* define strategy.
*
* Inherit strategy will clone the property from the parent model
* and will set it on the current model
*/
static $defineProperty<Model extends LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: 'inherit' | 'define' | ((value: Model[Prop]) => Model[Prop])): void;
/**
* Boot the model
*/
static boot(): void;
/**
* Register before hooks
*/
static before(event: EventsList, handler: HooksHandler<any, EventsList>): typeof BaseModel;
/**
* Register after hooks
*/
static after(event: EventsList, handler: HooksHandler<any, EventsList>): typeof BaseModel;
/**
* Returns a fresh persisted instance of model by applying
* attributes to the model instance
*/
static create(values: any, options?: ModelAssignOptions): Promise<any>;
/**
* Same as [[BaseModel.create]], but persists multiple instances. The create
* many call will be wrapped inside a managed transaction for consistency.
* If required, you can also pass a transaction client and the method
* will use that instead of create a new one.
*/
static createMany(values: any, options?: ModelAssignOptions): Promise<any[]>;
/**
* Find model instance using the primary key
*/
static find(value: any, options?: ModelAdapterOptions): Promise<any>;
/**
* Find model instance using the primary key
*/
static findOrFail(value: any, options?: ModelAdapterOptions): Promise<any>;
/**
* Find model instance using a key/value pair
*/
static findBy(key: string, value: any, options?: ModelAdapterOptions): Promise<any>;
/**
* Find model instance using a key/value pair
*/
static findByOrFail(key: string, value: any, options?: ModelAdapterOptions): Promise<any>;
/**
* Same as `query().first()`
*/
static first(options?: ModelAdapterOptions): Promise<any>;
/**
* Same as `query().firstOrFail()`
*/
static firstOrFail(options?: ModelAdapterOptions): Promise<any>;
/**
* Find model instance using a key/value pair
*/
static findMany(value: any[], options?: ModelAdapterOptions): Promise<any>;
/**
* Find model instance using a key/value pair or create a
* new one without persisting it.
*/
static firstOrNew(searchPayload: any, savePayload?: any, options?: ModelAssignOptions): Promise<any>;
/**
* Same as `firstOrNew`, but also persists the newly created model instance.
*/
static firstOrCreate(searchPayload: any, savePayload?: any, options?: ModelAssignOptions): Promise<any>;
/**
* Updates or creates a new row inside the database
*/
static updateOrCreate(searchPayload: any, updatedPayload: any, options?: ModelAssignOptions): Promise<any>;
/**
* Find existing rows or create an in-memory instances of the missing ones.
*/
static fetchOrNewUpMany(uniqueKeys: any, payload: any, options?: ModelAssignOptions): Promise<any[]>;
/**
* Find existing rows or create missing one's. One database call per insert
* is invoked, so that each insert goes through the lifecycle of model
* hooks.
*/
static fetchOrCreateMany(uniqueKeys: any, payload: any, options?: ModelAssignOptions): Promise<any[]>;
/**
* Update existing rows or create missing one's. One database call per insert
* is invoked, so that each insert and update goes through the lifecycle
* of model hooks.
*/
static updateOrCreateMany(uniqueKeys: any, payload: any, options?: ModelAssignOptions): Promise<any>;
/**
* Returns all rows from the model table
*/
static all(options?: ModelAdapterOptions): Promise<any>;
/**
* Truncate model table
*/
static truncate(cascade?: boolean): any;
constructor();
/**
* Custom options defined on the model instance that are
* passed to the adapter
*/
private modelOptions?;
/**
* Reference to transaction that will be used for performing queries on a given
* model instance.
*/
private modelTrx?;
/**
* The transaction listener listens for the `commit` and `rollback` events and
* cleansup the `$trx` reference
*/
private transactionListener;
/**
* When `fill` method is called, then we may have a situation where it
* removed the values which exists in `original` and hence the dirty
* diff has to do a negative diff as well
*/
private fillInvoked;
/**
* A copy of cached getters
*/
private cachedGetters;
/**
* Raises exception when mutations are performed on a delete model
*/
private ensureIsntDeleted;
/**
* Invoked when performing the insert call. The method initiates
* all `datetime` columns, if there are not initiated already
* and `autoCreate` or `autoUpdate` flags are turned on.
*/
protected initiateAutoCreateColumns(): void;
/**
* Invoked when performing the update call. The method initiates
* all `datetime` columns, if there have `autoUpdate` flag
* turned on.
*/
protected initiateAutoUpdateColumns(): void;
/**
* Preparing the object to be sent to the adapter. We need
* to create the object with the property names to be
* used by the adapter.
*/
protected prepareForAdapter(attributes: ModelObject): {};
/**
* Returns true when the field must be included
* inside the serialized object.
*/
private shouldSerializeField;
/**
* A type only reference to the columns
*/
$columns: any;
/**
* A copy of attributes that will be sent over to adapter
*/
$attributes: ModelObject;
/**
* Original represents the properties that already has been
* persisted or loaded by the adapter.
*/
$original: ModelObject;
/**
* Preloaded relationships on the model instance
*/
$preloaded: {
[relation: string]: LucidRow | LucidRow[];
};
/**
* Extras are dynamic properties set on the model instance, which
* are not serialized and neither casted for adapter calls.
*
* This is helpful when adapter wants to load some extra data conditionally
* and that data must not be persisted back the adapter.
*/
$extras: ModelObject;
/**
* Sideloaded are dynamic properties set on the model instance, which
* are not serialized and neither casted for adapter calls.
*
* This is helpful when you want to add dynamic meta data to the model
* and it's children as well.
*
* The difference between [[extras]] and [[sideloaded]] is:
*
* - Extras can be different for each model instance
* - Extras are not shared down the hierarchy (example relationships)
* - Sideloaded are shared across multiple model instances created via `$createMultipleFromAdapterResult`.
* - Sideloaded are passed to the relationships as well.
*/
$sideloaded: ModelObject;
/**
* Persisted means the model has been persisted with the adapter. This will
* also be true, when model instance is created as a result of fetch
* call from the adapter.
*/
$isPersisted: boolean;
/**
* Once deleted the model instance cannot make calls to the adapter
*/
$isDeleted: boolean;
/**
* `$isLocal` tells if the model instance was created locally vs
* one generated as a result of fetch call from the adapter.
*/
$isLocal: boolean;
/**
* Returns the value of primary key. The value must be
* set inside attributes object
*/
get $primaryKeyValue(): any | undefined;
/**
* Opposite of [[this.isPersisted]]
*/
get $isNew(): boolean;
/**
* Returns dirty properties of a model by doing a diff
* between original values and current attributes
*/
get $dirty(): any;
/**
* Finding if model is dirty with changes or not
*/
get $isDirty(): boolean;
/**
* Returns the transaction
*/
get $trx(): TransactionClientContract | undefined;
/**
* Set the trx to be used by the model to executing queries
*/
set $trx(trx: TransactionClientContract | undefined);
/**
* Get options
*/
get $options(): ModelOptions | undefined;
/**
* Set options
*/
set $options(options: ModelOptions | undefined);
/**
* Set options on the model instance along with transaction
*/
$setOptionsAndTrx(options?: ModelAdapterOptions): void;
/**
* A chainable method to set transaction on the model
*/
useTransaction(trx: TransactionClientContract): this;
/**
* A chainable method to set transaction on the model
*/
useConnection(connection: string): this;
/**
* Set attribute
*/
$setAttribute(key: string, value: any): void;
/**
* Get value of attribute
*/
$getAttribute(key: string): any;
/**
* Returns the attribute value from the cache which was resolved by
* the mutated by a getter. This is done to avoid re-mutating
* the same attribute value over and over again.
*/
$getAttributeFromCache(key: string, callback: CacheNode['getter']): any;
/**
* Returns the related model or default value when model is missing
*/
$getRelated(key: any): any;
/**
* A boolean to know if relationship has been preloaded or not
*/
$hasRelated(key: any): boolean;
/**
* Sets the related data on the model instance. The method internally handles
* `one to one` or `many` relations
*/
$setRelated(key: any, models: LucidRow | LucidRow[]): void;
/**
* Push related adds to the existing related collection
*/
$pushRelated(key: any, models: LucidRow | LucidRow[]): void;
/**
* Merges the object with the model attributes, assuming object keys
* are coming the database.
*
* 1. If key is unknown, it will be added to the `extras` object.
* 2. If key is defined as a relationship, it will be ignored and one must call `$setRelated`.
*/
$consumeAdapterResult(adapterResult: ModelObject, sideloadedAttributes?: ModelObject): void;
/**
* Sync originals with the attributes. After this `isDirty` will
* return false
*/
$hydrateOriginals(): void;
/**
* Set bulk attributes on the model instance. Setting relationships via
* fill isn't allowed, since we disallow setting relationships
* locally
*/
fill(values: any, allowExtraProperties?: boolean): this;
/**
* Merge bulk attributes with existing attributes.
*
* 1. If key is unknown, it will be added to the `extras` object.
* 2. If key is defined as a relationship, it will be ignored and one must call `$setRelated`.
*/
merge(values: any, allowExtraProperties?: boolean): this;
/**
* Preloads one or more relationships for the current model
*/
load(relationName: any, callback?: any): Promise<void>;
/**
* @deprecated
*/
preload(relationName: any, callback?: any): Promise<void>;
/**
* Lazy load the relationship aggregate value
*/
loadAggregate(relationName: any, callback?: any): LazyLoadAggregates<this>;
/**
* Lazy load the relationship count value
*/
loadCount(relationName: any, callback?: any): LazyLoadAggregates<this>;
/**
* Perform save on the model instance to commit mutations.
*/
save(): Promise<this>;
/**
* Perform delete by issuing a delete request on the adapter
*/
delete(): Promise<void>;
/**
* Serializes model attributes to a plain object
*/
serializeAttributes(fields?: CherryPickFields, raw?: boolean): ModelObject;
/**
* Serializes model compute properties to an object.
*/
serializeComputed(fields?: CherryPickFields): ModelObject;
/**
* Serializes relationships to a plain object. When `raw=true`, it will
* recurisvely serialize the relationships as well.
*/
serializeRelations(cherryPick?: CherryPick['relations'], raw?: boolean): ModelObject | {
[key: string]: LucidRow | LucidRow[];
};
/**
* Converting model to it's JSON representation
*/
serialize(cherryPick?: CherryPick): any;
/**
* Convert model to a plain Javascript object
*/
toObject(): {
$extras: ModelObject;
};
/**
* Returns the serialize method output. However, any model can overwrite
* it to define it's custom serialize output
*/
toJSON(): any;
/**
* Returns the query for `insert`, `update` or `delete` actions.
* Since the query builder for these actions are not exposed to
* the end user, this method gives a way to compose queries.
*/
$getQueryFor(action: 'insert' | 'update' | 'delete' | 'refresh', client: QueryClientContract): any;
/**
* Returns an instance of relationship on the given model
*/
related(relationName: any): any;
/**
* Reload/Refresh the model instance
*/
refresh(): Promise<this>;
}