import { AsyncLocalStorage } from "node:async_hooks"; import { inspect } from "node:util"; type UnionToIntersection = (U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never; type MaybeArray = T | T[]; type MaybePromise = T | Promise; interface FnUnknownToUnknown { (a: unknown): unknown; } interface RecordKeyTrue { [K: string]: true; } interface RecordString { [K: string]: string; } interface RecordStringOrNumber { [K: string]: string | number; } interface RecordOptionalString { [K: string]: string | undefined; } interface RecordUnknown { [K: string]: unknown; } type ShallowSimplify = T extends any ? { [K in keyof T]: T[K] } : T; /** * Merge methods from multiple class into another class. * @param derivedCtor - target class to merge methods into * @param constructors - classes to merge methods from */ declare function applyMixins(targetClass: any, mixinClasses: any[]): void; /** * When array is passed, it is returned as is, otherwise, returns a new array with the provided value. * @param item - array or a value to turn into array */ declare const toArray: (item: T) => T extends unknown[] ? T : [T]; declare const noop: () => void; declare const returnArg: (a: T) => T; type EmptyObject = {}; declare const emptyObject: {}; type EmptyTuple = []; declare const emptyArray: never[]; /** * For code generation: quote a string with a single quote, escape characters. * @param s - string to quote */ declare const singleQuote: (s: string) => string; /** * For code generation: quote string with a backtick, escape characters. * @param s - string to quote */ declare const backtickQuote: (s: string) => string; /** * For code generation: some strings must be quoted when used as an object key. * This function quotes the strings when needed. * @param key - object key to quote * @param toCamel - change to camel case */ declare const quoteObjectKey: (key: string, toCamel: boolean | undefined) => string; /** * Check if the object has at least one value that is not `undefined`. * Nulls counts. * @param obj - any object */ declare const objectHasValues: (obj?: object) => boolean; /** * If we simply log file path as it is, it may be not clickable in the terminal. * On Windows, it is clickable as it is, so it is returned as is. * On Linux (at least in my JetBrains editor terminal) it's transformed to URL format to be clickable. * @param path - file path */ declare const pathToLog: (path: string) => string; /** * Translate a string to camelCase * @param str - string to translate */ declare const toCamelCase: (str: string) => string; /** * Translate a string to a PascalCase * @param str - string to translate */ declare const toPascalCase: (str: string) => string; /** * Translate a string to a snake_case. * @param str - string to translate */ declare const toSnakeCase: (str: string) => string; /** * Compare two values deeply. * undefined and empty object are considered to be equal. * @param a - any value * @param b - any value */ declare const deepCompare: (a: unknown, b: unknown) => boolean; /** * Returns a relative path to use as an `import` source to import one file from another. * @param from - TS file where we want to place the `import` * @param to - TS file that we're importing */ declare const getImportPath: (from: string, to: string) => string; /** * Get stack trace to collect info about who called the function */ declare const getStackTrace: () => NodeJS.CallSite[] | undefined; /** * Get a file path of the function which called the function which called this `getCallerFilePath`. * Determines file path by error stack trace, skips any paths that are located in `node_modules`. * @param stack - optionally provide an existing stack trace */ declare const getCallerFilePath: (stack?: NodeJS.CallSite[] | undefined) => string | undefined; declare const pick: (obj: T, keys: Keys[]) => Pick; declare const omit: (obj: T, keys: Keys[]) => Omit; declare const getFreeAlias: (obj: RecordUnknown | undefined, as: string) => string; declare const setFreeAlias: (obj: RecordUnknown, as: string, value: unknown) => string; declare const getFreeSetAlias: (set: Set, as: string, start?: number) => string; declare const exhaustive: (_: never) => never; declare const pluralize: (w: string, count: number, append?: string) => string; declare const colors: { yellow: (s: string) => string; green: (s: string) => string; red: (s: string) => string; blue: (s: string) => string; bright: (s: string) => string; blueBold: (s: string) => string; yellowBold: (s: string) => string; greenBold: (s: string) => string; pale: (s: string) => string; }; interface SubQueryForSql extends ToSQLQuery { __forSql: true; } interface HasBeforeAndBeforeSet { before?: QueryBeforeHook[]; beforeSet?: QueryData['beforeSet']; } interface ArgWithBeforeAndBeforeSet { q: HasBeforeAndBeforeSet; } interface PrepareSubQueryForSqlArg extends PickQueryQ { dynamicBefore?: boolean; } interface PrepareSubQueryForSql { (mainQuery: ArgWithBeforeAndBeforeSet, subQuery: PrepareSubQueryForSqlArg): SubQueryForSql; } declare const prepareSubQueryForSql: PrepareSubQueryForSql; type HookPurpose = 'Create' | 'Update' | 'Delete'; interface HasCteHooks { cteHooks?: CteHooks; } interface CteHooks { hasSelect?: boolean; tableHooks?: CteTableHooks; ensureCount?: EnsureCount; } interface EnsureCount { [cteName: string]: EnsureCountItem; } type EnsureCountItem = { count: number; } | { jsonNotNull: string; }; interface CteTableHooks { [K: string]: CteTableHook; } interface CteTableHook { table: string; shape: Column.Shape.Data; tableHook: TableHook; throwOnNotFound?: boolean; } interface TableHook { hookPurpose?: HookPurpose; select?: HookSelect; afterCreate?: QueryAfterHook[]; afterUpdate?: QueryAfterHook[]; afterSave?: QueryAfterHook[]; afterDelete?: QueryAfterHook[]; afterCreateCommit?: QueryAfterHook[]; afterUpdateCommit?: QueryAfterHook[]; afterSaveCommit?: QueryAfterHook[]; afterDeleteCommit?: QueryAfterHook[]; } type HookSelect = Map; interface HookSelectValue { select: string | { sql: string; }; as?: string; temp?: string; onAs?: ((as: string) => void)[]; notLoaded?: boolean; } interface HasTableHook { tableHook?: TableHook; } interface HasHookSelect { hookSelect?: HookSelect; } declare abstract class OrchidOrmError extends Error {} /** * When we search for a single record, and it is not found, it can either throw an error, or return `undefined`. * * Unlike other database libraries, `Orchid ORM` decided to throw errors by default when using methods `take`, `find`, `findBy`, `get` and the record is not found. * It is a [good practice](https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/centralizedhandling.md) to catch common errors in a centralized place (see [global error handling](https://orchid-orm.netlify.app/guide/error-handling.html#global-error-handling)), and this allows for a more concise code. * * If it's more suitable to get the `undefined` value instead of throwing, use `takeOptional`, `findOptional`, `findByOptional`, `getOptional` instead. */ declare class NotFoundError extends OrchidOrmError { #private; constructor(query: IsQuery, message?: string); getQuery(): Query; } declare class OrchidOrmInternalError extends Error { #private; data?: RecordUnknown | undefined; constructor(query: IsQuery, message?: string, data?: RecordUnknown | undefined); getQuery(): Query; } type QueryErrorName = 'parseComplete' | 'bindComplete' | 'closeComplete' | 'noData' | 'portalSuspended' | 'replicationStart' | 'emptyQuery' | 'copyDone' | 'copyData' | 'rowDescription' | 'parameterDescription' | 'parameterStatus' | 'backendKeyData' | 'notification' | 'readyForQuery' | 'commandComplete' | 'dataRow' | 'copyInResponse' | 'copyOutResponse' | 'authenticationOk' | 'authenticationMD5Password' | 'authenticationCleartextPassword' | 'authenticationSASL' | 'authenticationSASLContinue' | 'authenticationSASLFinal' | 'error' | 'notice'; declare abstract class QueryError extends OrchidOrmInternalError { #private; message: string; length?: number; name: QueryErrorName; stack: string | undefined; code: string | undefined; detail: string | undefined; severity: string | undefined; hint: string | undefined; position: string | undefined; internalPosition: string | undefined; internalQuery: string | undefined; where: string | undefined; schema: string | undefined; table: string | undefined; column: string | undefined; dataType: string | undefined; constraint: string | undefined; file: string | undefined; line: string | undefined; routine: string | undefined; get isUnique(): boolean; get columns(): { [K in keyof T["shape"]]?: true | undefined }; } interface QueryLogObject { colors: boolean; beforeQuery(sql: SingleSql): unknown; afterQuery(sql: SingleSql, logData: unknown): void; onError(error: Error, sql: SingleSql, logData: unknown): void; } interface QueryLogger { log(message: string): void; warn(message: string): void; error(message: string): void; } interface QueryLogOptions { log?: boolean | Partial; logger?: QueryLogger; } declare const logColors: { boldCyanBright: (message: string) => string; boldBlue: (message: string) => string; boldYellow: (message: string) => string; boldMagenta: (message: string) => string; boldRed: (message: string) => string; }; declare const logParamToLogObject: (logger: QueryLogger, log: QueryLogOptions["log"]) => QueryLogObject | undefined; declare class QueryLog { /** * Override the `log` option, which can also be set in `createDb` or when creating a table instance: * * ```ts * // turn log on for this query: * await db.table.all().log(true); * await db.table.all().log(); // no argument for true * * // turn log off for this query: * await db.table.all().log(false); * ``` * * Use {@link $withOptions} to override `log` for a scope of a callback. */ log(this: T, log?: boolean): T; } interface SqlSessionState { /** * Postgres role for SQL session context. * * `$withOptions` applies it around query execution; transaction options apply * it with transaction-local semantics. */ role?: string; /** * Postgres custom settings for SQL session context. * * `$withOptions` applies them around query execution; transaction options * apply them with transaction-local semantics. */ setConfig?: Record; } type QuerySchema = (() => string) | string; interface HasQuerySchema { q: { schema?: QuerySchema; }; } declare const getQuerySchema: (query: HasQuerySchema) => string | undefined; declare class QueryWithSchema { /** * Specifies the schema to be used as a prefix of a table name. * * Though this method can be used to set the schema right when building the query, * it's better to specify schema when calling `db(table, () => columns, { schema: string })` * * ```ts * db.table.withSchema('customSchema').select('id'); * ``` * * Resulting SQL: * * ```sql * SELECT "user"."id" FROM "customSchema"."user" * ``` * * You can set a **default** schema for all tables in a callback by using {@link $withOptions}. * * @param schema - a name of the database schema to use */ withSchema(this: T, schema: QuerySchema | undefined): T; } interface AsyncState extends SqlSessionState { transactionAdapter?: Adapter; transactionId?: number; afterCommit?: TransactionAfterCommitHook[]; log?: QueryLogObject; testTransactionCount?: number; catchI?: number; schema?: QuerySchema; transactionRole?: SqlSessionState['role']; transactionSetConfig?: SqlSessionState['setConfig']; } interface StorageOptions extends SqlSessionState { log?: boolean; schema?: QuerySchema; } interface ProcessedStorageOptions extends SqlSessionState { log?: QueryLogObject; schema?: QuerySchema; } declare class QueryStorage { withOptions(this: PickQueryQAndInternal, options: StorageOptions, cb: () => Promise): Promise; } /** * Generic result returning from query methods. */ interface QueryResultRow { [K: string]: any; } interface QueryResult { rowCount: number; rows: T[]; fields: { name: string; }[]; } interface QueryArraysResult { rowCount: number; rows: R[]; fields: { name: string; }[]; } interface AdapterConfigBase { databaseURL?: string; database?: string; user?: string; password?: string | (() => string | Promise); searchPath?: string; ssl?: any; /** * Postgres settings to apply when driver connections are configured. * * `searchPath` is normalized to `search_path` in this map. */ setConfig?: RecordString; schema?: QuerySchema; host?: string; /** * This option may be useful in CI when database container has started, CI starts performing next steps, * migrations begin to apply though database may be not fully ready for connections yet. * * Set `connectRetry: true` for the default backoff strategy. It performs 10 attempts starting with 50ms delay and increases delay exponentially according to this formula: * * ``` * (factor, defaults to 1.5) ** (currentAttempt - 1) * (delay, defaults to 50) * ``` * * So the 2nd attempt will happen in 50ms from start, 3rd attempt in 125ms, 3rd in 237ms, and so on. * * You can customize max attempts to be made, `factor` multiplier and the starting delay by passing: * * ```ts * const options = { * databaseURL: process.env.DATABASE_URL, * connectRetry: { * attempts: 15, // max attempts * strategy: { * delay: 100, // initial delay * factor: 2, // multiplier for the formula above * } * } * }; * * rakeDb(options, { ... }); * ``` * * You can pass a custom function to `strategy` to customize delay behavior: * * ```ts * import { setTimeout } from 'timers/promises'; * * const options = { * databaseURL: process.env.DATABASE_URL, * connectRetry: { * attempts: 5, * stragegy(currentAttempt: number, maxAttempts: number) { * // linear: wait 100ms after 1st attempt, then 200m after 2nd, and so on. * return setTimeout(currentAttempt * 100); * }, * }, * }; * ``` */ connectRetry?: AdapterConfigConnectRetryParam | true; } interface AdapterConfigConnectRetryParam { attempts?: number; strategy?: AdapterConfigConnectRetryStrategyParam | AdapterConfigConnectRetryStrategy; } interface AdapterConfigConnectRetryStrategyParam { delay?: number; factor?: number; } interface AdapterConfigConnectRetry { attempts: number; strategy: AdapterConfigConnectRetryStrategy; } interface AdapterConfigConnectRetryStrategy { (attempt: number, attempts: number): Promise | void; } interface AdapterTransactionOptions extends ProcessedStorageOptions { level?: IsolationLevel; readOnly?: boolean; deferrable?: boolean; } interface Adapter { errorClass: new (...args: any[]) => Error; searchPath?: string; driverAdapter: DriverAdapter; isInTransaction(): boolean; assignError(to: QueryError, from: Error): void; query(text: string, values?: unknown[], startingSavepoint?: string, releasingSavepoint?: string, sqlSessionState?: SqlSessionState): Promise>; arrays(text: string, values?: unknown[], startingSavepoint?: string, releasingSavepoint?: string, sqlSessionState?: SqlSessionState): Promise>; /** * Run a transaction * * `options` can be `undefined`. */ transaction(asyncStorage: AsyncLocalStorage | undefined, options: AdapterTransactionOptions | undefined, cb: (adapter: TransactionAdapter) => Promise): Promise; close(): Promise; getDatabase(): string; getUser(): string; getSearchPath(): string | undefined; getHost(): string; getSchema(): QuerySchema | undefined; clone(params?: AdapterConfigBase): Adapter; } /** * Adapter interface for transaction contexts. */ interface TransactionAdapter extends Adapter { isInTransaction(): true; } type Pool = any; type Client = any; /** * Adapter class used by runtime orchestrator to create driver-specific adapters. */ interface DriverAdapter { errorClass: new (...args: any[]) => Error; errorFields: RecordString; configure(config: AdapterConfigBase): Pool; manualPool: boolean; borrow(pool: Pool): Client; release(client: Client): void; queryClient(client: Client, text: string, values?: unknown[], startingSavepoint?: string, releasingSavepoint?: string, arraysMode?: boolean): Promise>; begin(pool: Pool, cb: (client: DriverClient) => Promise, options?: string): Promise; close(pool: Pool): Promise; } /** * Constructor params for the shared runtime adapter orchestrator. */ interface AdapterParams { /** * Driver-specific adapter class implementing `DriverAdapter`. */ driverAdapter: DriverAdapter; /** * Base config saved by runtime and used for clone recreation. */ config: AdapterConfigBase; } /** * Shared runtime adapter orchestrator over a driver-specific adapter implementation. */ declare class AdapterClass implements Adapter { private readonly params; errorClass: new (...args: any[]) => Error; driverAdapter: DriverAdapter; private pool; private readonly config; private readonly connectionState; constructor(params: AdapterParams); query(text: string, values?: unknown[], startingSavepoint?: string, releasingSavepoint?: string, sqlSessionState?: SqlSessionState): Promise>; arrays(text: string, values?: unknown[], startingSavepoint?: string, releasingSavepoint?: string, sqlSessionState?: SqlSessionState): Promise>; clone(params?: AdapterConfigBase): Adapter; isInTransaction(): boolean; getDatabase(): string; getUser(): string; getSearchPath(): string | undefined; getHost(): string; getSchema(): QuerySchema | undefined; transaction(asyncStorage: AsyncLocalStorage | undefined, options: AdapterTransactionOptions | undefined, cb: (adapter: TransactionAdapter) => Promise): Promise; close: () => Promise; assignError(to: QueryError, from: Error): void; } /** * Shared runtime transaction adapter orchestrator over a driver-specific transaction adapter. */ declare class TransactionAdapterClass implements TransactionAdapter { private adapter; private client; errorClass: new (...args: any[]) => Error; driverAdapter: DriverAdapter; constructor(adapter: Adapter, client: Client); query(text: string, values?: unknown[], startingSavepoint?: string, releasingSavepoint?: string, sqlSessionState?: SqlSessionState): Promise>; arrays(text: string, values?: unknown[], startingSavepoint?: string, releasingSavepoint?: string, sqlSessionState?: SqlSessionState): Promise>; clone(params?: AdapterConfigBase): Adapter; isInTransaction(): true; getDatabase(): string; getUser(): string; getSearchPath(): string | undefined; getHost(): string; getSchema(): QuerySchema | undefined; transaction(asyncStorage: AsyncLocalStorage | undefined, options: AdapterTransactionOptions | undefined, cb: (adapter: TransactionAdapter) => Promise): Promise; close(): Promise; assignError(to: QueryError, from: Error): void; } /** * Element of `afterCommit` transaction array. See {@link AsyncState.afterCommit}. */ type TransactionAfterCommitHook = unknown[] | Query | AfterCommitHook[] | AfterCommitStandaloneHook; interface AfterCommitHook { (data: unknown[], q: Query): unknown | Promise; } interface AfterCommitStandaloneHook { (): unknown | Promise; } declare const makeConnectRetryConfig: (config: AdapterConfigConnectRetryParam) => AdapterConfigConnectRetry; declare const wrapAdapterFnWithConnectRetry: any>(connectRetryConfig: AdapterConfigConnectRetry, fn: Fn) => Fn; /** * Expression for a SQL identifier reference. * Used to safely quote identifiers in raw SQL queries. */ declare class SqlRefExpression extends Expression { name: string; result: { value: Column.Pick.QueryColumn; }; q: ExpressionData; constructor(name: string); makeSQL(): string; } interface ColumnSchemaGetterTableClass { prototype: { columns: { shape: Column.Shape.ForValidation; }; }; inputSchema(): unknown; querySchema(): unknown; pkeySchema(): unknown; createSchema(): unknown; } type ColumnSchemaGetterColumns = T['prototype']['columns']['shape']; interface ColumnTypeSchemaArg { type: unknown; nullable(this: T): Column.Modifiers.Nullable; encode: unknown; parse: unknown; parseNull: unknown; asType: unknown; narrowType: unknown; narrowAllTypes: unknown; error?: unknown; } interface ColumnSchemaConfig extends ColumnTypeSchemaArg { dateAsNumber: unknown; dateAsDate: unknown; enum: unknown; array: unknown; boolean(): unknown; buffer(): unknown; unknown(): unknown; never(): unknown; stringSchema(): unknown; stringMin(max: number): unknown; stringMax(max: number): unknown; stringMinMax(min: number, max: number): unknown; number(): unknown; int(): unknown; stringNumberDate(): unknown; timeInterval(): unknown; bit(max?: number): unknown; uuid(): unknown; json(): T; inputSchema(this: ColumnSchemaGetterTableClass): unknown; outputSchema(this: ColumnSchemaGetterTableClass): unknown; querySchema(this: ColumnSchemaGetterTableClass): unknown; createSchema(this: ColumnSchemaGetterTableClass): unknown; updateSchema(this: ColumnSchemaGetterTableClass): unknown; pkeySchema(this: ColumnSchemaGetterTableClass): unknown; smallint(): T; integer(): T; real(): T; smallSerial(): T; serial(): T; bigint(): T; decimal(precision?: number, scale?: number): T; doublePrecision(): T; bigSerial(): T; money(): T; varchar(limit?: number): T; text(): T; string(limit?: number): T; citext(): T; date(): T; timestampNoTZ(precision?: number): T; timestamp(precision?: number): T; geographyPointSchema(): unknown; } interface TableData { primaryKey?: TableData.PrimaryKey; indexes?: TableData.Index[]; excludes?: TableData.Exclude[]; constraints?: TableData.Constraint[]; } declare namespace TableData { export type DropMode = 'CASCADE' | 'RESTRICT'; export interface PrimaryKey { columns: string[]; name?: string; } export interface ColumnIndex { options: Index.ColumnArg & Index.Options; } export interface ColumnExclude extends ColumnIndex { with: string; } export interface Index { columns: Index.ColumnOrExpressionOptions[]; options: Index.Options; } export interface Exclude { columns: Exclude.ColumnOrExpressionOptions[]; options: Exclude.Options; } export interface Constraint { name?: string; check?: Check; identity?: Identity; references?: References; dropMode?: TableData.DropMode; } export type Check = RawSqlBase; export interface ColumnReferences { fnOrTable: TableData.References.FnOrTable; foreignColumns: string[]; options?: References.Options; } export interface References extends ColumnReferences { columns: string[]; } export interface Identity extends SequenceBaseOptions { always?: boolean; } interface SequenceBaseOptions { increment?: number; start?: number; min?: number; max?: number; cache?: number; cycle?: boolean; } export interface SequenceOptions extends SequenceBaseOptions { dataType?: 'smallint' | 'integer' | 'bigint'; ownedBy?: string; } export namespace Index { export interface ColumnOptions { collate?: string; opclass?: string; order?: string; weight?: SearchWeight; } export interface UniqueOptionsArg { name?: Name; nullsNotDistinct?: boolean; using?: string; include?: MaybeArray; with?: string; tablespace?: string; where?: string; dropMode?: DropMode; } export interface OptionsArg extends UniqueOptionsArg { unique?: boolean; } export interface TsVectorArg extends OptionsArg, TsVectorOptions {} export type Options = TsVectorArg; export interface UniqueColumnArg extends ColumnOptions, UniqueOptionsArg { expression?: string; } export interface ColumnArg extends UniqueColumnArg { unique?: boolean; } interface TsVectorOptions { language?: string; languageColumn?: string; tsVector?: boolean; } export interface TsVectorColumnArg extends ColumnArg, TsVectorOptions {} export interface ExpressionOptions extends ColumnOptions { expression: string; } export interface ColumnOptionsForColumn extends ColumnOptions { column: Column; } export type ColumnOrExpressionOptions = ColumnOptionsForColumn | ExpressionOptions; export {}; } export namespace Exclude { export interface Options { name?: string; using?: string; include?: MaybeArray; with?: string; tablespace?: string; where?: string; dropMode?: DropMode; } export interface ArgColumnOptions { collate?: string; opclass?: string; order?: string; } export interface ColumnArg extends Options, ArgColumnOptions {} interface ColumnBaseOptions extends ArgColumnOptions { with: string; } interface ColumnOptions extends ColumnBaseOptions { column: Column; } interface ExpressionOptions extends ColumnBaseOptions { expression: string; } export type ColumnOrExpressionOptions = ColumnOptions | ExpressionOptions; export {}; } export namespace References { type FnOrTable = (() => Column.ForeignKey.TableParam) | string; /** * - MATCH FULL will not allow one column of a multicolumn foreign key to be null unless all foreign key columns are null; * if they are all null, the row is not required to have a match in the referenced table. * - MATCH SIMPLE (default) allows any of the foreign key columns to be null; if any of them are null, the row is not required to have a match in the referenced table. * - MATCH PARTIAL - PG docs say it's not implemented. */ type Match = 'FULL' | 'PARTIAL' | 'SIMPLE'; /** * - NO ACTION Produce an error indicating that the deletion or update would create a foreign key constraint violation. If the constraint is deferred, this error will be produced at constraint check time if there still exist any referencing rows. This is the default action. * - RESTRICT Produce an error indicating that the deletion or update would create a foreign key constraint violation. This is the same as NO ACTION except that the check is not deferrable. * - CASCADE Delete any rows referencing the deleted row, or update the values of the referencing column(s) to the new values of the referenced columns, respectively. * - SET NULL Set all the referencing columns, or a specified subset of the referencing columns, to null. A subset of columns can only be specified for ON DELETE actions. * - SET DEFAULT Set all the referencing columns, or a specified subset of the referencing columns, to their default values. A subset of columns can only be specified for ON DELETE actions. (There must be a row in the referenced table matching the default values, if they are not null, or the operation will fail.) */ type Action = 'NO ACTION' | 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT'; interface BaseOptions { match?: Match; onUpdate?: Action; onDelete?: Action; dropMode?: TableData.DropMode; } interface Options extends BaseOptions { name?: string; } } export {}; } type TableDataInput = { primaryKey?: TableData.PrimaryKey; index?: TableData.Index; exclude?: TableData.Exclude; constraint?: TableData.Constraint; }; interface TableDataItem { tableDataItem: true; columns: unknown; } interface NonUniqDataItem extends TableDataItem { columns: EmptyTuple; } interface UniqueTableDataItem { columns: (keyof Shape)[]; name: string; } interface TableDataMethods { primaryKey(columns: Columns, name?: Name): { tableDataItem: true; columns: Columns; name: string extends Name ? never : Name; }; unique, ...(Key | TableData.Index.ColumnOrExpressionOptions)[]], Name extends string>(columns: Columns, options?: TableData.Index.UniqueOptionsArg): { tableDataItem: true; columns: Columns extends (Key | TableData.Index.ColumnOptionsForColumn)[] ? { [I in keyof Columns]: 'column' extends keyof Columns[I] ? Columns[I]['column'] : Columns[I] } : never; name: string extends Name ? never : Name; }; index(columns: (Key | TableData.Index.ColumnOrExpressionOptions)[], options?: TableData.Index.OptionsArg): NonUniqDataItem; searchIndex(columns: (Key | TableData.Index.ColumnOrExpressionOptions)[], options?: TableData.Index.TsVectorArg): NonUniqDataItem; /** * Defines an `EXCLUDE` constraint for multiple columns. * * The first argument is an array of columns and/or SQL expressions: * * ```ts * interface ExcludeColumnOptions { * // column name OR expression is required * column: string; * // SQL expression, like 'tstzrange("startDate", "endDate")' * expression: string; * * // required: operator for the EXCLUDE constraint to work * with: string; * * collate?: string; * opclass?: string; // for example, varchar_ops * order?: string; // ASC, DESC, ASC NULLS FIRST, DESC NULLS LAST * } * ``` * * The second argument is an optional object with options for the whole exclude constraint: * * ```ts * interface ExcludeOptions { * // algorithm to use such as GIST, GIN * using?: string; * // EXCLUDE creates an index under the hood, include columns to the index * include?: MaybeArray; * // see "storage parameters" in the Postgres document for creating an index, for example, 'fillfactor = 70' * with?: string; * // The tablespace in which to create the constraint. If not specified, default_tablespace is consulted, or temp_tablespaces for indexes on temporary tables. * tablespace?: string; * // WHERE clause to filter records for the constraint * where?: string; * // for dropping the index at a down migration * dropMode?: DropMode; * } * ``` * * Example: * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable( * 'table', * (t) => ({ * id: t.identity().primaryKey(), * roomId: t.integer(), * startAt: t.timestamp(), * endAt: t.timestamp(), * }), * (t) => [ * t.exclude( * [ * { column: 'roomId', with: '=' }, * { expression: 'tstzrange("startAt", "endAt")', with: '&&' }, * ], * { * using: 'GIST', * }, * ), * ], * ); * }); * ``` */ exclude(columns: TableData.Exclude.ColumnOrExpressionOptions[], options?: TableData.Exclude.Options): NonUniqDataItem; foreignKey(columns: [string, ...string[]], fnOrTable: () => new () => { columns: { shape: Shape; }; }, foreignColumns: [keyof Shape, ...(keyof Shape)[]], options?: TableData.References.Options): NonUniqDataItem; foreignKey(columns: [string, ...string[]], fnOrTable: string, foreignColumns: [string, ...string[]], options?: TableData.References.Options): NonUniqDataItem; check(check: RawSqlBase, name?: string): NonUniqDataItem; sql: SqlFn; } type TableDataItemsUniqueColumns> = MaybeArray extends T ? never : T extends UniqueTableDataItem ? ItemUniqueColumns : T extends unknown[] ? { [Item in T[number] as PropertyKey]: Item extends UniqueTableDataItem ? ItemUniqueColumns : never }[PropertyKey] : never; type ItemUniqueColumns> = { [Column in T['columns'][number]]: UniqueQueryTypeOrExpression }; type TableDataItemsUniqueColumnTuples> = MaybeArray extends T ? never : T extends UniqueTableDataItem ? T['columns'] : T extends TableDataItem[] ? Exclude : never; type UniqueQueryTypeOrExpression = T | Expression>; type TableDataItemsUniqueConstraints> = MaybeArray extends T ? never : T extends UniqueTableDataItem ? T['name'] : T extends UniqueTableDataItem[] ? T[number]['name'] : never; type TableDataFn> = (t: TableDataMethods) => Data; declare const tableDataMethods: TableDataMethods; declare const parseTableData: (dataFn?: TableDataFn) => TableData; declare const parseTableDataInput: (tableData: TableData, item: TableDataInput) => void; interface AdditionalNumberData { lt?: number; lte?: number; gt?: number; gte?: number; step?: number; int?: boolean; finite?: boolean; safe?: boolean; } interface BaseNumberData extends Column.Data, AdditionalNumberData {} interface AdditionalStringData { min?: number; max?: number; length?: number; email?: boolean; url?: boolean; emoji?: boolean; uuid?: boolean; cuid?: boolean; cuid2?: boolean; ulid?: boolean; regex?: RegExp; includes?: string; startsWith?: string; endsWith?: string; datetime?: { offset?: boolean; precision?: number; }; ipv4?: true; ipv6?: true; nonEmpty?: boolean; trim?: boolean; toLowerCase?: boolean; toUpperCase?: boolean; } interface StringData extends Column.Data, AdditionalStringData {} interface AdditionalDateData { min?: Date; max?: Date; } interface DateColumnData extends Column.Data, AdditionalDateData {} interface ArrayMethodsData { min?: number; max?: number; length?: number; nonEmpty?: boolean; } type Code = string | Codes; type Codes = Code[]; interface ColumnToCodeCtx { t: string; table: string; currentSchema: string; migration?: boolean; snakeCase?: boolean; } /** * Push code: this will append a code string to the last code array element when possible. * @param code - array of code to push into * @param add - code to push */ declare const addCode: (code: Code[], add: Code) => void; /** * Convert the code item into string. * * @param code - code item * @param tabs - each new line will be prefixed with the tabs. Each element of the code represents a new line * @param shift - array elements of the given code will be shifted with this sting */ declare const codeToString: (code: Code, tabs: string, shift: string) => string; declare const columnsShapeToCode: (ctx: ColumnToCodeCtx, shape: Column.Shape.QueryInit) => Codes; declare const pushTableDataCode: (code: Codes, ast: TableData) => Codes; declare const primaryKeyInnerToCode: (primaryKey: TableData.PrimaryKey, t: string) => string; declare const indexInnerToCode: (index: TableData.Index, t: string) => Codes; declare const excludeInnerToCode: (item: TableData.Exclude, t: string) => Codes; declare const constraintInnerToCode: (item: TableData.Constraint, t: string, m?: boolean) => Codes; declare const referencesArgsToCode: ({ columns, fnOrTable, foreignColumns, options }: Exclude, name?: string | false, m?: boolean) => Codes; interface NumberColumnData extends BaseNumberData, Column.Data { identity?: TableData.Identity; } interface SerialColumnData extends NumberColumnData { default: Expression; } declare abstract class NumberBaseColumn extends Column { data: NumberColumnData; operators: OperatorsNumber; } declare abstract class IntegerBaseColumn extends NumberBaseColumn> { data: NumberColumnData; constructor(schema: Schema); } declare abstract class NumberAsStringBaseColumn extends Column, OperatorsNumber, InputType> { operators: OperatorsNumber; data: Column.Data; constructor(schema: Schema); } interface DecimalColumnData extends Column.Data { numericPrecision?: number; numericScale?: number; } declare class DecimalColumn extends NumberAsStringBaseColumn { data: DecimalColumnData; operators: OperatorsNumber; dataType: "numeric"; constructor(schema: Schema, numericPrecision?: number, numericScale?: number); toCode(ctx: ColumnToCodeCtx, key: string): Code; toSQL(): string; } type IdentityColumn = Column.Modifiers.Default; declare class SmallIntColumn extends IntegerBaseColumn { dataType: "int2"; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; identity(this: T, options?: TableData.Identity): IdentityColumn; } declare class IntegerColumn extends IntegerBaseColumn { dataType: "int4"; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; identity(this: T, options?: TableData.Identity): IdentityColumn; } declare class BigIntColumn extends NumberAsStringBaseColumn { dataType: "int8"; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; identity(this: T, options?: TableData.Identity): IdentityColumn; } declare class RealColumn extends NumberBaseColumn> { dataType: "float4"; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class DoublePrecisionColumn extends NumberAsStringBaseColumn { dataType: "float8"; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class SmallSerialColumn extends IntegerBaseColumn { dataType: "int2"; data: SerialColumnData; constructor(schema: Schema); toSQL(): string; toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class SerialColumn extends IntegerBaseColumn { dataType: "int4"; data: SerialColumnData; constructor(schema: Schema); toSQL(): string; toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class BigSerialColumn extends NumberAsStringBaseColumn { dataType: "int8"; data: SerialColumnData; constructor(schema: Schema); toSQL(): string; toCode(ctx: ColumnToCodeCtx, key: string): Code; } interface TimeInterval { years?: number; months?: number; days?: number; hours?: number; minutes?: number; seconds?: number; } type DateColumnInput = string | number | Date; declare abstract class DateBaseColumn extends Column, OperatorsDate, DateColumnInput, string, ReturnType> { data: DateColumnData; operators: OperatorsDate; asNumber: Schema['dateAsNumber']; asDate: Schema['dateAsDate']; constructor(schema: Schema); } declare class DateColumn extends DateBaseColumn { dataType: "date"; toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare abstract class DateTimeBaseClass extends DateBaseColumn { data: DateColumnData & { dateTimePrecision?: number; }; constructor(schema: Schema, dateTimePrecision?: number); toSQL(): string; } declare abstract class DateTimeTzBaseClass extends DateTimeBaseClass { abstract baseDataType: string; toSQL(): string; } declare class TimestampColumn extends DateTimeBaseClass { dataType: "timestamp"; toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class TimestampTZColumn extends DateTimeTzBaseClass { dataType: "timestamptz"; baseDataType: "timestamp"; toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class TimeColumn extends Column, OperatorsTime> { data: DateColumnData & { dateTimePrecision?: number; }; dataType: "time"; operators: OperatorsTime; constructor(schema: Schema, dateTimePrecision?: number); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class IntervalColumn extends Column, OperatorsDate> { data: Column.Data & { fields?: string; precision?: number; }; dataType: "interval"; operators: OperatorsDate; constructor(schema: Schema, fields?: string, precision?: number); toCode(ctx: ColumnToCodeCtx, key: string): Code; toSQL(): string; } declare class EnumColumn extends Column { enumName: string; options: T; operators: OperatorsOrdinalText; dataType: string; constructor(schema: Schema, enumName: string, options: T, schemaType: SchemaType); toCode(ctx: ColumnToCodeCtx, key: string): Code; toSQL(): string; } interface ArrayColumnValue { type: unknown; inputSchema: any; inputType: unknown; outputType: unknown; outputSchema: any; queryType: any; querySchema: any; toSQL(): string; toCode(ctx: ColumnToCodeCtx, key: string): Code; data: Column.Data; } interface ArrayData extends Column.Data, ArrayMethodsData { item: Item; arrayDims: number; } declare class ArrayColumn extends Column, Item['inputType'][], Item['outputType'][], OutputType, Item['queryType'][], QueryType> { dataType: "array"; operators: OperatorsArray; data: ArrayData; constructor(schema: Schema, item: Item, inputType: InputType, outputType?: OutputType, queryType?: QueryType); toSQL(): string; toCode(this: ArrayColumn, ctx: ColumnToCodeCtx, key: string): Code; } declare class JSONColumn extends Column { dataType: "jsonb"; operators: OperatorsJson; constructor(schema: Schema, inputType: Schema['type']); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class JSONTextColumn extends Column, OperatorsText> { dataType: "json"; operators: OperatorsText; private static _instance; static get instance(): JSONTextColumn; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } interface DefaultSchemaConfig extends ColumnSchemaConfig { parse(this: T, fn: (input: T['type']) => Output): Column.Modifiers.Parse; parseNull(this: T, fn: () => Output): Column.Modifiers.ParseNull; encode(this: T, fn: (input: Input) => unknown): Column.Modifiers.Encode; /** * @deprecated use narrowType instead */ asType(this: T, _fn: (type: () => { type: Type; inputType: Input; outputType: Output; queryType: Query; }) => Types): { [K in keyof T]: K extends keyof Types ? Types[K] : T[K] }; narrowType(this: T, _fn: (type: () => { inputType: T['inputType'] extends never ? never : Type; outputType: Type; queryType: Type; }) => Types): { [K in keyof T]: K extends keyof Types ? Types[K] : T[K] }; narrowAllTypes(this: T, _fn: (type: () => { inputType: undefined extends Types['input'] ? T['inputType'] : Types['input']; outputType: undefined extends Types['output'] ? T['outputType'] : Types['output']; queryType: undefined extends Types['query'] ? T['queryType'] : Types['query']; }) => Types): { [K in keyof T]: K extends keyof Types ? Types[K] : T[K] }; dateAsNumber(this: T): Column.Modifiers.Parse; dateAsDate(this: T): Column.Modifiers.Parse; enum(dataType: string, type: T): EnumColumn; array(item: Item): ArrayColumn; json(): JSONColumn : T, DefaultSchemaConfig>; inputSchema(): undefined; outputSchema(): undefined; querySchema(): undefined; updateSchema(): undefined; pkeySchema(): undefined; smallint(): SmallIntColumn; integer(): IntegerColumn; real(): RealColumn; smallSerial(): SmallSerialColumn; serial(): SerialColumn; bigint(): BigIntColumn; decimal(precision?: number, scale?: number): DecimalColumn; doublePrecision(): DoublePrecisionColumn; bigSerial(): BigSerialColumn; money(): MoneyColumn; varchar(limit?: number): VarCharColumn; text(): TextColumn; string(limit?: number): StringColumn; citext(): CitextColumn; date(): DateColumn; timestampNoTZ(precision?: number): TimestampColumn; timestamp(precision?: number): TimestampTZColumn; } declare const defaultSchemaConfig: DefaultSchemaConfig; type TextColumnData = StringData; declare abstract class TextBaseColumn extends Column, Ops> { data: TextColumnData; operators: Ops; constructor(schema: Schema, schemaType?: ReturnType); } declare abstract class LimitedTextBaseColumn extends TextBaseColumn { data: TextColumnData & { maxChars?: number; }; operators: OperatorsOrdinalText; constructor(schema: Schema, limit?: number); toSQL(): string; } declare class VarCharColumn extends LimitedTextBaseColumn { dataType: "varchar"; toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class StringColumn extends VarCharColumn { constructor(schema: Schema, limit?: number); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class TextColumn extends TextBaseColumn { dataType: "text"; data: TextColumnData & { minArg?: number; maxArg?: number; }; operators: OperatorsOrdinalText; private static _instance; static get instance(): TextColumn; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class ByteaColumn extends Column, OperatorsOrdinalText, Buffer, Buffer, ReturnType, string, ReturnType> { dataType: "bytea"; operators: OperatorsOrdinalText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class PointColumn extends Column, OperatorsText> { dataType: "point"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class LineColumn extends Column, OperatorsText> { dataType: "line"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class LsegColumn extends Column, OperatorsText> { dataType: "lseg"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class BoxColumn extends Column, OperatorsText> { dataType: "box"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class PathColumn extends Column, OperatorsText> { dataType: "path"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class PolygonColumn extends Column, OperatorsText> { dataType: "polygon"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class CircleColumn extends Column, OperatorsText> { dataType: "circle"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class MoneyColumn extends Column, OperatorsNumber, string | number, number, ReturnType, string | number> { dataType: "money"; data: NumberColumnData; operators: OperatorsNumber; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class CidrColumn extends Column, OperatorsText> { dataType: "cidr"; operators: OperatorsText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class InetColumn extends Column, OperatorsOrdinalText> { dataType: "inet"; operators: OperatorsOrdinalText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class MacAddrColumn extends Column, OperatorsOrdinalText> { dataType: "macaddr"; operators: OperatorsOrdinalText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class MacAddr8Column extends Column, OperatorsOrdinalText> { dataType: "macaddr8"; operators: OperatorsOrdinalText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class BitColumn extends Column, OperatorsOrdinalText> { dataType: "bit"; operators: OperatorsOrdinalText; data: Column.Data & { length: number; }; constructor(schema: Schema, length: number); toCode(ctx: ColumnToCodeCtx, key: string): Code; toSQL(): string; } declare class BitVaryingColumn extends Column, OperatorsOrdinalText> { dataType: "varbit"; operators: OperatorsOrdinalText; data: Column.Data & { length?: number; }; constructor(schema: Schema, length?: number); toCode(ctx: ColumnToCodeCtx, key: string): Code; toSQL(): string; } type TsVectorGeneratedColumns = string[] | SearchWeightRecord; declare class TsVectorColumn extends Column, OperatorsOrdinalText> { defaultLanguage: string; dataType: "tsvector"; operators: OperatorsOrdinalText; constructor(schema: Schema, defaultLanguage?: string); toCode(ctx: ColumnToCodeCtx, key: string): Code; /** * For `tsvector` column type, it can also accept language (optional) and columns: * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('post', (t) => ({ * id: t.id(), * title: t.text(), * body: t.text(), * // join title and body into a single ts_vector * generatedTsVector: t.tsvector().generated(['title', 'body']).searchIndex(), * // with language: * spanishTsVector: t * .tsvector() * .generated('spanish', ['title', 'body']) * .searchIndex(), * })); * }); * ``` * * @param args */ generated(this: T, ...args: StaticSQLArgs | [language: string, columns: TsVectorGeneratedColumns] | [columns: TsVectorGeneratedColumns]): Column.Modifiers.Generated; } declare class TsQueryColumn extends Column, OperatorsOrdinalText> { dataType: "tsquery"; operators: OperatorsOrdinalText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class UUIDColumn extends Column, OperatorsOrdinalText> { dataType: "uuid"; operators: OperatorsOrdinalText; constructor(schema: Schema); /** * see {@link Column.primaryKey} */ primaryKey(this: T, name?: Name): // using & bc otherwise the return type doesn't match `primaryKey` in ColumnType and TS complains T & { data: { primaryKey: Name; default: RawSqlBase; }; }; toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class XMLColumn extends Column, OperatorsText> { dataType: "xml"; operators: OperatorsText; private static _instance; static get instance(): XMLColumn; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class CitextColumn extends TextBaseColumn { dataType: "citext"; data: TextColumnData & { minArg?: number; maxArg?: number; }; operators: OperatorsOrdinalText; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare class BooleanColumn extends Column, OperatorsBoolean> { dataType: "bool"; operators: OperatorsBoolean; private static _instance; static get instance(): BooleanColumn; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } interface Timestamps { createdAt: Column.Modifiers.Default; updatedAt: Column.Modifiers.Default; } interface TimestampHelpers { /** * Add `createdAt` and `updatedAt` timestamps. Both have `now()` as a default, `updatedAt` is automatically updated during update. */ timestamps(this: { timestamp(): T; }): Timestamps; /** * The same as {@link timestamps}, for the timestamp without time zone time. */ timestampsNoTZ(this: { timestampNoTZ(): T; }): Timestamps; } declare class CustomTypeColumn extends Column, OperatorsAny> { typeName: string; typeSchema?: string | undefined; operators: OperatorsAny; dataType: string; constructor(schema: Schema, typeName: string, typeSchema?: string | undefined, extension?: string); toCode(ctx: ColumnToCodeCtx, key: string): Code; as(this: T, column: C): C; } declare class DomainColumn extends CustomTypeColumn { toCode(ctx: ColumnToCodeCtx, key: string): Code; } interface PostgisPoint { lon: number; lat: number; srid?: number; } declare class PostgisGeographyPointColumn extends Column, OperatorsAny> { dataType: string; operators: OperatorsAny; static encode: ({ srid, lon, lat }: PostgisPoint) => string; static isDefaultPoint(typmod: number): boolean; constructor(schema: Schema); toCode(ctx: ColumnToCodeCtx, key: string): Code; } declare const getColumnTypes: (types: ColumnTypes, fn: (t: ColumnTypes) => Shape, nowSQL: string | undefined, language: string | undefined) => Shape; interface DefaultColumnTypes extends TimestampHelpers { schema: SchemaConfig; enum: SchemaConfig['enum']; array: SchemaConfig['array']; name(this: T, name: string): T; sql: SqlFn; smallint: SchemaConfig['smallint']; integer: SchemaConfig['integer']; bigint: SchemaConfig['bigint']; numeric: SchemaConfig['decimal']; decimal: SchemaConfig['decimal']; real: SchemaConfig['real']; doublePrecision: SchemaConfig['doublePrecision']; identity(options?: TableData.Identity): IdentityColumn>; smallSerial: SchemaConfig['smallSerial']; serial: SchemaConfig['serial']; bigSerial: SchemaConfig['bigSerial']; money: SchemaConfig['money']; varchar: SchemaConfig['varchar']; text: SchemaConfig['text']; string: SchemaConfig['string']; citext: SchemaConfig['citext']; bytea(): ByteaColumn; date: SchemaConfig['date']; timestampNoTZ: SchemaConfig['timestampNoTZ']; timestamp: SchemaConfig['timestamp']; time(precision?: number): TimeColumn; interval(fields?: string, precision?: number): IntervalColumn; boolean(): BooleanColumn; point(): PointColumn; line(): LineColumn; lseg(): LsegColumn; box(): BoxColumn; path(): PathColumn; polygon(): PolygonColumn; circle(): CircleColumn; cidr(): CidrColumn; inet(): InetColumn; macaddr(): MacAddrColumn; macaddr8(): MacAddr8Column; bit(length: number): BitColumn; bitVarying(length?: number): BitVaryingColumn; tsvector(): TsVectorColumn; tsquery(): TsQueryColumn; uuid(): UUIDColumn; xml(): XMLColumn; json: SchemaConfig['json']; jsonText(): JSONTextColumn; type(dataType: string): CustomTypeColumn; domain(dataType: string): DomainColumn; geography: { point(): PostgisGeographyPointColumn; }; } declare const makeColumnTypes: (schema: SchemaConfig) => DefaultColumnTypes; type SimpleJoinItemNonSubQueryArgs = [{ [K: string]: string | Expression; } | Expression | true] | [leftColumn: string | Expression, rightColumn: string | Expression] | [leftColumn: string | Expression, op: string, rightColumn: string | Expression]; type JoinItemArgs = { u?: true; c?: Column.QueryColumns; l: SubQueryForSql; a: string; i?: boolean; } | { u?: true; c?: Column.QueryColumns; j: IsQuery; s: boolean; r?: IsQuery; } | { u?: true; c?: Column.QueryColumns; w: string; r: IsQuery; s: boolean; } | { u?: true; c?: Column.QueryColumns; w: string; a: SimpleJoinItemNonSubQueryArgs; } | { u?: true; c?: Column.QueryColumns; q: IsQuery; s: boolean; } | { u?: true; c?: Column.QueryColumns; q: IsQuery; r: IsQuery; s: boolean; } | { u?: true; c?: Column.QueryColumns; q: IsQuery; a: SimpleJoinItemNonSubQueryArgs; s: boolean; } | { u?: true; c: Column.Shape.Data; a: string; d: RecordUnknown[]; }; interface JoinItem { type: string; args: JoinItemArgs; } type getValueKey = typeof getValueKey; declare const getValueKey: unique symbol; interface PickQueryDataParsers { defaultParsers?: ColumnsParsers; parsers?: ColumnsParsers; batchParsers?: BatchParsers; } type ColumnParser = FnUnknownToUnknown; interface BatchParser { path: string[]; fn: (path: string[], queryResult: { rows: unknown[]; }) => MaybePromise; } type ColumnsParsers = { [K in string | getValueKey]?: ColumnParser }; type BatchParsers = BatchParser[]; interface QueryThen { (onfulfilled?: (value: T) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; } type QueryThenShallowSimplify = QueryThen>; type QueryThenShallowSimplifyArr = QueryThen[]>; type QueryThenShallowSimplifyOptional = QueryThen | undefined>; type QueryThenByQuery = T['returnType'] extends undefined | 'all' ? QueryThenShallowSimplifyArr> : T['returnType'] extends 'one' ? QueryThenShallowSimplifyOptional> : T['returnType'] extends 'oneOrThrow' ? QueryThenShallowSimplify> : T['returnType'] extends 'value' ? QueryThen : T['returnType'] extends 'valueOrThrow' ? QueryThen : T['returnType'] extends 'rows' ? QueryThen[keyof Result][][]> : T['returnType'] extends 'pluck' ? QueryThen : QueryThen; type QueryThenByReturnType = T extends undefined | 'all' ? QueryThenShallowSimplifyArr> : T extends 'one' ? QueryThenShallowSimplifyOptional> : T extends 'oneOrThrow' ? QueryThenShallowSimplify> : T extends 'value' ? QueryThen : T extends 'valueOrThrow' ? QueryThen : T extends 'rows' ? QueryThen[keyof Result][][]> : T extends 'pluck' ? QueryThen : QueryThen; interface QueryCatch { (this: { then: (onfulfilled?: (value: Q) => any) => any; }, onrejected?: (reason: any) => TResult | PromiseLike): Promise; } interface QueryCatchers { catchUniqueError(this: { then: (onfulfilled?: (value: ThenResult) => any) => any; }, fn: (reason: QueryError) => CatchResult): Promise; } type WithSelectable = keyof W['shape'] | `${W['table']}.${keyof W['shape'] & string}`; /** * The first argument of all `join` and `joinLateral` methods. * See argument of {@link join}. */ type JoinFirstArg = PickQueryResultAs | keyof T['relations'] | keyof T['withData'] | ((q: { [K in keyof T['relations']]: T['relations'][K]['query'] }) => PickQueryResultAs) | FnPickQueryResultAs; interface FnPickQueryResultAs { (): PickQueryResultAs; } /** * Arguments of `join` methods (not `joinLateral`). * See {@link join} */ type JoinArgs> = Arg extends PickQueryResultAs ? [conditions: { [K in JoinSelectable]: keyof T['__selectable'] | Expression } | Expression] | [leftColumn: JoinSelectable | Expression, rightColumn: keyof T['__selectable'] | Expression] | [leftColumn: JoinSelectable | Expression, op: string, rightColumn: keyof T['__selectable'] | Expression] : Arg extends keyof T['withData'] ? JoinWithArgs : EmptyTuple; /** * Column names of the joined table that can be used to join. * Derived from 'result', not from 'shape', * because if the joined table has a specific selection, it will be wrapped like: * ```sql * JOIN (SELECT something FROM joined) joined ON joined.something = ... * ``` * And the selection becomes available to use in the `ON` and to select from the joined table. */ type JoinSelectable = keyof Q['result'] | `${Q['__as']}.${keyof Q['result'] & string}`; type JoinWithArgs = [conditions: { [K in WithSelectable]: keyof T['__selectable'] | Expression } | Expression] | [leftColumn: WithSelectable | Expression, rightColumn: keyof T['__selectable'] | Expression] | [leftColumn: WithSelectable | Expression, op: string, rightColumn: keyof T['__selectable'] | Expression]; type JoinResultRequireMain = { [K in keyof T]: K extends '__selectable' ? T['__selectable'] & JoinedSelectable : T[K] }; /** * Result of all `join` methods, not `joinLateral`. * Adds joined table columns from its 'result' to the '__selectable' of the query. */ type JoinResult = RequireMain extends true ? { [K in keyof T]: K extends '__selectable' ? T['__selectable'] & Joined['__selectable'] : K extends 'relations' ? { [K in keyof T['relations'] | keyof Joined['relations']]: K extends keyof Joined['relations'] ? Joined['relations'][K] : T['relations'][K] } : T[K] } : { [K in keyof T]: K extends '__selectable' ? { [K in keyof T['__selectable']]: { as: T['__selectable'][K]['as']; column: Column.Modifiers.QueryColumnToNullable; } } & Joined['__selectable'] : K extends 'result' ? { [K in keyof T['result']]: Column.Modifiers.QueryColumnToNullable } : K extends 'then' ? QueryThenByQuery }> : K extends 'relations' ? { [K in keyof T['relations'] | keyof Joined['relations']]: K extends keyof Joined['relations'] ? Joined['relations'][K] : T['relations'][K] } : T[K] }; /** * Calls {@link JoinResult} with either callback result, if join has a callback, * or with a query derived from the first join argument. */ type JoinResultFromArgs = JoinResult['result'], ReturnType['__as'], ReturnType['relations'], RequireJoined> : Arg extends PickQueryHasSelectResultShapeAsRelations ? JoinResultSelectable : Arg extends keyof T['relations'] ? JoinResultSelectable : Arg extends FirstArgCallback ? JoinResultSelectable['shape'], ReturnType['__as'], ReturnType['relations'], RequireJoined> : Arg extends keyof T['withData'] ? T['withData'][Arg] extends WithDataItem ? JoinResultSelectable : never : never, RequireMain>; interface GenericJoinCallback { (...args: any[]): PickQueryResultAsRelations; } interface FirstArgCallback { (...args: any[]): PickQueryShapeAsRelations; } /** * Result of all `joinLateral` methods. * Adds joined table columns from its 'result' to the '__selectable' of the query. * * @param T - query type to join to * @param Arg - first arg of join, see {@link JoinFirstArg} * @param RequireJoined - when false, joined table shape will be mapped to make all columns optional */ type JoinLateralResult = JoinAddSelectable>; /** * Build `selectable` type for joined table. * * When `RequireJoined` parameter is false, * the result type of the joined table will be mapped to make all columns optional. * * Callback may override the joined table alias. * * The resulting selectable receives all joined table columns prefixed with the table name or alias, * and a star prefixed with the table name or alias to select all joined columns. */ type JoinResultSelectable = RequireJoined extends true ? { __selectable: { [K in '*' | (keyof Result & string) as `${As}.${K}`]: K extends '*' ? { as: As; column: ColumnsShape.MapToObjectColumn; } : { as: K; column: Result[K]; } }; relations: { [K in keyof JoinedRelations & string as `${As}.${K}`]: JoinedRelations[K] }; } : { __selectable: { [K in '*' | (keyof Result & string) as `${As}.${K}`]: K extends '*' ? { as: As; column: ColumnsShape.MapToNullableObjectColumn; } : { as: K; column: Column.Modifiers.QueryColumnToNullable; } }; relations: { [K in keyof JoinedRelations & string as `${As}.${K}`]: JoinedRelations[K] }; }; type JoinAddSelectable = { [K in keyof T]: K extends '__selectable' ? T['__selectable'] & Joined['__selectable'] : T[K] }; /** * Map the first argument of `join` or `joinLateral` to a query type. * * `with` table arg is mapped into `QueryBase`, * query arg is returned as is, * relation name is replaced with a relation table. */ type JoinArgToQuery> = Arg extends keyof T['withData'] ? T['withData'][Arg] extends WithDataItem ? { [K in 'result' | '__as' | keyof T]: K extends '__as' ? T['withData'][Arg]['table'] : K extends '__selectable' ? { [K in keyof T['withData'][Arg]['shape'] & string as `${T['withData'][Arg]['table']}.${K}`]: { as: K; column: T['withData'][Arg]['shape'][K]; } } : K extends 'result' ? T['withData'][Arg]['shape'] : K extends keyof T ? T[K] : never } : never : Arg extends PickQuerySelectableResultAs ? Arg : Arg extends keyof T['relations'] ? T['relations'][Arg]['query'] : Arg extends JoinArgToQueryCallback ? ReturnType : never; interface JoinArgToQueryCallback { (...args: any[]): IsQuery; } /** * Type of the `join` callback (not `joinLateral`). * * Receives a query builder that can access columns of both the main and the joined table. * * The query builder is limited to `or` and `where` methods only. * * Callback must return a query builder. */ interface JoinCallback> { (q: JoinQueryBuilder>): IsQuery; } type JoinCallbackArgs> = [cb?: JoinCallback | true]; /** * Type of {@link QueryJoin.join} query method. */ interface JoinQueryMethod { , Cb extends JoinCallbackArgs>(this: T, arg: Arg, ...args: Cb | JoinArgs): JoinResultFromArgs; } declare class QueryJoin { /** * ## Select relation * * Before joining a table, consider if selecting a relation is enough for your case: * * ```ts * // select users with profiles * // result type is Array<{ name: string, profile: Profile }> * await db.user.select('name', { * profile: (q) => q.profile, * }); * * // select posts with counts of comments, filter and order by comments count * // result type is Array * await db.post * .select('*', { * commentsCount: (q) => q.comments.count(), * }) * .where({ commentsCount: { gt: 10 } }) * .order({ commentsCount: 'DESC' }); * * // select authors with array of their book titles * // result type is Array * await db.author.select('*', { * books: (q) => q.books.pluck('title'), * }); * ``` * * Internally, such selects will use `LEFT JOIN LATERAL` to join a relation. * If you're loading users with profiles (one-to-one relation), and some users don't have a profile, `profile` property will have `NULL` for such users. * If you want to load only users that have profiles, and filter out the rest, add `.join()` method to the relation without arguments: * * ```ts * // load only users who have a profile * await db.user.select('*', { * profile: (q) => q.profile.join(), * }); * * // load only users who have a specific profile * await db.user.select('*', { * profile: (q) => q.profile.join().where({ age: { gt: 20 } }), * }); * ``` * * You can also use this `.join()` method on the one-to-many relations, and records with empty array will be filtered out: * * ```ts * // posts that have no tags won't be loaded * // result type is Array * db.post.select('*', { * tags: (q) => q.tags.join(), * }); * ``` * * # join * * `join` methods allows to join other tables, relations by name, [with](/guide/advanced-queries#with) statements, sub queries. * * All the `join` methods accept the same arguments, but returning type is different because with `join` it's guaranteed to load joined table, and with `leftJoin` the joined table columns may be `NULL` when no matching record was found. * * For the following examples, imagine you have a `User` table with `id` and `name`, and `Message` table with `id`, `text`, messages belongs to user via `userId` column: * * ```ts * export class UserTable extends BaseTable { * readonly table = 'user'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * name: t.text(), * })); * * relations = { * messages: this.hasMany(() => MessageTable, { * primaryKey: 'id', * foreignKey: 'userId', * }), * }; * } * * export class MessageTable extends BaseTable { * readonly table = 'message'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * text: t.text(), * ...t.timestamps(), * })); * * relations = { * user: this.belongsTo(() => UserTable, { * primaryKey: 'id', * foreignKey: 'userId', * }), * }; * } * ``` * * `join` is a method for SQL `JOIN`, which is equivalent to `INNER JOIN`, `LEFT INNERT JOIN`. * * When no matching record is found, it will skip records of the main table. * * ### join relation * * When relations are defined between the tables, you can join them by a relation name. * Joined table can be references from `where` and `select` by a relation name. * * ```ts * const result = await db.user * .join('messages') * // after joining a table, you can use it in `where` conditions: * .where({ 'messages.text': { startsWith: 'Hi' } }) * .select( * 'name', // name is User column, table name may be omitted * 'messages.text', // text is the Message column, and the table name is required * ); * * // result has the following type: * const ok: { name: string; text: string }[] = result; * ``` * * The first argument can also be a callback, where instead of relation name as a string you're picking it as a property of `q`. * In such a way, you can alias the relation with `as`, add `where` conditions, use other query methods. * * ```ts * const result = await db.user.join((q) => * q.messages.as('m').where({ text: 'some text' }), * ); * ``` * * Optionally, you can pass a second callback argument, it makes `on` and `orOn` methods available. * * But remember that when joining a relation, the relevant `ON` conditions are already handled automatically. * * ```ts * const result = await db.user.join( * (q) => q.messages.as('m'), * (q) => * q * .on('messages.text', 'user.name') // additionally, match message with user name * .where({ text: 'some text' }), // you can add `where` in a second callback as well. * ); * ``` * * ### join a relation of the joined * * After joining a relation or a table: * * ```ts * db.post.join('comments'); * * db.post.join(() => db.comment); * ``` * * You can join a relation of that joined table: * * ```ts * db.post.join('comments').join('comments.author'); * * db.post.join(() => db.comment).join('comment.author'); * ``` * * Note that in the first case it's `comments` - a relation name, while in the second case it is a table name. * * ### joins deduplication * * When joining the same table with the same condition more than once, duplicated joins will be ignored: * * ```ts * // joining a relation * db.post.join('comments').join('comments'); * * // joining a table with a condition * db.post * .join('comments', 'comments.postId', 'post.id') * .join('comments', 'comments.postId', 'post.id'); * ``` * * Both queries will produce SQL with only 1 join * * ```sql * SELECT * FROM post JOIN comments ON comments.postId = post.id * ``` * * However, this is only possible if the join has no dynamic values: * * ```ts * db.post * .join('comments', (q) => q.where({ rating: { gt: 5 } })) * .join('comments', (q) => q.where({ rating: { gt: 5 } })); * ``` * * Both joins above have the same `{ gt: 5 }`, but still, the `5` is a dynamic value and in this case joins will be duplicated, * resulting in a database error. * * ### select full joined records * * `select` supports selecting a full record of a previously joined table by passing a table name with `.*` at the end: * * ```ts * const result = await db.book.join('author').select('title', { * author: 'author.*', * }); * * // result has the following type: * const ok: { * // title of the book * title: string; * // a full author record is included: * author: { id: number; name: string; updatedAt: Date; createdAt: Date }; * }[] = result; * ``` * * It works fine for `1:1` (`belongsTo`, `hasOne`) relations, but it may have an unexpected result for `1:M` or `M:M` (`hasMany`, `hasAndBelongsToMany`) relations. * For any kind of relation, it results in one main table record with data of exactly one joined table record, i.e. when selecting in this way, the records **won't** be collected into arrays. * * ```ts * const result = await db.user * .join('messages') * .where({ 'messages.text': { startsWith: 'Hi' } }) * .select('name', { messages: 'messages.*' }); * * // result has the following type: * const ok: { * name: string; * // full message is included: * messages: { id: number; text: string; updatedAt: Date; createdAt: Date }; * }[] = result; * ``` * * Because it's a one-to-many relation, one user has many messages, the user data will be duplicated for different messages data: * * | name | msg | * | ------ | ------------------------------ | * | user 1 | `{ id: 1, text: 'message 1' }` | * | user 1 | `{ id: 2, text: 'message 2' }` | * | user 1 | `{ id: 3, text: 'message 3' }` | * * ### join table * * If relation wasn't defined, provide a `db.table` instance and specify columns for the join. * Joined table can be references from `where` and `select` by a table name. * * ```ts * db.user * .join(db.message, 'userId', 'user.id') * .where({ 'message.text': { startsWith: 'Hi' } }) * .select('name', 'message.text'); * ``` * * The name of the joining table can be omitted, but not the name of the main table: * * ```ts * db.user.join(db.message, 'userId', 'user.id'); * ``` * * Joined table can have an alias for referencing it further: * * ```ts * db.user * .join(db.message.as('m'), 'message.userId', 'user.id') * .where({ 'm.text': { startsWith: 'Hi' } }) * .select('name', 'm.text'); * ``` * * Joined table can be selected as an object as well as the relation join above: * * ```ts * const result = await db.user * .join(db.message.as('m'), 'message.userId', 'user.id') * .where({ 'm.text': { startsWith: 'Hi' } }) * .select('name', { msg: 'm.*' }); * * // result has the following type: * const ok: { * name: string; * // full message is included as msg: * msg: { id: number; text: string; updatedAt: Date; createdAt: Date }; * }[] = result; * ``` * * You can provide a custom comparison operator * * ```ts * db.user.join(db.message, 'userId', '!=', 'user.id'); * ``` * * Join can accept raw SQL for the `ON` part of join: * * ```ts * db.user.join( * db.message, * // `sql` can be imported from your `BaseTable` file * sql`lower("message"."text") = lower("user"."name")`, * ); * ``` * * Join can accept raw SQL instead of columns: * * ```ts * db.user.join( * db.message, * sql`lower("message"."text")`, * sql`lower("user"."name")`, * ); * * // with operator: * db.user.join( * db.message, * sql`lower("message"."text")`, * '!=', * sql`lower("user"."name")`, * ); * ``` * * To join based on multiple columns, you can provide an object where keys are joining table columns, and values are main table columns or a raw SQL: * * ```ts * db.user.join(db.message, { * 'message.userId': 'user.id', * * // joined table name may be omitted * userId: 'user.id', * * // value can be a raw SQL expression: * text: sql`lower("user"."name")`, * }); * ``` * * Join all records without conditions by providing `true`: * * ```ts * db.user.join(db.message, true); * ``` * * Join methods can accept a callback with a special query builder that has `on` and `orOn` methods for handling advanced cases: * * ```ts * db.user.join( * db.message, * (q) => * q * .on('message.userId', 'user.id') * // joined table name may be omitted * .on('userId', 'user.id') * // operator can be specified: * .on('userId', '!=', 'user.id') * // operator can be specified with table names as well: * .on('message.userId', '!=', 'user.id') * // `.orOn` takes the same arguments as `.on` and acts like `.or`: * .on('userId', 'user.id') // where message.userId = user.id * .orOn('text', 'user.name'), // or message.text = user.name * ); * ``` * * Column names in the where conditions are applied for the joined table, but you can specify a table name to add a condition for the main table. * * ```ts * db.user.join(db.message, (q) => * q * .on('userId', 'user.id') * .where({ * // not prefixed column name is for joined table: * text: { startsWith: 'hello' }, * // specify a table name to set condition on the main table: * 'user.name': 'Bob', * }) * // id is a column of a joined table Message * .whereIn('id', [1, 2, 3]) * // condition for id of a user * .whereIn('user.id', [4, 5, 6]), * ); * ``` * * The query above will generate the following SQL (simplified): * * ```sql * SELECT * FROM "user" * JOIN "message" * ON "message"."userId" = "user"."id" * AND "message"."text" ILIKE 'hello%' * AND "user"."name" = 'Bob' * AND "message"."id" IN (1, 2, 3) * AND "user"."id" IN (4, 5, 6) * ``` * * The join argument can be a query with `select`, `where`, and other methods. In such case, it will be handled as a sub query: * * ```ts * db.user.join( * db.message * .select('id', 'userId', 'text') * .where({ text: { startsWith: 'Hi' } }) * .as('t'), * 'userId', * 'user.id', * ); * ``` * * It will produce such SQL: * * ```sql * SELECT * FROM "user" * JOIN ( * SELECT "t"."id", "t"."userId", "t"."text" * FROM "message" AS "t" * ) "t" ON "t"."userId" = "user"."id" * ``` * * ## implicit join lateral * * `JOIN`'s source expression that comes before `ON` cannot access other tables, but in some cases this may be needed. * * For example, let's consider joining last 10 messages of a user: * * ```ts * await db.user.join('messages', (q) => q.order({ createdAt: 'DESC' }).limit(10)); * ``` * * When the `join`'s callback returns a more complex query than the one that simply applies certain conditions, * it will implicitly generate a `JOIN LATERAL` SQL query, as the following: * * ```sql * SELECT * * FROM "user" * JOIN LATERAL ( * SELECT * * FROM "message" AS "messages" * WHERE "message"."userId" = "user"."id" * ORDER BY "message"."createdAt" DESC * LIMIT 10 * ) "messages" ON true * ``` * * @param arg - {@link JoinFirstArg} * @param args - {@link JoinArgs} */ join, Cb extends JoinCallbackArgs>(this: T, arg: Arg, ...args: Cb | JoinArgs): JoinResultFromArgs; /** * `leftJoin` is a method for SQL `LEFT JOIN`, which is equivalent to `OUTER JOIN`, `LEFT OUTER JOIN`. * * When no matching record is found, it will fill joined table columns with `NULL` values in the result rows. * * Works just like `join`, except for result type that may have `null`: * * ```ts * const result = await db.user * .leftJoin('messages') * .select('name', 'messages.text'); * * // the same query, but joining table explicitly * const result2: typeof result = await db.user * .leftJoin(db.message, 'userId', 'user.id') * .select('name', 'message.text'); * * // result has the following type: * const ok: { name: string; text: string | null }[] = result; * ``` * * @param arg - {@link JoinFirstArg} * @param args - {@link JoinArgs} */ leftJoin, Cb extends JoinCallbackArgs>(this: T, arg: Arg, ...args: Cb | JoinArgs): JoinResultFromArgs; /** * `rightJoin` is a method for SQL `RIGHT JOIN`, which is equivalent to `RIGHT OUTER JOIN`. * * Takes the same arguments as `json`. * * It will load all records from the joining table, and fill the main table columns with `null` when no match is found. * * The columns of the table you're joining to are becoming nullable when using `rightJoin`. * * ```ts * const result = await db.user * .rightJoin('messages') * .select('name', 'messages.text'); * * // even though name is not a nullable column, it becomes nullable after using rightJoin * const ok: { name: string | null; text: string }[] = result; * ``` * * @param arg - {@link JoinFirstArg} * @param args - {@link JoinArgs} */ rightJoin, Cb extends JoinCallbackArgs>(this: T, arg: Arg, ...args: Cb | JoinArgs): JoinResultFromArgs; /** * `fullJoin` is a method for SQL `FULL JOIN`, which is equivalent to `FULL OUTER JOIN`. * * Takes the same arguments as `json`. * * It will load all records from the joining table, both sides of the join may result in `null` values when there is no match. * * All columns become nullable after using `fullJoin`. * * ```ts * const result = await db.user * .rightJoin('messages') * .select('name', 'messages.text'); * * // all columns can be null * const ok: { name: string | null; text: string | null }[] = result; * ``` * * @param arg - {@link JoinFirstArg} * @param args - {@link JoinArgs} */ fullJoin, Cb extends JoinCallbackArgs>(this: T, arg: Arg, ...args: Cb | JoinArgs): JoinResultFromArgs; /** * `joinLateral` allows joining a table with a sub-query that can reference the main table of current query and the other joined tables. * * First argument is the other table you want to join, or a name of relation, or a name of `with` defined table. * * Second argument is a callback where you can reference other tables using `on` and `orOn`, select columns, do `where` conditions, and use any other query methods to build a sub-query. * * Note that the regular `join` will also generate `JOIN LATERAL` SQL expression when the query returned from callback is complex enough (see the bottom of {@link join} description). * * ```ts * // joinLateral messages relation, alias it as `m` * // without aliasing you can refer to the message by a table name * db.user * .joinLateral(db.message.as('m'), (q) => * q * // select message columns * .select('text') * // join the message to the user, column names can be prefixed with table names * .on('authorId', 'user.id') * // message columns are available without prefixing, * // outer table columns are available with a table name * .where({ text: 'some text', 'user.name': 'name' }) * .order({ createdAt: 'DESC' }), * ) * // only selected message columns are available in select and where * .select('id', 'name', 'm.text') * .where({ 'm.text': messageData.text }); * ``` * * As well as simple `join`, `joinLateral` can select an object of full joined record: * * ```ts * // join by relation name * const result = await db.user * .joinLateral('messages', (q) => q.as('message')) // alias to 'message' * .select('name', { message: 'message.*' }); * * // result has the following type: * const ok: { * name: string; * // full message is included: * message: { id: number; text: string; updatedAt: Date; createdAt: Date }; * }[] = result; * ``` * * `message` can be aliased withing the `select` as well as in case of a simple `join`: * * ```ts * // join by relation name * const result = await db.user * .joinLateral('messages', (q) => q.as('message')) // alias to 'message' * .select('name', { msg: 'message.*' }); * * // result has the following type: * const ok: { * name: string; * // full message is included as msg: * msg: { id: number; text: string; updatedAt: Date; createdAt: Date }; * }[] = result; * ``` * * @param arg - {@link JoinFirstArg} * @param cb - callback for shaping the joined query */ joinLateral, As extends string, Result extends Column.QueryColumns, JoinedRelations extends RelationsBase>(this: T, arg: Arg, cb: (q: JoinQueryBuilder>) => { __as: As; result: Result; relations: JoinedRelations; }): JoinLateralResult; /** * The same as {@link joinLateral}, but when no records found for the join it will result in `null`: * * ```ts * const result = await db.user * .leftJoinLateral('messages', (q) => q.as('message')) * .select('name', 'message.text'); * * // result has the following type: * const ok: { name: string; text: string | null }[] = result; * ``` * * @param arg - {@link JoinFirstArg} * @param cb - callback for shaping the joined query */ leftJoinLateral, As extends string, Result extends Column.QueryColumns, JoinedRelations extends RelationsBase>(this: T, arg: Arg, cb: (q: JoinQueryBuilder>) => { __as: As; result: Result; relations: JoinedRelations; }): JoinLateralResult; /** * This method may be useful * for combining with [createForEachFrom](/guide/create-update-delete.html#createForEachFrom-insertForEachFrom). * * `createForEachFrom` creates multiple record based on a selecting query: * * ```sql * INSERT INTO t1(c1, c2) * SELECT c1, c2 FROM t2 * ``` * * Such a query inserts one record per one selected record. * * Use `joinData` to insert a multiplication of selected records and the provided data. * * ```ts * const data = [{ column2: 'one' }, { column2: 'two' }, { column2: 'three' }]; * * await db.table.createForEachFrom( * db.otherTable * .joinData('data', (t) => ({ column2: t.text() }), data) * .select('otherTable.column1', 'data.column2'), * ); * ``` * * If the query on the other table returns 2 records, * and the data array contains 3 records, then 2 \* 3 = 6 will be inserted - every combination. * * Joined data values are available in `where` just as usual. * * @param as - alias to reference joined columns * @param fn - declare column types * @param data - array of data to join */ joinData>(this: T, as: As, fn: (types: T['columnTypes']) => RecordType, data: Item[]): { [K in keyof T]: K extends '__selectable' ? T['__selectable'] & { [K in keyof RecordType & string as `${As}.${K}`]: { as: K; column: RecordType[K]; } } : T[K] }; } type OnArgs = [leftColumn: keyof S, rightColumn: keyof S] | [leftColumn: keyof S, op: string, rightColumn: keyof S]; declare const pushQueryOnForOuter: (q: T, joinFrom: PickQuerySelectable, joinTo: PickQuerySelectable, leftColumn: string, rightColumn: string) => T; type OnJsonPathEqualsArgs = [leftColumn: keyof S, leftPath: string, rightColumn: keyof S, rightPath: string]; /** * Mutative {@link OnMethods.prototype.on} */ declare const _queryJoinOn: (q: T, args: OnArgs) => T; /** * Argument of join callback. * It is a query object of table that you're joining, with ability to select main table's columns. * Adds {@link OnMethods.prototype.on} method and similar to the query. */ type JoinQueryBuilder = { [K in keyof J | keyof OnMethods]: K extends '__selectable' ? SelectableFromShape & Omit : K extends keyof OnMethods ? OnMethods[K] : K extends keyof J ? J[K] : never }; declare class OnMethods { /** * Use `on` to specify columns to join records. * * ```ts * q * .on('message.userId', 'user.id') * // joined table name may be omitted * .on('userId', 'user.id') * // operator can be specified: * .on('userId', '!=', 'user.id') * // operator can be specified with table names as well: * .on('message.userId', '!=', 'user.id') * ``` * * @param args - columns to join with */ on(this: T, ...args: OnArgs): T; /** * Works as {@link on}, but the added conditions will be separated from previous with `OR`. * * @param args - columns to join with */ orOn(this: T, ...args: OnArgs): T; /** * Use `onJsonPathEquals` to join record based on a field of their JSON column: * * ```ts * db.table.join(db.otherTable, (q) => * // '$.key' is a JSON path * q.onJsonPathEquals('otherTable.data', '$.key', 'table.data', '$.key'), * ); * ``` * * @param args - columns and JSON paths to join with. */ onJsonPathEquals(this: T, ...args: OnJsonPathEqualsArgs): T; } declare class ColumnRefExpression extends Expression { name: string; result: { value: T; }; q: ExpressionData; constructor(value: T, name: string); makeSQL(ctx: ToSQLCtx, quotedAs?: string): string; } declare class RefExpression extends Expression { ref: string; result: { value: T; }; q: ExpressionData; table?: string; constructor(value: T, query: Query, ref: string); makeSQL(ctx: ToSQLCtx): string; } declare class ValExpression extends Expression { value: unknown; result: { value: Column; }; q: ExpressionData; constructor(value: unknown); makeSQL(ctx: ToSqlValues): string; } type SortDir = 'ASC' | 'DESC' | 'ASC NULLS FIRST' | 'DESC NULLS LAST'; type OrderItem = string | { [K: string]: SortDir; } | Expression; type OrderTsQueryConfig = true | OrderTsQueryConfigObject; interface OrderTsQueryConfigObject { coverDensity?: boolean; weights?: number[]; normalization?: number; dir?: SortDir; } type SearchWeight = 'A' | 'B' | 'C' | 'D'; interface SearchWeightRecord { [K: string]: SearchWeight; } interface WhereSearchItem { as: string; vectorSQL: string; } type QuerySourceItem = { queryAs: string; as?: string; textSQL?: MaybeArray; langSQL?: string; vectorSQL?: string; order?: OrderTsQueryConfig; } & ({ language?: string; } | { languageColumn: string; }) & ({ text: string | Expression; } | { in: MaybeArray | SearchWeightRecord; } | { vector: string; }) & ({ query: string | Expression; } | { plainQuery: string | Expression; } | { phraseQuery: string | Expression; } | { tsQuery: string | Expression; }); interface QueryDataSources { [K: string]: QuerySourceItem; } declare namespace Order { export interface ArgThis extends PickQuerySelectable, PickQueryResult, PickQueryTsQuery {} export type Arg = ArgKey | ArgTsQuery | { [K in ArgKey | ArgTsQuery]?: K extends ArgTsQuery ? OrderTsQueryConfig : SortDir } | Expression; export type Args = Arg[]; type ArgTsQuery = string | undefined extends T['__tsQuery'] ? never : Exclude; type ArgKey = { [K in keyof T['__selectable']]: T['__selectable'][K]['column']['queryType'] extends undefined ? never : K }[keyof T['__selectable']] | { [K in keyof T['result']]: T['result'][K]['dataType'] extends 'array' | 'object' | 'runtimeComputed' ? never : K }[keyof T['result']]; export {}; } declare class QueryOrder { /** * Adds an order by clause to the query. * * Takes one or more arguments, each argument can be a column name or an object. * * ```ts * db.table.order('id', 'name'); // ASC by default * * db.table.order({ * id: 'ASC', // or DESC * * // to set nulls order: * name: 'ASC NULLS FIRST', * age: 'DESC NULLS LAST', * }); * ``` * * `order` can refer to the values returned from `select` sub-queries (unlike `where` which cannot). * So you can select a count of related records and order by it. * * For example, `comment` has many `likes`. * We are selecting few columns of `comment`, selecting `likesCount` by a sub-query in a select, and ordering comments by likes count: * * ```ts * db.comment * .select('title', 'content', { * likesCount: (q) => q.likes.count(), * }) * .order({ * likesCount: 'DESC', * }); * ``` * * @param args - column name(s) or an object with column names and sort directions. */ order(this: T, ...args: Order.Args): T; /** * Order by SQL expression * * Order by raw SQL expression. * * ```ts * db.table.orderSql`raw sql`; * ``` * * @param args - SQL expression */ orderSql(this: T, ...args: SQLQueryArgs): T; } interface WindowArg { [K: string]: WindowArgDeclaration | Expression; } interface WindowArgDeclaration { partitionBy?: SelectableOrExpression | SelectableOrExpressions; order?: Order.Arg; } type WindowResult = T & { windows: { [K in keyof W]: true }; }; declare class QueryWindow { /** * Add a window with `window` and use it later by its name for aggregate or window functions: * * ```ts * db.table * // define window `windowName` * .window({ * windowName: { * partitionBy: 'someColumn', * order: { * id: 'DESC', * }, * }, * }) * .select({ * avg: (q) => * // calculate average price over the window * q.avg('price', { * // use window by its name * over: 'windowName', * }), * }); * ``` * * @param arg - window config */ window>(this: T, arg: W): WindowResult; } interface AggregateOptions { distinct?: boolean; order?: Order.Arg | Order.Args; filter?: WhereArg; filterOr?: WhereArgs; withinGroup?: boolean; over?: Over; } type Over = keyof T['windows'] | WindowArgDeclaration; type QueryGetSelf = PickQuerySelectable; type GetArg = GetStringArg | Expression; type GetStringArg = keyof T['__selectable'] & string; type GetResult> = Arg extends string ? SetQueryReturnsValueOrThrow : Arg extends Expression ? SetQueryReturnsColumnOrThrow : never; type GetResultOptional> = Arg extends string ? SetQueryReturnsValueOptional : Arg extends Expression ? SetQueryReturnsColumnOptional : never; type HeadlineSearchArg = Exclude; interface HeadlineParams { text?: SelectableOrExpressionOfType>; options?: string | Expression; } interface SearchAggregateMethods { /** * Give the `as` alias for the search, and it becomes possible to select a text with highlights of the matching words or phrases: * * ```ts * db.table * .search({ * as: 'search', * in: 'body', * query: 'query', * }) * .select({ * highlightedText: (q) => q.headline('search'), * }); * ``` * * When searching in the generated `tsvector` column, need to provide a text source to the `headline`: * * ```ts * db.table * .search({ * as: 'search', * vector: 'textVector', * query: 'query', * }) * .select({ * // `body` is a column name * highlightedText: (q) => q.headline('search', { text: 'body' }), * }); * ``` * * `text` can be a raw SQL, here we are joining multiple columns: * * ```ts * import { raw } from 'orchid-orm'; * * db.table * .search({ * as: 'search', * vector: 'titleAndBodyVector', * query: 'query', * }) * .select({ * highlightedText: (q) => * q.headline('search', { text: raw`concat_ws(' ', title, body)` }), * }); * ``` * * `headline` supports a string for `options`, see details [in Postgres doc](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE). * * Provide a simple string or a raw SQL: * * ```ts * db.table * .search({ * as: 'search', * in: 'body', * query: 'query', * }) * .select({ * highlightedText: (q) => * q.headline('search', { * options: * 'MaxFragments=10, MaxWords=7, MinWords=3, StartSel=<<, StopSel=>>', * }), * }); * ``` * * @param search - name of the search to use the query from * @param options - `text` for a text source, `options` for `ts_headline` options */ headline(this: T, search: HeadlineSearchArg, options?: HeadlineParams): SetQueryReturnsColumnOrThrow>; } type SearchArg = { as?: As; order?: OrderTsQueryConfig; } & ({ language?: string | Expression; } | { languageColumn?: keyof T['__selectable']; }) & ({ text: string | Expression; } | { in: MaybeArray | { [K in keyof T['__selectable']]?: SearchWeight }; } | { vector: { [K in keyof T['__selectable']]: T['__selectable'][K]['column']['dataType'] extends 'tsvector' ? K : never }[keyof T['__selectable']]; }) & ({ query: string | Expression; } | { plainQuery: string | Expression; } | { phraseQuery: string | Expression; } | { tsQuery: string | Expression; }); type WhereSearchResult = T & { __tsQuery: string extends As ? never : As; }; declare class SearchMethods { /** * ## language * * By default, the search language is English. * * You can set a different default language in the `createBaseTable` config: * * ```ts * import { createBaseTable } from 'orchid-orm'; * * export const BaseTable = createBaseTable({ * language: 'swedish', * }); * ``` * * See the list of supported language configs with the SQL: * * ```sql * SELECT cfgname FROM pg_ts_config; * ``` * * When performing a search, you can override the default language: * * ```ts * db.table.search({ * language: 'finnish', * in: 'body', * query: 'query', * }); * ``` * * `language` also accepts a raw SQL. * * The language can be stored in the column of this table, then you can use `languageColumn` to use this column for the search: * * ```ts * db.table.search({ * // the table has `lang` column, use it for the search * languageColumn: 'lang', * in: 'body', * query: 'query', * }); * ``` * * ## text vector to search in * * The text to search in can be a simple string, or a raw SQL, or a text column, or multiple columns: * * ```ts * db.table.search({ * // search in the given string * text: 'simply a string to search in', * query: 'query', * }); * * import { raw } from 'orchid-orm'; * * db.table.search({ * // raw SQL: join text columns with space * text: raw`concat_ws(' ', title, body)`, * query: 'query', * }); * * db.table.search({ * // search in a single text column * in: 'body', * query: 'query', * }); * * db.table.search({ * // search in multiple columns, they are concatenated with `concat_ws` as shown above * in: ['title', 'body'], * query: 'query', * }); * * db.table.search({ * // search in multiple columns with different weights. Weight can be A, B, C, or D * in: { * title: 'A', * body: 'B', * }, * query: 'query', * }); * ``` * * For better performance, define a [generated](/guide/migration-column-methods.html#generated) column of `tsvector` type, and use it in the search with `vector` keyword: * * ```ts * db.table.search({ * vector: 'titleAndBodyVector', * query: 'query', * }); * ``` * * ## search query * * Read about different search queries in [this Postgres doc](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES). * * `search` method can accept one of the following queries: * * - `query`: corresponds to `websearch_to_tsquery` in Postgres, good to use by default * - `plainQuery`: corresponds to `plainto_tsquery` * - `phraseQuery`: corresponds to `phraseto_tsquery` * - `tsQuery`: corresponds to `to_tsquery` * * The `query` (`websearch_to_tsquery`) can work with any user input, while other query kinds require a specific format and will fail for invalid input. * * Each query kind accepts a string or a raw SQL. * * ```ts * import { raw } from 'orchid-orm'; * * db.table.search({ * vector: 'titleAndBodyVector', * // can accept raw SQL: * phraseQuery: raw`'The Fat Rats'`, * }); * ``` * * ## order by search rank * * Read about search ranking in [this Postgres doc](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-RANKING). * * Set `order: true` to order results by the search rank: * * ```ts * db.table.search({ * in: 'body', * query: 'query', * // will add ORDER BY ts_rank(to_tsvector('english', body)) DESC * order: true, * }); * ``` * * To order with `ts_rank_cd` instead of `ts_rank`, set `coverDensity: true`: * * ```ts * db.table.search({ * in: 'body', * query: 'query', * // will add ORDER BY ts_rank_cd(to_tsvector('english', body)) DESC * order: { * coverDensity: true, * }, * }); * ``` * * Other options are: * * ```ts * db.table.search({ * in: 'body', * query: 'query', * order: { * // weights for D, C, B, A: * weights: [0.1, 0.2, 0.4, 1], * // by default, rank ignores the document length * // change rank behavior by providing here a special number * normalization: 32, * // it's possible to change the order direction: * dir: 'ASC', // DESC by default * }, * }); * ``` * * Giving the `as` alias for the search allows to set the ordering in the `order` method: * * ```ts * db.table * .search({ * as: 'search', * in: 'body', * query: 'query', * }) * .order({ * // can be `search: true` for defaults * search: { * // same options as above * coverDensity: true, * weights: [0.1, 0.2, 0.4, 1.0], * normalization: 32, * dir: 'ASC', * }, * }); * ``` * * @param arg - search config */ search(this: T, arg: SearchArg): WhereSearchResult; } interface OperatorsCount extends OperatorsNumber { isCount: true; } type CountColumn = Column.Pick.QueryColumnOfTypeAndOps<'int8', number, OperatorsCount>; type CountReturn = SetQueryReturnsColumnOrThrow & OperatorsCount; type SelectableDataType = { [K in keyof T['__selectable']]: T['__selectable'][K]['column']['dataType'] extends DataType ? K : never }[keyof T['__selectable']] | Expression>; type NumericReturn = Arg extends keyof T['__selectable'] ? SetQueryReturnsColumnOrThrow> & OperatorsNumber : Arg extends Expression ? SetQueryReturnsColumnOrThrow> & OperatorsNumber : never; type NullableNumberReturn = SetQueryReturnsColumnOrThrow> & OperatorsNumber; type BooleanQueryColumn = Column.Pick.QueryColumnOfTypeAndOps<'bool', boolean, OperatorsBoolean>; type BooleanNullable = Column.Pick.QueryColumnOfTypeAndOps<'bool', boolean | null, OperatorsBoolean>; type NullableBooleanReturn = SetQueryReturnsColumnOrThrow & OperatorsBoolean; type NullableJSONAggReturn> = SetQueryReturnsColumnOrThrow['type'] | null)[] | null; outputType: (ExpressionOutput['outputType'] | null)[] | null; queryType: (ExpressionOutput['queryType'] | null)[] | null; operators: OperatorsArray; }> & OperatorsArray; interface RecordSelectableOrExpression { [K: string]: SelectableOrExpression; } type NullableJSONObjectReturn> = SetQueryReturnsColumnOrThrow['type'] } | null; outputType: { [K in keyof Obj]: ExpressionOutput['outputType'] } | null; queryType: { [K in keyof Obj]: ExpressionOutput['queryType'] } | null; operators: OperatorsAny; }> & OperatorsAny; type StringColumn$1 = Column.Pick.QueryColumnOfTypeAndOps; type StringNullable = Column.Pick.QueryColumnOfTypeAndOps; type NullableStringReturn = SetQueryReturnsColumnOrThrow & OperatorsText; interface AggregateArgTypes { minMax: 'citext' | 'date' | 'float4' | 'float8' | 'inet' | 'int2' | 'int4' | 'int8' | 'interval' | 'money' | 'numeric' | 'text' | 'time' | 'timestamp' | 'timestamptz'; sum: 'float4' | 'float8' | 'int2' | 'int4' | 'int8' | 'interval' | 'money' | 'numeric'; avg: // unlike sum, avg has no money 'float4' | 'float8' | 'int2' | 'int4' | 'int8' | 'interval' | 'numeric'; bit: 'bit' | 'int2' | 'int4' | 'int8'; bool: 'bool'; stringAgg: 'bytea' | 'text'; } interface AggregateMethods extends SearchAggregateMethods {} declare class AggregateMethods { /** * Use `exists()` to check if there is at least one record-matching condition. * * It will discard previous `select` statements if any. Returns a boolean. * * ```ts * const exists: boolean = await db.table.where(...conditions).exists(); * ``` */ exists(this: T): SetQueryReturnsColumnOrThrow; /** * Count records with the `count` function: * * ```ts * // count all records: * const result: number = await db.table.count(); * * // count records where a column is not NULL: * db.table.count('name'); * * // see options above: * db.table.count('*', aggregateOptions); * * // select counts of people grouped by city * db.people * .select('city', { * population: (q) => q.count(), * }) * .group('city'); * ``` * * @param arg - optionally, provide a column or a raw SQL for the `count` argument * @param options - aggregation options */ count(this: T, arg?: SelectableOrExpression, options?: AggregateOptions): CountReturn; /** * Get the minimum value for the specified numeric column, returns number or `null` if there are no records. * * ```ts * const result: number | null = await db.table.min( * 'numericColumn', * aggregateOptions, * ); * * // select min product price grouped by product category * db.product * .select('category', { * minPrice: (q) => q.min('price'), * }) * .group('category') * .take(); * ``` * * @param arg - numeric column or raw SQL * @param options - aggregation options */ min>(this: T, arg: Arg, options?: AggregateOptions): NumericReturn; /** * Gets the maximum value for the specified numeric column, returns number or `null` if there are no records. * * ```ts * const result: number | null = await db.table.max( * 'numericColumn', * aggregateOptions, * ); * * // select max product price grouped by product category * db.product * .select('category', { * maxPrice: (q) => q.max('price'), * }) * .group('category') * .take(); * ``` * * @param arg - numeric column or raw SQL * @param options - aggregation options */ max>(this: T, arg: Arg, options?: AggregateOptions): NumericReturn; /** * Retrieve the sum of the values of a given numeric column, returns number or `null` if there are no records. * * ```ts * const result: number | null = await db.table.sum( * 'numericColumn', * aggregateOptions, * ); * * // select sum of employee salaries grouped by years * db.employee * .select('year', { * yearlySalaries: (q) => q.sum('salary'), * }) * .group('year'); * ``` * * @param arg - numeric column or raw SQL * @param options - aggregation options */ sum>(this: T, arg: Arg, options?: AggregateOptions): NumericReturn; /** * Retrieve the average value of a numeric column, it returns a number or `null` if there are no records. * * ```ts * const result: number | null = db.table.avg('numericColumn', aggregateOptions); * * // select average movies ratings * db.movie * .select('title', { * averageRating: (q) => q.avg('rating'), * }) * .group('title'); * ``` * * @param arg - numeric column or raw SQL * @param options - aggregation options */ avg>(this: T, arg: Arg, options?: AggregateOptions): NumericReturn; /** * Bitwise `and` aggregation, returns `number` or `null` if there are no records. * * ```ts * const result: number | null = db.table.bitAnd( * 'numericColumn', * aggregateOptions, * ); * * // select grouped `bitAnd` * db.table * .select('someColumn', { * bitAnd: (q) => q.bitAnd('numericColumn'), * }) * .group('someColumn'); * ``` * * @param arg - numeric column or raw SQL * @param options - aggregation options */ bitAnd>(this: T, arg: Arg, options?: AggregateOptions): NumericReturn; /** * Bitwise `or` aggregation, returns `number` or `null` if there are no records. * * ```ts * const result: number | null = db.table.bitOr('numericColumn', aggregateOptions); * * // select grouped `bitOr` * db.table * .select('someColumn', { * bitOr: (q) => q.bitOr('numericColumn'), * }) * .group('someColumn'); * ``` * * @param arg - numeric column or raw SQL * @param options - aggregation options */ bitOr>(this: T, arg: Arg, options?: AggregateOptions): NumericReturn; /** * Aggregate booleans with `and` logic, it returns `boolean` or `null` if there are no records. * * ```ts * const result: boolean | null = db.table.boolAnd( * 'booleanColumn', * aggregateOptions, * ); * * // select grouped `boolAnd` * db.table * .select('someColumn', { * boolAnd: (q) => q.boolAnd('booleanColumn'), * }) * .group('someColumn'); * ``` * * @param arg - boolean column or raw SQL * @param options - aggregation options */ boolAnd(this: T, arg: SelectableDataType, options?: AggregateOptions): NullableBooleanReturn; /** * Aggregate booleans with `or` logic, it returns `boolean` or `null` if there are no records. * * ```ts * const result: boolean | null = db.table.boolOr( * 'booleanColumn', * aggregateOptions, * ); * * // select grouped `boolOr` * db.table * .select('someColumn', { * boolOr: (q) => q.boolOr('booleanColumn'), * }) * .group('someColumn'); * ``` * * @param arg - boolean column or raw SQL * @param options - aggregation options */ boolOr(this: T, arg: SelectableDataType, options?: AggregateOptions): NullableBooleanReturn; /** * Equivalent to {@link boolAnd} */ every(this: T, arg: SelectableDataType, options?: AggregateOptions): NullableBooleanReturn; /** * Aggregate values into an array by using `json_agg`. Returns array of values or `null` if there are no records. * * `jsonAgg` is working a bit faster, `jsonbAgg` is better only when applying JSON operations in SQL. * * ```ts * const idsOrNull: number[] | null = db.table.jsonAgg('id', aggregateOptions); * * const namesOrNull: string[] | null = db.table.jsonbAgg( * 'name', * aggregateOptions, * ); * * // select grouped `jsonAgg` * db.table * .select('someColumn', { * jsonAgg: (q) => q.jsonAgg('anyColumn'), * }) * .group('someColumn'); * ``` * * @param arg - any column or raw SQL * @param options - aggregation options */ jsonAgg>(this: T, arg: Arg, options?: AggregateOptions): NullableJSONAggReturn; /** * See {@link jsonAgg} */ jsonbAgg>(this: T, arg: Arg, options?: AggregateOptions): NullableJSONAggReturn; /** * It does the construction of JSON objects, keys are provided strings and values can be table columns or raw SQL expressions, and returns `object` or `null` if no records. * * `jsonObjectAgg` is different from `jsonbObjectAgg` by internal representation in the database, `jsonObjectAgg` is a bit faster as it constructs a simple string. * * ```ts * import { TextColumn } from './string'; * * // object has type { nameAlias: string, foo: string } | null * const object = await db.table.jsonObjectAgg( * { * // select a column with alias * nameAlias: 'name', * // select raw SQL with alias * foo: sql`"bar" || "baz"`, * }, * aggregateOptions, * ); * * // select aggregated object * db.table.select('id', { * object: (q) => * q.jsonObjectAgg({ * nameAlias: 'name', * foo: sql`"bar" || "baz"`, * }), * }); * ``` * * @param arg - object where values are column names or SQL * @param options - aggregation options */ jsonObjectAgg>(this: T, arg: Obj, options?: AggregateOptions): NullableJSONObjectReturn; /** * See {@link jsonObjectAgg} */ jsonbObjectAgg>(this: T, arg: Obj, options?: AggregateOptions): NullableJSONObjectReturn; /** * Select joined strings, it returns a string or `null` if no records. * * ```ts * const result: string | null = db.table.stringAgg( * 'name', * ', ', * aggregateOptions, * ); * * // select joined strings grouped by some column * db.table * .select('someColumn', { * joinedNames: (q) => q.stringAgg('name', ', '), * }) * .group('someColumn'); * ``` * * @param arg - string column or SQL * @param delimiter - string to join with * @param options - aggration options */ stringAgg(this: T, arg: SelectableDataType, delimiter: string, options?: AggregateOptions): NullableStringReturn; /** * Concatenates `xml` columns, returns a `string` or `null` if no records. * * ```ts * const xml: string | null = await db.table.xmlAgg('xmlColumn', aggregateOptions); * * // select joined XMLs grouped by some column * db.table * .select('someColumn', { * joinedXMLs: (q) => q.xmlAgg('xml'), * }) * .group('someColumn'); * ``` * * @param arg - column or SQL with XML * @param options - aggregation options */ xmlAgg(this: T, arg: SelectableOrExpressionOfType, options?: AggregateOptions): NullableStringReturn; /** * Selects the` row_number` window function. * * Returns the number of the current row within its partition, counting from 1. * * ```ts * // result is of type Array<{ rowNumber: number }> * const result = await db.table.select({ * rowNumber: (q) => * q.rowNumber({ * partitionBy: 'someColumn', * order: { createdAt: 'ASC' }, * }), * }); * ``` * * @param over - OVER clause config */ rowNumber(this: T, over?: Over): NullableNumberReturn; /** * Selects the` rank` window function. * * Returns the rank of the current row, with gaps; that is, the row_number of the first row in its peer group. * * ```ts * // result is of type Array<{ rank: number }> * const result = await db.table.select({ * rank: (q) => * q.rank({ * partitionBy: 'someColumn', * order: { createdAt: 'ASC' }, * }), * }); * ``` * * @param over - OVER clause config */ rank(this: T, over?: Over): NullableNumberReturn; /** * Selects the` dense_rank` window function. * * Returns the rank of the current row, without gaps; this function effectively counts peer groups. * * ```ts * // result is of type Array<{ denseRank: number }> * const result = await db.table.select({ * denseRank: (q) => * q.denseRank({ * partitionBy: 'someColumn', * order: { createdAt: 'ASC' }, * }), * }); * ``` * * @param over - OVER clause config */ denseRank(this: T, over?: Over): NullableNumberReturn; /** * Selects the `percent_rank` window function. * * Returns the relative rank of the current row, that is (rank - 1) / (total partition rows - 1). The value thus ranges from 0 to 1 inclusive. * * ```ts * // result is of type Array<{ percentRank: number }> * const result = await db.table.select({ * percentRank: (q) => * q.percentRank({ * partitionBy: 'someColumn', * order: { createdAt: 'ASC' }, * }), * }); * ``` * * @param over - OVER clause config */ percentRank(this: T, over?: Over): NullableNumberReturn; /** * Selects the `cume_dist` window function. * * Returns the cumulative distribution, that is (number of partition rows preceding or peers with current row) / (total partition rows). The value thus ranges from 1/N to 1. * * ```ts * // result is of type Array<{ cumeDist: number }> * const result = await db.table.select({ * cumeDist: (q) => * q.cumeDist({ * partitionBy: 'someColumn', * order: { createdAt: 'ASC' }, * }), * }); * ``` * * @param over - OVER clause config */ cumeDist(this: T, over?: Over): NullableNumberReturn; } interface OrExpression extends Expression, OperatorsBoolean {} type OrExpressionArg = QueryOrExpressionBooleanOrNullResult | undefined; declare class OrExpression extends Expression { args: [OrExpressionArg, ...OrExpressionArg[]]; result: { value: BooleanQueryColumn; }; q: ExpressionData; constructor(args: [OrExpressionArg, ...OrExpressionArg[]]); makeSQL(ctx: ToSQLCtx, quotedAs?: string): string; } interface QueryReturnsFnAdd extends PickQueryHasSelect { type(fn: (types: T['columnTypes']) => C): { [K in keyof T]: K extends 'result' ? { value: C; } : K extends 'returnType' ? 'valueOrThrow' : K extends 'then' ? QueryThen : T[K] } & C['operators']; } type SetQueryReturnsFn = { [K in keyof T]: K extends 'result' ? { value: C; } : K extends 'returnType' ? 'valueOrThrow' : K extends 'then' ? QueryThen : T[K] } & QueryReturnsFnAdd; declare class QueryExpressions { /** * `column` references a table column, this can be used in raw SQL or when building a column expression. * Only for referencing a column in the query's table. For referencing joined table's columns, see [ref](#ref). * * ```ts * import { sql } from './baseTable'; * * await db.table.select({ * // select `("table"."id" = 1 OR "table"."name" = 'name') AS "one"`, * // returns a boolean * one: (q) => * sql`${q.column('id')} = ${1} OR ${q.column('name')} = ${'name'}`, * * // selects the same as above, but by building a query * two: (q) => q.column('id').equals(1).or(q.column('name').equals('name')), * }); * ``` * * @param name - column name */ column(this: T, name: K): ColumnRefExpression & T['shape'][K]['operators']; /** * `ref` is similar to [column](#column), but it also allows to reference a column of joined table, * and other dynamically defined columns. * * ```ts * import { sql } from './baseTable'; * * await db.table.join('otherTable').select({ * // select `("otherTable"."id" = 1 OR "otherTable"."name" = 'name') AS "one"`, * // returns a boolean * one: (q) => * sql`${q.ref('otherTable.id')} = ${1} OR ${q.ref( * 'otherTable.name', * )} = ${'name'}`, * * // selects the same as above, but by building a query * two: (q) => * q * .ref('otherTable.id') * .equals(1) * .or(q.ref('otherTable.name').equals('name')), * }); * ``` * * @param arg - any available column name, such as of a joined table */ ref(this: T, arg: K): RefExpression & T['__selectable'][K]['column']['operators']; val(value: unknown): ValExpression; /** * `fn` allows to call an arbitrary SQL function. * * For example, calling `sqrt` function to get a square root from some numeric column: * * ```ts * const q = await db.table.select({ * sqrt: (q) => q.fn('sqrt', ['numericColumn']), * }).take(); * * q.sqrt; // has type `number` just as provided * ``` * * If this is an aggregate function, you can specify aggregation options (see [Aggregate](/guide/aggregate.html)) via third parameter. * * Use `type` method to specify a column type so that its operators such as `lt` and `gt` become available: * * ```ts * const q = await db.table.select({ * // Produces `sqrt("numericColumn") > 5` * sqrtIsGreaterThan5: (q) => * q * .fn('sqrt', ['numericColumn']) * .type((t) => t.float()) * .gt(5), * }).take(); * * // Return type is boolean | null * // todo: it should be just boolean if the column is not nullable, but for now it's always nullable * q.sqrtIsGreaterThan5; * ``` * * @param fn * @param args * @param options */ fn>(this: T, fn: string, args: SelectableOrExpressions, options?: AggregateOptions): SetQueryReturnsFn; or(...args: [OrExpressionArg, ...OrExpressionArg[]]): OrExpression; } type WhereArg = { [K in keyof T['__selectable'] | 'NOT' | 'OR' | 'IN']?: K extends 'NOT' ? WhereArg | WhereArgs : K extends 'OR' ? (WhereArg | WhereArgs)[] : K extends 'IN' ? MaybeArray<{ columns: (keyof T['__selectable'])[]; values: unknown[][] | IsQuery | Expression; }> : T['__selectable'][K]['column']['queryType'] | null | { [O in keyof T['__selectable'][K]['column']['operators']]?: T['__selectable'][K]['column']['operators'][O]['_opType'] } | { result: { value: { queryType: T['__selectable'][K]['column']['queryType'] | null; }; }; } | ((q: T) => { result: { value: { queryType: T['__selectable'][K]['column']['queryType'] | null; }; }; }) } | ((q: WhereQueryBuilder) => QueryOrExpressionBooleanOrNullResult | WhereQueryBuilder); /** * Callback argument of `where`. * It has `where` methods (`where`, `whereNot`, `whereExists`, etc.), * and it has relations that you can aggregate and use a boolean comparison with, such as: * ```ts * db.table.where((q) => q.relation.count().equals(10)) * ``` */ type WhereQueryBuilder = EmptyObject extends T['relations'] ? { [K in keyof T]: K extends keyof Where | keyof QueryExpressions | 'table' | 'get' | 'columnTypes' | '__selectable' | 'relations' | 'useHelper' | 'modify' | 'result' | 'returnType' | 'withData' | 'windows' | 'then' ? T[K] : never } : { [K in keyof T['relations'] | keyof T]: K extends keyof T['relations'] ? T['relations'][K]['query'] : K extends keyof T & (keyof Where | keyof QueryExpressions | 'table' | 'get' | 'columnTypes' | '__selectable' | 'relations' | 'useHelper' | 'modify' | 'result' | 'returnType' | 'withData' | 'windows' | 'then') ? T[K] : never }; type WhereArgs = WhereArg[]; type WhereNotArgs = [WhereArg]; type WhereInColumn = keyof T['__selectable'] | [keyof T['__selectable'], ...(keyof T['__selectable'])[]]; type WhereInValues = Column extends keyof T['__selectable'] ? Iterable | IsQuery | Expression : ({ [I in keyof Column]: Column[I] extends keyof T['__selectable'] ? T['__selectable'][Column[I]]['column']['queryType'] : never } & { length: Column extends { length: number; } ? Column['length'] : never; })[] | IsQuery | Expression; type WhereInArg = { [K in keyof T['__selectable']]?: Iterable | IsQuery | Expression }; interface QueryHasWhere { __hasWhere: true; } interface QueryFnReturningSelect { (q: never): QueryHasSelect; } /** * Mutative {@link Where.prototype.where} */ declare const _queryWhere: (q: T, args: WhereArgs) => T & QueryHasWhere; declare const _queryFindBy: (q: T, arg: WhereArg) => QueryTake; declare const _queryFindByOptional: (q: T, arg: WhereArg) => QueryTakeOptional; /** * Mutative {@link Where.prototype.whereIn} */ declare const _queryWhereIn: (q: T, and: boolean, arg: unknown, values: unknown[] | Iterable | IsQuery | Expression | undefined, not?: boolean) => T & QueryHasWhere; /** * Mutative {@link Where.prototype.whereExists} */ declare const _queryWhereExists: >(q: T, arg: Arg, args: [JoinCallback] | JoinArgs) => T & QueryHasWhere; declare class Where { /** * Constructing `WHERE` conditions: * * ```ts * import { sql } from './baseTable' * * db.table.where({ * // column of the current table * name: 'John', * * // table name may be specified, it can be the name of a joined table * 'table.lastName': 'Johnsonuk', * * // object with operators, see the "column operators" section to see a full list of them: * age: { * gt: 30, * lt: 70, * }, * * // where column equals to raw SQL * // import `sql` from your `BaseTable` * column: sql`sql expression`, * // or use `(q) => sql` for the same * column2: (q) => sql`sql expression`, * * // reference other columns in such a way: * firstName: (q) => q.ref('lastName'), * }); * ``` * * Multiple `where`s are joined with `AND`: * * ```ts * db.table.where({ foo: 'foo' }).where({ bar: 'bar' }); * ``` * * ```sql * SELECT * FROM table WHERE foo = 'foo' AND bar = 'bar' * ``` * * `undefined` values are ignored, so you can supply a partial object with conditions: * * ```ts * type Params = { * // allow providing exact age, or lower or greater than * age?: number | { lt?: number; gt?: number }; * }; * * const loadRecords = async (params: Params) => { * // this will load all records if params is an empty object * const records = await db.table.where(params); * }; * ``` * * It supports a sub-query that is selecting a single value to compare it with a column: * * ```ts * db.table.where({ * // compare `someColumn` in one table with the `column` value returned from another query. * someColumn: db.otherTable.where(...conditions).get('column'), * }); * ``` * * `where` can accept other queries and merge their conditions: * * ```ts * const otherQuery = db.table.where({ name: 'John' }); * * db.table.where({ id: 1 }, otherQuery); * // this will produce WHERE "table"."id" = 1 AND "table"."name' = 'John' * ``` * * `where` supports raw SQL: * * ```ts * db.table.where(sql`a = b`); * ``` * * `where` can accept a callback with a specific query builder containing all "where" methods such as `where`, `orWhere`, `whereNot`, `whereIn`, `whereExists`: * * ```ts * db.table.where((q) => * q * .where({ name: 'Name' }) * .orWhere({ id: 1 }, { id: 2 }) * .whereIn('letter', ['a', 'b', 'c']) * .whereExists(db.message, 'authorId', 'id'), * ); * ``` * * `where` can accept multiple arguments, conditions are joined with `AND`: * * ```ts * db.table.where( * { id: 1 }, * db.table.where({ name: 'John' }), * sql`a = b`, * ); * ``` * * ## where sub query * * `where` handles a special callback where you can query a relation to get some value and filter by that value. * * It is useful for a faceted search. For instance, posts have tags, and we want to find all posts that have all the given tags. * * ```ts * const givenTags = ['typescript', 'node.js']; * * const posts = await db.post.where( * (post) => * post.tags // query tags of the post * .whereIn('tagName', givenTags) // where name of the tag is inside array * .count() // count how many such tags were found * .equals(wantedTags.length), // the count must be exactly the length of array * // if the post has ony `typescript` tag but not the `node.js` it will be omitted * ); * ``` * * This will produce an efficient SQL query: * * ```sql * SELECT * FROM "post" * WHERE ( * SELECT count(*) = 3 * FROM "tag" AS "tags" * WHERE "tag"."tagName" IN ('typescript', 'node.js') * -- join tags to the post via "postTag" table * AND EXISTS ( * SELECT 1 FROM "postTag" * WHERE "postTag"."postId" = "post"."id" * AND "postTag"."tagId" = "tag"."id" * ) * ) * ``` * * In the example above we use `count()`, you can also use any other aggregate method instead, such as `min`, `max`, `avg`. * * The `count()` is chained with `equals` to check for a strict equality, any other operation is also allowed, such as `not`, `lt`, `gt`. * * ## where special keys * * The object passed to `where` can contain special keys, each of the keys corresponds to its own method and takes the same value as the type of argument of the method. * * For example: * * ```ts * db.table.where({ * NOT: { key: 'value' }, * OR: [{ name: 'a' }, { name: 'b' }], * IN: { * columns: ['id', 'name'], * values: [ * [1, 'a'], * [2, 'b'], * ], * }, * }); * ``` * * Using methods `whereNot`, `orWhere`, `whereIn` instead of this is a shorter and cleaner way, but in some cases, such object keys way may be more convenient. * * ```ts * db.table.where({ * // see .whereNot * NOT: { id: 1 }, * // can be an array: * NOT: [{ id: 1 }, { id: 2 }], * * // see .orWhere * OR: [{ name: 'a' }, { name: 'b' }], * // can be an array: * // this will give id = 1 AND id = 2 OR id = 3 AND id = 4 * OR: [ * [{ id: 1 }, { id: 2 }], * [{ id: 3 }, { id: 4 }], * ], * * // see .in, the key syntax requires an object with columns and values * IN: { * columns: ['id', 'name'], * values: [ * [1, 'a'], * [2, 'b'], * ], * }, * // can be an array: * IN: [ * { * columns: ['id', 'name'], * values: [ * [1, 'a'], * [2, 'b'], * ], * }, * { columns: ['someColumn'], values: [['foo', 'bar']] }, * ], * }); * ``` * * ## column operators * * `where` argument can take an object where the key is the name of the operator and the value is its argument. * * Different types of columns support different sets of operators. * * All column operators can take a value of the same type as the column, a sub-query, or a raw SQL expression: * * ```ts * db.table.where({ * numericColumn: { * // lower than 5 * lt: 5, * * // lower than the value returned by sub-query * lt: db.otherTable.select('someNumber').take(), * * // raw SQL expression produces WHERE "numericColumn" < "otherColumn" + 10 * lt: sql`"otherColumn" + 10`, * }, * }); * ``` * * ### Any type of column operators * * `equals` is a simple `=` operator, it may be useful for comparing column value with JSON object: * * ```ts * db.table.where({ * // when searching for an exact same JSON value, this won't work: * jsonColumn: someObject, * * // use `{ equals: ... }` instead: * jsonColumn: { equals: someObject }, * }); * ``` * * `not` is `!=` (aka `<>`) not equal operator: * * ```ts * db.table.where({ * anyColumn: { not: value }, * }); * ``` * * `in` is for the `IN` operator to check if the column value is included in a list of values. * * Takes an array of the same type as a column, a sub-query that returns a list of values, or a raw SQL expression that returns a list. * * ```ts * db.table.where({ * column: { * in: ['a', 'b', 'c'], * * // WHERE "column" IN (SELECT "column" FROM "otherTable") * in: db.otherTable.select('column'), * * in: sql`('a', 'b')`, * }, * }); * ``` * * `notIn` is for the `NOT IN` operator, and takes the same arguments as `in` * * ### Numeric, Date, and Time column operators * * To compare numbers, dates, and times. * * `lt` is for `<` (lower than) * * `lte` is for `<=` (lower than or equal) * * `gt` is for `>` (greater than) * * `gte` is for `>=` (greater than or equal) * * ```ts * db.table.where({ * numericColumn: { * gt: 5, * lt: 10, * }, * * date: { * lte: new Date(), * }, * * time: { * gte: new Date(), * }, * }); * ``` * * `between` also works with numeric, dates, and time columns, it takes an array of two elements. * * Both elements can be of the same type as a column, a sub-query, or a raw SQL expression. * * ```ts * db.table.where({ * column: { * // simple values * between: [1, 10], * * // sub-query and raw SQL expression * between: [db.otherTable.select('column').take(), sql`2 + 2`], * }, * }); * ``` * * ### Text column operators * * For `text`, `varchar`, `string`, and `json` columns. * * `json` is stored as text, so it has text operators. Use the `jsonb` type for JSON operators. * * Takes a string, or sub-query returning string, or raw SQL expression as well as other operators. * * ```ts * db.table.where({ * textColumn: { * // WHERE "textColumn" LIKE '%string%' * contains: 'string', * // WHERE "textColumn" ILIKE '%string%' * containsInsensitive: 'string', * // WHERE "textColumn" LIKE 'string%' * startsWith: 'string', * // WHERE "textColumn" ILIKE 'string%' * startsWithInsensitive: 'string', * // WHERE "textColumn" LIKE '%string' * endsWith: 'string', * // WHERE "textColumn" ILIKE '%string' * endsWithInsensitive: 'string', * }, * }); * ``` * * ### JSONB column operators * * JSON functions are available only for the `jsonb` column, note that the `json` type has text operators instead. * * You can use [jsonPathQueryFirst](/guide/json.html#jsonpathqueryfirst) to filter by a JSON value, follow the link for details. * * The value can be of any type, it can also be returned from a sub-query, raw SQL expression. * * ```ts * db.table.where((q) => * q.get('jsonbColumn').jsonPathQueryFirst('$.name').equals(value), * ); * ``` * * `jsonSupersetOf`: check if the column value is a superset of provided value. * * For instance, it is true if the column has JSON `{ "a": 1, "b": 2 }` and provided value is `{ "a": 1 }`. * * Takes the value of any type, or sub query which returns a single value, or a raw SQL expression. * * ```ts * db.table.where({ * jsonbColumn: { * jsonSupersetOf: { a: 1 }, * }, * }); * ``` * * `jsonSubsetOf`: check if the column value is a subset of provided value. * * For instance, it is true if the column has JSON `{ "a": 1 }` and provided value is `{ "a": 1, "b": 2 }`. * * Takes the value of any type, or sub query which returns a single value, or a raw SQL expression. * * ```ts * db.table.where({ * jsonbColumn: { * jsonSubsetOf: { a: 1 }, * }, * }); * ``` * * @param args - {@link WhereArgs} */ where(this: T, ...args: WhereArgs): T & QueryHasWhere; /** * Use a custom SQL expression in `WHERE` statement: * * ```ts * db.table.whereSql`a = b`; * ``` * * @param args - SQL expression */ whereSql(this: T, ...args: SQLQueryArgs): T & QueryHasWhere; /** * `whereNot` takes the same argument as `where`, * multiple conditions are combined with `AND`, * the whole group of conditions is negated with `NOT`. * * ```ts * // find records of different colors than red * db.table.whereNot({ color: 'red' }); * // WHERE NOT color = 'red' * db.table.whereNot({ one: 1, two: 2 }); * // WHERE NOT (one = 1 AND two = 2) * ``` * * @param args - {@link WhereArgs} */ whereNot(this: T, ...args: WhereNotArgs): T & QueryHasWhere; /** * `whereNotSql` is a version of `whereNot` accepting SQL expression: * * ```ts * db.table.whereNotSql`sql expression` * ``` * * @param args - SQL expression */ whereNotSql(this: T, ...args: SQLQueryArgs): T; /** * `whereOneOf` stands for "...**and** where one of the given is true". * * Accepts the same arguments as `where`. * * ```ts * db.table.where({ id: 1 }).whereOneOf({ color: 'red' }, { color: 'blue' }); * ``` * * ```sql * SELECT * FROM table * WHERE id = 1 AND (color = 'red' OR color = 'blue') * ``` * * Note that columns inside every argument are joined with `AND`: * * ```ts * db.table.whereOneOf({ id: 1, color: 'red' }, { id: 2 }); * ``` * * ```sql * SELECT * FROM table * WHERE (id = 1 AND color = 'red') OR (id = 2) * ``` * * @param args - same arguments as in {@link where}, joined with `OR` */ whereOneOf(this: T, ...args: WhereArgs): T & QueryHasWhere; /** * Negative {@link whereOneOf}: * * ```ts * db.table.where({ id: 1 }).whereNotOneOf({ color: 'red' }, { color: 'blue' }); * ``` * * ```sql * SELECT * FROM table * WHERE id = 1 AND NOT (color = 'red' OR color = 'blue') * ``` * * @param args - same arguments as in {@link where}, joined with `OR` */ whereNotOneOf(this: T, ...args: WhereArgs): T; /** * `orWhere` stands for "...**or** where one of the given is true". * * Accepts the same arguments as `where`. * * ```ts * db.table.where({ id: 1, color: 'red' }).orWhere({ id: 2, color: 'blue' }); * // equivalent: * db.table.orWhere({ id: 1, color: 'red' }, { id: 2, color: 'blue' }); * ``` * * ```sql * SELECT * FROM table * WHERE (id = 1 AND color = 'red') OR (id = 2 AND color = 'blue') * ``` * * @param args - same arguments as in {@link where}, joined with `OR` */ orWhere(this: T, ...args: WhereArgs): T & QueryHasWhere; /** * `orWhereNot` takes the same arguments as {@link orWhere}, and prepends each condition with `NOT` just as {@link whereNot} does. * * @param args - {@link WhereArgs} will be prefixed with `NOT` and joined with `OR` */ orWhereNot(this: T, ...args: WhereArgs): T & QueryHasWhere; /** * `whereIn` and related methods are for the `IN` operator to check for inclusion in a list of values. * * When used with a single column it works equivalent to the `in` column operator: * * ```ts * db.table.whereIn('column', [1, 2, 3]); * db.table.whereIn('column', new Set([1, 2, 3])); * // the same as: * db.table.where({ column: { in: [1, 2, 3] } }); * db.table.where({ column: { in: new Set([1, 2, 3]) } }); * ``` * * `whereIn` can support a tuple of columns, that's what the `in` operator cannot support: * * ```ts * db.table.whereIn( * ['id', 'name'], * [ * [1, 'Alice'], * [2, 'Bob'], * ], * ); * ``` * * It supports sub query which should return records with columns of the same type: * * ```ts * db.table.whereIn(['id', 'name'], db.otherTable.select('id', 'name')); * ``` * * It supports raw SQL expression: * * ```ts * db.table.whereIn(['id', 'name'], sql`((1, 'one'), (2, 'two'))`); * ``` * * When empty set of values is given, `whereIn` will resolve into a {@link QueryMethods.none} query that has a special behavior. * * ```ts * // following queries resolves into `none`: * db.table.whereIn('id', []) * db.table.whereIn(['id', 'name'], []) * db.table.whereIn({ id: [] }) * ``` */ whereIn>(this: T, ...args: [column: Column, values: WhereInValues] | [arg: WhereInArg]): T & QueryHasWhere; /** * Takes the same arguments as {@link whereIn}. * Add a `WHERE IN` condition prefixed with `OR` to the query: * * ```ts * db.table.whereIn('a', [1, 2, 3]).orWhereIn('b', ['one', 'two']); * ``` */ orWhereIn>(this: T, ...args: [column: Column, values: WhereInValues] | [WhereInArg]): T & QueryHasWhere; /** * Acts as `whereIn`, but negates the condition with `NOT`: * * ```ts * db.table.whereNotIn('color', ['red', 'green', 'blue']); * ``` */ whereNotIn>(this: T, ...args: [column: Column, values: WhereInValues] | [arg: WhereInArg]): T & QueryHasWhere; /** * Acts as `whereIn`, but prepends `OR` to the condition and negates it with `NOT`: * * ```ts * db.table.whereNotIn('a', [1, 2, 3]).orWhereNoIn('b', ['one', 'two']); * ``` */ orWhereNotIn>(this: T, ...args: [column: Column, values: WhereInValues] | [arg: WhereInArg]): T & QueryHasWhere; /** * `whereExists` is for support of the `WHERE EXISTS (query)` clause. * * This method is accepting the same arguments as `join`, see the {@link Join.join} section for more details. * * ```ts * // find users who have accounts * // find by a relation name if it's defined * db.user.whereExists('account'); * * // find users who have an account with positive balance * // `accounts` is a relation name * db.user.whereExists((q) => q.accounts.where({ balance: { gt: 0 } })); * * // find using a table and a join conditions * db.user.whereExists(db.account, 'account.id', 'user.id'); * * // find using a query builder in a callback: * db.user.whereExists(db.account, (q) => q.on('account.id', '=', 'user.id')); * ``` */ whereExists, Cb extends JoinCallbackArgs>(this: T, arg: Arg, ...args: Cb | JoinArgs): Arg extends QueryFnReturningSelect ? { error: 'Cannot select in whereExists'; } : Cb[0] extends QueryFnReturningSelect ? { error: 'Cannot select in whereExists'; } : T & QueryHasWhere; /** * Acts as `whereExists`, but prepends the condition with `OR`: * * ```ts * // find users who have an account or a profile, * // imagine that the user has both `account` and `profile` relations defined. * db.user.whereExist('account').orWhereExists('profile'); * ``` */ orWhereExists>(this: T, arg: Arg, ...args: JoinArgs): T & QueryHasWhere; /** * Acts as `whereExists`, but negates the condition with `NOT`: * * ```ts * // find users who don't have an account, * // image that the user `belongsTo` or `hasOne` account. * db.user.whereNotExist('account'); * ``` * * @param arg - relation name, or a query object, or a `with` table alias, or a callback returning a query object. * @param args - no arguments needed when the first argument is a relation name, or conditions to join the table with. */ whereNotExists>(this: T, arg: Arg, ...args: JoinArgs): T & QueryHasWhere; /** * Acts as `whereExists`, but prepends the condition with `OR` and negates it with `NOT`: * * ```ts * // find users who don't have an account OR who don't have a profile * // imagine that the user has both `account` and `profile` relations defined. * db.user.whereNotExists('account').orWhereNotExists('profile'); * ``` */ orWhereNotExists>(this: T, arg: Arg, ...args: JoinArgs): T & QueryHasWhere; } type QueryScopes = { [K in Keys]: unknown }; interface ScopeArgumentQuery extends Where, PickQuerySelectableShapeRelationsWithData { __isQuery: true; table: Table; shape: Shape; __selectable: SelectableFromShape; } /** * This feature allows defining a set of query modifiers to use it later. * Only [where conditions](/guide/where.html) can be set in a scope. * If you define a scope with name `default`, it will be applied for all table queries by default. * * ```ts * import { BaseTable } from './baseTable'; * * export class SomeTable extends BaseTable { * readonly table = 'some'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * hidden: t.boolean(), * active: t.boolean(), * })); * * scopes = this.setScopes({ * default: (q) => q.where({ hidden: false }), * active: (q) => q.where({ active: true }), * }); * } * * const db = orchidORM( * { databaseURL: '...' }, * { * some: SomeTable, * }, * ); * * // the default scope is applied for all queries: * const nonHiddenRecords = await db.some; * ``` */ declare class QueryScope { /** * See {@link QueryScope} * * Use the `scope` method to apply a pre-defined scope. * * ```ts * // use the `active` scope that is defined in the table: * await db.some.scope('active'); * ``` * * @param scope - name of the scope to apply */ scope(this: T, scope: keyof T['__scopes']): T & QueryHasWhere; /** * See {@link QueryScope} * * Remove conditions that were added by the scope from the query. * * ```ts * // SomeTable has a default scope, ignore it for this query: * await db.some.unscope('default'); * ``` * * @param scope - name of the scope to remove from the query */ unscope(this: T, scope: keyof T['__scopes']): T; } type DeleteMethodsNames = 'delete'; type DeleteArgs = T['__hasWhere'] extends true ? EmptyTuple : [never]; type DeleteResult = T['__hasSelect'] extends true ? T : T['returnType'] extends undefined | 'all' ? SetQueryReturnsRowCountMany : SetQueryReturnsRowCount; declare const _queryDelete: (query: T) => DeleteResult; declare class QueryDelete { /** * This method deletes one or more rows, based on other conditions specified in the query. * * By default, `delete` will return a count of deleted records. * * Place `select`, `selectAll`, or `get` before `delete` to specify returning columns. * * Need to provide `where`, `findBy`, or `find` conditions before calling `delete`. * To prevent accidental deletion of all records, deleting without where will result in TypeScript and a runtime error. * * Use `all()` to delete ALL records without conditions: * * ```ts * await db.table.all().delete(); * ``` * * ```ts * // deletedCount is the number of deleted records * const deletedCount = await db.table.where(...conditions).delete(); * * // returns a single value, throws if not found * const id: number | undefined = await db.table * .findBy(...conditions) * .get('id') * .delete(); * * // returns an array of records with specified columns * const deletedRecord = await db.table * .select('id', 'name', 'age') * .where(...conditions) * .delete(); * * // returns an array of fully deleted records * const deletedUsersFull = await db.table * .selectAll() * .where(...conditions) * .delete(); * ``` * * `delete` supports joining, under the hood the join is transformed to `USING` and `WHERE` statements: * * ```ts * // delete all users who have corresponding profile records: * db.table.join(db.profile, 'profile.userId', 'user.id').all().delete(); * ``` * * `delete` can be used in {@link WithMethods.with} expressions: * * ```ts * db.$qb * // delete a record in one table * .with('a', db.table.find(1).select('id').delete()) * // delete a record in other table using the first table record id * .with('b', (q) => * db.otherTable.select('id').whereIn('aId', q.from('a').pluck('id')).delete(), * ) * .from('b'); * ``` */ delete(this: T, ..._args: DeleteArgs): DeleteResult; } type SoftDeleteOption = true | keyof Shape; interface QueryWithSoftDelete extends PickQueryResult, PickQueryReturnType, PickQueryHasSelect, PickQueryHasWhere { __scopes: NonDeletedScope; } interface NonDeletedScope { nonDeleted: true; } /** * `softDelete` configures the table to set `deletedAt` to current time instead of deleting records. * All queries on such table will filter out deleted records by default. * * ```ts * import { BaseTable } from './baseTable'; * * export class SomeTable extends BaseTable { * readonly table = 'some'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * deletedAt: t.timestamp().nullable(), * })); * * // true is for using `deletedAt` column * readonly softDelete = true; * // or provide a different column name * readonly softDelete = 'myDeletedAt'; * } * * const db = orchidORM( * { databaseURL: '...' }, * { * someTable: SomeTable, * }, * ); * * // deleted records are ignored by default * const onlyNonDeleted = await db.someTable; * ``` */ declare class SoftDeleteMethods { /** * `includeDeleted` disables the default `deletedAt` filter: * * ```ts * const allRecords = await db.someTable.includeDeleted(); * ``` */ includeDeleted(this: T): T; /** * `hardDelete` deletes records bypassing the `softDelete` behavior: * * ```ts * await db.someTable.find(1).hardDelete(); * ``` */ hardDelete(this: T, ..._args: DeleteArgs): DeleteResult; } interface QueryInternalColumnNameToKey { columnNameToKeyMap?: Map; } interface TableRlsConfig { enable?: boolean; force?: boolean; } interface DbRlsOptions { tableRlsDefaults?: TableRlsConfig; } declare namespace DefaultPrivileges { export type ObjectType = (typeof DEFAULT_PRIVILEGE.OBJECT_TYPES)[number]; export interface Privilege { Table: (typeof DEFAULT_PRIVILEGE.PRIVILEGES.TABLE)[number]; Sequence: (typeof DEFAULT_PRIVILEGE.PRIVILEGES.SEQUENCE)[number]; Function: (typeof DEFAULT_PRIVILEGE.PRIVILEGES.FUNCTION)[number]; Type: (typeof DEFAULT_PRIVILEGE.PRIVILEGES.TYPE)[number]; Schema: (typeof DEFAULT_PRIVILEGE.PRIVILEGES.SCHEMA)[number]; LargeObject: (typeof DEFAULT_PRIVILEGE.PRIVILEGES.LARGE_OBJECT)[number]; } interface ObjectSetting { privileges?: T[]; grantablePrivileges?: T[]; } export interface SchemaTargetConfig { owner?: string; schema: string; all?: boolean; allGrantable?: boolean; tables?: ObjectSetting; sequences?: ObjectSetting; functions?: ObjectSetting; types?: ObjectSetting; } export interface GlobalTargetConfig { owner?: string; schema?: never; all?: boolean; allGrantable?: boolean; tables?: ObjectSetting; sequences?: ObjectSetting; functions?: ObjectSetting; types?: ObjectSetting; schemas?: ObjectSetting; largeObjects?: ObjectSetting; } export interface SupportedDefaultPrivileges { OBJECT_TYPES: string[]; PRIVILEGES: { TABLE: string[]; SEQUENCE: string[]; FUNCTION: string[]; TYPE: string[]; SCHEMA: string[]; LARGE_OBJECT?: string[]; }; } export type SchemaConfig = SchemaTargetConfig | GlobalTargetConfig; export {}; } declare const DEFAULT_PRIVILEGE: { OBJECT_TYPES: readonly ["TABLES", "SEQUENCES", "FUNCTIONS", "TYPES", "SCHEMAS", "LARGE_OBJECTS"]; PRIVILEGES: { TABLE: readonly ["ALL", "SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", "MAINTAIN"]; SEQUENCE: readonly ["ALL", "USAGE", "SELECT", "UPDATE"]; FUNCTION: readonly ["ALL", "EXECUTE"]; TYPE: readonly ["ALL", "USAGE"]; SCHEMA: readonly ["ALL", "USAGE", "CREATE"]; LARGE_OBJECT: readonly ["ALL", "SELECT", "UPDATE"]; }; }; declare function getSupportedDefaultPrivileges(version: number): DefaultPrivileges.SupportedDefaultPrivileges; interface DbRole { name: string; super?: boolean; inherit?: boolean; createRole?: boolean; createDb?: boolean; canLogin?: boolean; replication?: boolean; connLimit?: number; validUntil?: Date; bypassRls?: boolean; config?: RecordOptionalString; defaultPrivileges?: DefaultPrivileges.SchemaConfig[]; } interface QueryInternal extends QueryInternalColumnNameToKey { runtimeDefaultColumns?: string[]; asyncStorage: AsyncLocalStorage; scopes?: RecordUnknown; snakeCase?: boolean; noPrimaryKey: boolean; comment?: string; primaryKeys?: string[]; singlePrimaryKey: SinglePrimaryKey; uniqueColumns: UniqueColumns; uniqueColumnNames: UniqueColumnNames; uniqueColumnTuples: UniqueColumnTuples; uniqueConstraints: UniqueConstraints; extensions?: DbExtension[]; domains?: DbDomainArgRecord; generatorIgnore?: GeneratorIgnore; roles?: DbRole[]; rls?: DbRlsOptions; tableRls?: TableRlsConfig; managedRolesSql?: string; tableData: TableData; nowSQL?: string; callbackArg?: Query; selectAllCount: number; /** * @see DbSharedOptions */ nestedCreateBatchMax: number; } type ShapeColumnPrimaryKeys = { [K in { [K in keyof Shape]: Shape[K]['data']['primaryKey'] extends string ? K : never }[keyof Shape]]: UniqueQueryTypeOrExpression }; type ShapeUniqueColumns = { [K in keyof Shape]: Shape[K]['data']['unique'] extends string ? { [C in K]: UniqueQueryTypeOrExpression } : never }[keyof Shape]; type UniqueConstraints = { [K in keyof Shape]: Shape[K]['data']['primaryKey'] extends string ? string extends Shape[K]['data']['primaryKey'] ? never : Shape[K]['data']['primaryKey'] : Shape[K]['data']['unique'] extends string ? string extends Shape[K]['data']['unique'] ? never : Shape[K]['data']['unique'] : never }[keyof Shape]; type NoPrimaryKeyOption = 'error' | 'warning' | 'ignore'; interface DbSharedOptions extends QueryLogOptions { autoPreparedStatements?: boolean; noPrimaryKey?: NoPrimaryKeyOption; rls?: DbRlsOptions; extensions?: (string | RecordString)[]; domains?: { [K: string]: DbDomainArg>; }; generatorIgnore?: GeneratorIgnore; schema?: QuerySchema; /** * For `hasMany` and `hasOne`: * controls nested create|connect|connectOrCreate strategy in `createMany`. * When creating many records <= this value, it will use a single query with CTEs. * Otherwise, it will perform nested operations in separate queries in a transaction. * A single query is more efficient on lower amount of records and on lower latency to a database. */ nestedCreateBatchMax?: number; roles?: DbRole[]; managedRolesSql?: string; } interface DbOptions extends DbSharedOptions { schemaConfig?: SchemaConfig; columnTypes?: ColumnTypes | ((t: DefaultColumnTypes) => ColumnTypes); snakeCase?: boolean; nowSQL?: string; } interface DbOptionsWithAdapter extends DbOptions { adapter: Adapter; } interface DbTableOptions extends QueryLogOptions { schema?: QuerySchema; /** * Prepare all SQL queries before executing, * true by default */ autoPreparedStatements?: boolean; noPrimaryKey?: NoPrimaryKeyOption; snakeCase?: boolean; /** * Default language for the full text search */ language?: string; /** * See {@link ScopeMethods} */ scopes?: DbTableOptionScopes; /** * See {@link SoftDeleteMethods} */ softDelete?: SoftDeleteOption; /** * Table comment, for migrations generator */ comment?: string; /** * Computed SQL or JS columns definitions */ computed?: ComputedOptionsFactory; /** * For customizing `now()` sql, used in soft delete */ nowSQL?: string; } type DbTableOptionScopes
= { [K in Keys]: (q: ScopeArgumentQuery) => IsQuery }; interface QueryBuilder extends Query { returnType: undefined; } declare class Db
, ShapeWithComputed extends Column.QueryColumnsInit = Shape, Scopes extends RecordUnknown | undefined = EmptyObject, DefaultSelect extends keyof Shape = keyof Shape> extends QueryMethods implements Query { adapterNotInTransaction: Adapter; qb: QueryBuilder; table: Table; columnTypes: ColumnTypes; q: QueryData; __isQuery: true; __as: Table & string; __selectable: SelectableFromShape; __hasSelect: boolean; __hasWhere: boolean; __defaults: { [K in { [K in keyof Shape]: unknown extends Shape[K]['data']['default'] ? never : K }[keyof Shape]]: true }; __scopes: { [K in keyof Scopes]: true }; __defaultSelect: DefaultSelect; baseQuery: Query; columns: (keyof Shape)[]; outputType: ColumnsShape.DefaultSelectOutput; inputType: ColumnsShape.Input; result: { [K in DefaultSelect]: Shape[K] }; returnType: undefined; then: QueryThenShallowSimplifyArr>; windows: EmptyObject; relations: EmptyObject; relationQueries: EmptyObject; withData: EmptyObject; error: new (message: string, length: number, name: QueryErrorName) => QueryError; internal: QueryInternal<{ [K in keyof PrimaryKeys]: (keyof PrimaryKeys extends K ? never : keyof PrimaryKeys) extends never ? PrimaryKeys[K] : never }[keyof PrimaryKeys], PrimaryKeys | UniqueColumns, { [K in keyof Shape]: Shape[K]['data']['unique'] extends string ? K : never }[keyof Shape] | keyof PrimaryKeys, UniqueColumnTuples, UniqueConstraints>; catch: QueryCatch; shape: ShapeWithComputed; constructor(adapterNotInTransaction: Adapter, qb: QueryBuilder, table: Table | undefined, shape: ShapeWithComputed, columnTypes: ColumnTypes, asyncStorage: AsyncLocalStorage, options: DbTableOptions, tableData?: TableData); /** * When in transaction, returns a db adapter object for the transaction, * returns a default adapter object otherwise. */ $getAdapter(): Adapter; [inspect.custom](): string; /** * Use `query` to perform raw SQL queries. * * ```ts * const value = 1; * * // it is safe to interpolate inside the backticks (``): * const result = await db.query<{ one: number }>`SELECT ${value} AS one`; * // data is inside `rows` array: * result.rows[0].one; * ``` * * If the query is executing inside a transaction, it will use the transaction connection automatically. * * ```ts * await db.transaction(async () => { * // both queries will execute in the same transaction * await db.query`SELECT 1`; * await db.query`SELECT 2`; * }); * ``` * * Alternatively, support a simple SQL string, with optional `values`: * * Note that the values is a simple array, and the SQL is referring to the values with `$1`, `$2` and so on. * * ```ts * const value = 1; * * // it is NOT safe to interpolate inside a simple string, use `values` to pass the values. * import { raw } from 'orchid-orm'; * * const result = await db.query<{ one: number }>(raw({ * raw: 'SELECT $1 AS one', * values: [value], * })); * // data is inside `rows` array: * result.rows[0].one; * ``` * * @param args - SQL template literal, or a raw SQL object created by `raw()` or `sql()` function */ get query(): DbSqlQuery; private _query?; /** * Performs a SQL query, returns a db result with array of arrays instead of objects: * * ```ts * const value = 1; * * // it is safe to interpolate inside the backticks (``): * const result = await db.queryArrays<[number]>`SELECT ${value} AS one`; * // `rows` is an array of arrays: * const row = result.rows[0]; * row[0]; // our value * ``` * * @param args - SQL template literal, or a raw SQL object created by `raw()` or `sql()` function */ queryArrays(...args: SQLQueryArgs): Promise>; } interface DbTableConstructor {
, Options extends DbTableOptions>(table: Table, shape?: ((t: ColumnTypes) => Shape) | Shape, tableData?: TableDataFn, options?: Options): Db extends never ? never : ShapeColumnPrimaryKeys, ShapeUniqueColumns | TableDataItemsUniqueColumns, TableDataItemsUniqueColumnTuples, UniqueConstraints | TableDataItemsUniqueConstraints, ColumnTypes, Shape & ComputedColumnsFromOptions, MapTableScopesOption, ColumnsShape.DefaultSelectKeys> & { ko: Shape; }; } interface DbSqlMethod { (...args: StaticSQLArgs): RawSql, ColumnTypes>; (...args: [DynamicSQLArg>]): DynamicRawSQL, ColumnTypes>; ref(name: string): SqlRefExpression; unsafe(sql: string | number | boolean): UnsafeSqlExpression; } type MapTableScopesOption = T extends { scopes: RecordUnknown; } ? T extends { softDelete: true | PropertyKey; } ? T['scopes'] & NonDeletedScope : T['scopes'] : T extends { softDelete: true | PropertyKey; } ? { nonDeleted: unknown; } : EmptyObject; interface DbResult extends Db, DbTableConstructor { adapterNotInTransaction: Adapter; adapter: Adapter; close: Adapter['close']; sql: DbSqlMethod; } /** * If you'd like to use the query builder of OrchidORM as a standalone tool, install `pqb` package and use `createDb` to initialize it. * * As `Orchid ORM` focuses on ORM usage, docs examples mostly demonstrates how to work with ORM-defined tables, * but everything that's not related to table relations should also work with `pqb` query builder on its own. * * It is accepting the same options as `orchidORM` + options of `createBaseTable`: * * ```ts * import { createDb } from 'orchid-orm'; * * import { zodSchemaConfig } from 'orchid-orm-schema-to-zod'; * // or * import { SchemaConfig } from 'orchid-orm-valibot'; * * const db = createDb({ * // db connection options * databaseURL: process.env.DATABASE_URL, * log: true, * * // columns in db are in snake case: * snakeCase: true, * * // override default SQL for timestamp, see `nowSQL` above * nowSQL: `now() AT TIME ZONE 'UTC'`, * * // optional, but recommended: makes zod schemas for your tables * schemaConfig: zodSchemaConfig, * // or * schemaConfig: valibotSchemaConfig, * * // override column types: * columnTypes: (t) => ({ * // by default timestamp is returned as a string, override to a number * timestamp: () => t.timestamp().asNumber(), * }), * }); * ``` * * After `db` is defined, construct queryable tables in such way: * * ```ts * export const User = db('user', (t) => ({ * id: t.identity().primaryKey(), * name: t.string(), * password: t.varchar(100), * age: t.integer().nullable(), * ...t.timestamps(), * })); * ``` * * Now the `User` can be used for making type-safe queries: * * ```ts * const users = await User.select('id', 'name') // only known columns are allowed * .where({ age: { gte: 20 } }) // gte is available only on the numeric field, and the only number is allowed * .order({ createdAt: 'DESC' }) // type safe as well * .limit(10); * * // users array has a proper type of Array<{ id: number, name: string }> * ``` * * The optional third argument is for table options: * * ```ts * const Table = db('table', (t) => ({ ...columns }), { * // provide this value if the table belongs to a specific database schema: * schema: 'customTableSchema', * // override `log` option of `createDb`: * log: true, // boolean or object described `createdDb` section * logger: { ... }, // override logger * noPrimaryKey: 'ignore', // override noPrimaryKey * snakeCase: true, // override snakeCase * }) * ``` */ declare const createDbWithAdapter: >({ log, logger, snakeCase, schemaConfig, columnTypes: ctOrFn, schema, ...options }: DbOptionsWithAdapter) => DbResult; declare function _createDbSqlMethod(columnTypes: ColumnTypes): DbSqlMethod; declare const _initQueryBuilder: (adapter: Adapter, columnTypes: unknown, asyncStorage: AsyncLocalStorage, commonOptions: DbTableOptions, options: DbSharedOptions) => Db; type SQLQueryArgs = TemplateLiteralArgs | [RawSqlBase]; interface DbSqlQuery { (...args: SQLQueryArgs): Promise>; /** * Returns an array of records: * * ```ts * const array: T[] = await db.$query.records`SELECT * FROM table`; * ``` */ records(...args: SQLQueryArgs): Promise; /** * Returns a single record, throws [NotFoundError](/guide/error-handling) if not found. * * ```ts * const one: T = await db.$query.take`SELECT * FROM table LIMIT 1`; * ``` */ take(...args: SQLQueryArgs): Promise; /** * Returns a single record or `undefined` when not found. * * ```ts * const maybeOne: T | undefined = await db.$query * .takeOptional`SELECT * FROM table LIMIT 1`; * ``` */ takeOptional(...args: SQLQueryArgs): Promise; /** * Returns array of tuples of the values: * * ```ts * const arrayOfTuples: [number, string][] = await db.$query.rows< * [number, string] * >`SELECT id, name FROM table`; * ``` */ rows(...args: SQLQueryArgs): Promise; /** * Returns a flat array of values for a single column: * * ```ts * const strings: string[] = await db.$query.pluck`SELECT name FROM table`; * ``` */ pluck(...args: SQLQueryArgs): Promise; /** * Returns a single value, throws [NotFoundError](/guide/error-handling) if not found. * * ```ts * const value: number = await db.$query.get`SELECT 1`; * ``` */ get(...args: SQLQueryArgs): Promise; /** * Returns a single value or `undefined` when not found. * * ```ts * const value: number | undefined = await db.$query.getOptional`SELECT 1`; * ``` */ getOptional(...args: SQLQueryArgs): Promise; } interface RawSqlBase extends Expression { _sql: string | TemplateLiteralArgs; _values?: RawSQLValues; } interface RawSql extends Expression, RawSqlBase, ExpressionTypeMethod {} declare class RawSql> extends Expression { result: { value: T; }; columnTypes: ColumnTypes; q: ExpressionData; _sql: string | TemplateLiteralArgs; _values?: RawSQLValues; constructor(sql: string | TemplateLiteralArgs, values?: RawSQLValues, type?: T); values(this: Self, values: RawSQLValues): Self; makeSQL(ctx: ToSqlValues, quotedAs?: string): string; } declare const isRawSQL: (arg: unknown) => arg is RawSqlBase; declare const rawSqlToCode: (rawSql: RawSqlBase, t: string) => string; interface DynamicRawSQL extends Expression, ExpressionTypeMethod {} declare class DynamicRawSQL> extends Expression { fn: DynamicSQLArg; columnTypes: ColumnTypes; result: { value: T; }; q: ExpressionData; dynamicBefore: boolean; constructor(fn: DynamicSQLArg); makeSQL(ctx: ToSQLCtx, quotedAs?: string): string; } /** * @deprecated use `sql` instead */ declare function raw(...args: StaticSQLArgs): RawSql>; /** * @deprecated use `sql` instead */ declare function raw(...args: [DynamicSQLArg>]): DynamicRawSQL>; interface SqlFn { (this: T, ...args: Args): Args extends [RecordUnknown] ? (...sql: TemplateLiteralArgs) => RawSql : RawSql; /** * `sql.ref` quotes a SQL identifier such as a table name, column name, or schema name. * Use it when you need to dynamically reference an identifier in raw SQL. * * ```ts * import { sql } from './baseTable'; * * const schema = 'my_schema'; * * // Produces: SET LOCAL search_path TO "my_schema" * await db.$query`SET LOCAL search_path TO ${sql.ref(schema)}` * ``` * * It handles dots to support qualified names: * * ```ts * // "my_schema"."my_table" * sql.ref('my_schema.my_table'); * ``` */ ref(name: string): SqlRefExpression; unsafe(sql: string | number | boolean): UnsafeSqlExpression; } declare class UnsafeSqlExpression extends Expression { sql: string | number | boolean; result: { value: Column.Pick.QueryColumn; }; q: ExpressionData; constructor(sql: string | number | boolean); makeSQL(): string; } interface MutativeQueriesSelectRelationsQueryData { selectRelation?: true; } interface MutativeQueriesSelectRelationsSqlProp { mutativeQueriesSelectRelationsState?: MutativeQueriesSelectRelationsSqlState; } interface MutativeQueriesSelectRelationsSqlState { query: IsQuery; value?: MutativeQueriesSelectRelationsValue; } interface MutativeQueriesSelectRelationsValue { [K: string]: IsQuery; } interface SqlCommonOptions extends HasTableHook, HasCteHooks, MutativeQueriesSelectRelationsSqlProp {} interface SingleSqlItem { text: string; values?: unknown[]; runAfterQuery?: RunAfterQuery; } interface RunAfterQuery { (queryResult: QueryResult): void | Promise<{ result: unknown; }>; } interface SingleSql extends SingleSqlItem, SqlCommonOptions {} interface BatchSql extends SqlCommonOptions { batch: SingleSql[]; } type Sql = SingleSql | BatchSql; declare const quoteTableWithSchema: (query: ToSQLQuery) => string; declare const getSqlText: (sql: Sql) => string; declare class QuerySql { /** * @deprecated: use `sql` exported from the `createBaseTable` (see "define a base table" in the docs) * * When there is a need to use a piece of raw SQL, use the `sql` exported from the `BaseTable` file, it is also attached to query objects for convenience. * * When selecting a custom SQL, specify a resulting type with `` syntax: * * ```ts * import { sql } from './baseTable'; * * const result: { num: number }[] = await db.table.select({ * num: sql`random() * 100`, * }); * ``` * * In a situation when you want the result to be parsed, such as when returning a timestamp that you want to be parsed into a `Date` object, provide a column type in such a way: * * This example assumes that the `timestamp` column was overridden with `asDate` as shown in [Override column types](/guide/columns-overview#override-column-types). * * ```ts * import { sql } from './baseTable'; * * const result: { timestamp: Date }[] = await db.table.select({ * timestamp: sql`now()`.type((t) => t.timestamp()), * }); * ``` * * In some cases such as when using [from](/guide/orm-and-query-builder.html#from), setting column type via callback allows for special `where` operations: * * ```ts * const subQuery = db.someTable.select({ * sum: () => sql`$a + $b`.type((t) => t.decimal()).values({ a: 1, b: 2 }), * }); * * // `gt`, `gte`, `min`, `lt`, `lte`, `max` in `where` * // are allowed only for numeric columns: * const result = await db.$from(subQuery).where({ sum: { gte: 5 } }); * ``` * * Many query methods have a version suffixed with `Sql`, you can pass an SQL template literal directly to these methods. * These methods are: `whereSql`, `whereNotSql`, `orderSql`, `havingSql`, `fromSql`, `findBySql`. * * ```ts * await db.table.whereSql`"someValue" = random() * 100`; * ``` * * Interpolating values in template literals is completely safe: * * ```ts * // get value from user-provided params * const { value } = req.params; * * // SQL injection is prevented by a library, this is safe: * await db.table.whereSql`column = ${value}`; * ``` * * In the example above, TS cannot check if the table has `column` column, or if there are joined tables that have such column which will lead to error. * Instead, use the [column](/guide/sql-expressions#column) or [ref](/guide/sql-expressions#ref) to reference a column: * * ```ts * // ids will be prefixed with proper table names, no ambiguity: * db.table.join(db.otherTable, 'id', 'other.otherId').where` * ${db.table.column('id')} = 1 AND * ${db.otherTable.ref('id')} = 2 * `; * ``` * * SQL can be passed with a simple string, it's important to note that this is not safe to interpolate values in it. * * ```ts * import { sql } from './baseTable'; * * // no interpolation is okay * await db.table.where(sql({ raw: 'column = random() * 100' })); * * // get value from user-provided params * const { value } = req.params; * * // this is NOT safe, SQL injection is possible: * await db.table.where(sql({ raw: `column = random() * ${value}` })); * ``` * * To inject values into `sql({ raw: '...' })` SQL strings, denote it with `$` in the string and provide `values` object. * * Use `$$` to provide column or/and table name (`column` or `ref` are preferable). Column names will be quoted so don't quote them manually. * * ```ts * import { sql } from './baseTable'; * * // get value from user-provided params * const { value } = req.params; * * // this is SAFE, SQL injection are prevented: * await db.table.where( * sql({ * raw: '$$column = random() * $value', * values: { * column: 'someTable.someColumn', // or simply 'column' * one: value, * two: 123, * }, * }), * ); * ``` * * Summarizing: * * ```ts * import { sql } from './baseTable'; * * // simplest form: * sql`key = ${value}`; * * // with resulting type: * sql`key = ${value}`; * * // with column type for select: * sql`key = ${value}`.type((t) => t.boolean()); * * // with column name via `column` method: * sql`${db.table.column('column')} = ${value}`; * * // raw SQL string, not allowed to interpolate values: * sql({ raw: 'random()' }); * * // with resulting type and `raw` string: * sql({ raw: 'random()' }); * * // with column name and a value in a `raw` string: * sql({ * raw: `$$column = $value`, * values: { column: 'columnName', value: 123 }, * }); * * // combine template literal, column type, and values: * sql`($one + $two) / $one`.type((t) => t.numeric()).values({ one: 1, two: 2 }); * ``` * * @param args - template literal or an object { raw: string } * @return object that has `type` and `values` methods */ sql(this: PickQueryColumTypes, ...args: StaticSQLArgs): RawSql, ColumnTypes>; sql(this: PickQueryColumTypes, ...args: [DynamicSQLArg>]): DynamicRawSQL, ColumnTypes>; } interface WithDataItem { table: string; shape: Column.QueryColumns; } interface WithDataItems { [K: string]: WithDataItem; } interface CteItem { n: string | ((as: string) => void); o?: CteOptions; q?: SubQueryForSql; s?: Expression; p?: boolean; } interface CteOptions { columns?: string[]; recursive?: true; materialized?: true; notMaterialized?: true; } interface TopCTE { names: RecordUnknown; stack: string[][]; append: string[][]; } declare const addTopCteSql: (ctx: ToSQLCtx, as: string | undefined, sql: string) => string; declare const addTopCte: (place: "before" | "after", ctx: ToSQLCtx, q: SubQueryForSql, type: QueryData["type"], as?: string | ((as: string) => void), dontAddTableHook?: boolean) => string; /** * Function to turn the operator expression into SQL. * * @param key - SQL of the target to apply operator for, can be a quoted column name or an SQL expression wrapped with parens. * @param args - arguments of operator function. * @param ctx - context object for SQL conversions, for collecting query variables. * @param quotedAs - quoted table name. */ interface OperatorToSQL { (key: string, args: [unknown], ctx: unknown, quotedAs?: string): string; } interface Operator { (this: T, arg: Value): { [K in Exclude]: K extends 'result' ? { value: Column; } : K extends 'returnType' ? 'valueOrThrow' : K extends 'then' ? QueryThen : T[K] } & Column['operators']; _opType: Value; } interface Base { __hasSelect: true; equals: Operator; not: Operator; in: Operator; notIn: Operator; } interface OperatorsBooleanSelf extends OperatorsBoolean { result: { value: BooleanQueryColumn; }; } interface Ord extends Base { lt: Operator; lte: Operator; gt: Operator; gte: Operator; between: Operator<[Value | IsQuery | Expression, Value | IsQuery | Expression], BooleanQueryColumn>; } type OperatorsNumber = Ord; interface OperatorsBoolean extends Ord { and: Operator; or: Operator; } interface OperatorsText extends Base { contains: Operator; containsSensitive: Operator; startsWith: Operator; startsWithSensitive: Operator; endsWith: Operator; endsWithSensitive: Operator; } interface OperatorsOrdinalText extends Ord, OperatorsText {} interface JsonPathQueryOptions { vars?: RecordUnknown; silent?: boolean; } interface JsonPathQueryTypeOptions extends JsonPathQueryOptions { type?: (types: T['columnTypes']) => C; } interface JsonPathQuery { /** * Selects a value from JSON data using a JSON path. * * Calls the [jsonb_path_query_first](https://www.postgresql.org/docs/current/functions-json.html) Postgres function. * * Type can be provided via `{ type: (t) => t.columnType() }` options, by default the type is `unknown`. * * Optionally takes `vars` and `silent` parameters, see [Postgres docs](https://www.postgresql.org/docs/current/functions-json.html) for details. * * The `type` option sets the output type when selecting a value, * also it makes specific operators available in `where`, so that you can apply `contains` if the type is text, and `gt` if the type is numeric. * * ```ts * // query a single value from a JSON data, * // because of the provided type, string JSON value will be parsed to a Date object. * const value = await db.table * .get('data') * .jsonPathQueryFirst('$.path.to.date', { type: (t) => t.date().asDate() }); * * // using it in a select * const records = await db.table.select({ * date: (q) => * q.get('data').jsonPathQueryFirst('$[*] ? (@ = key)', { * type: (t) => t.integer(), * // defining `vars` and `silent` * vars: { key: 'key' }, * silent: true, * }), * }); * * // using it in `where` * const filtered = await db.table.where((q) => * // filtering records by the `name` property from the `data` JSON column * q.get('data').jsonPathQueryFirst('$.name').equals('name'), * ); * * // using it in update * await db.table.find(id).update({ * // using data property to set the `name` column * name: (q) => * q.get('data').jsonPathQueryFirst('$.name', { type: (t) => t.string() }), * }); * * // filtering records to contain 'word' in the json property "name" * await db.table.where((q) => * q * .get('data') * .jsonPathQueryFirst('$.name', { type: (t) => t.string() }) * .contains('word'), * ); * ``` * * @param path - JSON path * @param options - can have type, vars, silent */ >(this: T, path: string, options?: JsonPathQueryTypeOptions): Omit, keyof T['result']['value']['operators']> & C['operators']; _opType: never; } interface OperatorsJson extends Ord { jsonPathQueryFirst: JsonPathQuery; jsonSupersetOf: Operator; jsonSubsetOf: Operator; jsonSet: { /** * Returns a JSON value/object/array where a given value is set at the given path. * The path is a key or an array of keys to access the value. * * Calls the [jsonb_set](https://www.postgresql.org/docs/current/functions-json.html) Postgres function. * * It can be used in all contexts on a single JSON value. * * ```ts * await db.table.find(id).update({ * data: (q) => q.get('data').jsonSet(['path', 'to', 'value'], 'new value'), * // supports sql for the value * data: (q) => q.get('data').jsonSet(['path', 'to', 'value'], sql`'new value'`), * }); * ``` * * @param path - key or array of keys * @param value - value to set */ (this: T, path: MaybeArray, value: unknown): T; _opType: never; }; jsonReplace: { /** * The same as {@link jsonSet}, but sets the last argument of `jsonb_set` to false, * so this function only has effect when the value already existed in the JSON. * * ```ts * await db.table.find(id).update({ * // data.path.to.value will be updated only if it already was defined * data: (q) => q.get('data').jsonReplace(['path', 'to', 'value'], 'new value'), * // supports sql for the value * data: (q) => * q.get('data').jsonReplace(['path', 'to', 'value'], sql`'new value'`), * }); * ``` * * @param path - key or array of keys * @param value - value to set */ (this: T, path: MaybeArray, value: unknown): T; _opType: never; }; jsonInsert: { /** * Inserts a value into a given position of JSON array and returns the whole array. * The path is a key or an array of keys to access the value. * * If a value exists at the given path, the value is not replaced. * * Provide `{ after: true }` option to insert a value after a given position. * * Calls the [jsonb_insert](https://www.postgresql.org/docs/current/functions-json.html) Postgres function. * * It can be used in all contexts on a single JSON value. * * ```ts * // update the record with data { tags: ['two'] } to have data { tags: ['one', 'two'] } * await db.table.find(id).update({ * data: (q) => q.get('data').jsonInsert(['tags', 0], 'one'), * // supports sql for the value * data: (q) => q.get('data').jsonInsert(['tags', 0], sql`'one'`), * }); * * // add 'three' after 'two' * await db.table.find(id).update({ * data: (q) => q.get('data').jsonInsert(['tags', 1], 'three', { after: true }), * }); * ``` * * @param path - key or array of keys * @param value - value to insert * @param options - can have `after: true` */ (this: T, path: MaybeArray, value: unknown, options?: { after?: boolean; }): T; _opType: never; }; jsonRemove: { /** * Remove a value from a JSON object or array at a given path. * The path is a key or an array of keys to access the value. * * Uses the [#-](https://www.postgresql.org/docs/current/functions-json.html) Postgres operator. * * It can be used in all contexts on a single JSON value. * * ```ts * // the record has data { tags: ['one', 'two'] } * // removing the first tag, the data will be { tags: ['two'] } * const result = await db.table.find(id).update({ * data: (q) => q.get('data').jsonRemove(['tags', 0]), * }); * ``` * * @param path - key or array of keys */ (this: T, path: MaybeArray): T; _opType: never; }; } type OperatorsAny = Base; type OperatorsDate = Ord; type OperatorsTime = Ord; interface OperatorsArray extends Ord { has: Operator; hasEvery: Operator; hasSome: Operator; containedIn: Operator; length: { _opType: number | { [K in Exclude]?: OperatorsNumber[K]['_opType'] }; }; } declare const Operators: { any: OperatorsAny; ordinalText: OperatorsOrdinalText; boolean: OperatorsBoolean; number: OperatorsNumber; date: OperatorsDate; time: OperatorsTime; text: OperatorsText; json: OperatorsJson; array: OperatorsArray; }; type SelectableOrExpression = '*' | keyof T['__selectable'] | Expression; type SelectableOrExpressions = ('*' | keyof T['__selectable'] | Expression)[]; type ExpressionOutput> = Expr extends keyof T['__selectable'] ? T['__selectable'][Expr]['column'] : Expr extends Expression ? Expr['result']['value'] : never; type ExpressionChain = (OperatorToSQL | unknown)[]; interface ExpressionData extends HasBeforeAndBeforeSet { chain?: ExpressionChain; expr?: Expression; before?: QueryBeforeHook[]; dynamicBefore?: boolean; } declare abstract class Expression { abstract result: { value: T; }; abstract q: ExpressionData; meta: { kind: 'select'; }; toSQL(ctx: ToSqlValues, quotedAs?: string): string; abstract makeSQL(ctx: ToSqlValues, quotedAs?: string): string; } declare const isExpression: (arg: unknown) => arg is Expression; type TemplateLiteralArgs = [strings: TemplateStringsArray, ...values: unknown[]]; interface DynamicSQLArg { (sql: (...args: StaticSQLArgs) => Expression): Expression; } type StaticSQLArgs = TemplateLiteralArgs | [{ raw: string; values?: RawSQLValues; }]; type RawSQLValues = RecordUnknown; declare abstract class ExpressionTypeMethod { type(this: T, fn: (types: T['columnTypes']) => C): // Omit is optimal Omit & { result: { value: C; }; }; } type IsolationLevel = 'SERIALIZABLE' | 'REPEATABLE READ' | 'READ COMMITTED' | 'READ UNCOMMITTED'; interface TransactionOptions extends SqlSessionState { /** * Enable or disable logging for all queries in the transaction. */ log?: boolean; /** * Default schema to use for queries in the transaction. */ schema?: QuerySchema; /** * Postgres isolation level for the top-level transaction. */ level?: IsolationLevel; /** * Whether the top-level transaction should be read-only. */ readOnly?: boolean; /** * Whether the top-level transaction should be deferrable. */ deferrable?: boolean; /** * Postgres role to apply for the transaction callback. * * Nested transactions can temporarily replace the parent transaction role. */ role?: SqlSessionState['role']; /** * Postgres custom settings to apply for the transaction callback. * * Nested transaction settings are shallow-merged over the parent transaction * settings while the nested callback runs. */ setConfig?: SqlSessionState['setConfig']; } interface AfterCommitErrorFulfilledResult extends PromiseFulfilledResult { name?: string; } interface AfterCommitErrorRejectedResult extends PromiseRejectedResult { name?: string; } type AfterCommitErrorResult = AfterCommitErrorFulfilledResult | AfterCommitErrorRejectedResult; /** * `AfterCommitError` is thrown when one of after commit hooks throws. * * ```ts * interface AfterCommitError extends OrchidOrmError { * // the result of transaction functions * result: unknown; * * // Promise.allSettled result + optional function names * hookResults: ( * | { * status: 'fulfilled'; * value: unknown; * name?: string; * } * | { * status: 'rejected'; * reason: any; // the error object thrown by a hook * name?: string; * } * )[]; * } * ``` * * Use `function name() {}` function syntax for hooks to give them names, * so later they can be identified when handling after commit errors. * * ```ts * class SomeTable extends BaseTable { * readonly table = 'someTable'; * columns = this.setColumns((t) => ({ * ...someColumns, * })); * * init(orm: typeof db) { * // anonymous funciton - has no name * this.afterCreateCommit([], async () => { * // ... * }); * * // named function * this.afterCreateCommit([], function myHook() => { * // ... * }); * } * } * ``` */ declare class AfterCommitError extends OrchidOrmError { result: unknown; hookResults: AfterCommitErrorResult[]; constructor(result: unknown, hookResults: AfterCommitErrorResult[]); } type AfterCommitErrorHandler = (error: AfterCommitError) => void | Promise; declare class QueryTransaction { /** * In Orchid ORM the method is `$transaction`, when using `pqb` on its own it is `transaction`. * * `COMMIT` happens automatically after the callback was successfully resolved, and `ROLLBACK` is done automatically if the callback fails. * * Let's consider the case of transferring money from one user to another: * * ```ts * export const transferMoney = async ( * fromId: number, * toId: number, * amount: number, * ) => { * try { * // db.$transaction returns data that is returned from the callback * // result here is senderRemainder * const result = await db.$transaction(async () => { * const sender = await db.user.find(fromId); * const senderRemainder = sender.balance - amount; * if (senderRemainder < 0) { * throw new Error('Sender does not have enough money'); * } * * await db.user.find(fromId).decrement({ * balance: amount, * }); * await db.user.find(toId).increment({ * balance: amount, * }); * * return senderRemainder; * }); * } catch (error) { * // handle transaction error * } * }; * ``` * * It performs 3 queries in a single transaction: load sender record, decrement sender's balance, increment receiver's balance. * * If sender or receiver record doesn't exist, it will throw `NotFound` error, and there is an error thrown when sender's balance is too low. * In such case, the transaction will be rolled back and no changes will be applied to the database. * * Internally, ORM relies on [AsyncLocalStorage](https://nodejs.org/api/async_context.html#class-asynclocalstorage) feature of node.js, * it allows passing the transaction object implicitly. So that any query that is done inside of callback, will run inside a transaction. * * ## nested transactions * * Transactions can be nested one in another. * The top level transaction is the real one, * and the nested ones are emulated with [savepoint](https://www.postgresql.org/docs/current/sql-savepoint.html) instead of `BEGIN` * and [release savepoint](https://www.postgresql.org/docs/current/sql-release-savepoint.html) instead of `COMMIT`. * * Use [ensureTransaction](#ensuretransaction) to run all queries in a single transaction. * * ```ts * const result = await db.$transaction(async () => { * await db.table.create(...one); * * const result = await db.$transaction(async () => { * await db.table.create(...two); * return 123; * }); * * await db.table.create(...three); * * return result; * }); * * // result is returned from the inner transaction * result === 123; * ``` * * If the inner transaction throws an error, and it is caught by `try/catch` of outer transaction, * it performs [rollback to savepoint](https://www.postgresql.org/docs/current/sql-rollback-to.html) * and the outer transaction can continue: * * ```ts * class CustomError extends Error {} * * await db.$transaction(async () => { * try { * await db.$transaction(async () => { * throw new CustomError(); * }); * } catch (err) { * if (err instanceof CustomError) { * // ignore this error * return; * } * throw err; * } * * // this transaction can continue * await db.table.create(...data); * }); * ``` * * If the error in the inner transaction is not caught, all nested transactions are rolled back and aborted. * * ## SQL session context in transactions * * Pass `role` and `setConfig` in transaction options to apply Postgres SQL session context for the whole transaction: * * ```ts * await db.$transaction( * { * role: 'app_user', * setConfig: { * 'app.tenant_id': tenantId, * 'app.user_id': userId, * }, * }, * async () => { * const project = await db.project.find(projectId); * * await db.project.find(projectId).update({ lastViewedAt: new Date() }); * * return project; * }, * ); * ``` * * This is different from `$withOptions({ role, setConfig }, cb)`. * `$withOptions` is query-scoped and reconciles SQL session state around each query. * Transaction options are applied once for the transaction and are useful for request-scoped RLS work that is already transaction-bound. * * Nested transactions can temporarily override the parent transaction role and config. * When the nested transaction finishes, Orchid restores the parent transaction context before the outer callback continues. */ transaction(this: PickQueryQAndInternal, cb: () => Promise): Promise; transaction(this: PickQueryQAndInternal, options: IsolationLevel | TransactionOptions, cb: () => Promise): Promise; /** * Use the `$ensureTransaction` when you want to ensure the sequence of queries is running in a transaction, but there is no need for Postgres [savepoints](https://www.postgresql.org/docs/current/sql-savepoint.html). * * ```ts * async function updateUserBalance(userId: string, amount: number) { * await db.$ensureTransaction(async () => { * await db.transfer.create({ userId, amount }) * await db.user.find(userId).increment({ balance: amount }) * }) * } * * async function saveDeposit(userId: string, deposit: { ... }) { * await db.$ensureTransaction(async () => { * await db.deposit.create(deposit) * // transaction in updateUserBalance won't be started * await updateUserBalance(userId, deposit.amount) * }) * } * ``` */ ensureTransaction(this: PickQueryQAndInternal, cb: () => Promise): Promise; isInTransaction(): boolean; /** * Schedules a hook to run after the outermost transaction commits: * * ```ts * await db.$transaction(async () => { * await db.table.create(data) * await db.table.where({ ...conditions }).update({ key: 'value' }) * * db.$afterCommit(() => { // can be sync or async * console.log('after commit') * }) * }) * ``` * * If used outside the transaction, the hook will be executed almost immediately, on the next microtask: * * ```ts * db.$afterCommit(async () => { // can be sync or async * console.log('after commit') * }) * ``` * * If the callback has no `try/catch` and throws an error, * this will cause `uncaughtException` if the callback is sync and `unhandledRejection` if it is async. */ afterCommit(this: Query, hook: AfterCommitStandaloneHook): void; /** * Whenever a query in a transaction fails, the transaction is transitioned to a failed state, no further queries are possible. * * Use [catchUniqueError](/guide/error-handling.html#catchuniqueerror) to handle uniqueness errors, * the following examples do not use it to illustrate error handling. * * ```ts * // This transaction is going to fail * db.$transaction(async () => { * try { * // imagine it fails because the username is already taken * await db.user.insert({ username: 'taken' }); * } catch (err) { * // even though the query is wrapped in a try-catch, the transaction fails anyway * } * }); * ``` * * You can use `catch` method on a query instead of `try-catch` to surpass the problem. * The following transaction won't fail: * * ```ts * // Transaction succeeds * db.$transaction(async () => { * const result = await db.user.insert({ username: 'taken' }).catch(() => 'failed'); * * if (result === 'failed') { * await db.user.insert({ username: 'another' }); * } * }); * ``` * * This is because when using `catch` method, `OrchidORM` will wrap the query with a savepoint. * * Alternatively, you can use the `recoverable()` method: * * ```ts * // Transaction succeeds * db.$transaction(async () => { * try { * await db.user.insert({ username: 'taken' }).recoverable(); * } catch (err) { * await db.user.insert({ username: 'another' }); * } * }); * ``` */ recoverable(this: T): T; } interface ColumnsShape { [K: string]: Column; } declare namespace ColumnsShape { export type DefaultSelectKeys = { [K in keyof S]: S[K]['data']['explicitSelect'] extends true | undefined ? never : K }[keyof S]; export type DefaultOutput = { [K in DefaultSelectKeys]: Set[K]['outputType'] }; export type Input = { [K in Exclude]: Shape[K]['inputType'] } & { [K in Exclude]?: Shape[K]['inputType'] }; export type InputPartial = { [K in keyof Shape]?: Shape[K]['inputType'] }; export type Output = { [K in keyof Shape]: Shape[K]['outputType'] }; export type DefaultSelectOutput = { [K in { [K in keyof Shape]: Shape[K]['data']['explicitSelect'] extends true | undefined ? never : K }[keyof Shape]]: Shape[K]['outputType'] }; export interface MapToObjectColumn { dataType: 'object'; type: { [K in keyof Shape]: Shape[K]['type'] }; outputType: ShallowSimplify>; queryType: { [K in keyof Shape]: Shape[K]['queryType'] }; operators: OperatorsAny; } export interface MapToNullableObjectColumn { dataType: 'object'; type: { [K in keyof Shape]: Shape[K]['type'] }; outputType: ShallowSimplify> | undefined; queryType: { [K in keyof Shape]: Shape[K]['queryType'] } | null; operators: OperatorsAny; } export interface MapToPluckColumn { dataType: 'array'; type: Shape['pluck']['type'][]; outputType: Shape['pluck']['outputType'][]; queryType: Shape['pluck']['queryType'][]; operators: OperatorsAny; } export interface MapToObjectArrayColumn { dataType: 'array'; type: { [K in keyof Shape]: Shape[K]['type'] }[]; outputType: ShallowSimplify>[]; queryType: { [K in keyof Shape]: Shape[K]['queryType'] }[]; operators: OperatorsAny; } type ObjectOutput = { [K in keyof Shape]: Shape[K]['outputType'] }; export {}; } interface SelectSelf extends PickQuerySelectable, PickQueryHasSelect, PickQueryDefaultSelect, PickQueryShape, PickQueryRelations, PickQueryResult, PickQueryReturnType, PickQueryWithData {} type SelectArgs = ('*' | keyof T['__selectable'])[]; interface SubQueryAddition extends IsSubQuery { withData: T['withData']; } type SelectAsFnArg = EmptyObject extends T['relations'] ? T : { [K in keyof T['relations'] | keyof T]: K extends keyof T['relations'] ? T['relations'][K]['maybeSingle'] & SubQueryAddition : K extends keyof T ? T[K] : never }; interface SelectAsArg { [K: string]: keyof T['__selectable'] | Expression | ((q: SelectAsFnArg) => unknown); } type SelectAsFnReturnType = { result: Column.QueryColumns; returnType: Exclude; } | Expression; interface SelectAsCheckReturnTypes { [K: string]: PropertyKey | Expression | ((q: never) => SelectAsFnReturnType); } type SelectReturnType = T['returnType'] extends 'valueOrThrow' ? 'oneOrThrow' : T extends 'value' ? 'one' : T['returnType'] extends 'pluck' ? 'all' : T['returnType']; type SelectResult = { [K in keyof T]: K extends '__hasSelect' ? true : K extends 'result' ? { [K in '*' extends Columns[number] ? Exclude | T['__defaultSelect'] : Columns[number] as T['__selectable'][K]['as']]: T['__selectable'][K]['column'] } & (T['__hasSelect'] extends (T['returnType'] extends 'value' | 'valueOrThrow' ? never : true) ? Omit : unknown) : K extends 'returnType' ? SelectReturnType : K extends 'then' ? QueryThenByReturnType, { [K in '*' extends Columns[number] ? Exclude | T['__defaultSelect'] : Columns[number] as T['__selectable'][K]['as']]: T['__selectable'][K]['column'] } & (T['__hasSelect'] extends (T['returnType'] extends 'value' | 'valueOrThrow' ? never : true) ? Omit : unknown)> : T[K] }; type SelectResultObj = Obj extends SelectAsCheckReturnTypes ? { [K in keyof T]: K extends '__hasSelect' ? true : K extends '__selectable' ? T['__selectable'] & SelectAsSelectable : K extends 'result' ? { [K in T['__hasSelect'] extends (T['returnType'] extends 'value' | 'valueOrThrow' ? never : true) ? keyof Obj | keyof T['result'] : keyof Obj]: K extends keyof Obj ? SelectAsValueResult : K extends keyof T['result'] ? T['result'][K] : never } : K extends 'returnType' ? SelectReturnType : K extends 'then' ? QueryThenByReturnType, { [K in T['__hasSelect'] extends (T['returnType'] extends 'value' | 'valueOrThrow' ? never : true) ? keyof Obj | keyof T['result'] : keyof Obj]: K extends keyof Obj ? SelectAsValueResult : K extends keyof T['result'] ? T['result'][K] : never }> : T[K] } : `Invalid return type of ${{ [K in keyof Obj]: Obj[K] extends ((...args: any[]) => any) ? ReturnType extends SelectAsFnReturnType ? never : K : never }[keyof Obj] & string}`; type SelectResultColumnsAndObj = { [K in keyof T]: K extends '__hasSelect' ? true : K extends '__selectable' ? T['__selectable'] & SelectAsSelectable : K extends 'result' ? // Combine previously selected items, all columns if * was provided, { [K in ('*' extends Columns[number] ? Exclude | T['__defaultSelect'] : Columns[number]) | keyof Obj as K extends Columns[number] ? T['__selectable'][K]['as'] : K]: K extends keyof Obj ? SelectAsValueResult : T['__selectable'][K]['column'] } & (T['__hasSelect'] extends (T['returnType'] extends 'value' | 'valueOrThrow' ? never : true) ? Omit : unknown) : K extends 'returnType' ? SelectReturnType : K extends 'then' ? QueryThenByReturnType, { [K in ('*' extends Columns[number] ? Exclude | T['__defaultSelect'] : Columns[number]) | keyof Obj as K extends Columns[number] ? T['__selectable'][K]['as'] : K]: K extends keyof Obj ? SelectAsValueResult : T['__selectable'][K]['column'] } & (T['__hasSelect'] extends (T['returnType'] extends 'value' | 'valueOrThrow' ? never : true) ? Omit : unknown)> : T[K] }; interface AllowedRelationOneQueryForSelectable extends IsSubQuery { result: Column.QueryColumns; returnType: 'value' | 'valueOrThrow' | 'one' | 'oneOrThrow'; } type SelectAsSelectable = UnionToIntersection<{ [K in keyof Obj]: Obj[K] extends ((q: never) => infer R extends AllowedRelationOneQueryForSelectable) ? { [C in R['returnType'] extends 'value' | 'valueOrThrow' ? K : keyof R['result'] as R['returnType'] extends 'value' | 'valueOrThrow' ? K : `${K & string}.${C & string}`]: { as: C; column: R['returnType'] extends 'value' | 'valueOrThrow' ? R['result']['value'] : R['result'][C & keyof R['result']]; } } : never }[keyof Obj]>; type SelectAsValueResult = Arg extends keyof T['__selectable'] ? T['__selectable'][Arg]['column'] : Arg extends Expression ? Arg['result']['value'] : Arg extends ((q: never) => IsQuery) ? SelectSubQueryResult> : Arg extends ((q: never) => Expression) ? ReturnType['result']['value'] : Arg extends ((q: never) => IsQuery | Expression) ? SelectSubQueryResult, Expression>> | Exclude, IsQuery>['result']['value'] : never; type SelectSubQueryResult = Arg['returnType'] extends undefined | 'all' ? ColumnsShape.MapToObjectArrayColumn : Arg['returnType'] extends 'value' | 'valueOrThrow' ? Arg['result']['value'] : Arg['returnType'] extends 'pluck' ? ColumnsShape.MapToPluckColumn : Arg['returnType'] extends 'one' ? ColumnsShape.MapToNullableObjectColumn : ColumnsShape.MapToObjectColumn; declare function _querySelect>(q: T, columns: Columns): SelectResult; declare function _querySelect>(q: T, obj: Obj): SelectResultObj; declare function _querySelect, Obj extends SelectAsArg>(q: T, args: [...columns: Columns, obj: Obj]): SelectResultColumnsAndObj; declare class Select { /** * Takes a list of columns to be selected, and by default, the query builder will select all columns of the table. * * The last argument can be an object. Keys of the object are column aliases, value can be a column name, sub-query, or raw SQL expression. * * ```ts * import { sql } from './baseTable' * * // select columns of the table: * db.table.select('id', 'name', { idAlias: 'id' }); * * // accepts columns with table names: * db.table.select('user.id', 'user.name', { nameAlias: 'user.name' }); * * // table name may refer to the current table or a joined table: * db.table * .join(db.message, 'authorId', 'user.id') * .select('user.name', 'message.text', { textAlias: 'message.text' }); * * // select value from the sub-query, * // this sub-query should return a single record and a single column: * db.table.select({ * subQueryResult: Otherdb.table.select('column').take(), * }); * * // select raw SQL value, specify the returning type via syntax: * db.table.select({ * raw: sql`1 + 2`, * }); * * // select raw SQL value, the resulting type can be set by providing a column type in such way: * db.table.select({ * raw: sql`1 + 2`.type((t) => t.integer()), * }); * * // same raw SQL query as above, but the sql is returned from a callback * db.table.select({ * raw: () => sql`1 + 2`.type((t) => t.integer()), * }); * ``` * * When you use the ORM and defined relations, `select` can also accept callbacks with related table queries: * * ```ts * await db.author.select({ * allBooks: (q) => q.books, * firstBook: (q) => q.books.order({ createdAt: 'ASC' }).take(), * booksCount: (q) => q.books.count(), * }); * ``` * * When you're selecting a relation that's connected via `belongsTo` or `hasOne`, it becomes available to use in `order` or in `where`: * * ```ts * // select books with their authors included, order by author name and filter by author column: * await db.books * .select({ * author: (q) => q.author, * }) * .order('author.name') * .where({ 'author.isPopular': true }); * ``` */ select>(this: T, ...args: Columns): SelectResult; select>(this: T, obj: Obj): SelectResultObj; select, Obj extends SelectAsArg>(this: T, ...args: [...columns: Columns, obj: Obj]): SelectResultColumnsAndObj; /** * When querying the table or creating records, all columns are selected by default, * but updating and deleting queries are returning affected row counts by default. * * Use `selectAll` to select all columns. If the `.select` method was applied before it will be discarded. * * ```ts * const selectFull = await db.table * .select('id', 'name') // discarded by `selectAll` * .selectAll(); * * const updatedFull = await db.table.selectAll().where(conditions).update(data); * * const deletedFull = await db.table.selectAll().where(conditions).delete(); * ``` */ selectAll(this: T): SelectResult; } type SelectItem = string | SelectAs | Expression | undefined; interface SelectAs { selectAs: SelectAsValue; } interface SelectAsValue { [K: string]: string | Query | Expression | undefined; } declare const getShapeFromSelect: (q: IsQuery, isSubQuery?: boolean) => Column.QueryColumns; type AfterHook
= Table extends (new () => { columns: { shape: infer R; }; }) ? keyof R : never; } export namespace Error { interface Messages { required?: string; invalidType?: string; } interface Message { message?: string; } type StringOrMessage = string | Message; } export interface InputOutputQueryTypes { inputType: unknown; outputType: unknown; queryType: unknown; } export interface InputOutputQueryTypesWithSchemas extends InputOutputQueryTypes { inputSchema: unknown; outputSchema: unknown; querySchema: unknown; } export interface QueryData { explicitSelect?: boolean; primaryKey?: string; unique?: string; optional?: true; isNullable?: true; default?: unknown; name?: string; readOnly?: boolean; appReadOnly: true | undefined; } export interface Data extends ColumnDataComputedProp { key: string; name?: string; optional: true | undefined; isNullable?: true; primaryKey?: string; default: unknown; defaultDefault: unknown; runtimeDefault?(): unknown; explicitSelect?: boolean; as?: Column.Pick.Data; unique?: string; modifyQuery?(q: Query, column: Column.Pick.Data): void; checks?: Column.Data.Check[]; isOfCustomType?: boolean; errors?: RecordString; defaultTimestamp?: 'createdAt' | 'updatedAt'; alias?: string; extension?: string; encode?(input: any): unknown; parse?(input: any): unknown; parseItem?(input: string): unknown; parseNull?(): unknown; jsonCast?: string; readOnly?: boolean; appReadOnly: true | undefined; setOnCreate?(arg: QueryHookUtils): unknown; setOnUpdate?(arg: QueryHookUtils): unknown; setOnSave?(arg: QueryHookUtils): unknown; typmod?: number; virtual?: true; maxChars?: number; numericPrecision?: number; numericScale?: number; dateTimePrecision?: number; validationDefault?: unknown; indexes?: TableData.ColumnIndex[]; excludes?: TableData.ColumnExclude[]; comment?: string; collate?: string; compression?: string; foreignKeys?: TableData.ColumnReferences[]; identity?: TableData.Identity; generated?: Data.Generated; readonly?: boolean; } export namespace Data { interface Check { sql: RawSqlBase; name?: string; } interface Generated { toSQL(ctx: { values: unknown[]; snakeCase: boolean | undefined; }, quotedAs?: string): string; toCode(): string; } } interface AsTypeArgWithType { type: Schema; input?: Schema; output?: Schema; query?: Schema; } interface AsTypeArgWithoutType { input: Schema; output: Schema; query: Schema; } export type AsTypeArg = AsTypeArgWithType | AsTypeArgWithoutType; export {}; } declare function makeColumnNullable(column: T, inputSchema: InputSchema, outputSchema: OutputSchema, querySchema: QuerySchema): Column.Modifiers.Nullable; declare const setColumnData: (q: T, key: K, value: T["data"][K]) => T; declare const setDataValue: (item: T, key: Key, value: Value, params?: Column.Error.StringOrMessage) => T; declare function setCurrentColumnName(name: string): void; declare const consumeColumnName: () => string | undefined; declare const setDefaultLanguage: (lang?: string) => void; declare abstract class Column { inputSchema: InputSchema; outputSchema: OutputSchema; querySchema: QuerySchema; abstract dataType: string; abstract operators: Ops; abstract toCode(ctx: ColumnToCodeCtx, key: string): Code; type: Type; inputType: InputType; outputType: OutputType; queryType: QueryType; nullType: unknown; nullSchema: unknown; isNullable: boolean; data: Column.Data; error: Schema['error']; _parse?: (input: unknown) => unknown; constructor(schema: ColumnTypeSchemaArg, inputSchema: InputSchema, outputSchema?: OutputSchema, querySchema?: QuerySchema); /** * Set a default value to a column. Columns that have defaults become optional when creating a record. * * If you provide a value or a raw SQL, such default should be set on the column in migration to be applied on a database level. * * Or you can specify a callback that returns a value. This function will be called for each creating record. Such a default won't be applied to a database. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * // values as defaults: * int: t.integer().default(123), * text: t.text().default('text'), * * // raw SQL default: * timestamp: t.timestamp().default(t.sql`now()`), * * // runtime default, each new records gets a new random value: * random: t.numeric().default(() => Math.random()), * })); * } * ``` * * @param value - default value or a function returning a value */ default T['inputType'])>(this: T, value: Value): Column.Modifiers.Default; /** * Use `hasDefault` to let the column be omitted when creating records. * * It's better to use {@link default} instead so the value is explicit and serves as a hint. */ hasDefault(this: T): Column.Modifiers.Default; /** * Set a database-level validation check to a column. `check` accepts a raw SQL. * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * // validate rank to be from 1 to 10 * rank: t.integer().check(t.sql`1 >= "rank" AND "rank" <= 10`), * // constraint name can be passed as a second argument * column: t.integer().check(t.sql`...`, 'check_name'), * // a single column can have multiple checks * multiChecksColumn: t * .integer() * .check(t.sql`...`) * .check(t.sql`...`, 'optional_name'), * })); * }); * ``` * * @param sql - raw SQL expression * @param name - to specify a constraint name */ check(this: T, sql: RawSqlBase, name?: string): T; /** * Use `nullable` to mark the column as nullable. By default, all columns are required. * * Nullable columns are optional when creating records. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * name: t.integer().nullable(), * })); * } * ``` */ nullable: Schema['nullable']; /** * Set a custom function to process value for the column when creating or updating a record. * * The type of `input` argument will be used as the type of the column when creating and updating. * * If you have a validation library [installed and configured](/guide/columns-validation-methods.html), * first argument is a schema to validate the input. * * ```ts * import { z } from 'zod'; * * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * // encode boolean, number, or string to text before saving * column: t * .string() * // when having validation library, the first argument is a validation schema * .encode( * z.boolean().or(z.number()).or(z.string()), * (input: boolean | number | string) => String(input), * ) * // no schema argument otherwise * .encode((input: boolean | number | string) => String(input)), * })); * } * * // numbers and booleans will be converted to a string: * await db.table.create({ column: 123 }); * await db.table.create({ column: true }); * await db.table.where({ column: 'true' }).update({ column: false }); * ``` * * @param fn - function to encode value for a database, argument type is specified by you, return type must be compatible with a database */ encode: Schema['encode']; /** * Set a custom function to process value after loading it from a database. * * The type of input is the type of column before `.parse`, the resulting type will replace the type of column. * * If you have a validation library [installed and configured](/guide/columns-validation-methods.html), * first argument is a schema for validating the output. * * For handling `null` values use {@link parseNull} instead or in addition. * * ```ts * import { z } from 'zod'; * import { number, integer } from 'valibot'; * * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * columnZod: t * .string() * // when having validation library, the first argument is a schema * .parse(z.number().int(), (input) => parseInt(input)) * // no schema argument otherwise * .parse((input) => parseInt(input)), * * columnValibot: t * .string() * .parse(number([integer()]), (input) => parseInt(input)) * .parse((input) => parseInt(input)), * })); * } * * // column will be parsed to a number * const value: number = await db.table.get('column'); * ``` * * @param fn - function to parse a value from the database, argument is the type of this column, return type is up to you */ parse: Schema['parse']; /** * Use `parseNull` to specify runtime defaults at selection time. * * The `parseNull` function is only triggered for `nullable` columns. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * column: t * .integer() * .parse(String) // parse non-nulls to string * .parseNull(() => false), // replace nulls with false * .nullable(), * })); * } * * const record = await db.table.take() * record.column // can be a string or boolean, not null * ``` * * If you have a validation library [installed and configured](/guide/columns-validation-methods), * first argument is a schema for validating the output. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * column: t * .integer() * .parse(z.string(), String) // parse non-nulls to string * .parseNull(z.literal(false), () => false), // replace nulls with false * .nullable(), * })); * } * * const record = await db.table.take() * record.column // can be a string or boolean, not null * * Table.outputSchema().parse({ * column: false, // the schema expects strings or `false` literals, not nulls * }) * ``` */ parseNull: Schema['parseNull']; /** * This method changes a column type without modifying its behavior. * This is needed when converting columns to a validation schema, the converter will pick a different type specified by `.as`. * * Before calling `.as` need to use `.encode` with the input of the same type as the input of the target column, * and `.parse` which returns the correct type. * * ```ts * // column has the same type as t.integer() * const column = t * .string() * .encode((input: number) => input) * .parse((text) => parseInt(text)) * .as(t.integer()); * ``` * * @param column - other column type to inherit from */ as(this: T, column: C): C; /** * @deprecated use narrowType instead */ asType: Schema['asType']; /** * `narrowType` narrows TypeScript types of a column. It sets input, output, query type altogether. * * For example, to narrow a `string` type to a union of string literals. * * When _not_ integrating with [validation libraries](/guide/columns-validation-methods), `narrowType` has the following syntax: * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * size: t.string().narrowType((t) => t<'small' | 'medium' | 'large'>()), * })); * } * * // size will be typed as 'small' | 'medium' | 'large' * const size = await db.table.get('size'); * ``` * * - `input` is for `create`, `update` methods. * - `output` is for the data that is loaded from a database and parsed if the column has `parse`. * - `query` is used in `where` and other query methods, it should be compatible with the actual database column type. * * When integrating with a [validation library](/guide/columns-validation-methods), also provide validation schemas: * * ```ts * const sizeSchema = z.union([ * z.literal('small'), * z.literal('medium'), * z.literal('large'), * ]); * * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * size: t.text().narrowType(sizeSchema), * })); * } * * // size will be typed as 'small' | 'medium' | 'large' * const size = await db.table.get('size'); * ``` */ narrowType: Schema['narrowType']; /** * Allows to narrow different TypeScript types of a column granularly. * * Use it when the column's input is different from output. * * When _not_ integrating with [validation libraries](/guide/columns-validation-methods), `narrowAllTypes` has the following syntax: * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * size: t.string().narrowAllTypes((t) => * t<{ * // what types are accepted when creating/updating * input: 'small' | 'medium' | 'large'; * // how types are retured from a database * output: 'small' | 'medium' | 'large'; * // what types the column accepts in `where` and similar * query: 'small' | 'medium' | 'large'; * }>(), * ), * })); * } * * // size will be typed as 'small' | 'medium' | 'large' * const size = await db.table.get('size'); * ``` * * - `input` is for `create`, `update` methods. * - `output` is for the data that is loaded from a database and parsed if the column has `parse`. * - `query` is used in `where` and other query methods, it should be compatible with the actual database column type. * * When integrating with a [validation library](/guide/columns-validation-methods), also provide validation schemas: * * ```ts * const sizeSchema = z.union([ * z.literal('small'), * z.literal('medium'), * z.literal('large'), * ]); * * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * size: t.text().narrowAllTypes({ * input: sizeSchema, * output: sizeSchema, * query: sizeSchema, * }), * })); * } * * // size will be typed as 'small' | 'medium' | 'large' * const size = await db.table.get('size'); * ``` */ narrowAllTypes: Schema['narrowAllTypes']; input(this: T, fn: (schema: T['inputSchema']) => InputSchema): { [K in keyof T]: K extends 'inputSchema' ? InputSchema : T[K] }; output(this: T, fn: (schema: T['outputSchema']) => OutputSchema): { [K in keyof T]: K extends 'outputSchema' ? OutputSchema : T[K] }; query(this: T, fn: (schema: T['querySchema']) => QuerySchema): { [K in keyof T]: K extends 'querySchema' ? QuerySchema : T[K] }; /** * Set a database column name. * * @param name - name of the column in database. */ name(this: T, name: string): T; /** * Append `select(false)` to a column to exclude it from the default selection. * It won't be selected with `selectAll` or `select('*')` as well. * * ```ts * export class UserTable extends BaseTable { * readonly table = 'user'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * name: t.string(), * password: t.string().select(false), * })); * } * * // only id and name are selected, without password * const user = await db.user.find(123); * * // password is still omitted, even with the wildcard * const same = await db.user.find(123).select('*'); * * const comment = await db.comment.find(123).select({ * // password is omitted in the sub-selects as well * author: (q) => q.author, * }); * * // password is omitted here as well * const created = await db.user.create(userData); * ``` * * Such a column can only be selected explicitly. * * ```ts * const userWithPassword = await db.user.find(123).select('*', 'password'); * ``` */ select(this: T, value: Value): Column.Modifiers.DefaultSelect; /** * Forbid the column to be used in [create](/guide/create-update-delete.html#create-insert) and [update](/guide/create-update-delete.html#update) methods. * * `readOnly` column is still can be set from a [hook](http://localhost:5173/guide/hooks.html#set-values-before-create-or-update). * * `readOnly` column can be used together with a `default`. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * column: t.string().default(() => 'default value'), * another: t.string().readOnly(), * })); * * init(orm: typeof db) { * this.beforeSave(({ set }) => { * set({ another: 'value' }); * }); * } * } * * // later in the code * db.table.create({ column: 'value' }); // TS error, runtime error * ``` */ readOnly(this: T): T & Column.Modifiers.IsAppReadOnly; /** * Set a column value when creating a record. * This works for [readOnly](#readonly) columns as well. * * If no value or undefined is returned, the hook won't have any effect. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * column: t.string().setOnCreate(() => 'value'), * })); * } * ``` */ setOnCreate(this: T, fn: (arg: QueryHookUtils) => T['inputType'] | void): T; /** * Set a column value when updating a record. * This works for [readOnly](#readonly) columns as well. * * If no value or undefined is returned, the hook won't have any effect. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * column: t.string().setOnUpdate(() => 'value'), * })); * } * ``` */ setOnUpdate(this: T, fn: (arg: QueryHookUtils) => T['inputType'] | void): T; /** * Set a column value when creating or updating a record. * This works for [readOnly](#readonly) columns as well. * * If no value or undefined is returned, the hook won't have any effect. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * column: t.string().setOnSave(() => 'value'), * })); * } * ``` */ setOnSave(this: T, fn: (arg: QueryHookUtils) => T['inputType'] | void): T; /** * Mark the column as a primary key. * This column type becomes an argument of the `.find` method. * So if the primary key is of `integer` type (`identity` or `serial`), `.find` will accept the number, * or if the primary key is of `UUID` type, `.find` will expect a string. * * Using `primaryKey` on a `uuid` column will automatically add a [gen_random_uuid](https://www.postgresql.org/docs/current/functions-uuid.html) default. * * ```ts * export class Table extends BaseTable { * readonly table = 'table'; * columns = this.setColumns((t) => ({ * id: t.uuid().primaryKey(), * // database-level name can be passed: * id: t.uuid().primaryKey('primary_key_name'), * })); * } * * // primary key can be used by `find` later: * db.table.find('97ba9e78-7510-415a-9c03-23d440aec443'); * ``` * * @param name - to specify a constraint name */ primaryKey(this: T, name?: Name): T & Column.Modifiers.IsPrimaryKey; /** * Defines a reference between different tables to enforce data integrity. * * In [snakeCase](/guide/orm-and-query-builder.html#snakecase-option) mode, columns of both tables are translated to a snake_case. * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * otherId: t.integer().foreignKey('otherTableName', 'columnName'), * })); * }); * ``` * * In the migration it's different from OrchidORM table code where a callback with a table is expected: * * ```ts * export class SomeTable extends BaseTable { * readonly table = 'someTable'; * columns = this.setColumns((t) => ({ * otherTableId: t.integer().foreignKey(() => OtherTable, 'id'), * })); * } * ``` * * Optionally you can pass the third argument to `foreignKey` with options: * * ```ts * type ForeignKeyOptions = { * // name of the constraint * name?: string; * // see database docs for MATCH in FOREIGN KEY * match?: 'FULL' | 'PARTIAL' | 'SIMPLE'; * * onUpdate?: 'NO ACTION' | 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT'; * onDelete?: 'NO ACTION' | 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT'; * }; * ``` * * ## composite foreign key * * Set foreign key from multiple columns in the current table to corresponding columns in the other table. * * The first argument is an array of columns in the current table, the second argument is another table name, the third argument is an array of columns in another table, and the fourth argument is for options. * * Options are the same as in a single-column foreign key. * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * id: t.integer(), * name: t.string(), // string is varchar(255) * ...t.foreignKey( * ['id', 'name'], * 'otherTable', * ['foreignId', 'foreignName'], * { * name: 'constraintName', * match: 'FULL', * onUpdate: 'RESTRICT', * onDelete: 'CASCADE', * }, * ), * })); * }); * ``` * * @param fn - function returning a table class * @param column - column in the foreign table to connect with * @param options - {@link ForeignKeyOptions} */ foreignKey(this: T, fn: () => new () => { columns: { shape: Shape; }; }, column: keyof Shape, options?: TableData.References.Options): T; foreignKey(this: T, table: Table, column: Column, options?: TableData.References.Options): T; toSQL(): string; /** * Add an index to the column. * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * // add an index to the name column with default settings: * name: t.text().index(), * // options are described below: * name: t.text().index({ ...options }), * // with a database-level name: * name: t.text().index({ name: 'custom_index_name', ...indexOptions }), * })); * }); * ``` * * Possible options are: * * ```ts * type IndexOptions = { * name?: string, * // NULLS NOT DISTINCT: availabe in Postgres 15+, makes sense only for unique index * nullsNotDistinct?: true; * // index algorithm to use such as GIST, GIN * using?: string; * // specify collation: * collate?: string; * // see `opclass` in the Postgres document for creating the index * opclass?: string; * // specify index order such as ASC NULLS FIRST, DESC NULLS LAST * order?: string; * // include columns to an index to optimize specific queries * include?: MaybeArray; * // see "storage parameters" in the Postgres document for creating an index, for example, 'fillfactor = 70' * with?: string; * // The tablespace in which to create the index. If not specified, default_tablespace is consulted, or temp_tablespaces for indexes on temporary tables. * tablespace?: string; * // WHERE clause to filter records for the index * where?: string; * // mode is for dropping the index * mode?: 'CASCADE' | 'RESTRICT'; * }; * ``` * * @param args */ index(this: T, ...args: [options?: TableData.Index.ColumnArg]): T; /** * `searchIndex` is designed for [full text search](/guide/text-search). * * It can accept the same options as a regular `index`, but it is `USING GIN` by default, and it is concatenating columns into a `tsvector` database type. * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * id: t.identity().primaryKey(), * title: t.text(), * body: t.text(), * ...t.searchIndex(['title', 'body']), * })); * }); * ``` * * Produces the following index ('english' is a default language, see [full text search](/guide/text-search.html#language) for changing it): * * ```sql * CREATE INDEX "table_title_body_idx" ON "table" USING GIN (to_tsvector('english', "title" || ' ' || "body")) * ``` * * You can set different search weights (`A` to `D`) on different columns inside the index: * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * id: t.identity().primaryKey(), * title: t.text(), * body: t.text(), * ...t.searchIndex([ * { column: 'title', weight: 'A' }, * { column: 'body', weight: 'B' }, * ]), * })); * }); * ``` * * When the table has localized columns, * you can define different indexes for different languages by setting the `language` parameter: * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * id: t.identity().primaryKey(), * titleEn: t.text(), * bodyEn: t.text(), * titleFr: t.text(), * bodyFr: t.text(), * ...t.searchIndex(['titleEn', 'bodyEn'], { language: 'english' }), * ...t.searchIndex(['titleFr', 'bodyFr'], { language: 'french' }), * })); * }); * ``` * * Alternatively, different table records may correspond to a single language, * then you can define a search index that relies on a language column by using `languageColumn` parameter: * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * id: t.identity().primaryKey(), * lang: t.type('regconfig'), * title: t.text(), * body: t.text(), * ...t.searchIndex(['title', 'body'], { languageColumn: 'lang' }), * })); * }); * ``` * * It can be more efficient to use a [generated](/guide/migration-column-methods.html#generated-column) column instead of indexing text column in the way described above, * and to set a `searchIndex` on it: * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * id: t.identity().primaryKey(), * title: t.text(), * body: t.text(), * generatedTsVector: t.tsvector().generated(['title', 'body']).searchIndex(), * })); * }); * ``` * * Produces the following index: * * ```sql * CREATE INDEX "table_generatedTsVector_idx" ON "table" USING GIN ("generatedTsVector") * ``` * * @param options - index options */ searchIndex(this: T, ...args: [options?: TableData.Index.TsVectorColumnArg]): T; unique(this: T, ...args: [options?: Options]): T & Column.Modifiers.IsUnique; /** * Add [EXCLUDE constraint](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-EXCLUDE) to the column. * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * // exclude rows with overlapping time ranges, && is for the `WITH` operator * timeRange: t.type('tstzrange').exclude('&&'), * // with a database-level name: * timeRange: t.type('tstzrange').exclude('&&', 'no_overlap'), * // with options: * timeRange: t.type('tstzrange').exclude('&&', { ...options }), * // with name and options: * name: t.type('tstzrange').exclude('&&', 'no_overlap', { ...options }), * })); * }); * ``` * * Possible options are: * * ```ts * interface ExcludeColumnOptions { * // specify collation: * collate?: string; * // see `opclass` in the Postgres document for creating the index * opclass?: string; * // specify index order such as ASC NULLS FIRST, DESC NULLS LAST * order?: string; * // algorithm to use such as GIST, GIN * using?: string; * // EXCLUDE creates an index under the hood, include columns to the index * include?: MaybeArray; * // see "storage parameters" in the Postgres document for creating an index, for example, 'fillfactor = 70' * with?: string; * // The tablespace in which to create the constraint. If not specified, default_tablespace is consulted, or temp_tablespaces for indexes on temporary tables. * tablespace?: string; * // WHERE clause to filter records for the constraint * where?: string; * // for dropping the index at a down migration * dropMode?: DropMode; * } * ``` */ exclude(this: T, op: string, ...args: [options?: TableData.Exclude.ColumnArg]): T; comment(this: T, comment: string): T; compression(this: T, compression: string): T; collate(this: T, collate: string): T; modifyQuery(this: T, cb: (q: Query) => void): T; /** * Define a generated column. `generated` accepts a raw SQL. * * ```ts * import { change } from '../dbScript'; * * change(async (db) => { * await db.createTable('table', (t) => ({ * two: t.integer().generated`1 + 1`, * })); * }); * ``` * * @param args - raw SQL */ generated(this: T, ...args: StaticSQLArgs): Column.Modifiers.Generated; } interface ColumnFromDbParams { isNullable?: boolean; default?: string; maxChars?: number; numericPrecision?: number; numericScale?: number; dateTimePrecision?: number; compression?: string; collate?: string; extension?: string; typmod: number; } declare const assignDbDataToColumn: (column: Column.Pick.Data, params: ColumnFromDbParams) => Column.Pick.Data; type CreateFromMethodNames = 'createOneFrom' | 'insertOneFrom' | CreateManyFromMethodNames; type CreateManyFromMethodNames = 'createManyFrom' | 'insertManyFrom' | 'createForEachFrom' | 'insertForEachFrom'; interface QueryReturningOne extends IsQuery { result: Column.QueryColumns; returnType: 'one' | 'oneOrThrow'; } type CreateRawOrFromResult = T extends { isCount: true; } ? T : T['returnType'] extends undefined | 'all' ? SetQueryReturnsOne : T['returnType'] extends 'pluck' ? SetQueryReturnsColumn : T; type InsertRawOrFromResult = T['__hasSelect'] extends true ? T['returnType'] extends undefined | 'all' ? SetQueryReturnsOne : T['returnType'] extends 'pluck' ? SetQueryReturnsColumn : T : SetQueryReturnsRowCount; type CreateManyFromResult = T extends { isCount: true; } ? T : T['returnType'] extends 'one' | 'oneOrThrow' ? SetQueryReturnsAll : T['returnType'] extends 'value' | 'valueOrThrow' ? SetValueQueryReturnsPluckColumn : T; type InsertManyFromResult = T['__hasSelect'] extends true ? T['returnType'] extends 'one' | 'oneOrThrow' ? SetQueryReturnsAll : T['returnType'] extends 'value' | 'valueOrThrow' ? SetValueQueryReturnsPluckColumn : T : SetQueryReturnsRowCountMany; /** * Function to collect column names from the inner query of create `from` methods. * * @param q - the creating query * @param from - inner query to grab the columns from. * @param obj - optionally passed object with specific data, only available when creating a single record. * @param many - whether it's for `createForEachFrom`. If no, throws if the inner query returns multiple records. */ declare const _queryCreateManyFrom: (q: T, query: Q, data: Omit, keyof Q["result"]>[]) => CreateManyFromResult; declare class QueryCreateFrom { /** * Inserts a single record based on a query that selects a single record. * * Performs a single SQL query based on `INSERT ... SELECT ... FROM`. * * See {@link createManyFrom} to insert multiple records based on a single record query, * and {@link createForEachFrom} to insert a record per every one found by the query. * * The first argument is a query of a **single** record, it should have `find`, `take`, or similar. * * The second optional argument is a data which will be merged with columns returned by the query. * * The data for the second argument is the same as in {@link create}. * * Columns with runtime defaults (defined with a callback) are supported here. * The value for such a column will be injected unless selected from a related table or provided in a data object. * * ```ts * const oneRecord = await db.table.createOneFrom( * db.relatedTable * // use select to map columns from one table to another * .select({ * // relatedTable's id will be inserted as "relatedId" * relatedId: 'id', * }) * .findBy({ key: 'value' }), * // optional argument: * { * key: 'value', * // supports sql, nested select, create, update, delete queries * fromSql: () => sql`custom sql`, * fromQuery: () => db.otherTable.find(id).update(data).get('column'), * fromRelated: (q) => q.relatedTable.create(data).get('column'), * }, * ); * ``` * * The query above will produce such a SQL (omitting `from*` values): * * ```sql * INSERT INTO "table"("relatedId", "key") * SELECT "relatedTable"."id" AS "relatedId", 'value' * FROM "relatedTable" * WHERE "relatedTable"."key" = 'value' * LIMIT 1 * RETURNING * * ``` * * @param query - query to create new records from * @param data - additionally you can set some columns */ createOneFrom(this: T, query: Q, data?: Omit, Q['result'] extends infer R ? keyof R : never>): CreateRawOrFromResult; /** * Works exactly as {@link createOneFrom}, except that it returns inserted row count by default. * * @param query - query to create new records from * @param data - additionally you can set some columns */ insertOneFrom(this: T, query: Q, data?: Omit, Q['result'] extends infer R ? keyof R : never>): InsertRawOrFromResult; /** * Inserts multiple records based on a query that selects a single record. * * Performs a single SQL query based on `INSERT ... SELECT ... FROM`. * * See {@link createOneFrom} to insert a single record based on a single record query, * and {@link createForEachFrom} to insert a record per every one found by the query. * * The first argument is a query of a **single** record, it should have `find`, `take`, or similar. * * The second argument is array of objects to be merged with columns returned by the query. * * The data for the second argument is the same as in {@link createMany}. * * Columns with runtime defaults (defined with a callback) are supported here. * The value for such a column will be injected unless selected from a related table or provided in a data object. * * ```ts * const twoRecords = await db.table.createManyFrom( * db.relatedTable * // use select to map columns from one table to another * .select({ * // relatedTable's id will be inserted as "relatedId" * relatedId: 'id', * }) * .findBy({ key: 'value' }), * [ * { * key: 'value 1', * // supports sql, nested select, create, update, delete queries * fromSql: () => sql`custom sql`, * fromQuery: () => db.otherTable.find(id).update(data).get('column'), * fromRelated: (q) => q.relatedTable.create(data).get('column'), * }, * { * key: 'value 2', * }, * ], * ); * ``` * * The query above will produce such a SQL (omitting `from*` values): * * ```sql * WITH "relatedTable" AS ( * SELECT "relatedTable"."id" AS "relatedId", 'value' * FROM "relatedTable" * WHERE "relatedTable"."key" = 'value' * LIMIT 1 * ) * INSERT INTO "table"("relatedId", "key") * SELECT "relatedTable".*, v."key"::text * FROM "relatedTable", (VALUES ('value1'), ('value2')) v("key") * RETURNING * * ``` * * @param query - query to create new records from * @param data - array of records to create */ createManyFrom(this: T, query: Q, data: Omit, Q['result'] extends infer R ? keyof R : never>[]): CreateManyFromResult; /** * Works exactly as {@link createManyFrom}, except that it returns inserted row count by default. * * @param query - query to create new records from * @param data - array of records to create */ insertManyFrom(this: T, query: Q, data: Omit, Q['result'] extends infer R ? keyof R : never>[]): InsertManyFromResult; /** * Inserts a single record per every record found in a given query. * * Performs a single SQL query based on `INSERT ... SELECT ... FROM`. * * Unlike {@link createOneFrom}, it doesn't accept second argument with data. * * Runtime defaults cannot work with it. * * ```ts * const manyRecords = await db.table.createForEachFrom( * db.relatedTable.select({ relatedId: 'id' }).where({ key: 'value' }), * ); * ``` * * @param query - query to create new records from */ createForEachFrom(this: T, query: IsQuery): CreateManyFromResult; /** * Works exactly as {@link createForEachFrom}, except that it returns inserted row count by default. * * @param query - query to create new records from */ insertForEachFrom(this: T, query: IsQuery): InsertManyFromResult; } interface CreateSelf extends IsQuery, PickQueryHasSelect, PickQueryDefaults, PickQueryResult, PickQueryRelations, PickQueryWithData, PickQueryReturnType, PickQueryShape, PickQueryUniqueProperties, PickQueryInputType {} type CreateData = EmptyObject extends T['relations'] ? CreateDataWithDefaults : CreateRelationsData; type CreateDataWithDefaults = { [K in keyof T['inputType'] as K extends Defaults ? never : K]: K extends Defaults ? never : CreateColumn } & { [K in Defaults]?: K extends keyof T['inputType'] ? CreateColumn : never }; type CreateDataWithDefaultsForRelations = { [K in keyof T['inputType'] as K extends Defaults | OmitFKeys ? never : K]: K extends Defaults | OmitFKeys ? never : CreateColumn } & { [K in Defaults as K extends OmitFKeys ? never : K]?: CreateColumn }; type CreateColumn = T['inputType'][K] | ((q: T) => QueryOrExpression); type CreateRelationsData = CreateDataWithDefaultsForRelations & CreateBelongsToData & T['relations'][keyof T['relations']]['optionalDataForCreate']; type CreateBelongsToData = [T['relations'][keyof T['relations']]['dataForCreate']] extends [never] ? EmptyObject : CreateRelationsDataOmittingFKeys; type CreateRelationsDataOmittingFKeys = (Union extends RelationConfigDataForCreate ? (u: Union['columns'] extends keyof T['__defaults'] ? { [P in Exclude]: CreateColumn } & { [P in keyof T['__defaults'] & Union['columns']]?: CreateColumn } & Partial : { [P in Union['columns'] & keyof T['inputType']]: CreateColumn } | Union['nested']) => void : never) extends ((u: infer Obj) => void) ? Obj : never; type CreateResult = T extends { isCount: true; } ? T : T['returnType'] extends undefined | 'all' ? SetQueryReturnsOneResult> : T['returnType'] extends 'pluck' ? SetQueryReturnsColumnResult> : SetQueryResult>; type InsertResult = T['__hasSelect'] extends true ? T['returnType'] extends undefined | 'all' ? SetQueryReturnsOneResult> : T['returnType'] extends 'pluck' ? SetQueryReturnsColumnResult> : SetQueryResult> : SetQueryReturnsRowCount; type CreateManyResult = T extends { isCount: true; } ? T : T['returnType'] extends 'one' | 'oneOrThrow' ? SetQueryReturnsAll : T['returnType'] extends 'value' | 'valueOrThrow' ? SetValueQueryReturnsPluckColumn : T; type InsertManyResult = T['__hasSelect'] extends true ? T['returnType'] extends 'one' | 'oneOrThrow' ? SetQueryReturnsAll : T['returnType'] extends 'value' | 'valueOrThrow' ? SetValueQueryReturnsPluckColumn : T : SetQueryReturnsRowCountMany; /** * When creating a record with a *belongs to* nested record, * un-nullify foreign key columns of the result. * * The same should work as well with any non-null columns passed to `create`, but it's to be implemented later. */ type NarrowCreateResult = EmptyObject extends T['relations'] ? T['result'] : { [K in keyof T['result']]: true extends { [R in keyof T['relations']]: K extends T['relations'][R]['omitForeignKeyInCreate'] ? R extends keyof Data ? true : T['relations'][R]['omitForeignKeyInCreate'] extends keyof Data ? null | undefined extends Data[T['relations'][R]['omitForeignKeyInCreate']] ? never : true : never : never }[keyof T['relations']] ? Column.Pick.QueryColumnOfTypeAndOps, T['result'][K]['operators']> : T['result'][K] }; type IgnoreResult = T['returnType'] extends 'oneOrThrow' ? QueryTakeOptional : T['returnType'] extends 'valueOrThrow' ? SetQueryReturnsColumnOptional : T; type OnConflictArg = T['internal']['uniqueColumnNames'] | T['internal']['uniqueColumnTuples'] | Expression | { constraint: T['internal']['uniqueConstraints']; }; type AddQueryDefaults = { [K in keyof T]: K extends '__defaults' ? { [K in keyof T['__defaults'] | DefaultKeys]: true } : T[K] }; /** * Used by ORM to access the context of current create query. * Is passed to the `create` method of a {@link VirtualColumn} */ interface CreateCtx { columns: Map; returnTypeAll?: true; resultAll: RecordUnknown[]; } declare const _queryCreate: >(q: T, data: Data) => CreateResult; declare const _queryInsert: >(query: T, data: Data) => InsertResult; declare const _queryCreateMany: (q: T, data: CreateData[]) => CreateManyResult; declare const _queryInsertMany: (q: T, data: CreateData[]) => InsertManyResult; declare const _queryDefaults: >>(q: T, data: Data) => AddQueryDefaults; /** * Names of all create methods, * is used in relational query to remove these methods if chained relation shouldn't have them, * for the case of has one/many through. */ type CreateMethodsNames = 'create' | 'insert' | 'createMany' | 'insertMany' | CreateFromMethodNames; type CreateManyMethodsNames = 'createMany' | 'insertMany' | CreateManyFromMethodNames; type ExtraPropertiesAreNotAllowed = keyof Data extends keyof T['inputType'] | keyof T['relations'] ? Data : `Extra properties are not allowed: ${Exclude & string}`; declare class QueryCreate { /** * `create` and `insert` create a single record. * * Use `select`, `selectAll`, `get`, or `pluck` alongside `create` or `insert` to * specify returning columns. * * Each column may accept a specific value, a raw SQL, or a query that returns a single value. * * ```ts * import { sql } from './baseTable'; * * const oneRecord = await db.table.create({ * name: 'John', * password: '1234', * }); * * // When using `.onConflictDoNothing()`, * // the record may be not created and the `createdCount` will be 0. * const createdCount = await db.table.insert(data).onConflictDoNothing(); * * await db.table.create({ * // raw SQL * column1: () => sql`'John' || ' ' || 'Doe'`, * * // query that returns a single value * // returning multiple values will result in Postgres error * column2: () => db.otherTable.get('someColumn'), * * // nesting creates, updates, deletes produces a single SQL * column4: () => db.otherTable.create(data).get('someColumn'), * column5: (q) => q.relatedTable.find(id).update(data).get('someColumn'), * }); * ``` * * Creational methods can be used in {@link WithMethods.with} expressions: * * ```ts * db.$qb * // create a record in one table * .with('a', db.table.select('id').create(data)) * // create a record in other table using the first table record id * .with('b', (q) => * db.otherTable.select('id').create({ * ...otherData, * aId: () => q.from('a').get('id'), * }), * ) * .from('b'); * ``` */ create>(this: T, data: ExtraPropertiesAreNotAllowed): CreateResult; /** * Works exactly as {@link create}, except that it returns inserted row count by default. */ insert>(this: T, data: ExtraPropertiesAreNotAllowed): InsertResult; /** * `createMany` and `insertMany` will create a batch of records. * * Each column may be set with a specific value, a raw SQL, or a query, the same as in {@link create}. * * In case one of the objects has fewer fields, the `DEFAULT` SQL keyword will be placed in its place in the `VALUES` statement. * * ```ts * const manyRecords = await db.table.createMany([ * { key: 'value', otherKey: 'other value' }, * { key: 'value' }, // default will be used for `otherKey` * ]); * * // `createdCount` will be 3. * const createdCount = await db.table.insertMany([data, data, data]); * ``` * * When nesting creates, a separate create query will be executed for every time it's used: * * ```ts * // will be performed twice, even though it is defined once * const nestedCreate = db.otherTable.create(data).get('column'); * * await db.table.createMany([{ column: nestedCreate }, { column: nestedCreate }]); * ``` * * Because of a limitation of Postgres protocol, queries having more than **65535** of values are going to fail in runtime. * To solve this seamlessly, `OrchidORM` will automatically batch such queries, and wrap them into a transaction, unless they are already in a transaction. * * ```ts * // OK: executes 2 inserts wrapped into a transaction * await db.table.createMany( * Array.from({ length: 65536 }, () => ({ text: 'text' })), * ); * ``` * * However, this only works in the case shown above. This **won't** work if you're using the `createMany` in `with` statement, * or if the insert is used as a sub-query in other query part. * * @param data - array of records data, may have values, raw SQL, queries, relation operations */ createMany(this: T, data: CreateData[]): CreateManyResult; /** * Works exactly as {@link createMany}, except that it returns inserted row count by default. * * @param data - array of records data, may have values, raw SQL, queries, relation operations */ insertMany(this: T, data: CreateData[]): InsertManyResult; /** * `defaults` allows setting values that will be used later in `create`. * * Columns provided in `defaults` are marked as optional in the following `create`. * * Default data is the same as in {@link create} and {@link createMany}, * so you can provide a raw SQL, or a query with a query. * * ```ts * // Will use firstName from defaults and lastName from create argument: * db.table * .defaults({ * firstName: 'first name', * lastName: 'last name', * }) * .create({ * lastName: 'override the last name', * }); * ``` * * @param data - default values for `create` and `createMany` which will follow `defaults` */ defaults>>(this: T, data: Data): AddQueryDefaults; /** * By default, violating unique constraint will cause the creative query to throw, * you can define what to do on a conflict: to ignore it, or to merge the existing record with a new data. * * A conflict occurs when a table has a primary key or a unique index on a column, * or a composite primary key unique index on a set of columns, * and a row being created has the same value as a row that already exists in the table in this column(s). * * Use {@link onConflictDoNothing} to suppress the error and continue without updating the record, * or the `merge` to update the record with new values automatically, * or the `set` to specify own values for the update. * * `onConflict` only accepts column names that are defined in `primaryKey` or `unique` in the table definition. * To specify a constraint, its name also must be explicitly set in `primaryKey` or `unique` in the table code. * * Postgres has a limitation that a single `INSERT` query can have only a single `ON CONFLICT` clause that can target only a single unique constraint * for updating the record. * * If your table has multiple potential reasons for unique constraint violation, such as username and email columns in a user table, * consider using `upsert` instead. * * ```ts * // leave `onConflict` without argument to ignore or merge on any conflict * db.table.create(data).onConflictDoNothing(); * * // single column: * // (this requires a composite primary key or unique index, see below) * db.table.create(data).onConflict('email').merge(); * * // array of columns: * db.table.create(data).onConflict(['email', 'name']).merge(); * * // constraint name * db.table.create(data).onConflict({ constraint: 'unique_index_name' }).merge(); * * // raw SQL expression: * db.table * .create(data) * .onConflict(sql`(email) where condition`) * .merge(); * ``` * * :::info * A primary key or a unique index for a **single** column can be fined on a column: * * ```ts * export class MyTable extends BaseTable { * columns = this.setColumns((t) => ({ * pkey: t.uuid().primaryKey(), * unique: t.string().unique(), * })); * } * ``` * * But for composite primary keys or indexes (having multiple columns), define it in a separate function: * * ```ts * export class MyTable extends BaseTable { * columns = this.setColumns( * (t) => ({ * one: t.integer(), * two: t.string(), * three: t.boolean(), * }), * (t) => [t.primaryKey(['one', 'two']), t.unique(['two', 'three'])], * ); * } * ``` * ::: * * You can use the `sql` function exported from your `BaseTable` file in onConflict. * It can be useful to specify a condition when you have a partial index: * * ```ts * db.table * .create({ * email: 'ignore@example.com', * name: 'John Doe', * active: true, * }) * // ignore only when having conflicting email and when active is true. * .onConflict(sql`(email) where active`) * .ignore(); * ``` * * For `merge` and `set`, you can append `where` to update data only for the matching rows: * * ```ts * const timestamp = Date.now(); * * db.table * .create(data) * .onConflict('email') * .set({ * name: 'John Doe', * updatedAt: timestamp, * }) * .where({ updatedAt: { lt: timestamp } }); * ``` * * @param arg - optionally provide an array of columns */ onConflict>(this: T, arg: Arg): OnConflictQueryBuilder; /** * Use `onConflictDoNothing` to suppress unique constraint violation error when creating a record. * * Adds `ON CONFLICT (columns) DO NOTHING` clause to the insert statement, columns are optional. * * Can also accept a constraint name. * * ```ts * db.table * .create({ * email: 'ignore@example.com', * name: 'John Doe', * }) * // on any conflict: * .onConflictDoNothing() * // or, for a specific column: * .onConflictDoNothing('email') * // or, for a specific constraint: * .onConflictDoNothing({ constraint: 'unique_index_name' }); * ``` * * When there is a conflict, nothing can be returned from the database, so `onConflictDoNothing` adds `| undefined` part to the response type. * * ```ts * const maybeRecord: RecordType | undefined = await db.table * .create(data) * .onConflictDoNothing(); * * const maybeId: number | undefined = await db.table * .get('id') * .create(data) * .onConflictDoNothing(); * ``` * * When creating multiple records, only created records will be returned. If no records were created, array will be empty: * * ```ts * // array can be empty * const arr = await db.table.createMany([data, data, data]).onConflictDoNothing(); * ``` */ onConflictDoNothing>(this: T, arg?: Arg): IgnoreResult; } type OnConflictSet$1 = { [K in keyof T['inputType']]?: T['inputType'][K] | (() => QueryOrExpression) }; declare class OnConflictQueryBuilder | undefined> { private query; private onConflict; constructor(query: T, onConflict: Arg); /** * Available only after `onConflict`. * * Updates the record with a given data when conflict occurs. * * ```ts * db.table * .create(data) * .onConflict('email') * .set({ * // supports plain values and SQL expressions * key: 'value', * fromSql: () => sql`custom sql`, * }) * // to update records only on certain conditions * .where({ ...certainConditions }); * ``` * * @param set - object containing new column values */ set(set: OnConflictSet$1): T; /** * Available only after `onConflict`. * * Use this method to merge all the data you have passed into `create` to update the existing record on conflict. * * If the table has columns with **dynamic** default values, such values will be applied as well. * * You can exclude certain columns from being merged by passing the `except` option. * * ```ts * // merge the full data * db.table.create(data).onConflict('email').merge(); * * // merge only a single column * db.table.create(data).onConflict('email').merge('name'); * * // merge multiple columns * db.table.create(data).onConflict('email').merge(['name', 'quantity']); * * // merge all columns except some * db.table * .create(data) * .onConflict('email') * .merge({ except: ['name', 'quantity'] }); * * // merge can be applied also for batch creates * db.table.createMany([data1, data2, data2]).onConflict('email').merge(); * * // update records only on certain conditions * db.table * .create(data) * .onConflict('email') * .merge() * .where({ ...certainConditions }); * ``` * * @param merge - no argument will merge all data, or provide a column(s) to merge, or provide `except` to update all except some. */ merge(merge?: keyof T['shape'] | (keyof T['shape'])[] | { except: keyof T['shape'] | (keyof T['shape'])[]; }): T; } interface UpdateSelf extends PickQuerySelectable, PickQueryResult, PickQueryRelations, PickQueryWithData, PickQueryReturnType, PickQueryShape, PickQueryInputType, PickQueryAs, PickQueryHasSelect, PickQueryHasWhere {} type UpdateData = EmptyObject extends T['relations'] ? { [K in keyof T['inputType']]?: UpdateColumn } : { [K in keyof T['inputType'] | keyof T['relations']]?: K extends keyof T['inputType'] ? UpdateColumn : UpdateRelationData }; type UpdateColumn = T['inputType'][Key] | ((q: { [K in keyof T['relations'] | keyof T]: K extends keyof T['relations'] ? T['relations'][K]['query'] : K extends keyof T ? T[K] : never }) => QueryOrExpression); type UpdateRelationData = T['returnType'] extends undefined | 'all' ? Rel['dataForUpdate'] : Rel['dataForUpdateOne']; type UpdateArg = T['__hasWhere'] extends true ? UpdateData : 'Update statement must have where conditions. To update all prefix `update` with `all()`'; type UpdateResult = T['__hasSelect'] extends true ? T : T['returnType'] extends undefined | 'all' ? SetQueryReturnsRowCountMany : SetQueryReturnsRowCount; type NumericColumns = { [K in keyof T['inputType']]: Exclude extends number | bigint | null ? K : never }[keyof T['inputType']]; type ChangeCountArg = NumericColumns | { [K in NumericColumns]?: T['shape'][K]['type'] extends number | null ? number : number | string | bigint }; type UpdateManyBySelf = UpdateSelf & PickQueryResultReturnTypeUniqueColumns & PickQueryUniqueProperties; type UpdateManyData = ({ [K in keyof T['shape'] as T['shape'][K] extends { data: { primaryKey: string; }; } ? K : never]: T['shape'][K]['queryType'] | Expression } & { [P in keyof T['inputType']]?: T['inputType'][P] | Expression })[]; type UpdateManyByKeys = T['internal']['uniqueColumnNames'] | T['internal']['uniqueColumnTuples']; type UpdateManyByKeyColumns = Keys extends string ? Keys : Keys extends unknown[] ? Keys[number] & string : never; type UpdateManyByData = ({ [P in K & keyof T['inputType']]-?: T['inputType'][P] } & { [P in keyof T['inputType'] as P extends K ? never : P]?: T['inputType'][P] | Expression })[]; type UpdateManyResult = T['__hasSelect'] extends true ? T['returnType'] extends 'one' | 'oneOrThrow' ? SetQueryReturnsAllResult : T['returnType'] extends 'value' | 'valueOrThrow' ? SetQueryReturnsPluckColumnResult : SetQueryResult : SetQueryReturnsRowCountMany; declare const _queryUpdate: (updateSelf: T, arg: UpdateArg) => UpdateResult; declare const _queryUpdateOrThrow: (q: T, arg: UpdateArg) => UpdateResult; declare class QueryUpdate { /** * `update` takes an object with columns and values to update records. * * By default, `update` will return a count of updated records. * * Use `select`, `selectAll`, `get`, or `pluck` alongside `update` to specify * returning columns. * * You need to provide `where`, `findBy`, or `find` conditions before calling `update`. * To ensure that the whole table won't be updated by accident, updating without where conditions will result in TypeScript and runtime errors. * * Use `all()` to update ALL records without conditions: * * ```ts * await db.table.all().update({ name: 'new name' }); * ``` * * If `select` and `where` were specified before the update it will return an array of updated records. * * If `select` and `take`, `find`, or similar were specified before the update it will return one updated record. * * For a column value you can provide a specific value, raw SQL, a query object that returns a single value, or a callback with a sub-query. * * The callback is allowed to select a single value from a relation (see `fromRelation` column below), * or to use a [jsonSet](/guide/advanced-queries.html#jsonset), * [jsonInsert](/guide/advanced-queries.html#jsoninsert), * and [jsonRemove](/guide/advanced-queries.html#jsonremove) for a JSON column (see `jsonColumn` below). * * ```ts * import { sql } from './baseTable'; * * // returns number of updated records by default * const updatedCount = await db.table * .where({ name: 'old name' }) * .update({ name: 'new name' }); * * // returning only `id` * const id = await db.table.find(1).get('id').update({ name: 'new name' }); * * // `selectAll` + `find` will return a full record * const oneFullRecord = await db.table * .selectAll() * .find(1) * .update({ name: 'new name' }); * * // `selectAll` + `where` will return array of full records * const recordsArray = await db.table * .select('id', 'name') * .where({ id: 1 }) * .update({ name: 'new name' }); * * await db.table.where({ ...conditions }).update({ * // set the column to a specific value * value: 123, * * // use custom SQL to update the column * fromSql: () => sql`2 + 2`, * * // use query that returns a single value * // returning multiple values will result in Postgres error * fromQuery: () => db.otherTable.get('someColumn'), * * // select a single value from a related record * fromRelation: (q) => q.relatedTable.get('someColumn'), * * // set a new value to the `.foo.bar` path into a JSON column * jsonColumn: (q) => q.jsonSet('jsonColumn', ['foo', 'bar'], 'new value'), * }); * ``` * * `update` can be used in [with](/guide/advanced-queries#with) expressions: * * ```ts * db.$qb * // update record in one table * .with('a', db.table.find(1).select('id').update(data)) * // update record in other table using the first table record id * .with('b', (q) => * db.otherTable * .find(1) * .select('id') * .update({ * ...otherData, * aId: () => q.from('a').get('id'), * }), * ) * .from('b'); * * `update` can be used in {@link WithMethods.with} expressions: * * ```ts * db.$qb * // update record in one table * .with('a', db.table.find(1).select('id').update(data)) * // update record in other table using the first table record id * .with('b', (q) => * db.otherTable * .find(1) * .select('id') * .update({ * ...otherData, * aId: () => q.from('a').get('id'), * }), * ) * .from('b'); * ``` * * ### sub-queries * * In all `create`, `update`, `upsert` methods, * you can use sub queries that are either selecting a single value, * or creating/updating/deleting a record and return a single value. * * ```ts * await db.table.where({ ...conditions }).update({ * // `column` will be set to a value of the `otherColumn` of the created record. * column: () => db.otherTable.get('otherColumn').create({ ...data }), * * // `column2` will be set to a value of the `otherColumn` of the updated record. * column2: () => * db.otherTable * .get('otherColumn') * .findBy({ ...conditions }) * .update({ key: 'value' }), * * // `column3` will be set to a value of the `otherColumn` of the deleted record. * column3: () => * db.otherTable * .get('otherColumn') * .findBy({ ...conditions }) * .delete(), * }); * ``` * * This is achieved by defining a `WITH` clause under the hood, it produces such a query: * * ```sql * WITH q AS ( * INSERT INTO "otherTable"(col1, col2, col3) * VALUES ('val1', 'val2', 'val3') * RETURNING "otherTable"."selectedColumn" * ) * -- In a case of create * INSERT INTO "table"("column") VALUES ((SELECT * FROM "q")) * -- In a case of update * UPDATE "table" * SET "column" = (SELECT * FROM "q") * ``` * * The query is atomic. * No changes will persist in the database if the sub-query fails, or if the top-level query fails, or if multiple rows are returned from a sub-query. * * [//]: # 'not supported in create because cannot query related records for a thing that is not created yet' * [//]: # 'modificational sub queries are not allowed in update because it would be too hard to join a with statement to the update query' * * Only selective sub-queries are supported in `update` queries when the sub-query is using a relation: * * ```ts * db.book.update({ * authorName: (q) => q.author.get('name'), * }); * ``` * * ### null, undefined, unknown columns * * - `null` value will set a column to `NULL` * - `undefined` value will be ignored * - unknown columns will be ignored * * ```ts * db.table.findBy({ id: 1 }).update({ * name: null, // updates to null * age: undefined, // skipped, no effect * lalala: 123, // skipped * }); * ``` * * ### empty set * * When trying to query update with an empty object, it will be transformed seamlessly to a `SELECT` query: * * ```ts * // imagine the data is an empty object * const data = req.body; * * // query is transformed to `SELECT count(*) WHERE key = 'value'` * const count = await db.table.where({ key: 'value' }).update(data); * * // will select a full record by id * const record = await db.table.find(1).selectAll().update(data); * * // will select a single column by id * const name = await db.table.find(1).get('name').update(data); * ``` * * If the table has `updatedAt` [timestamp](/guide/common-column-methods.html#timestamps), it will be updated even for an empty data. * * @param arg - data to update records with, may have specific values, raw SQL, queries, or callbacks with sub-queries. */ update(this: T, arg: UpdateArg): UpdateResult; /** * To make sure that at least one row was updated use `updateOrThrow`: * * ```ts * import { NotFoundError } from 'orchid-orm'; * * try { * // updatedCount is guaranteed to be greater than 0 * const updatedCount = await db.table * .where(conditions) * .updateOrThrow({ name: 'name' }); * * // updatedRecords is guaranteed to be a non-empty array * const updatedRecords = await db.table * .where(conditions) * .select('id') * .updateOrThrow({ name: 'name' }); * } catch (err) { * if (err instanceof NotFoundError) { * // handle error * } * } * ``` * * @param arg - data to update records with, may have specific values, raw SQL, queries, or callbacks with sub-queries. */ updateOrThrow(this: T, arg: UpdateArg): UpdateResult; /** * Use `updateFrom` to update records in one table based on a query result from another table or CTE. * * `updateFrom` accepts the same arguments as {@link Query.join}. * * ```ts * // save all author names to their books by using a relation name: * db.books.updateFrom('author').set({ authorName: (q) => q.ref('author.name') }); * * // update from authors that match the condition: * db.books * .updateFrom((q) => q.author.where({ writingSkills: 'good' })) * .set({ authorName: (q) => q.ref('author.name') }); * * // update from any table using custom `on` conditions: * db.books * .updateFrom( * () => db.authors, * (q) => q.on('authors.id', 'books.authorId'), * ) * .set({ authorName: (q) => q.ref('author.name') }); * * // conditions after `updateFrom` can reference both tables: * db.books * .updateFrom(() => db.authors) * .where({ * 'authors.id': (q) => q.ref('books.authorId'), * }) * .set({ authorName: (q) => q.ref('author.name') }); * * // can join and use another table in between `updateFrom` and `set`: * db.books * .updateFrom('author') * .join('publisher') * .set({ * authorName: (q) => q.ref('author.name'), * publisherName: (q) => q.ref('publisher.name'), * }); * * // updating from a CTE * db.books * .with('a', () => * db.authors.where({ writingSkills: 'good' }).select('id', 'name').limit(10), * ) * .updateFrom('a', (q) => q.on('a.id', 'books.authorId')) * .set({ authorName: (q) => q.ref('author.name') }); * ``` */ updateFrom, Cb extends JoinCallbackArgs>(this: T, arg: Arg, ...args: Cb | JoinArgs): JoinResultFromArgs & QueryHasWhere; /** * Use after {@link updateFrom} */ set(this: T, arg: UpdateArg): UpdateResult; /** * Increments a column by `1`, returns a count of updated records by default. * * ```ts * const updatedCount = await db.table * .where(...conditions) * .increment('numericColumn'); * ``` * * When using `find` or `get` it will throw `NotFoundError` when no records found. * * ```ts * // throws when not found * const updatedCount = await db.table.find(1).increment('numericColumn'); * * // also throws when not found * const updatedCount2 = await db.table * .where(...conditions) * .get('columnName') * .increment('numericColumn'); * ``` * * Provide an object to increment multiple columns with different values. * Use `select` to specify columns to return. * * ```ts * // increment someColumn by 5 and otherColumn by 10, return updated records * const result = await db.table * .selectAll() * .where(...conditions) * .increment({ * someColumn: 5, * otherColumn: 10, * }); * ``` * * @param data - name of the column to increment, or an object with columns and values to add */ increment(this: T, data: ChangeCountArg): UpdateResult; /** * Decrements a column by `1`, returns a count of updated records by default. * * ```ts * const updatedCount = await db.table * .where(...conditions) * .decrement('numericColumn'); * ``` * * When using `find` or `get` it will throw `NotFoundError` when no records found. * * ```ts * // throws when not found * const updatedCount = await db.table.find(1).decrement('numericColumn'); * * // also throws when not found * const updatedCount2 = await db.table * .where(...conditions) * .get('columnName') * .decrement('numericColumn'); * ``` * * Provide an object to decrement multiple columns with different values. * Use `select` to specify columns to return. * * ```ts * // decrement someColumn by 5 and otherColumn by 10, return updated records * const result = await db.table * .selectAll() * .where(...conditions) * .decrement({ * someColumn: 5, * otherColumn: 10, * }); * ``` * * @param data - name of the column to decrement, or an object with columns and values to subtract */ decrement(this: T, data: ChangeCountArg): UpdateResult; /** * Updates multiple records with different per-row data in a single query. * * Each row must include the primary key and the columns to update. * All rows must have the same set of non-key columns. * * Returns a count of updated records by default. * Use `select`, `selectAll`, `get`, or `pluck` alongside `updateMany` to return * updated records. * * Throws {@link NotFoundError} if any record is not found. * Use {@link updateManyOptional} to skip missing records without throwing. * * ```ts * // returns count of updated records * const count = await db.table.updateMany([ * { id: 1, name: 'Alice', age: 30 }, * { id: 2, name: 'Bob', age: 25 }, * ]); * * // returns array of updated records * const records = await db.table.select('id', 'name').updateMany([ * { id: 1, name: 'Alice' }, * { id: 2, name: 'Bob' }, * ]); * ``` * * `.set()` applies shared values to all rows. * `.set()` values take precedence over per-row values for the same column. * * ```ts * await db.table * .updateMany([ * { id: 1, name: 'Alice' }, * { id: 2, name: 'Bob' }, * ]) * .set({ updatedBy: currentUser.id }); * ``` */ updateMany(this: T, data: UpdateManyData): UpdateManyResult & QueryHasWhere; /** * Same as {@link updateMany}, but skips missing records rather than throwing. * * ```ts * // updates what it can, doesn't throw for missing id: 999 * const count = await db.table.updateManyOptional([ * { id: 1, name: 'Alice' }, * { id: 999, name: 'Ghost' }, * ]); * ``` */ updateManyOptional(this: T, data: UpdateManyData): UpdateManyResult & QueryHasWhere; /** * Like {@link updateMany}, but matches rows by a unique column or a compound unique constraint instead of the primary key. * * Throws {@link NotFoundError} if any record is not found. * Use {@link updateManyByOptional} to skip records with no matching key without throwing. * * ```ts * // single unique column * await db.table.updateManyBy('email', [ * { email: 'alice@test.com', name: 'Alice' }, * { email: 'bob@test.com', name: 'Bob' }, * ]); * * // compound unique constraint * await db.table.updateManyBy(['firstName', 'lastName'], [ * { firstName: 'John', lastName: 'Doe', bio: 'updated' }, * ]); * ``` */ updateManyBy, K extends string = UpdateManyByKeyColumns>(this: T, keys: Keys, data: UpdateManyByData): UpdateManyResult & QueryHasWhere; /** * Same as {@link updateManyBy}, but skips records with no matching key rather than throwing. * * ```ts * await db.table.updateManyByOptional('email', [ * { email: 'alice@test.com', name: 'Alice' }, * { email: 'unknown@test.com', name: 'Ghost' }, * ]); * ``` */ updateManyByOptional, K extends string = UpdateManyByKeyColumns>(this: T, keys: Keys, data: UpdateManyByData): UpdateManyResult & QueryHasWhere; } declare abstract class VirtualColumn> extends Column { dataType: string; operators: OperatorsAny; constructor(schema: Schema, inputSchema?: InputSchema); toCode(): never; create?(q: CreateSelf, ctx: CreateCtx, items: unknown[], rowIndex: number[], count: number): void; update?(q: UpdateSelf, set: RecordUnknown): void; } declare class UnknownColumn extends VirtualColumn { static instance: UnknownColumn; selectable: boolean; constructor(schema: Schema); } interface ColumnsByType { [K: string]: () => Column.Pick.Data; } declare const makeColumnsByType: (schema: ColumnSchemaConfig) => never; interface DbStructureDomainsMap { [K: string]: Column; } declare const setColumnParse: (column: Column.Pick.Data, fn: (input: any) => unknown, outputSchema?: unknown) => any; declare const setColumnParseNull: (column: Column.Pick.Data, fn: () => unknown, nullSchema?: unknown) => any; declare const setColumnEncode: (column: Column.Pick.Data, fn: (input: any) => unknown, inputSchema?: unknown) => any; declare const getColumnBaseType: (column: Column.Pick.Data, domainsMap: DbStructureDomainsMap, type: string) => string; interface ColumnDataComputedProp { computed?: Expression; } type ComputedColumnsFromOptions | undefined> = T extends ((...args: any[]) => infer R extends ComputedOptionsConfig) ? { [K in keyof R]: R[K] extends QueryOrExpression ? R[K]['result']['value'] : R[K] extends (() => { result: { value: infer Value extends Column.Pick.QueryColumn; }; }) ? Value : never } : EmptyObject; interface ComputedOptionsConfig { [K: string]: QueryOrExpression | ReturnsQueryOrExpression; } type ComputedOptionsFactory = (t: ComputedMethods) => ComputedOptionsConfig; interface RuntimeComputedQueryColumn extends Column.Pick.QueryColumn { dataType: 'runtimeComputed'; type: never; outputType: OutputType; queryType: undefined; operators: { cannotQueryRuntimeComputed: never; }; } interface ComputedMethods extends QueryComputedArg { computeAtRuntime(dependsOn: Deps[], fn: (record: { [K in keyof Shape & Deps]: Shape[K]['outputType'] }) => OutputType): { result: { value: RuntimeComputedQueryColumn; }; }; computeBatchAtRuntime(dependsOn: Deps[], fn: (record: { [K in keyof Shape & Deps]: Shape[K]['outputType'] }[]) => MaybePromise): { result: { value: RuntimeComputedQueryColumn; }; }; } declare class ComputedColumn { kind: 'one' | 'many'; deps: string[]; fn: FnUnknownToUnknown; constructor(kind: 'one' | 'many', deps: string[], fn: FnUnknownToUnknown); } interface ComputedColumns { [K: string]: ComputedColumn; } interface QueryComputedArg extends QueryExpressions, QuerySql { shape: Shape; columnTypes: ColumnTypes; windows: EmptyObject; relations: RelationsBase; result: EmptyObject; __selectable: { [K in keyof Shape]: { as: string; column: Column.Pick.QueryColumn; } }; } type QueryDataTransform = QueryDataTransformFn | { map: (record: unknown, index: number, array: unknown) => unknown; thisArg?: unknown; }; interface QueryDataTransformFn { (data: unknown, queryData: unknown): unknown; } /** * See `transform` query method. * This helper applies all transform functions to a result. * * @param queryData - query data * @param returnType - return type of the query, for proper `map` handling * @param fns - array of transform functions, can be undefined * @param result - query result to transform */ declare class QueryTransform { /** * Transform the result of the query right after loading it. * * `transform` method should be called in the last order, other methods can't be chained after calling it. * * It is meant to transform the whole result of a query, for transforming individual records consider using {@link QueryMap.map}. * * The [hooks](/guide/hooks.html) that are going to run after the query will receive the query result **before** transferring. * * Consider the following example of a cursor-based pagination by `id`: * * ```ts * const lastId: number | undefined = req.query.cursor; * * type Result = { * nodes: { id: number; text: string }[]; * cursor?: number; * }; * * // result is only for demo, it will be inferred * const posts: Result = await db.post * .select('id', 'text') * .where({ id: { lt: lastId } }) * .order({ id: 'DESC' }) * .limit(100) * .transform((nodes) => ({ nodes, cursor: nodes.at(-1)?.id })); * ``` * * You can also use the `tranform` on nested sub-queries: * * ```ts * type Result = { * nodes: { * id: number; * text: string; * comments: { nodes: { id: number; text: string }[]; cursor?: number }; * }[]; * cursor?: number; * }; * * const postsWithComments: Result = await db.post * .select('id', 'text') * .select({ * comments: (q) => * q.comments * .select('id', 'text') * .transform((nodes) => ({ nodes, cursor: nodes.at(-1)?.id })), * }) * .transform((nodes) => ({ nodes, cursor: nodes.at(-1)?.id })); * ``` * * @param fn - function to transform query result with */ transform(this: T, fn: (input: T extends { then: QueryThen; } ? Data : never, queryData: QueryData) => Result): { [K in keyof T]: K extends 'returnType' ? 'valueOrThrow' : K extends 'result' ? { value: Column.Pick.QueryColumnOfType; } : K extends 'then' ? QueryThen : T[K] }; } type WhereItem = { [K: string]: unknown | { [K: string]: unknown | SubQueryForSql | Expression; } | Expression; NOT?: MaybeArray; AND?: MaybeArray; OR?: MaybeArray[]; IN?: MaybeArray; EXISTS?: MaybeArray; ON?: WhereOnItem | WhereJsonPathEqualsItem; SEARCH?: MaybeArray; } | Query | Expression; interface WhereInItem { columns: string[]; values: unknown[][] | SubQueryForSql | Expression; } type WhereJsonPathEqualsItem = [leftColumn: string, leftPath: string, rightColumn: string, rightPath: string]; interface WhereOnItem { joinFrom: WhereOnJoinItem; from: string; joinTo: WhereOnJoinItem; to: string; useOuterAliases?: true; op?: string; } type WhereOnJoinItem = { table?: string; q: { as?: string; }; } | string; type HavingItem = TemplateLiteralArgs | Expression[]; interface WindowItem { [K: string]: WindowDeclaration | Expression; } interface WindowDeclaration { partitionBy?: SelectableOrExpression | SelectableOrExpression[]; order?: OrderItem; } interface UnionItem { a: SubQueryForSql | Expression; k: UnionKind; p?: boolean; } type UnionKind = 'UNION' | 'UNION ALL' | 'INTERSECT' | 'INTERSECT ALL' | 'EXCEPT' | 'EXCEPT ALL'; interface QueryDataUnion { b: SubQueryForSql; u: UnionItem[]; p?: boolean; } type OnConflictTarget = string | string[] | Expression | { constraint: string; }; type OnConflictSet = RecordUnknown; type OnConflictMerge = string | string[] | { except: string | string[]; }; interface RecordOfColumnsShapeBase { [K: string]: Column.Shape.QueryInit; } interface WithConfigs { [K: string]: WithConfig; } interface WithConfig { shape: Column.Shape.QueryInit; computeds?: ComputedColumns; } type JoinedShapes = RecordOfColumnsShapeBase; interface JoinedParsers { [K: string]: ColumnsParsers | undefined; } type QueryBeforeHook = (query: Query) => void | Promise; type QueryBeforeActionHook = (utils: QueryHookUtils) => void | Promise; type QueryAfterHook = (data: Data, query: Query) => unknown | Promise; type QueryScopeData = (q: Query) => { and?: WhereItem[]; or?: WhereItem[][]; }; type QueryDataFromItem = string | SubQueryForSql | Expression; interface QueryDataJoinTo extends PickQueryTable, PickQueryQ {} interface HandleResult { (q: Query, returnType: QueryReturnType, result: QueryResult, sql: Sql, isSubQuery?: true): unknown; } type WithItems = CteItem[]; interface JoinValueDedupItem { q: Query; a: string; } type QueryType = undefined | null | 'upsert' | 'insert' | 'update' | 'delete'; interface AsFn { (as: string): void; } interface QueryData extends QueryDataAliases, PickQueryDataParsers, HasHookSelect, MutativeQueriesSelectRelationsQueryData { type: QueryType; adapter: Adapter; shape: ColumnsShape; handleResult: HandleResult; catch?: boolean; returnType: QueryReturnType; returning?: boolean; returningMany?: boolean; wrapInTransaction?: boolean; throwOnNotFound?: boolean; ensureCount?: number; with?: WithItems; withShapes?: WithConfigs; joinTo?: QueryDataJoinTo; joinedShapes?: JoinedShapes; joinedParsers?: JoinedParsers; joinedBatchParsers?: { [K: string]: BatchParsers; }; joinedComputeds?: { [K: string]: ComputedColumns | undefined; }; joined?: { [K: string]: Query; }; joinedForSelect?: string; innerJoinLateral?: true; valuesJoinedAs?: RecordString; schema?: QuerySchema; select?: SelectItem[]; selectCache?: { sql: string; aliases: string[]; }; selectAllColumns?: string[]; /** * Subset of the `shape` that only includes columns with no `data.explicitSelect`. */ selectAllShape: RecordUnknown; /** * column type for query with 'value' or 'valueOrThrow' return type * Is needed in {@link getShapeFromSelect} to get shape of sub-select that returns a single value. */ getColumn?: Column.Pick.QueryColumn; expr?: Expression; from?: MaybeArray; updateFrom?: JoinItemArgs; sources?: QueryDataSources; and?: WhereItem[]; or?: WhereItem[][]; order?: OrderItem[]; returnsOne?: true; useFromLimitOffset?: true; coalesceValue?: unknown | Expression; notFoundDefault?: unknown; defaults?: RecordUnknown; runtimeComputeds?: ComputedColumns; selectedComputeds?: ComputedColumns; beforeSet?: Set; dynamicBefore?: HasBeforeAndBeforeSet[]; before?: QueryBeforeHook[]; after?: QueryAfterHook[]; beforeCreate?: QueryBeforeHook[]; afterCreate?: QueryAfterHook[]; afterCreateCommit?: QueryAfterHook[]; afterCreateSelect?: Set; beforeUpdate?: QueryBeforeHook[]; afterUpdate?: QueryAfterHook[]; afterUpdateCommit?: QueryAfterHook[]; afterUpdateSelect?: Set; afterSave?: QueryAfterHook[]; afterSaveCommit?: QueryAfterHook[]; beforeDelete?: QueryBeforeHook[]; afterDelete?: QueryAfterHook[]; afterDeleteCommit?: QueryAfterHook[]; afterDeleteSelect?: Set; catchAfterCommitErrors?: AfterCommitErrorHandler[]; log?: QueryLogObject; logger: QueryLogger; autoPreparedStatements?: boolean; transform?: QueryDataTransform[]; language?: string; subQuery?: number; chainMultiple?: boolean; relChain?: { query: Query; rel: RelationConfigBase; }[]; /** * Stores current operator functions available for the query. * Is needed to remove these operators from query object when changing the query type, see {@link setQueryOperators}. */ operators?: RecordUnknown; scopes?: { [K: string]: QueryScopeData; }; all?: true; chain?: ExpressionChain; outerQuery?: Query; hookCreateSet?: RecordUnknown[]; hookUpdateSet?: RecordUnknown[]; appendQueries?: SubQueryForSql[]; asFns?: AsFn[]; /** select and upsert **/ distinct?: SelectableOrExpression[]; only?: boolean; join?: JoinItem[]; joinValueDedup?: Map; group?: (string | Expression)[]; having?: HavingItem[]; window?: WindowItem[]; union?: QueryDataUnion; limit?: number; offset?: number; for?: { type: 'UPDATE' | 'NO KEY UPDATE' | 'SHARE' | 'KEY SHARE'; tableNames?: string[] | Expression; mode?: 'NO WAIT' | 'SKIP LOCKED'; }; /** upsert **/ upsertUpdate?: boolean; upsertSecond?: boolean; upsertInsert?(): unknown; /** insert **/ columns: string[]; insertFrom?: SubQueryForSql; insertValuesAs?: string; queryColumnsCount?: number; values: unknown[][]; onConflict?: { target?: OnConflictTarget; set?: OnConflictSet; merge?: OnConflictMerge; }; /** update **/ updateData?: UpdateQueryDataItem[]; updateMany?: UpdateManyQueryData; } interface UpdateManyQueryData { primaryKeys: string[]; setColumns: string[]; data: RecordUnknown[]; strict?: boolean; } interface UpdateQueryDataObject { [K: string]: Expression | { op: string; arg: unknown; } | unknown; } interface UpdatedAtDataInjector { (data: UpdateQueryDataItem[]): UpdateQueryDataObject | void; } type UpdateQueryDataItem = UpdateQueryDataObject | UpdatedAtDataInjector; /** * Push a new element into an array in the query data - immutable version * * @param q - query * @param key - key to get the array * @param value - new element to push */ declare const pushQueryValueImmutable: (q: T, key: string, value: unknown) => T; declare const getClonedQueryData: (query: QueryData) => QueryData; interface ToSqlOptionsInternal { hasNonSelect?: boolean; aliasValue?: true; skipBatchCheck?: true; selectedCount?: number; selectList?: string[]; } interface ToSqlValues { values: unknown[]; } interface TopToSqlCtx extends ToSqlOptionsInternal, HasCteHooks, ToSqlValues { topCtx: TopToSqlCtx; topCTE?: TopCTE; tableHook?: TableHook; mutativeQueriesSelectRelationsSqlState?: MutativeQueriesSelectRelationsSqlState; cteHookTopNullSelectAppended?: boolean; } interface ToSQLCtx extends ToSqlOptionsInternal, ToSqlValues { topCtx: TopToSqlCtx; qb: QueryBuilder; q: QueryData; sql: string[]; selectedCount: number; cteName?: string; wrapAs?: string; } interface ToSQLQuery extends IsQuery { __isQuery: Query['__isQuery']; q: Query['q']; qb: Query['qb']; table?: Query['table']; internal: QueryInternal; relations: Query['relations']; withData: Query['withData']; clone: Query['clone']; baseQuery: Query['baseQuery']; returnType: Query['returnType']; result: Query['result']; shape: Query['shape']; } interface FromQuerySelf extends PickQuerySelectable, PickQueryShape, PickQueryReturnType, PickQueryWithData, PickQueryAs, PickQueryHasSelect {} type FromArg = IsQuery | Exclude; type FromResult>> = Arg extends string ? T['withData'] extends WithDataItems ? { [K in keyof T]: K extends '__selectable' ? SelectableFromShape : K extends 'result' ? T['withData'][Arg]['shape'] : K extends 'then' ? QueryThenByQuery : T[K] } : SetQueryTableAlias : Arg extends PickQuerySelectableResultInputTypeAs ? { [K in keyof T]: K extends '__defaultSelect' ? keyof Arg['result'] : K extends '__selectable' ? SelectableFromShape : K extends '__as' ? Arg['__as'] : K extends 'result' ? Arg['result'] : K extends 'shape' ? Arg['result'] : K extends 'inputType' ? Arg['inputType'] : K extends 'then' ? QueryThenByQuery : T[K] } : Arg extends (infer A)[] ? { [K in keyof T]: K extends '__selectable' ? UnionToIntersection : T[K] } : T; declare class FromMethods { /** * Set the `FROM` value, by default the table name is used. * * `from` determines a set of available tables and columns withing the query, * and thus it must not follow `select`, use `select` only after `from`. * * ```ts * // accepts sub-query: * db.table.from(db.otherTable.select('foo', 'bar')); * * // accepts alias of `WITH` expression: * q.with('withTable', db.table.select('id', 'name')) * .from('withTable') * // `select` is after `from` * .select('id', 'name'); * ``` * * `from` can accept multiple sources: * * ```ts * db.table * // add a `WITH` statement called `withTable * .with('withTable', db.table.select('one')) * // select from `withTable` and from `otherTable` * .from('withTable', db.otherTable.select('two')) * // source names and column names are properly typed when selecting * .select('withTable.one', 'otherTable.two'); * ``` * * @param arg - query or name of CTE table */ from>>(this: T, arg: T['__hasSelect'] extends true ? '`select` must be placed after `from`' : Arg): FromResult; /** * Set the `FROM` value with custom SQL: * * ```ts * const value = 123; * db.table.fromSql`value = ${value}`; * ``` * * @param args - SQL expression */ fromSql(this: T, ...args: SQLQueryArgs): T; /** * Adds `ONLY` SQL keyword to the `FROM`. * When selecting from a parent table that has a table inheritance, * setting `only` will make it to select rows only from the parent table. * * ```ts * db.table.only(); * * // disabling `only` after being enabled * db.table.only().only(false); * ``` * * @param only - can be disabled by passing `false` if was enabled previously. */ only(this: T, only?: boolean): T; } interface CteArgsOptions { columns?: string[] | boolean; materialized?: true; notMaterialized?: true; } interface CteRecursiveOptions extends CteArgsOptions { union?: 'UNION' | 'UNION ALL' | 'INTERSECT' | 'INTERSECT ALL' | 'EXCEPT' | 'EXCEPT ALL'; } interface CteQueryBuilder extends Query { sql: QuerySql['sql']; relations: EmptyObject; withData: T['withData']; } type CteResult = { [K in keyof T]: K extends 'withData' ? { [K in keyof T['withData'] | Name]: K extends Name ? { table: Name; shape: Q['result']; } : K extends keyof T['withData'] ? T['withData'][K] : never } : T[K] }; type CteSqlResult = { [K in keyof T]: K extends 'withData' ? { [K in Name | keyof T['withData']]: K extends Name ? { table: Name; shape: Shape; } : K extends keyof T['withData'] ? T['withData'][K] : never } : T[K] }; declare const _prependWith: (q: Query, name: string | ((as: string) => void), queryArg: PickQueryResult | ((q: CteQueryBuilder) => PickQueryResult)) => Query; declare class CteQuery { /** * Use `with` to add a Common Table Expression (CTE) to the query. * * `with` can be chained to any table on `db` instance, or to `db.$qb`, * note that in the latter case it won't have customized column types to use for typing SQL. * * ```ts * import { sql } from './baseTable'; * * // can access custom columns when using off a table * db.anyTable.with('x', (q) => * q.select({ column: (q) => sql`123`.type((t) => t.customColumn()) }), * ); * * // only default columns are available when using off `$qb` * db.$qb.with('x', (q) => * q.select({ column: (q) => sql`123`.type((t) => t.integer()) }), * ); * ``` * * `with` accepts query objects, callbacks returning query objects, and custom SQL expressions returned from callbacks. * * ```ts * import { sql } from './baseTable'; * * db.table * .with( * 'alias', * // define CTE by building a query * db.table.select('one', 'two', 'three').where({ x: 123 }), * ) * .from('alias') * .select('one') * .where({ two: 123 }); * * // 2nd argument can be a callback accepting a query builder * db.table * .with('alias', (q) => * // select a custom sql * q.select({ column: (q) => sql`123`.type((t) => t.integer()) }), * ) * .from('alias') * .select('column') * .where({ column: 123 }); * * // 2nd argument can be used for options * db.table * .with( * 'alias', * { * // all parameters are optional * materialized: true, * notMaterialized: true, * }, * db.table, * ) * .from('alias'); * ``` * * One `WITH` expression can reference the other: * * ```ts * db.$qb * .with('a', db.table.select('id', 'name')) * .with('b', (q) => q.from('a').where({ key: 'value' })) * .from('b'); * ``` * * Defined `WITH` expression can be used in `.from` or `.join` with all the type safeness: * * ```ts * db.table.with('alias', db.table).from('alias').select('alias.id'); * * db.firstTable * .with('secondTable', db.secondTable) * .join('secondTable', 'secondTable.someId', 'firstTable.id') * .select('firstTable.column', 'secondTable.column'); * ``` * * ## creating records using `with` values * * You can use values returned from `with` statements when creating records: * * ```ts * db.table * .with('created', () => db.someTable.create(data).select('one', 'two')) * .create({ * column: (q) => q.from('created').get('one'), * otherColumn: (q) => q.from('created').get('two'), * }); * * // A record in `with` is created once, its values are used to create two records * db.table * .with('created', () => db.someTable.create(data).select('one', 'two')) * .createMany([ * { * column: (q) => q.from('created').get('one'), * otherColumn: (q) => q.from('created').get('two'), * }, * { * column: (q) => q.from('created').get('one'), * otherColumn: (q) => q.from('created').get('two'), * }, * ]); * ``` */ with(this: T, name: Name, query: Q | ((q: CteQueryBuilder) => Q)): CteResult; with(this: T, name: Name, options: CteArgsOptions, query: Q | ((q: CteQueryBuilder) => Q)): CteResult; /** * It is priceless for fetching tree-like structures, or any other recursive cases. * * For example, it is useful for loading a tree of categories, where one category can include many other categories. * * Similarly to [with](#with), `withRecursive` can be chained to any table or `db.$qb`. * * For the first example, consider the employee table, an employee may or may not have a manager. * * ```ts * class Employee extends BaseTable { * readonly table = 'employee'; * columns = this.setColumns((t) => ({ * id: t.identity().primaryKey(), * name: t.string(), * managerId: t.integer().nullable(), * })); * } * ``` * * The task is to load all subordinates of the manager with the id 1. * * ```ts * db.$qb * .withRecursive( * 'subordinates', * // the base, anchor query: find the manager to begin recursion with * db.employee.select('id', 'name', 'managerId').find(1), * // recursive query: * // find employees whos managerId is id from the surrounding subordinates CTE * (q) => * q * .from(db.employee) * .select('id', 'name', 'managerId') * .join('subordinates', 'subordinates.id', 'profile.managerId'), * ) * .from('subordinates'); * ``` * * As being shown, `withRecursive` accepts one query to begin with, and a second query in a callback that can reference the surrounding table expression "subordinates". * * These two queries are joined with `UNION ALL` by default. * * You can customize it by passing options after the name. * * ```ts * db.$qb * .withRecursive( * 'subordinates', * { * // all parameters are optional * union: 'UNION', * materialized: true, * notMaterialized: true, * }, * // ...snip * ) * .from('subordinates'); * ``` * * Recursive query can be constructed with basic SQL instructions only, without referencing other tables. * In the following example, we recursively select numbers from 1 to 100, and additionally apply n > 10 filter in the end. * * ```ts * import { sql } from './baseTable'; * * db.$qb * .withRecursive( * 't', * // select `1 AS n` for the base query * (q) => q.select({ n: (q) => sql`1`.type((t) => t.integer()) }), * // select `n + 1 AS n` for the recursive part * (q) => * q * .from('t') * // type can be omitted here because it was defined in the base query * .select({ n: (q) => sql`n + 1` }) * .where({ n: { lt: 100 } }), * ) * .from('t') * .where({ n: { gt: 10 } }); * ``` */ withRecursive>(this: T, name: Name, base: Q | ((qb: CteQueryBuilder) => Q), recursive: (qb: { [K in keyof Result]: K extends 'result' ? Q['result'] : Result[K] }) => PickQueryResult): Result; withRecursive>(this: T, name: Name, options: CteRecursiveOptions, base: Q | ((qb: CteQueryBuilder) => Q), recursive: (qb: { [K in keyof Result]: K extends 'result' ? Q['result'] : Result[K] }) => PickQueryResult): Result; /** * Use `withSql` to add a Common Table Expression (CTE) based on a custom SQL. * * Similarly to [with](#with), `withRecursive` can be chained to any table or `db.$qb`. * * ```ts * import { sql } from './baseTable'; * * db.table * .withSql( * 'alias', * // define column types of the expression: * (t) => ({ * one: t.integer(), * two: t.string(), * }), * // define SQL expression: * (q) => sql`(VALUES (1, 'two')) t(one, two)`, * ) * // is not prefixed in the middle of a query chain * .withSql( * 'second', * (t) => ({ * x: t.integer(), * }), * (q) => sql`(VALUES (1)) t(x)`, * ) * .from('alias'); * ``` * * Options can be passed via a second argument: * * ```ts * import { sql } from './baseTable'; * * db.table * .withSql( * 'alias', * { * // all parameters are optional * recursive: true, * materialized: true, * notMaterialized: true, * }, * (t) => ({ * one: t.integer(), * two: t.string(), * }), * (q) => sql`(VALUES (1, 'two')) t(one, two)`, * ) * .from('alias'); * ``` */ withSql(this: T, name: Name, options: CteOptions, shape: (t: T['columnTypes']) => Shape, expr: (q: T) => Expression): CteSqlResult; withSql(this: T, name: Name, shape: (t: T['columnTypes']) => Shape, expr: (q: T) => Expression): CteSqlResult; } type UnionArgs = ({ result: { [K in keyof T['result']]: { queryType: T['result'][K]['queryType']; } }; } | ((q: T) => Expression))[]; declare class Union { /** * Creates a union query, takes one or more queries or SQL expressions. * * ```ts * import { sql } from './baseTable'; * * // The first query of the union * db.one * .select('id', 'name') * // add two more queries to the union * .union( * db.two.select('id', 'name'), * (q = sql`SELECT id, name FROM "thirdTable"`), * ) * // sub-sequent `union` is equivalent to passing multiple queries into a single `union` * .union(db.three.select('id', 'name')); * ``` * * `order`, `limit`, `offset` are special, it matters if you place them **before** or **after** the `union`, it also have a meaning to place them before and after. * * ```ts * // order, limit, offset are applied ONLY to 'one' * db.one * .order('x') * .limit(1) * .offset(1) * // 'two' also has order, limit, and offset * .unionAll(db.two.order('y').limit(2).offset(2)) * // sets order, limit, offset for all records * .order('z') * .limit(3) * .offset(3); * ``` * * Equivalent SQL: * * ```sql * -- both union parts have their own order, limit, offset * ( SELECT * FROM one ORDER x ASC LIMIT 1 OFFSET 1 ) * UNION ALL * ( SELECT * FROM two ORDER y ASC LIMIT 2 OFFSET 2 ) * -- order, limit, offset of the whole query * ORDER BY z ASC LIMIT 3 OFFSET 3 * ``` * * All the listed methods have the same signature, they are only different by SQL keyword: * * - `union` - union of all queries, performs deduplication * - `unionAll` - `union` that allows duplicated rows * - `intersect` - get only rows that are present in all queries * - `intersectAll` - `intersect` that allows duplicated rows * - `except` - get only rows that are in the first query but not in the second * - `exceptAll` - `except` that allows duplicated rows * * @param args - array of queries or SQL expressions */ union(this: T, ...args: UnionArgs): T; /** * Same as {@link union}, but allows duplicated rows. * * @param args - array of queries or SQL expressions */ unionAll(this: T, ...args: UnionArgs): T; /** * Same as {@link union}, but uses a `INTERSECT` SQL keyword instead * * @param args - array of queries or SQL expressions */ intersect(this: T, ...args: UnionArgs): T; /** * Same as {@link intersect}, but allows duplicated rows. * * @param args - array of queries or SQL expressions */ intersectAll(this: T, ...args: UnionArgs): T; /** * Same as {@link union}, but uses an `EXCEPT` SQL keyword instead * * @param args - array of queries or SQL expressions */ except(this: T, ...args: UnionArgs): T; /** * Same as {@link except}, but allows duplicated rows. * * @param args - array of queries or SQL expressions */ exceptAll(this: T, ...args: UnionArgs): T; } declare abstract class QueryJsonMethods { /** * Wraps the query in a way to select a single JSON string. * So that JSON encoding is done on a database side, and the application doesn't have to turn a response to a JSON. * It may be better for performance in some cases. * * ```ts * // json is a JSON string that you can directly send as a response. * const json = await db.table.select('id', 'name').json(); * ``` * * @param coalesce */ json(this: T, coalesce?: boolean): SetQueryReturnsColumnOptional>; } type ForQueryBuilder = Q & { noWait(this: T): T; skipLocked(this: T): T; }; declare class For { forUpdate(this: T, tableNames?: string[] | Expression): ForQueryBuilder; forNoKeyUpdate(this: T, tableNames?: string[] | Expression): ForQueryBuilder; forShare(this: T, tableNames?: string[] | Expression): ForQueryBuilder; forKeyShare(this: T, tableNames?: string[] | Expression): ForQueryBuilder; } type ClearStatement = 'with' | 'select' | 'where' | 'union' | 'using' | 'join' | 'group' | 'order' | 'having' | 'limit' | 'offset' | 'counters'; declare class Clear { clear(this: T, ...clears: ClearStatement[]): T; } type HavingArgFn = (q: T) => { result: { value: { outputType: boolean; }; }; }; declare class Having { /** * Build a `HAVING` clause to the query to filter records by results of [aggregate functions](#aggregate-functions). * * The argument of `having` is a function where you call the aggregate function and compare it with some value by using [column operators](/guide/where.html#column-operators). * * ```ts * db.table.having((q) => q.count().gte(10)); * // HAVING count(*) >= 10 * ``` * * Multiple having conditions will be combined with `AND`: * * ```ts * db.table.having( * (q) => q.sum('column').gt(5), * (q) => q.avg('column').lt(10), * ); * // HAVING sum(column) > 5 AND avg(column) < 10 * ``` * * After applying a comparison, `or` and `and` methods become available: * * ```ts * db.table.having((q) => * q.sum('column').equals(5).or(q.min('column').gt(1), q.max('column').lt(10)), * ); * // HAVING (sum(column) = 5) OR (min(column) > 1 AND max(column) < 10) * ``` * * Aggregate functions are exactly the same functions described in [aggregate functions](#aggregate-functions), they can accept aggregation options: * * ```ts * db.table.having((q) => * q * .count('id', { * distinct: true, * order: { createdAt: 'DESC', filter: { someColumn: { not: null } } }, * }) * .gte(10), * ); * ``` * * Arguments of the aggregate function and of the comparison can be raw SQL: * * ```ts * import { sql } from './baseTable'; * * db.table.having((q) => q.count(sql('coalesce(one, two)')).gte(sql`2 + 2`)); * ``` * * @param args - raw SQL template string or one or multiple callbacks returning a boolean expression */ having(this: T, ...args: HavingArgFn[]): T; /** * Provide SQL expression for the `HAVING` SQL statement: * * ```ts * db.table.havingSql`count(*) >= ${10}`; * ``` * * @param args - SQL expression */ havingSql(this: T, ...args: SQLQueryArgs): T; } type UpsertCreate = { [K in keyof CD as K extends DataKey ? never : K]: CD[K] } & { [K in DataKey]?: K extends keyof CD ? CD[K] : never }; type UpsertResult = T['__hasSelect'] extends true ? T['returnType'] extends 'value' | 'valueOrThrow' ? SetValueQueryReturnsValueOrThrow : SetQueryReturnsOne : SetQueryReturnsVoid; interface UpsertThis extends UpdateSelf, CreateSelf { __hasWhere: true; returnType: 'one' | 'oneOrThrow' | 'value' | 'valueOrThrow' | 'void'; } type UpsertData> = { update: Update; create: CreateData | ((update: Update) => CreateData); } | { data: Update; create: UpsertCreate> | ((update: Update) => UpsertCreate>); }; declare const _queryUpsert: (q: Query, data: UpsertData>) => Query; declare class QueryUpsert { /** * `upsert` tries to update a single record, and then it creates the record if it doesn't yet exist. * * `find` or `findBy` must precede `upsert` because it does not work with multiple updates. * * In case more than one row was updated, it will throw `MoreThanOneRowError` and the transaction will be rolled back. * * It can take `update` and `create` objects, then they are used separately for update and create queries. * Or, it can take `data` and `create` objects, `data` will be used for update and be mixed to `create` object. * * `data` and `update` objects are of the same type that's expected by `update` method, `create` object is of type of `create` method argument. * * No values are returned by default, place `select` or `selectAll` before `upsert` to specify returning columns. * * ```ts * await db.user * .selectAll() * .findBy({ email: 'some@email.com' }) * .upsert({ * data: { * // update record's name * name: 'new name', * // supports sql and nested queries * fromSQL: () => sql`*SQL expression*`, * fromQuery: () => db.someTable.create(data).get('column'), * }, * create: { * // create a new record with this email and a name 'new name' * email: 'some@email.com', * // supports sql and nested queries as well * }, * create: { * // create a new record with this email and a name 'new name' * email: 'some@email.com', * }, * }); * * // the same as above but using `update` and `create` * await db.user * .selectAll() * .findBy({ email: 'some@email.com' }) * .upsert({ * update: { * name: 'updated user', * }, * create: { * email: 'some@email.com', * // here we use a different name when creating a record * name: 'created user', * }, * }); * ``` * * The data for `create` may be returned from a function, it won't be called if a record was updated: * * ```ts * await db.user * .selectAll() * .findBy({ email: 'some@email.com' }) * .upsert({ * update: { * name: 'updated user', * }, * create: () => ({ * email: 'some@email.com', * name: 'created user', * }), * }); * * // the same as above using `data` * await db.user * .selectAll() * .findBy({ email: 'some@email.com' }) * .upsert({ * data: { * name: 'updated user', * }, * create: () => ({ * email: 'some@email.com', * // name in `create` is overriding the name from `data` * name: 'created user', * }), * }); * ``` * * Data from `data` or `update` is passed to the `create` function and can be used: * * ```ts * const user = await db.user * .selectAll() * .findBy({ email: 'some@email.com' }) * .upsert({ * data: { * name: 'updated user', * }, * // `updateData` has the exact type of what is passed to `data` * create: (updateData) => ({ * email: `${updateData.name}@email.com`, * }), * }); * ``` * * `upsert` works in the exact same way as [orCreate](#orCreate), but with `UPDATE` statement instead of `SELECT`. * it also performs a single query if the record exists, and two queries if there is no record yet. * * @param data - `update` property for the data to update, `create` property for the data to create */ upsert>(this: T, data: UpsertData): UpsertResult; } declare class QueryGet { /** * `.get` returns a single value, adds `LIMIT 1` to the query, and accepts a column name or a raw SQL expression. * * `get` throws a `NotFoundError` when not found, and `getOptional` returns `undefined`. * * ```ts * import { NumberColumn } from 'orchid-orm'; * import { sql } from './baseTable'; * * const firstName: string = await db.table.get('name'); * * const rawResult: number = await db.table.get(sql((t) => t.integer())`1 + 1`); * * const firstNameOptional: string | undefined = await db.table.getOptional( * 'name', * ); * ``` * * @param arg - string for a column to get, or a raw SQL */ get>(this: T, arg: Arg): GetResult; /** * `.getOptional` returns a single value or undefined when not found: * * ```ts * const firstName: string | undefined = await db.table.getOptional('name'); * ``` * * @param arg - string for a column to get, or a raw SQL */ getOptional>(this: T, arg: Arg): GetResultOptional; } interface MergeQueryArg extends PickQueryTable, PickQuerySelectable, PickQueryResult, PickQueryReturnType, PickQueryWithData, PickQueryWindows, PickQueryThen, PickQueryHasSelect, PickQueryHasWhere {} type MergeQuery = { [K in keyof T]: K extends '__hasWhere' | '__hasSelect' ? T[K] & Q[K] : K extends '__selectable' | 'windows' | 'withData' ? Q[K] & Omit : K extends 'result' ? MergeQueryResult : K extends 'returnType' ? Q['returnType'] extends undefined ? T['returnType'] : Q['returnType'] : K extends 'then' ? Q['returnType'] extends undefined ? QueryThenByQuery> : Q['returnType'] extends 'all' | 'one' | 'oneOrThrow' | 'rows' ? QueryThenByQuery> : Q['__hasSelect'] extends true ? Q['then'] : T['__hasSelect'] extends true ? T['then'] : Q['then'] : T[K] }; type MergeQueryResult = T['__hasSelect'] extends true ? Q['__hasSelect'] extends true ? Omit & Q['result'] : T['result'] : Q['result']; declare class MergeQueryMethods { merge(this: T, q: Q): MergeQuery; } declare class QueryMap { /** * Use `map` to transform individual records of a query result. * * Use `map` to transform individual records of a query result. If the query returns multiple, `map` function going to transform records one by one. * * For an optional query result (`findOptional`, `getOptional`, etc.), `map` is **not** called for empty results. * * For transforming the result of a query as a whole, consider using {@link Query.transform} instead. * * ```ts * // add a `titleLength` to every post * const posts = await db.post.limit(10).map((post, i) => ({ * ...post, * titleLength: post.title.length, * })); * * posts[0].titleLength; // number * * // using the exact same `map` function to transform a single post * const singlePost = await db.post.find(id).map((post, i) => ({ * ...post, * titleLength: post.title.length, * })); * * singlePost.titleLength; // number * * // can be used in sub-queries * const postsWithComments = await db.post.select('title', { * comments: (q) => * q.comments.map((comment, i) => ({ * ...comment, * truncatedContent: comment.content.slice(0, 100), * })), * }); * * postsWithComments[0].comments[0].truncatedContent; // string * ``` * * @param fn - function to transform an individual record * @param thisArg - same as in the native array map */ map(this: T, fn: T extends { returnType: 'valueOrThrow'; then: QueryThen<(infer Data) | null>; } ? (input: Data, index: number, value: Data) => Result : T['returnType'] extends QueryReturnTypeAll | 'pluck' ? T extends { then: QueryThen<(infer Data)[]>; } ? (input: Data, index: number, arr: Data[]) => Result : never : T extends { then: QueryThen<(infer Data) | undefined>; } ? (input: Data, index: number, value: Data) => Result : never, thisArg?: unknown): Result extends RecordUnknown ? { [K in keyof T]: K extends 'result' ? { [K in keyof Result]: Column.Pick.QueryColumnOfType } : K extends 'then' ? QueryThen : T[K] } : { [K in keyof T]: K extends 'returnType' ? T['returnType'] extends QueryReturnTypeAll | 'pluck' ? 'pluck' : T['returnType'] extends 'one' ? 'value' : 'valueOrThrow' : K extends 'result' ? T['returnType'] extends QueryReturnTypeAll | 'pluck' ? { pluck: Column.Pick.QueryColumnOfType; } : T['returnType'] extends QueryReturnTypeOptional ? { value: Column.Pick.QueryColumnOfType; } : { value: Column.Pick.QueryColumnOfType; } ? Result | null : Result>; } : K extends 'then' ? QueryThen; } ? Result | null : Result> : T[K] }; } type OrCreateArg = Data | (() => Data); declare function _orCreate(query: T, data: unknown | FnUnknownToUnknown, updateData?: unknown, mergeData?: unknown): UpsertResult; declare class QueryOrCreate { /** * `orCreate` creates a record only if it was not found by conditions. * * `find` or `findBy` must precede `orCreate`. * * It is accepting the same argument as `create` commands. * * No result is returned by default, place `get`, `select`, or `selectAll` before `orCreate` to specify returning columns. * * ```ts * const user = await db.user * .selectAll() * .findBy({ email: 'some@email.com' }) * .orCreate({ * email: 'some@email.com', * name: 'created user', * // supports sql and nested queries * fromSQL: () => sql`*SQL expression*`, * fromQuery: () => db.someTable.create(data).get('column'), * fromRelated: (q) => q.relatedTable.update(data).get('column'), * }); * ``` * * The data can be returned from a function, it won't be called if the record was found: * * ```ts * const user = await db.user * .selectAll() * .findBy({ email: 'some@email.com' }) * .orCreate(() => ({ * email: 'some@email.com', * name: 'created user', * })); * ``` * * `orCreate` works by performing just a single query in the case if the record exists, and one additional query when the record does not exist. * * At first, it performs a "find" query, the query cost is exact same as if you didn't use `orCreate`. * * Then, if the record wasn't found, it performs a single query with CTE expressions to try finding it again, for the case it was already created just a moment before, * and then it creates the record if it's still not found. Using such CTE allows to skip using transactions, while still conforming to atomicity. * * ```sql * -- first query * SELECT * FROM "table" WHERE "key" = 'value' * * -- the record could have been created in between these two queries * * -- second query * WITH find_row AS ( * SELECT * FROM "table" WHERE "key" = 'value' * ) * WITH insert_row AS ( * INSERT INTO "table" ("key") * SELECT 'value' * -- skip the insert if the row already exists * WHERE NOT EXISTS (SELECT 1 FROM find_row) * RETURNING * * ) * SELECT * FROM find_row * UNION ALL * SELECT * FROM insert_row * ``` * * @param data - the same data as for `create`, it may be returned from a callback */ orCreate(this: T, data: OrCreateArg>): UpsertResult; } /** * Call `.clone()` on a supposed query object */ declare const _clone: (q: unknown) => Query; declare class QueryClone { /** * Clones the current query chain, useful for re-using partial query snippets in other queries without mutating the original. * * Used under the hood, and not really needed on the app side. */ clone(this: T): T; } type WrapQueryArg = FromQuerySelf; /** * This function is useful when wrapping a query, * such as when doing `SELECT json_agg(t.*) FROM (...) AS t`, * to get rid of default scope conditions (WHERE deletedAt IS NULL) * that otherwise would be duplicated inside the `FROM` and after `AS t`. */ declare function cloneQueryBaseUnscoped(query: Query): Query; declare class QueryWrap { wrap(this: T, query: Q, as?: As): SetQueryTableAlias; } declare class QueryDistinct { /** * Adds a `DISTINCT` keyword to `SELECT`: * * ```ts * db.table.distinct().select('name'); * ``` * * Can accept column names or raw SQL expressions to place it to `DISTINCT ON (...)`: * * ```ts * import { sql } from './baseTable'; * * // Distinct on the name and raw SQL * db.table.distinct('name', sql`raw sql`).select('id', 'name'); * ``` * * @param columns - column names or a raw SQL */ distinct(this: T, ...columns: SelectableOrExpressions): T; } interface SubQueryReturningSingle extends IsSubQuery { returnType: 'one' | 'oneOrThrow'; } declare class QueryLimitOffset { /** * Adds a limit clause to the query. * * ```ts * db.table.limit(10); * ``` * * @param arg - limit number */ limit(this: T, arg: T extends SubQueryReturningSingle ? 'Cannot apply limit on the query returning a single record' : number | undefined): T; /** * Adds an offset clause to the query. * * ```ts * db.table.offset(10); * ``` * * @param arg - offset number */ offset(this: T, arg: number | undefined): T; } declare class QueryTruncate { /** * Truncates the specified table. * * ```ts * // simply truncate * await db.table.truncate(); * * // restart autoincrementing columns: * await db.table.truncate({ restartIdentity: true }); * * // truncate also dependant tables: * await db.table.truncate({ cascade: true }); * ``` * * @param options - truncate options, may have `cascade: true` and `restartIdentity: true` */ truncate(this: T, options?: { restartIdentity?: boolean; cascade?: boolean; }): SetQueryReturnsVoid; } type GroupArgs = ({ [K in keyof T['result']]: T['result'][K]['dataType'] extends 'array' | 'object' | 'runtimeComputed' ? never : K }[keyof T['result']] | Expression)[]; interface QueryHelperQuery extends MergeQueryArg { returnType: QueryReturnType; __selectable: Omit}`>; result: Column.QueryColumns; windows: EmptyObject; withData: WithDataItems; then: unknown; } interface IsQueryHelper { isQueryHelper: true; table: string | undefined; args: unknown[]; result: unknown; } interface IsQueryHelperForTable
extends IsQueryHelper { table: Table; } interface QueryHelper extends IsQueryHelper { >(q: Q, ...args: Args): Result extends MergeQueryArg ? MergeQuery : Result; __as: T['__as']; table: T['table']; args: Args; result: Result; } type QueryHelperResult> = T['result']; interface NarrowTypeSelf extends PickQueryResultReturnType { returnType: undefined | 'all' | 'one' | 'oneOrThrow' | 'value' | 'valueOrThrow' | 'pluck'; } type NarrowInvalidKeys = { [K in keyof Narrow]: K extends keyof T['result'] ? Narrow[K] extends T['result'][K]['outputType'] ? never : K : K }[keyof Narrow]; interface NarrowValueTypeResult extends Column.QueryColumns { value: { [K in keyof T['result']['value']]: K extends 'outputType' ? Narrow : T['result']['value'][K] }; } interface NarrowPluckTypeResult extends Column.QueryColumns { pluck: { [K in keyof T['result']['pluck']]: K extends 'outputType' ? Narrow extends unknown[] ? Narrow[number] : Narrow : T['result']['pluck'][K] }; } type QueryIfResult = { [K in keyof T]: K extends 'result' ? { [K in keyof T['result'] | keyof R['result']]: K extends keyof T['result'] ? K extends keyof R['result'] ? R['result'][K] | T['result'][K] : T['result'][K] : Column.Modifiers.QueryColumnToOptional } : K extends 'then' ? QueryIfResultThen : T[K] }; type QueryIfResultThen = T['returnType'] extends undefined | 'all' ? QueryThenShallowSimplifyArr<{ [K in keyof T['result']]: K extends keyof R['result'] ? T['result'][K]['outputType'] | R['result'][K]['outputType'] : T['result'][K]['outputType'] } & { [K in keyof R['result'] as K extends keyof T['result'] ? never : K]?: R['result'][K]['outputType'] }> : T['returnType'] extends 'one' ? QueryThenShallowSimplifyOptional<{ [K in keyof T['result']]: K extends keyof R['result'] ? T['result'][K]['outputType'] | R['result'][K]['outputType'] : T['result'][K]['outputType'] } & { [K in keyof R['result'] as K extends keyof T['result'] ? never : K]?: R['result'][K]['outputType'] }> : T['returnType'] extends 'oneOrThrow' ? QueryThenShallowSimplify<{ [K in keyof T['result']]: K extends keyof R['result'] ? T['result'][K]['outputType'] | R['result'][K]['outputType'] : T['result'][K]['outputType'] } & { [K in keyof R['result'] as K extends keyof T['result'] ? never : K]?: R['result'][K]['outputType'] }> : T['returnType'] extends 'value' ? QueryThen : T['returnType'] extends 'valueOrThrow' ? QueryThen : T['returnType'] extends 'rows' ? QueryThen<(T['result'][keyof T['result']]['outputType'] | R['result'][keyof R['result']]['outputType'])[][]> : T['returnType'] extends 'pluck' ? QueryThen<(T['result']['pluck']['outputType'] | R['result']['pluck']['outputType'])[]> : QueryThen; interface QueryMethods extends QueryClone, QueryAsMethods, AggregateMethods, QueryDistinct, Select, FromMethods, QueryJoin, QueryLimitOffset, CteQuery, Union, QueryJsonMethods, QueryCreate, QueryCreateFrom, QueryUpdate, QueryDelete, QueryStorage, QueryTransaction, QueryTruncate, For, Where, SearchMethods, Clear, Having, QueryCatchers, QueryLog, QueryOrder, QueryWithSchema, QueryHooks, QueryUpsert, QueryOrCreate, QueryGet, MergeQueryMethods, QuerySql, QueryTransform, QueryMap, QueryScope, SoftDeleteMethods, QueryExpressions, QueryWrap, QueryWindow {} declare class QueryMethods { /** * `.all` is a default behavior, that returns an array of objects: * * ```ts * const records = db.table * .take() // .take() will be overridden by .all() * .all(); * ``` */ all(this: T): SetQueryReturnsAll; /** * Use `take` to "take" a single record. It adds `LIMIT 1`, throws a `NotFoundError` when not found. * * ```ts * const taken: TableType = await db.table.where({ key: 'value' }).take(); * ``` * * Makes no effect if the query previously has `get`, `pluck`, `exec`. * * Changes `getOptional` to `get`. */ take(this: T): QueryTake; /** * Use `takeOptional` to "take" a single record. It adds `LIMIT 1`, returns `undefined` when not found. * * ```ts * const takenOptional: TableType | undefined = await db.table * .where({ key: 'value' }) * .takeOptional(); * ``` * * Makes no effect if the query previously has `getOptional`, `pluck`, `exec`. * * Changes `get` to `getOptional`. */ takeOptional(this: T): QueryTakeOptional; /** * `.rows` returns an array of arrays without field names: * * ```ts * const rows: Array> = await db.table * .select('id', 'name') * .rows(); * * rows.forEach((row) => { * // row is array of column values * row.forEach((value) => { * // value is an id or a name * }); * }); * ``` */ rows(this: T): SetQueryReturnsRows; /** * `.pluck` returns a single array of a single selected column values: * * ```ts * const ids = await db.table.select('id').pluck(); * // ids are an array of all users' id like [1, 2, 3] * ``` * @param select - column name or a raw SQL */ pluck>(this: T, select: S): SetQueryReturnsPluck; /** * `.exec` won't parse the response at all, and returns undefined: * * ```ts * const nothing = await db.table.take().exec(); * ``` */ exec(this: T): SetQueryReturnsVoid; /** * Call `toSQL` on a query to get an object with a `text` SQL string and a `values` array of binding values: * * ```ts * const sql = db.table.select('id', 'name').where({ name: 'name' }).toSQL(); * * expect(sql.text).toBe( * 'SELECT "table"."id", "table"."name" FROM "table" WHERE "table"."name" = $1', * ); * expect(sql.values).toEqual(['name']); * ``` * * `toSQL` is called internally when awaiting a query. * * It is caching the result. Not mutating query methods are resetting the cache, but need to be careful with mutating methods that start with `_` - they won't reset the cache, which may lead to unwanted results. * * `toSQL` optionally accepts such parameters: * * ```ts * type ToSqlOptions = { * values?: []; * }; * ``` */ toSQL(this: ToSQLQuery, callFromThen?: boolean): Sql; /** * Finds a single record by the primary key (id), throws [NotFoundError](/guide/error-handling.html) if not found. * Not available if the table has no or multiple primary keys. * * ```ts * const result: TableType = await db.table.find(1); * ``` * * @param value - primary key value to find by */ find(this: T, value: T['internal']['singlePrimaryKey'] | Expression): QueryTake & QueryHasWhere; /** * Finds a single record with a given SQL, throws {@link NotFoundError} if not found: * * ```ts * await db.user.findBySql` * age = ${age} AND * name = ${name} * `; * ``` * * @param args - SQL expression */ findBySql(this: T, ...args: SQLQueryArgs): QueryTake & QueryHasWhere; /** * Finds a single record by the primary key (id), returns `undefined` when not found. * Not available if the table has no or multiple primary keys. * * ```ts * const result: TableType | undefined = await db.table.find(123); * ``` * * @param value - primary key value to find by, or a raw SQL */ findOptional(this: T, value: T['internal']['singlePrimaryKey'] | Expression): QueryTakeOptional & QueryHasWhere; /** * Finds a single record with a given SQL. * Returns `undefined` when not found. * * ```ts * await db.user.findBySqlOptional` * age = ${age} AND * name = ${name} * `; * ``` * * @param args - SQL expression */ findBySqlOptional(this: T, ...args: SQLQueryArgs): QueryTakeOptional & QueryHasWhere; /** * Finds a single unique record, throws [NotFoundError](/guide/error-handling.html) if not found. * It accepts values of primary keys, unique columns, or compound unique constraints defined on the table. * `findBy`'s argument type is a union of all possible sets of unique conditions. * * You can use `where(...).take()` for non-unique conditions. * * ```ts * await db.table.findBy({ key: 'value' }); * ``` * * @param uniqueColumnValues - is derived from primary keys, unique columns, and compound unique constraints in the table */ findBy(this: T, uniqueColumnValues: T['internal']['uniqueColumns']): QueryTake & QueryHasWhere; /** * Finds a single unique record, returns `undefined` if not found. * It accepts values of primary keys, unique columns, or compound unique constraints defined on the table. * `findBy`'s argument type is a union of all possible sets of unique conditions. * * You can use `where(...).takeOptional()` for non-unique conditions. * * ```ts * await db.table.findByOptional({ key: 'value' }); * ``` * * @param uniqueColumnValues - is derived from primary keys, unique columns, and compound unique constraints in the table */ findByOptional(this: T, uniqueColumnValues: T['internal']['uniqueColumns']): QueryTakeOptional & QueryHasWhere; /** * For the `GROUP BY` SQL statement, it is accepting column names or raw expressions. * * `group` is useful when aggregating values. * * ```ts * // Select the category and sum of prices grouped by the category * const results = db.product * .select('category') * .selectSum('price', { as: 'sumPrice' }) * .group('category'); * ``` * * Also, it's possible to group by a selected value: * * ```ts * import { sql } from './baseTable'; * * const results = db.product * .select({ * month: sql`extract(month from "createdAt")`.type((t) => * // month is returned as string, parse it to int * t.string().parse(parseInt), * ), * }) * .selectSum('price', { as: 'sumPrice' }) * // group by month extracted from "createdAt" * .group('month'); * ``` * * Column aliases in `select` take precedence over table columns, * so if in the query above `db.product` had a column `month`, * the query would work in the exact same way, group by would reference the selected `month` expression. * * @param columns - column names or a raw SQL */ group(this: T, ...columns: T['__hasSelect'] extends true ? GroupArgs : { error: 'select is required for group'; }[]): T; /** * `none` will resolve the query into an empty result, without executing a database query. * * ```ts * await db.table.none(); // -> empty array * await db.table.findOptional(123).none(); // -> undefined * await db.table.find(123).none(); // throws NotFoundError * ``` * * [create](/guide/create-update-delete.html#create) chained with `count`, [update](/guide/create-update-delete.html#update), and [delete](/guide/create-update-delete.html#del-delete) are returning a count of affected records. * * When they are called with `none`, query does not execute and 0 is returned. * * ```ts * await db.table.insert(data); // -> 0 * await db.table.all().update(data); // -> 0 * await db.table.all().delete(); // -> 0 * ``` * * When it's being used in sub-selects, it will return empty arrays, `undefined`'s, or `0` for count, * or it will throw if the sub-query require a result: * * ```ts * await db.user.select({ * // returns empty array * pets: (q) => q.pets.none(), * // returns `undefined` * firstPet: (q) => q.pets.none().takeOptional(), * // throws NotFound error * requriedFirstPet: (q) => q.pets.none().take(), * // returns `undefined` * firstPetName: (q) => q.pets.none().getOptional('name'), * // throws NotFound error * requiredFirstPetName: (q) => q.pets.none().get('name'), * // returns empty array * petsNames: (q) => q.pets.none().pluck('name'), * // returns 0 * petsCount: (q) => q.pets.none().count(), * }); * ``` * * When the `none` query is being used for joins that require match, the host query will return an empty result: * * ```ts * // all the following queries will resolve into empty arrays * * await db.user.select({ * pets: (q) => q.pets.join().none(), * }); * * await db.user.join((q) => q.pets.none()); * * await db.user.join('pets', (q) => q.none()); * ``` * * When it's being used in `leftJoin` or `fullJoin`, it implicitly adds `ON false` into the join's SQL. * * ```ts * // this query can return user records * await db.user.leftJoin('pets', (q) => q.none()); * * // this query won't return user records, because of the added where condition * await db.user.leftJoin('pets', (q) => q.none()).where({ 'pets.name': 'Kitty' }); * ``` */ none(this: T): T; /** * Use `makeHelper` to make a query helper - a function where you can modify the query, and reuse this function across different places. * * The idea is similar to {@link modify}, the difference is that `modify` is per query, and `makeHelper` can be reused. * * ```ts * const defaultAuthorSelect = db.author.makeHelper((q) => { * return q.select('firstName', 'lastName'); * }); * * // this will select id, firstName, lastName with a correct TS type * // and return a single record * const result = await defaultAuthorSelect(db.author.select('id').find(1)); * ``` * * Such helper is available for relation queries inside `select`: * * ```ts * await db.book.select({ * author: (book) => defaultAuthorSelect(book.author), * }); * ``` * * Helper can accept additional arguments: * * ```ts * const selectFollowing = db.user.makeHelper((q, currentUser: { id: number }) => { * return q.select({ * following: (q) => * q.followers.where({ followerId: currentUser.id }).exists(), * }); * }); * * // select some columns and the `following` boolean field from users * await selectFollowing(db.user.select('id', 'name'), currentUser); * ``` * * To get the result type of query helper, use `QueryHelperResult` type: * * ```ts * import { QueryHelperResult } from 'orchid-orm'; * * const selectHelper = db.table.makeHelper((q) => q.select('id', 'name')); * * // This type is identical to `db.table.select('id', 'name')` * type SelectQuery = QueryHelperResult; * * // Await to get result, the type is `{ id: number, name: string }[]` * type Result = Awaited>; * ``` * * @param fn - helper function */ makeHelper(this: T, fn: (q: T, ...args: Args) => Result): QueryHelper; /** * `useHelper` allows to use {@link makeHelper} in different queries: * * ```ts * const helper = db.table.makeHelper((q) => { * // all query methods are available * return q.select('name').where({ active: true }).order({ createdAt: 'DESC' }); * }); * * const record = await db.table.select('id').useHelper(helper).find(1); * * record.id; // id was selected before `useHelper` * record.name; // name was selected by the function * ``` * * When the helper result isn't certain, it will result in a union of all possibilities. * Use this sparingly as it complicates dealing with the result. * * ```ts * const helper = db.table.makeHelper((q) => { * if (Math.random() > 0.5) { * return q.select('one'); * } else { * return q.select('two'); * } * }); * * const record = await db.table.useHelper(helper).find(1); * * // TS error: we don't know for sure if the `one` was selected. * record.one; * * // use `in` operator to disambiguate the result type * if ('one' in record) { * record.one; * } else { * record.two; * } * ``` * * You can define and pass parameters: * * ```ts * const helper = db.table.makeHelper((q, select: 'id' | 'name') => { * return q.select(select); * }); * * const record = await db.table.useHelper(helper, 'id').find(1); * // record has type { id: number } | { name: string } * if ('id' in record) { * record.id; * } * ``` * * @param fn - function to useHelper the query with. The result type will be merged with the main query as if the `merge` method was used. * @param args */ useHelper>(this: T, fn: Fn, ...args: Fn['args']): Fn['result'] extends MergeQueryArg ? MergeQuery : Fn['result']; /** * `modify` is useful when you'd like to modify the query based on some condition. * * ```ts * // parameters coming from outside * const selectOneOrAnother = true; * const filterBySomething = true; * * type ResultType = * | { id: number; one: string }[] * | { id: number; another: string }[]; * const result = await db.table * .select('id') * // conditional select results in a union type * .modify((q) => (includeName ? q.select('one') : q.select('another'))) * // can use any query methods in modify * .modify((q) => (filterBySomething ? q.where({ something: true }) : q)); * ``` * * @param fn - accepts the current query as a parameters. Anything returned by the function will be the return type of the query. */ modify(this: T, fn: (q: T) => R): R; /** * Narrows a part of the query output type. * Use with caution, type-safety isn't guaranteed with it. * This is similar so using `as` keyword from TypeScript, except that it applies only to a part of the result. * * The syntax `()<{ ... }>()` is enforced by internal limitations. * * ```ts * const rows = db.table * // filter out records where the `nullableColumn` is null * .where({ nullableColumn: { not: null } }); * // narrows only a specified column, the rest of result is unchanged * .narrowType()<{ nullableColumn: string }>() * * // the column had type `string | null`, now it is `string` * rows[0].nullableColumn * * // imagine that table has a enum column kind with variants 'first' | 'second' * // and a boolean `approved` * db.table * .where({ kind: 'first', approved: true }) * // after applying such `where`, it's safe to narrow the type to receive the literal values * .narrowType()<{ kind: 'first', approved: true }>(); * ``` */ narrowType(this: T): () => T['returnType'] extends undefined | 'all' | 'one' | 'oneOrThrow' ? [NarrowInvalidKeys] extends [never] ? { [K in keyof T]: K extends 'result' ? T['result'] & { [K in keyof Narrow]: { outputType: Narrow[K]; } } : K extends 'then' ? QueryThenByQuery : T[K] } : `narrowType() error: provided type does not extend the '${NarrowInvalidKeys & string}' column type` : (T['returnType'] extends 'pluck' ? Narrow extends unknown[] ? Narrow[number] : Narrow : Narrow) extends (T['returnType'] extends 'pluck' ? T['result']['pluck']['outputType'] : T['result']['value']['outputType']) ? { [K in keyof T]: K extends 'result' ? T['returnType'] extends 'value' | 'valueOrThrow' ? NarrowValueTypeResult : NarrowPluckTypeResult : K extends 'then' ? QueryThenByQuery : NarrowPluckTypeResult> : T[K] } : 'narrowType() error: provided type does not extend the returning column column type'; if(this: T, condition: boolean | null | undefined, fn: (q: T) => R & { returnType: T['returnType']; }): QueryIfResult; queryRelated(this: T, relName: RelName, params: T['relations'][RelName]['params']): T['relations'][RelName]['maybeSingle']; chain(this: T, relName: RelName): T['__subQuery'] extends true | undefined ? [T['returnType'], T['relations'][RelName]['returnsOne']] extends ['one' | 'oneOrThrow', true] ? { [K in keyof T['relations'][RelName]['maybeSingle']]: K extends '__selectable' ? T['relations'][RelName]['maybeSingle']['__selectable'] & Omit : T['relations'][RelName]['maybeSingle'][K] } & IsSubQuery : JoinResultRequireMain> : T['relations'][RelName]['query']; } interface DbExtension { name: string; version?: string; } interface GeneratorIgnore { schemas?: string[]; enums?: string[]; domains?: string[]; extensions?: string[]; tables?: string[]; } interface DbDomainArg { (columnTypes: ColumnTypes): Column; } interface DbDomainArgRecord { [K: string]: DbDomainArg; } type SelectableFromShape = { [K in keyof Shape]: { as: K; column: Shape[K]; } } & { [K in keyof Shape & string as `${Table}.${K}`]: { as: K; column: Shape[K]; } }; type QueryReturnType = QueryReturnTypeAll | 'one' | 'oneOrThrow' | 'rows' | 'pluck' | 'value' | 'valueOrThrow' | 'void'; type QueryReturnTypeAll = undefined | 'all'; type QueryReturnTypeOptional = 'one' | 'value'; interface QueryHasSelect { __hasSelect: true; } interface IsQuery { __isQuery: true; } interface IsSubQuery { __subQuery: true; } interface IsQueries { [K: string]: IsQuery; } interface QueryOrExpression { result: { value: Column.Pick.QueryColumnOfType; }; } interface QuerySelectable { [K: PropertyKey]: { as: string; column: Column.Pick.QueryColumn; }; } interface Query extends IsQuery, PickQueryTable, PickQueryShape, PickQuerySelectable, QueryMethods { __as: string; __hasSelect: boolean; __hasWhere: boolean; __defaults: EmptyObject; __scopes: EmptyObject; __defaultSelect: PropertyKey; result: Column.QueryColumns; withData: WithDataItems; baseQuery: Query; internal: QueryInternal; returnType: QueryReturnType; qb: QueryBuilder; columnTypes: unknown; inputType: RecordUnknown; q: QueryData; then: QueryThen; catch: QueryCatch; windows: EmptyObject; relations: RelationsBase; relationQueries: IsQueries; error: new (message: string, length: number, name: QueryErrorName) => QueryError; } declare namespace Query { namespace Order { type Arg = Order.Arg; type Args = Order.Args; } } type SelectableOfType = { [K in keyof T['__selectable']]: T['__selectable'][K]['column']['type'] extends Type | null ? K : never }[keyof T['__selectable']]; type SelectableOrExpressionOfType = SelectableOfType | Expression>; type SetQueryReturnsAll = { [K in keyof T]: K extends 'returnType' ? 'all' : K extends 'then' ? QueryThenShallowSimplifyArr> : T[K] } & QueryHasWhere; type SetQueryReturnsAllResult = { [K in keyof T]: K extends 'returnType' ? 'all' : K extends 'result' ? Result : K extends 'then' ? QueryThenShallowSimplifyArr : T[K] } & QueryHasWhere; type QueryTakeOptional = T['returnType'] extends 'value' | 'pluck' | 'void' ? T : T['returnType'] extends 'valueOrThrow' ? { [K in keyof T]: K extends 'returnType' ? 'value' : K extends 'then' ? QueryThen : T[K] } : { [K in keyof T]: K extends 'returnType' ? 'one' : K extends 'then' ? QueryThenShallowSimplifyOptional> : T[K] }; type QueryManyTakeOptional = { [K in keyof T]: K extends 'returnType' ? 'one' : K extends 'then' ? QueryThenShallowSimplifyOptional> : T[K] }; type QueryTake = T['returnType'] extends 'valueOrThrow' | 'pluck' | 'void' ? T : T['returnType'] extends 'value' ? { [K in keyof T]: K extends 'returnType' ? 'valueOrThrow' : K extends 'then' ? QueryThen> : T[K] } : { [K in keyof T]: K extends 'returnType' ? 'oneOrThrow' : K extends 'then' ? QueryThenShallowSimplify> : T[K] }; type QueryManyTake = { [K in keyof T]: K extends 'returnType' ? 'oneOrThrow' : K extends 'then' ? QueryThenShallowSimplify> : T[K] }; type SetQueryReturnsOne = { [K in keyof T]: K extends 'returnType' ? 'oneOrThrow' : K extends 'then' ? QueryThenShallowSimplify> : T[K] }; type SetQueryReturnsOneResult = { [K in keyof T]: K extends 'returnType' ? 'oneOrThrow' : K extends 'result' ? Result : K extends 'then' ? QueryThenShallowSimplify> : T[K] }; type SetQueryReturnsRows = { [K in keyof T]: K extends 'returnType' ? 'rows' : K extends 'then' ? QueryThen[keyof T['result']][][]> : T[K] }; type SetQueryReturnsPluck = S extends keyof T['__selectable'] ? { [K in keyof T]: K extends '__hasSelect' ? true : K extends 'result' ? { pluck: T['__selectable'][S]['column']; } : K extends 'returnType' ? 'pluck' : K extends 'then' ? QueryThen : T[K] } : { [K in keyof T]: K extends '__hasSelect' ? true : K extends 'result' ? { pluck: S extends Expression ? S['result']['value'] : never; } : K extends 'returnType' ? 'pluck' : K extends 'then' ? QueryThen<(S extends Expression ? S['result']['value']['outputType'] : never)[]> : T[K] }; type SetValueQueryReturnsPluckColumn = { [K in keyof T]: K extends 'result' ? { pluck: T['result']['value']; } : K extends 'returnType' ? 'pluck' : K extends 'then' ? QueryThen : T[K] } & QueryHasSelect; type SetQueryReturnsPluckColumnResult = { [K in keyof T]: K extends 'result' ? { pluck: T['result']['value']; } : K extends 'returnType' ? 'pluck' : K extends 'result' ? Result : K extends 'then' ? QueryThen : T[K] } & QueryHasSelect; type SetQueryReturnsValueOrThrow = SetQueryReturnsColumnOrThrow & T['__selectable'][Arg]['column']['operators']; type SetValueQueryReturnsValueOrThrow = { [K in keyof T]: K extends 'returnType' ? 'valueOrThrow' : K extends 'then' ? QueryThen : T[K] }; type SetQueryReturnsValueOptional> = SetQueryReturnsColumnOptional & Omit & Column.Modifiers.OperatorsNullable; type SetQueryReturnsColumnOrThrow = { [K in keyof T]: K extends 'result' ? { value: Column; } : K extends 'returnType' ? 'valueOrThrow' : K extends 'then' ? QueryThen : T[K] } & QueryHasSelect; type SetQueryReturnsColumnOptional = { [K in keyof T]: K extends 'result' ? { value: Column; } : K extends 'returnType' ? 'value' : K extends 'then' ? QueryThen : T[K] } & QueryHasSelect; type SetQueryReturnsColumn = { [K in keyof T]: K extends 'result' ? { value: T['result']['pluck']; } : K extends 'returnType' ? 'valueOrThrow' : K extends 'then' ? QueryThen : T[K] } & QueryHasSelect; type SetQueryReturnsColumnResult = { [K in keyof T]: K extends 'result' ? { value: T['result']['pluck']; } : K extends 'returnType' ? 'valueOrThrow' : K extends 'result' ? Result : K extends 'then' ? QueryThen : T[K] } & QueryHasSelect; type SetQueryReturnsRowCount = { [K in keyof T]: K extends 'returnType' ? 'valueOrThrow' : K extends 'result' ? { value: Column.Pick.QueryColumnOfType; } : K extends 'then' ? QueryThen : T[K] }; type SetQueryReturnsRowCountMany = { [K in keyof T]: K extends 'returnType' ? 'pluck' : K extends 'result' ? { pluck: Column.Pick.QueryColumnOfType; } : K extends 'then' ? QueryThen : T[K] }; type SetQueryReturnsVoid = { [K in keyof T]: K extends 'returnType' ? 'void' : K extends 'then' ? QueryThen : T[K] }; type SetQueryResult = { [K in keyof T]: K extends 'result' ? Result : K extends 'then' ? QueryThenByQuery : T[K] }; interface ReturnsQueryOrExpression { (): QueryOrExpression; } interface QueryOrExpressionBooleanOrNullResult { result: { value: Column.Pick.QueryColumnOfType; }; } declare const isQueryReturnsAll: (q: Query) => boolean; interface RelationJoinQuery { (joiningQuery: IsQuery, baseQuery: IsQuery): IsQuery; } interface RelationConfigQuery extends PickQueryResult, PickQuerySelectable, PickQueryShape, PickQueryTable, PickQueryAs, PickQueryRelations {} interface RelationConfigBase extends IsQuery { returnsOne: boolean; query: RelationConfigQuery; joinQuery: RelationJoinQuery; reverseJoin: RelationJoinQuery; params: unknown; queryRelated(params: unknown): unknown; modifyRelatedQuery?(relatedQuery: IsQuery): (query: IsQuery) => void; maybeSingle: PickQuerySelectableReturnType; omitForeignKeyInCreate: PropertyKey; dataForCreate?: RelationConfigDataForCreate; optionalDataForCreate: unknown; dataForUpdate: unknown; dataForUpdateOne: unknown; primaryKeys: string[]; } interface RelationConfigDataForCreate { columns: PropertyKey; nested: RecordUnknown; } interface RelationsBase { [K: string]: RelationConfigBase; } interface PickQueryTable { table?: string; } interface PickQueryThen { then: unknown; } interface PickQueryHasSelect { __hasSelect: boolean; } interface PickQueryHasWhere { __hasWhere: boolean; } interface PickQueryDefaults { __defaults: EmptyObject; } interface PickQueryTsQuery { __tsQuery?: string; } interface PickQueryScopes { __scopes: EmptyObject; } interface PickQueryDefaultSelect { __defaultSelect: PropertyKey; } interface PickQueryHasSelectResultReturnType extends PickQueryHasSelect, PickQueryResult, PickQueryReturnType {} interface PickQueryHasSelectResultShapeAsRelations extends PickQueryHasSelect, PickQueryResult, PickQueryShape, PickQueryAs, PickQueryRelations {} interface PickQueryHasSelectHasWhereResultReturnType extends PickQueryHasSelect, PickQueryHasWhere, PickQueryResult, PickQueryReturnType {} interface PickQueryHasSelectResult extends PickQueryHasSelect, PickQueryResult {} interface PickQuerySelectable { __selectable: QuerySelectable; } interface PickQuerySelectableResult extends PickQuerySelectable, PickQueryResult {} interface PickQuerySelectableRelations extends PickQuerySelectable, PickQueryRelations {} interface PickQuerySelectableResultWindows extends PickQuerySelectable, PickQueryResult, PickQueryWindows {} interface PickQuerySelectableResultRelationsWindows extends PickQuerySelectableResult, PickQueryRelations, PickQueryWindows {} interface PickQueryMetaSelectableResultRelationsWindowsColumnTypes extends PickQuerySelectableResultRelationsWindows, PickQueryColumTypes {} interface PickQuerySelectableShapeAs extends PickQuerySelectable, PickQueryShape, PickQueryAs {} interface PickQueryTableMetaShapeTableAs extends PickQuerySelectableShapeAs, PickQueryTable {} interface PickQuerySelectableShapeRelationsWithData extends PickQuerySelectable, PickQueryShape, PickQueryRelations, PickQueryWithData {} interface PickQuerySelectableShapeRelationsWithDataAs extends PickQuerySelectableShapeRelationsWithData, PickQueryAs {} interface PickQuerySelectableShapeRelationsWithDataAsResultReturnType extends PickQuerySelectableShapeRelationsWithDataAs, PickQueryResult, PickQueryReturnType {} interface PickQuerySelectableRelationsResultReturnType extends PickQuerySelectableRelations, PickQueryResult, PickQueryReturnType {} interface PickQuerySelectableResultRelationsWithDataReturnType extends PickQuerySelectable, PickQueryResult, PickQueryRelations, PickQueryWithData, PickQueryReturnType {} interface PickQuerySelectableResultRelationsWithDataReturnTypeShapeAs extends PickQuerySelectableResultRelationsWithDataReturnType, PickQueryShape, PickQueryAs {} interface PickQuerySelectableShape extends PickQuerySelectable, PickQueryShape {} interface PickQuerySelectableColumnTypes extends PickQuerySelectable, PickQueryColumTypes {} interface PickQuerySelectableShapeRelationsReturnTypeIsSubQuery extends PickQueryIsSubQuery, PickQuerySelectable, PickQueryShape, PickQueryRelations, PickQueryReturnType {} interface PickQuerySelectableReturnType extends PickQuerySelectable, PickQueryReturnType {} interface PickQuerySelectableResultInputTypeAs extends PickQuerySelectableResult, PickQueryInputType, PickQueryAs {} interface PickQuerySelectableResultAs extends PickQuerySelectable, PickQueryResult, PickQueryAs {} interface PickQueryIsSubQuery { __subQuery?: boolean; } interface PickQueryResult { result: Column.QueryColumns; } interface PickQueryShape { shape: Column.QueryColumns; } interface PickQueryReturnType { returnType: QueryReturnType; } interface PickQueryResultReturnType extends PickQueryResult, PickQueryReturnType {} interface PickQueryResultUniqueColumns extends PickQueryResult { internal: { uniqueColumns: unknown; }; } interface PickQueryResultReturnTypeUniqueColumns extends PickQueryResultUniqueColumns, PickQueryReturnType {} interface PickQueryUniqueProperties { internal: { uniqueColumnNames: unknown; uniqueColumnTuples: unknown; uniqueConstraints: unknown; }; } interface PickQueryInputType { inputType: RecordUnknown; } interface PickQueryWithData { withData: WithDataItems; } interface PickQueryWindows { windows: EmptyObject; } interface PickQueryRelations { relations: RelationsBase; } interface PickQueryColumTypes { columnTypes: unknown; } interface PickQueryWithDataColumnTypes extends PickQueryWithData, PickQueryColumTypes {} interface PickQueryResultColumnTypes extends PickQueryResult, PickQueryColumTypes {} interface PickQueryAs { __as: string; } interface PickQueryResultAs extends PickQueryResult, PickQueryAs {} interface PickQueryResultAsRelations extends PickQueryResultAs, PickQueryRelations {} interface PickQueryShapeAsRelations extends PickQueryShape, PickQueryAs, PickQueryRelations {} interface PickQueryRelationsWithData extends PickQueryWithData, PickQueryRelations {} interface PickQuerySinglePrimaryKey { internal: { singlePrimaryKey: unknown; }; } interface PickQueryShapeSinglePrimaryKey extends PickQueryShape, PickQuerySinglePrimaryKey {} interface PickQueryShapeResultSinglePrimaryKey extends PickQueryShapeSinglePrimaryKey, PickQueryResult {} interface PickQueryShapeResultReturnTypeSinglePrimaryKey extends PickQueryShapeResultSinglePrimaryKey, PickQueryReturnType {} interface PickQueryQ { q: QueryData; } interface PickQueryInternal { internal: QueryInternal; } interface PickQueryQAndInternal extends IsQuery, PickQueryQ, PickQueryInternal {} interface PickQueryDataAliases { aliases?: RecordString; } interface QueryDataAliases extends PickQueryDataAliases { as?: string; outerAliases?: RecordString; } type SetQueryTableAlias = { [K in keyof T]: K extends '__selectable' ? Omit & { [K in keyof T['shape'] & string as `${As}.${K}`]: { as: K; column: T['shape'][K]; } } : K extends '__as' ? As : T[K] }; type AsQueryArg = PickQuerySelectableShapeAs; /** getters **/ declare const getQueryAs: (q: { table?: string; q: { as?: string; }; }) => string; declare abstract class QueryAsMethods { /** * Sets table alias: * * ```ts * db.table.as('u').select('u.name'); * * // Can be used in the join: * db.table.join(db.profile.as('p'), 'p.userId', 'user.id'); * ``` * * @param as - alias for the table of this query */ as(this: T, as: As): SetQueryTableAlias; } declare const _appendQuery: (main: Query, append: Query, asFn: (as: string) => void) => Query; declare const getPrimaryKeys: (q: Query) => string[]; /** * Set value into the object in query data, create the object if it doesn't yet exist. * Does not mutate the object. * * @param q - query * @param object - query data key to get the object * @param key - object key to set the value into * @param value - value to set by the key */ declare const setQueryObjectValueImmutable: (q: T, object: string, key: string, value: unknown) => T; declare const _queryTake: (query: T) => QueryTake; declare const _queryTakeOptional: (query: T) => QueryTakeOptional; declare const _queryRows: (q: T) => SetQueryReturnsRows; type Value = any; declare const escapeForMigration: (value: Value) => string; declare const escapeString: (value: string) => string; /** * Result type for `columnInfo` method. * Sets query kind to 'columnInfo', returns a single value (may return undefined), * the value is a {@link GetColumnInfo} object or a Record with keys for column names and ColumnInfo objects as values. **/ type SetQueryReturnsColumnInfo = Omit & { result: { value: Column.Pick.QueryColumnOfType; }; returnType: 'value'; then: QueryThenShallowSimplify; }; type GetColumnInfo = { defaultValue: unknown; type: string; maxLength: number | null; nullable: boolean; }; /** * Returns an object with the column info about the current table, or an individual column if one is passed, returning an object with the following keys: * * ```ts * type ColumnInfo = { * defaultValue: unknown; // the default value for the column * type: string; // the column type * maxLength: number | null; // the max length set for the column, present on string types * nullable: boolean; // whether the column may be null * }; * * import { getColumnInfo } from 'orchid-orm'; * * // columnInfo has type Record, where string is name of columns * const columnInfo = await getColumnInfo(db.table); * * // singleColumnInfo has the type ColumnInfo * const singleColumnInfo = await getColumnInfo(db.table, 'name'); * ``` * * @param column - optional: select info for only a single column if provided, or for all table columns if not */ declare function getColumnInfo(query: T, column?: Column): SetQueryReturnsColumnInfo; type CopyOptions = { columns?: Column[]; format?: 'text' | 'csv' | 'binary'; freeze?: boolean; delimiter?: string; null?: string; header?: boolean | 'match'; quote?: string; escape?: string; forceQuote?: Column[] | '*'; forceNotNull?: Column[]; forceNull?: Column[]; encoding?: string; } & ({ from: string | { program: string; }; } | { to: string | { program: string; }; }); type CopyArg = CopyOptions; /** * `copyTableData` is a function to invoke a `COPY` SQL statement, it can copy from or to a file or a program. * * Copying from `STDIN` or to `STDOUT` is not supported. * * It supports all the options of the `COPY` statement of Postgres. See details in [Postgres document](https://www.postgresql.org/docs/current/sql-copy.html). * * The copying is performed by the Postgres database server, and it must have access to the file. * * Type of copy argument: * * ```ts * export type CopyOptions = { * columns?: Column[]; * format?: 'text' | 'csv' | 'binary'; * freeze?: boolean; * delimiter?: string; * null?: string; * header?: boolean | 'match'; * quote?: string; * escape?: string; * forceQuote?: Column[] | '*'; * forceNotNull?: Column[]; * forceNull?: Column[]; * encoding?: string; * } & ( * | { * from: string | { program: string }; * } * | { * to: string | { program: string }; * } * ); * ``` * * Example usage: * * ```ts * import { copyTableData } from 'orchid-orm'; * * await copyTableData(db.table, { * columns: ['id', 'title', 'description'], * from: 'path-to-file', * }); * ``` * * @param arg - object with copy options */ declare function copyTableData(query: T, arg: CopyArg): T; type Arg$1 = { $qb: Query; } | Query; declare const testTransaction: { /** * Start a test transaction. * The returned promise is resolved immediately when transaction starts, not waiting for it to end. * * @param arg - ORM instance or a queryable instance (such as db.someTable). */ start(arg: Arg$1): Promise; /** * Rollback a test transaction. * * @param arg - the same ORM or query argument passed into the `testTransaction.start`. */ rollback(arg: Arg$1): Promise | undefined; /** * Will roll back the current `testTransaction` (won't have any effect if it was rolled back already), * and if there's no nested test transactions left, it will close the db connection. * * @param arg - the same ORM or query argument passed into the `testTransaction.start`. */ close(arg: Arg$1): Promise; }; export { type Adapter, AdapterClass, type AdapterConfigBase, type AdapterParams, type AfterCommitStandaloneHook, type AfterHook, ArrayColumn, type ArrayColumnValue, type ArrayData, type AsyncState, type BaseNumberData, BigIntColumn, BigSerialColumn, BitColumn, BitVaryingColumn, BooleanColumn, BoxColumn, ByteaColumn, CidrColumn, CircleColumn, CitextColumn, type Code, type Codes, Column, type ColumnFromDbParams, type ColumnSchemaConfig, type ColumnSchemaGetterColumns, type ColumnSchemaGetterTableClass, type ColumnToCodeCtx, type ColumnTypeSchemaArg, type ColumnsByType, type ColumnsShape, type ComputedColumnsFromOptions, type ComputedOptionsConfig, type ComputedOptionsFactory, type CreateCtx, type CreateData, type CreateManyMethodsNames, type CreateMethodsNames, type CreateSelf, CustomTypeColumn, DateBaseColumn, DateColumn, type DateColumnData, DateTimeBaseClass, DateTimeTzBaseClass, Db, type DbDomainArg, type DbExtension, type DbOptions, type DbResult, type DbRlsOptions, type DbSharedOptions, type DbSqlMethod, type DbStructureDomainsMap, type DbTableOptionScopes, type DbTableOptions, DecimalColumn, type DecimalColumnData, type DefaultColumnTypes, type DefaultPrivileges, type DefaultSchemaConfig, type DeleteMethodsNames, DomainColumn, DoublePrecisionColumn, type DriverAdapter, DynamicRawSQL, type EmptyObject, type EmptyTuple, EnumColumn, Expression, type FromArg, type FromResult, type GeneratorIgnore, type HookSelectValue, InetColumn, IntegerBaseColumn, IntegerColumn, IntervalColumn, type IsQuery, type IsolationLevel, JSONColumn, JSONTextColumn, type JoinQueryMethod, type JoinedShapes, LimitedTextBaseColumn, LineColumn, LsegColumn, MacAddr8Column, MacAddrColumn, type MapTableScopesOption, type MaybeArray, type MaybePromise, type MergeQuery, MoneyColumn, type NoPrimaryKeyOption, type NonUniqDataItem, NotFoundError, NumberAsStringBaseColumn, NumberBaseColumn, type NumberColumnData, Operators, type OperatorsArray, type OperatorsJson, type OperatorsOrdinalText, OrchidOrmInternalError, type Ord, PathColumn, type PickQueryInputType, type PickQueryInternal, type PickQueryQ, type PickQueryRelations, type PickQuerySelectableRelations, type PickQueryShape, PointColumn, PolygonColumn, PostgisGeographyPointColumn, type Query, type QueryAfterHook, type QueryArraysResult, type QueryBeforeActionHook, type QueryBeforeHook, type QueryData, QueryError, type QueryHasWhere, type QueryHelperResult, QueryHookUtils, QueryHooks, type QueryInternal, type QueryLogObject, type QueryLogOptions, type QueryLogger, type QueryManyTake, type QueryManyTakeOptional, type QueryOrExpression, type QueryResult, type QueryResultRow, type QueryReturnType, type QuerySchema, type QueryScopes, RawSql, type RawSqlBase, RealColumn, type RecordKeyTrue, type RecordOptionalString, type RecordString, type RecordStringOrNumber, type RecordUnknown, type RelationConfigBase, type RelationJoinQuery, type RelationsBase, type SearchWeight, type SelectableFromShape, SerialColumn, type SerialColumnData, type ShallowSimplify, type ShapeColumnPrimaryKeys, type ShapeUniqueColumns, type SingleSql, type SingleSqlItem, SmallIntColumn, SmallSerialColumn, type Sql, type SqlFn, type SqlSessionState, type StorageOptions, StringColumn, type StringData, type TableData, type TableDataFn, type TableDataInput, type TableDataItem, type TableDataItemsUniqueColumnTuples, type TableDataItemsUniqueColumns, type TableDataItemsUniqueConstraints, type TableDataMethods, type TableRlsConfig, type TemplateLiteralArgs, TextBaseColumn, TextColumn, TimeColumn, TimestampColumn, TimestampTZColumn, type Timestamps, TransactionAdapterClass, type TransactionOptions, TsQueryColumn, TsVectorColumn, UUIDColumn, type UniqueConstraints, type UniqueTableDataItem, UnknownColumn, type UpdateData, type UpsertData, type UpsertThis, VarCharColumn, VirtualColumn, type WhereArg, XMLColumn, _appendQuery, _clone, _createDbSqlMethod, _hookSelectColumns, _initQueryBuilder, _orCreate, _prependWith, _queryCreate, _queryCreateMany, _queryCreateManyFrom, _queryDefaults, _queryDelete, _queryFindBy, _queryFindByOptional, _queryHookAfterCreate, _queryHookAfterUpdate, _queryInsert, _queryInsertMany, _queryJoinOn, _queryRows, _querySelect, _queryTake, _queryTakeOptional, _queryUpdate, _queryUpdateOrThrow, _queryUpsert, _queryWhere, _queryWhereExists, _queryWhereIn, addCode, addTopCte, addTopCteSql, applyMixins, assignDbDataToColumn, backtickQuote, cloneQueryBaseUnscoped, codeToString, colors, columnsShapeToCode, constraintInnerToCode, consumeColumnName, copyTableData, createDbWithAdapter, deepCompare, defaultSchemaConfig, emptyArray, emptyObject, escapeForMigration, escapeString, excludeInnerToCode, exhaustive, getCallerFilePath, getClonedQueryData, getColumnBaseType, getColumnInfo, getColumnTypes, getFreeAlias, getFreeSetAlias, getImportPath, getPrimaryKeys, getQueryAs, getQuerySchema, getShapeFromSelect, getSqlText, getStackTrace, getSupportedDefaultPrivileges, indexInnerToCode, isExpression, isQueryReturnsAll, isRawSQL, logColors, logParamToLogObject, makeColumnNullable, makeColumnTypes, makeColumnsByType, makeConnectRetryConfig, noop, objectHasValues, omit, parseTableData, parseTableDataInput, pathToLog, pick, pluralize, prepareSubQueryForSql, primaryKeyInnerToCode, pushQueryOnForOuter, pushQueryValueImmutable, pushTableDataCode, quoteObjectKey, quoteTableWithSchema, raw, rawSqlToCode, referencesArgsToCode, returnArg, setColumnData, setColumnEncode, setColumnParse, setColumnParseNull, setCurrentColumnName, setDataValue, setDefaultLanguage, setFreeAlias, setQueryObjectValueImmutable, singleQuote, tableDataMethods, testTransaction, toArray, toCamelCase, toPascalCase, toSnakeCase, wrapAdapterFnWithConnectRetry };