import { SelectArg, SelectExpression } from 'kysely'; import Dream from '../Dream.js'; import { PassthroughOnClause, WhereStatement } from '../types/associations/shared.js'; import { AllDefaultScopeNames, CreateOrFindByExtraOpts, DreamColumnNames, DreamSerializerKey, FindablePropertiesForClass, OrderDir, PassthroughColumnNames, PluckEachArgs, PrimaryKeyForFind, TableColumnNames, UpdateableProperties, UpdateOrCreateByExtraOpts, ValidatedPluckEachColumnNames } from '../types/dream.js'; import { BaseModelColumnTypes, FindEachOpts, LoadForModifierFn, QueryWithJoinedAssociationsType, QueryWithJoinedAssociationsTypeAndNoPreload } from '../types/query.js'; import { JoinedAssociation, JoinedAssociationsTypeFromAssociations, VariadicJoinsArgs, VariadicLeftJoinLoadArgs, VariadicLoadArgs } from '../types/variadic.js'; import DreamTransaction from './DreamTransaction.js'; import Query from './Query.js'; export default class DreamClassTransactionBuilder { private dreamClass; private dreamTransaction; dreamInstance: DreamInstance; /** * Constructs a new DreamClassTransactionBuilder. * * @param dreamInstance - The Dream instance to build the transaction for * @param txn - The DreamTransaction instance */ constructor(dreamClass: DreamClass, dreamTransaction: DreamTransaction | null); /** * Retrieves an array containing all records corresponding to * this model. Be careful using this, since it will attempt to * pull every record into memory at once. For a large number * of records, consider using `.findEach`, which will pull * the records in batches. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).all() * // [User{id: 1}, User{id: 2}...] * * // only load specific columns (always includes primary key) * await User.txn(txn).all({ columns: ['name'] }) * // Users will have both 'id' and 'name' properties * }) * ``` * * @param options - Query options * @param options.columns - Array of column names to select. The primary key is always included automatically. For STI models, the type field is also automatically included. * @returns an array of dreams */ all>(this: I, options?: { columns?: DreamColumnNames[]; }): Promise; /** * Retrieves the number of records corresponding * to this model. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).count() * // 42 * }) * ``` * * @returns The number of records corresponding to this model */ count>(this: I): Promise; /** * Retrieves the number of records in each group, keyed by the * value of the provided group column (a SQL `GROUP BY`). * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).countBy('name') * // Map(2) { 'fred' => 2, 'zed' => 1 } * }) * ``` * * Only groups with at least one matching row appear in the Map; seed absent * groups yourself with `map.get(key) ?? 0`. When the group column is nullable, * records with a `null` value are grouped under a real `null` key. * * @param groupColumn - the column to group by * @returns A Map from each present group value to the number of records in that group */ countBy, T extends DreamColumnNames>(this: I, groupColumn: T): Promise>; /** * Returns a new Query instance, specifying a limit * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).limit(2).all() * // [User{}, User{}] * }) * ``` * * @param limit - The number of records to limit the query to * @returns A Query for this model with the limit clause applied */ limit>(this: I, limit: number | null): Query; /** * Returns a new Query instance, specifying an offset * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).order('id').offset(2).limit(2).all() * // [User{id: 3}, User{id: 4}] * }) * ``` * * @param offset - The number of records to offset the query by * @returns A Query for this model with the offset clause applied */ offset>(this: I, offset: number | null): Query; /** * Retrieves the max value of the specified column * for this model's records. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).max('id') * // 99 * }) * ``` * * @param columnName - A column name on the model * @returns The max value of the specified column for this model's records */ max, T extends DreamColumnNames>(this: I, columnName: T): Promise; /** * Retrieves the max value of the specified column within each group, keyed by * the value of the provided group column (a SQL `GROUP BY`). * * ```ts * await ApplicationModel.transaction(async txn => { * await CompositionAsset.txn(txn).maxBy('name', 'score') * // Map(2) { 'primary' => 9, 'secondary' => 4 } * }) * ``` * * Only groups with at least one matching row appear in the Map. When the group * column is nullable, records with a `null` value are grouped under a real * `null` key; a group whose aggregated values are all `null` yields a `null` * value. * * @param groupColumn - the column to group by * @param aggregatedColumn - the column to take the max of within each group * @returns A Map from each present group value to the max of the aggregated column in that group */ maxBy, GroupColumnName extends DreamColumnNames, AggregatedColumnName extends DreamColumnNames>(this: I, groupColumn: GroupColumnName, aggregatedColumn: AggregatedColumnName): Promise>; /** * Retrieves the min value of the specified column * for this model's records. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).min('id') * // 1 * }) * ``` * * @param columnName - A column name on the model * @returns The min value of the specified column for this model's records */ min, T extends DreamColumnNames>(this: I, columnName: T): Promise; /** * Retrieves the min value of the specified column within each group, keyed by * the value of the provided group column (a SQL `GROUP BY`). * * ```ts * await ApplicationModel.transaction(async txn => { * await CompositionAsset.txn(txn).minBy('name', 'score') * // Map(2) { 'primary' => 1, 'secondary' => 4 } * }) * ``` * * Only groups with at least one matching row appear in the Map. When the group * column is nullable, records with a `null` value are grouped under a real * `null` key; a group whose aggregated values are all `null` yields a `null` * value. * * @param groupColumn - the column to group by * @param aggregatedColumn - the column to take the min of within each group * @returns A Map from each present group value to the min of the aggregated column in that group */ minBy, GroupColumnName extends DreamColumnNames, AggregatedColumnName extends DreamColumnNames>(this: I, groupColumn: GroupColumnName, aggregatedColumn: AggregatedColumnName): Promise>; /** * Retrieves the sum value of the specified column * for this Query * * ```ts * await Game.txn(txn).sum('score') * // 1 * ``` * * @param columnName - a column name on the model * @returns the sum of the values of the specified column for this Query */ sum, T extends DreamColumnNames>(this: I, columnName: T): Promise; /** * Retrieves the sum of the specified column within each group, keyed by * the value of the provided group column (a SQL `GROUP BY`). * * ```ts * await ApplicationModel.transaction(async txn => { * await CompositionAsset.txn(txn).sumBy('name', 'score') * // Map(2) { 'primary' => 10, 'secondary' => 4 } * }) * ``` * * Only groups with at least one matching row appear in the Map. When the group * column is nullable, records with a `null` value are grouped under a real * `null` key; a group whose aggregated values are all `null` yields a `null` * value. * * @param groupColumn - the column to group by * @param aggregatedColumn - the column to sum within each group * @returns A Map from each present group value to the sum of the aggregated column in that group */ sumBy, GroupColumnName extends DreamColumnNames, AggregatedColumnName extends DreamColumnNames>(this: I, groupColumn: GroupColumnName, aggregatedColumn: AggregatedColumnName): Promise>; /** * Retrieves the average value of the specified column * for this Query * * ```ts * await Game.txn(txn).avg('score') * // 1 * ``` * * @param columnName - a column name on the model * @returns the average of the values of the specified column for this Query */ avg, T extends DreamColumnNames>(this: I, columnName: T): Promise; /** * Retrieves the average of the specified column within each group, keyed by * the value of the provided group column (a SQL `GROUP BY`). * * ```ts * await ApplicationModel.transaction(async txn => { * await CompositionAsset.txn(txn).avgBy('name', 'score') * // Map(2) { 'primary' => 5, 'secondary' => 4 } * }) * ``` * * Only groups with at least one matching row appear in the Map. When the group * column is nullable, records with a `null` value are grouped under a real * `null` key; a group whose aggregated values are all `null` yields a `null` * value. * * @param groupColumn - the column to group by * @param aggregatedColumn - the column to average within each group * @returns A Map from each present group value to the average of the aggregated column in that group */ avgBy, GroupColumnName extends DreamColumnNames, AggregatedColumnName extends DreamColumnNames>(this: I, groupColumn: GroupColumnName, aggregatedColumn: AggregatedColumnName): Promise>; /** * Persists a new record, setting the provided attributes. * Automatically sets createdAt and updatedAt timestamps. * * ```ts * await ApplicationModel.transaction(async txn => { * const user = await User.txn(txn).create({ email: 'how@yadoin', password: 'secure123' }) * // Creates and saves a User with the given attributes * * await Post.txn(txn).create({ body: 'howdy', user }) * // Creates a Post with a BelongsTo association to the user * }) * ``` * * @param attributes - attributes or belongs to associations you wish to set on this model before persisting * @param __namedParameters - optional parameters * @param __namedParameters.skipHooks - if true, will skip applying model hooks. Defaults to false * @returns A newly persisted dream instance */ create>(this: I, attributes?: UpdateableProperties, { skipHooks }?: { skipHooks?: boolean; }): Promise; /** * Finds a record for the corresponding model with the * specified primary key. If not found, null is returned. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).find(123) * // User{id: 123} * * await User.txn(txn).find(null) * // null * * await User.txn(txn).find(undefined) * // null * }) * ``` * * @param primaryKey - The primaryKey of the record to look up. * @returns Either the found record, or else null */ find>(this: I, primaryKey: PrimaryKeyForFind): Promise; /** * Finds a record for the corresponding model with the * specified primary key. If not found, an exception is raised. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).findOrFail(123) * // User{id: 123} * }) * ``` * * @param primaryKey - The primaryKey of the record to look up * @returns The found record */ findOrFail>(this: I, primaryKey: PrimaryKeyForFind): Promise; /** * Finds the first record—ordered by primary key—matching * the corresponding model and the specified where statement. * If not found, null is returned. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).findBy({ email: 'how@yadoin' }) * // User{email: 'how@yadoin'} * }) * ``` * * @param attributes - The where statement used to locate the record * @returns Either the first model found matching the whereStatement, or else null */ findBy>(this: I, attributes: WhereStatement): Promise; /** * Finds the first record—ordered by primary key—matching * the corresponding model and the specified where statement. * If not found, an exception is raised. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).findOrFailBy({ email: 'how@yadoin' }) * }) * // User{email: 'how@yadoin'} * ``` * * @param whereStatement - The where statement used to locate the record * @returns The first model found matching the whereStatement */ findOrFailBy>(this: I, whereStatement: WhereStatement): Promise; /** * Attempt to find the model with the given attributes. * If no record is found, then a new record is created. * * ```ts * await ApplicationModel.transaction(async txn => { * const user = await User.txn(txn).findOrCreateBy({ email }, { createWith: params }) * }) * ``` * * @param attributes - The base attributes for finding, but also the attributes to use when creating * @param extraOpts - Additional options * @param extraOpts.createWith - additional attributes to persist when creating, but not used for finding * @param extraOpts.skipHooks - if true, will skip applying model hooks. Defaults to false * @returns A dream instance */ findOrCreateBy>(this: I, attributes: FindablePropertiesForClass, extraOpts?: CreateOrFindByExtraOpts): Promise>; /** * Attempt to update the model with the given attributes. * If no record is found, then a new record is created. * All lifecycle hooks are run for whichever action is taken. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).updateOrCreateBy({ email }, { with: { name: 'Alice' }) * }) * ``` * * @param attributes - The base attributes for finding, but also the attributes to use when creating * @param extraOpts.with - additional attributes to persist when updating and creating, but not used for finding * @param extraOpts.skipHooks - if true, will skip applying model hooks. Defaults to false * @returns A dream instance */ updateOrCreateBy>(this: I, attributes: FindablePropertiesForClass, extraOpts?: UpdateOrCreateByExtraOpts): Promise>; /** * Finds all records for the corresponding model in batches, * and then calls the provided callback for each found record. * Once all records have been passed for a given batch, the next set of * records will be fetched and passed to your callback, until all * records matching the corresponding model have been fetched. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).findEach(user => { * console.log(user) * }) * }) * // User{email: 'hello@world'} * // User{email: 'goodbye@world'} * ``` * * Records are always visited in ascending primary key order; any `order` * applied to the query is discarded. See {@link Query.findEach} for why. * * @param cb - The callback to call for each found record * @param options.batchSize - The batch size you wish to collect records in. If not provided, it will default to 1000 * @returns void */ findEach>(this: I, cb: (instance: DreamInstance) => void | Promise, options?: FindEachOpts): Promise; /** * Returns the first record corresponding to the * model, ordered by primary key. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).first() * // User{id: 1} * }) * ``` * * @returns First record, or null if no record exists */ first>(this: I): Promise; /** * Returns the first record corresponding to the * model, ordered by primary key. If no record * is found, an exception is raised. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).firstOrFail() * // User{id: 1} * }) * ``` * * @returns First record */ firstOrFail>(this: I): Promise; /** * Returns true if a record exists for the given * model class. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).exists() * // false * * await User.txn(txn).create({ email: 'how@yadoin' }) * * await User.txn(txn).exists() * // true * }) * ``` * * @returns boolean */ exists>(this: I): Promise; /** * Load each specified association using a single SQL query. * See {@link #preload} for preloading in separate queries. * * Note: since leftJoinPreload loads via single query, it has * some downsides and that may be avoided using {@link #preload}: * 1. `limit` and `offset` will be automatically removed * 2. `through` associations will bring additional namespaces into the query that can conflict with through associations from other associations, creating an invalid query * 3. each nested association will result in an additional record which duplicates data from the outer record. E.g., given `.leftJoinPreload('a', 'b', 'c')`, if each `a` has 10 `b` and each `b` has 10 `c`, then for one `a`, 100 records will be returned, each of which has all of the columns of `a`. `.preload('a', 'b', 'c')` would perform three separate SQL queries, but the data for a single `a` would only be returned once. * 4. the individual query becomes more complex the more associations are included * 5. associations loading associations loading associations could result in exponential amounts of data; in those cases, `.preload(...).findEach(...)` avoids instantiating massive amounts of data at once * * ```ts * const user = await User.txn(txn).leftJoinPreload('posts', 'comments', { and: { visibility: 'public' } }, 'replies').first() * console.log(user.posts[0].comments[0].replies) * // [Reply{id: 1}, Reply{id: 2}] * ``` * * @param args - A chain of association names and and/andNot/andAny clauses * @returns A query for this model with the include statement applied */ leftJoinPreload, DB extends DreamInstance['DB'], TableName extends DreamInstance['table'], Schema extends DreamInstance['schema'], const Arr extends readonly unknown[], const LastArg extends VariadicLeftJoinLoadArgs, const JoinedAssociationsCandidate = JoinedAssociationsTypeFromAssociations, const JoinedAssociations extends readonly JoinedAssociation[] = JoinedAssociationsCandidate extends readonly JoinedAssociation[] ? JoinedAssociationsCandidate : never, RetQuery = QueryWithJoinedAssociationsTypeAndNoPreload, JoinedAssociations>>(this: I, ...args: [...Arr, LastArg]): RetQuery; /** * Applies preload statement to a Query scoped to this model. * Upon instantiating records of this model type, * specified associations will be preloaded. * * Preloading/loading is necessary prior to accessing associations * on a Dream instance. * * Preload is useful for avoiding the N+1 query problem * * ```ts * await ApplicationModel.transaction(async txn => { * const user = await User.txn(txn).preload('posts', 'comments', { and: { visibility: 'public' } }, 'replies').first() * console.log(user.posts[0].comments[0].replies) * // [Reply{id: 1}, Reply{id: 2}] * }) * ``` * * @param args - A chain of association names and and/andNot/andAny clauses * @returns A query for this model with the preload statement applied */ preload, DB extends DreamInstance['DB'], TableName extends DreamInstance['table'], Schema extends DreamInstance['schema'], const Arr extends readonly unknown[]>(this: I, ...args: [...Arr, VariadicLoadArgs]): Query>; /** * Recursively preloads all Dream associations referenced by `rendersOne` and `rendersMany` * in a DreamSerializer. This traverses the entire content tree of serializers to automatically * load all necessary associations, eliminating N+1 query problems and removing the need to * manually remember which associations to preload for serialization. * * This method decouples data loading code from data rendering code by having the serializer * (rendering code) inform the query (loading code) about which associations are needed. * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or * modifying existing ones - the loading code automatically adapts without requiring * corresponding modifications to preload statements. * * This method analyzes the serializer (specified by `serializerKey` or 'default') and * automatically preloads all associations that will be needed during serialization. * * ```ts * await ApplicationModel.transaction(async txn => { * // Instead of manually specifying all associations: * await User.txn(txn).preload('posts', 'comments', 'replies').all() * * // Automatically preload everything needed for serialization: * await User.txn(txn).preloadFor('summary').all() * * // Add where conditions to specific associations during preloading: * await User.txn(txn).preloadFor('detailed', (associationName, dreamClass) => { * if (dreamClass.typeof(Post) && associationName === 'comments') { * return { and: { published: true } } * } * }).all() * * // Skip preloading specific associations to handle them manually: * await User.txn(txn).preloadFor('summary', (associationName, dreamClass) => { * if (dreamClass.typeof(User) && associationName === 'posts') { * return 'omit' // Handle posts preloading separately with custom logic * } * }) * .preload('posts', { and: { featured: true } }) // Custom preloading * .all() * }) * ``` * * @param serializerKey - The serializer key to use for determining which associations to preload. * @param modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading * @returns A Query with all serialization associations preloaded */ preloadFor, SerializerKey extends DreamSerializerKey>(this: T, serializerKey: SerializerKey, modifierFn?: LoadForModifierFn): Query>; /** * Returns a new Query instance with the provided * inner join statement attached * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).innerJoin('posts').first() * }) * ``` * * @param args - A chain of association names and and/andNot/andAny clauses * @returns A Query for this model with the inner join clause applied */ innerJoin, DB extends DreamInstance['DB'], TableName extends DreamInstance['table'], Schema extends DreamInstance['schema'], const Arr extends readonly unknown[], const LastArg extends VariadicJoinsArgs, const JoinedAssociationsCandidate = JoinedAssociationsTypeFromAssociations, const JoinedAssociations extends readonly JoinedAssociation[] = JoinedAssociationsCandidate extends readonly JoinedAssociation[] ? JoinedAssociationsCandidate : never, RetQuery = QueryWithJoinedAssociationsType, JoinedAssociations>>(this: I, ...args: [...Arr, LastArg]): RetQuery; /** * Returns a new Query instance with the provided * left join statement attached * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).leftJoin('posts').first() * }) * ``` * * @param args - A chain of association names and and/andNot/andAny clauses * @returns A Query for this model with the left join clause applied */ leftJoin, DB extends DreamInstance['DB'], TableName extends DreamInstance['table'], Schema extends DreamInstance['schema'], const Arr extends readonly unknown[], const LastArg extends VariadicJoinsArgs, const JoinedAssociationsCandidate = JoinedAssociationsTypeFromAssociations, const JoinedAssociations extends readonly JoinedAssociation[] = JoinedAssociationsCandidate extends readonly JoinedAssociation[] ? JoinedAssociationsCandidate : never, RetQuery = QueryWithJoinedAssociationsType, JoinedAssociations>>(this: I, ...args: [...Arr, LastArg]): RetQuery; /** * Returns a new instance of Query scoped to the given * model class * * ```ts * await ApplicationModel.transaction(async txn => { * const query = User.txn(txn).queryInstance() * }) * ``` * * @returns A new Query instance */ queryInstance>(this: I): Query; /** * @deprecated Use {@link removeDefaultScope} instead. This method will become private in v3. * * Returns a query which bypasses user-removable default scopes, including on * association loads. An STI child's reserved type discriminator remains * enforced; query the STI base model to span its registered children. * * @returns A query which bypasses user-removable default scopes */ removeAllDefaultScopes>(this: I): Query; /** * Prevents a specific default scope from applying when * the Query is executed * * @returns A new Query which will prevent a specific default scope from applying */ removeDefaultScope>(this: I, scopeName: AllDefaultScopeNames): Query; /** * Returns the last record corresponding to the * model, ordered by primary key. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).last() * // User{id: 99} * }) * ``` * * @returns Last record, or null if no record exists */ last>(this: I): Promise; /** * Returns the last record corresponding to the * model, ordered by primary key. If no record * is found, an exception is raised. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).lastOrFail() * // User{id: 99} * }) * ``` * * @returns Last record */ lastOrFail>(this: I): Promise; /** * Returns a new Kysely SelectQueryBuilder instance to be used * in a sub Query * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).where({ * id: Post.txn(txn).nestedSelect('userId'), * }).all() * // [User{id: 1}, ...] * }) * ``` * * @param selection - the column to use for your nested Query * @returns A Kysely SelectQueryBuilder instance */ nestedSelect, DB extends DreamInstance['DB'], SE extends SelectExpression>(this: I, selection: SelectArg): import("kysely").SelectQueryBuilder; /** * Returns a new Query instance, attaching the provided * order statement * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).order('id').all() * // [User{id: 1}, User{id: 2}, ...] * }) * ``` * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).order({ name: 'asc', id: 'desc' }).all() * // [User{name: 'a', id: 99}, User{name: 'a', id: 97}, User{ name: 'b', id: 98 } ...] * }) * ``` * * @param orderStatement - Either a string or an object specifying order. If a string, the order is implicitly ascending. If the orderStatement is an object, statements will be provided in the order of the keys set in the object * @returns A query for this model with the order clause applied */ order>(this: I, arg: DreamColumnNames | Partial, OrderDir>> | null): Query; rootTableName: DreamInstance["table"]; rootTableAlias: DreamInstance extends Dream ? DreamInstance["table"] : DreamInstance; allowPreload: true; allowLeftJoinPreload: true; allowLimit: true; allowOffset: true; allowPaginate: true; }>>; /** * Plucks the provided fields from the corresponding model. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).pluck('id') * // [1, 3, 2] * }) * ``` * * If more than one column is requested, a multi-dimensional * array is returned: * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).order('id').pluck('id', 'email') * // [[1, 'a@a.com'], [2, 'b@b.com']] * }) * ``` * * @param columnNames - The column or array of columns to pluck * @returns An array of pluck results */ pluck, ColumnNames extends TableColumnNames[], ReturnValue extends ColumnNames['length'] extends 1 ? BaseModelColumnTypes[0][] : BaseModelColumnTypes[]>(this: I, ...columnNames: ColumnNames): Promise; /** * Plucks the specified fields from the given dream class table * in batches, passing each found columns into the provided callback function. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).order('id').pluckEach('id', (id) => { * console.log(id) * }) * // 1 * // 2 * // 3 * }) * ``` * * @param fields - A list of fields to pluck, followed by a callback function to call for each set of found fields * @returns void */ pluckEach, const ColumnNames extends unknown[]>(this: I, ...args: PluckEachArgs>, BaseModelColumnTypes>, DreamInstance>>): Promise; pluckEach, const ColumnNames extends (keyof UpdateableProperties)[]>(this: I, ...args: PluckEachArgs>): Promise; /** * Sends data through for use as passthrough data * for the associations that require it. * * ```ts * class Post { * @deco.HasMany('LocalizedText') * public localizedTexts: LocalizedText[] * * @deco.HasOne('LocalizedText', { * where: { locale: DreamConst.passthrough }, * }) * public currentLocalizedText: LocalizedText * } * * await ApplicationModel.transaction(async txn => { * await User.txn(txn).passthrough({ locale: 'es-ES' }) * .preload('posts', 'currentLocalizedText') * .first() * }) * ``` * * @param passthroughWhereStatement - Where statement used for associations that require passthrough data * @returns A Query for this model with the passthrough data */ passthrough, PassthroughColumns extends PassthroughColumnNames>(this: I, passthroughWhereStatement: PassthroughOnClause): Query; /** * Applies a where statement to a new Query instance * scoped to this model. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).where({ email: 'how@yadoin' }).first() * // User{email: 'how@yadoin'} * }) * ``` * * @param whereStatement - Where statement to apply to the Query * @returns A Query for this model with the where clause applied */ where>(this: I, whereStatement: WhereStatement): Query; /** * Applies "OR"'d where statements to a Query scoped * to this model. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).whereAny([{ email: 'how@yadoin' }, { name: 'fred' }]).first() * // [User{email: 'how@yadoin'}, User{name: 'fred'}, User{name: 'fred'}] * }) * ``` * * @param whereStatements - An array of where statements to `OR` together * @returns A Query for this model with the whereAny clause applied */ whereAny>(this: I, whereStatements: WhereStatement[]): Query; /** * Applies a whereNot statement to a new Query instance * scoped to this model. * * ```ts * await ApplicationModel.transaction(async txn => { * await User.txn(txn).whereNot({ email: 'how@yadoin' }).first() * // User{email: 'hello@world'} * }) * ``` * * @param whereStatement - A where statement to negate and apply to the Query * @returns A Query for this model with the whereNot clause applied */ whereNot>(this: I, whereStatement: WhereStatement): Query; }