Skip to content

Commit

Permalink
Merge pull request #1471 from Angelelz/feat-generated-columns
Browse files Browse the repository at this point in the history
Feat: Drizzle-ORM support for Generated columns
  • Loading branch information
AndriiSherman authored Jun 27, 2024
2 parents 4ecfe1f + 6b0a11e commit 3245641
Show file tree
Hide file tree
Showing 97 changed files with 1,647 additions and 432 deletions.
2 changes: 1 addition & 1 deletion changelogs/drizzle-orm/0.30.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ const usersOnUpdate = pgTable('users_on_update', {

- [BUG]: insertions on columns with the smallserial datatype are not optional - #1848

Thanks @Angelelz and @gabrielDonnantuoni!
Thanks @Angelelz and @gabrielDonnantuoni!
10 changes: 10 additions & 0 deletions changelogs/drizzle-orm/0.30.7-preview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- 🎉 Added custom schema support to enums in Postgres:
```ts
import { pgSchema } from 'drizzle-orm/pg-core';

const mySchema = pgSchema('mySchema');
const colors = mySchema.enum('colors', ['red', 'green', 'blue']);
```

- 🐛 Split `where` clause in Postgres `.onConflictDoUpdate` method into `setWhere` and `targetWhere` clauses, to support both `where` cases in `on conflict ...` clause (#1628, #1302)
- 🐛 Fix query generation for `where` clause in Postgres `.onConflictDoNothing` method, as it was placed in a wrong spot (#1628)
2 changes: 1 addition & 1 deletion drizzle-orm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "drizzle-orm",
"version": "0.31.2",
"version": "0.32.0",
"description": "Drizzle ORM package for SQL databases",
"type": "module",
"scripts": {
Expand Down
50 changes: 48 additions & 2 deletions drizzle-orm/src/column-builder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { entityKind } from '~/entity.ts';
import type { Column } from './column.ts';
import type { MySqlColumn } from './mysql-core/index.ts';
import type { ExtraConfigColumn, PgColumn } from './pg-core/index.ts';
import type { ExtraConfigColumn, PgColumn, PgSequenceOptions } from './pg-core/index.ts';
import type { SQL } from './sql/sql.ts';
import type { SQLiteColumn } from './sqlite-core/index.ts';
import type { Simplify } from './utils.ts';
Expand All @@ -19,30 +19,49 @@ export type ColumnDataType =

export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'common';

export type GeneratedStorageMode = 'virtual' | 'stored';

export type GeneratedType = 'always' | 'byDefault';

export type GeneratedColumnConfig<TDataType> = {
as: TDataType | SQL | (() => SQL);
type?: GeneratedType;
mode?: GeneratedStorageMode;
};

export type GeneratedIdentityConfig = {
sequenceName?: string;
sequenceOptions?: PgSequenceOptions;
type: 'always' | 'byDefault';
};

export interface ColumnBuilderBaseConfig<TDataType extends ColumnDataType, TColumnType extends string> {
name: string;
dataType: TDataType;
columnType: TColumnType;
data: unknown;
driverParam: unknown;
enumValues: string[] | undefined;
generated: GeneratedColumnConfig<unknown> | undefined;
}

export type MakeColumnConfig<
T extends ColumnBuilderBaseConfig<ColumnDataType, string>,
TTableName extends string,
TData = T extends { $type: infer U } ? U : T['data'],
> = {
name: T['name'];
tableName: TTableName;
dataType: T['dataType'];
columnType: T['columnType'];
data: T extends { $type: infer U } ? U : T['data'];
data: TData;
driverParam: T['driverParam'];
notNull: T extends { notNull: true } ? true : false;
hasDefault: T extends { hasDefault: true } ? true : false;
enumValues: T['enumValues'];
baseColumn: T extends { baseBuilder: infer U extends ColumnBuilderBase } ? BuildColumn<TTableName, U, 'common'>
: never;
generated: T['generated'] extends object ? T['generated'] : undefined;
} & {};

export type ColumnBuilderTypeConfig<
Expand All @@ -60,6 +79,7 @@ export type ColumnBuilderTypeConfig<
notNull: T extends { notNull: infer U } ? U : boolean;
hasDefault: T extends { hasDefault: infer U } ? U : boolean;
enumValues: T['enumValues'];
generated: GeneratedColumnConfig<T['data']> | undefined;
}
& TTypeConfig
>;
Expand All @@ -77,6 +97,8 @@ export type ColumnBuilderRuntimeConfig<TData, TRuntimeConfig extends object = ob
uniqueType: string | undefined;
dataType: string;
columnType: string;
generated: GeneratedColumnConfig<TData> | undefined;
generatedIdentity: GeneratedIdentityConfig | undefined;
} & TRuntimeConfig;

export interface ColumnBuilderExtraConfig {
Expand All @@ -101,6 +123,24 @@ export type $Type<T extends ColumnBuilderBase, TType> = T & {
};
};

export type HasGenerated<T extends ColumnBuilderBase, TGenerated extends {} = {}> = T & {
_: {
hasDefault: true;
generated: TGenerated;
};
};

export type IsIdentityByDefault<
T extends ColumnBuilderBase,
TType extends 'always' | 'byDefault',
> = T & {
_: {
notNull: true;
hasDefault: true;
generated: { as: any; type: TType };
};
};

export interface ColumnBuilderBase<
T extends ColumnBuilderBaseConfig<ColumnDataType, string> = ColumnBuilderBaseConfig<ColumnDataType, string>,
TTypeConfig extends object = object,
Expand Down Expand Up @@ -133,6 +173,7 @@ export abstract class ColumnBuilder<
uniqueType: undefined,
dataType,
columnType,
generated: undefined,
} as ColumnBuilderRuntimeConfig<T['data'], TRuntimeConfig>;
}

Expand Down Expand Up @@ -223,6 +264,11 @@ export abstract class ColumnBuilder<
this.config.notNull = true;
return this as TExtraConfig['primaryKeyHasDefault'] extends true ? HasDefault<NotNull<this>> : NotNull<this>;
}

abstract generatedAlwaysAs(
as: SQL | T['data'] | (() => SQL),
config?: Partial<GeneratedColumnConfig<unknown>>,
): HasGenerated<this>;
}

export type BuildColumn<
Expand Down
18 changes: 17 additions & 1 deletion drizzle-orm/src/column.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, ColumnDataType } from './column-builder.ts';
import type {
ColumnBuilderBaseConfig,
ColumnBuilderRuntimeConfig,
ColumnDataType,
GeneratedColumnConfig,
GeneratedIdentityConfig,
} from './column-builder.ts';
import { entityKind } from './entity.ts';
import type { DriverValueMapper, SQL, SQLWrapper } from './sql/sql.ts';
import type { Table } from './table.ts';
Expand All @@ -25,6 +31,7 @@ export type ColumnTypeConfig<T extends ColumnBaseConfig<ColumnDataType, string>,
hasDefault: T['hasDefault'];
enumValues: T['enumValues'];
baseColumn: T extends { baseColumn: infer U } ? U : unknown;
generated: GeneratedColumnConfig<T['data']> | undefined;
} & TTypeConfig;

export type ColumnRuntimeConfig<TData, TRuntimeConfig extends object> = ColumnBuilderRuntimeConfig<
Expand Down Expand Up @@ -68,6 +75,8 @@ export abstract class Column<
readonly dataType: T['dataType'];
readonly columnType: T['columnType'];
readonly enumValues: T['enumValues'] = undefined;
readonly generated: GeneratedColumnConfig<T['data']> | undefined = undefined;
readonly generatedIdentity: GeneratedIdentityConfig | undefined = undefined;

protected config: ColumnRuntimeConfig<T['data'], TRuntimeConfig>;

Expand All @@ -88,6 +97,8 @@ export abstract class Column<
this.uniqueType = config.uniqueType;
this.dataType = config.dataType as T['dataType'];
this.columnType = config.columnType;
this.generated = config.generated;
this.generatedIdentity = config.generatedIdentity;
}

abstract getSQLType(): string;
Expand All @@ -99,6 +110,11 @@ export abstract class Column<
mapToDriverValue(value: unknown): unknown {
return value;
}

// ** @internal */
shouldDisableInsert(): boolean {
return this.config.generatedIdentity !== undefined && this.config.generatedIdentity.type !== 'byDefault';
}
}

export type UpdateColConfig<
Expand Down
2 changes: 2 additions & 0 deletions drizzle-orm/src/mysql-core/columns/bigint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlBigInt53BuilderInitial<TName extends string> = MySqlBigInt53Bui
data: number;
driverParam: number | string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlBigInt53Builder<T extends ColumnBuilderBaseConfig<'number', 'MySqlBigInt53'>>
Expand Down Expand Up @@ -58,6 +59,7 @@ export type MySqlBigInt64BuilderInitial<TName extends string> = MySqlBigInt64Bui
data: bigint;
driverParam: string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlBigInt64Builder<T extends ColumnBuilderBaseConfig<'bigint', 'MySqlBigInt64'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/binary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlBinaryBuilderInitial<TName extends string> = MySqlBinaryBuilder
data: string;
driverParam: string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlBinaryBuilder<T extends ColumnBuilderBaseConfig<'string', 'MySqlBinary'>> extends MySqlColumnBuilder<
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/boolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlBooleanBuilderInitial<TName extends string> = MySqlBooleanBuild
data: boolean;
driverParam: number | boolean;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlBooleanBuilder<T extends ColumnBuilderBaseConfig<'boolean', 'MySqlBoolean'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/char.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type MySqlCharBuilderInitial<TName extends string, TEnum extends [string,
data: TEnum[number];
driverParam: number | string;
enumValues: TEnum;
generated: undefined;
}>;

export class MySqlCharBuilder<T extends ColumnBuilderBaseConfig<'string', 'MySqlChar'>> extends MySqlColumnBuilder<
Expand Down
15 changes: 15 additions & 0 deletions drizzle-orm/src/mysql-core/columns/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
ColumnBuilderRuntimeConfig,
ColumnDataType,
HasDefault,
HasGenerated,
MakeColumnConfig,
} from '~/column-builder.ts';
import type { ColumnBaseConfig } from '~/column.ts';
Expand All @@ -14,6 +15,7 @@ import { entityKind } from '~/entity.ts';
import type { ForeignKey, UpdateDeleteAction } from '~/mysql-core/foreign-keys.ts';
import { ForeignKeyBuilder } from '~/mysql-core/foreign-keys.ts';
import type { AnyMySqlTable, MySqlTable } from '~/mysql-core/table.ts';
import type { SQL } from '~/sql/sql.ts';
import type { Update } from '~/utils.ts';
import { uniqueKeyName } from '../unique-constraint.ts';

Expand All @@ -30,6 +32,10 @@ export interface MySqlColumnBuilderBase<
TTypeConfig extends object = object,
> extends ColumnBuilderBase<T, TTypeConfig & { dialect: 'mysql' }> {}

export interface MySqlGeneratedColumnConfig {
mode?: 'virtual' | 'stored';
}

export abstract class MySqlColumnBuilder<
T extends ColumnBuilderBaseConfig<ColumnDataType, string> = ColumnBuilderBaseConfig<ColumnDataType, string> & {
data: any;
Expand All @@ -55,6 +61,15 @@ export abstract class MySqlColumnBuilder<
return this;
}

generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: MySqlGeneratedColumnConfig): HasGenerated<this> {
this.config.generated = {
as,
type: 'always',
mode: config?.mode ?? 'virtual',
};
return this as any;
}

/** @internal */
buildForeignKeys(column: MySqlColumn, table: MySqlTable): ForeignKey[] {
return this.foreignKeyConfigs.map(({ ref, actions }) => {
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type ConvertCustomConfig<TName extends string, T extends Partial<CustomTy
data: T['data'];
driverParam: T['driverData'];
enumValues: undefined;
generated: undefined;
}
& (T['notNull'] extends true ? { notNull: true } : {})
& (T['default'] extends true ? { hasDefault: true } : {});
Expand Down
2 changes: 2 additions & 0 deletions drizzle-orm/src/mysql-core/columns/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type MySqlDateBuilderInitial<TName extends string> = MySqlDateBuilder<{
data: Date;
driverParam: string | number;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlDateBuilder<T extends ColumnBuilderBaseConfig<'date', 'MySqlDate'>> extends MySqlColumnBuilder<T> {
Expand Down Expand Up @@ -55,6 +56,7 @@ export type MySqlDateStringBuilderInitial<TName extends string> = MySqlDateStrin
data: string;
driverParam: string | number;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlDateStringBuilder<T extends ColumnBuilderBaseConfig<'string', 'MySqlDateString'>>
Expand Down
3 changes: 2 additions & 1 deletion drizzle-orm/src/mysql-core/columns/datetime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type MySqlDateTimeBuilderInitial<TName extends string> = MySqlDateTimeBui
data: Date;
driverParam: string | number;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlDateTimeBuilder<T extends ColumnBuilderBaseConfig<'date', 'MySqlDateTime'>>
Expand Down Expand Up @@ -68,8 +69,8 @@ export type MySqlDateTimeStringBuilderInitial<TName extends string> = MySqlDateT
columnType: 'MySqlDateTimeString';
data: string;
driverParam: string | number;

enumValues: undefined;
generated: undefined;
}>;

export class MySqlDateTimeStringBuilder<T extends ColumnBuilderBaseConfig<'string', 'MySqlDateTimeString'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/decimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlDecimalBuilderInitial<TName extends string> = MySqlDecimalBuild
data: string;
driverParam: string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlDecimalBuilder<
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/double.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlDoubleBuilderInitial<TName extends string> = MySqlDoubleBuilder
data: number;
driverParam: number | string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlDoubleBuilder<T extends ColumnBuilderBaseConfig<'number', 'MySqlDouble'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type MySqlEnumColumnBuilderInitial<TName extends string, TEnum extends [s
data: TEnum[number];
driverParam: string;
enumValues: TEnum;
generated: undefined;
}>;

export class MySqlEnumColumnBuilder<T extends ColumnBuilderBaseConfig<'string', 'MySqlEnumColumn'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/float.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlFloatBuilderInitial<TName extends string> = MySqlFloatBuilder<{
data: number;
driverParam: number | string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlFloatBuilder<T extends ColumnBuilderBaseConfig<'number', 'MySqlFloat'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/int.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlIntBuilderInitial<TName extends string> = MySqlIntBuilder<{
data: number;
driverParam: number | string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlIntBuilder<T extends ColumnBuilderBaseConfig<'number', 'MySqlInt'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlJsonBuilderInitial<TName extends string> = MySqlJsonBuilder<{
data: unknown;
driverParam: string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlJsonBuilder<T extends ColumnBuilderBaseConfig<'json', 'MySqlJson'>> extends MySqlColumnBuilder<T> {
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/mediumint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type MySqlMediumIntBuilderInitial<TName extends string> = MySqlMediumIntB
data: number;
driverParam: number | string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlMediumIntBuilder<T extends ColumnBuilderBaseConfig<'number', 'MySqlMediumInt'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/real.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type MySqlRealBuilderInitial<TName extends string> = MySqlRealBuilder<{
data: number;
driverParam: number | string;
enumValues: undefined;
generated: undefined;
}>;

export class MySqlRealBuilder<T extends ColumnBuilderBaseConfig<'number', 'MySqlReal'>>
Expand Down
1 change: 1 addition & 0 deletions drizzle-orm/src/mysql-core/columns/serial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type MySqlSerialBuilderInitial<TName extends string> = NotNull<
data: number;
driverParam: number;
enumValues: undefined;
generated: undefined;
}>
>
>;
Expand Down
Loading

0 comments on commit 3245641

Please sign in to comment.