import type { DrainOuterGeneric, IsNever, IsNullable } from './type-utils.js'; /** * This type can be used to specify a different type for * select, insert and update operations. * * Also see the {@link Generated} type. * * ### Examples * * The next example defines a number column that is optional * in inserts and updates. All columns are always optional * in updates so therefore we don't need to specify `undefined` * for the update type. The type below is useful for all kinds of * database generated columns like identifiers. The `Generated` * type is actually just a shortcut for the type in this example: * * ```ts * type GeneratedNumber = ColumnType * ``` * * The above example makes the column optional in inserts * and updates, but you can still choose to provide the * column. If you want to prevent insertion/update you * can se the type as `never`: * * ```ts * type ReadonlyNumber = ColumnType * ``` * * Here's one more example where the type is different * for each different operation: * * ```ts * type UnupdateableDate = ColumnType * ``` */ export type ColumnType = { readonly __select__: SelectType; readonly __insert__: InsertType; readonly __update__: UpdateType; }; /** * A shortcut for defining database-generated columns. The type * is the same for all selects, inserts and updates but the * column is optional for inserts and updates. * * The update type is `S` instead of `S | undefined` because updates are always * optional --> no need to specify optionality. * ``` */ export type Generated = ColumnType; /** * A shortcut for defining columns that are only database-generated * (like postgres GENERATED ALWAYS AS IDENTITY). No insert/update * is allowed. */ export type GeneratedAlways = ColumnType; /** * A shortcut for defining JSON columns, which are by default inserted/updated * as stringified JSON strings. */ export type JSONColumnType = ColumnType; /** * Evaluates to `K` if `T` can be `null` or `undefined`. */ type IfNullable = IsNullable extends true ? K : never; /** * Evaluates to `K` if `T` can't be `null` or `undefined`. */ type IfNotNullable = IsNullable extends true ? never : IfNotNever; /** * Evaluates to `K` if `T` isn't `never`. */ type IfNotNever = IsNever extends true ? never : K; export type SelectType = T extends ColumnType ? S : T; export type InsertType = T extends ColumnType ? I : T; export type UpdateType = T extends ColumnType ? U : T; /** * Keys of `R` whose `InsertType` values can be `null` or `undefined`. */ export type NullableInsertKeys = { [K in keyof R]: IfNullable, K>; }[keyof R]; /** * Keys of `R` whose `InsertType` values can't be `null` or `undefined`. */ export type NonNullableInsertKeys = { [K in keyof R]: IfNotNullable, K>; }[keyof R]; /** * Keys of `R` whose `SelectType` values are not `never` */ type NonNeverSelectKeys = { [K in keyof R]: IfNotNever, K>; }[keyof R]; /** * Keys of `R` whose `UpdateType` values are not `never` */ export type UpdateKeys = { [K in keyof R]: IfNotNever, K>; }[keyof R]; /** * Given a table interface, extracts the select type from all * {@link ColumnType} types. * * ### Examples * * ```ts * interface PersonTable { * id: Generated * first_name: string * modified_at: ColumnType * } * * type Person = Selectable * // { * // id: number, * // first_name: string * // modified_at: Date * // } * ``` */ export type Selectable = DrainOuterGeneric<{ [K in NonNeverSelectKeys]: SelectType; }>; /** * Given a table interface, extracts the insert type from all * {@link ColumnType} types. * * ### Examples * * ```ts * interface PersonTable { * id: Generated * first_name: string * modified_at: ColumnType * } * * type InsertablePerson = Insertable * // { * // id?: number, * // first_name: string * // modified_at: string * // } * ``` */ export type Insertable = DrainOuterGeneric]: InsertType; } & { [K in NullableInsertKeys]?: InsertType; }>; /** * Given a table interface, extracts the update type from all * {@link ColumnType} types. * * ### Examples * * ```ts * interface PersonTable { * id: Generated * first_name: string * modified_at: ColumnType * } * * type UpdateablePerson = Updateable * // { * // id?: number, * // first_name?: string * // } * ``` */ export type Updateable = DrainOuterGeneric<{ [K in UpdateKeys]?: UpdateType | undefined; }>; /** * Wrap your column type to opt-out from dehydration by {@link ShallowDehydrateValue}, * when used by JSON functions, such as the ones used by the relational helpers. * * Why need this? * * An edge case surfaced in issues where a numeric string column type was actually * not a numeric data type column, but text - and thus shouldn't be dehydrated * to `number`. * * Another use case would be, when someone finds a way to keep nested columns hydrated * at runtime, e.g. via a plugin, and wants to prevent dehydration of such columns * at the type level. * * ### Examples * * ```ts * import type { NonDehydrateable } from 'kysely' * import { jsonArrayFrom } from 'kysely/helpers/postgres' * * const result = await db * .withTables<{ * my_table: { * a_column: '1' | '2' | '3', * another_column: NonDehydrateable<'1' | '2' | '3'>, * column_too: NonDehydrateable> * } * }>() * .selectFrom('person') * .select((eb) => [ * 'id', * jsonArrayFrom( * eb.selectFrom('my_table') * .select(['a_column', 'another_column', 'column_too']) * ).as('related') * ]) * .execute() * ``` * * In the example above, "a_column" will be dehydrated to `number` * given it is a numeric string - which is normally a numeric data type column * that gets output as a string by underlying database drivers to avoid * precision loss or overflow. * * "another_column" and "column_too" will remain as `'1' | '2' | '3'`, given they're * wrapped in `NonDehydrateable`, which prevents their dehydration. */ export type NonDehydrateable = [T] extends [ ColumnType ] ? ColumnType : T & { __kysely_dehydrate__?: false; }; export {};