From 443df39fc5ae042950eae1bf8585df56b1f5cb8b Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 23 Jul 2024 15:52:40 +0100 Subject: [PATCH 001/152] created singlestore-core and singlestore driver --- drizzle-orm/src/singlestore-core/alias.ts | 11 + drizzle-orm/src/singlestore-core/checks.ts | 32 + .../src/singlestore-core/columns/bigint.ts | 115 ++ .../src/singlestore-core/columns/binary.ts | 58 + .../src/singlestore-core/columns/boolean.ts | 54 + .../src/singlestore-core/columns/char.ts | 64 + .../src/singlestore-core/columns/common.ts | 151 +++ .../src/singlestore-core/columns/custom.ts | 221 +++ .../singlestore-core/columns/date.common.ts | 42 + .../src/singlestore-core/columns/date.ts | 110 ++ .../src/singlestore-core/columns/datetime.ts | 132 ++ .../src/singlestore-core/columns/decimal.ts | 68 + .../src/singlestore-core/columns/double.ts | 65 + .../src/singlestore-core/columns/enum.ts | 61 + .../src/singlestore-core/columns/float.ts | 44 + .../src/singlestore-core/columns/index.ts | 25 + .../src/singlestore-core/columns/int.ts | 58 + .../src/singlestore-core/columns/json.ts | 46 + .../src/singlestore-core/columns/mediumint.ts | 61 + .../src/singlestore-core/columns/real.ts | 66 + .../src/singlestore-core/columns/serial.ts | 71 + .../src/singlestore-core/columns/smallint.ts | 61 + .../src/singlestore-core/columns/text.ts | 84 ++ .../src/singlestore-core/columns/time.ts | 58 + .../src/singlestore-core/columns/timestamp.ts | 121 ++ .../src/singlestore-core/columns/tinyint.ts | 58 + .../src/singlestore-core/columns/varbinary.ts | 60 + .../src/singlestore-core/columns/varchar.ts | 67 + .../src/singlestore-core/columns/year.ts | 44 + drizzle-orm/src/singlestore-core/db.ts | 513 +++++++ drizzle-orm/src/singlestore-core/dialect.ts | 1077 +++++++++++++++ .../src/singlestore-core/expressions.ts | 25 + .../src/singlestore-core/foreign-keys.ts | 125 ++ drizzle-orm/src/singlestore-core/index.ts | 17 + drizzle-orm/src/singlestore-core/indexes.ts | 108 ++ .../src/singlestore-core/primary-keys.ts | 63 + .../singlestore-core/query-builders/delete.ts | 170 +++ .../singlestore-core/query-builders/index.ts | 6 + .../singlestore-core/query-builders/insert.ts | 296 ++++ .../query-builders/query-builder.ts | 103 ++ .../singlestore-core/query-builders/query.ts | 157 +++ .../singlestore-core/query-builders/select.ts | 1195 +++++++++++++++++ .../query-builders/select.types.ts | 432 ++++++ .../singlestore-core/query-builders/update.ts | 209 +++ drizzle-orm/src/singlestore-core/schema.ts | 40 + drizzle-orm/src/singlestore-core/session.ts | 149 ++ drizzle-orm/src/singlestore-core/subquery.ts | 17 + drizzle-orm/src/singlestore-core/table.ts | 131 ++ .../src/singlestore-core/unique-constraint.ts | 64 + drizzle-orm/src/singlestore-core/utils.ts | 68 + drizzle-orm/src/singlestore-core/view-base.ts | 15 + .../src/singlestore-core/view-common.ts | 1 + drizzle-orm/src/singlestore-core/view.ts | 208 +++ drizzle-orm/src/singlestore/driver.ts | 99 ++ drizzle-orm/src/singlestore/index.ts | 2 + drizzle-orm/src/singlestore/migrator.ts | 11 + drizzle-orm/src/singlestore/session.ts | 337 +++++ 57 files changed, 7746 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/alias.ts create mode 100644 drizzle-orm/src/singlestore-core/checks.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/bigint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/binary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/boolean.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/char.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/custom.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/datetime.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/decimal.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/double.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/enum.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/float.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/index.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/int.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/json.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/mediumint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/real.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/serial.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/smallint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/text.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/time.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/timestamp.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/tinyint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varbinary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varchar.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/year.ts create mode 100644 drizzle-orm/src/singlestore-core/db.ts create mode 100644 drizzle-orm/src/singlestore-core/dialect.ts create mode 100644 drizzle-orm/src/singlestore-core/expressions.ts create mode 100644 drizzle-orm/src/singlestore-core/foreign-keys.ts create mode 100644 drizzle-orm/src/singlestore-core/index.ts create mode 100644 drizzle-orm/src/singlestore-core/indexes.ts create mode 100644 drizzle-orm/src/singlestore-core/primary-keys.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/delete.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/index.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/insert.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query-builder.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.types.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/update.ts create mode 100644 drizzle-orm/src/singlestore-core/schema.ts create mode 100644 drizzle-orm/src/singlestore-core/session.ts create mode 100644 drizzle-orm/src/singlestore-core/subquery.ts create mode 100644 drizzle-orm/src/singlestore-core/table.ts create mode 100644 drizzle-orm/src/singlestore-core/unique-constraint.ts create mode 100644 drizzle-orm/src/singlestore-core/utils.ts create mode 100644 drizzle-orm/src/singlestore-core/view-base.ts create mode 100644 drizzle-orm/src/singlestore-core/view-common.ts create mode 100644 drizzle-orm/src/singlestore-core/view.ts create mode 100644 drizzle-orm/src/singlestore/driver.ts create mode 100644 drizzle-orm/src/singlestore/index.ts create mode 100644 drizzle-orm/src/singlestore/migrator.ts create mode 100644 drizzle-orm/src/singlestore/session.ts diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts new file mode 100644 index 0000000000..8320c5533d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -0,0 +1,11 @@ +import { TableAliasProxyHandler } from '~/alias.ts'; +import type { BuildAliasTable } from './query-builders/select.types.ts'; +import type { MySqlTable } from './table.ts'; +import type { MySqlViewBase } from './view-base.ts'; + +export function alias( + table: TTable, + alias: TAlias, +): BuildAliasTable { + return new Proxy(table, new TableAliasProxyHandler(alias, false)) as any; +} diff --git a/drizzle-orm/src/singlestore-core/checks.ts b/drizzle-orm/src/singlestore-core/checks.ts new file mode 100644 index 0000000000..af9a29f6ae --- /dev/null +++ b/drizzle-orm/src/singlestore-core/checks.ts @@ -0,0 +1,32 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { MySqlTable } from './table.ts'; + +export class CheckBuilder { + static readonly [entityKind]: string = 'MySqlCheckBuilder'; + + protected brand!: 'MySqlConstraintBuilder'; + + constructor(public name: string, public value: SQL) {} + + /** @internal */ + build(table: MySqlTable): Check { + return new Check(table, this); + } +} + +export class Check { + static readonly [entityKind]: string = 'MySqlCheck'; + + readonly name: string; + readonly value: SQL; + + constructor(public table: MySqlTable, builder: CheckBuilder) { + this.name = builder.name; + this.value = builder.value; + } +} + +export function check(name: string, value: SQL): CheckBuilder { + return new CheckBuilder(name, value); +} diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts new file mode 100644 index 0000000000..ca1eedb3ff --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -0,0 +1,115 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; + +export type MySqlBigInt53BuilderInitial = MySqlBigInt53Builder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlBigInt53'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlBigInt53Builder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlBigInt53Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'number', 'MySqlBigInt53'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlBigInt53> { + return new MySqlBigInt53>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlBigInt53> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlBigInt53'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'number') { + return value; + } + return Number(value); + } +} + +export type MySqlBigInt64BuilderInitial = MySqlBigInt64Builder<{ + name: TName; + dataType: 'bigint'; + columnType: 'MySqlBigInt64'; + data: bigint; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlBigInt64Builder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlBigInt64Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'bigint', 'MySqlBigInt64'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlBigInt64> { + return new MySqlBigInt64>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlBigInt64> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlBigInt64'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + // eslint-disable-next-line unicorn/prefer-native-coercion-functions + override mapFromDriverValue(value: string): bigint { + return BigInt(value); + } +} + +interface MySqlBigIntConfig { + mode: T; + unsigned?: boolean; +} + +export function bigint( + name: TName, + config: MySqlBigIntConfig, +): TMode extends 'number' ? MySqlBigInt53BuilderInitial : MySqlBigInt64BuilderInitial; +export function bigint(name: string, config: MySqlBigIntConfig) { + if (config.mode === 'number') { + return new MySqlBigInt53Builder(name, config.unsigned); + } + return new MySqlBigInt64Builder(name, config.unsigned); +} diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts new file mode 100644 index 0000000000..87a8e0f8c9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -0,0 +1,58 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlBinaryBuilder> extends MySqlColumnBuilder< + T, + MySqlBinaryConfig +> { + static readonly [entityKind]: string = 'MySqlBinaryBuilder'; + + constructor(name: T['name'], length: number | undefined) { + super(name, 'string', 'MySqlBinary'); + this.config.length = length; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlBinary> { + return new MySqlBinary>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlBinary> extends MySqlColumn< + T, + MySqlBinaryConfig +> { + static readonly [entityKind]: string = 'MySqlBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `binary` : `binary(${this.length})`; + } +} + +export interface MySqlBinaryConfig { + length?: number; +} + +export function binary( + name: TName, + config: MySqlBinaryConfig = {}, +): MySqlBinaryBuilderInitial { + return new MySqlBinaryBuilder(name, config.length); +} diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts new file mode 100644 index 0000000000..3a915e6733 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -0,0 +1,54 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlBooleanBuilderInitial = MySqlBooleanBuilder<{ + name: TName; + dataType: 'boolean'; + columnType: 'MySqlBoolean'; + data: boolean; + driverParam: number | boolean; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlBooleanBuilder> + extends MySqlColumnBuilder +{ + static readonly [entityKind]: string = 'MySqlBooleanBuilder'; + + constructor(name: T['name']) { + super(name, 'boolean', 'MySqlBoolean'); + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlBoolean> { + return new MySqlBoolean>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlBoolean> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlBoolean'; + + getSQLType(): string { + return 'boolean'; + } + + override mapFromDriverValue(value: number | boolean): boolean { + if (typeof value === 'boolean') { + return value; + } + return value === 1; + } +} + +export function boolean(name: TName): MySqlBooleanBuilderInitial { + return new MySqlBooleanBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts new file mode 100644 index 0000000000..f871796a5d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -0,0 +1,64 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { Writable } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlCharBuilderInitial = MySqlCharBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; +}>; + +export class MySqlCharBuilder> extends MySqlColumnBuilder< + T, + MySqlCharConfig +> { + static readonly [entityKind]: string = 'MySqlCharBuilder'; + + constructor(name: T['name'], config: MySqlCharConfig) { + super(name, 'string', 'MySqlChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlChar & { enumValues: T['enumValues'] }> { + return new MySqlChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlChar> + extends MySqlColumn> +{ + static readonly [entityKind]: string = 'MySqlChar'; + + readonly length: number | undefined = this.config.length; + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `char` : `char(${this.length})`; + } +} + +export interface MySqlCharConfig { + length?: number; + enum?: TEnum; +} + +export function char>( + name: TName, + config: MySqlCharConfig> = {}, +): MySqlCharBuilderInitial> { + return new MySqlCharBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts new file mode 100644 index 0000000000..a0a192477e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -0,0 +1,151 @@ +import { ColumnBuilder } from '~/column-builder.ts'; +import type { + ColumnBuilderBase, + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnBuilderRuntimeConfig, + ColumnDataType, + HasDefault, + HasGenerated, + IsAutoincrement, + MakeColumnConfig, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { Column } from '~/column.ts'; +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'; + +export interface ReferenceConfig { + ref: () => MySqlColumn; + actions: { + onUpdate?: UpdateDeleteAction; + onDelete?: UpdateDeleteAction; + }; +} + +export interface MySqlColumnBuilderBase< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TTypeConfig extends object = object, +> extends ColumnBuilderBase {} + +export interface MySqlGeneratedColumnConfig { + mode?: 'virtual' | 'stored'; +} + +export abstract class MySqlColumnBuilder< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig & { + data: any; + }, + TRuntimeConfig extends object = object, + TTypeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends ColumnBuilder + implements MySqlColumnBuilderBase +{ + static readonly [entityKind]: string = 'MySqlColumnBuilder'; + + private foreignKeyConfigs: ReferenceConfig[] = []; + + references(ref: ReferenceConfig['ref'], actions: ReferenceConfig['actions'] = {}): this { + this.foreignKeyConfigs.push({ ref, actions }); + return this; + } + + unique(name?: string): this { + this.config.isUnique = true; + this.config.uniqueName = name; + return this; + } + + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: MySqlGeneratedColumnConfig): HasGenerated { + 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 }) => { + return ((ref, actions) => { + const builder = new ForeignKeyBuilder(() => { + const foreignColumn = ref(); + return { columns: [column], foreignColumns: [foreignColumn] }; + }); + if (actions.onUpdate) { + builder.onUpdate(actions.onUpdate); + } + if (actions.onDelete) { + builder.onDelete(actions.onDelete); + } + return builder.build(table); + })(ref, actions); + }); + } + + /** @internal */ + abstract build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlColumn>; +} + +// To understand how to use `MySqlColumn` and `AnyMySqlColumn`, see `Column` and `AnyColumn` documentation. +export abstract class MySqlColumn< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends Column { + static readonly [entityKind]: string = 'MySqlColumn'; + + constructor( + override readonly table: MySqlTable, + config: ColumnBuilderRuntimeConfig, + ) { + if (!config.uniqueName) { + config.uniqueName = uniqueKeyName(table, [config.name]); + } + super(table, config); + } +} + +export type AnyMySqlColumn> = {}> = MySqlColumn< + Required, TPartial>> +>; + +export interface MySqlColumnWithAutoIncrementConfig { + autoIncrement: boolean; +} + +export abstract class MySqlColumnBuilderWithAutoIncrement< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends MySqlColumnBuilder { + static readonly [entityKind]: string = 'MySqlColumnBuilderWithAutoIncrement'; + + constructor(name: NonNullable, dataType: T['dataType'], columnType: T['columnType']) { + super(name, dataType, columnType); + this.config.autoIncrement = false; + } + + autoincrement(): IsAutoincrement> { + this.config.autoIncrement = true; + this.config.hasDefault = true; + return this as IsAutoincrement>; + } +} + +export abstract class MySqlColumnWithAutoIncrement< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlColumnWithAutoIncrement'; + + readonly autoIncrement: boolean = this.config.autoIncrement; +} diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts new file mode 100644 index 0000000000..1c5e2603f3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -0,0 +1,221 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { Equal } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type ConvertCustomConfig> = + & { + name: TName; + dataType: 'custom'; + columnType: 'MySqlCustomColumn'; + data: T['data']; + driverParam: T['driverData']; + enumValues: undefined; + generated: undefined; + } + & (T['notNull'] extends true ? { notNull: true } : {}) + & (T['default'] extends true ? { hasDefault: true } : {}); + +export interface MySqlCustomColumnInnerConfig { + customTypeValues: CustomTypeValues; +} + +export class MySqlCustomColumnBuilder> + extends MySqlColumnBuilder< + T, + { + fieldConfig: CustomTypeValues['config']; + customTypeParams: CustomTypeParams; + }, + { + mysqlColumnBuilderBrand: 'MySqlCustomColumnBuilderBrand'; + } + > +{ + static readonly [entityKind]: string = 'MySqlCustomColumnBuilder'; + + constructor( + name: T['name'], + fieldConfig: CustomTypeValues['config'], + customTypeParams: CustomTypeParams, + ) { + super(name, 'custom', 'MySqlCustomColumn'); + this.config.fieldConfig = fieldConfig; + this.config.customTypeParams = customTypeParams; + } + + /** @internal */ + build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlCustomColumn> { + return new MySqlCustomColumn>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlCustomColumn> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlCustomColumn'; + + private sqlName: string; + private mapTo?: (value: T['data']) => T['driverParam']; + private mapFrom?: (value: T['driverParam']) => T['data']; + + constructor( + table: AnyMySqlTable<{ name: T['tableName'] }>, + config: MySqlCustomColumnBuilder['config'], + ) { + super(table, config); + this.sqlName = config.customTypeParams.dataType(config.fieldConfig); + this.mapTo = config.customTypeParams.toDriver; + this.mapFrom = config.customTypeParams.fromDriver; + } + + getSQLType(): string { + return this.sqlName; + } + + override mapFromDriverValue(value: T['driverParam']): T['data'] { + return typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data']; + } + + override mapToDriverValue(value: T['data']): T['driverParam'] { + return typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data']; + } +} + +export type CustomTypeValues = { + /** + * Required type for custom column, that will infer proper type model + * + * Examples: + * + * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar` + * + * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer` + */ + data: unknown; + + /** + * Type helper, that represents what type database driver is accepting for specific database data type + */ + driverData?: unknown; + + /** + * What config type should be used for {@link CustomTypeParams} `dataType` generation + */ + config?: unknown; + + /** + * Whether the config argument should be required or not + * @default false + */ + configRequired?: boolean; + + /** + * If your custom data type should be notNull by default you can use `notNull: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + notNull?: boolean; + + /** + * If your custom data type has default you can use `default: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + default?: boolean; +}; + +export interface CustomTypeParams { + /** + * Database data type string representation, that is used for migrations + * @example + * ``` + * `jsonb`, `text` + * ``` + * + * If database data type needs additional params you can use them from `config` param + * @example + * ``` + * `varchar(256)`, `numeric(2,3)` + * ``` + * + * To make `config` be of specific type please use config generic in {@link CustomTypeValues} + * + * @example + * Usage example + * ``` + * dataType() { + * return 'boolean'; + * }, + * ``` + * Or + * ``` + * dataType(config) { + * return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`; + * } + * ``` + */ + dataType: (config: T['config'] | (Equal extends true ? never : undefined)) => string; + + /** + * Optional mapping function, between user input and driver + * @example + * For example, when using jsonb we need to map JS/TS object to string before writing to database + * ``` + * toDriver(value: TData): string { + * return JSON.stringify(value); + * } + * ``` + */ + toDriver?: (value: T['data']) => T['driverData'] | SQL; + + /** + * Optional mapping function, that is responsible for data mapping from database to JS/TS code + * @example + * For example, when using timestamp we need to map string Date representation to JS Date + * ``` + * fromDriver(value: string): Date { + * return new Date(value); + * }, + * ``` + */ + fromDriver?: (value: T['driverData']) => T['data']; +} + +/** + * Custom mysql database data type generator + */ +export function customType( + customTypeParams: CustomTypeParams, +): Equal extends true ? ( + dbName: TName, + fieldConfig: T['config'], + ) => MySqlCustomColumnBuilder> + : ( + dbName: TName, + fieldConfig?: T['config'], + ) => MySqlCustomColumnBuilder> +{ + return ( + dbName: TName, + fieldConfig?: T['config'], + ): MySqlCustomColumnBuilder> => { + return new MySqlCustomColumnBuilder(dbName as ConvertCustomConfig['name'], fieldConfig, customTypeParams); + }; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts new file mode 100644 index 0000000000..3fd8aa6124 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -0,0 +1,42 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnDataType, + HasDefault, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import { sql } from '~/sql/sql.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export interface MySqlDateColumnBaseConfig { + hasOnUpdateNow: boolean; +} + +export abstract class MySqlDateColumnBaseBuilder< + T extends ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends MySqlColumnBuilder { + static readonly [entityKind]: string = 'MySqlDateColumnBuilder'; + + defaultNow() { + return this.default(sql`(now())`); + } + + // "on update now" also adds an implicit default value to the column - https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html + onUpdateNow(): HasDefault { + this.config.hasOnUpdateNow = true; + this.config.hasDefault = true; + return this as HasDefault; + } +} + +export abstract class MySqlDateBaseColumn< + T extends ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlDateColumn'; + + readonly hasOnUpdateNow: boolean = this.config.hasOnUpdateNow; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts new file mode 100644 index 0000000000..d7e2c409ef --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -0,0 +1,110 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { Equal } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlDateBuilderInitial = MySqlDateBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'MySqlDate'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlDateBuilder> extends MySqlColumnBuilder { + static readonly [entityKind]: string = 'MySqlDateBuilder'; + + constructor(name: T['name']) { + super(name, 'date', 'MySqlDate'); + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlDate> { + return new MySqlDate>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlDate> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlDate'; + + constructor( + table: AnyMySqlTable<{ name: T['tableName'] }>, + config: MySqlDateBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value); + } +} + +export type MySqlDateStringBuilderInitial = MySqlDateStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlDateString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlDateStringBuilder> + extends MySqlColumnBuilder +{ + static readonly [entityKind]: string = 'MySqlDateStringBuilder'; + + constructor(name: T['name']) { + super(name, 'string', 'MySqlDateString'); + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlDateString> { + return new MySqlDateString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlDateString> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlDateString'; + + constructor( + table: AnyMySqlTable<{ name: T['tableName'] }>, + config: MySqlDateStringBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } +} + +export interface MySqlDateConfig { + mode?: TMode; +} + +export function date( + name: TName, + config?: MySqlDateConfig, +): Equal extends true ? MySqlDateStringBuilderInitial : MySqlDateBuilderInitial; +export function date(name: string, config: MySqlDateConfig = {}) { + if (config.mode === 'string') { + return new MySqlDateStringBuilder(name); + } + return new MySqlDateBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts new file mode 100644 index 0000000000..040c571302 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -0,0 +1,132 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { Equal } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlDateTimeBuilderInitial = MySqlDateTimeBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'MySqlDateTime'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlDateTimeBuilder> + extends MySqlColumnBuilder +{ + static readonly [entityKind]: string = 'MySqlDateTimeBuilder'; + + constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { + super(name, 'date', 'MySqlDateTime'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlDateTime> { + return new MySqlDateTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlDateTime> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlDateTime'; + + readonly fsp: number | undefined; + + constructor( + table: AnyMySqlTable<{ name: T['tableName'] }>, + config: MySqlDateTimeBuilder['config'], + ) { + super(table, config); + this.fsp = config.fsp; + } + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `datetime${precision}`; + } + + override mapToDriverValue(value: Date): unknown { + return value.toISOString().replace('T', ' ').replace('Z', ''); + } + + override mapFromDriverValue(value: string): Date { + return new Date(value.replace(' ', 'T') + 'Z'); + } +} + +export type MySqlDateTimeStringBuilderInitial = MySqlDateTimeStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlDateTimeString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlDateTimeStringBuilder> + extends MySqlColumnBuilder +{ + static readonly [entityKind]: string = 'MySqlDateTimeStringBuilder'; + + constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { + super(name, 'string', 'MySqlDateTimeString'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlDateTimeString> { + return new MySqlDateTimeString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlDateTimeString> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlDateTimeString'; + + readonly fsp: number | undefined; + + constructor( + table: AnyMySqlTable<{ name: T['tableName'] }>, + config: MySqlDateTimeStringBuilder['config'], + ) { + super(table, config); + this.fsp = config.fsp; + } + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `datetime${precision}`; + } +} + +export type DatetimeFsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +export interface MySqlDatetimeConfig { + mode?: TMode; + fsp?: DatetimeFsp; +} + +export function datetime( + name: TName, + config?: MySqlDatetimeConfig, +): Equal extends true ? MySqlDateTimeStringBuilderInitial : MySqlDateTimeBuilderInitial; +export function datetime(name: string, config: MySqlDatetimeConfig = {}) { + if (config.mode === 'string') { + return new MySqlDateTimeStringBuilder(name, config); + } + return new MySqlDateTimeBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts new file mode 100644 index 0000000000..fa25d9cdbf --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; + +export type MySqlDecimalBuilderInitial = MySqlDecimalBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlDecimal'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlDecimalBuilder< + T extends ColumnBuilderBaseConfig<'string', 'MySqlDecimal'>, +> extends MySqlColumnBuilderWithAutoIncrement { + static readonly [entityKind]: string = 'MySqlDecimalBuilder'; + + constructor(name: T['name'], precision?: number, scale?: number) { + super(name, 'string', 'MySqlDecimal'); + this.config.precision = precision; + this.config.scale = scale; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlDecimal> { + return new MySqlDecimal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlDecimal> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlDecimal'; + + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `decimal(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + return 'decimal'; + } else { + return `decimal(${this.precision})`; + } + } +} + +export interface MySqlDecimalConfig { + precision?: number; + scale?: number; +} + +export function decimal( + name: TName, + config: MySqlDecimalConfig = {}, +): MySqlDecimalBuilderInitial { + return new MySqlDecimalBuilder(name, config.precision, config.scale); +} diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts new file mode 100644 index 0000000000..dd349cf27b --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -0,0 +1,65 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; + +export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlDouble'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlDoubleBuilder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlDoubleBuilder'; + + constructor(name: T['name'], config: MySqlDoubleConfig | undefined) { + super(name, 'number', 'MySqlDouble'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlDouble> { + return new MySqlDouble>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlDouble> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlDouble'; + + precision: number | undefined = this.config.precision; + scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `double(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + return 'double'; + } else { + return `double(${this.precision})`; + } + } +} + +export interface MySqlDoubleConfig { + precision?: number; + scale?: number; +} + +export function double( + name: TName, + config?: MySqlDoubleConfig, +): MySqlDoubleBuilderInitial { + return new MySqlDoubleBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts new file mode 100644 index 0000000000..1d8b4c1f51 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -0,0 +1,61 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { Writable } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlEnumColumnBuilderInitial = + MySqlEnumColumnBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlEnumColumn'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; + +export class MySqlEnumColumnBuilder> + extends MySqlColumnBuilder +{ + static readonly [entityKind]: string = 'MySqlEnumColumnBuilder'; + + constructor(name: T['name'], values: T['enumValues']) { + super(name, 'string', 'MySqlEnumColumn'); + this.config.enumValues = values; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlEnumColumn & { enumValues: T['enumValues'] }> { + return new MySqlEnumColumn & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlEnumColumn> + extends MySqlColumn +{ + static readonly [entityKind]: string = 'MySqlEnumColumn'; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return `enum(${this.enumValues!.map((value) => `'${value}'`).join(',')})`; + } +} + +export function mysqlEnum>( + name: TName, + values: T | Writable, +): MySqlEnumColumnBuilderInitial> { + if (values.length === 0) { + throw new Error(`You have an empty array for "${name}" enum values`); + } + + return new MySqlEnumColumnBuilder(name, values); +} diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts new file mode 100644 index 0000000000..b66f1e05a4 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -0,0 +1,44 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; + +export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlFloat'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlFloatBuilder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlFloatBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'MySqlFloat'); + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlFloat> { + return new MySqlFloat>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlFloat> extends MySqlColumnWithAutoIncrement { + static readonly [entityKind]: string = 'MySqlFloat'; + + getSQLType(): string { + return 'float'; + } +} + +export function float(name: TName): MySqlFloatBuilderInitial { + return new MySqlFloatBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts new file mode 100644 index 0000000000..b51f0fac48 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -0,0 +1,25 @@ +export * from './bigint.ts'; +export * from './binary.ts'; +export * from './boolean.ts'; +export * from './char.ts'; +export * from './common.ts'; +export * from './custom.ts'; +export * from './date.ts'; +export * from './datetime.ts'; +export * from './decimal.ts'; +export * from './double.ts'; +export * from './enum.ts'; +export * from './float.ts'; +export * from './int.ts'; +export * from './json.ts'; +export * from './mediumint.ts'; +export * from './real.ts'; +export * from './serial.ts'; +export * from './smallint.ts'; +export * from './text.ts'; +export * from './time.ts'; +export * from './timestamp.ts'; +export * from './tinyint.ts'; +export * from './varbinary.ts'; +export * from './varchar.ts'; +export * from './year.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts new file mode 100644 index 0000000000..dbfb85760a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -0,0 +1,58 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; + +export type MySqlIntBuilderInitial = MySqlIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlIntBuilder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlIntBuilder'; + + constructor(name: T['name'], config?: MySqlIntConfig) { + super(name, 'number', 'MySqlInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlInt> { + return new MySqlInt>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlInt> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlInt'; + + getSQLType(): string { + return `int${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export interface MySqlIntConfig { + unsigned?: boolean; +} + +export function int(name: TName, config?: MySqlIntConfig): MySqlIntBuilderInitial { + return new MySqlIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts new file mode 100644 index 0000000000..f30ea1534a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -0,0 +1,46 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ + name: TName; + dataType: 'json'; + columnType: 'MySqlJson'; + data: unknown; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlJsonBuilder> extends MySqlColumnBuilder { + static readonly [entityKind]: string = 'MySqlJsonBuilder'; + + constructor(name: T['name']) { + super(name, 'json', 'MySqlJson'); + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlJson> { + return new MySqlJson>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlJson> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlJson'; + + getSQLType(): string { + return 'json'; + } + + override mapToDriverValue(value: T['data']): string { + return JSON.stringify(value); + } +} + +export function json(name: TName): MySqlJsonBuilderInitial { + return new MySqlJsonBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts new file mode 100644 index 0000000000..268028b447 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -0,0 +1,61 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { MySqlIntConfig } from './int.ts'; + +export type MySqlMediumIntBuilderInitial = MySqlMediumIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlMediumInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlMediumIntBuilder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlMediumIntBuilder'; + + constructor(name: T['name'], config?: MySqlIntConfig) { + super(name, 'number', 'MySqlMediumInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlMediumInt> { + return new MySqlMediumInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlMediumInt> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlMediumInt'; + + getSQLType(): string { + return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function mediumint( + name: TName, + config?: MySqlIntConfig, +): MySqlMediumIntBuilderInitial { + return new MySqlMediumIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts new file mode 100644 index 0000000000..7dd41dda0c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -0,0 +1,66 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; + +export type MySqlRealBuilderInitial = MySqlRealBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlReal'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlRealBuilder> + extends MySqlColumnBuilderWithAutoIncrement< + T, + MySqlRealConfig + > +{ + static readonly [entityKind]: string = 'MySqlRealBuilder'; + + constructor(name: T['name'], config: MySqlRealConfig | undefined) { + super(name, 'number', 'MySqlReal'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlReal> { + return new MySqlReal>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlReal> extends MySqlColumnWithAutoIncrement< + T, + MySqlRealConfig +> { + static readonly [entityKind]: string = 'MySqlReal'; + + precision: number | undefined = this.config.precision; + scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `real(${this.precision}, ${this.scale})`; + } else if (this.precision === undefined) { + return 'real'; + } else { + return `real(${this.precision})`; + } + } +} + +export interface MySqlRealConfig { + precision?: number; + scale?: number; +} + +export function real(name: TName, config: MySqlRealConfig = {}): MySqlRealBuilderInitial { + return new MySqlRealBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts new file mode 100644 index 0000000000..0f87f0bf57 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -0,0 +1,71 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + HasDefault, + IsAutoincrement, + IsPrimaryKey, + MakeColumnConfig, + NotNull, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; + +export type MySqlSerialBuilderInitial = IsAutoincrement< + IsPrimaryKey< + NotNull< + HasDefault< + MySqlSerialBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlSerial'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; + }> + > + > + > +>; + +export class MySqlSerialBuilder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlSerialBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'MySqlSerial'); + this.config.hasDefault = true; + this.config.autoIncrement = true; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlSerial> { + return new MySqlSerial>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlSerial< + T extends ColumnBaseConfig<'number', 'MySqlSerial'>, +> extends MySqlColumnWithAutoIncrement { + static readonly [entityKind]: string = 'MySqlSerial'; + + getSQLType(): string { + return 'serial'; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function serial(name: TName): MySqlSerialBuilderInitial { + return new MySqlSerialBuilder(name) as MySqlSerialBuilderInitial; +} diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts new file mode 100644 index 0000000000..fc1dd0d552 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -0,0 +1,61 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { MySqlIntConfig } from './int.ts'; + +export type MySqlSmallIntBuilderInitial = MySqlSmallIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlSmallInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlSmallIntBuilder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlSmallIntBuilder'; + + constructor(name: T['name'], config?: MySqlIntConfig) { + super(name, 'number', 'MySqlSmallInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlSmallInt> { + return new MySqlSmallInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlSmallInt> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlSmallInt'; + + getSQLType(): string { + return `smallint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function smallint( + name: TName, + config?: MySqlIntConfig, +): MySqlSmallIntBuilderInitial { + return new MySqlSmallIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts new file mode 100644 index 0000000000..72c232e16a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -0,0 +1,84 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { Writable } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; + +export type MySqlTextBuilderInitial = MySqlTextBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlText'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; +}>; + +export class MySqlTextBuilder> extends MySqlColumnBuilder< + T, + { textType: MySqlTextColumnType; enumValues: T['enumValues'] } +> { + static readonly [entityKind]: string = 'MySqlTextBuilder'; + + constructor(name: T['name'], textType: MySqlTextColumnType, config: MySqlTextConfig) { + super(name, 'string', 'MySqlText'); + this.config.textType = textType; + this.config.enumValues = config.enum; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlText> { + return new MySqlText>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlText> + extends MySqlColumn +{ + static readonly [entityKind]: string = 'MySqlText'; + + private textType: MySqlTextColumnType = this.config.textType; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return this.textType; + } +} + +export interface MySqlTextConfig { + enum?: TEnum; +} + +export function text>( + name: TName, + config: MySqlTextConfig> = {}, +): MySqlTextBuilderInitial> { + return new MySqlTextBuilder(name, 'text', config); +} + +export function tinytext>( + name: TName, + config: MySqlTextConfig> = {}, +): MySqlTextBuilderInitial> { + return new MySqlTextBuilder(name, 'tinytext', config); +} + +export function mediumtext>( + name: TName, + config: MySqlTextConfig> = {}, +): MySqlTextBuilderInitial> { + return new MySqlTextBuilder(name, 'mediumtext', config); +} + +export function longtext>( + name: TName, + config: MySqlTextConfig> = {}, +): MySqlTextBuilderInitial> { + return new MySqlTextBuilder(name, 'longtext', config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts new file mode 100644 index 0000000000..ae2251bda8 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -0,0 +1,58 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlTime'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlTimeBuilder> extends MySqlColumnBuilder< + T, + TimeConfig +> { + static readonly [entityKind]: string = 'MySqlTimeBuilder'; + + constructor( + name: T['name'], + config: TimeConfig | undefined, + ) { + super(name, 'string', 'MySqlTime'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlTime> { + return new MySqlTime>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlTime< + T extends ColumnBaseConfig<'string', 'MySqlTime'>, +> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlTime'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `time${precision}`; + } +} + +export type TimeConfig = { + fsp?: 0 | 1 | 2 | 3 | 4 | 5 | 6; +}; + +export function time(name: TName, config?: TimeConfig): MySqlTimeBuilderInitial { + return new MySqlTimeBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts new file mode 100644 index 0000000000..24e3b26508 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -0,0 +1,121 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { Equal } from '~/utils.ts'; +import { MySqlDateBaseColumn, MySqlDateColumnBaseBuilder } from './date.common.ts'; + +export type MySqlTimestampBuilderInitial = MySqlTimestampBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'MySqlTimestamp'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlTimestampBuilder> + extends MySqlDateColumnBaseBuilder +{ + static readonly [entityKind]: string = 'MySqlTimestampBuilder'; + + constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { + super(name, 'date', 'MySqlTimestamp'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlTimestamp> { + return new MySqlTimestamp>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlTimestamp> + extends MySqlDateBaseColumn +{ + static readonly [entityKind]: string = 'MySqlTimestamp'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `timestamp${precision}`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value + '+0000'); + } + + override mapToDriverValue(value: Date): string { + return value.toISOString().slice(0, -1).replace('T', ' '); + } +} + +export type MySqlTimestampStringBuilderInitial = MySqlTimestampStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlTimestampString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlTimestampStringBuilder> + extends MySqlDateColumnBaseBuilder +{ + static readonly [entityKind]: string = 'MySqlTimestampStringBuilder'; + + constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { + super(name, 'string', 'MySqlTimestampString'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlTimestampString> { + return new MySqlTimestampString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlTimestampString> + extends MySqlDateBaseColumn +{ + static readonly [entityKind]: string = 'MySqlTimestampString'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `timestamp${precision}`; + } +} + +export type TimestampFsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +export interface MySqlTimestampConfig { + mode?: TMode; + fsp?: TimestampFsp; +} + +export function timestamp( + name: TName, + config?: MySqlTimestampConfig, +): Equal extends true ? MySqlTimestampStringBuilderInitial + : MySqlTimestampBuilderInitial; +export function timestamp(name: string, config: MySqlTimestampConfig = {}) { + if (config.mode === 'string') { + return new MySqlTimestampStringBuilder(name, config); + } + return new MySqlTimestampBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts new file mode 100644 index 0000000000..c749e6da8b --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -0,0 +1,58 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { MySqlIntConfig } from './int.ts'; + +export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlTinyInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlTinyIntBuilder> + extends MySqlColumnBuilderWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlTinyIntBuilder'; + + constructor(name: T['name'], config?: MySqlIntConfig) { + super(name, 'number', 'MySqlTinyInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlTinyInt> { + return new MySqlTinyInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlTinyInt> + extends MySqlColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'MySqlTinyInt'; + + getSQLType(): string { + return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function tinyint(name: TName, config?: MySqlIntConfig): MySqlTinyIntBuilderInitial { + return new MySqlTinyIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts new file mode 100644 index 0000000000..be0a89cf64 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -0,0 +1,60 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'MySqlVarBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlVarBinaryBuilder> + extends MySqlColumnBuilder +{ + static readonly [entityKind]: string = 'MySqlVarBinaryBuilder'; + + /** @internal */ + constructor(name: T['name'], config: MySqlVarbinaryOptions) { + super(name, 'string', 'MySqlVarBinary'); + this.config.length = config?.length; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlVarBinary> { + return new MySqlVarBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlVarBinary< + T extends ColumnBaseConfig<'string', 'MySqlVarBinary'>, +> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlVarBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `varbinary` : `varbinary(${this.length})`; + } +} + +export interface MySqlVarbinaryOptions { + length: number; +} + +export function varbinary( + name: TName, + options: MySqlVarbinaryOptions, +): MySqlVarBinaryBuilderInitial { + return new MySqlVarBinaryBuilder(name, options); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts new file mode 100644 index 0000000000..b692bf7890 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -0,0 +1,67 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { Writable } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlVarCharBuilderInitial = MySqlVarCharBuilder< + { + name: TName; + dataType: 'string'; + columnType: 'MySqlVarChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + } +>; + +export class MySqlVarCharBuilder> + extends MySqlColumnBuilder> +{ + static readonly [entityKind]: string = 'MySqlVarCharBuilder'; + + /** @internal */ + constructor(name: T['name'], config: MySqlVarCharConfig) { + super(name, 'string', 'MySqlVarChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlVarChar & { enumValues: T['enumValues'] }> { + return new MySqlVarChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class MySqlVarChar> + extends MySqlColumn> +{ + static readonly [entityKind]: string = 'MySqlVarChar'; + + readonly length: number | undefined = this.config.length; + + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `varchar` : `varchar(${this.length})`; + } +} + +export interface MySqlVarCharConfig { + length: number; + enum?: TEnum; +} + +export function varchar>( + name: TName, + config: MySqlVarCharConfig>, +): MySqlVarCharBuilderInitial> { + return new MySqlVarCharBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts new file mode 100644 index 0000000000..224de12e9f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -0,0 +1,44 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlYearBuilderInitial = MySqlYearBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'MySqlYear'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlYearBuilder> extends MySqlColumnBuilder { + static readonly [entityKind]: string = 'MySqlYearBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'MySqlYear'); + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlYear> { + return new MySqlYear>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlYear< + T extends ColumnBaseConfig<'number', 'MySqlYear'>, +> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlYear'; + + getSQLType(): string { + return `year`; + } +} + +export function year(name: TName): MySqlYearBuilderInitial { + return new MySqlYearBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts new file mode 100644 index 0000000000..8df6ff3439 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -0,0 +1,513 @@ +import type { ResultSetHeader } from 'mysql2/promise'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; +import type { MySqlDialect } from './dialect.ts'; +import { + MySqlDeleteBase, + MySqlInsertBuilder, + MySqlSelectBuilder, + MySqlUpdateBuilder, + QueryBuilder, +} from './query-builders/index.ts'; +import { RelationalQueryBuilder } from './query-builders/query.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import type { + Mode, + MySqlQueryResultHKT, + MySqlQueryResultKind, + MySqlSession, + MySqlTransaction, + MySqlTransactionConfig, + PreparedQueryHKTBase, +} from './session.ts'; +import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { MySqlTable } from './table.ts'; + +export class MySqlDatabase< + TQueryResult extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = {}, + TSchema extends TablesRelationalConfig = ExtractTablesWithRelations, +> { + static readonly [entityKind]: string = 'MySqlDatabase'; + + declare readonly _: { + readonly schema: TSchema | undefined; + readonly fullSchema: TFullSchema; + readonly tableNamesMap: Record; + }; + + query: TFullSchema extends Record + ? DrizzleTypeError<'Seems like the schema generic is missing - did you forget to add it to your DB type?'> + : { + [K in keyof TSchema]: RelationalQueryBuilder; + }; + + constructor( + /** @internal */ + readonly dialect: MySqlDialect, + /** @internal */ + readonly session: MySqlSession, + schema: RelationalSchemaConfig | undefined, + protected readonly mode: Mode, + ) { + this._ = schema + ? { + schema: schema.schema, + fullSchema: schema.fullSchema as TFullSchema, + tableNamesMap: schema.tableNamesMap, + } + : { + schema: undefined, + fullSchema: {} as TFullSchema, + tableNamesMap: {}, + }; + this.query = {} as typeof this['query']; + if (this._.schema) { + for (const [tableName, columns] of Object.entries(this._.schema)) { + (this.query as MySqlDatabase>['query'])[tableName] = + new RelationalQueryBuilder( + schema!.fullSchema, + this._.schema, + this._.tableNamesMap, + schema!.fullSchema[tableName] as MySqlTable, + columns, + dialect, + session, + this.mode, + ); + } + } + } + + /** + * Creates a subquery that defines a temporary named result set as a CTE. + * + * It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param alias The alias for the subquery. + * + * Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries. + * + * @example + * + * ```ts + * // Create a subquery with alias 'sq' and use it in the select query + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * const result = await db.with(sq).select().from(sq); + * ``` + * + * To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them: + * + * ```ts + * // Select an arbitrary SQL value as a field in a CTE and reference it in the main query + * const sq = db.$with('sq').as(db.select({ + * name: sql`upper(${users.name})`.as('name'), + * }) + * .from(users)); + * + * const result = await db.with(sq).select({ name: sq.name }).from(sq); + * ``` + */ + $with(alias: TAlias) { + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder()); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + /** + * Incorporates a previously defined CTE (using `$with`) into the main query. + * + * This method allows the main query to reference a temporary named result set. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param queries The CTEs to incorporate into the main query. + * + * @example + * + * ```ts + * // Define a subquery 'sq' as a CTE using $with + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * // Incorporate the CTE 'sq' into the main query and select from it + * const result = await db.with(sq).select().from(sq); + * ``` + */ + with(...queries: WithSubquery[]) { + const self = this; + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + function select(): MySqlSelectBuilder; + function select( + fields: TSelection, + ): MySqlSelectBuilder; + function select(fields?: SelectedFields): MySqlSelectBuilder { + return new MySqlSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + function selectDistinct(): MySqlSelectBuilder; + function selectDistinct( + fields: TSelection, + ): MySqlSelectBuilder; + function selectDistinct( + fields?: SelectedFields, + ): MySqlSelectBuilder { + return new MySqlSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + function update( + table: TTable, + ): MySqlUpdateBuilder { + return new MySqlUpdateBuilder(table, self.session, self.dialect, queries); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + function delete_( + table: TTable, + ): MySqlDeleteBase { + return new MySqlDeleteBase(table, self.session, self.dialect, queries); + } + + return { select, selectDistinct, update, delete: delete_ }; + } + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + select(): MySqlSelectBuilder; + select(fields: TSelection): MySqlSelectBuilder; + select(fields?: SelectedFields): MySqlSelectBuilder { + return new MySqlSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + selectDistinct(): MySqlSelectBuilder; + selectDistinct( + fields: TSelection, + ): MySqlSelectBuilder; + selectDistinct(fields?: SelectedFields): MySqlSelectBuilder { + return new MySqlSelectBuilder({ + fields: fields ?? undefined, + session: this.session, + dialect: this.dialect, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + update(table: TTable): MySqlUpdateBuilder { + return new MySqlUpdateBuilder(table, this.session, this.dialect); + } + + /** + * Creates an insert query. + * + * Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert. + * + * See docs: {@link https://orm.drizzle.team/docs/insert} + * + * @param table The table to insert into. + * + * @example + * + * ```ts + * // Insert one row + * await db.insert(cars).values({ brand: 'BMW' }); + * + * // Insert multiple rows + * await db.insert(cars).values([{ brand: 'BMW' }, { brand: 'Porsche' }]); + * ``` + */ + insert(table: TTable): MySqlInsertBuilder { + return new MySqlInsertBuilder(table, this.session, this.dialect); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + delete(table: TTable): MySqlDeleteBase { + return new MySqlDeleteBase(table, this.session, this.dialect); + } + + execute( + query: SQLWrapper, + ): Promise> { + return this.session.execute(query.getSQL()); + } + + transaction( + transaction: ( + tx: MySqlTransaction, + config?: MySqlTransactionConfig, + ) => Promise, + config?: MySqlTransactionConfig, + ): Promise { + return this.session.transaction(transaction, config); + } +} + +export type MySQLWithReplicas = Q & { $primary: Q }; + +export const withReplicas = < + HKT extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, + Q extends MySqlDatabase< + HKT, + TPreparedQueryHKT, + TFullSchema, + TSchema extends Record ? ExtractTablesWithRelations : TSchema + >, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): MySQLWithReplicas => { + const select: Q['select'] = (...args: []) => getReplica(replicas).select(...args); + const selectDistinct: Q['selectDistinct'] = (...args: []) => getReplica(replicas).selectDistinct(...args); + const $with: Q['with'] = (...args: []) => getReplica(replicas).with(...args); + + const update: Q['update'] = (...args: [any]) => primary.update(...args); + const insert: Q['insert'] = (...args: [any]) => primary.insert(...args); + const $delete: Q['delete'] = (...args: [any]) => primary.delete(...args); + const execute: Q['execute'] = (...args: [any]) => primary.execute(...args); + const transaction: Q['transaction'] = (...args: [any, any]) => primary.transaction(...args); + + return { + ...primary, + update, + insert, + delete: $delete, + execute, + transaction, + $primary: primary, + select, + selectDistinct, + with: $with, + get query() { + return getReplica(replicas).query; + }, + }; +}; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts new file mode 100644 index 0000000000..4a72d9c5f7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -0,0 +1,1077 @@ +import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from '~/alias.ts'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { and, eq } from '~/expressions.ts'; +import type { MigrationConfig, MigrationMeta } from '~/migrator.ts'; +import { + type BuildRelationalQueryResult, + type DBQueryConfig, + getOperators, + getOrderByOperators, + Many, + normalizeRelation, + One, + type Relation, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { Param, SQL, sql, View } from '~/sql/sql.ts'; +import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { getTableName, getTableUniqueName, Table } from '~/table.ts'; +import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { MySqlColumn } from './columns/common.ts'; +import type { MySqlDeleteConfig } from './query-builders/delete.ts'; +import type { MySqlInsertConfig } from './query-builders/insert.ts'; +import type { MySqlSelectConfig, MySqlSelectJoinConfig, SelectedFieldsOrdered } from './query-builders/select.types.ts'; +import type { MySqlUpdateConfig } from './query-builders/update.ts'; +import type { MySqlSession } from './session.ts'; +import { MySqlTable } from './table.ts'; +import { MySqlViewBase } from './view-base.ts'; + +export class MySqlDialect { + static readonly [entityKind]: string = 'MySqlDialect'; + + async migrate( + migrations: MigrationMeta[], + session: MySqlSession, + config: Omit, + ): Promise { + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await session.execute(migrationTableCreate); + + const dbMigrations = await session.all<{ id: number; hash: string; created_at: string }>( + sql`select id, hash, created_at from ${sql.identifier(migrationsTable)} order by created_at desc limit 1`, + ); + + const lastDbMigration = dbMigrations[0]; + + await session.transaction(async (tx) => { + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + for (const stmt of migration.sql) { + await tx.execute(sql.raw(stmt)); + } + await tx.execute( + sql`insert into ${ + sql.identifier(migrationsTable) + } (\`hash\`, \`created_at\`) values(${migration.hash}, ${migration.folderMillis})`, + ); + } + } + }); + } + + escapeName(name: string): string { + return `\`${name}\``; + } + + escapeParam(_num: number): string { + return `?`; + } + + escapeString(str: string): string { + return `'${str.replace(/'/g, "''")}'`; + } + + private buildWithCTE(queries: Subquery[] | undefined): SQL | undefined { + if (!queries?.length) return undefined; + + const withSqlChunks = [sql`with `]; + for (const [i, w] of queries.entries()) { + withSqlChunks.push(sql`${sql.identifier(w._.alias)} as (${w._.sql})`); + if (i < queries.length - 1) { + withSqlChunks.push(sql`, `); + } + } + withSqlChunks.push(sql` `); + return sql.join(withSqlChunks); + } + + buildDeleteQuery({ table, where, returning, withList }: MySqlDeleteConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; + } + + buildUpdateSet(table: MySqlTable, set: UpdateSet): SQL { + const tableColumns = table[Table.Symbol.Columns]; + + const columnNames = Object.keys(tableColumns).filter((colName) => + set[colName] !== undefined || tableColumns[colName]?.onUpdateFn !== undefined + ); + + const setSize = columnNames.length; + return sql.join(columnNames.flatMap((colName, i) => { + const col = tableColumns[colName]!; + + const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); + const res = sql`${sql.identifier(col.name)} = ${value}`; + + if (i < setSize - 1) { + return [res, sql.raw(', ')]; + } + return [res]; + })); + } + + buildUpdateQuery({ table, set, where, returning, withList }: MySqlUpdateConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const setSql = this.buildUpdateSet(table, set); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + } + + /** + * Builds selection SQL with provided fields/expressions + * + * Examples: + * + * `select from` + * + * `insert ... returning ` + * + * If `isSingleTable` is true, then columns won't be prefixed with table name + */ + private buildSelection( + fields: SelectedFieldsOrdered, + { isSingleTable = false }: { isSingleTable?: boolean } = {}, + ): SQL { + const columnsLen = fields.length; + + const chunks = fields + .flatMap(({ field }, i) => { + const chunk: SQLChunk[] = []; + + if (is(field, SQL.Aliased) && field.isSelectionField) { + chunk.push(sql.identifier(field.fieldAlias)); + } else if (is(field, SQL.Aliased) || is(field, SQL)) { + const query = is(field, SQL.Aliased) ? field.sql : field; + + if (isSingleTable) { + chunk.push( + new SQL( + query.queryChunks.map((c) => { + if (is(c, MySqlColumn)) { + return sql.identifier(c.name); + } + return c; + }), + ), + ); + } else { + chunk.push(query); + } + + if (is(field, SQL.Aliased)) { + chunk.push(sql` as ${sql.identifier(field.fieldAlias)}`); + } + } else if (is(field, Column)) { + if (isSingleTable) { + chunk.push(sql.identifier(field.name)); + } else { + chunk.push(field); + } + } + + if (i < columnsLen - 1) { + chunk.push(sql`, `); + } + + return chunk; + }); + + return sql.join(chunks); + } + + buildSelectQuery( + { + withList, + fields, + fieldsFlat, + where, + having, + table, + joins, + orderBy, + groupBy, + limit, + offset, + lockingClause, + distinct, + setOperators, + }: MySqlSelectConfig, + ): SQL { + const fieldsList = fieldsFlat ?? orderSelectedFields(fields); + for (const f of fieldsList) { + if ( + is(f.field, Column) + && getTableName(f.field.table) + !== (is(table, Subquery) + ? table._.alias + : is(table, MySqlViewBase) + ? table[ViewBaseConfig].name + : is(table, SQL) + ? undefined + : getTableName(table)) + && !((table) => + joins?.some(({ alias }) => + alias === (table[Table.Symbol.IsAlias] ? getTableName(table) : table[Table.Symbol.BaseName]) + ))(f.field.table) + ) { + const tableName = getTableName(f.field.table); + throw new Error( + `Your "${ + f.path.join('->') + }" field references a column "${tableName}"."${f.field.name}", but the table "${tableName}" is not part of the query! Did you forget to join it?`, + ); + } + } + + const isSingleTable = !joins || joins.length === 0; + + const withSql = this.buildWithCTE(withList); + + const distinctSql = distinct ? sql` distinct` : undefined; + + const selection = this.buildSelection(fieldsList, { isSingleTable }); + + const tableSql = (() => { + if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { + return sql`${sql.identifier(table[Table.Symbol.OriginalName])} ${sql.identifier(table[Table.Symbol.Name])}`; + } + + return table; + })(); + + const joinsArray: SQL[] = []; + + if (joins) { + for (const [index, joinMeta] of joins.entries()) { + if (index === 0) { + joinsArray.push(sql` `); + } + const table = joinMeta.table; + const lateralSql = joinMeta.lateral ? sql` lateral` : undefined; + + if (is(table, MySqlTable)) { + const tableName = table[MySqlTable.Symbol.Name]; + const tableSchema = table[MySqlTable.Symbol.Schema]; + const origTableName = table[MySqlTable.Symbol.OriginalName]; + const alias = tableName === origTableName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined + }${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else if (is(table, View)) { + const viewName = table[ViewBaseConfig].name; + const viewSchema = table[ViewBaseConfig].schema; + const origViewName = table[ViewBaseConfig].originalName; + const alias = viewName === origViewName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + viewSchema ? sql`${sql.identifier(viewSchema)}.` : undefined + }${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else { + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table} on ${joinMeta.on}`, + ); + } + if (index < joins.length - 1) { + joinsArray.push(sql` `); + } + } + } + + const joinsSql = sql.join(joinsArray); + + const whereSql = where ? sql` where ${where}` : undefined; + + const havingSql = having ? sql` having ${having}` : undefined; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + orderBySql = sql` order by ${sql.join(orderBy, sql`, `)}`; + } + + let groupBySql; + if (groupBy && groupBy.length > 0) { + groupBySql = sql` group by ${sql.join(groupBy, sql`, `)}`; + } + + const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + let lockingClausesSql; + if (lockingClause) { + const { config, strength } = lockingClause; + lockingClausesSql = sql` for ${sql.raw(strength)}`; + if (config.noWait) { + lockingClausesSql.append(sql` no wait`); + } else if (config.skipLocked) { + lockingClausesSql.append(sql` skip locked`); + } + } + + const finalQuery = + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + + if (setOperators.length > 0) { + return this.buildSetOperations(finalQuery, setOperators); + } + + return finalQuery; + } + + buildSetOperations(leftSelect: SQL, setOperators: MySqlSelectConfig['setOperators']): SQL { + const [setOperator, ...rest] = setOperators; + + if (!setOperator) { + throw new Error('Cannot pass undefined values to any set operator'); + } + + if (rest.length === 0) { + return this.buildSetOperationQuery({ leftSelect, setOperator }); + } + + // Some recursive magic here + return this.buildSetOperations( + this.buildSetOperationQuery({ leftSelect, setOperator }), + rest, + ); + } + + buildSetOperationQuery({ + leftSelect, + setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, + }: { leftSelect: SQL; setOperator: MySqlSelectConfig['setOperators'][number] }): SQL { + const leftChunk = sql`(${leftSelect.getSQL()}) `; + const rightChunk = sql`(${rightSelect.getSQL()})`; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + const orderByValues: (SQL | Name)[] = []; + + // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` + // which is invalid MySql syntax, Table from one of the SELECTs cannot be used in global ORDER clause + for (const orderByUnit of orderBy) { + if (is(orderByUnit, MySqlColumn)) { + orderByValues.push(sql.identifier(orderByUnit.name)); + } else if (is(orderByUnit, SQL)) { + for (let i = 0; i < orderByUnit.queryChunks.length; i++) { + const chunk = orderByUnit.queryChunks[i]; + + if (is(chunk, MySqlColumn)) { + orderByUnit.queryChunks[i] = sql.identifier(chunk.name); + } + } + + orderByValues.push(sql`${orderByUnit}`); + } else { + orderByValues.push(sql`${orderByUnit}`); + } + } + + orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `; + } + + const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + + const operatorChunk = sql.raw(`${type} ${isAll ? 'all ' : ''}`); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; + } + + buildInsertQuery( + { table, values, ignore, onConflict }: MySqlInsertConfig, + ): { sql: SQL; generatedIds: Record[] } { + // const isSingleValue = values.length === 1; + const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; + const columns: Record = table[Table.Symbol.Columns]; + const colEntries: [string, MySqlColumn][] = Object.entries(columns).filter(([_, col]) => + !col.shouldDisableInsert() + ); + + const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name)); + const generatedIdsResponse: Record[] = []; + + for (const [valueIndex, value] of values.entries()) { + const generatedIds: Record = {}; + + const valueList: (SQLChunk | SQL)[] = []; + for (const [fieldName, col] of colEntries) { + const colValue = value[fieldName]; + if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { + // eslint-disable-next-line unicorn/no-negated-condition + if (col.defaultFn !== undefined) { + const defaultFnResult = col.defaultFn(); + generatedIds[fieldName] = defaultFnResult; + const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); + valueList.push(defaultValue); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (!col.default && col.onUpdateFn !== undefined) { + const onUpdateFnResult = col.onUpdateFn(); + const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + valueList.push(newValue); + } else { + valueList.push(sql`default`); + } + } else { + if (col.defaultFn && is(colValue, Param)) { + generatedIds[fieldName] = colValue.value; + } + valueList.push(colValue); + } + } + + generatedIdsResponse.push(generatedIds); + valuesSqlList.push(valueList); + if (valueIndex < values.length - 1) { + valuesSqlList.push(sql`, `); + } + } + + const valuesSql = sql.join(valuesSqlList); + + const ignoreSql = ignore ? sql` ignore` : undefined; + + const onConflictSql = onConflict ? sql` on duplicate key ${onConflict}` : undefined; + + return { + sql: sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`, + generatedIds: generatedIdsResponse, + }; + } + + sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { + return sql.toQuery({ + escapeName: this.escapeName, + escapeParam: this.escapeParam, + escapeString: this.escapeString, + invokeSource, + }); + } + + buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table, + tableConfig, + queryConfig: config, + tableAlias, + nestedQueryRelation, + joinOn, + }: { + fullSchema: Record; + schema: TablesRelationalConfig; + tableNamesMap: Record; + table: MySqlTable; + tableConfig: TableRelationalConfig; + queryConfig: true | DBQueryConfig<'many', true>; + tableAlias: string; + nestedQueryRelation?: Relation; + joinOn?: SQL; + }): BuildRelationalQueryResult { + let selection: BuildRelationalQueryResult['selection'] = []; + let limit, offset, orderBy: MySqlSelectConfig['orderBy'], where; + const joins: MySqlSelectJoinConfig[] = []; + + if (config === true) { + const selectionEntries = Object.entries(tableConfig.columns); + selection = selectionEntries.map(( + [key, value], + ) => ({ + dbKey: value.name, + tsKey: key, + field: aliasedTableColumn(value as MySqlColumn, tableAlias), + relationTableTsKey: undefined, + isJson: false, + selection: [], + })); + } else { + const aliasedColumns = Object.fromEntries( + Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]), + ); + + if (config.where) { + const whereSql = typeof config.where === 'function' + ? config.where(aliasedColumns, getOperators()) + : config.where; + where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias); + } + + const fieldsSelection: { tsKey: string; value: MySqlColumn | SQL.Aliased }[] = []; + let selectedColumns: string[] = []; + + // Figure out which columns to select + if (config.columns) { + let isIncludeMode = false; + + for (const [field, value] of Object.entries(config.columns)) { + if (value === undefined) { + continue; + } + + if (field in tableConfig.columns) { + if (!isIncludeMode && value === true) { + isIncludeMode = true; + } + selectedColumns.push(field); + } + } + + if (selectedColumns.length > 0) { + selectedColumns = isIncludeMode + ? selectedColumns.filter((c) => config.columns?.[c] === true) + : Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key)); + } + } else { + // Select all columns if selection is not specified + selectedColumns = Object.keys(tableConfig.columns); + } + + for (const field of selectedColumns) { + const column = tableConfig.columns[field]! as MySqlColumn; + fieldsSelection.push({ tsKey: field, value: column }); + } + + let selectedRelations: { + tsKey: string; + queryConfig: true | DBQueryConfig<'many', false>; + relation: Relation; + }[] = []; + + // Figure out which relations to select + if (config.with) { + selectedRelations = Object.entries(config.with) + .filter((entry): entry is [typeof entry[0], NonNullable] => !!entry[1]) + .map(([tsKey, queryConfig]) => ({ tsKey, queryConfig, relation: tableConfig.relations[tsKey]! })); + } + + let extras; + + // Figure out which extras to select + if (config.extras) { + extras = typeof config.extras === 'function' + ? config.extras(aliasedColumns, { sql }) + : config.extras; + for (const [tsKey, value] of Object.entries(extras)) { + fieldsSelection.push({ + tsKey, + value: mapColumnsInAliasedSQLToAlias(value, tableAlias), + }); + } + } + + // Transform `fieldsSelection` into `selection` + // `fieldsSelection` shouldn't be used after this point + for (const { tsKey, value } of fieldsSelection) { + selection.push({ + dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey]!.name, + tsKey, + field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value, + relationTableTsKey: undefined, + isJson: false, + selection: [], + }); + } + + let orderByOrig = typeof config.orderBy === 'function' + ? config.orderBy(aliasedColumns, getOrderByOperators()) + : config.orderBy ?? []; + if (!Array.isArray(orderByOrig)) { + orderByOrig = [orderByOrig]; + } + orderBy = orderByOrig.map((orderByValue) => { + if (is(orderByValue, Column)) { + return aliasedTableColumn(orderByValue, tableAlias) as MySqlColumn; + } + return mapColumnsInSQLToAlias(orderByValue, tableAlias); + }); + + limit = config.limit; + offset = config.offset; + + // Process all relations + for ( + const { + tsKey: selectedRelationTsKey, + queryConfig: selectedRelationConfigValue, + relation, + } of selectedRelations + ) { + const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation); + const relationTableName = getTableUniqueName(relation.referencedTable); + const relationTableTsName = tableNamesMap[relationTableName]!; + const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`; + const joinOn = and( + ...normalizedRelation.fields.map((field, i) => + eq( + aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias), + aliasedTableColumn(field, tableAlias), + ) + ), + ); + const builtRelation = this.buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table: fullSchema[relationTableTsName] as MySqlTable, + tableConfig: schema[relationTableTsName]!, + queryConfig: is(relation, One) + ? (selectedRelationConfigValue === true + ? { limit: 1 } + : { ...selectedRelationConfigValue, limit: 1 }) + : selectedRelationConfigValue, + tableAlias: relationTableAlias, + joinOn, + nestedQueryRelation: relation, + }); + const field = sql`${sql.identifier(relationTableAlias)}.${sql.identifier('data')}`.as(selectedRelationTsKey); + joins.push({ + on: sql`true`, + table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias), + alias: relationTableAlias, + joinType: 'left', + lateral: true, + }); + selection.push({ + dbKey: selectedRelationTsKey, + tsKey: selectedRelationTsKey, + field, + relationTableTsKey: relationTableTsName, + isJson: true, + selection: builtRelation.selection, + }); + } + } + + if (selection.length === 0) { + throw new DrizzleError({ message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")` }); + } + + let result; + + where = and(joinOn, where); + + if (nestedQueryRelation) { + let field = sql`json_array(${ + sql.join( + selection.map(({ field, tsKey, isJson }) => + isJson + ? sql`${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` + : is(field, SQL.Aliased) + ? field.sql + : field + ), + sql`, `, + ) + })`; + if (is(nestedQueryRelation, Many)) { + field = sql`coalesce(json_arrayagg(${field}), json_array())`; + } + const nestedSelection = [{ + dbKey: 'data', + tsKey: 'data', + field: field.as('data'), + isJson: true, + relationTableTsKey: tableConfig.tsName, + selection, + }]; + + const needsSubquery = limit !== undefined || offset !== undefined || (orderBy?.length ?? 0) > 0; + + if (needsSubquery) { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: [ + { + path: [], + field: sql.raw('*'), + }, + ...(((orderBy?.length ?? 0) > 0) + ? [{ + path: [], + field: sql`row_number() over (order by ${sql.join(orderBy!, sql`, `)})`, + }] + : []), + ], + where, + limit, + offset, + setOperators: [], + }); + + where = undefined; + limit = undefined; + offset = undefined; + orderBy = undefined; + } else { + result = aliasedTable(table, tableAlias); + } + + result = this.buildSelectQuery({ + table: is(result, MySqlTable) ? result : new Subquery(result, {}, tableAlias), + fields: {}, + fieldsFlat: nestedSelection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } else { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: selection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } + + return { + tableTsKey: tableConfig.tsName, + sql: result, + selection, + }; + } + + buildRelationalQueryWithoutLateralSubqueries({ + fullSchema, + schema, + tableNamesMap, + table, + tableConfig, + queryConfig: config, + tableAlias, + nestedQueryRelation, + joinOn, + }: { + fullSchema: Record; + schema: TablesRelationalConfig; + tableNamesMap: Record; + table: MySqlTable; + tableConfig: TableRelationalConfig; + queryConfig: true | DBQueryConfig<'many', true>; + tableAlias: string; + nestedQueryRelation?: Relation; + joinOn?: SQL; + }): BuildRelationalQueryResult { + let selection: BuildRelationalQueryResult['selection'] = []; + let limit, offset, orderBy: MySqlSelectConfig['orderBy'] = [], where; + + if (config === true) { + const selectionEntries = Object.entries(tableConfig.columns); + selection = selectionEntries.map(( + [key, value], + ) => ({ + dbKey: value.name, + tsKey: key, + field: aliasedTableColumn(value as MySqlColumn, tableAlias), + relationTableTsKey: undefined, + isJson: false, + selection: [], + })); + } else { + const aliasedColumns = Object.fromEntries( + Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]), + ); + + if (config.where) { + const whereSql = typeof config.where === 'function' + ? config.where(aliasedColumns, getOperators()) + : config.where; + where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias); + } + + const fieldsSelection: { tsKey: string; value: MySqlColumn | SQL.Aliased }[] = []; + let selectedColumns: string[] = []; + + // Figure out which columns to select + if (config.columns) { + let isIncludeMode = false; + + for (const [field, value] of Object.entries(config.columns)) { + if (value === undefined) { + continue; + } + + if (field in tableConfig.columns) { + if (!isIncludeMode && value === true) { + isIncludeMode = true; + } + selectedColumns.push(field); + } + } + + if (selectedColumns.length > 0) { + selectedColumns = isIncludeMode + ? selectedColumns.filter((c) => config.columns?.[c] === true) + : Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key)); + } + } else { + // Select all columns if selection is not specified + selectedColumns = Object.keys(tableConfig.columns); + } + + for (const field of selectedColumns) { + const column = tableConfig.columns[field]! as MySqlColumn; + fieldsSelection.push({ tsKey: field, value: column }); + } + + let selectedRelations: { + tsKey: string; + queryConfig: true | DBQueryConfig<'many', false>; + relation: Relation; + }[] = []; + + // Figure out which relations to select + if (config.with) { + selectedRelations = Object.entries(config.with) + .filter((entry): entry is [typeof entry[0], NonNullable] => !!entry[1]) + .map(([tsKey, queryConfig]) => ({ tsKey, queryConfig, relation: tableConfig.relations[tsKey]! })); + } + + let extras; + + // Figure out which extras to select + if (config.extras) { + extras = typeof config.extras === 'function' + ? config.extras(aliasedColumns, { sql }) + : config.extras; + for (const [tsKey, value] of Object.entries(extras)) { + fieldsSelection.push({ + tsKey, + value: mapColumnsInAliasedSQLToAlias(value, tableAlias), + }); + } + } + + // Transform `fieldsSelection` into `selection` + // `fieldsSelection` shouldn't be used after this point + for (const { tsKey, value } of fieldsSelection) { + selection.push({ + dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey]!.name, + tsKey, + field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value, + relationTableTsKey: undefined, + isJson: false, + selection: [], + }); + } + + let orderByOrig = typeof config.orderBy === 'function' + ? config.orderBy(aliasedColumns, getOrderByOperators()) + : config.orderBy ?? []; + if (!Array.isArray(orderByOrig)) { + orderByOrig = [orderByOrig]; + } + orderBy = orderByOrig.map((orderByValue) => { + if (is(orderByValue, Column)) { + return aliasedTableColumn(orderByValue, tableAlias) as MySqlColumn; + } + return mapColumnsInSQLToAlias(orderByValue, tableAlias); + }); + + limit = config.limit; + offset = config.offset; + + // Process all relations + for ( + const { + tsKey: selectedRelationTsKey, + queryConfig: selectedRelationConfigValue, + relation, + } of selectedRelations + ) { + const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation); + const relationTableName = getTableUniqueName(relation.referencedTable); + const relationTableTsName = tableNamesMap[relationTableName]!; + const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`; + const joinOn = and( + ...normalizedRelation.fields.map((field, i) => + eq( + aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias), + aliasedTableColumn(field, tableAlias), + ) + ), + ); + const builtRelation = this.buildRelationalQueryWithoutLateralSubqueries({ + fullSchema, + schema, + tableNamesMap, + table: fullSchema[relationTableTsName] as MySqlTable, + tableConfig: schema[relationTableTsName]!, + queryConfig: is(relation, One) + ? (selectedRelationConfigValue === true + ? { limit: 1 } + : { ...selectedRelationConfigValue, limit: 1 }) + : selectedRelationConfigValue, + tableAlias: relationTableAlias, + joinOn, + nestedQueryRelation: relation, + }); + let fieldSql = sql`(${builtRelation.sql})`; + if (is(relation, Many)) { + fieldSql = sql`coalesce(${fieldSql}, json_array())`; + } + const field = fieldSql.as(selectedRelationTsKey); + selection.push({ + dbKey: selectedRelationTsKey, + tsKey: selectedRelationTsKey, + field, + relationTableTsKey: relationTableTsName, + isJson: true, + selection: builtRelation.selection, + }); + } + } + + if (selection.length === 0) { + throw new DrizzleError({ + message: + `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}"). You need to have at least one item in "columns", "with" or "extras". If you need to select all columns, omit the "columns" key or set it to undefined.`, + }); + } + + let result; + + where = and(joinOn, where); + + if (nestedQueryRelation) { + let field = sql`json_array(${ + sql.join( + selection.map(({ field }) => + is(field, MySqlColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field + ), + sql`, `, + ) + })`; + if (is(nestedQueryRelation, Many)) { + field = sql`json_arrayagg(${field})`; + } + const nestedSelection = [{ + dbKey: 'data', + tsKey: 'data', + field, + isJson: true, + relationTableTsKey: tableConfig.tsName, + selection, + }]; + + const needsSubquery = limit !== undefined || offset !== undefined || orderBy.length > 0; + + if (needsSubquery) { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: [ + { + path: [], + field: sql.raw('*'), + }, + ...(orderBy.length > 0) + ? [{ + path: [], + field: sql`row_number() over (order by ${sql.join(orderBy, sql`, `)})`, + }] + : [], + ], + where, + limit, + offset, + setOperators: [], + }); + + where = undefined; + limit = undefined; + offset = undefined; + orderBy = undefined; + } else { + result = aliasedTable(table, tableAlias); + } + + result = this.buildSelectQuery({ + table: is(result, MySqlTable) ? result : new Subquery(result, {}, tableAlias), + fields: {}, + fieldsFlat: nestedSelection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } else { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: selection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } + + return { + tableTsKey: tableConfig.tsName, + sql: result, + selection, + }; + } +} diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts new file mode 100644 index 0000000000..a61f77786e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -0,0 +1,25 @@ +import { bindIfParam } from '~/expressions.ts'; +import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; +import { sql } from '~/sql/sql.ts'; +import type { MySqlColumn } from './columns/index.ts'; + +export * from '~/expressions.ts'; + +export function concat(column: MySqlColumn | SQL.Aliased, value: string | Placeholder | SQLWrapper): SQL { + return sql`${column} || ${bindIfParam(value, column)}`; +} + +export function substring( + column: MySqlColumn | SQL.Aliased, + { from, for: _for }: { from?: number | Placeholder | SQLWrapper; for?: number | Placeholder | SQLWrapper }, +): SQL { + const chunks: SQLChunk[] = [sql`substring(`, column]; + if (from !== undefined) { + chunks.push(sql` from `, bindIfParam(from, column)); + } + if (_for !== undefined) { + chunks.push(sql` for `, bindIfParam(_for, column)); + } + chunks.push(sql`)`); + return sql.join(chunks); +} diff --git a/drizzle-orm/src/singlestore-core/foreign-keys.ts b/drizzle-orm/src/singlestore-core/foreign-keys.ts new file mode 100644 index 0000000000..957e1f15cb --- /dev/null +++ b/drizzle-orm/src/singlestore-core/foreign-keys.ts @@ -0,0 +1,125 @@ +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; +import { MySqlTable } from './table.ts'; + +export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; + +export type Reference = () => { + readonly name?: string; + readonly columns: MySqlColumn[]; + readonly foreignTable: MySqlTable; + readonly foreignColumns: MySqlColumn[]; +}; + +export class ForeignKeyBuilder { + static readonly [entityKind]: string = 'MySqlForeignKeyBuilder'; + + /** @internal */ + reference: Reference; + + /** @internal */ + _onUpdate: UpdateDeleteAction | undefined; + + /** @internal */ + _onDelete: UpdateDeleteAction | undefined; + + constructor( + config: () => { + name?: string; + columns: MySqlColumn[]; + foreignColumns: MySqlColumn[]; + }, + actions?: { + onUpdate?: UpdateDeleteAction; + onDelete?: UpdateDeleteAction; + } | undefined, + ) { + this.reference = () => { + const { name, columns, foreignColumns } = config(); + return { name, columns, foreignTable: foreignColumns[0]!.table as MySqlTable, foreignColumns }; + }; + if (actions) { + this._onUpdate = actions.onUpdate; + this._onDelete = actions.onDelete; + } + } + + onUpdate(action: UpdateDeleteAction): this { + this._onUpdate = action; + return this; + } + + onDelete(action: UpdateDeleteAction): this { + this._onDelete = action; + return this; + } + + /** @internal */ + build(table: MySqlTable): ForeignKey { + return new ForeignKey(table, this); + } +} + +export type AnyForeignKeyBuilder = ForeignKeyBuilder; + +export class ForeignKey { + static readonly [entityKind]: string = 'MySqlForeignKey'; + + readonly reference: Reference; + readonly onUpdate: UpdateDeleteAction | undefined; + readonly onDelete: UpdateDeleteAction | undefined; + + constructor(readonly table: MySqlTable, builder: ForeignKeyBuilder) { + this.reference = builder.reference; + this.onUpdate = builder._onUpdate; + this.onDelete = builder._onDelete; + } + + getName(): string { + const { name, columns, foreignColumns } = this.reference(); + const columnNames = columns.map((column) => column.name); + const foreignColumnNames = foreignColumns.map((column) => column.name); + const chunks = [ + this.table[MySqlTable.Symbol.Name], + ...columnNames, + foreignColumns[0]!.table[MySqlTable.Symbol.Name], + ...foreignColumnNames, + ]; + return name ?? `${chunks.join('_')}_fk`; + } +} + +type ColumnsWithTable< + TTableName extends string, + TColumns extends MySqlColumn[], +> = { [Key in keyof TColumns]: AnyMySqlColumn<{ tableName: TTableName }> }; + +export type GetColumnsTable = ( + TColumns extends MySqlColumn ? TColumns + : TColumns extends MySqlColumn[] ? TColumns[number] + : never +) extends AnyMySqlColumn<{ tableName: infer TTableName extends string }> ? TTableName + : never; + +export function foreignKey< + TTableName extends string, + TForeignTableName extends string, + TColumns extends [AnyMySqlColumn<{ tableName: TTableName }>, ...AnyMySqlColumn<{ tableName: TTableName }>[]], +>( + config: { + name?: string; + columns: TColumns; + foreignColumns: ColumnsWithTable; + }, +): ForeignKeyBuilder { + function mappedConfig() { + const { name, columns, foreignColumns } = config; + return { + name, + columns, + foreignColumns, + }; + } + + return new ForeignKeyBuilder(mappedConfig); +} diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts new file mode 100644 index 0000000000..204e0af3c4 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -0,0 +1,17 @@ +export * from './alias.ts'; +export * from './checks.ts'; +export * from './columns/index.ts'; +export * from './db.ts'; +export * from './dialect.ts'; +export * from './foreign-keys.ts'; +export * from './indexes.ts'; +export * from './primary-keys.ts'; +export * from './query-builders/index.ts'; +export * from './schema.ts'; +export * from './session.ts'; +export * from './subquery.ts'; +export * from './table.ts'; +export * from './unique-constraint.ts'; +export * from './utils.ts'; +export * from './view-common.ts'; +export * from './view.ts'; diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts new file mode 100644 index 0000000000..5b73b1d309 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -0,0 +1,108 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; +import type { MySqlTable } from './table.ts'; + +interface IndexConfig { + name: string; + + columns: IndexColumn[]; + + /** + * If true, the index will be created as `create unique index` instead of `create index`. + */ + unique?: boolean; + + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; + + /** + * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. + */ + algorythm?: 'default' | 'inplace' | 'copy'; + + /** + * If set, adds locks to the index creation. + */ + lock?: 'default' | 'none' | 'shared' | 'exclusive'; +} + +export type IndexColumn = MySqlColumn | SQL; + +export class IndexBuilderOn { + static readonly [entityKind]: string = 'MySqlIndexBuilderOn'; + + constructor(private name: string, private unique: boolean) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): IndexBuilder { + return new IndexBuilder(this.name, columns, this.unique); + } +} + +export interface AnyIndexBuilder { + build(table: MySqlTable): Index; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface IndexBuilder extends AnyIndexBuilder {} + +export class IndexBuilder implements AnyIndexBuilder { + static readonly [entityKind]: string = 'MySqlIndexBuilder'; + + /** @internal */ + config: IndexConfig; + + constructor(name: string, columns: IndexColumn[], unique: boolean) { + this.config = { + name, + columns, + unique, + }; + } + + using(using: IndexConfig['using']): this { + this.config.using = using; + return this; + } + + algorythm(algorythm: IndexConfig['algorythm']): this { + this.config.algorythm = algorythm; + return this; + } + + lock(lock: IndexConfig['lock']): this { + this.config.lock = lock; + return this; + } + + /** @internal */ + build(table: MySqlTable): Index { + return new Index(this.config, table); + } +} + +export class Index { + static readonly [entityKind]: string = 'MySqlIndex'; + + readonly config: IndexConfig & { table: MySqlTable }; + + constructor(config: IndexConfig, table: MySqlTable) { + this.config = { ...config, table }; + } +} + +export type GetColumnsTableName = TColumns extends + AnyMySqlColumn<{ tableName: infer TTableName extends string }> | AnyMySqlColumn< + { tableName: infer TTableName extends string } + >[] ? TTableName + : never; + +export function index(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, false); +} + +export function uniqueIndex(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, true); +} diff --git a/drizzle-orm/src/singlestore-core/primary-keys.ts b/drizzle-orm/src/singlestore-core/primary-keys.ts new file mode 100644 index 0000000000..014cbd8c0b --- /dev/null +++ b/drizzle-orm/src/singlestore-core/primary-keys.ts @@ -0,0 +1,63 @@ +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; +import { MySqlTable } from './table.ts'; + +export function primaryKey< + TTableName extends string, + TColumn extends AnyMySqlColumn<{ tableName: TTableName }>, + TColumns extends AnyMySqlColumn<{ tableName: TTableName }>[], +>(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; +/** + * @deprecated: Please use primaryKey({ columns: [] }) instead of this function + * @param columns + */ +export function primaryKey< + TTableName extends string, + TColumns extends AnyMySqlColumn<{ tableName: TTableName }>[], +>(...columns: TColumns): PrimaryKeyBuilder; +export function primaryKey(...config: any) { + if (config[0].columns) { + return new PrimaryKeyBuilder(config[0].columns, config[0].name); + } + return new PrimaryKeyBuilder(config); +} + +export class PrimaryKeyBuilder { + static readonly [entityKind]: string = 'MySqlPrimaryKeyBuilder'; + + /** @internal */ + columns: MySqlColumn[]; + + /** @internal */ + name?: string; + + constructor( + columns: MySqlColumn[], + name?: string, + ) { + this.columns = columns; + this.name = name; + } + + /** @internal */ + build(table: MySqlTable): PrimaryKey { + return new PrimaryKey(table, this.columns, this.name); + } +} + +export class PrimaryKey { + static readonly [entityKind]: string = 'MySqlPrimaryKey'; + + readonly columns: MySqlColumn[]; + readonly name?: string; + + constructor(readonly table: MySqlTable, columns: MySqlColumn[], name?: string) { + this.columns = columns; + this.name = name; + } + + getName(): string { + return this.name + ?? `${this.table[MySqlTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/delete.ts b/drizzle-orm/src/singlestore-core/query-builders/delete.ts new file mode 100644 index 0000000000..e9a48da8ee --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/delete.ts @@ -0,0 +1,170 @@ +import { entityKind } from '~/entity.ts'; +import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import type { + AnyMySqlQueryResultHKT, + MySqlPreparedQueryConfig, + MySqlQueryResultHKT, + MySqlQueryResultKind, + MySqlSession, + PreparedQueryHKTBase, + PreparedQueryKind, +} from '~/mysql-core/session.ts'; +import type { MySqlTable } from '~/mysql-core/table.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export type MySqlDeleteWithout< + T extends AnyMySqlDeleteBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + MySqlDeleteBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type MySqlDelete< + TTable extends MySqlTable = MySqlTable, + TQueryResult extends MySqlQueryResultHKT = AnyMySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = MySqlDeleteBase; + +export interface MySqlDeleteConfig { + where?: SQL | undefined; + table: MySqlTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type MySqlDeletePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + MySqlPreparedQueryConfig & { + execute: MySqlQueryResultKind; + iterator: never; + }, + true +>; + +type MySqlDeleteDynamic = MySqlDelete< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnyMySqlDeleteBase = MySqlDeleteBase; + +export interface MySqlDeleteBase< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class MySqlDeleteBase< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'MySqlDelete'; + + private config: MySqlDeleteConfig; + + constructor( + private table: TTable, + private session: MySqlSession, + private dialect: MySqlDialect, + withList?: Subquery[], + ) { + super(); + this.config = { table, withList }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Delete all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Delete all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Delete all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): MySqlDeleteWithout { + this.config.where = where; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDeleteQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): MySqlDeletePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as MySqlDeletePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): MySqlDeleteDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/index.ts b/drizzle-orm/src/singlestore-core/query-builders/index.ts new file mode 100644 index 0000000000..16f0e1d4d9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/index.ts @@ -0,0 +1,6 @@ +export * from './delete.ts'; +export * from './insert.ts'; +export * from './query-builder.ts'; +export * from './select.ts'; +export * from './select.types.ts'; +export * from './update.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts new file mode 100644 index 0000000000..97e61de74c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -0,0 +1,296 @@ +import { entityKind, is } from '~/entity.ts'; +import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import type { + AnyMySqlQueryResultHKT, + MySqlPreparedQueryConfig, + MySqlQueryResultHKT, + MySqlQueryResultKind, + MySqlSession, + PreparedQueryHKTBase, + PreparedQueryKind, +} from '~/mysql-core/session.ts'; +import type { MySqlTable } from '~/mysql-core/table.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Param, SQL, sql } from '~/sql/sql.ts'; +import type { InferModelFromColumns } from '~/table.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; +import type { AnyMySqlColumn, MySqlColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; +import type { MySqlUpdateSetSource } from './update.ts'; + +export interface MySqlInsertConfig { + table: TTable; + values: Record[]; + ignore: boolean; + onConflict?: SQL; + returning?: SelectedFieldsOrdered; +} + +export type AnyMySqlInsertConfig = MySqlInsertConfig; + +export type MySqlInsertValue = + & { + [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; + } + & {}; + +export class MySqlInsertBuilder< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'MySqlInsertBuilder'; + + private shouldIgnore = false; + + constructor( + private table: TTable, + private session: MySqlSession, + private dialect: MySqlDialect, + ) {} + + ignore(): this { + this.shouldIgnore = true; + return this; + } + + values(value: MySqlInsertValue): MySqlInsertBase; + values(values: MySqlInsertValue[]): MySqlInsertBase; + values( + values: MySqlInsertValue | MySqlInsertValue[], + ): MySqlInsertBase { + values = Array.isArray(values) ? values : [values]; + if (values.length === 0) { + throw new Error('values() must be called with at least one value'); + } + const mappedValues = values.map((entry) => { + const result: Record = {}; + const cols = this.table[Table.Symbol.Columns]; + for (const colKey of Object.keys(entry)) { + const colValue = entry[colKey as keyof typeof entry]; + result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey]); + } + return result; + }); + + return new MySqlInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); + } +} + +export type MySqlInsertWithout = + TDynamic extends true ? T + : Omit< + MySqlInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | '$returning' + >, + T['_']['excludedMethods'] | K + >; + +export type MySqlInsertDynamic = MySqlInsert< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'] +>; + +export type MySqlInsertPrepare< + T extends AnyMySqlInsert, + TReturning extends Record | undefined = undefined, +> = PreparedQueryKind< + T['_']['preparedQueryHKT'], + MySqlPreparedQueryConfig & { + execute: TReturning extends undefined ? MySqlQueryResultKind : TReturning[]; + iterator: never; + }, + true +>; + +export type MySqlInsertOnDuplicateKeyUpdateConfig = { + set: MySqlUpdateSetSource; +}; + +export type MySqlInsert< + TTable extends MySqlTable = MySqlTable, + TQueryResult extends MySqlQueryResultHKT = AnyMySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TReturning extends Record | undefined = Record | undefined, +> = MySqlInsertBase; + +export type MySqlInsertReturning< + T extends AnyMySqlInsert, + TDynamic extends boolean, +> = MySqlInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + InferModelFromColumns>, + TDynamic, + T['_']['excludedMethods'] | '$returning' +>; + +export type AnyMySqlInsert = MySqlInsertBase; + +export interface MySqlInsertBase< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends + QueryPromise : TReturning[]>, + RunnableQuery : TReturning[], 'mysql'>, + SQLWrapper +{ + readonly _: { + readonly dialect: 'mysql'; + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly returning: TReturning; + readonly result: TReturning extends undefined ? MySqlQueryResultKind : TReturning[]; + }; +} + +export type PrimaryKeyKeys> = { + [K in keyof T]: T[K]['_']['isPrimaryKey'] extends true ? T[K]['_']['isAutoincrement'] extends true ? K + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never; +}[keyof T]; + +export type GetPrimarySerialOrDefaultKeys> = { + [K in PrimaryKeyKeys]: T[K]; +}; + +export class MySqlInsertBase< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TReturning extends Record | undefined = undefined, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise : TReturning[]> + implements + RunnableQuery : TReturning[], 'mysql'>, + SQLWrapper +{ + static readonly [entityKind]: string = 'MySqlInsert'; + + declare protected $table: TTable; + + private config: MySqlInsertConfig; + + constructor( + table: TTable, + values: MySqlInsertConfig['values'], + ignore: boolean, + private session: MySqlSession, + private dialect: MySqlDialect, + ) { + super(); + this.config = { table, values, ignore }; + } + + /** + * Adds an `on duplicate key update` clause to the query. + * + * Calling this method will update update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. + * + * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} + * + * @param config The `set` clause + * + * @example + * ```ts + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW'}) + * .onDuplicateKeyUpdate({ set: { brand: 'Porsche' }}); + * ``` + * + * While MySQL does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: + * + * ```ts + * import { sql } from 'drizzle-orm'; + * + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW' }) + * .onDuplicateKeyUpdate({ set: { id: sql`id` } }); + * ``` + */ + onDuplicateKeyUpdate( + config: MySqlInsertOnDuplicateKeyUpdateConfig, + ): MySqlInsertWithout { + const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); + this.config.onConflict = sql`update ${setSql}`; + return this as any; + } + + $returningId(): MySqlInsertWithout< + MySqlInsertReturning, + TDynamic, + '$returningId' + > { + const returning: SelectedFieldsOrdered = []; + for (const [key, value] of Object.entries(this.config.table[Table.Symbol.Columns])) { + if (value.primary) { + returning.push({ field: value, path: [key] }); + } + } + this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildInsertQuery(this.config).sql; + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): MySqlInsertPrepare { + const { sql, generatedIds } = this.dialect.buildInsertQuery(this.config); + return this.session.prepareQuery( + this.dialect.sqlToQuery(sql), + undefined, + undefined, + generatedIds, + this.config.returning, + ) as MySqlInsertPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): MySqlInsertDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts new file mode 100644 index 0000000000..f5d9cacc4c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts @@ -0,0 +1,103 @@ +import { entityKind } from '~/entity.ts'; +import { MySqlDialect } from '~/mysql-core/dialect.ts'; +import type { WithSubqueryWithSelection } from '~/mysql-core/subquery.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { MySqlSelectBuilder } from './select.ts'; +import type { SelectedFields } from './select.types.ts'; + +export class QueryBuilder { + static readonly [entityKind]: string = 'MySqlQueryBuilder'; + + private dialect: MySqlDialect | undefined; + + $with(alias: TAlias) { + const queryBuilder = this; + + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(queryBuilder); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + with(...queries: WithSubquery[]) { + const self = this; + + function select(): MySqlSelectBuilder; + function select( + fields: TSelection, + ): MySqlSelectBuilder; + function select( + fields?: TSelection, + ): MySqlSelectBuilder { + return new MySqlSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + }); + } + + function selectDistinct(): MySqlSelectBuilder; + function selectDistinct( + fields: TSelection, + ): MySqlSelectBuilder; + function selectDistinct( + fields?: TSelection, + ): MySqlSelectBuilder { + return new MySqlSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + distinct: true, + }); + } + + return { select, selectDistinct }; + } + + select(): MySqlSelectBuilder; + select(fields: TSelection): MySqlSelectBuilder; + select( + fields?: TSelection, + ): MySqlSelectBuilder { + return new MySqlSelectBuilder({ fields: fields ?? undefined, session: undefined, dialect: this.getDialect() }); + } + + selectDistinct(): MySqlSelectBuilder; + selectDistinct( + fields: TSelection, + ): MySqlSelectBuilder; + selectDistinct( + fields?: TSelection, + ): MySqlSelectBuilder { + return new MySqlSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + distinct: true, + }); + } + + // Lazy load dialect to avoid circular dependency + private getDialect() { + if (!this.dialect) { + this.dialect = new MySqlDialect(); + } + + return this.dialect; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts new file mode 100644 index 0000000000..955f73428b --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -0,0 +1,157 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { + type BuildQueryResult, + type BuildRelationalQueryResult, + type DBQueryConfig, + mapRelationalRow, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; +import type { KnownKeysOnly } from '~/utils.ts'; +import type { MySqlDialect } from '../dialect.ts'; +import type { + Mode, + MySqlPreparedQueryConfig, + MySqlSession, + PreparedQueryHKTBase, + PreparedQueryKind, +} from '../session.ts'; +import type { MySqlTable } from '../table.ts'; + +export class RelationalQueryBuilder< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TSchema extends TablesRelationalConfig, + TFields extends TableRelationalConfig, +> { + static readonly [entityKind]: string = 'MySqlRelationalQueryBuilder'; + + constructor( + private fullSchema: Record, + private schema: TSchema, + private tableNamesMap: Record, + private table: MySqlTable, + private tableConfig: TableRelationalConfig, + private dialect: MySqlDialect, + private session: MySqlSession, + private mode: Mode, + ) {} + + findMany>( + config?: KnownKeysOnly>, + ): MySqlRelationalQuery[]> { + return new MySqlRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? (config as DBQueryConfig<'many', true>) : {}, + 'many', + this.mode, + ); + } + + findFirst, 'limit'>>( + config?: KnownKeysOnly, 'limit'>>, + ): MySqlRelationalQuery | undefined> { + return new MySqlRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? { ...(config as DBQueryConfig<'many', true> | undefined), limit: 1 } : { limit: 1 }, + 'first', + this.mode, + ); + } +} + +export class MySqlRelationalQuery< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TResult, +> extends QueryPromise { + static readonly [entityKind]: string = 'MySqlRelationalQuery'; + + declare protected $brand: 'MySqlRelationalQuery'; + + constructor( + private fullSchema: Record, + private schema: TablesRelationalConfig, + private tableNamesMap: Record, + private table: MySqlTable, + private tableConfig: TableRelationalConfig, + private dialect: MySqlDialect, + private session: MySqlSession, + private config: DBQueryConfig<'many', true> | true, + private queryMode: 'many' | 'first', + private mode?: Mode, + ) { + super(); + } + + prepare() { + const { query, builtQuery } = this._toSQL(); + return this.session.prepareQuery( + builtQuery, + undefined, + (rawRows) => { + const rows = rawRows.map((row) => mapRelationalRow(this.schema, this.tableConfig, row, query.selection)); + if (this.queryMode === 'first') { + return rows[0] as TResult; + } + return rows as TResult; + }, + ) as PreparedQueryKind; + } + + private _getQuery() { + const query = this.mode === 'planetscale' + ? this.dialect.buildRelationalQueryWithoutLateralSubqueries({ + fullSchema: this.fullSchema, + schema: this.schema, + tableNamesMap: this.tableNamesMap, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + tableAlias: this.tableConfig.tsName, + }) + : this.dialect.buildRelationalQuery({ + fullSchema: this.fullSchema, + schema: this.schema, + tableNamesMap: this.tableNamesMap, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + tableAlias: this.tableConfig.tsName, + }); + return query; + } + + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: QueryWithTypings } { + const query = this._getQuery(); + + const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); + + return { builtQuery, query }; + } + + /** @internal */ + getSQL(): SQL { + return this._getQuery().sql as SQL; + } + + toSQL(): Query { + return this._toSQL().builtQuery; + } + + override execute(): Promise { + return this.prepare().execute(); + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts new file mode 100644 index 0000000000..a5a0ca69a0 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -0,0 +1,1195 @@ +import { entityKind, is } from '~/entity.ts'; +import type { MySqlColumn } from '~/mysql-core/columns/index.ts'; +import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import type { MySqlPreparedQueryConfig, MySqlSession, PreparedQueryHKTBase } from '~/mysql-core/session.ts'; +import type { SubqueryWithSelection } from '~/mysql-core/subquery.ts'; +import type { MySqlTable } from '~/mysql-core/table.ts'; +import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + BuildSubquerySelection, + GetSelectTableName, + GetSelectTableSelection, + JoinNullability, + JoinType, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import { SQL, View } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; +import { orderSelectedFields } from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { MySqlViewBase } from '../view-base.ts'; +import type { + AnyMySqlSelect, + CreateMySqlSelectFromBuilderMode, + GetMySqlSetOperators, + LockConfig, + LockStrength, + MySqlCreateSetOperatorFn, + MySqlJoinFn, + MySqlSelectConfig, + MySqlSelectDynamic, + MySqlSelectHKT, + MySqlSelectHKTBase, + MySqlSelectPrepare, + MySqlSelectWithout, + MySqlSetOperatorExcludedMethods, + MySqlSetOperatorWithResult, + SelectedFields, + SetOperatorRightSelect, +} from './select.types.ts'; + +export class MySqlSelectBuilder< + TSelection extends SelectedFields | undefined, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TBuilderMode extends 'db' | 'qb' = 'db', +> { + static readonly [entityKind]: string = 'MySqlSelectBuilder'; + + private fields: TSelection; + private session: MySqlSession | undefined; + private dialect: MySqlDialect; + private withList: Subquery[] = []; + private distinct: boolean | undefined; + + constructor( + config: { + fields: TSelection; + session: MySqlSession | undefined; + dialect: MySqlDialect; + withList?: Subquery[]; + distinct?: boolean; + }, + ) { + this.fields = config.fields; + this.session = config.session; + this.dialect = config.dialect; + if (config.withList) { + this.withList = config.withList; + } + this.distinct = config.distinct; + } + + from( + source: TFrom, + ): CreateMySqlSelectFromBuilderMode< + TBuilderMode, + GetSelectTableName, + TSelection extends undefined ? GetSelectTableSelection : TSelection, + TSelection extends undefined ? 'single' : 'partial', + TPreparedQueryHKT + > { + const isPartialSelect = !!this.fields; + + let fields: SelectedFields; + if (this.fields) { + fields = this.fields; + } else if (is(source, Subquery)) { + // This is required to use the proxy handler to get the correct field values from the subquery + fields = Object.fromEntries( + Object.keys(source._.selectedFields).map(( + key, + ) => [key, source[key as unknown as keyof typeof source] as unknown as SelectedFields[string]]), + ); + } else if (is(source, MySqlViewBase)) { + fields = source[ViewBaseConfig].selectedFields as SelectedFields; + } else if (is(source, SQL)) { + fields = {}; + } else { + fields = getTableColumns(source); + } + + return new MySqlSelectBase( + { + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }, + ) as any; + } +} + +export abstract class MySqlSelectQueryBuilderBase< + THKT extends MySqlSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends TypedQueryBuilder { + static readonly [entityKind]: string = 'MySqlSelectQueryBuilder'; + + override readonly _: { + readonly hkt: THKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; + + protected config: MySqlSelectConfig; + protected joinsNotNullableMap: Record; + private tableName: string | undefined; + private isPartialSelect: boolean; + /** @internal */ + readonly session: MySqlSession | undefined; + protected dialect: MySqlDialect; + + constructor( + { table, fields, isPartialSelect, session, dialect, withList, distinct }: { + table: MySqlSelectConfig['table']; + fields: MySqlSelectConfig['fields']; + isPartialSelect: boolean; + session: MySqlSession | undefined; + dialect: MySqlDialect; + withList: Subquery[]; + distinct: boolean | undefined; + }, + ) { + super(); + this.config = { + withList, + table, + fields: { ...fields }, + distinct, + setOperators: [], + }; + this.isPartialSelect = isPartialSelect; + this.session = session; + this.dialect = dialect; + this._ = { + selectedFields: fields as TSelectedFields, + } as this['_']; + this.tableName = getTableLikeName(table); + this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; + } + + private createJoin( + joinType: TJoinType, + ): MySqlJoinFn { + return ( + table: MySqlTable | Subquery | MySqlViewBase | SQL, + on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, + ) => { + const baseTableName = this.tableName; + const tableName = getTableLikeName(table); + + if (typeof tableName === 'string' && this.config.joins?.some((join) => join.alias === tableName)) { + throw new Error(`Alias "${tableName}" is already used in this query`); + } + + if (!this.isPartialSelect) { + // If this is the first join and this is not a partial select and we're not selecting from raw SQL, "move" the fields from the main table to the nested object + if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === 'string') { + this.config.fields = { + [baseTableName]: this.config.fields, + }; + } + if (typeof tableName === 'string' && !is(table, SQL)) { + const selection = is(table, Subquery) + ? table._.selectedFields + : is(table, View) + ? table[ViewBaseConfig].selectedFields + : table[Table.Symbol.Columns]; + this.config.fields[tableName] = selection; + } + } + + if (typeof on === 'function') { + on = on( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + + if (!this.config.joins) { + this.config.joins = []; + } + + this.config.joins.push({ on, table, joinType, alias: tableName }); + + if (typeof tableName === 'string') { + switch (joinType) { + case 'left': { + this.joinsNotNullableMap[tableName] = false; + break; + } + case 'right': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'inner': { + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'full': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = false; + break; + } + } + } + + return this as any; + }; + } + + /** + * Executes a `left join` operation by adding another table to the current query. + * + * Calling this method associates each row of the table with the corresponding row from the joined table, if a match is found. If no matching row exists, it sets all columns of the joined table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#left-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet | null }[] = await db.select() + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + leftJoin = this.createJoin('left'); + + /** + * Executes a `right join` operation by adding another table to the current query. + * + * Calling this method associates each row of the joined table with the corresponding row from the main table, if a match is found. If no matching row exists, it sets all columns of the main table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#right-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet }[] = await db.select() + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + rightJoin = this.createJoin('right'); + + /** + * Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values. + * + * Calling this method retrieves rows that have corresponding entries in both joined tables. Rows without matching entries in either table are excluded, resulting in a table that includes only matching pairs. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#inner-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet }[] = await db.select() + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + innerJoin = this.createJoin('inner'); + + /** + * Executes a `full join` operation by combining rows from two tables into a new table. + * + * Calling this method retrieves all rows from both main and joined tables, merging rows with matching values and filling in `null` for non-matching columns. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#full-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet | null }[] = await db.select() + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + fullJoin = this.createJoin('full'); + + private createSetOperator( + type: SetOperator, + isAll: boolean, + ): >( + rightSelection: + | ((setOperators: GetMySqlSetOperators) => SetOperatorRightSelect) + | SetOperatorRightSelect, + ) => MySqlSelectWithout< + this, + TDynamic, + MySqlSetOperatorExcludedMethods, + true + > { + return (rightSelection) => { + const rightSelect = (typeof rightSelection === 'function' + ? rightSelection(getMySqlSetOperators()) + : rightSelection) as TypedQueryBuilder< + any, + TResult + >; + + if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + + this.config.setOperators.push({ type, isAll, rightSelect }); + return this as any; + }; + } + + /** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * import { union } from 'drizzle-orm/mysql-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ + union = this.createSetOperator('union', false); + + /** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * import { unionAll } from 'drizzle-orm/mysql-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ + unionAll = this.createSetOperator('union', true); + + /** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { intersect } from 'drizzle-orm/mysql-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + intersect = this.createSetOperator('intersect', false); + + /** + * Adds `intersect all` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets including all duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect-all} + * + * @example + * + * ```ts + * // Select all products and quantities that are ordered by both regular and VIP customers + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders) + * .intersectAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * // or + * import { intersectAll } from 'drizzle-orm/mysql-core' + * + * await intersectAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ + intersectAll = this.createSetOperator('intersect', true); + + /** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { except } from 'drizzle-orm/mysql-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + except = this.createSetOperator('except', false); + + /** + * Adds `except all` set operator to the query. + * + * Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except-all} + * + * @example + * + * ```ts + * // Select all products that are ordered by regular customers but not by VIP customers + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered, + * }) + * .from(regularCustomerOrders) + * .exceptAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered, + * }) + * .from(vipCustomerOrders) + * ); + * // or + * import { exceptAll } from 'drizzle-orm/mysql-core' + * + * await exceptAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ + exceptAll = this.createSetOperator('except', true); + + /** @internal */ + addSetOperators(setOperators: MySqlSelectConfig['setOperators']): MySqlSelectWithout< + this, + TDynamic, + MySqlSetOperatorExcludedMethods, + true + > { + this.config.setOperators.push(...setOperators); + return this as any; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#filtering} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be selected. + * + * ```ts + * // Select all cars with green color + * await db.select().from(cars).where(eq(cars.color, 'green')); + * // or + * await db.select().from(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Select all BMW cars with a green color + * await db.select().from(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Select all cars with the green or blue color + * await db.select().from(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where( + where: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): MySqlSelectWithout { + if (typeof where === 'function') { + where = where( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.where = where; + return this as any; + } + + /** + * Adds a `having` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. It is typically used with aggregate functions to filter the aggregated data based on a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @param having the `having` clause. + * + * @example + * + * ```ts + * // Select all brands with more than one car + * await db.select({ + * brand: cars.brand, + * count: sql`cast(count(${cars.id}) as int)`, + * }) + * .from(cars) + * .groupBy(cars.brand) + * .having(({ count }) => gt(count, 1)); + * ``` + */ + having( + having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): MySqlSelectWithout { + if (typeof having === 'function') { + having = having( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.having = having; + return this as any; + } + + /** + * Adds a `group by` clause to the query. + * + * Calling this method will group rows that have the same values into summary rows, often used for aggregation purposes. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @example + * + * ```ts + * // Group and count people by their last names + * await db.select({ + * lastName: people.lastName, + * count: sql`cast(count(*) as int)` + * }) + * .from(people) + * .groupBy(people.lastName); + * ``` + */ + groupBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): MySqlSelectWithout; + groupBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlSelectWithout; + groupBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (MySqlColumn | SQL | SQL.Aliased)[] + ): MySqlSelectWithout { + if (typeof columns[0] === 'function') { + const groupBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy]; + } else { + this.config.groupBy = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + } + return this as any; + } + + /** + * Adds an `order by` clause to the query. + * + * Calling this method will sort the result-set in ascending or descending order. By default, the sort order is ascending. + * + * See docs: {@link https://orm.drizzle.team/docs/select#order-by} + * + * @example + * + * ``` + * // Select cars ordered by year + * await db.select().from(cars).orderBy(cars.year); + * ``` + * + * You can specify whether results are in ascending or descending order with the `asc()` and `desc()` operators. + * + * ```ts + * // Select cars ordered by year in descending order + * await db.select().from(cars).orderBy(desc(cars.year)); + * + * // Select cars ordered by year and price + * await db.select().from(cars).orderBy(asc(cars.year), desc(cars.price)); + * ``` + */ + orderBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): MySqlSelectWithout; + orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlSelectWithout; + orderBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (MySqlColumn | SQL | SQL.Aliased)[] + ): MySqlSelectWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } else { + const orderByArray = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } + return this as any; + } + + /** + * Adds a `limit` clause to the query. + * + * Calling this method will set the maximum number of rows that will be returned by this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param limit the `limit` clause. + * + * @example + * + * ```ts + * // Get the first 10 people from this query. + * await db.select().from(people).limit(10); + * ``` + */ + limit(limit: number): MySqlSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.limit = limit; + } else { + this.config.limit = limit; + } + return this as any; + } + + /** + * Adds an `offset` clause to the query. + * + * Calling this method will skip a number of rows when returning results from this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param offset the `offset` clause. + * + * @example + * + * ```ts + * // Get the 10th-20th people from this query. + * await db.select().from(people).offset(10).limit(10); + * ``` + */ + offset(offset: number): MySqlSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.offset = offset; + } else { + this.config.offset = offset; + } + return this as any; + } + + /** + * Adds a `for` clause to the query. + * + * Calling this method will specify a lock strength for this query that controls how strictly it acquires exclusive access to the rows being queried. + * + * See docs: {@link https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html} + * + * @param strength the lock strength. + * @param config the lock configuration. + */ + for(strength: LockStrength, config: LockConfig = {}): MySqlSelectWithout { + this.config.lockingClause = { strength, config }; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildSelectQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + as( + alias: TAlias, + ): SubqueryWithSelection { + return new Proxy( + new Subquery(this.getSQL(), this.config.fields, alias), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as SubqueryWithSelection; + } + + /** @internal */ + override getSelectedFields(): this['_']['selectedFields'] { + return new Proxy( + this.config.fields, + new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as this['_']['selectedFields']; + } + + $dynamic(): MySqlSelectDynamic { + return this as any; + } +} + +export interface MySqlSelectBase< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends + MySqlSelectQueryBuilderBase< + MySqlSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + QueryPromise +{} + +export class MySqlSelectBase< + TTableName extends string | undefined, + TSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> extends MySqlSelectQueryBuilderBase< + MySqlSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields +> { + static readonly [entityKind]: string = 'MySqlSelect'; + + prepare(): MySqlSelectPrepare { + if (!this.session) { + throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); + } + const fieldsList = orderSelectedFields(this.config.fields); + const query = this.session.prepareQuery< + MySqlPreparedQueryConfig & { execute: SelectResult[] }, + TPreparedQueryHKT + >(this.dialect.sqlToQuery(this.getSQL()), fieldsList); + query.joinsNotNullableMap = this.joinsNotNullableMap; + return query as MySqlSelectPrepare; + } + + execute = ((placeholderValues) => { + return this.prepare().execute(placeholderValues); + }) as ReturnType['execute']; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); +} + +applyMixins(MySqlSelectBase, [QueryPromise]); + +function createSetOperator(type: SetOperator, isAll: boolean): MySqlCreateSetOperatorFn { + return (leftSelect, rightSelect, ...restSelects) => { + const setOperators = [rightSelect, ...restSelects].map((select) => ({ + type, + isAll, + rightSelect: select as AnyMySqlSelect, + })); + + for (const setOperator of setOperators) { + if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + } + + return (leftSelect as AnyMySqlSelect).addSetOperators(setOperators) as any; + }; +} + +const getMySqlSetOperators = () => ({ + union, + unionAll, + intersect, + intersectAll, + except, + exceptAll, +}); + +/** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * import { union } from 'drizzle-orm/mysql-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ +export const union = createSetOperator('union', false); + +/** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * import { unionAll } from 'drizzle-orm/mysql-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ +export const unionAll = createSetOperator('union', true); + +/** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * import { intersect } from 'drizzle-orm/mysql-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const intersect = createSetOperator('intersect', false); + +/** + * Adds `intersect all` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets including all duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect-all} + * + * @example + * + * ```ts + * // Select all products and quantities that are ordered by both regular and VIP customers + * import { intersectAll } from 'drizzle-orm/mysql-core' + * + * await intersectAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * // or + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders) + * .intersectAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ +export const intersectAll = createSetOperator('intersect', true); + +/** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * import { except } from 'drizzle-orm/mysql-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const except = createSetOperator('except', false); + +/** + * Adds `except all` set operator to the query. + * + * Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except-all} + * + * @example + * + * ```ts + * // Select all products that are ordered by regular customers but not by VIP customers + * import { exceptAll } from 'drizzle-orm/mysql-core' + * + * await exceptAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * // or + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered, + * }) + * .from(regularCustomerOrders) + * .exceptAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered, + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ +export const exceptAll = createSetOperator('except', true); diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts new file mode 100644 index 0000000000..5f490a2d91 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -0,0 +1,432 @@ +import type { MySqlColumn } from '~/mysql-core/columns/index.ts'; +import type { MySqlTable, MySqlTableWithColumns } from '~/mysql-core/table.ts'; +import type { + SelectedFields as SelectedFieldsBase, + SelectedFieldsFlat as SelectedFieldsFlatBase, + SelectedFieldsOrdered as SelectedFieldsOrderedBase, +} from '~/operations.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + AppendToNullabilityMap, + AppendToResult, + BuildSubquerySelection, + GetSelectTableName, + JoinNullability, + JoinType, + MapColumnsToTableAlias, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import type { Table, UpdateTableConfig } from '~/table.ts'; +import type { Assume, ValidateShape } from '~/utils.ts'; +import type { MySqlPreparedQueryConfig, PreparedQueryHKTBase, PreparedQueryKind } from '../session.ts'; +import type { MySqlViewBase } from '../view-base.ts'; +import type { MySqlViewWithSelection } from '../view.ts'; +import type { MySqlSelectBase, MySqlSelectQueryBuilderBase } from './select.ts'; + +export interface MySqlSelectJoinConfig { + on: SQL | undefined; + table: MySqlTable | Subquery | MySqlViewBase | SQL; + alias: string | undefined; + joinType: JoinType; + lateral?: boolean; +} + +export type BuildAliasTable = TTable extends Table + ? MySqlTableWithColumns< + UpdateTableConfig; + }> + > + : TTable extends View ? MySqlViewWithSelection< + TAlias, + TTable['_']['existing'], + MapColumnsToTableAlias + > + : never; + +export interface MySqlSelectConfig { + withList?: Subquery[]; + fields: Record; + fieldsFlat?: SelectedFieldsOrdered; + where?: SQL; + having?: SQL; + table: MySqlTable | Subquery | MySqlViewBase | SQL; + limit?: number | Placeholder; + offset?: number | Placeholder; + joins?: MySqlSelectJoinConfig[]; + orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; + groupBy?: (MySqlColumn | SQL | SQL.Aliased)[]; + lockingClause?: { + strength: LockStrength; + config: LockConfig; + }; + distinct?: boolean; + setOperators: { + rightSelect: TypedQueryBuilder; + type: SetOperator; + isAll: boolean; + orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; + limit?: number | Placeholder; + offset?: number | Placeholder; + }[]; +} + +export type MySqlJoin< + T extends AnyMySqlSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +> = T extends any ? MySqlSelectWithout< + MySqlSelectKind< + T['_']['hkt'], + T['_']['tableName'], + AppendToResult< + T['_']['tableName'], + T['_']['selection'], + TJoinedName, + TJoinedTable extends MySqlTable ? TJoinedTable['_']['columns'] + : TJoinedTable extends Subquery ? Assume + : never, + T['_']['selectMode'] + >, + T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', + T['_']['preparedQueryHKT'], + AppendToNullabilityMap, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + T['_']['excludedMethods'] + > + : never; + +export type MySqlJoinFn< + T extends AnyMySqlSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, +> = < + TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +>( + table: TJoinedTable, + on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, +) => MySqlJoin; + +export type SelectedFieldsFlat = SelectedFieldsFlatBase; + +export type SelectedFields = SelectedFieldsBase; + +export type SelectedFieldsOrdered = SelectedFieldsOrderedBase; + +export type LockStrength = 'update' | 'share'; + +export type LockConfig = { + noWait: true; + skipLocked?: undefined; +} | { + noWait?: undefined; + skipLocked: true; +} | { + noWait?: undefined; + skipLocked?: undefined; +}; + +export interface MySqlSelectHKTBase { + tableName: string | undefined; + selection: unknown; + selectMode: SelectMode; + preparedQueryHKT: unknown; + nullabilityMap: unknown; + dynamic: boolean; + excludedMethods: string; + result: unknown; + selectedFields: unknown; + _type: unknown; +} + +export type MySqlSelectKind< + T extends MySqlSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record, + TDynamic extends boolean, + TExcludedMethods extends string, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> = (T & { + tableName: TTableName; + selection: TSelection; + selectMode: TSelectMode; + preparedQueryHKT: TPreparedQueryHKT; + nullabilityMap: TNullabilityMap; + dynamic: TDynamic; + excludedMethods: TExcludedMethods; + result: TResult; + selectedFields: TSelectedFields; +})['_type']; + +export interface MySqlSelectQueryBuilderHKT extends MySqlSelectHKTBase { + _type: MySqlSelectQueryBuilderBase< + MySqlSelectQueryBuilderHKT, + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export interface MySqlSelectHKT extends MySqlSelectHKTBase { + _type: MySqlSelectBase< + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export type MySqlSetOperatorExcludedMethods = + | 'where' + | 'having' + | 'groupBy' + | 'session' + | 'leftJoin' + | 'rightJoin' + | 'innerJoin' + | 'fullJoin' + | 'for'; + +export type MySqlSelectWithout< + T extends AnyMySqlSelectQueryBuilder, + TDynamic extends boolean, + K extends keyof T & string, + TResetExcluded extends boolean = false, +> = TDynamic extends true ? T : Omit< + MySqlSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + TDynamic, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K, + T['_']['result'], + T['_']['selectedFields'] + >, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K +>; + +export type MySqlSelectPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + MySqlPreparedQueryConfig & { + execute: T['_']['result']; + iterator: T['_']['result'][number]; + }, + true +>; + +export type MySqlSelectDynamic = MySqlSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + true, + never, + T['_']['result'], + T['_']['selectedFields'] +>; + +export type CreateMySqlSelectFromBuilderMode< + TBuilderMode extends 'db' | 'qb', + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> = TBuilderMode extends 'db' ? MySqlSelectBase + : MySqlSelectQueryBuilderBase; + +export type MySqlSelectQueryBuilder< + THKT extends MySqlSelectHKTBase = MySqlSelectQueryBuilderHKT, + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = ColumnsSelection, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, + TResult extends any[] = unknown[], + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> = MySqlSelectQueryBuilderBase< + THKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + never, + TResult, + TSelectedFields +>; + +export type AnyMySqlSelectQueryBuilder = MySqlSelectQueryBuilderBase; + +export type AnyMySqlSetOperatorInterface = MySqlSetOperatorInterface; + +export interface MySqlSetOperatorInterface< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> { + _: { + readonly hkt: MySqlSelectHKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; +} + +export type MySqlSetOperatorWithResult = MySqlSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + TResult, + any +>; + +export type MySqlSelect< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = MySqlSelectBase; + +export type AnyMySqlSelect = MySqlSelectBase; + +export type MySqlSetOperator< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, +> = MySqlSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + MySqlSetOperatorExcludedMethods +>; + +export type SetOperatorRightSelect< + TValue extends MySqlSetOperatorWithResult, + TResult extends any[], +> = TValue extends MySqlSetOperatorInterface + ? ValidateShape< + TValueResult[number], + TResult[number], + TypedQueryBuilder + > + : TValue; + +export type SetOperatorRestSelect< + TValue extends readonly MySqlSetOperatorWithResult[], + TResult extends any[], +> = TValue extends [infer First, ...infer Rest] + ? First extends MySqlSetOperatorInterface + ? Rest extends AnyMySqlSetOperatorInterface[] ? [ + ValidateShape>, + ...SetOperatorRestSelect, + ] + : ValidateShape[]> + : never + : TValue; + +export type MySqlCreateSetOperatorFn = < + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TValue extends MySqlSetOperatorWithResult, + TRest extends MySqlSetOperatorWithResult[], + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +>( + leftSelect: MySqlSetOperatorInterface< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + rightSelect: SetOperatorRightSelect, + ...restSelects: SetOperatorRestSelect +) => MySqlSelectWithout< + MySqlSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + false, + MySqlSetOperatorExcludedMethods, + true +>; + +export type GetMySqlSetOperators = { + union: MySqlCreateSetOperatorFn; + intersect: MySqlCreateSetOperatorFn; + except: MySqlCreateSetOperatorFn; + unionAll: MySqlCreateSetOperatorFn; + intersectAll: MySqlCreateSetOperatorFn; + exceptAll: MySqlCreateSetOperatorFn; +}; diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts new file mode 100644 index 0000000000..7884599cfb --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -0,0 +1,209 @@ +import type { GetColumnData } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import type { + AnyMySqlQueryResultHKT, + MySqlPreparedQueryConfig, + MySqlQueryResultHKT, + MySqlQueryResultKind, + MySqlSession, + PreparedQueryHKTBase, + PreparedQueryKind, +} from '~/mysql-core/session.ts'; +import type { MySqlTable } from '~/mysql-core/table.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import { mapUpdateSet, type UpdateSet } from '~/utils.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export interface MySqlUpdateConfig { + where?: SQL | undefined; + set: UpdateSet; + table: MySqlTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type MySqlUpdateSetSource = + & { + [Key in keyof TTable['$inferInsert']]?: + | GetColumnData + | SQL; + } + & {}; + +export class MySqlUpdateBuilder< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'MySqlUpdateBuilder'; + + declare readonly _: { + readonly table: TTable; + }; + + constructor( + private table: TTable, + private session: MySqlSession, + private dialect: MySqlDialect, + private withList?: Subquery[], + ) {} + + set(values: MySqlUpdateSetSource): MySqlUpdateBase { + return new MySqlUpdateBase(this.table, mapUpdateSet(this.table, values), this.session, this.dialect, this.withList); + } +} + +export type MySqlUpdateWithout< + T extends AnyMySqlUpdateBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T : Omit< + MySqlUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K +>; + +export type MySqlUpdatePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + MySqlPreparedQueryConfig & { + execute: MySqlQueryResultKind; + iterator: never; + }, + true +>; + +export type MySqlUpdateDynamic = MySqlUpdate< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +export type MySqlUpdate< + TTable extends MySqlTable = MySqlTable, + TQueryResult extends MySqlQueryResultHKT = AnyMySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = MySqlUpdateBase; + +export type AnyMySqlUpdateBase = MySqlUpdateBase; + +export interface MySqlUpdateBase< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class MySqlUpdateBase< + TTable extends MySqlTable, + TQueryResult extends MySqlQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'MySqlUpdate'; + + private config: MySqlUpdateConfig; + + constructor( + table: TTable, + set: UpdateSet, + private session: MySqlSession, + private dialect: MySqlDialect, + withList?: Subquery[], + ) { + super(); + this.config = { set, table, withList }; + } + + /** + * Adds a 'where' clause to the query. + * + * Calling this method will update only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param where the 'where' clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be updated. + * + * ```ts + * // Update all cars with green color + * db.update(cars).set({ color: 'red' }) + * .where(eq(cars.color, 'green')); + * // or + * db.update(cars).set({ color: 'red' }) + * .where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Update all BMW cars with a green color + * db.update(cars).set({ color: 'red' }) + * .where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Update all cars with the green or blue color + * db.update(cars).set({ color: 'red' }) + * .where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): MySqlUpdateWithout { + this.config.where = where; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildUpdateQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): MySqlUpdatePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as MySqlUpdatePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): MySqlUpdateDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts new file mode 100644 index 0000000000..b36531e44e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -0,0 +1,40 @@ +import { entityKind, is } from '~/entity.ts'; +import { type MySqlTableFn, mysqlTableWithSchema } from './table.ts'; +import { type mysqlView, mysqlViewWithSchema } from './view.ts'; + +export class MySqlSchema { + static readonly [entityKind]: string = 'MySqlSchema'; + + constructor( + public readonly schemaName: TName, + ) {} + + table: MySqlTableFn = (name, columns, extraConfig) => { + return mysqlTableWithSchema(name, columns, extraConfig, this.schemaName); + }; + + view = ((name, columns) => { + return mysqlViewWithSchema(name, columns, this.schemaName); + }) as typeof mysqlView; +} + +/** @deprecated - use `instanceof MySqlSchema` */ +export function isMySqlSchema(obj: unknown): obj is MySqlSchema { + return is(obj, MySqlSchema); +} + +/** + * Create a MySQL schema. + * https://dev.mysql.com/doc/refman/8.0/en/create-database.html + * + * @param name mysql use schema name + * @returns MySQL schema + */ +export function mysqlDatabase(name: TName) { + return new MySqlSchema(name); +} + +/** + * @see mysqlDatabase + */ +export const mysqlSchema = mysqlDatabase; diff --git a/drizzle-orm/src/singlestore-core/session.ts b/drizzle-orm/src/singlestore-core/session.ts new file mode 100644 index 0000000000..08ad1ebb68 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/session.ts @@ -0,0 +1,149 @@ +import { entityKind } from '~/entity.ts'; +import { TransactionRollbackError } from '~/errors.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { type Query, type SQL, sql } from '~/sql/sql.ts'; +import type { Assume, Equal } from '~/utils.ts'; +import { MySqlDatabase } from './db.ts'; +import type { MySqlDialect } from './dialect.ts'; +import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; + +export type Mode = 'default' | 'planetscale'; + +export interface MySqlQueryResultHKT { + readonly $brand: 'MySqlQueryResultHKT'; + readonly row: unknown; + readonly type: unknown; +} + +export interface AnyMySqlQueryResultHKT extends MySqlQueryResultHKT { + readonly type: any; +} + +export type MySqlQueryResultKind = (TKind & { + readonly row: TRow; +})['type']; + +export interface MySqlPreparedQueryConfig { + execute: unknown; + iterator: unknown; +} + +export interface MySqlPreparedQueryHKT { + readonly $brand: 'MySqlPreparedQueryHKT'; + readonly config: unknown; + readonly type: unknown; +} + +export type PreparedQueryKind< + TKind extends MySqlPreparedQueryHKT, + TConfig extends MySqlPreparedQueryConfig, + TAssume extends boolean = false, +> = Equal extends true + ? Assume<(TKind & { readonly config: TConfig })['type'], MySqlPreparedQuery> + : (TKind & { readonly config: TConfig })['type']; + +export abstract class MySqlPreparedQuery { + static readonly [entityKind]: string = 'MySqlPreparedQuery'; + + /** @internal */ + joinsNotNullableMap?: Record; + + abstract execute(placeholderValues?: Record): Promise; + + abstract iterator(placeholderValues?: Record): AsyncGenerator; +} + +export interface MySqlTransactionConfig { + withConsistentSnapshot?: boolean; + accessMode?: 'read only' | 'read write'; + isolationLevel: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable'; +} + +export abstract class MySqlSession< + TQueryResult extends MySqlQueryResultHKT = MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> { + static readonly [entityKind]: string = 'MySqlSession'; + + constructor(protected dialect: MySqlDialect) {} + + abstract prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind; + + execute(query: SQL): Promise { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + ).execute(); + } + + abstract all(query: SQL): Promise; + + abstract transaction( + transaction: (tx: MySqlTransaction) => Promise, + config?: MySqlTransactionConfig, + ): Promise; + + protected getSetTransactionSQL(config: MySqlTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.isolationLevel) { + parts.push(`isolation level ${config.isolationLevel}`); + } + + return parts.length ? sql.join(['set transaction ', parts.join(' ')]) : undefined; + } + + protected getStartTransactionSQL(config: MySqlTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.withConsistentSnapshot) { + parts.push('with consistent snapshot'); + } + + if (config.accessMode) { + parts.push(config.accessMode); + } + + return parts.length ? sql.join(['start transaction ', parts.join(' ')]) : undefined; + } +} + +export abstract class MySqlTransaction< + TQueryResult extends MySqlQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> extends MySqlDatabase { + static readonly [entityKind]: string = 'MySqlTransaction'; + + constructor( + dialect: MySqlDialect, + session: MySqlSession, + protected schema: RelationalSchemaConfig | undefined, + protected readonly nestedIndex: number, + mode: Mode, + ) { + super(dialect, session, schema, mode); + } + + rollback(): never { + throw new TransactionRollbackError(); + } + + /** Nested transactions (aka savepoints) only work with InnoDB engine. */ + abstract override transaction( + transaction: (tx: MySqlTransaction) => Promise, + ): Promise; +} + +export interface PreparedQueryHKTBase extends MySqlPreparedQueryHKT { + type: MySqlPreparedQuery>; +} diff --git a/drizzle-orm/src/singlestore-core/subquery.ts b/drizzle-orm/src/singlestore-core/subquery.ts new file mode 100644 index 0000000000..9d2c1828c5 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/subquery.ts @@ -0,0 +1,17 @@ +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import type { Subquery, WithSubquery } from '~/subquery.ts'; + +export type SubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & Subquery> + & AddAliasToSelection; + +export type WithSubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & WithSubquery> + & AddAliasToSelection; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts new file mode 100644 index 0000000000..3b1d4c3a39 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -0,0 +1,131 @@ +import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; +import type { CheckBuilder } from './checks.ts'; +import type { MySqlColumn, MySqlColumnBuilder, MySqlColumnBuilderBase } from './columns/common.ts'; +import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; +import type { AnyIndexBuilder } from './indexes.ts'; +import type { PrimaryKeyBuilder } from './primary-keys.ts'; +import type { UniqueConstraintBuilder } from './unique-constraint.ts'; + +export type MySqlTableExtraConfig = Record< + string, + | AnyIndexBuilder + | CheckBuilder + | ForeignKeyBuilder + | PrimaryKeyBuilder + | UniqueConstraintBuilder +>; + +export type TableConfig = TableConfigBase; + +/** @internal */ +export const InlineForeignKeys = Symbol.for('drizzle:MySqlInlineForeignKeys'); + +export class MySqlTable extends Table { + static readonly [entityKind]: string = 'MySqlTable'; + + declare protected $columns: T['columns']; + + /** @internal */ + static override readonly Symbol = Object.assign({}, Table.Symbol, { + InlineForeignKeys: InlineForeignKeys as typeof InlineForeignKeys, + }); + + /** @internal */ + override [Table.Symbol.Columns]!: NonNullable; + + /** @internal */ + [InlineForeignKeys]: ForeignKey[] = []; + + /** @internal */ + override [Table.Symbol.ExtraConfigBuilder]: + | ((self: Record) => MySqlTableExtraConfig) + | undefined = undefined; +} + +export type AnyMySqlTable = {}> = MySqlTable< + UpdateTableConfig +>; + +export type MySqlTableWithColumns = + & MySqlTable + & { + [Key in keyof T['columns']]: T['columns'][Key]; + }; + +export function mysqlTableWithSchema< + TTableName extends string, + TSchemaName extends string | undefined, + TColumnsMap extends Record, +>( + name: TTableName, + columns: TColumnsMap, + extraConfig: ((self: BuildColumns) => MySqlTableExtraConfig) | undefined, + schema: TSchemaName, + baseName = name, +): MySqlTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; +}> { + const rawTable = new MySqlTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; + }>(name, schema, baseName); + + const builtColumns = Object.fromEntries( + Object.entries(columns).map(([name, colBuilderBase]) => { + const colBuilder = colBuilderBase as MySqlColumnBuilder; + const column = colBuilder.build(rawTable); + rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable)); + return [name, column]; + }), + ) as unknown as BuildColumns; + + const table = Object.assign(rawTable, builtColumns); + + table[Table.Symbol.Columns] = builtColumns; + table[Table.Symbol.ExtraConfigColumns] = builtColumns as unknown as BuildExtraConfigColumns< + TTableName, + TColumnsMap, + 'mysql' + >; + + if (extraConfig) { + table[MySqlTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( + self: Record, + ) => MySqlTableExtraConfig; + } + + return table; +} + +export interface MySqlTableFn { + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: (self: BuildColumns) => MySqlTableExtraConfig, + ): MySqlTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; + }>; +} + +export const mysqlTable: MySqlTableFn = (name, columns, extraConfig) => { + return mysqlTableWithSchema(name, columns, extraConfig, undefined, name); +}; + +export function mysqlTableCreator(customizeTableName: (name: string) => string): MySqlTableFn { + return (name, columns, extraConfig) => { + return mysqlTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + }; +} diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts new file mode 100644 index 0000000000..66ed65198a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -0,0 +1,64 @@ +import { entityKind } from '~/entity.ts'; +import type { MySqlColumn } from './columns/index.ts'; +import { MySqlTable } from './table.ts'; + +export function unique(name?: string): UniqueOnConstraintBuilder { + return new UniqueOnConstraintBuilder(name); +} + +export function uniqueKeyName(table: MySqlTable, columns: string[]) { + return `${table[MySqlTable.Symbol.Name]}_${columns.join('_')}_unique`; +} + +export class UniqueConstraintBuilder { + static readonly [entityKind]: string = 'MySqlUniqueConstraintBuilder'; + + /** @internal */ + columns: MySqlColumn[]; + + constructor( + columns: MySqlColumn[], + private name?: string, + ) { + this.columns = columns; + } + + /** @internal */ + build(table: MySqlTable): UniqueConstraint { + return new UniqueConstraint(table, this.columns, this.name); + } +} + +export class UniqueOnConstraintBuilder { + static readonly [entityKind]: string = 'MySqlUniqueOnConstraintBuilder'; + + /** @internal */ + name?: string; + + constructor( + name?: string, + ) { + this.name = name; + } + + on(...columns: [MySqlColumn, ...MySqlColumn[]]) { + return new UniqueConstraintBuilder(columns, this.name); + } +} + +export class UniqueConstraint { + static readonly [entityKind]: string = 'MySqlUniqueConstraint'; + + readonly columns: MySqlColumn[]; + readonly name?: string; + readonly nullsNotDistinct: boolean = false; + + constructor(readonly table: MySqlTable, columns: MySqlColumn[], name?: string) { + this.columns = columns; + this.name = name ?? uniqueKeyName(this.table, this.columns.map((column) => column.name)); + } + + getName() { + return this.name; + } +} diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts new file mode 100644 index 0000000000..f09f65f3e9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -0,0 +1,68 @@ +import { is } from '~/entity.ts'; +import { Table } from '~/table.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import type { Check } from './checks.ts'; +import { CheckBuilder } from './checks.ts'; +import type { ForeignKey } from './foreign-keys.ts'; +import { ForeignKeyBuilder } from './foreign-keys.ts'; +import type { Index } from './indexes.ts'; +import { IndexBuilder } from './indexes.ts'; +import type { PrimaryKey } from './primary-keys.ts'; +import { PrimaryKeyBuilder } from './primary-keys.ts'; +import { MySqlTable } from './table.ts'; +import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; +import { MySqlViewConfig } from './view-common.ts'; +import type { MySqlView } from './view.ts'; + +export function getTableConfig(table: MySqlTable) { + const columns = Object.values(table[MySqlTable.Symbol.Columns]); + const indexes: Index[] = []; + const checks: Check[] = []; + const primaryKeys: PrimaryKey[] = []; + const uniqueConstraints: UniqueConstraint[] = []; + const foreignKeys: ForeignKey[] = Object.values(table[MySqlTable.Symbol.InlineForeignKeys]); + const name = table[Table.Symbol.Name]; + const schema = table[Table.Symbol.Schema]; + const baseName = table[Table.Symbol.BaseName]; + + const extraConfigBuilder = table[MySqlTable.Symbol.ExtraConfigBuilder]; + + if (extraConfigBuilder !== undefined) { + const extraConfig = extraConfigBuilder(table[MySqlTable.Symbol.Columns]); + for (const builder of Object.values(extraConfig)) { + if (is(builder, IndexBuilder)) { + indexes.push(builder.build(table)); + } else if (is(builder, CheckBuilder)) { + checks.push(builder.build(table)); + } else if (is(builder, UniqueConstraintBuilder)) { + uniqueConstraints.push(builder.build(table)); + } else if (is(builder, PrimaryKeyBuilder)) { + primaryKeys.push(builder.build(table)); + } else if (is(builder, ForeignKeyBuilder)) { + foreignKeys.push(builder.build(table)); + } + } + } + + return { + columns, + indexes, + foreignKeys, + checks, + primaryKeys, + uniqueConstraints, + name, + schema, + baseName, + }; +} + +export function getViewConfig< + TName extends string = string, + TExisting extends boolean = boolean, +>(view: MySqlView) { + return { + ...view[ViewBaseConfig], + ...view[MySqlViewConfig], + }; +} diff --git a/drizzle-orm/src/singlestore-core/view-base.ts b/drizzle-orm/src/singlestore-core/view-base.ts new file mode 100644 index 0000000000..46b1527d90 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-base.ts @@ -0,0 +1,15 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { View } from '~/sql/sql.ts'; + +export abstract class MySqlViewBase< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends View { + static readonly [entityKind]: string = 'MySqlViewBase'; + + declare readonly _: View['_'] & { + readonly viewBrand: 'MySqlViewBase'; + }; +} diff --git a/drizzle-orm/src/singlestore-core/view-common.ts b/drizzle-orm/src/singlestore-core/view-common.ts new file mode 100644 index 0000000000..9bbc130c33 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-common.ts @@ -0,0 +1 @@ +export const MySqlViewConfig = Symbol.for('drizzle:MySqlViewConfig'); diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts new file mode 100644 index 0000000000..4cc7d416c9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -0,0 +1,208 @@ +import type { BuildColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; +import { getTableColumns } from '~/utils.ts'; +import type { MySqlColumn, MySqlColumnBuilderBase } from './columns/index.ts'; +import { QueryBuilder } from './query-builders/query-builder.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import { mysqlTable } from './table.ts'; +import { MySqlViewBase } from './view-base.ts'; +import { MySqlViewConfig } from './view-common.ts'; + +export interface ViewBuilderConfig { + algorithm?: 'undefined' | 'merge' | 'temptable'; + definer?: string; + sqlSecurity?: 'definer' | 'invoker'; + withCheckOption?: 'cascaded' | 'local'; +} + +export class ViewBuilderCore { + static readonly [entityKind]: string = 'MySqlViewBuilder'; + + declare readonly _: { + readonly name: TConfig['name']; + readonly columns: TConfig['columns']; + }; + + constructor( + protected name: TConfig['name'], + protected schema: string | undefined, + ) {} + + protected config: ViewBuilderConfig = {}; + + algorithm( + algorithm: Exclude, + ): this { + this.config.algorithm = algorithm; + return this; + } + + definer( + definer: Exclude, + ): this { + this.config.definer = definer; + return this; + } + + sqlSecurity( + sqlSecurity: Exclude, + ): this { + this.config.sqlSecurity = sqlSecurity; + return this; + } + + withCheckOption( + withCheckOption?: Exclude, + ): this { + this.config.withCheckOption = withCheckOption ?? 'cascaded'; + return this; + } +} + +export class ViewBuilder extends ViewBuilderCore<{ name: TName }> { + static readonly [entityKind]: string = 'MySqlViewBuilder'; + + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): MySqlViewWithSelection> { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder()); + } + const selectionProxy = new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }); + const aliasedSelection = new Proxy(qb.getSelectedFields(), selectionProxy); + return new Proxy( + new MySqlView({ + mysqlConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: aliasedSelection, + query: qb.getSQL().inlineParams(), + }, + }), + selectionProxy as any, + ) as MySqlViewWithSelection>; + } +} + +export class ManualViewBuilder< + TName extends string = string, + TColumns extends Record = Record, +> extends ViewBuilderCore<{ name: TName; columns: TColumns }> { + static readonly [entityKind]: string = 'MySqlManualViewBuilder'; + + private columns: Record; + + constructor( + name: TName, + columns: TColumns, + schema: string | undefined, + ) { + super(name, schema); + this.columns = getTableColumns(mysqlTable(name, columns)) as BuildColumns; + } + + existing(): MySqlViewWithSelection> { + return new Proxy( + new MySqlView({ + mysqlConfig: undefined, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: undefined, + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as MySqlViewWithSelection>; + } + + as(query: SQL): MySqlViewWithSelection> { + return new Proxy( + new MySqlView({ + mysqlConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: query.inlineParams(), + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as MySqlViewWithSelection>; + } +} + +export class MySqlView< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends MySqlViewBase { + static readonly [entityKind]: string = 'MySqlView'; + + declare protected $MySqlViewBrand: 'MySqlView'; + + [MySqlViewConfig]: ViewBuilderConfig | undefined; + + constructor({ mysqlConfig, config }: { + mysqlConfig: ViewBuilderConfig | undefined; + config: { + name: TName; + schema: string | undefined; + selectedFields: SelectedFields; + query: SQL | undefined; + }; + }) { + super(config); + this[MySqlViewConfig] = mysqlConfig; + } +} + +export type MySqlViewWithSelection< + TName extends string, + TExisting extends boolean, + TSelectedFields extends ColumnsSelection, +> = MySqlView & TSelectedFields; + +/** @internal */ +export function mysqlViewWithSchema( + name: string, + selection: Record | undefined, + schema: string | undefined, +): ViewBuilder | ManualViewBuilder { + if (selection) { + return new ManualViewBuilder(name, selection, schema); + } + return new ViewBuilder(name, schema); +} + +export function mysqlView(name: TName): ViewBuilder; +export function mysqlView>( + name: TName, + columns: TColumns, +): ManualViewBuilder; +export function mysqlView( + name: string, + selection?: Record, +): ViewBuilder | ManualViewBuilder { + return mysqlViewWithSchema(name, selection, undefined); +} diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts new file mode 100644 index 0000000000..3b21bf11dd --- /dev/null +++ b/drizzle-orm/src/singlestore/driver.ts @@ -0,0 +1,99 @@ +import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mysql2'; +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { MySqlDatabase } from '~/mysql-core/db.ts'; +import { MySqlDialect } from '~/mysql-core/dialect.ts'; +import type { Mode } from '~/mysql-core/session.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { DrizzleError } from '../index.ts'; +import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; +import { MySql2Session } from './session.ts'; + +export interface MySqlDriverOptions { + logger?: Logger; +} + +export class MySql2Driver { + static readonly [entityKind]: string = 'MySql2Driver'; + + constructor( + private client: MySql2Client, + private dialect: MySqlDialect, + private options: MySqlDriverOptions = {}, + ) { + } + + createSession( + schema: RelationalSchemaConfig | undefined, + mode: Mode, + ): MySql2Session, TablesRelationalConfig> { + return new MySql2Session(this.client, this.dialect, schema, { logger: this.options.logger, mode }); + } +} + +export { MySqlDatabase } from '~/mysql-core/db.ts'; + +export type MySql2Database< + TSchema extends Record = Record, +> = MySqlDatabase; + +export type MySql2DrizzleConfig = Record> = + & Omit, 'schema'> + & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); + +export function drizzle = Record>( + client: MySql2Client | CallbackConnection | CallbackPool, + config: MySql2DrizzleConfig = {}, +): MySql2Database { + const dialect = new MySqlDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + if (isCallbackClient(client)) { + client = client.promise(); + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + if (config.mode === undefined) { + throw new DrizzleError({ + message: + 'You need to specify "mode": "planetscale" or "default" when providing a schema. Read more: https://orm.drizzle.team/docs/rqb#modes', + }); + } + + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const mode = config.mode ?? 'default'; + + const driver = new MySql2Driver(client as MySql2Client, dialect, { logger }); + const session = driver.createSession(schema, mode); + return new MySqlDatabase(dialect, session, schema, mode) as MySql2Database; +} + +interface CallbackClient { + promise(): MySql2Client; +} + +function isCallbackClient(client: any): client is CallbackClient { + return typeof client.promise === 'function'; +} diff --git a/drizzle-orm/src/singlestore/index.ts b/drizzle-orm/src/singlestore/index.ts new file mode 100644 index 0000000000..b1b6a52e71 --- /dev/null +++ b/drizzle-orm/src/singlestore/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore/migrator.ts b/drizzle-orm/src/singlestore/migrator.ts new file mode 100644 index 0000000000..2f3c9c3dcf --- /dev/null +++ b/drizzle-orm/src/singlestore/migrator.ts @@ -0,0 +1,11 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import type { MySql2Database } from './driver.ts'; + +export async function migrate>( + db: MySql2Database, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + await db.dialect.migrate(migrations, db.session, config); +} diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts new file mode 100644 index 0000000000..ab11d1f175 --- /dev/null +++ b/drizzle-orm/src/singlestore/session.ts @@ -0,0 +1,337 @@ +import type { Connection as CallbackConnection } from 'mysql2'; +import type { + Connection, + FieldPacket, + OkPacket, + Pool, + PoolConnection, + QueryOptions, + ResultSetHeader, + RowDataPacket, +} from 'mysql2/promise'; +import { once } from 'node:events'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import type { SelectedFieldsOrdered } from '~/mysql-core/query-builders/select.types.ts'; +import { + type Mode, + MySqlPreparedQuery, + type MySqlPreparedQueryConfig, + type MySqlPreparedQueryHKT, + type MySqlQueryResultHKT, + MySqlSession, + MySqlTransaction, + type MySqlTransactionConfig, + type PreparedQueryKind, +} from '~/mysql-core/session.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, sql } from '~/sql/sql.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; + +export type MySql2Client = Pool | Connection; + +export type MySqlRawQueryResult = [ResultSetHeader, FieldPacket[]]; +export type MySqlQueryResultType = RowDataPacket[][] | RowDataPacket[] | OkPacket | OkPacket[] | ResultSetHeader; +export type MySqlQueryResult< + T = any, +> = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; + +export class MySql2PreparedQuery extends MySqlPreparedQuery { + static readonly [entityKind]: string = 'MySql2PreparedQuery'; + + private rawQuery: QueryOptions; + private query: QueryOptions; + + constructor( + private client: MySql2Client, + queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + this.rawQuery = { + sql: queryString, + // rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + this.query = { + sql: queryString, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + } + + async execute(placeholderValues: Record = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + this.logger.logQuery(this.rawQuery.sql, params); + + const { fields, client, rawQuery, query, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + if (!fields && !customResultMapper) { + const res = await client.query(rawQuery, params); + const insertId = res[0].insertId; + const affectedRows = res[0].affectedRows; + // for each row, I need to check keys from + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + return res; + } + + const result = await client.query(query, params); + const rows = result[0]; + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + async *iterator( + placeholderValues: Record = {}, + ): AsyncGenerator { + const params = fillPlaceholders(this.params, placeholderValues); + const conn = ((isPool(this.client) ? await this.client.getConnection() : this.client) as {} as { + connection: CallbackConnection; + }).connection; + + const { fields, query, rawQuery, joinsNotNullableMap, client, customResultMapper } = this; + const hasRowsMapper = Boolean(fields || customResultMapper); + const driverQuery = hasRowsMapper ? conn.query(query, params) : conn.query(rawQuery, params); + + const stream = driverQuery.stream(); + + function dataListener() { + stream.pause(); + } + + stream.on('data', dataListener); + + try { + const onEnd = once(stream, 'end'); + const onError = once(stream, 'error'); + + while (true) { + stream.resume(); + const row = await Promise.race([onEnd, onError, new Promise((resolve) => stream.once('data', resolve))]); + if (row === undefined || (Array.isArray(row) && row.length === 0)) { + break; + } else if (row instanceof Error) { // eslint-disable-line no-instanceof/no-instanceof + throw row; + } else { + if (hasRowsMapper) { + if (customResultMapper) { + const mappedRow = customResultMapper([row as unknown[]]); + yield (Array.isArray(mappedRow) ? mappedRow[0] : mappedRow); + } else { + yield mapResultRow(fields!, row as unknown[], joinsNotNullableMap); + } + } else { + yield row as T['execute']; + } + } + } + } finally { + stream.off('data', dataListener); + if (isPool(client)) { + conn.end(); + } + } + } +} + +export interface MySql2SessionOptions { + logger?: Logger; + mode: Mode; +} + +export class MySql2Session< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends MySqlSession { + static readonly [entityKind]: string = 'MySql2Session'; + + private logger: Logger; + private mode: Mode; + + constructor( + private client: MySql2Client, + dialect: MySqlDialect, + private schema: RelationalSchemaConfig | undefined, + private options: MySql2SessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + this.mode = options.mode; + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + // Add returningId fields + // Each driver gets them from response from database + return new MySql2PreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + /** + * @internal + * What is its purpose? + */ + async query(query: string, params: unknown[]): Promise { + this.logger.logQuery(query, params); + const result = await this.client.query({ + sql: query, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + return result; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client.execute(querySql.sql, querySql.params).then((result) => result[0]) as Promise; + } + + override async transaction( + transaction: (tx: MySql2Transaction) => Promise, + config?: MySqlTransactionConfig, + ): Promise { + const session = isPool(this.client) + ? new MySql2Session( + await this.client.getConnection(), + this.dialect, + this.schema, + this.options, + ) + : this; + const tx = new MySql2Transaction( + this.dialect, + session as MySqlSession, + this.schema, + 0, + this.mode, + ); + if (config) { + const setTransactionConfigSql = this.getSetTransactionSQL(config); + if (setTransactionConfigSql) { + await tx.execute(setTransactionConfigSql); + } + const startTransactionSql = this.getStartTransactionSQL(config); + await (startTransactionSql ? tx.execute(startTransactionSql) : tx.execute(sql`begin`)); + } else { + await tx.execute(sql`begin`); + } + try { + const result = await transaction(tx); + await tx.execute(sql`commit`); + return result; + } catch (err) { + await tx.execute(sql`rollback`); + throw err; + } finally { + if (isPool(this.client)) { + (session.client as PoolConnection).release(); + } + } + } +} + +export class MySql2Transaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends MySqlTransaction { + static readonly [entityKind]: string = 'MySql2Transaction'; + + override async transaction(transaction: (tx: MySql2Transaction) => Promise): Promise { + const savepointName = `sp${this.nestedIndex + 1}`; + const tx = new MySql2Transaction( + this.dialect, + this.session, + this.schema, + this.nestedIndex + 1, + this.mode, + ); + await tx.execute(sql.raw(`savepoint ${savepointName}`)); + try { + const result = await transaction(tx); + await tx.execute(sql.raw(`release savepoint ${savepointName}`)); + return result; + } catch (err) { + await tx.execute(sql.raw(`rollback to savepoint ${savepointName}`)); + throw err; + } + } +} + +function isPool(client: MySql2Client): client is Pool { + return 'getConnection' in client; +} + +export interface MySql2QueryResultHKT extends MySqlQueryResultHKT { + type: MySqlRawQueryResult; +} + +export interface MySql2PreparedQueryHKT extends MySqlPreparedQueryHKT { + type: MySql2PreparedQuery>; +} From 57e0dc3ad31c17bf261d977373da0838bed39eee Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 23 Jul 2024 16:22:52 +0100 Subject: [PATCH 002/152] change 'json_array' to 'json_to_array' --- drizzle-orm/src/singlestore-core/dialect.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 4a72d9c5f7..04383a2c65 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -690,7 +690,7 @@ export class MySqlDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_array(${ + let field = sql`json_to_array(${ sql.join( selection.map(({ field, tsKey, isJson }) => isJson @@ -703,7 +703,7 @@ export class MySqlDialect { ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`coalesce(json_arrayagg(${field}), json_array())`; + field = sql`coalesce(json_to_arrayagg(${field}), json_to_array())`; } const nestedSelection = [{ dbKey: 'data', @@ -961,7 +961,7 @@ export class MySqlDialect { }); let fieldSql = sql`(${builtRelation.sql})`; if (is(relation, Many)) { - fieldSql = sql`coalesce(${fieldSql}, json_array())`; + fieldSql = sql`coalesce(${fieldSql}, json_to_array())`; } const field = fieldSql.as(selectedRelationTsKey); selection.push({ @@ -987,7 +987,7 @@ export class MySqlDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_array(${ + let field = sql`json_to_array(${ sql.join( selection.map(({ field }) => is(field, MySqlColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field @@ -996,7 +996,7 @@ export class MySqlDialect { ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`json_arrayagg(${field})`; + field = sql`json_to_arrayagg(${field})`; } const nestedSelection = [{ dbKey: 'data', From e10136e9ee0c1b71163d66490550560e0ff60b71 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 23 Jul 2024 16:52:34 +0100 Subject: [PATCH 003/152] add bson type --- drizzle-orm/src/column-builder.ts | 9 ++-- .../src/singlestore-core/columns/bson.ts | 46 +++++++++++++++++++ .../src/singlestore-core/columns/common.ts | 17 +++++++ .../src/singlestore-core/columns/index.ts | 1 + 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 drizzle-orm/src/singlestore-core/columns/bson.ts diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index 4a19a79a93..afe14953b5 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -5,6 +5,7 @@ import type { ExtraConfigColumn, PgColumn, PgSequenceOptions } from './pg-core/i import type { SQL } from './sql/sql.ts'; import type { SQLiteColumn } from './sqlite-core/index.ts'; import type { Simplify } from './utils.ts'; +import { SingleStoreColumn } from './singlestore-core/index.ts'; export type ColumnDataType = | 'string' @@ -17,7 +18,7 @@ export type ColumnDataType = | 'custom' | 'buffer'; -export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'common'; +export type Dialect = 'singlestore' | 'pg' | 'mysql' | 'sqlite' | 'common'; export type GeneratedStorageMode = 'virtual' | 'stored'; @@ -299,7 +300,8 @@ export type BuildColumn< TTableName extends string, TBuilder extends ColumnBuilderBase, TDialect extends Dialect, -> = TDialect extends 'pg' ? PgColumn> +> = TDialect extends 'singlestore' ? SingleStoreColumn> + : TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : TDialect extends 'common' ? Column> @@ -337,7 +339,8 @@ export type BuildExtraConfigColumns< & {}; export type ChangeColumnTableName = - TDialect extends 'pg' ? PgColumn> + TDialect extends 'singlestore' ? SingleStoreColumn> + : TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : never; diff --git a/drizzle-orm/src/singlestore-core/columns/bson.ts b/drizzle-orm/src/singlestore-core/columns/bson.ts new file mode 100644 index 0000000000..762eacf26d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/bson.ts @@ -0,0 +1,46 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; + +export type MySqlBsonBuilderInitial = MySqlBsonBuilder<{ + name: TName; + dataType: 'json'; // The bson is stored as a json string the same way binary is stored as a string (check `./binary.ts`) + columnType: 'MySqlBson'; + data: unknown; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class MySqlBsonBuilder> extends MySqlColumnBuilder { + static readonly [entityKind]: string = 'MySqlBsonBuilder'; + + constructor(name: T['name']) { + super(name, 'json', 'MySqlBson'); + } + + /** @internal */ + override build( + table: AnyMySqlTable<{ name: TTableName }>, + ): MySqlBson> { + return new MySqlBson>(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class MySqlBson> extends MySqlColumn { + static readonly [entityKind]: string = 'MySqlBson'; + + getSQLType(): string { + return 'bson'; + } + + override mapToDriverValue(value: T['data']): string { + return JSON.stringify(value); + } +} + +export function bson(name: TName): MySqlBsonBuilderInitial { + return new MySqlBsonBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index a0a192477e..99196cb288 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -96,6 +96,23 @@ export abstract class MySqlColumnBuilder< ): MySqlColumn>; } +export abstract class SingleStoreColumn< +T extends ColumnBaseConfig = ColumnBaseConfig, +TRuntimeConfig extends object = object, +> extends Column { +static readonly [entityKind]: string = 'MySqlColumn'; + +constructor( + override readonly table: MySqlTable, + config: ColumnBuilderRuntimeConfig, +) { + if (!config.uniqueName) { + config.uniqueName = uniqueKeyName(table, [config.name]); + } + super(table, config); +} +} + // To understand how to use `MySqlColumn` and `AnyMySqlColumn`, see `Column` and `AnyColumn` documentation. export abstract class MySqlColumn< T extends ColumnBaseConfig = ColumnBaseConfig, diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts index b51f0fac48..0dcb41be94 100644 --- a/drizzle-orm/src/singlestore-core/columns/index.ts +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -1,6 +1,7 @@ export * from './bigint.ts'; export * from './binary.ts'; export * from './boolean.ts'; +export * from './bson.ts'; export * from './char.ts'; export * from './common.ts'; export * from './custom.ts'; From 6c177c94a08f07d5a9f0a5e1eaac13ca07c1d667 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Tue, 23 Jul 2024 16:54:54 +0100 Subject: [PATCH 004/152] Renamed mysql to singlestore in singlestore-core --- drizzle-orm/src/column-builder.ts | 6 +- drizzle-orm/src/singlestore-core/alias.ts | 6 +- drizzle-orm/src/singlestore-core/checks.ts | 12 +- .../src/singlestore-core/columns/bigint.ts | 66 +++--- .../src/singlestore-core/columns/binary.ts | 45 ++-- .../src/singlestore-core/columns/boolean.ts | 32 +-- .../src/singlestore-core/columns/bson.ts | 33 +-- .../src/singlestore-core/columns/char.ts | 59 +++--- .../src/singlestore-core/columns/common.ts | 76 +++---- .../src/singlestore-core/columns/custom.ts | 48 +++-- .../singlestore-core/columns/date.common.ts | 17 +- .../src/singlestore-core/columns/date.ts | 76 ++++--- .../src/singlestore-core/columns/datetime.ts | 79 +++---- .../src/singlestore-core/columns/decimal.ts | 38 ++-- .../src/singlestore-core/columns/double.ts | 41 ++-- .../src/singlestore-core/columns/enum.ts | 36 ++-- .../src/singlestore-core/columns/float.ts | 35 +-- .../src/singlestore-core/columns/int.ts | 42 ++-- .../src/singlestore-core/columns/json.ts | 33 +-- .../src/singlestore-core/columns/mediumint.ts | 38 ++-- .../src/singlestore-core/columns/real.ts | 50 +++-- .../src/singlestore-core/columns/serial.ts | 39 ++-- .../src/singlestore-core/columns/smallint.ts | 38 ++-- .../src/singlestore-core/columns/text.ts | 84 ++++---- .../src/singlestore-core/columns/time.ts | 43 ++-- .../src/singlestore-core/columns/timestamp.ts | 74 +++---- .../src/singlestore-core/columns/tinyint.ts | 39 ++-- .../src/singlestore-core/columns/varbinary.ts | 40 ++-- .../src/singlestore-core/columns/varchar.ts | 57 ++--- .../src/singlestore-core/columns/year.ts | 37 ++-- drizzle-orm/src/singlestore-core/db.ts | 116 +++++----- drizzle-orm/src/singlestore-core/dialect.ts | 110 +++++----- .../src/singlestore-core/expressions.ts | 6 +- .../src/singlestore-core/foreign-keys.ts | 45 ++-- drizzle-orm/src/singlestore-core/indexes.ts | 22 +- .../src/singlestore-core/primary-keys.ts | 26 +-- .../singlestore-core/query-builders/delete.ts | 78 +++---- .../singlestore-core/query-builders/insert.ts | 177 ++++++++-------- .../query-builders/query-builder.ts | 48 +++-- .../singlestore-core/query-builders/query.ts | 38 ++-- .../singlestore-core/query-builders/select.ts | 199 +++++++++--------- .../query-builders/select.types.ts | 192 +++++++++-------- .../singlestore-core/query-builders/update.ts | 102 ++++----- drizzle-orm/src/singlestore-core/schema.ts | 37 ++-- drizzle-orm/src/singlestore-core/session.ts | 71 ++++--- drizzle-orm/src/singlestore-core/subquery.ts | 8 +- drizzle-orm/src/singlestore-core/table.ts | 72 ++++--- .../src/singlestore-core/unique-constraint.ts | 26 +-- drizzle-orm/src/singlestore-core/utils.ts | 20 +- drizzle-orm/src/singlestore-core/view-base.ts | 6 +- .../src/singlestore-core/view-common.ts | 2 +- drizzle-orm/src/singlestore-core/view.ts | 78 +++---- 52 files changed, 1469 insertions(+), 1329 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index afe14953b5..ad278e29dd 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -2,10 +2,10 @@ import { entityKind } from '~/entity.ts'; import type { Column } from './column.ts'; import type { MySqlColumn } from './mysql-core/index.ts'; import type { ExtraConfigColumn, PgColumn, PgSequenceOptions } from './pg-core/index.ts'; +import type { SingleStoreColumn } from './singlestore-core/index.ts'; import type { SQL } from './sql/sql.ts'; import type { SQLiteColumn } from './sqlite-core/index.ts'; import type { Simplify } from './utils.ts'; -import { SingleStoreColumn } from './singlestore-core/index.ts'; export type ColumnDataType = | 'string' @@ -18,7 +18,7 @@ export type ColumnDataType = | 'custom' | 'buffer'; -export type Dialect = 'singlestore' | 'pg' | 'mysql' | 'sqlite' | 'common'; +export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'singlestore' | 'common'; export type GeneratedStorageMode = 'virtual' | 'stored'; @@ -300,7 +300,7 @@ export type BuildColumn< TTableName extends string, TBuilder extends ColumnBuilderBase, TDialect extends Dialect, -> = TDialect extends 'singlestore' ? SingleStoreColumn> +> = TDialect extends 'singlestore' ? SingleStoreColumn> : TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> : TDialect extends 'sqlite' ? SQLiteColumn> diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts index 8320c5533d..08e7ecc67a 100644 --- a/drizzle-orm/src/singlestore-core/alias.ts +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -1,9 +1,9 @@ import { TableAliasProxyHandler } from '~/alias.ts'; import type { BuildAliasTable } from './query-builders/select.types.ts'; -import type { MySqlTable } from './table.ts'; -import type { MySqlViewBase } from './view-base.ts'; +import type { SingleStoreTable } from './table.ts'; +import type { SingleStoreViewBase } from './view-base.ts'; -export function alias( +export function alias( table: TTable, alias: TAlias, ): BuildAliasTable { diff --git a/drizzle-orm/src/singlestore-core/checks.ts b/drizzle-orm/src/singlestore-core/checks.ts index af9a29f6ae..29fdb76802 100644 --- a/drizzle-orm/src/singlestore-core/checks.ts +++ b/drizzle-orm/src/singlestore-core/checks.ts @@ -1,27 +1,27 @@ import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; -import type { MySqlTable } from './table.ts'; +import type { SingleStoreTable } from './table.ts'; export class CheckBuilder { - static readonly [entityKind]: string = 'MySqlCheckBuilder'; + static readonly [entityKind]: string = 'SingleStoreCheckBuilder'; - protected brand!: 'MySqlConstraintBuilder'; + protected brand!: 'SingleStoreConstraintBuilder'; constructor(public name: string, public value: SQL) {} /** @internal */ - build(table: MySqlTable): Check { + build(table: SingleStoreTable): Check { return new Check(table, this); } } export class Check { - static readonly [entityKind]: string = 'MySqlCheck'; + static readonly [entityKind]: string = 'SingleStoreCheck'; readonly name: string; readonly value: SQL; - constructor(public table: MySqlTable, builder: CheckBuilder) { + constructor(public table: SingleStoreTable, builder: CheckBuilder) { this.name = builder.name; this.value = builder.value; } diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts index ca1eedb3ff..6ea4a72978 100644 --- a/drizzle-orm/src/singlestore-core/columns/bigint.ts +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -1,44 +1,44 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -export type MySqlBigInt53BuilderInitial = MySqlBigInt53Builder<{ +export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ name: TName; dataType: 'number'; - columnType: 'MySqlBigInt53'; + columnType: 'SingleStoreBigInt53'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlBigInt53Builder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreBigInt53Builder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt53Builder'; + static readonly [entityKind]: string = 'SingleStoreBigInt53Builder'; constructor(name: T['name'], unsigned: boolean = false) { - super(name, 'number', 'MySqlBigInt53'); + super(name, 'number', 'SingleStoreBigInt53'); this.config.unsigned = unsigned; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlBigInt53> { - return new MySqlBigInt53>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt53> { + return new SingleStoreBigInt53>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlBigInt53> - extends MySqlColumnWithAutoIncrement +export class SingleStoreBigInt53> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt53'; + static readonly [entityKind]: string = 'SingleStoreBigInt53'; getSQLType(): string { return `bigint${this.config.unsigned ? ' unsigned' : ''}`; @@ -52,41 +52,41 @@ export class MySqlBigInt53 } } -export type MySqlBigInt64BuilderInitial = MySqlBigInt64Builder<{ +export type SingleStoreBigInt64BuilderInitial = SingleStoreBigInt64Builder<{ name: TName; dataType: 'bigint'; - columnType: 'MySqlBigInt64'; + columnType: 'SingleStoreBigInt64'; data: bigint; driverParam: string; enumValues: undefined; generated: undefined; }>; -export class MySqlBigInt64Builder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreBigInt64Builder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt64Builder'; + static readonly [entityKind]: string = 'SingleStoreBigInt64Builder'; constructor(name: T['name'], unsigned: boolean = false) { - super(name, 'bigint', 'MySqlBigInt64'); + super(name, 'bigint', 'SingleStoreBigInt64'); this.config.unsigned = unsigned; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlBigInt64> { - return new MySqlBigInt64>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt64> { + return new SingleStoreBigInt64>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlBigInt64> - extends MySqlColumnWithAutoIncrement +export class SingleStoreBigInt64> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt64'; + static readonly [entityKind]: string = 'SingleStoreBigInt64'; getSQLType(): string { return `bigint${this.config.unsigned ? ' unsigned' : ''}`; @@ -98,18 +98,18 @@ export class MySqlBigInt64 } } -interface MySqlBigIntConfig { +interface SingleStoreBigIntConfig { mode: T; unsigned?: boolean; } -export function bigint( +export function bigint( name: TName, - config: MySqlBigIntConfig, -): TMode extends 'number' ? MySqlBigInt53BuilderInitial : MySqlBigInt64BuilderInitial; -export function bigint(name: string, config: MySqlBigIntConfig) { + config: SingleStoreBigIntConfig, +): TMode extends 'number' ? SingleStoreBigInt53BuilderInitial : SingleStoreBigInt64BuilderInitial; +export function bigint(name: string, config: SingleStoreBigIntConfig) { if (config.mode === 'number') { - return new MySqlBigInt53Builder(name, config.unsigned); + return new SingleStoreBigInt53Builder(name, config.unsigned); } - return new MySqlBigInt64Builder(name, config.unsigned); + return new SingleStoreBigInt64Builder(name, config.unsigned); } diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts index 87a8e0f8c9..9cb05ac531 100644 --- a/drizzle-orm/src/singlestore-core/columns/binary.ts +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -1,43 +1,48 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder<{ +export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlBinary'; + columnType: 'SingleStoreBinary'; data: string; driverParam: string; enumValues: undefined; generated: undefined; }>; -export class MySqlBinaryBuilder> extends MySqlColumnBuilder< - T, - MySqlBinaryConfig -> { - static readonly [entityKind]: string = 'MySqlBinaryBuilder'; +export class SingleStoreBinaryBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreBinaryConfig + > +{ + static readonly [entityKind]: string = 'SingleStoreBinaryBuilder'; constructor(name: T['name'], length: number | undefined) { - super(name, 'string', 'MySqlBinary'); + super(name, 'string', 'SingleStoreBinary'); this.config.length = length; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlBinary> { - return new MySqlBinary>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBinary> { + return new SingleStoreBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlBinary> extends MySqlColumn< +export class SingleStoreBinary> extends SingleStoreColumn< T, - MySqlBinaryConfig + SingleStoreBinaryConfig > { - static readonly [entityKind]: string = 'MySqlBinary'; + static readonly [entityKind]: string = 'SingleStoreBinary'; length: number | undefined = this.config.length; @@ -46,13 +51,13 @@ export class MySqlBinary> ex } } -export interface MySqlBinaryConfig { +export interface SingleStoreBinaryConfig { length?: number; } export function binary( name: TName, - config: MySqlBinaryConfig = {}, -): MySqlBinaryBuilderInitial { - return new MySqlBinaryBuilder(name, config.length); + config: SingleStoreBinaryConfig = {}, +): SingleStoreBinaryBuilderInitial { + return new SingleStoreBinaryBuilder(name, config.length); } diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts index 3a915e6733..795b12e7fa 100644 --- a/drizzle-orm/src/singlestore-core/columns/boolean.ts +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -1,41 +1,43 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlBooleanBuilderInitial = MySqlBooleanBuilder<{ +export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ name: TName; dataType: 'boolean'; - columnType: 'MySqlBoolean'; + columnType: 'SingleStoreBoolean'; data: boolean; driverParam: number | boolean; enumValues: undefined; generated: undefined; }>; -export class MySqlBooleanBuilder> - extends MySqlColumnBuilder +export class SingleStoreBooleanBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'MySqlBooleanBuilder'; + static readonly [entityKind]: string = 'SingleStoreBooleanBuilder'; constructor(name: T['name']) { - super(name, 'boolean', 'MySqlBoolean'); + super(name, 'boolean', 'SingleStoreBoolean'); } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlBoolean> { - return new MySqlBoolean>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBoolean> { + return new SingleStoreBoolean>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlBoolean> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlBoolean'; +export class SingleStoreBoolean> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreBoolean'; getSQLType(): string { return 'boolean'; @@ -49,6 +51,6 @@ export class MySqlBoolean> } } -export function boolean(name: TName): MySqlBooleanBuilderInitial { - return new MySqlBooleanBuilder(name); +export function boolean(name: TName): SingleStoreBooleanBuilderInitial { + return new SingleStoreBooleanBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/columns/bson.ts b/drizzle-orm/src/singlestore-core/columns/bson.ts index 762eacf26d..cc12f23088 100644 --- a/drizzle-orm/src/singlestore-core/columns/bson.ts +++ b/drizzle-orm/src/singlestore-core/columns/bson.ts @@ -1,36 +1,41 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlBsonBuilderInitial = MySqlBsonBuilder<{ +export type SingleStoreBsonBuilderInitial = SingleStoreBsonBuilder<{ name: TName; dataType: 'json'; // The bson is stored as a json string the same way binary is stored as a string (check `./binary.ts`) - columnType: 'MySqlBson'; + columnType: 'SingleStoreBson'; data: unknown; driverParam: string; enumValues: undefined; generated: undefined; }>; -export class MySqlBsonBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlBsonBuilder'; +export class SingleStoreBsonBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreBsonBuilder'; constructor(name: T['name']) { - super(name, 'json', 'MySqlBson'); + super(name, 'json', 'SingleStoreBson'); } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlBson> { - return new MySqlBson>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBson> { + return new SingleStoreBson>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlBson> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlBson'; +export class SingleStoreBson> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreBson'; getSQLType(): string { return 'bson'; @@ -41,6 +46,6 @@ export class MySqlBson> extends } } -export function bson(name: TName): MySqlBsonBuilderInitial { - return new MySqlBsonBuilder(name); +export function bson(name: TName): SingleStoreBsonBuilderInitial { + return new SingleStoreBsonBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts index f871796a5d..f59c173cb4 100644 --- a/drizzle-orm/src/singlestore-core/columns/char.ts +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -1,47 +1,50 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlCharBuilderInitial = MySqlCharBuilder<{ - name: TName; - dataType: 'string'; - columnType: 'MySqlChar'; - data: TEnum[number]; - driverParam: number | string; - enumValues: TEnum; - generated: undefined; -}>; +export type SingleStoreCharBuilderInitial = + SingleStoreCharBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + }>; -export class MySqlCharBuilder> extends MySqlColumnBuilder< - T, - MySqlCharConfig -> { - static readonly [entityKind]: string = 'MySqlCharBuilder'; +export class SingleStoreCharBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreCharConfig + > +{ + static readonly [entityKind]: string = 'SingleStoreCharBuilder'; - constructor(name: T['name'], config: MySqlCharConfig) { - super(name, 'string', 'MySqlChar'); + constructor(name: T['name'], config: SingleStoreCharConfig) { + super(name, 'string', 'SingleStoreChar'); this.config.length = config.length; this.config.enum = config.enum; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlChar & { enumValues: T['enumValues'] }> { - return new MySqlChar & { enumValues: T['enumValues'] }>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreChar & { enumValues: T['enumValues'] }> { + return new SingleStoreChar & { enumValues: T['enumValues'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlChar> - extends MySqlColumn> +export class SingleStoreChar> + extends SingleStoreColumn> { - static readonly [entityKind]: string = 'MySqlChar'; + static readonly [entityKind]: string = 'SingleStoreChar'; readonly length: number | undefined = this.config.length; override readonly enumValues = this.config.enum; @@ -51,14 +54,14 @@ export class MySqlChar> } } -export interface MySqlCharConfig { +export interface SingleStoreCharConfig { length?: number; enum?: TEnum; } export function char>( name: TName, - config: MySqlCharConfig> = {}, -): MySqlCharBuilderInitial> { - return new MySqlCharBuilder(name, config); + config: SingleStoreCharConfig> = {}, +): SingleStoreCharBuilderInitial> { + return new SingleStoreCharBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index 99196cb288..baa33abbdd 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -13,41 +13,41 @@ import type { import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; 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 { ForeignKey, UpdateDeleteAction } from '~/singlestore-core/foreign-keys.ts'; +import { ForeignKeyBuilder } from '~/singlestore-core/foreign-keys.ts'; +import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; export interface ReferenceConfig { - ref: () => MySqlColumn; + ref: () => SingleStoreColumn; actions: { onUpdate?: UpdateDeleteAction; onDelete?: UpdateDeleteAction; }; } -export interface MySqlColumnBuilderBase< +export interface SingleStoreColumnBuilderBase< T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, TTypeConfig extends object = object, -> extends ColumnBuilderBase {} +> extends ColumnBuilderBase {} -export interface MySqlGeneratedColumnConfig { +export interface SingleStoreGeneratedColumnConfig { mode?: 'virtual' | 'stored'; } -export abstract class MySqlColumnBuilder< +export abstract class SingleStoreColumnBuilder< T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig & { data: any; }, TRuntimeConfig extends object = object, TTypeConfig extends object = object, TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, -> extends ColumnBuilder - implements MySqlColumnBuilderBase +> extends ColumnBuilder + implements SingleStoreColumnBuilderBase { - static readonly [entityKind]: string = 'MySqlColumnBuilder'; + static readonly [entityKind]: string = 'SingleStoreColumnBuilder'; private foreignKeyConfigs: ReferenceConfig[] = []; @@ -62,7 +62,7 @@ export abstract class MySqlColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: MySqlGeneratedColumnConfig): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { this.config.generated = { as, type: 'always', @@ -72,7 +72,7 @@ export abstract class MySqlColumnBuilder< } /** @internal */ - buildForeignKeys(column: MySqlColumn, table: MySqlTable): ForeignKey[] { + buildForeignKeys(column: SingleStoreColumn, table: SingleStoreTable): ForeignKey[] { return this.foreignKeyConfigs.map(({ ref, actions }) => { return ((ref, actions) => { const builder = new ForeignKeyBuilder(() => { @@ -92,36 +92,19 @@ export abstract class MySqlColumnBuilder< /** @internal */ abstract build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlColumn>; + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreColumn>; } +// To understand how to use `SingleStoreColumn` and `AnySingleStoreColumn`, see `Column` and `AnyColumn` documentation. export abstract class SingleStoreColumn< -T extends ColumnBaseConfig = ColumnBaseConfig, -TRuntimeConfig extends object = object, -> extends Column { -static readonly [entityKind]: string = 'MySqlColumn'; - -constructor( - override readonly table: MySqlTable, - config: ColumnBuilderRuntimeConfig, -) { - if (!config.uniqueName) { - config.uniqueName = uniqueKeyName(table, [config.name]); - } - super(table, config); -} -} - -// To understand how to use `MySqlColumn` and `AnyMySqlColumn`, see `Column` and `AnyColumn` documentation. -export abstract class MySqlColumn< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, -> extends Column { - static readonly [entityKind]: string = 'MySqlColumn'; +> extends Column { + static readonly [entityKind]: string = 'SingleStoreColumn'; constructor( - override readonly table: MySqlTable, + override readonly table: SingleStoreTable, config: ColumnBuilderRuntimeConfig, ) { if (!config.uniqueName) { @@ -131,20 +114,21 @@ export abstract class MySqlColumn< } } -export type AnyMySqlColumn> = {}> = MySqlColumn< - Required, TPartial>> ->; +export type AnySingleStoreColumn> = {}> = + SingleStoreColumn< + Required, TPartial>> + >; -export interface MySqlColumnWithAutoIncrementConfig { +export interface SingleStoreColumnWithAutoIncrementConfig { autoIncrement: boolean; } -export abstract class MySqlColumnBuilderWithAutoIncrement< +export abstract class SingleStoreColumnBuilderWithAutoIncrement< T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, TRuntimeConfig extends object = object, TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, -> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlColumnBuilderWithAutoIncrement'; +> extends SingleStoreColumnBuilder { + static readonly [entityKind]: string = 'SingleStoreColumnBuilderWithAutoIncrement'; constructor(name: NonNullable, dataType: T['dataType'], columnType: T['columnType']) { super(name, dataType, columnType); @@ -158,11 +142,11 @@ export abstract class MySqlColumnBuilderWithAutoIncrement< } } -export abstract class MySqlColumnWithAutoIncrement< +export abstract class SingleStoreColumnWithAutoIncrement< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, -> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlColumnWithAutoIncrement'; +> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreColumnWithAutoIncrement'; readonly autoIncrement: boolean = this.config.autoIncrement; } diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts index 1c5e2603f3..727099884f 100644 --- a/drizzle-orm/src/singlestore-core/columns/custom.ts +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -1,16 +1,16 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; import type { Equal } from '~/utils.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = & { name: TName; dataType: 'custom'; - columnType: 'MySqlCustomColumn'; + columnType: 'SingleStoreCustomColumn'; data: T['data']; driverParam: T['driverData']; enumValues: undefined; @@ -19,55 +19,57 @@ export type ConvertCustomConfig> - extends MySqlColumnBuilder< +export class SingleStoreCustomColumnBuilder> + extends SingleStoreColumnBuilder< T, { fieldConfig: CustomTypeValues['config']; customTypeParams: CustomTypeParams; }, { - mysqlColumnBuilderBrand: 'MySqlCustomColumnBuilderBrand'; + singlestoreColumnBuilderBrand: 'SingleStoreCustomColumnBuilderBrand'; } > { - static readonly [entityKind]: string = 'MySqlCustomColumnBuilder'; + static readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder'; constructor( name: T['name'], fieldConfig: CustomTypeValues['config'], customTypeParams: CustomTypeParams, ) { - super(name, 'custom', 'MySqlCustomColumn'); + super(name, 'custom', 'SingleStoreCustomColumn'); this.config.fieldConfig = fieldConfig; this.config.customTypeParams = customTypeParams; } /** @internal */ build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlCustomColumn> { - return new MySqlCustomColumn>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreCustomColumn> { + return new SingleStoreCustomColumn>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlCustomColumn> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlCustomColumn'; +export class SingleStoreCustomColumn> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreCustomColumn'; private sqlName: string; private mapTo?: (value: T['data']) => T['driverParam']; private mapFrom?: (value: T['driverParam']) => T['data']; constructor( - table: AnyMySqlTable<{ name: T['tableName'] }>, - config: MySqlCustomColumnBuilder['config'], + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreCustomColumnBuilder['config'], ) { super(table, config); this.sqlName = config.customTypeParams.dataType(config.fieldConfig); @@ -199,23 +201,27 @@ export interface CustomTypeParams { } /** - * Custom mysql database data type generator + * Custom singlestore database data type generator */ export function customType( customTypeParams: CustomTypeParams, ): Equal extends true ? ( dbName: TName, fieldConfig: T['config'], - ) => MySqlCustomColumnBuilder> + ) => SingleStoreCustomColumnBuilder> : ( dbName: TName, fieldConfig?: T['config'], - ) => MySqlCustomColumnBuilder> + ) => SingleStoreCustomColumnBuilder> { return ( dbName: TName, fieldConfig?: T['config'], - ): MySqlCustomColumnBuilder> => { - return new MySqlCustomColumnBuilder(dbName as ConvertCustomConfig['name'], fieldConfig, customTypeParams); + ): SingleStoreCustomColumnBuilder> => { + return new SingleStoreCustomColumnBuilder( + dbName as ConvertCustomConfig['name'], + fieldConfig, + customTypeParams, + ); }; } diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts index 3fd8aa6124..45dd668c91 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.common.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -7,24 +7,25 @@ import type { import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import { sql } from '~/sql/sql.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export interface MySqlDateColumnBaseConfig { +export interface SingleStoreDateColumnBaseConfig { hasOnUpdateNow: boolean; } -export abstract class MySqlDateColumnBaseBuilder< +export abstract class SingleStoreDateColumnBaseBuilder< T extends ColumnBuilderBaseConfig, TRuntimeConfig extends object = object, TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, -> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateColumnBuilder'; +> extends SingleStoreColumnBuilder { + static readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; defaultNow() { return this.default(sql`(now())`); } // "on update now" also adds an implicit default value to the column - https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html + // TODO(singlestore) onUpdateNow(): HasDefault { this.config.hasOnUpdateNow = true; this.config.hasDefault = true; @@ -32,11 +33,11 @@ export abstract class MySqlDateColumnBaseBuilder< } } -export abstract class MySqlDateBaseColumn< +export abstract class SingleStoreDateBaseColumn< T extends ColumnBaseConfig, TRuntimeConfig extends object = object, -> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateColumn'; +> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreDateColumn'; readonly hasOnUpdateNow: boolean = this.config.hasOnUpdateNow; } diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts index d7e2c409ef..1c64fe3f16 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -1,41 +1,46 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Equal } from '~/utils.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlDateBuilderInitial = MySqlDateBuilder<{ +export type SingleStoreDateBuilderInitial = SingleStoreDateBuilder<{ name: TName; dataType: 'date'; - columnType: 'MySqlDate'; + columnType: 'SingleStoreDate'; data: Date; driverParam: string | number; enumValues: undefined; generated: undefined; }>; -export class MySqlDateBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateBuilder'; +export class SingleStoreDateBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreDateBuilder'; constructor(name: T['name']) { - super(name, 'date', 'MySqlDate'); + super(name, 'date', 'SingleStoreDate'); } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlDate> { - return new MySqlDate>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDate> { + return new SingleStoreDate>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlDate> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDate'; +export class SingleStoreDate> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreDate'; constructor( - table: AnyMySqlTable<{ name: T['tableName'] }>, - config: MySqlDateBuilder['config'], + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateBuilder['config'], ) { super(table, config); } @@ -49,42 +54,44 @@ export class MySqlDate> extends } } -export type MySqlDateStringBuilderInitial = MySqlDateStringBuilder<{ +export type SingleStoreDateStringBuilderInitial = SingleStoreDateStringBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlDateString'; + columnType: 'SingleStoreDateString'; data: string; driverParam: string | number; enumValues: undefined; generated: undefined; }>; -export class MySqlDateStringBuilder> - extends MySqlColumnBuilder +export class SingleStoreDateStringBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateStringBuilder'; + static readonly [entityKind]: string = 'SingleStoreDateStringBuilder'; constructor(name: T['name']) { - super(name, 'string', 'MySqlDateString'); + super(name, 'string', 'SingleStoreDateString'); } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlDateString> { - return new MySqlDateString>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateString> { + return new SingleStoreDateString>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlDateString> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateString'; +export class SingleStoreDateString> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreDateString'; constructor( - table: AnyMySqlTable<{ name: T['tableName'] }>, - config: MySqlDateStringBuilder['config'], + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateStringBuilder['config'], ) { super(table, config); } @@ -94,17 +101,18 @@ export class MySqlDateString { +export interface SingleStoreDateConfig { mode?: TMode; } -export function date( +export function date( name: TName, - config?: MySqlDateConfig, -): Equal extends true ? MySqlDateStringBuilderInitial : MySqlDateBuilderInitial; -export function date(name: string, config: MySqlDateConfig = {}) { + config?: SingleStoreDateConfig, +): Equal extends true ? SingleStoreDateStringBuilderInitial + : SingleStoreDateBuilderInitial; +export function date(name: string, config: SingleStoreDateConfig = {}) { if (config.mode === 'string') { - return new MySqlDateStringBuilder(name); + return new SingleStoreDateStringBuilder(name); } - return new MySqlDateBuilder(name); + return new SingleStoreDateBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index 040c571302..f5d45629bd 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -1,49 +1,51 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Equal } from '~/utils.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlDateTimeBuilderInitial = MySqlDateTimeBuilder<{ +export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ name: TName; dataType: 'date'; - columnType: 'MySqlDateTime'; + columnType: 'SingleStoreDateTime'; data: Date; driverParam: string | number; enumValues: undefined; generated: undefined; }>; -export class MySqlDateTimeBuilder> - extends MySqlColumnBuilder +export class SingleStoreDateTimeBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateTimeBuilder'; + static readonly [entityKind]: string = 'SingleStoreDateTimeBuilder'; - constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { - super(name, 'date', 'MySqlDateTime'); + constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + super(name, 'date', 'SingleStoreDateTime'); this.config.fsp = config?.fsp; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlDateTime> { - return new MySqlDateTime>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTime> { + return new SingleStoreDateTime>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlDateTime> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateTime'; +export class SingleStoreDateTime> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreDateTime'; readonly fsp: number | undefined; constructor( - table: AnyMySqlTable<{ name: T['tableName'] }>, - config: MySqlDateTimeBuilder['config'], + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeBuilder['config'], ) { super(table, config); this.fsp = config.fsp; @@ -63,45 +65,47 @@ export class MySqlDateTime> } } -export type MySqlDateTimeStringBuilderInitial = MySqlDateTimeStringBuilder<{ +export type SingleStoreDateTimeStringBuilderInitial = SingleStoreDateTimeStringBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlDateTimeString'; + columnType: 'SingleStoreDateTimeString'; data: string; driverParam: string | number; enumValues: undefined; generated: undefined; }>; -export class MySqlDateTimeStringBuilder> - extends MySqlColumnBuilder +export class SingleStoreDateTimeStringBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateTimeStringBuilder'; + static readonly [entityKind]: string = 'SingleStoreDateTimeStringBuilder'; - constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { - super(name, 'string', 'MySqlDateTimeString'); + constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + super(name, 'string', 'SingleStoreDateTimeString'); this.config.fsp = config?.fsp; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlDateTimeString> { - return new MySqlDateTimeString>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTimeString> { + return new SingleStoreDateTimeString>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlDateTimeString> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateTimeString'; +export class SingleStoreDateTimeString> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreDateTimeString'; readonly fsp: number | undefined; constructor( - table: AnyMySqlTable<{ name: T['tableName'] }>, - config: MySqlDateTimeStringBuilder['config'], + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeStringBuilder['config'], ) { super(table, config); this.fsp = config.fsp; @@ -115,18 +119,19 @@ export class MySqlDateTimeString { +export interface SingleStoreDatetimeConfig { mode?: TMode; fsp?: DatetimeFsp; } -export function datetime( +export function datetime( name: TName, - config?: MySqlDatetimeConfig, -): Equal extends true ? MySqlDateTimeStringBuilderInitial : MySqlDateTimeBuilderInitial; -export function datetime(name: string, config: MySqlDatetimeConfig = {}) { + config?: SingleStoreDatetimeConfig, +): Equal extends true ? SingleStoreDateTimeStringBuilderInitial + : SingleStoreDateTimeBuilderInitial; +export function datetime(name: string, config: SingleStoreDatetimeConfig = {}) { if (config.mode === 'string') { - return new MySqlDateTimeStringBuilder(name, config); + return new SingleStoreDateTimeStringBuilder(name, config); } - return new MySqlDateTimeBuilder(name, config); + return new SingleStoreDateTimeBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index fa25d9cdbf..e5095c4d82 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -1,45 +1,45 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -export type MySqlDecimalBuilderInitial = MySqlDecimalBuilder<{ +export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlDecimal'; + columnType: 'SingleStoreDecimal'; data: string; driverParam: string; enumValues: undefined; generated: undefined; }>; -export class MySqlDecimalBuilder< - T extends ColumnBuilderBaseConfig<'string', 'MySqlDecimal'>, -> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDecimalBuilder'; +export class SingleStoreDecimalBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreDecimal'>, +> extends SingleStoreColumnBuilderWithAutoIncrement { + static readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; constructor(name: T['name'], precision?: number, scale?: number) { - super(name, 'string', 'MySqlDecimal'); + super(name, 'string', 'SingleStoreDecimal'); this.config.precision = precision; this.config.scale = scale; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlDecimal> { - return new MySqlDecimal>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDecimal> { + return new SingleStoreDecimal>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlDecimal> - extends MySqlColumnWithAutoIncrement +export class SingleStoreDecimal> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDecimal'; + static readonly [entityKind]: string = 'SingleStoreDecimal'; readonly precision: number | undefined = this.config.precision; readonly scale: number | undefined = this.config.scale; @@ -55,14 +55,14 @@ export class MySqlDecimal> } } -export interface MySqlDecimalConfig { +export interface SingleStoreDecimalConfig { precision?: number; scale?: number; } export function decimal( name: TName, - config: MySqlDecimalConfig = {}, -): MySqlDecimalBuilderInitial { - return new MySqlDecimalBuilder(name, config.precision, config.scale); + config: SingleStoreDecimalConfig = {}, +): SingleStoreDecimalBuilderInitial { + return new SingleStoreDecimalBuilder(name, config.precision, config.scale); } diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts index dd349cf27b..6ca945431c 100644 --- a/drizzle-orm/src/singlestore-core/columns/double.ts +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -1,42 +1,45 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder<{ +export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlDouble'; + columnType: 'SingleStoreDouble'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlDoubleBuilder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreDoubleBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDoubleBuilder'; + static readonly [entityKind]: string = 'SingleStoreDoubleBuilder'; - constructor(name: T['name'], config: MySqlDoubleConfig | undefined) { - super(name, 'number', 'MySqlDouble'); + constructor(name: T['name'], config: SingleStoreDoubleConfig | undefined) { + super(name, 'number', 'SingleStoreDouble'); this.config.precision = config?.precision; this.config.scale = config?.scale; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlDouble> { - return new MySqlDouble>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDouble> { + return new SingleStoreDouble>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlDouble> - extends MySqlColumnWithAutoIncrement +export class SingleStoreDouble> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDouble'; + static readonly [entityKind]: string = 'SingleStoreDouble'; precision: number | undefined = this.config.precision; scale: number | undefined = this.config.scale; @@ -52,14 +55,14 @@ export class MySqlDouble> } } -export interface MySqlDoubleConfig { +export interface SingleStoreDoubleConfig { precision?: number; scale?: number; } export function double( name: TName, - config?: MySqlDoubleConfig, -): MySqlDoubleBuilderInitial { - return new MySqlDoubleBuilder(name, config); + config?: SingleStoreDoubleConfig, +): SingleStoreDoubleBuilderInitial { + return new SingleStoreDoubleBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts index 1d8b4c1f51..af04c50a59 100644 --- a/drizzle-orm/src/singlestore-core/columns/enum.ts +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -1,46 +1,46 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlEnumColumnBuilderInitial = - MySqlEnumColumnBuilder<{ +export type SingleStoreEnumColumnBuilderInitial = + SingleStoreEnumColumnBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlEnumColumn'; + columnType: 'SingleStoreEnumColumn'; data: TEnum[number]; driverParam: string; enumValues: TEnum; generated: undefined; }>; -export class MySqlEnumColumnBuilder> - extends MySqlColumnBuilder +export class SingleStoreEnumColumnBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'MySqlEnumColumnBuilder'; + static readonly [entityKind]: string = 'SingleStoreEnumColumnBuilder'; constructor(name: T['name'], values: T['enumValues']) { - super(name, 'string', 'MySqlEnumColumn'); + super(name, 'string', 'SingleStoreEnumColumn'); this.config.enumValues = values; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlEnumColumn & { enumValues: T['enumValues'] }> { - return new MySqlEnumColumn & { enumValues: T['enumValues'] }>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreEnumColumn & { enumValues: T['enumValues'] }> { + return new SingleStoreEnumColumn & { enumValues: T['enumValues'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlEnumColumn> - extends MySqlColumn +export class SingleStoreEnumColumn> + extends SingleStoreColumn { - static readonly [entityKind]: string = 'MySqlEnumColumn'; + static readonly [entityKind]: string = 'SingleStoreEnumColumn'; override readonly enumValues = this.config.enumValues; @@ -49,13 +49,13 @@ export class MySqlEnumColumn>( +export function singlestoreEnum>( name: TName, values: T | Writable, -): MySqlEnumColumnBuilderInitial> { +): SingleStoreEnumColumnBuilderInitial> { if (values.length === 0) { throw new Error(`You have an empty array for "${name}" enum values`); } - return new MySqlEnumColumnBuilder(name, values); + return new SingleStoreEnumColumnBuilder(name, values); } diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index b66f1e05a4..a54ee06a1a 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -1,44 +1,49 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ +export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlFloat'; + columnType: 'SingleStoreFloat'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlFloatBuilder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreFloatBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlFloatBuilder'; + static readonly [entityKind]: string = 'SingleStoreFloatBuilder'; constructor(name: T['name']) { - super(name, 'number', 'MySqlFloat'); + super(name, 'number', 'SingleStoreFloat'); } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlFloat> { - return new MySqlFloat>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreFloat> { + return new SingleStoreFloat>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlFloat> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlFloat'; +export class SingleStoreFloat> + extends SingleStoreColumnWithAutoIncrement +{ + static readonly [entityKind]: string = 'SingleStoreFloat'; getSQLType(): string { return 'float'; } } -export function float(name: TName): MySqlFloatBuilderInitial { - return new MySqlFloatBuilder(name); +export function float(name: TName): SingleStoreFloatBuilderInitial { + return new SingleStoreFloatBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts index dbfb85760a..e9ca0a6822 100644 --- a/drizzle-orm/src/singlestore-core/columns/int.ts +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -1,41 +1,44 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -export type MySqlIntBuilderInitial = MySqlIntBuilder<{ +export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlInt'; + columnType: 'SingleStoreInt'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlIntBuilder'; + static readonly [entityKind]: string = 'SingleStoreIntBuilder'; - constructor(name: T['name'], config?: MySqlIntConfig) { - super(name, 'number', 'MySqlInt'); + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreInt'); this.config.unsigned = config ? config.unsigned : false; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlInt> { - return new MySqlInt>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreInt> { + return new SingleStoreInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlInt> - extends MySqlColumnWithAutoIncrement +export class SingleStoreInt> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlInt'; + static readonly [entityKind]: string = 'SingleStoreInt'; getSQLType(): string { return `int${this.config.unsigned ? ' unsigned' : ''}`; @@ -49,10 +52,13 @@ export class MySqlInt> } } -export interface MySqlIntConfig { +export interface SingleStoreIntConfig { unsigned?: boolean; } -export function int(name: TName, config?: MySqlIntConfig): MySqlIntBuilderInitial { - return new MySqlIntBuilder(name, config); +export function int( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreIntBuilderInitial { + return new SingleStoreIntBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts index f30ea1534a..0b069f256d 100644 --- a/drizzle-orm/src/singlestore-core/columns/json.ts +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -1,36 +1,41 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ +export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ name: TName; dataType: 'json'; - columnType: 'MySqlJson'; + columnType: 'SingleStoreJson'; data: unknown; driverParam: string; enumValues: undefined; generated: undefined; }>; -export class MySqlJsonBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlJsonBuilder'; +export class SingleStoreJsonBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreJsonBuilder'; constructor(name: T['name']) { - super(name, 'json', 'MySqlJson'); + super(name, 'json', 'SingleStoreJson'); } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlJson> { - return new MySqlJson>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreJson> { + return new SingleStoreJson>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlJson> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlJson'; +export class SingleStoreJson> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreJson'; getSQLType(): string { return 'json'; @@ -41,6 +46,6 @@ export class MySqlJson> extends } } -export function json(name: TName): MySqlJsonBuilderInitial { - return new MySqlJsonBuilder(name); +export function json(name: TName): SingleStoreJsonBuilderInitial { + return new SingleStoreJsonBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts index 268028b447..b963ee6e5d 100644 --- a/drizzle-orm/src/singlestore-core/columns/mediumint.ts +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -1,45 +1,45 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; -import type { MySqlIntConfig } from './int.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; -export type MySqlMediumIntBuilderInitial = MySqlMediumIntBuilder<{ +export type SingleStoreMediumIntBuilderInitial = SingleStoreMediumIntBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlMediumInt'; + columnType: 'SingleStoreMediumInt'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlMediumIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreMediumIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlMediumIntBuilder'; + static readonly [entityKind]: string = 'SingleStoreMediumIntBuilder'; - constructor(name: T['name'], config?: MySqlIntConfig) { - super(name, 'number', 'MySqlMediumInt'); + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreMediumInt'); this.config.unsigned = config ? config.unsigned : false; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlMediumInt> { - return new MySqlMediumInt>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreMediumInt> { + return new SingleStoreMediumInt>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlMediumInt> - extends MySqlColumnWithAutoIncrement +export class SingleStoreMediumInt> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlMediumInt'; + static readonly [entityKind]: string = 'SingleStoreMediumInt'; getSQLType(): string { return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; @@ -55,7 +55,7 @@ export class MySqlMediumInt( name: TName, - config?: MySqlIntConfig, -): MySqlMediumIntBuilderInitial { - return new MySqlMediumIntBuilder(name, config); + config?: SingleStoreIntConfig, +): SingleStoreMediumIntBuilderInitial { + return new SingleStoreMediumIntBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts index 7dd41dda0c..cc66f6c569 100644 --- a/drizzle-orm/src/singlestore-core/columns/real.ts +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -1,46 +1,51 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -export type MySqlRealBuilderInitial = MySqlRealBuilder<{ +export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlReal'; + columnType: 'SingleStoreReal'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlRealBuilder> - extends MySqlColumnBuilderWithAutoIncrement< +export class SingleStoreRealBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement< T, - MySqlRealConfig + SingleStoreRealConfig > { - static readonly [entityKind]: string = 'MySqlRealBuilder'; + static readonly [entityKind]: string = 'SingleStoreRealBuilder'; - constructor(name: T['name'], config: MySqlRealConfig | undefined) { - super(name, 'number', 'MySqlReal'); + constructor(name: T['name'], config: SingleStoreRealConfig | undefined) { + super(name, 'number', 'SingleStoreReal'); this.config.precision = config?.precision; this.config.scale = config?.scale; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlReal> { - return new MySqlReal>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreReal> { + return new SingleStoreReal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlReal> extends MySqlColumnWithAutoIncrement< - T, - MySqlRealConfig -> { - static readonly [entityKind]: string = 'MySqlReal'; +export class SingleStoreReal> + extends SingleStoreColumnWithAutoIncrement< + T, + SingleStoreRealConfig + > +{ + static readonly [entityKind]: string = 'SingleStoreReal'; precision: number | undefined = this.config.precision; scale: number | undefined = this.config.scale; @@ -56,11 +61,14 @@ export class MySqlReal> extend } } -export interface MySqlRealConfig { +export interface SingleStoreRealConfig { precision?: number; scale?: number; } -export function real(name: TName, config: MySqlRealConfig = {}): MySqlRealBuilderInitial { - return new MySqlRealBuilder(name, config); +export function real( + name: TName, + config: SingleStoreRealConfig = {}, +): SingleStoreRealBuilderInitial { + return new SingleStoreRealBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts index 0f87f0bf57..30fb7a40ed 100644 --- a/drizzle-orm/src/singlestore-core/columns/serial.ts +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -9,17 +9,17 @@ import type { } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -export type MySqlSerialBuilderInitial = IsAutoincrement< +export type SingleStoreSerialBuilderInitial = IsAutoincrement< IsPrimaryKey< NotNull< HasDefault< - MySqlSerialBuilder<{ + SingleStoreSerialBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlSerial'; + columnType: 'SingleStoreSerial'; data: number; driverParam: number; enumValues: undefined; @@ -30,29 +30,32 @@ export type MySqlSerialBuilderInitial = IsAutoincrement< > >; -export class MySqlSerialBuilder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreSerialBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSerialBuilder'; + static readonly [entityKind]: string = 'SingleStoreSerialBuilder'; constructor(name: T['name']) { - super(name, 'number', 'MySqlSerial'); + super(name, 'number', 'SingleStoreSerial'); this.config.hasDefault = true; this.config.autoIncrement = true; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlSerial> { - return new MySqlSerial>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSerial> { + return new SingleStoreSerial>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlSerial< - T extends ColumnBaseConfig<'number', 'MySqlSerial'>, -> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSerial'; +export class SingleStoreSerial< + T extends ColumnBaseConfig<'number', 'SingleStoreSerial'>, +> extends SingleStoreColumnWithAutoIncrement { + static readonly [entityKind]: string = 'SingleStoreSerial'; getSQLType(): string { return 'serial'; @@ -66,6 +69,6 @@ export class MySqlSerial< } } -export function serial(name: TName): MySqlSerialBuilderInitial { - return new MySqlSerialBuilder(name) as MySqlSerialBuilderInitial; +export function serial(name: TName): SingleStoreSerialBuilderInitial { + return new SingleStoreSerialBuilder(name) as SingleStoreSerialBuilderInitial; } diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts index fc1dd0d552..02e1726081 100644 --- a/drizzle-orm/src/singlestore-core/columns/smallint.ts +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -1,45 +1,45 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; -import type { MySqlIntConfig } from './int.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; -export type MySqlSmallIntBuilderInitial = MySqlSmallIntBuilder<{ +export type SingleStoreSmallIntBuilderInitial = SingleStoreSmallIntBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlSmallInt'; + columnType: 'SingleStoreSmallInt'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlSmallIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreSmallIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSmallIntBuilder'; + static readonly [entityKind]: string = 'SingleStoreSmallIntBuilder'; - constructor(name: T['name'], config?: MySqlIntConfig) { - super(name, 'number', 'MySqlSmallInt'); + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreSmallInt'); this.config.unsigned = config ? config.unsigned : false; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlSmallInt> { - return new MySqlSmallInt>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSmallInt> { + return new SingleStoreSmallInt>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlSmallInt> - extends MySqlColumnWithAutoIncrement +export class SingleStoreSmallInt> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSmallInt'; + static readonly [entityKind]: string = 'SingleStoreSmallInt'; getSQLType(): string { return `smallint${this.config.unsigned ? ' unsigned' : ''}`; @@ -55,7 +55,7 @@ export class MySqlSmallInt export function smallint( name: TName, - config?: MySqlIntConfig, -): MySqlSmallIntBuilderInitial { - return new MySqlSmallIntBuilder(name, config); + config?: SingleStoreIntConfig, +): SingleStoreSmallIntBuilderInitial { + return new SingleStoreSmallIntBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts index 72c232e16a..8c40039f04 100644 --- a/drizzle-orm/src/singlestore-core/columns/text.ts +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -1,48 +1,54 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; +export type SingleStoreTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; -export type MySqlTextBuilderInitial = MySqlTextBuilder<{ - name: TName; - dataType: 'string'; - columnType: 'MySqlText'; - data: TEnum[number]; - driverParam: string; - enumValues: TEnum; - generated: undefined; -}>; +export type SingleStoreTextBuilderInitial = + SingleStoreTextBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; -export class MySqlTextBuilder> extends MySqlColumnBuilder< - T, - { textType: MySqlTextColumnType; enumValues: T['enumValues'] } -> { - static readonly [entityKind]: string = 'MySqlTextBuilder'; +export class SingleStoreTextBuilder> + extends SingleStoreColumnBuilder< + T, + { textType: SingleStoreTextColumnType; enumValues: T['enumValues'] } + > +{ + static readonly [entityKind]: string = 'SingleStoreTextBuilder'; - constructor(name: T['name'], textType: MySqlTextColumnType, config: MySqlTextConfig) { - super(name, 'string', 'MySqlText'); + constructor(name: T['name'], textType: SingleStoreTextColumnType, config: SingleStoreTextConfig) { + super(name, 'string', 'SingleStoreText'); this.config.textType = textType; this.config.enumValues = config.enum; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlText> { - return new MySqlText>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreText> { + return new SingleStoreText>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlText> - extends MySqlColumn +export class SingleStoreText> + extends SingleStoreColumn { - static readonly [entityKind]: string = 'MySqlText'; + static readonly [entityKind]: string = 'SingleStoreText'; - private textType: MySqlTextColumnType = this.config.textType; + private textType: SingleStoreTextColumnType = this.config.textType; override readonly enumValues = this.config.enumValues; @@ -51,34 +57,34 @@ export class MySqlText> } } -export interface MySqlTextConfig { +export interface SingleStoreTextConfig { enum?: TEnum; } export function text>( name: TName, - config: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - return new MySqlTextBuilder(name, 'text', config); + config: SingleStoreTextConfig> = {}, +): SingleStoreTextBuilderInitial> { + return new SingleStoreTextBuilder(name, 'text', config); } export function tinytext>( name: TName, - config: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - return new MySqlTextBuilder(name, 'tinytext', config); + config: SingleStoreTextConfig> = {}, +): SingleStoreTextBuilderInitial> { + return new SingleStoreTextBuilder(name, 'tinytext', config); } export function mediumtext>( name: TName, - config: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - return new MySqlTextBuilder(name, 'mediumtext', config); + config: SingleStoreTextConfig> = {}, +): SingleStoreTextBuilderInitial> { + return new SingleStoreTextBuilder(name, 'mediumtext', config); } export function longtext>( name: TName, - config: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - return new MySqlTextBuilder(name, 'longtext', config); + config: SingleStoreTextConfig> = {}, +): SingleStoreTextBuilderInitial> { + return new SingleStoreTextBuilder(name, 'longtext', config); } diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts index ae2251bda8..a5259adbb0 100644 --- a/drizzle-orm/src/singlestore-core/columns/time.ts +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -1,45 +1,50 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ +export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlTime'; + columnType: 'SingleStoreTime'; data: string; driverParam: string | number; enumValues: undefined; generated: undefined; }>; -export class MySqlTimeBuilder> extends MySqlColumnBuilder< - T, - TimeConfig -> { - static readonly [entityKind]: string = 'MySqlTimeBuilder'; +export class SingleStoreTimeBuilder> + extends SingleStoreColumnBuilder< + T, + TimeConfig + > +{ + static readonly [entityKind]: string = 'SingleStoreTimeBuilder'; constructor( name: T['name'], config: TimeConfig | undefined, ) { - super(name, 'string', 'MySqlTime'); + super(name, 'string', 'SingleStoreTime'); this.config.fsp = config?.fsp; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlTime> { - return new MySqlTime>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTime> { + return new SingleStoreTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlTime< - T extends ColumnBaseConfig<'string', 'MySqlTime'>, -> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlTime'; +export class SingleStoreTime< + T extends ColumnBaseConfig<'string', 'SingleStoreTime'>, +> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreTime'; readonly fsp: number | undefined = this.config.fsp; @@ -53,6 +58,6 @@ export type TimeConfig = { fsp?: 0 | 1 | 2 | 3 | 4 | 5 | 6; }; -export function time(name: TName, config?: TimeConfig): MySqlTimeBuilderInitial { - return new MySqlTimeBuilder(name, config); +export function time(name: TName, config?: TimeConfig): SingleStoreTimeBuilderInitial { + return new SingleStoreTimeBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index 24e3b26508..db770b6c73 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -1,45 +1,45 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Equal } from '~/utils.ts'; -import { MySqlDateBaseColumn, MySqlDateColumnBaseBuilder } from './date.common.ts'; +import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; -export type MySqlTimestampBuilderInitial = MySqlTimestampBuilder<{ +export type SingleStoreTimestampBuilderInitial = SingleStoreTimestampBuilder<{ name: TName; dataType: 'date'; - columnType: 'MySqlTimestamp'; + columnType: 'SingleStoreTimestamp'; data: Date; driverParam: string | number; enumValues: undefined; generated: undefined; }>; -export class MySqlTimestampBuilder> - extends MySqlDateColumnBaseBuilder +export class SingleStoreTimestampBuilder> + extends SingleStoreDateColumnBaseBuilder { - static readonly [entityKind]: string = 'MySqlTimestampBuilder'; + static readonly [entityKind]: string = 'SingleStoreTimestampBuilder'; - constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { - super(name, 'date', 'MySqlTimestamp'); + constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + super(name, 'date', 'SingleStoreTimestamp'); this.config.fsp = config?.fsp; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlTimestamp> { - return new MySqlTimestamp>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestamp> { + return new SingleStoreTimestamp>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlTimestamp> - extends MySqlDateBaseColumn +export class SingleStoreTimestamp> + extends SingleStoreDateBaseColumn { - static readonly [entityKind]: string = 'MySqlTimestamp'; + static readonly [entityKind]: string = 'SingleStoreTimestamp'; readonly fsp: number | undefined = this.config.fsp; @@ -57,41 +57,41 @@ export class MySqlTimestamp } } -export type MySqlTimestampStringBuilderInitial = MySqlTimestampStringBuilder<{ +export type SingleStoreTimestampStringBuilderInitial = SingleStoreTimestampStringBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlTimestampString'; + columnType: 'SingleStoreTimestampString'; data: string; driverParam: string | number; enumValues: undefined; generated: undefined; }>; -export class MySqlTimestampStringBuilder> - extends MySqlDateColumnBaseBuilder -{ - static readonly [entityKind]: string = 'MySqlTimestampStringBuilder'; +export class SingleStoreTimestampStringBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreTimestampString'>, +> extends SingleStoreDateColumnBaseBuilder { + static readonly [entityKind]: string = 'SingleStoreTimestampStringBuilder'; - constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { - super(name, 'string', 'MySqlTimestampString'); + constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + super(name, 'string', 'SingleStoreTimestampString'); this.config.fsp = config?.fsp; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlTimestampString> { - return new MySqlTimestampString>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestampString> { + return new SingleStoreTimestampString>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlTimestampString> - extends MySqlDateBaseColumn +export class SingleStoreTimestampString> + extends SingleStoreDateBaseColumn { - static readonly [entityKind]: string = 'MySqlTimestampString'; + static readonly [entityKind]: string = 'SingleStoreTimestampString'; readonly fsp: number | undefined = this.config.fsp; @@ -103,19 +103,19 @@ export class MySqlTimestampString { +export interface SingleStoreTimestampConfig { mode?: TMode; fsp?: TimestampFsp; } -export function timestamp( +export function timestamp( name: TName, - config?: MySqlTimestampConfig, -): Equal extends true ? MySqlTimestampStringBuilderInitial - : MySqlTimestampBuilderInitial; -export function timestamp(name: string, config: MySqlTimestampConfig = {}) { + config?: SingleStoreTimestampConfig, +): Equal extends true ? SingleStoreTimestampStringBuilderInitial + : SingleStoreTimestampBuilderInitial; +export function timestamp(name: string, config: SingleStoreTimestampConfig = {}) { if (config.mode === 'string') { - return new MySqlTimestampStringBuilder(name, config); + return new SingleStoreTimestampStringBuilder(name, config); } - return new MySqlTimestampBuilder(name, config); + return new SingleStoreTimestampBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts index c749e6da8b..d911cae96e 100644 --- a/drizzle-orm/src/singlestore-core/columns/tinyint.ts +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -1,45 +1,45 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; -import type { MySqlIntConfig } from './int.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; -export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuilder<{ +export type SingleStoreTinyIntBuilderInitial = SingleStoreTinyIntBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlTinyInt'; + columnType: 'SingleStoreTinyInt'; data: number; driverParam: number | string; enumValues: undefined; generated: undefined; }>; -export class MySqlTinyIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement +export class SingleStoreTinyIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlTinyIntBuilder'; + static readonly [entityKind]: string = 'SingleStoreTinyIntBuilder'; - constructor(name: T['name'], config?: MySqlIntConfig) { - super(name, 'number', 'MySqlTinyInt'); + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreTinyInt'); this.config.unsigned = config ? config.unsigned : false; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlTinyInt> { - return new MySqlTinyInt>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTinyInt> { + return new SingleStoreTinyInt>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlTinyInt> - extends MySqlColumnWithAutoIncrement +export class SingleStoreTinyInt> + extends SingleStoreColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlTinyInt'; + static readonly [entityKind]: string = 'SingleStoreTinyInt'; getSQLType(): string { return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; @@ -53,6 +53,9 @@ export class MySqlTinyInt> } } -export function tinyint(name: TName, config?: MySqlIntConfig): MySqlTinyIntBuilderInitial { - return new MySqlTinyIntBuilder(name, config); +export function tinyint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreTinyIntBuilderInitial { + return new SingleStoreTinyIntBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts index be0a89cf64..545b87476f 100644 --- a/drizzle-orm/src/singlestore-core/columns/varbinary.ts +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -1,45 +1,45 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryBuilder<{ +export type SingleStoreVarBinaryBuilderInitial = SingleStoreVarBinaryBuilder<{ name: TName; dataType: 'string'; - columnType: 'MySqlVarBinary'; + columnType: 'SingleStoreVarBinary'; data: string; driverParam: string; enumValues: undefined; generated: undefined; }>; -export class MySqlVarBinaryBuilder> - extends MySqlColumnBuilder +export class SingleStoreVarBinaryBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'MySqlVarBinaryBuilder'; + static readonly [entityKind]: string = 'SingleStoreVarBinaryBuilder'; /** @internal */ - constructor(name: T['name'], config: MySqlVarbinaryOptions) { - super(name, 'string', 'MySqlVarBinary'); + constructor(name: T['name'], config: SingleStoreVarbinaryOptions) { + super(name, 'string', 'SingleStoreVarBinary'); this.config.length = config?.length; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlVarBinary> { - return new MySqlVarBinary>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarBinary> { + return new SingleStoreVarBinary>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlVarBinary< - T extends ColumnBaseConfig<'string', 'MySqlVarBinary'>, -> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlVarBinary'; +export class SingleStoreVarBinary< + T extends ColumnBaseConfig<'string', 'SingleStoreVarBinary'>, +> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreVarBinary'; length: number | undefined = this.config.length; @@ -48,13 +48,13 @@ export class MySqlVarBinary< } } -export interface MySqlVarbinaryOptions { +export interface SingleStoreVarbinaryOptions { length: number; } export function varbinary( name: TName, - options: MySqlVarbinaryOptions, -): MySqlVarBinaryBuilderInitial { - return new MySqlVarBinaryBuilder(name, options); + options: SingleStoreVarbinaryOptions, +): SingleStoreVarBinaryBuilderInitial { + return new SingleStoreVarBinaryBuilder(name, options); } diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts index b692bf7890..415b3c27bb 100644 --- a/drizzle-orm/src/singlestore-core/columns/varchar.ts +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -1,49 +1,50 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlVarCharBuilderInitial = MySqlVarCharBuilder< - { - name: TName; - dataType: 'string'; - columnType: 'MySqlVarChar'; - data: TEnum[number]; - driverParam: number | string; - enumValues: TEnum; - generated: undefined; - } ->; +export type SingleStoreVarCharBuilderInitial = + SingleStoreVarCharBuilder< + { + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + } + >; -export class MySqlVarCharBuilder> - extends MySqlColumnBuilder> +export class SingleStoreVarCharBuilder> + extends SingleStoreColumnBuilder> { - static readonly [entityKind]: string = 'MySqlVarCharBuilder'; + static readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; /** @internal */ - constructor(name: T['name'], config: MySqlVarCharConfig) { - super(name, 'string', 'MySqlVarChar'); + constructor(name: T['name'], config: SingleStoreVarCharConfig) { + super(name, 'string', 'SingleStoreVarChar'); this.config.length = config.length; this.config.enum = config.enum; } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlVarChar & { enumValues: T['enumValues'] }> { - return new MySqlVarChar & { enumValues: T['enumValues'] }>( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarChar & { enumValues: T['enumValues'] }> { + return new SingleStoreVarChar & { enumValues: T['enumValues'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlVarChar> - extends MySqlColumn> +export class SingleStoreVarChar> + extends SingleStoreColumn> { - static readonly [entityKind]: string = 'MySqlVarChar'; + static readonly [entityKind]: string = 'SingleStoreVarChar'; readonly length: number | undefined = this.config.length; @@ -54,14 +55,14 @@ export class MySqlVarChar> } } -export interface MySqlVarCharConfig { +export interface SingleStoreVarCharConfig { length: number; enum?: TEnum; } export function varchar>( name: TName, - config: MySqlVarCharConfig>, -): MySqlVarCharBuilderInitial> { - return new MySqlVarCharBuilder(name, config); + config: SingleStoreVarCharConfig>, +): SingleStoreVarCharBuilderInitial> { + return new SingleStoreVarCharBuilder(name, config); } diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts index 224de12e9f..c774b44d81 100644 --- a/drizzle-orm/src/singlestore-core/columns/year.ts +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -1,44 +1,49 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type MySqlYearBuilderInitial = MySqlYearBuilder<{ +export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ name: TName; dataType: 'number'; - columnType: 'MySqlYear'; + columnType: 'SingleStoreYear'; data: number; driverParam: number; enumValues: undefined; generated: undefined; }>; -export class MySqlYearBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlYearBuilder'; +export class SingleStoreYearBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreYearBuilder'; constructor(name: T['name']) { - super(name, 'number', 'MySqlYear'); + super(name, 'number', 'SingleStoreYear'); } /** @internal */ override build( - table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlYear> { - return new MySqlYear>(table, this.config as ColumnBuilderRuntimeConfig); + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreYear> { + return new SingleStoreYear>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class MySqlYear< - T extends ColumnBaseConfig<'number', 'MySqlYear'>, -> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlYear'; +export class SingleStoreYear< + T extends ColumnBaseConfig<'number', 'SingleStoreYear'>, +> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreYear'; getSQLType(): string { return `year`; } } -export function year(name: TName): MySqlYearBuilderInitial { - return new MySqlYearBuilder(name); +export function year(name: TName): SingleStoreYearBuilderInitial { + return new SingleStoreYearBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 8df6ff3439..7157bc6f4f 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -6,35 +6,35 @@ import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; -import type { MySqlDialect } from './dialect.ts'; +import type { SingleStoreDialect } from './dialect.ts'; import { - MySqlDeleteBase, - MySqlInsertBuilder, - MySqlSelectBuilder, - MySqlUpdateBuilder, QueryBuilder, + SingleStoreDeleteBase, + SingleStoreInsertBuilder, + SingleStoreSelectBuilder, + SingleStoreUpdateBuilder, } from './query-builders/index.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { Mode, - MySqlQueryResultHKT, - MySqlQueryResultKind, - MySqlSession, - MySqlTransaction, - MySqlTransactionConfig, PreparedQueryHKTBase, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, + SingleStoreTransaction, + SingleStoreTransactionConfig, } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; -import type { MySqlTable } from './table.ts'; +import type { SingleStoreTable } from './table.ts'; -export class MySqlDatabase< - TQueryResult extends MySqlQueryResultHKT, +export class SingleStoreDatabase< + TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, TFullSchema extends Record = {}, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations, > { - static readonly [entityKind]: string = 'MySqlDatabase'; + static readonly [entityKind]: string = 'SingleStoreDatabase'; declare readonly _: { readonly schema: TSchema | undefined; @@ -50,9 +50,9 @@ export class MySqlDatabase< constructor( /** @internal */ - readonly dialect: MySqlDialect, + readonly dialect: SingleStoreDialect, /** @internal */ - readonly session: MySqlSession, + readonly session: SingleStoreSession, schema: RelationalSchemaConfig | undefined, protected readonly mode: Mode, ) { @@ -70,12 +70,12 @@ export class MySqlDatabase< this.query = {} as typeof this['query']; if (this._.schema) { for (const [tableName, columns] of Object.entries(this._.schema)) { - (this.query as MySqlDatabase>['query'])[tableName] = + (this.query as SingleStoreDatabase>['query'])[tableName] = new RelationalQueryBuilder( schema!.fullSchema, this._.schema, this._.tableNamesMap, - schema!.fullSchema[tableName] as MySqlTable, + schema!.fullSchema[tableName] as SingleStoreTable, columns, dialect, session, @@ -192,12 +192,12 @@ export class MySqlDatabase< * .from(cars); * ``` */ - function select(): MySqlSelectBuilder; + function select(): SingleStoreSelectBuilder; function select( fields: TSelection, - ): MySqlSelectBuilder; - function select(fields?: SelectedFields): MySqlSelectBuilder { - return new MySqlSelectBuilder({ + ): SingleStoreSelectBuilder; + function select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: self.session, dialect: self.dialect, @@ -229,14 +229,14 @@ export class MySqlDatabase< * .orderBy(cars.brand); * ``` */ - function selectDistinct(): MySqlSelectBuilder; + function selectDistinct(): SingleStoreSelectBuilder; function selectDistinct( fields: TSelection, - ): MySqlSelectBuilder; + ): SingleStoreSelectBuilder; function selectDistinct( fields?: SelectedFields, - ): MySqlSelectBuilder { - return new MySqlSelectBuilder({ + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: self.session, dialect: self.dialect, @@ -266,10 +266,10 @@ export class MySqlDatabase< * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); * ``` */ - function update( + function update( table: TTable, - ): MySqlUpdateBuilder { - return new MySqlUpdateBuilder(table, self.session, self.dialect, queries); + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, self.session, self.dialect, queries); } /** @@ -291,10 +291,10 @@ export class MySqlDatabase< * await db.delete(cars).where(eq(cars.color, 'green')); * ``` */ - function delete_( + function delete_( table: TTable, - ): MySqlDeleteBase { - return new MySqlDeleteBase(table, self.session, self.dialect, queries); + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, self.session, self.dialect, queries); } return { select, selectDistinct, update, delete: delete_ }; @@ -336,10 +336,12 @@ export class MySqlDatabase< * .from(cars); * ``` */ - select(): MySqlSelectBuilder; - select(fields: TSelection): MySqlSelectBuilder; - select(fields?: SelectedFields): MySqlSelectBuilder { - return new MySqlSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }); + select(): SingleStoreSelectBuilder; + select( + fields: TSelection, + ): SingleStoreSelectBuilder; + select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }); } /** @@ -366,12 +368,12 @@ export class MySqlDatabase< * .orderBy(cars.brand); * ``` */ - selectDistinct(): MySqlSelectBuilder; + selectDistinct(): SingleStoreSelectBuilder; selectDistinct( fields: TSelection, - ): MySqlSelectBuilder; - selectDistinct(fields?: SelectedFields): MySqlSelectBuilder { - return new MySqlSelectBuilder({ + ): SingleStoreSelectBuilder; + selectDistinct(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect, @@ -400,8 +402,10 @@ export class MySqlDatabase< * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); * ``` */ - update(table: TTable): MySqlUpdateBuilder { - return new MySqlUpdateBuilder(table, this.session, this.dialect); + update( + table: TTable, + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, this.session, this.dialect); } /** @@ -423,8 +427,10 @@ export class MySqlDatabase< * await db.insert(cars).values([{ brand: 'BMW' }, { brand: 'Porsche' }]); * ``` */ - insert(table: TTable): MySqlInsertBuilder { - return new MySqlInsertBuilder(table, this.session, this.dialect); + insert( + table: TTable, + ): SingleStoreInsertBuilder { + return new SingleStoreInsertBuilder(table, this.session, this.dialect); } /** @@ -446,35 +452,37 @@ export class MySqlDatabase< * await db.delete(cars).where(eq(cars.color, 'green')); * ``` */ - delete(table: TTable): MySqlDeleteBase { - return new MySqlDeleteBase(table, this.session, this.dialect); + delete( + table: TTable, + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, this.session, this.dialect); } execute( query: SQLWrapper, - ): Promise> { + ): Promise> { return this.session.execute(query.getSQL()); } transaction( transaction: ( - tx: MySqlTransaction, - config?: MySqlTransactionConfig, + tx: SingleStoreTransaction, + config?: SingleStoreTransactionConfig, ) => Promise, - config?: MySqlTransactionConfig, + config?: SingleStoreTransactionConfig, ): Promise { return this.session.transaction(transaction, config); } } -export type MySQLWithReplicas = Q & { $primary: Q }; +export type SingleStoreWithReplicas = Q & { $primary: Q }; export const withReplicas = < - HKT extends MySqlQueryResultHKT, + HKT extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, TFullSchema extends Record, TSchema extends TablesRelationalConfig, - Q extends MySqlDatabase< + Q extends SingleStoreDatabase< HKT, TPreparedQueryHKT, TFullSchema, @@ -484,7 +492,7 @@ export const withReplicas = < primary: Q, replicas: [Q, ...Q[]], getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, -): MySQLWithReplicas => { +): SingleStoreWithReplicas => { const select: Q['select'] = (...args: []) => getReplica(replicas).select(...args); const selectDistinct: Q['selectDistinct'] = (...args: []) => getReplica(replicas).selectDistinct(...args); const $with: Q['with'] = (...args: []) => getReplica(replicas).with(...args); diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 04383a2c65..d72424c8e6 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -22,21 +22,25 @@ import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; -import { MySqlColumn } from './columns/common.ts'; -import type { MySqlDeleteConfig } from './query-builders/delete.ts'; -import type { MySqlInsertConfig } from './query-builders/insert.ts'; -import type { MySqlSelectConfig, MySqlSelectJoinConfig, SelectedFieldsOrdered } from './query-builders/select.types.ts'; -import type { MySqlUpdateConfig } from './query-builders/update.ts'; -import type { MySqlSession } from './session.ts'; -import { MySqlTable } from './table.ts'; -import { MySqlViewBase } from './view-base.ts'; - -export class MySqlDialect { - static readonly [entityKind]: string = 'MySqlDialect'; +import { SingleStoreColumn } from './columns/common.ts'; +import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; +import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; +import type { + SelectedFieldsOrdered, + SingleStoreSelectConfig, + SingleStoreSelectJoinConfig, +} from './query-builders/select.types.ts'; +import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; +import type { SingleStoreSession } from './session.ts'; +import { SingleStoreTable } from './table.ts'; +import { SingleStoreViewBase } from './view-base.ts'; + +export class SingleStoreDialect { + static readonly [entityKind]: string = 'SingleStoreDialect'; async migrate( migrations: MigrationMeta[], - session: MySqlSession, + session: SingleStoreSession, config: Omit, ): Promise { const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; @@ -100,7 +104,7 @@ export class MySqlDialect { return sql.join(withSqlChunks); } - buildDeleteQuery({ table, where, returning, withList }: MySqlDeleteConfig): SQL { + buildDeleteQuery({ table, where, returning, withList }: SingleStoreDeleteConfig): SQL { const withSql = this.buildWithCTE(withList); const returningSql = returning @@ -112,7 +116,7 @@ export class MySqlDialect { return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; } - buildUpdateSet(table: MySqlTable, set: UpdateSet): SQL { + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { const tableColumns = table[Table.Symbol.Columns]; const columnNames = Object.keys(tableColumns).filter((colName) => @@ -133,7 +137,7 @@ export class MySqlDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList }: MySqlUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList }: SingleStoreUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); const setSql = this.buildUpdateSet(table, set); @@ -177,7 +181,7 @@ export class MySqlDialect { chunk.push( new SQL( query.queryChunks.map((c) => { - if (is(c, MySqlColumn)) { + if (is(c, SingleStoreColumn)) { return sql.identifier(c.name); } return c; @@ -225,16 +229,16 @@ export class MySqlDialect { lockingClause, distinct, setOperators, - }: MySqlSelectConfig, + }: SingleStoreSelectConfig, ): SQL { - const fieldsList = fieldsFlat ?? orderSelectedFields(fields); + const fieldsList = fieldsFlat ?? orderSelectedFields(fields); for (const f of fieldsList) { if ( is(f.field, Column) && getTableName(f.field.table) !== (is(table, Subquery) ? table._.alias - : is(table, MySqlViewBase) + : is(table, SingleStoreViewBase) ? table[ViewBaseConfig].name : is(table, SQL) ? undefined @@ -279,10 +283,10 @@ export class MySqlDialect { const table = joinMeta.table; const lateralSql = joinMeta.lateral ? sql` lateral` : undefined; - if (is(table, MySqlTable)) { - const tableName = table[MySqlTable.Symbol.Name]; - const tableSchema = table[MySqlTable.Symbol.Schema]; - const origTableName = table[MySqlTable.Symbol.OriginalName]; + if (is(table, SingleStoreTable)) { + const tableName = table[SingleStoreTable.Symbol.Name]; + const tableSchema = table[SingleStoreTable.Symbol.Schema]; + const origTableName = table[SingleStoreTable.Symbol.OriginalName]; const alias = tableName === origTableName ? undefined : joinMeta.alias; joinsArray.push( sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ @@ -353,7 +357,7 @@ export class MySqlDialect { return finalQuery; } - buildSetOperations(leftSelect: SQL, setOperators: MySqlSelectConfig['setOperators']): SQL { + buildSetOperations(leftSelect: SQL, setOperators: SingleStoreSelectConfig['setOperators']): SQL { const [setOperator, ...rest] = setOperators; if (!setOperator) { @@ -374,7 +378,7 @@ export class MySqlDialect { buildSetOperationQuery({ leftSelect, setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, - }: { leftSelect: SQL; setOperator: MySqlSelectConfig['setOperators'][number] }): SQL { + }: { leftSelect: SQL; setOperator: SingleStoreSelectConfig['setOperators'][number] }): SQL { const leftChunk = sql`(${leftSelect.getSQL()}) `; const rightChunk = sql`(${rightSelect.getSQL()})`; @@ -383,15 +387,15 @@ export class MySqlDialect { const orderByValues: (SQL | Name)[] = []; // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` - // which is invalid MySql syntax, Table from one of the SELECTs cannot be used in global ORDER clause + // which is invalid SingleStore syntax, Table from one of the SELECTs cannot be used in global ORDER clause for (const orderByUnit of orderBy) { - if (is(orderByUnit, MySqlColumn)) { + if (is(orderByUnit, SingleStoreColumn)) { orderByValues.push(sql.identifier(orderByUnit.name)); } else if (is(orderByUnit, SQL)) { for (let i = 0; i < orderByUnit.queryChunks.length; i++) { const chunk = orderByUnit.queryChunks[i]; - if (is(chunk, MySqlColumn)) { + if (is(chunk, SingleStoreColumn)) { orderByUnit.queryChunks[i] = sql.identifier(chunk.name); } } @@ -417,12 +421,12 @@ export class MySqlDialect { } buildInsertQuery( - { table, values, ignore, onConflict }: MySqlInsertConfig, + { table, values, ignore, onConflict }: SingleStoreInsertConfig, ): { sql: SQL; generatedIds: Record[] } { // const isSingleValue = values.length === 1; const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; - const columns: Record = table[Table.Symbol.Columns]; - const colEntries: [string, MySqlColumn][] = Object.entries(columns).filter(([_, col]) => + const columns: Record = table[Table.Symbol.Columns]; + const colEntries: [string, SingleStoreColumn][] = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert() ); @@ -500,16 +504,16 @@ export class MySqlDialect { fullSchema: Record; schema: TablesRelationalConfig; tableNamesMap: Record; - table: MySqlTable; + table: SingleStoreTable; tableConfig: TableRelationalConfig; queryConfig: true | DBQueryConfig<'many', true>; tableAlias: string; nestedQueryRelation?: Relation; joinOn?: SQL; - }): BuildRelationalQueryResult { - let selection: BuildRelationalQueryResult['selection'] = []; - let limit, offset, orderBy: MySqlSelectConfig['orderBy'], where; - const joins: MySqlSelectJoinConfig[] = []; + }): BuildRelationalQueryResult { + let selection: BuildRelationalQueryResult['selection'] = []; + let limit, offset, orderBy: SingleStoreSelectConfig['orderBy'], where; + const joins: SingleStoreSelectJoinConfig[] = []; if (config === true) { const selectionEntries = Object.entries(tableConfig.columns); @@ -518,7 +522,7 @@ export class MySqlDialect { ) => ({ dbKey: value.name, tsKey: key, - field: aliasedTableColumn(value as MySqlColumn, tableAlias), + field: aliasedTableColumn(value as SingleStoreColumn, tableAlias), relationTableTsKey: undefined, isJson: false, selection: [], @@ -535,7 +539,7 @@ export class MySqlDialect { where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias); } - const fieldsSelection: { tsKey: string; value: MySqlColumn | SQL.Aliased }[] = []; + const fieldsSelection: { tsKey: string; value: SingleStoreColumn | SQL.Aliased }[] = []; let selectedColumns: string[] = []; // Figure out which columns to select @@ -566,7 +570,7 @@ export class MySqlDialect { } for (const field of selectedColumns) { - const column = tableConfig.columns[field]! as MySqlColumn; + const column = tableConfig.columns[field]! as SingleStoreColumn; fieldsSelection.push({ tsKey: field, value: column }); } @@ -619,7 +623,7 @@ export class MySqlDialect { } orderBy = orderByOrig.map((orderByValue) => { if (is(orderByValue, Column)) { - return aliasedTableColumn(orderByValue, tableAlias) as MySqlColumn; + return aliasedTableColumn(orderByValue, tableAlias) as SingleStoreColumn; } return mapColumnsInSQLToAlias(orderByValue, tableAlias); }); @@ -651,7 +655,7 @@ export class MySqlDialect { fullSchema, schema, tableNamesMap, - table: fullSchema[relationTableTsName] as MySqlTable, + table: fullSchema[relationTableTsName] as SingleStoreTable, tableConfig: schema[relationTableTsName]!, queryConfig: is(relation, One) ? (selectedRelationConfigValue === true @@ -747,7 +751,7 @@ export class MySqlDialect { } result = this.buildSelectQuery({ - table: is(result, MySqlTable) ? result : new Subquery(result, {}, tableAlias), + table: is(result, SingleStoreTable) ? result : new Subquery(result, {}, tableAlias), fields: {}, fieldsFlat: nestedSelection.map(({ field }) => ({ path: [], @@ -798,15 +802,15 @@ export class MySqlDialect { fullSchema: Record; schema: TablesRelationalConfig; tableNamesMap: Record; - table: MySqlTable; + table: SingleStoreTable; tableConfig: TableRelationalConfig; queryConfig: true | DBQueryConfig<'many', true>; tableAlias: string; nestedQueryRelation?: Relation; joinOn?: SQL; - }): BuildRelationalQueryResult { - let selection: BuildRelationalQueryResult['selection'] = []; - let limit, offset, orderBy: MySqlSelectConfig['orderBy'] = [], where; + }): BuildRelationalQueryResult { + let selection: BuildRelationalQueryResult['selection'] = []; + let limit, offset, orderBy: SingleStoreSelectConfig['orderBy'] = [], where; if (config === true) { const selectionEntries = Object.entries(tableConfig.columns); @@ -815,7 +819,7 @@ export class MySqlDialect { ) => ({ dbKey: value.name, tsKey: key, - field: aliasedTableColumn(value as MySqlColumn, tableAlias), + field: aliasedTableColumn(value as SingleStoreColumn, tableAlias), relationTableTsKey: undefined, isJson: false, selection: [], @@ -832,7 +836,7 @@ export class MySqlDialect { where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias); } - const fieldsSelection: { tsKey: string; value: MySqlColumn | SQL.Aliased }[] = []; + const fieldsSelection: { tsKey: string; value: SingleStoreColumn | SQL.Aliased }[] = []; let selectedColumns: string[] = []; // Figure out which columns to select @@ -863,7 +867,7 @@ export class MySqlDialect { } for (const field of selectedColumns) { - const column = tableConfig.columns[field]! as MySqlColumn; + const column = tableConfig.columns[field]! as SingleStoreColumn; fieldsSelection.push({ tsKey: field, value: column }); } @@ -916,7 +920,7 @@ export class MySqlDialect { } orderBy = orderByOrig.map((orderByValue) => { if (is(orderByValue, Column)) { - return aliasedTableColumn(orderByValue, tableAlias) as MySqlColumn; + return aliasedTableColumn(orderByValue, tableAlias) as SingleStoreColumn; } return mapColumnsInSQLToAlias(orderByValue, tableAlias); }); @@ -948,7 +952,7 @@ export class MySqlDialect { fullSchema, schema, tableNamesMap, - table: fullSchema[relationTableTsName] as MySqlTable, + table: fullSchema[relationTableTsName] as SingleStoreTable, tableConfig: schema[relationTableTsName]!, queryConfig: is(relation, One) ? (selectedRelationConfigValue === true @@ -990,7 +994,7 @@ export class MySqlDialect { let field = sql`json_to_array(${ sql.join( selection.map(({ field }) => - is(field, MySqlColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field + is(field, SingleStoreColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field ), sql`, `, ) @@ -1040,7 +1044,7 @@ export class MySqlDialect { } result = this.buildSelectQuery({ - table: is(result, MySqlTable) ? result : new Subquery(result, {}, tableAlias), + table: is(result, SingleStoreTable) ? result : new Subquery(result, {}, tableAlias), fields: {}, fieldsFlat: nestedSelection.map(({ field }) => ({ path: [], diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts index a61f77786e..6d4284d180 100644 --- a/drizzle-orm/src/singlestore-core/expressions.ts +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -1,16 +1,16 @@ import { bindIfParam } from '~/expressions.ts'; import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; import { sql } from '~/sql/sql.ts'; -import type { MySqlColumn } from './columns/index.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; export * from '~/expressions.ts'; -export function concat(column: MySqlColumn | SQL.Aliased, value: string | Placeholder | SQLWrapper): SQL { +export function concat(column: SingleStoreColumn | SQL.Aliased, value: string | Placeholder | SQLWrapper): SQL { return sql`${column} || ${bindIfParam(value, column)}`; } export function substring( - column: MySqlColumn | SQL.Aliased, + column: SingleStoreColumn | SQL.Aliased, { from, for: _for }: { from?: number | Placeholder | SQLWrapper; for?: number | Placeholder | SQLWrapper }, ): SQL { const chunks: SQLChunk[] = [sql`substring(`, column]; diff --git a/drizzle-orm/src/singlestore-core/foreign-keys.ts b/drizzle-orm/src/singlestore-core/foreign-keys.ts index 957e1f15cb..fbebd684cb 100644 --- a/drizzle-orm/src/singlestore-core/foreign-keys.ts +++ b/drizzle-orm/src/singlestore-core/foreign-keys.ts @@ -1,18 +1,18 @@ import { entityKind } from '~/entity.ts'; -import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; -import { MySqlTable } from './table.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; export type Reference = () => { readonly name?: string; - readonly columns: MySqlColumn[]; - readonly foreignTable: MySqlTable; - readonly foreignColumns: MySqlColumn[]; + readonly columns: SingleStoreColumn[]; + readonly foreignTable: SingleStoreTable; + readonly foreignColumns: SingleStoreColumn[]; }; export class ForeignKeyBuilder { - static readonly [entityKind]: string = 'MySqlForeignKeyBuilder'; + static readonly [entityKind]: string = 'SingleStoreForeignKeyBuilder'; /** @internal */ reference: Reference; @@ -26,8 +26,8 @@ export class ForeignKeyBuilder { constructor( config: () => { name?: string; - columns: MySqlColumn[]; - foreignColumns: MySqlColumn[]; + columns: SingleStoreColumn[]; + foreignColumns: SingleStoreColumn[]; }, actions?: { onUpdate?: UpdateDeleteAction; @@ -36,7 +36,7 @@ export class ForeignKeyBuilder { ) { this.reference = () => { const { name, columns, foreignColumns } = config(); - return { name, columns, foreignTable: foreignColumns[0]!.table as MySqlTable, foreignColumns }; + return { name, columns, foreignTable: foreignColumns[0]!.table as SingleStoreTable, foreignColumns }; }; if (actions) { this._onUpdate = actions.onUpdate; @@ -55,7 +55,7 @@ export class ForeignKeyBuilder { } /** @internal */ - build(table: MySqlTable): ForeignKey { + build(table: SingleStoreTable): ForeignKey { return new ForeignKey(table, this); } } @@ -63,13 +63,13 @@ export class ForeignKeyBuilder { export type AnyForeignKeyBuilder = ForeignKeyBuilder; export class ForeignKey { - static readonly [entityKind]: string = 'MySqlForeignKey'; + static readonly [entityKind]: string = 'SingleStoreForeignKey'; readonly reference: Reference; readonly onUpdate: UpdateDeleteAction | undefined; readonly onDelete: UpdateDeleteAction | undefined; - constructor(readonly table: MySqlTable, builder: ForeignKeyBuilder) { + constructor(readonly table: SingleStoreTable, builder: ForeignKeyBuilder) { this.reference = builder.reference; this.onUpdate = builder._onUpdate; this.onDelete = builder._onDelete; @@ -80,9 +80,9 @@ export class ForeignKey { const columnNames = columns.map((column) => column.name); const foreignColumnNames = foreignColumns.map((column) => column.name); const chunks = [ - this.table[MySqlTable.Symbol.Name], + this.table[SingleStoreTable.Symbol.Name], ...columnNames, - foreignColumns[0]!.table[MySqlTable.Symbol.Name], + foreignColumns[0]!.table[SingleStoreTable.Symbol.Name], ...foreignColumnNames, ]; return name ?? `${chunks.join('_')}_fk`; @@ -91,20 +91,23 @@ export class ForeignKey { type ColumnsWithTable< TTableName extends string, - TColumns extends MySqlColumn[], -> = { [Key in keyof TColumns]: AnyMySqlColumn<{ tableName: TTableName }> }; + TColumns extends SingleStoreColumn[], +> = { [Key in keyof TColumns]: AnySingleStoreColumn<{ tableName: TTableName }> }; -export type GetColumnsTable = ( - TColumns extends MySqlColumn ? TColumns - : TColumns extends MySqlColumn[] ? TColumns[number] +export type GetColumnsTable = ( + TColumns extends SingleStoreColumn ? TColumns + : TColumns extends SingleStoreColumn[] ? TColumns[number] : never -) extends AnyMySqlColumn<{ tableName: infer TTableName extends string }> ? TTableName +) extends AnySingleStoreColumn<{ tableName: infer TTableName extends string }> ? TTableName : never; export function foreignKey< TTableName extends string, TForeignTableName extends string, - TColumns extends [AnyMySqlColumn<{ tableName: TTableName }>, ...AnyMySqlColumn<{ tableName: TTableName }>[]], + TColumns extends [ + AnySingleStoreColumn<{ tableName: TTableName }>, + ...AnySingleStoreColumn<{ tableName: TTableName }>[], + ], >( config: { name?: string; diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 5b73b1d309..59d2bfb11f 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; -import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; -import type { MySqlTable } from './table.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import type { SingleStoreTable } from './table.ts'; interface IndexConfig { name: string; @@ -29,10 +29,10 @@ interface IndexConfig { lock?: 'default' | 'none' | 'shared' | 'exclusive'; } -export type IndexColumn = MySqlColumn | SQL; +export type IndexColumn = SingleStoreColumn | SQL; export class IndexBuilderOn { - static readonly [entityKind]: string = 'MySqlIndexBuilderOn'; + static readonly [entityKind]: string = 'SingleStoreIndexBuilderOn'; constructor(private name: string, private unique: boolean) {} @@ -42,14 +42,14 @@ export class IndexBuilderOn { } export interface AnyIndexBuilder { - build(table: MySqlTable): Index; + build(table: SingleStoreTable): Index; } // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface IndexBuilder extends AnyIndexBuilder {} export class IndexBuilder implements AnyIndexBuilder { - static readonly [entityKind]: string = 'MySqlIndexBuilder'; + static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; /** @internal */ config: IndexConfig; @@ -78,23 +78,23 @@ export class IndexBuilder implements AnyIndexBuilder { } /** @internal */ - build(table: MySqlTable): Index { + build(table: SingleStoreTable): Index { return new Index(this.config, table); } } export class Index { - static readonly [entityKind]: string = 'MySqlIndex'; + static readonly [entityKind]: string = 'SingleStoreIndex'; - readonly config: IndexConfig & { table: MySqlTable }; + readonly config: IndexConfig & { table: SingleStoreTable }; - constructor(config: IndexConfig, table: MySqlTable) { + constructor(config: IndexConfig, table: SingleStoreTable) { this.config = { ...config, table }; } } export type GetColumnsTableName = TColumns extends - AnyMySqlColumn<{ tableName: infer TTableName extends string }> | AnyMySqlColumn< + AnySingleStoreColumn<{ tableName: infer TTableName extends string }> | AnySingleStoreColumn< { tableName: infer TTableName extends string } >[] ? TTableName : never; diff --git a/drizzle-orm/src/singlestore-core/primary-keys.ts b/drizzle-orm/src/singlestore-core/primary-keys.ts index 014cbd8c0b..47dc0a19cc 100644 --- a/drizzle-orm/src/singlestore-core/primary-keys.ts +++ b/drizzle-orm/src/singlestore-core/primary-keys.ts @@ -1,11 +1,11 @@ import { entityKind } from '~/entity.ts'; -import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; -import { MySqlTable } from './table.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; export function primaryKey< TTableName extends string, - TColumn extends AnyMySqlColumn<{ tableName: TTableName }>, - TColumns extends AnyMySqlColumn<{ tableName: TTableName }>[], + TColumn extends AnySingleStoreColumn<{ tableName: TTableName }>, + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], >(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; /** * @deprecated: Please use primaryKey({ columns: [] }) instead of this function @@ -13,7 +13,7 @@ export function primaryKey< */ export function primaryKey< TTableName extends string, - TColumns extends AnyMySqlColumn<{ tableName: TTableName }>[], + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], >(...columns: TColumns): PrimaryKeyBuilder; export function primaryKey(...config: any) { if (config[0].columns) { @@ -23,16 +23,16 @@ export function primaryKey(...config: any) { } export class PrimaryKeyBuilder { - static readonly [entityKind]: string = 'MySqlPrimaryKeyBuilder'; + static readonly [entityKind]: string = 'SingleStorePrimaryKeyBuilder'; /** @internal */ - columns: MySqlColumn[]; + columns: SingleStoreColumn[]; /** @internal */ name?: string; constructor( - columns: MySqlColumn[], + columns: SingleStoreColumn[], name?: string, ) { this.columns = columns; @@ -40,24 +40,24 @@ export class PrimaryKeyBuilder { } /** @internal */ - build(table: MySqlTable): PrimaryKey { + build(table: SingleStoreTable): PrimaryKey { return new PrimaryKey(table, this.columns, this.name); } } export class PrimaryKey { - static readonly [entityKind]: string = 'MySqlPrimaryKey'; + static readonly [entityKind]: string = 'SingleStorePrimaryKey'; - readonly columns: MySqlColumn[]; + readonly columns: SingleStoreColumn[]; readonly name?: string; - constructor(readonly table: MySqlTable, columns: MySqlColumn[], name?: string) { + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { this.columns = columns; this.name = name; } getName(): string { return this.name - ?? `${this.table[MySqlTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + ?? `${this.table[SingleStoreTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; } } diff --git a/drizzle-orm/src/singlestore-core/query-builders/delete.ts b/drizzle-orm/src/singlestore-core/query-builders/delete.ts index e9a48da8ee..e0a4637841 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/delete.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/delete.ts @@ -1,27 +1,27 @@ import { entityKind } from '~/entity.ts'; -import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { - AnyMySqlQueryResultHKT, - MySqlPreparedQueryConfig, - MySqlQueryResultHKT, - MySqlQueryResultKind, - MySqlSession, + AnySingleStoreQueryResultHKT, PreparedQueryHKTBase, PreparedQueryKind, -} from '~/mysql-core/session.ts'; -import type { MySqlTable } from '~/mysql-core/table.ts'; -import { QueryPromise } from '~/query-promise.ts'; + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; -export type MySqlDeleteWithout< - T extends AnyMySqlDeleteBase, +export type SingleStoreDeleteWithout< + T extends AnySingleStoreDeleteBase, TDynamic extends boolean, K extends keyof T & string, > = TDynamic extends true ? T : Omit< - MySqlDeleteBase< + SingleStoreDeleteBase< T['_']['table'], T['_']['queryResult'], T['_']['preparedQueryHKT'], @@ -31,43 +31,43 @@ export type MySqlDeleteWithout< T['_']['excludedMethods'] | K >; -export type MySqlDelete< - TTable extends MySqlTable = MySqlTable, - TQueryResult extends MySqlQueryResultHKT = AnyMySqlQueryResultHKT, +export type SingleStoreDelete< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = MySqlDeleteBase; +> = SingleStoreDeleteBase; -export interface MySqlDeleteConfig { +export interface SingleStoreDeleteConfig { where?: SQL | undefined; - table: MySqlTable; + table: SingleStoreTable; returning?: SelectedFieldsOrdered; withList?: Subquery[]; } -export type MySqlDeletePrepare = PreparedQueryKind< +export type SingleStoreDeletePrepare = PreparedQueryKind< T['_']['preparedQueryHKT'], - MySqlPreparedQueryConfig & { - execute: MySqlQueryResultKind; + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; iterator: never; }, true >; -type MySqlDeleteDynamic = MySqlDelete< +type SingleStoreDeleteDynamic = SingleStoreDelete< T['_']['table'], T['_']['queryResult'], T['_']['preparedQueryHKT'] >; -type AnyMySqlDeleteBase = MySqlDeleteBase; +type AnySingleStoreDeleteBase = SingleStoreDeleteBase; -export interface MySqlDeleteBase< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export interface SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, TDynamic extends boolean = false, TExcludedMethods extends string = never, -> extends QueryPromise> { +> extends QueryPromise> { readonly _: { readonly table: TTable; readonly queryResult: TQueryResult; @@ -77,23 +77,23 @@ export interface MySqlDeleteBase< }; } -export class MySqlDeleteBase< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export class SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, TDynamic extends boolean = false, // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static readonly [entityKind]: string = 'MySqlDelete'; +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreDelete'; - private config: MySqlDeleteConfig; + private config: SingleStoreDeleteConfig; constructor( private table: TTable, - private session: MySqlSession, - private dialect: MySqlDialect, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, withList?: Subquery[], ) { super(); @@ -129,7 +129,7 @@ export class MySqlDeleteBase< * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); * ``` */ - where(where: SQL | undefined): MySqlDeleteWithout { + where(where: SQL | undefined): SingleStoreDeleteWithout { this.config.where = where; return this as any; } @@ -144,11 +144,11 @@ export class MySqlDeleteBase< return rest; } - prepare(): MySqlDeletePrepare { + prepare(): SingleStoreDeletePrepare { return this.session.prepareQuery( this.dialect.sqlToQuery(this.getSQL()), this.config.returning, - ) as MySqlDeletePrepare; + ) as SingleStoreDeletePrepare; } override execute: ReturnType['execute'] = (placeholderValues) => { @@ -164,7 +164,7 @@ export class MySqlDeleteBase< iterator = this.createIterator(); - $dynamic(): MySqlDeleteDynamic { + $dynamic(): SingleStoreDeleteDynamic { return this as any; } } diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts index 97e61de74c..129bf22146 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/insert.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -1,27 +1,27 @@ import { entityKind, is } from '~/entity.ts'; -import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { - AnyMySqlQueryResultHKT, - MySqlPreparedQueryConfig, - MySqlQueryResultHKT, - MySqlQueryResultKind, - MySqlSession, + AnySingleStoreQueryResultHKT, PreparedQueryHKTBase, PreparedQueryKind, -} from '~/mysql-core/session.ts'; -import type { MySqlTable } from '~/mysql-core/table.ts'; -import { QueryPromise } from '~/query-promise.ts'; -import type { RunnableQuery } from '~/runnable-query.ts'; + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { InferModelFromColumns } from '~/table.ts'; import { Table } from '~/table.ts'; import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; -import type { AnyMySqlColumn, MySqlColumn } from '../columns/common.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from '../columns/common.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; -import type { MySqlUpdateSetSource } from './update.ts'; +import type { SingleStoreUpdateSetSource } from './update.ts'; -export interface MySqlInsertConfig { +export interface SingleStoreInsertConfig { table: TTable; values: Record[]; ignore: boolean; @@ -29,27 +29,27 @@ export interface MySqlInsertConfig { returning?: SelectedFieldsOrdered; } -export type AnyMySqlInsertConfig = MySqlInsertConfig; +export type AnySingleStoreInsertConfig = SingleStoreInsertConfig; -export type MySqlInsertValue = +export type SingleStoreInsertValue = & { [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; } & {}; -export class MySqlInsertBuilder< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export class SingleStoreInsertBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, > { - static readonly [entityKind]: string = 'MySqlInsertBuilder'; + static readonly [entityKind]: string = 'SingleStoreInsertBuilder'; private shouldIgnore = false; constructor( private table: TTable, - private session: MySqlSession, - private dialect: MySqlDialect, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, ) {} ignore(): this { @@ -57,11 +57,11 @@ export class MySqlInsertBuilder< return this; } - values(value: MySqlInsertValue): MySqlInsertBase; - values(values: MySqlInsertValue[]): MySqlInsertBase; + values(value: SingleStoreInsertValue): SingleStoreInsertBase; + values(values: SingleStoreInsertValue[]): SingleStoreInsertBase; values( - values: MySqlInsertValue | MySqlInsertValue[], - ): MySqlInsertBase { + values: SingleStoreInsertValue | SingleStoreInsertValue[], + ): SingleStoreInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -76,58 +76,61 @@ export class MySqlInsertBuilder< return result; }); - return new MySqlInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); + return new SingleStoreInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); } } -export type MySqlInsertWithout = - TDynamic extends true ? T - : Omit< - MySqlInsertBase< - T['_']['table'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'], - T['_']['returning'], - TDynamic, - T['_']['excludedMethods'] | '$returning' - >, - T['_']['excludedMethods'] | K - >; - -export type MySqlInsertDynamic = MySqlInsert< +export type SingleStoreInsertWithout< + T extends AnySingleStoreInsert, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | '$returning' + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreInsertDynamic = SingleStoreInsert< T['_']['table'], T['_']['queryResult'], T['_']['preparedQueryHKT'], T['_']['returning'] >; -export type MySqlInsertPrepare< - T extends AnyMySqlInsert, +export type SingleStoreInsertPrepare< + T extends AnySingleStoreInsert, TReturning extends Record | undefined = undefined, > = PreparedQueryKind< T['_']['preparedQueryHKT'], - MySqlPreparedQueryConfig & { - execute: TReturning extends undefined ? MySqlQueryResultKind : TReturning[]; + SingleStorePreparedQueryConfig & { + execute: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; iterator: never; }, true >; -export type MySqlInsertOnDuplicateKeyUpdateConfig = { - set: MySqlUpdateSetSource; +export type SingleStoreInsertOnDuplicateKeyUpdateConfig = { + set: SingleStoreUpdateSetSource; }; -export type MySqlInsert< - TTable extends MySqlTable = MySqlTable, - TQueryResult extends MySqlQueryResultHKT = AnyMySqlQueryResultHKT, +export type SingleStoreInsert< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, TReturning extends Record | undefined = Record | undefined, -> = MySqlInsertBase; +> = SingleStoreInsertBase; -export type MySqlInsertReturning< - T extends AnyMySqlInsert, +export type SingleStoreInsertReturning< + T extends AnySingleStoreInsert, TDynamic extends boolean, -> = MySqlInsertBase< +> = SingleStoreInsertBase< T['_']['table'], T['_']['queryResult'], T['_']['preparedQueryHKT'], @@ -136,33 +139,36 @@ export type MySqlInsertReturning< T['_']['excludedMethods'] | '$returning' >; -export type AnyMySqlInsert = MySqlInsertBase; +export type AnySingleStoreInsert = SingleStoreInsertBase; -export interface MySqlInsertBase< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export interface SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, TReturning extends Record | undefined = undefined, TDynamic extends boolean = false, TExcludedMethods extends string = never, > extends - QueryPromise : TReturning[]>, - RunnableQuery : TReturning[], 'mysql'>, + QueryPromise : TReturning[]>, + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, SQLWrapper { readonly _: { - readonly dialect: 'mysql'; + readonly dialect: 'singlestore'; readonly table: TTable; readonly queryResult: TQueryResult; readonly preparedQueryHKT: TPreparedQueryHKT; readonly dynamic: TDynamic; readonly excludedMethods: TExcludedMethods; readonly returning: TReturning; - readonly result: TReturning extends undefined ? MySqlQueryResultKind : TReturning[]; + readonly result: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; }; } -export type PrimaryKeyKeys> = { +export type PrimaryKeyKeys> = { [K in keyof T]: T[K]['_']['isPrimaryKey'] extends true ? T[K]['_']['isAutoincrement'] extends true ? K : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never : never @@ -170,13 +176,13 @@ export type PrimaryKeyKeys> = { : never; }[keyof T]; -export type GetPrimarySerialOrDefaultKeys> = { +export type GetPrimarySerialOrDefaultKeys> = { [K in PrimaryKeyKeys]: T[K]; }; -export class MySqlInsertBase< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export class SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -185,23 +191,26 @@ export class MySqlInsertBase< TDynamic extends boolean = false, // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, -> extends QueryPromise : TReturning[]> +> extends QueryPromise : TReturning[]> implements - RunnableQuery : TReturning[], 'mysql'>, + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, SQLWrapper { - static readonly [entityKind]: string = 'MySqlInsert'; + static readonly [entityKind]: string = 'SingleStoreInsert'; declare protected $table: TTable; - private config: MySqlInsertConfig; + private config: SingleStoreInsertConfig; constructor( table: TTable, - values: MySqlInsertConfig['values'], + values: SingleStoreInsertConfig['values'], ignore: boolean, - private session: MySqlSession, - private dialect: MySqlDialect, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, ) { super(); this.config = { table, values, ignore }; @@ -210,7 +219,7 @@ export class MySqlInsertBase< /** * Adds an `on duplicate key update` clause to the query. * - * Calling this method will update update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. + * Calling this method will update update the row if any unique index conflicts. SingleStore will automatically determine the conflict target based on the primary key and unique indexes. * * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} * @@ -223,7 +232,7 @@ export class MySqlInsertBase< * .onDuplicateKeyUpdate({ set: { brand: 'Porsche' }}); * ``` * - * While MySQL does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: + * While SingleStore does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: * * ```ts * import { sql } from 'drizzle-orm'; @@ -234,15 +243,15 @@ export class MySqlInsertBase< * ``` */ onDuplicateKeyUpdate( - config: MySqlInsertOnDuplicateKeyUpdateConfig, - ): MySqlInsertWithout { + config: SingleStoreInsertOnDuplicateKeyUpdateConfig, + ): SingleStoreInsertWithout { const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); this.config.onConflict = sql`update ${setSql}`; return this as any; } - $returningId(): MySqlInsertWithout< - MySqlInsertReturning, + $returningId(): SingleStoreInsertWithout< + SingleStoreInsertReturning, TDynamic, '$returningId' > { @@ -252,7 +261,7 @@ export class MySqlInsertBase< returning.push({ field: value, path: [key] }); } } - this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); + this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); return this as any; } @@ -266,7 +275,7 @@ export class MySqlInsertBase< return rest; } - prepare(): MySqlInsertPrepare { + prepare(): SingleStoreInsertPrepare { const { sql, generatedIds } = this.dialect.buildInsertQuery(this.config); return this.session.prepareQuery( this.dialect.sqlToQuery(sql), @@ -274,7 +283,7 @@ export class MySqlInsertBase< undefined, generatedIds, this.config.returning, - ) as MySqlInsertPrepare; + ) as SingleStoreInsertPrepare; } override execute: ReturnType['execute'] = (placeholderValues) => { @@ -290,7 +299,7 @@ export class MySqlInsertBase< iterator = this.createIterator(); - $dynamic(): MySqlInsertDynamic { + $dynamic(): SingleStoreInsertDynamic { return this as any; } } diff --git a/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts index f5d9cacc4c..b76a0457e8 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts @@ -1,17 +1,17 @@ import { entityKind } from '~/entity.ts'; -import { MySqlDialect } from '~/mysql-core/dialect.ts'; -import type { WithSubqueryWithSelection } from '~/mysql-core/subquery.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { WithSubqueryWithSelection } from '~/singlestore-core/subquery.ts'; import type { ColumnsSelection } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; -import { MySqlSelectBuilder } from './select.ts'; +import { SingleStoreSelectBuilder } from './select.ts'; import type { SelectedFields } from './select.types.ts'; export class QueryBuilder { - static readonly [entityKind]: string = 'MySqlQueryBuilder'; + static readonly [entityKind]: string = 'SingleStoreQueryBuilder'; - private dialect: MySqlDialect | undefined; + private dialect: SingleStoreDialect | undefined; $with(alias: TAlias) { const queryBuilder = this; @@ -35,14 +35,14 @@ export class QueryBuilder { with(...queries: WithSubquery[]) { const self = this; - function select(): MySqlSelectBuilder; + function select(): SingleStoreSelectBuilder; function select( fields: TSelection, - ): MySqlSelectBuilder; + ): SingleStoreSelectBuilder; function select( fields?: TSelection, - ): MySqlSelectBuilder { - return new MySqlSelectBuilder({ + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: undefined, dialect: self.getDialect(), @@ -50,14 +50,14 @@ export class QueryBuilder { }); } - function selectDistinct(): MySqlSelectBuilder; + function selectDistinct(): SingleStoreSelectBuilder; function selectDistinct( fields: TSelection, - ): MySqlSelectBuilder; + ): SingleStoreSelectBuilder; function selectDistinct( fields?: TSelection, - ): MySqlSelectBuilder { - return new MySqlSelectBuilder({ + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: undefined, dialect: self.getDialect(), @@ -69,22 +69,26 @@ export class QueryBuilder { return { select, selectDistinct }; } - select(): MySqlSelectBuilder; - select(fields: TSelection): MySqlSelectBuilder; + select(): SingleStoreSelectBuilder; + select(fields: TSelection): SingleStoreSelectBuilder; select( fields?: TSelection, - ): MySqlSelectBuilder { - return new MySqlSelectBuilder({ fields: fields ?? undefined, session: undefined, dialect: this.getDialect() }); + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + }); } - selectDistinct(): MySqlSelectBuilder; + selectDistinct(): SingleStoreSelectBuilder; selectDistinct( fields: TSelection, - ): MySqlSelectBuilder; + ): SingleStoreSelectBuilder; selectDistinct( fields?: TSelection, - ): MySqlSelectBuilder { - return new MySqlSelectBuilder({ + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: undefined, dialect: this.getDialect(), @@ -95,7 +99,7 @@ export class QueryBuilder { // Lazy load dialect to avoid circular dependency private getDialect() { if (!this.dialect) { - this.dialect = new MySqlDialect(); + this.dialect = new SingleStoreDialect(); } return this.dialect; diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts index 955f73428b..40d3f05adc 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/query.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -10,38 +10,38 @@ import { } from '~/relations.ts'; import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; import type { KnownKeysOnly } from '~/utils.ts'; -import type { MySqlDialect } from '../dialect.ts'; +import type { SingleStoreDialect } from '../dialect.ts'; import type { Mode, - MySqlPreparedQueryConfig, - MySqlSession, PreparedQueryHKTBase, PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreSession, } from '../session.ts'; -import type { MySqlTable } from '../table.ts'; +import type { SingleStoreTable } from '../table.ts'; export class RelationalQueryBuilder< TPreparedQueryHKT extends PreparedQueryHKTBase, TSchema extends TablesRelationalConfig, TFields extends TableRelationalConfig, > { - static readonly [entityKind]: string = 'MySqlRelationalQueryBuilder'; + static readonly [entityKind]: string = 'SingleStoreRelationalQueryBuilder'; constructor( private fullSchema: Record, private schema: TSchema, private tableNamesMap: Record, - private table: MySqlTable, + private table: SingleStoreTable, private tableConfig: TableRelationalConfig, - private dialect: MySqlDialect, - private session: MySqlSession, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, private mode: Mode, ) {} findMany>( config?: KnownKeysOnly>, - ): MySqlRelationalQuery[]> { - return new MySqlRelationalQuery( + ): SingleStoreRelationalQuery[]> { + return new SingleStoreRelationalQuery( this.fullSchema, this.schema, this.tableNamesMap, @@ -57,8 +57,8 @@ export class RelationalQueryBuilder< findFirst, 'limit'>>( config?: KnownKeysOnly, 'limit'>>, - ): MySqlRelationalQuery | undefined> { - return new MySqlRelationalQuery( + ): SingleStoreRelationalQuery | undefined> { + return new SingleStoreRelationalQuery( this.fullSchema, this.schema, this.tableNamesMap, @@ -73,22 +73,22 @@ export class RelationalQueryBuilder< } } -export class MySqlRelationalQuery< +export class SingleStoreRelationalQuery< TPreparedQueryHKT extends PreparedQueryHKTBase, TResult, > extends QueryPromise { - static readonly [entityKind]: string = 'MySqlRelationalQuery'; + static readonly [entityKind]: string = 'SingleStoreRelationalQuery'; - declare protected $brand: 'MySqlRelationalQuery'; + declare protected $brand: 'SingleStoreRelationalQuery'; constructor( private fullSchema: Record, private schema: TablesRelationalConfig, private tableNamesMap: Record, - private table: MySqlTable, + private table: SingleStoreTable, private tableConfig: TableRelationalConfig, - private dialect: MySqlDialect, - private session: MySqlSession, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, private config: DBQueryConfig<'many', true> | true, private queryMode: 'many' | 'first', private mode?: Mode, @@ -108,7 +108,7 @@ export class MySqlRelationalQuery< } return rows as TResult; }, - ) as PreparedQueryKind; + ) as PreparedQueryKind; } private _getQuery() { diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts index a5a0ca69a0..419aafca03 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -1,9 +1,4 @@ import { entityKind, is } from '~/entity.ts'; -import type { MySqlColumn } from '~/mysql-core/columns/index.ts'; -import type { MySqlDialect } from '~/mysql-core/dialect.ts'; -import type { MySqlPreparedQueryConfig, MySqlSession, PreparedQueryHKTBase } from '~/mysql-core/session.ts'; -import type { SubqueryWithSelection } from '~/mysql-core/subquery.ts'; -import type { MySqlTable } from '~/mysql-core/table.ts'; import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { BuildSubquerySelection, @@ -17,6 +12,15 @@ import type { } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + PreparedQueryHKTBase, + SingleStorePreparedQueryConfig, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SubqueryWithSelection } from '~/singlestore-core/subquery.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { ColumnsSelection, Query } from '~/sql/sql.ts'; import { SQL, View } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; @@ -24,45 +28,45 @@ import { Table } from '~/table.ts'; import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; import { orderSelectedFields } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; -import { MySqlViewBase } from '../view-base.ts'; +import { SingleStoreViewBase } from '../view-base.ts'; import type { - AnyMySqlSelect, - CreateMySqlSelectFromBuilderMode, - GetMySqlSetOperators, + AnySingleStoreSelect, + CreateSingleStoreSelectFromBuilderMode, + GetSingleStoreSetOperators, LockConfig, LockStrength, - MySqlCreateSetOperatorFn, - MySqlJoinFn, - MySqlSelectConfig, - MySqlSelectDynamic, - MySqlSelectHKT, - MySqlSelectHKTBase, - MySqlSelectPrepare, - MySqlSelectWithout, - MySqlSetOperatorExcludedMethods, - MySqlSetOperatorWithResult, SelectedFields, SetOperatorRightSelect, + SingleStoreCreateSetOperatorFn, + SingleStoreJoinFn, + SingleStoreSelectConfig, + SingleStoreSelectDynamic, + SingleStoreSelectHKT, + SingleStoreSelectHKTBase, + SingleStoreSelectPrepare, + SingleStoreSelectWithout, + SingleStoreSetOperatorExcludedMethods, + SingleStoreSetOperatorWithResult, } from './select.types.ts'; -export class MySqlSelectBuilder< +export class SingleStoreSelectBuilder< TSelection extends SelectedFields | undefined, TPreparedQueryHKT extends PreparedQueryHKTBase, TBuilderMode extends 'db' | 'qb' = 'db', > { - static readonly [entityKind]: string = 'MySqlSelectBuilder'; + static readonly [entityKind]: string = 'SingleStoreSelectBuilder'; private fields: TSelection; - private session: MySqlSession | undefined; - private dialect: MySqlDialect; + private session: SingleStoreSession | undefined; + private dialect: SingleStoreDialect; private withList: Subquery[] = []; private distinct: boolean | undefined; constructor( config: { fields: TSelection; - session: MySqlSession | undefined; - dialect: MySqlDialect; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; withList?: Subquery[]; distinct?: boolean; }, @@ -76,9 +80,9 @@ export class MySqlSelectBuilder< this.distinct = config.distinct; } - from( + from( source: TFrom, - ): CreateMySqlSelectFromBuilderMode< + ): CreateSingleStoreSelectFromBuilderMode< TBuilderMode, GetSelectTableName, TSelection extends undefined ? GetSelectTableSelection : TSelection, @@ -97,15 +101,15 @@ export class MySqlSelectBuilder< key, ) => [key, source[key as unknown as keyof typeof source] as unknown as SelectedFields[string]]), ); - } else if (is(source, MySqlViewBase)) { + } else if (is(source, SingleStoreViewBase)) { fields = source[ViewBaseConfig].selectedFields as SelectedFields; } else if (is(source, SQL)) { fields = {}; } else { - fields = getTableColumns(source); + fields = getTableColumns(source); } - return new MySqlSelectBase( + return new SingleStoreSelectBase( { table: source, fields, @@ -119,8 +123,8 @@ export class MySqlSelectBuilder< } } -export abstract class MySqlSelectQueryBuilderBase< - THKT extends MySqlSelectHKTBase, +export abstract class SingleStoreSelectQueryBuilderBase< + THKT extends SingleStoreSelectHKTBase, TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, @@ -132,7 +136,7 @@ export abstract class MySqlSelectQueryBuilderBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends TypedQueryBuilder { - static readonly [entityKind]: string = 'MySqlSelectQueryBuilder'; + static readonly [entityKind]: string = 'SingleStoreSelectQueryBuilder'; override readonly _: { readonly hkt: THKT; @@ -147,21 +151,21 @@ export abstract class MySqlSelectQueryBuilderBase< readonly selectedFields: TSelectedFields; }; - protected config: MySqlSelectConfig; + protected config: SingleStoreSelectConfig; protected joinsNotNullableMap: Record; private tableName: string | undefined; private isPartialSelect: boolean; /** @internal */ - readonly session: MySqlSession | undefined; - protected dialect: MySqlDialect; + readonly session: SingleStoreSession | undefined; + protected dialect: SingleStoreDialect; constructor( { table, fields, isPartialSelect, session, dialect, withList, distinct }: { - table: MySqlSelectConfig['table']; - fields: MySqlSelectConfig['fields']; + table: SingleStoreSelectConfig['table']; + fields: SingleStoreSelectConfig['fields']; isPartialSelect: boolean; - session: MySqlSession | undefined; - dialect: MySqlDialect; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; withList: Subquery[]; distinct: boolean | undefined; }, @@ -186,9 +190,9 @@ export abstract class MySqlSelectQueryBuilderBase< private createJoin( joinType: TJoinType, - ): MySqlJoinFn { + ): SingleStoreJoinFn { return ( - table: MySqlTable | Subquery | MySqlViewBase | SQL, + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, ) => { const baseTableName = this.tableName; @@ -380,19 +384,19 @@ export abstract class MySqlSelectQueryBuilderBase< private createSetOperator( type: SetOperator, isAll: boolean, - ): >( + ): >( rightSelection: - | ((setOperators: GetMySqlSetOperators) => SetOperatorRightSelect) + | ((setOperators: GetSingleStoreSetOperators) => SetOperatorRightSelect) | SetOperatorRightSelect, - ) => MySqlSelectWithout< + ) => SingleStoreSelectWithout< this, TDynamic, - MySqlSetOperatorExcludedMethods, + SingleStoreSetOperatorExcludedMethods, true > { return (rightSelection) => { const rightSelect = (typeof rightSelection === 'function' - ? rightSelection(getMySqlSetOperators()) + ? rightSelection(getSingleStoreSetOperators()) : rightSelection) as TypedQueryBuilder< any, TResult @@ -426,7 +430,7 @@ export abstract class MySqlSelectQueryBuilderBase< * db.select({ name: customers.name }).from(customers) * ); * // or - * import { union } from 'drizzle-orm/mysql-core' + * import { union } from 'drizzle-orm/singlestore-core' * * await union( * db.select({ name: users.name }).from(users), @@ -453,7 +457,7 @@ export abstract class MySqlSelectQueryBuilderBase< * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) * ); * // or - * import { unionAll } from 'drizzle-orm/mysql-core' + * import { unionAll } from 'drizzle-orm/singlestore-core' * * await unionAll( * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), @@ -480,7 +484,7 @@ export abstract class MySqlSelectQueryBuilderBase< * db.select({ courseName: depB.courseName }).from(depB) * ); * // or - * import { intersect } from 'drizzle-orm/mysql-core' + * import { intersect } from 'drizzle-orm/singlestore-core' * * await intersect( * db.select({ courseName: depA.courseName }).from(depA), @@ -514,7 +518,7 @@ export abstract class MySqlSelectQueryBuilderBase< * .from(vipCustomerOrders) * ); * // or - * import { intersectAll } from 'drizzle-orm/mysql-core' + * import { intersectAll } from 'drizzle-orm/singlestore-core' * * await intersectAll( * db.select({ @@ -549,7 +553,7 @@ export abstract class MySqlSelectQueryBuilderBase< * db.select({ courseName: depB.courseName }).from(depB) * ); * // or - * import { except } from 'drizzle-orm/mysql-core' + * import { except } from 'drizzle-orm/singlestore-core' * * await except( * db.select({ courseName: depA.courseName }).from(depA), @@ -583,7 +587,7 @@ export abstract class MySqlSelectQueryBuilderBase< * .from(vipCustomerOrders) * ); * // or - * import { exceptAll } from 'drizzle-orm/mysql-core' + * import { exceptAll } from 'drizzle-orm/singlestore-core' * * await exceptAll( * db.select({ @@ -602,10 +606,10 @@ export abstract class MySqlSelectQueryBuilderBase< exceptAll = this.createSetOperator('except', true); /** @internal */ - addSetOperators(setOperators: MySqlSelectConfig['setOperators']): MySqlSelectWithout< + addSetOperators(setOperators: SingleStoreSelectConfig['setOperators']): SingleStoreSelectWithout< this, TDynamic, - MySqlSetOperatorExcludedMethods, + SingleStoreSetOperatorExcludedMethods, true > { this.config.setOperators.push(...setOperators); @@ -643,7 +647,7 @@ export abstract class MySqlSelectQueryBuilderBase< */ where( where: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, - ): MySqlSelectWithout { + ): SingleStoreSelectWithout { if (typeof where === 'function') { where = where( new Proxy( @@ -680,7 +684,7 @@ export abstract class MySqlSelectQueryBuilderBase< */ having( having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, - ): MySqlSelectWithout { + ): SingleStoreSelectWithout { if (typeof having === 'function') { having = having( new Proxy( @@ -713,14 +717,14 @@ export abstract class MySqlSelectQueryBuilderBase< * ``` */ groupBy( - builder: (aliases: this['_']['selection']) => ValueOrArray, - ): MySqlSelectWithout; - groupBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlSelectWithout; + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + groupBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; groupBy( ...columns: - | [(aliases: this['_']['selection']) => ValueOrArray] - | (MySqlColumn | SQL | SQL.Aliased)[] - ): MySqlSelectWithout { + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { if (typeof columns[0] === 'function') { const groupBy = columns[0]( new Proxy( @@ -730,7 +734,7 @@ export abstract class MySqlSelectQueryBuilderBase< ); this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy]; } else { - this.config.groupBy = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + this.config.groupBy = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; } return this as any; } @@ -760,14 +764,14 @@ export abstract class MySqlSelectQueryBuilderBase< * ``` */ orderBy( - builder: (aliases: this['_']['selection']) => ValueOrArray, - ): MySqlSelectWithout; - orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlSelectWithout; + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; orderBy( ...columns: - | [(aliases: this['_']['selection']) => ValueOrArray] - | (MySqlColumn | SQL | SQL.Aliased)[] - ): MySqlSelectWithout { + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { if (typeof columns[0] === 'function') { const orderBy = columns[0]( new Proxy( @@ -784,7 +788,7 @@ export abstract class MySqlSelectQueryBuilderBase< this.config.orderBy = orderByArray; } } else { - const orderByArray = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.orderBy = orderByArray; @@ -811,7 +815,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).limit(10); * ``` */ - limit(limit: number): MySqlSelectWithout { + limit(limit: number): SingleStoreSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.limit = limit; } else { @@ -836,7 +840,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).offset(10).limit(10); * ``` */ - offset(offset: number): MySqlSelectWithout { + offset(offset: number): SingleStoreSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.offset = offset; } else { @@ -851,11 +855,12 @@ export abstract class MySqlSelectQueryBuilderBase< * Calling this method will specify a lock strength for this query that controls how strictly it acquires exclusive access to the rows being queried. * * See docs: {@link https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html} + * TODO(singlestore) * * @param strength the lock strength. * @param config the lock configuration. */ - for(strength: LockStrength, config: LockConfig = {}): MySqlSelectWithout { + for(strength: LockStrength, config: LockConfig = {}): SingleStoreSelectWithout { this.config.lockingClause = { strength, config }; return this as any; } @@ -887,12 +892,12 @@ export abstract class MySqlSelectQueryBuilderBase< ) as this['_']['selectedFields']; } - $dynamic(): MySqlSelectDynamic { + $dynamic(): SingleStoreSelectDynamic { return this as any; } } -export interface MySqlSelectBase< +export interface SingleStoreSelectBase< TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, @@ -904,8 +909,8 @@ export interface MySqlSelectBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends - MySqlSelectQueryBuilderBase< - MySqlSelectHKT, + SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, TTableName, TSelection, TSelectMode, @@ -919,7 +924,7 @@ export interface MySqlSelectBase< QueryPromise {} -export class MySqlSelectBase< +export class SingleStoreSelectBase< TTableName extends string | undefined, TSelection, TSelectMode extends SelectMode, @@ -930,8 +935,8 @@ export class MySqlSelectBase< TExcludedMethods extends string = never, TResult = SelectResult[], TSelectedFields = BuildSubquerySelection, -> extends MySqlSelectQueryBuilderBase< - MySqlSelectHKT, +> extends SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, TTableName, TSelection, TSelectMode, @@ -942,19 +947,19 @@ export class MySqlSelectBase< TResult, TSelectedFields > { - static readonly [entityKind]: string = 'MySqlSelect'; + static readonly [entityKind]: string = 'SingleStoreSelect'; - prepare(): MySqlSelectPrepare { + prepare(): SingleStoreSelectPrepare { if (!this.session) { throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); } - const fieldsList = orderSelectedFields(this.config.fields); + const fieldsList = orderSelectedFields(this.config.fields); const query = this.session.prepareQuery< - MySqlPreparedQueryConfig & { execute: SelectResult[] }, + SingleStorePreparedQueryConfig & { execute: SelectResult[] }, TPreparedQueryHKT >(this.dialect.sqlToQuery(this.getSQL()), fieldsList); query.joinsNotNullableMap = this.joinsNotNullableMap; - return query as MySqlSelectPrepare; + return query as SingleStoreSelectPrepare; } execute = ((placeholderValues) => { @@ -971,14 +976,14 @@ export class MySqlSelectBase< iterator = this.createIterator(); } -applyMixins(MySqlSelectBase, [QueryPromise]); +applyMixins(SingleStoreSelectBase, [QueryPromise]); -function createSetOperator(type: SetOperator, isAll: boolean): MySqlCreateSetOperatorFn { +function createSetOperator(type: SetOperator, isAll: boolean): SingleStoreCreateSetOperatorFn { return (leftSelect, rightSelect, ...restSelects) => { const setOperators = [rightSelect, ...restSelects].map((select) => ({ type, isAll, - rightSelect: select as AnyMySqlSelect, + rightSelect: select as AnySingleStoreSelect, })); for (const setOperator of setOperators) { @@ -989,11 +994,11 @@ function createSetOperator(type: SetOperator, isAll: boolean): MySqlCreateSetOpe } } - return (leftSelect as AnyMySqlSelect).addSetOperators(setOperators) as any; + return (leftSelect as AnySingleStoreSelect).addSetOperators(setOperators) as any; }; } -const getMySqlSetOperators = () => ({ +const getSingleStoreSetOperators = () => ({ union, unionAll, intersect, @@ -1013,7 +1018,7 @@ const getMySqlSetOperators = () => ({ * * ```ts * // Select all unique names from customers and users tables - * import { union } from 'drizzle-orm/mysql-core' + * import { union } from 'drizzle-orm/singlestore-core' * * await union( * db.select({ name: users.name }).from(users), @@ -1040,7 +1045,7 @@ export const union = createSetOperator('union', false); * * ```ts * // Select all transaction ids from both online and in-store sales - * import { unionAll } from 'drizzle-orm/mysql-core' + * import { unionAll } from 'drizzle-orm/singlestore-core' * * await unionAll( * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), @@ -1067,7 +1072,7 @@ export const unionAll = createSetOperator('union', true); * * ```ts * // Select course names that are offered in both departments A and B - * import { intersect } from 'drizzle-orm/mysql-core' + * import { intersect } from 'drizzle-orm/singlestore-core' * * await intersect( * db.select({ courseName: depA.courseName }).from(depA), @@ -1094,7 +1099,7 @@ export const intersect = createSetOperator('intersect', false); * * ```ts * // Select all products and quantities that are ordered by both regular and VIP customers - * import { intersectAll } from 'drizzle-orm/mysql-core' + * import { intersectAll } from 'drizzle-orm/singlestore-core' * * await intersectAll( * db.select({ @@ -1136,7 +1141,7 @@ export const intersectAll = createSetOperator('intersect', true); * * ```ts * // Select all courses offered in department A but not in department B - * import { except } from 'drizzle-orm/mysql-core' + * import { except } from 'drizzle-orm/singlestore-core' * * await except( * db.select({ courseName: depA.courseName }).from(depA), @@ -1163,7 +1168,7 @@ export const except = createSetOperator('except', false); * * ```ts * // Select all products that are ordered by regular customers but not by VIP customers - * import { exceptAll } from 'drizzle-orm/mysql-core' + * import { exceptAll } from 'drizzle-orm/singlestore-core' * * await exceptAll( * db.select({ diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts index 5f490a2d91..26f177634b 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -1,5 +1,3 @@ -import type { MySqlColumn } from '~/mysql-core/columns/index.ts'; -import type { MySqlTable, MySqlTableWithColumns } from '~/mysql-core/table.ts'; import type { SelectedFields as SelectedFieldsBase, SelectedFieldsFlat as SelectedFieldsFlatBase, @@ -18,49 +16,51 @@ import type { SelectResult, SetOperator, } from '~/query-builders/select.types.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/table.ts'; import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { Table, UpdateTableConfig } from '~/table.ts'; import type { Assume, ValidateShape } from '~/utils.ts'; -import type { MySqlPreparedQueryConfig, PreparedQueryHKTBase, PreparedQueryKind } from '../session.ts'; -import type { MySqlViewBase } from '../view-base.ts'; -import type { MySqlViewWithSelection } from '../view.ts'; -import type { MySqlSelectBase, MySqlSelectQueryBuilderBase } from './select.ts'; +import type { PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig } from '../session.ts'; +import type { SingleStoreViewBase } from '../view-base.ts'; +import type { SingleStoreViewWithSelection } from '../view.ts'; +import type { SingleStoreSelectBase, SingleStoreSelectQueryBuilderBase } from './select.ts'; -export interface MySqlSelectJoinConfig { +export interface SingleStoreSelectJoinConfig { on: SQL | undefined; - table: MySqlTable | Subquery | MySqlViewBase | SQL; + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; alias: string | undefined; joinType: JoinType; lateral?: boolean; } -export type BuildAliasTable = TTable extends Table - ? MySqlTableWithColumns< +export type BuildAliasTable = TTable extends Table + ? SingleStoreTableWithColumns< UpdateTableConfig; + columns: MapColumnsToTableAlias; }> > - : TTable extends View ? MySqlViewWithSelection< + : TTable extends View ? SingleStoreViewWithSelection< TAlias, TTable['_']['existing'], - MapColumnsToTableAlias + MapColumnsToTableAlias > : never; -export interface MySqlSelectConfig { +export interface SingleStoreSelectConfig { withList?: Subquery[]; fields: Record; fieldsFlat?: SelectedFieldsOrdered; where?: SQL; having?: SQL; - table: MySqlTable | Subquery | MySqlViewBase | SQL; + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; limit?: number | Placeholder; offset?: number | Placeholder; - joins?: MySqlSelectJoinConfig[]; - orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; - groupBy?: (MySqlColumn | SQL | SQL.Aliased)[]; + joins?: SingleStoreSelectJoinConfig[]; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + groupBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; lockingClause?: { strength: LockStrength; config: LockConfig; @@ -70,27 +70,27 @@ export interface MySqlSelectConfig { rightSelect: TypedQueryBuilder; type: SetOperator; isAll: boolean; - orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; limit?: number | Placeholder; offset?: number | Placeholder; }[]; } -export type MySqlJoin< - T extends AnyMySqlSelectQueryBuilder, +export type SingleStoreJoin< + T extends AnySingleStoreSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, - TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL, + TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, TJoinedName extends GetSelectTableName = GetSelectTableName, -> = T extends any ? MySqlSelectWithout< - MySqlSelectKind< +> = T extends any ? SingleStoreSelectWithout< + SingleStoreSelectKind< T['_']['hkt'], T['_']['tableName'], AppendToResult< T['_']['tableName'], T['_']['selection'], TJoinedName, - TJoinedTable extends MySqlTable ? TJoinedTable['_']['columns'] + TJoinedTable extends SingleStoreTable ? TJoinedTable['_']['columns'] : TJoinedTable extends Subquery ? Assume : never, T['_']['selectMode'] @@ -106,23 +106,23 @@ export type MySqlJoin< > : never; -export type MySqlJoinFn< - T extends AnyMySqlSelectQueryBuilder, +export type SingleStoreJoinFn< + T extends AnySingleStoreSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, > = < - TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL, + TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, TJoinedName extends GetSelectTableName = GetSelectTableName, >( table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, -) => MySqlJoin; +) => SingleStoreJoin; -export type SelectedFieldsFlat = SelectedFieldsFlatBase; +export type SelectedFieldsFlat = SelectedFieldsFlatBase; -export type SelectedFields = SelectedFieldsBase; +export type SelectedFields = SelectedFieldsBase; -export type SelectedFieldsOrdered = SelectedFieldsOrderedBase; +export type SelectedFieldsOrdered = SelectedFieldsOrderedBase; export type LockStrength = 'update' | 'share'; @@ -137,7 +137,7 @@ export type LockConfig = { skipLocked?: undefined; }; -export interface MySqlSelectHKTBase { +export interface SingleStoreSelectHKTBase { tableName: string | undefined; selection: unknown; selectMode: SelectMode; @@ -150,8 +150,8 @@ export interface MySqlSelectHKTBase { _type: unknown; } -export type MySqlSelectKind< - T extends MySqlSelectHKTBase, +export type SingleStoreSelectKind< + T extends SingleStoreSelectHKTBase, TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, @@ -173,9 +173,9 @@ export type MySqlSelectKind< selectedFields: TSelectedFields; })['_type']; -export interface MySqlSelectQueryBuilderHKT extends MySqlSelectHKTBase { - _type: MySqlSelectQueryBuilderBase< - MySqlSelectQueryBuilderHKT, +export interface SingleStoreSelectQueryBuilderHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, this['tableName'], Assume, this['selectMode'], @@ -188,8 +188,8 @@ export interface MySqlSelectQueryBuilderHKT extends MySqlSelectHKTBase { >; } -export interface MySqlSelectHKT extends MySqlSelectHKTBase { - _type: MySqlSelectBase< +export interface SingleStoreSelectHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectBase< this['tableName'], Assume, this['selectMode'], @@ -202,7 +202,7 @@ export interface MySqlSelectHKT extends MySqlSelectHKTBase { >; } -export type MySqlSetOperatorExcludedMethods = +export type SingleStoreSetOperatorExcludedMethods = | 'where' | 'having' | 'groupBy' @@ -213,13 +213,13 @@ export type MySqlSetOperatorExcludedMethods = | 'fullJoin' | 'for'; -export type MySqlSelectWithout< - T extends AnyMySqlSelectQueryBuilder, +export type SingleStoreSelectWithout< + T extends AnySingleStoreSelectQueryBuilder, TDynamic extends boolean, K extends keyof T & string, TResetExcluded extends boolean = false, > = TDynamic extends true ? T : Omit< - MySqlSelectKind< + SingleStoreSelectKind< T['_']['hkt'], T['_']['tableName'], T['_']['selection'], @@ -234,16 +234,16 @@ export type MySqlSelectWithout< TResetExcluded extends true ? K : T['_']['excludedMethods'] | K >; -export type MySqlSelectPrepare = PreparedQueryKind< +export type SingleStoreSelectPrepare = PreparedQueryKind< T['_']['preparedQueryHKT'], - MySqlPreparedQueryConfig & { + SingleStorePreparedQueryConfig & { execute: T['_']['result']; iterator: T['_']['result'][number]; }, true >; -export type MySqlSelectDynamic = MySqlSelectKind< +export type SingleStoreSelectDynamic = SingleStoreSelectKind< T['_']['hkt'], T['_']['tableName'], T['_']['selection'], @@ -256,17 +256,23 @@ export type MySqlSelectDynamic = MySqlSele T['_']['selectedFields'] >; -export type CreateMySqlSelectFromBuilderMode< +export type CreateSingleStoreSelectFromBuilderMode< TBuilderMode extends 'db' | 'qb', TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, TPreparedQueryHKT extends PreparedQueryHKTBase, -> = TBuilderMode extends 'db' ? MySqlSelectBase - : MySqlSelectQueryBuilderBase; +> = TBuilderMode extends 'db' ? SingleStoreSelectBase + : SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT + >; -export type MySqlSelectQueryBuilder< - THKT extends MySqlSelectHKTBase = MySqlSelectQueryBuilderHKT, +export type SingleStoreSelectQueryBuilder< + THKT extends SingleStoreSelectHKTBase = SingleStoreSelectQueryBuilderHKT, TTableName extends string | undefined = string | undefined, TSelection extends ColumnsSelection = ColumnsSelection, TSelectMode extends SelectMode = SelectMode, @@ -274,7 +280,7 @@ export type MySqlSelectQueryBuilder< TNullabilityMap extends Record = Record, TResult extends any[] = unknown[], TSelectedFields extends ColumnsSelection = ColumnsSelection, -> = MySqlSelectQueryBuilderBase< +> = SingleStoreSelectQueryBuilderBase< THKT, TTableName, TSelection, @@ -287,11 +293,31 @@ export type MySqlSelectQueryBuilder< TSelectedFields >; -export type AnyMySqlSelectQueryBuilder = MySqlSelectQueryBuilderBase; +export type AnySingleStoreSelectQueryBuilder = SingleStoreSelectQueryBuilderBase< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; -export type AnyMySqlSetOperatorInterface = MySqlSetOperatorInterface; +export type AnySingleStoreSetOperatorInterface = SingleStoreSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; -export interface MySqlSetOperatorInterface< +export interface SingleStoreSetOperatorInterface< TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, @@ -304,7 +330,7 @@ export interface MySqlSetOperatorInterface< TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > { _: { - readonly hkt: MySqlSelectHKT; + readonly hkt: SingleStoreSelectHKT; readonly tableName: TTableName; readonly selection: TSelection; readonly selectMode: TSelectMode; @@ -317,7 +343,7 @@ export interface MySqlSetOperatorInterface< }; } -export type MySqlSetOperatorWithResult = MySqlSetOperatorInterface< +export type SingleStoreSetOperatorWithResult = SingleStoreSetOperatorInterface< any, any, any, @@ -329,35 +355,35 @@ export type MySqlSetOperatorWithResult = MySqlSetOperator any >; -export type MySqlSelect< +export type SingleStoreSelect< TTableName extends string | undefined = string | undefined, TSelection extends ColumnsSelection = Record, TSelectMode extends SelectMode = SelectMode, TNullabilityMap extends Record = Record, -> = MySqlSelectBase; +> = SingleStoreSelectBase; -export type AnyMySqlSelect = MySqlSelectBase; +export type AnySingleStoreSelect = SingleStoreSelectBase; -export type MySqlSetOperator< +export type SingleStoreSetOperator< TTableName extends string | undefined = string | undefined, TSelection extends ColumnsSelection = Record, TSelectMode extends SelectMode = SelectMode, TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, TNullabilityMap extends Record = Record, -> = MySqlSelectBase< +> = SingleStoreSelectBase< TTableName, TSelection, TSelectMode, TPreparedQueryHKT, TNullabilityMap, true, - MySqlSetOperatorExcludedMethods + SingleStoreSetOperatorExcludedMethods >; export type SetOperatorRightSelect< - TValue extends MySqlSetOperatorWithResult, + TValue extends SingleStoreSetOperatorWithResult, TResult extends any[], -> = TValue extends MySqlSetOperatorInterface +> = TValue extends SingleStoreSetOperatorInterface ? ValidateShape< TValueResult[number], TResult[number], @@ -366,11 +392,11 @@ export type SetOperatorRightSelect< : TValue; export type SetOperatorRestSelect< - TValue extends readonly MySqlSetOperatorWithResult[], + TValue extends readonly SingleStoreSetOperatorWithResult[], TResult extends any[], > = TValue extends [infer First, ...infer Rest] - ? First extends MySqlSetOperatorInterface - ? Rest extends AnyMySqlSetOperatorInterface[] ? [ + ? First extends SingleStoreSetOperatorInterface + ? Rest extends AnySingleStoreSetOperatorInterface[] ? [ ValidateShape>, ...SetOperatorRestSelect, ] @@ -378,12 +404,12 @@ export type SetOperatorRestSelect< : never : TValue; -export type MySqlCreateSetOperatorFn = < +export type SingleStoreCreateSetOperatorFn = < TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, - TValue extends MySqlSetOperatorWithResult, - TRest extends MySqlSetOperatorWithResult[], + TValue extends SingleStoreSetOperatorWithResult, + TRest extends SingleStoreSetOperatorWithResult[], TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, TNullabilityMap extends Record = TTableName extends string ? Record : {}, @@ -392,7 +418,7 @@ export type MySqlCreateSetOperatorFn = < TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, >( - leftSelect: MySqlSetOperatorInterface< + leftSelect: SingleStoreSetOperatorInterface< TTableName, TSelection, TSelectMode, @@ -405,8 +431,8 @@ export type MySqlCreateSetOperatorFn = < >, rightSelect: SetOperatorRightSelect, ...restSelects: SetOperatorRestSelect -) => MySqlSelectWithout< - MySqlSelectBase< +) => SingleStoreSelectWithout< + SingleStoreSelectBase< TTableName, TSelection, TSelectMode, @@ -418,15 +444,15 @@ export type MySqlCreateSetOperatorFn = < TSelectedFields >, false, - MySqlSetOperatorExcludedMethods, + SingleStoreSetOperatorExcludedMethods, true >; -export type GetMySqlSetOperators = { - union: MySqlCreateSetOperatorFn; - intersect: MySqlCreateSetOperatorFn; - except: MySqlCreateSetOperatorFn; - unionAll: MySqlCreateSetOperatorFn; - intersectAll: MySqlCreateSetOperatorFn; - exceptAll: MySqlCreateSetOperatorFn; +export type GetSingleStoreSetOperators = { + union: SingleStoreCreateSetOperatorFn; + intersect: SingleStoreCreateSetOperatorFn; + except: SingleStoreCreateSetOperatorFn; + unionAll: SingleStoreCreateSetOperatorFn; + intersectAll: SingleStoreCreateSetOperatorFn; + exceptAll: SingleStoreCreateSetOperatorFn; }; diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts index 7884599cfb..d26394dfe5 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/update.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -1,31 +1,31 @@ import type { GetColumnData } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { - AnyMySqlQueryResultHKT, - MySqlPreparedQueryConfig, - MySqlQueryResultHKT, - MySqlQueryResultKind, - MySqlSession, + AnySingleStoreQueryResultHKT, PreparedQueryHKTBase, PreparedQueryKind, -} from '~/mysql-core/session.ts'; -import type { MySqlTable } from '~/mysql-core/table.ts'; -import { QueryPromise } from '~/query-promise.ts'; + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import { mapUpdateSet, type UpdateSet } from '~/utils.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; -export interface MySqlUpdateConfig { +export interface SingleStoreUpdateConfig { where?: SQL | undefined; set: UpdateSet; - table: MySqlTable; + table: SingleStoreTable; returning?: SelectedFieldsOrdered; withList?: Subquery[]; } -export type MySqlUpdateSetSource = +export type SingleStoreUpdateSetSource = & { [Key in keyof TTable['$inferInsert']]?: | GetColumnData @@ -33,12 +33,12 @@ export type MySqlUpdateSetSource = } & {}; -export class MySqlUpdateBuilder< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export class SingleStoreUpdateBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, > { - static readonly [entityKind]: string = 'MySqlUpdateBuilder'; + static readonly [entityKind]: string = 'SingleStoreUpdateBuilder'; declare readonly _: { readonly table: TTable; @@ -46,22 +46,28 @@ export class MySqlUpdateBuilder< constructor( private table: TTable, - private session: MySqlSession, - private dialect: MySqlDialect, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, private withList?: Subquery[], ) {} - set(values: MySqlUpdateSetSource): MySqlUpdateBase { - return new MySqlUpdateBase(this.table, mapUpdateSet(this.table, values), this.session, this.dialect, this.withList); + set(values: SingleStoreUpdateSetSource): SingleStoreUpdateBase { + return new SingleStoreUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ); } } -export type MySqlUpdateWithout< - T extends AnyMySqlUpdateBase, +export type SingleStoreUpdateWithout< + T extends AnySingleStoreUpdateBase, TDynamic extends boolean, K extends keyof T & string, > = TDynamic extends true ? T : Omit< - MySqlUpdateBase< + SingleStoreUpdateBase< T['_']['table'], T['_']['queryResult'], T['_']['preparedQueryHKT'], @@ -71,36 +77,36 @@ export type MySqlUpdateWithout< T['_']['excludedMethods'] | K >; -export type MySqlUpdatePrepare = PreparedQueryKind< +export type SingleStoreUpdatePrepare = PreparedQueryKind< T['_']['preparedQueryHKT'], - MySqlPreparedQueryConfig & { - execute: MySqlQueryResultKind; + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; iterator: never; }, true >; -export type MySqlUpdateDynamic = MySqlUpdate< +export type SingleStoreUpdateDynamic = SingleStoreUpdate< T['_']['table'], T['_']['queryResult'], T['_']['preparedQueryHKT'] >; -export type MySqlUpdate< - TTable extends MySqlTable = MySqlTable, - TQueryResult extends MySqlQueryResultHKT = AnyMySqlQueryResultHKT, +export type SingleStoreUpdate< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = MySqlUpdateBase; +> = SingleStoreUpdateBase; -export type AnyMySqlUpdateBase = MySqlUpdateBase; +export type AnySingleStoreUpdateBase = SingleStoreUpdateBase; -export interface MySqlUpdateBase< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export interface SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, TDynamic extends boolean = false, TExcludedMethods extends string = never, -> extends QueryPromise>, SQLWrapper { +> extends QueryPromise>, SQLWrapper { readonly _: { readonly table: TTable; readonly queryResult: TQueryResult; @@ -110,25 +116,25 @@ export interface MySqlUpdateBase< }; } -export class MySqlUpdateBase< - TTable extends MySqlTable, - TQueryResult extends MySqlQueryResultHKT, +export class SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, // eslint-disable-next-line @typescript-eslint/no-unused-vars TDynamic extends boolean = false, // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static readonly [entityKind]: string = 'MySqlUpdate'; +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreUpdate'; - private config: MySqlUpdateConfig; + private config: SingleStoreUpdateConfig; constructor( table: TTable, set: UpdateSet, - private session: MySqlSession, - private dialect: MySqlDialect, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, withList?: Subquery[], ) { super(); @@ -168,7 +174,7 @@ export class MySqlUpdateBase< * .where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); * ``` */ - where(where: SQL | undefined): MySqlUpdateWithout { + where(where: SQL | undefined): SingleStoreUpdateWithout { this.config.where = where; return this as any; } @@ -183,11 +189,11 @@ export class MySqlUpdateBase< return rest; } - prepare(): MySqlUpdatePrepare { + prepare(): SingleStoreUpdatePrepare { return this.session.prepareQuery( this.dialect.sqlToQuery(this.getSQL()), this.config.returning, - ) as MySqlUpdatePrepare; + ) as SingleStoreUpdatePrepare; } override execute: ReturnType['execute'] = (placeholderValues) => { @@ -203,7 +209,7 @@ export class MySqlUpdateBase< iterator = this.createIterator(); - $dynamic(): MySqlUpdateDynamic { + $dynamic(): SingleStoreUpdateDynamic { return this as any; } } diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index b36531e44e..82da44a49e 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,40 +1,41 @@ import { entityKind, is } from '~/entity.ts'; -import { type MySqlTableFn, mysqlTableWithSchema } from './table.ts'; -import { type mysqlView, mysqlViewWithSchema } from './view.ts'; +import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; +import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; -export class MySqlSchema { - static readonly [entityKind]: string = 'MySqlSchema'; +export class SingleStoreSchema { + static readonly [entityKind]: string = 'SingleStoreSchema'; constructor( public readonly schemaName: TName, ) {} - table: MySqlTableFn = (name, columns, extraConfig) => { - return mysqlTableWithSchema(name, columns, extraConfig, this.schemaName); + table: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); }; view = ((name, columns) => { - return mysqlViewWithSchema(name, columns, this.schemaName); - }) as typeof mysqlView; + return singlestoreViewWithSchema(name, columns, this.schemaName); + }) as typeof singlestoreView; } -/** @deprecated - use `instanceof MySqlSchema` */ -export function isMySqlSchema(obj: unknown): obj is MySqlSchema { - return is(obj, MySqlSchema); +/** @deprecated - use `instanceof SingleStoreSchema` */ +export function isSingleStoreSchema(obj: unknown): obj is SingleStoreSchema { + return is(obj, SingleStoreSchema); } /** - * Create a MySQL schema. + * Create a SingleStore schema. * https://dev.mysql.com/doc/refman/8.0/en/create-database.html + * TODO(singlestore) * - * @param name mysql use schema name - * @returns MySQL schema + * @param name singlestore use schema name + * @returns SingleStore schema */ -export function mysqlDatabase(name: TName) { - return new MySqlSchema(name); +export function singlestoreDatabase(name: TName) { + return new SingleStoreSchema(name); } /** - * @see mysqlDatabase + * @see singlestoreDatabase */ -export const mysqlSchema = mysqlDatabase; +export const singlestoreSchema = singlestoreDatabase; diff --git a/drizzle-orm/src/singlestore-core/session.ts b/drizzle-orm/src/singlestore-core/session.ts index 08ad1ebb68..b95589a459 100644 --- a/drizzle-orm/src/singlestore-core/session.ts +++ b/drizzle-orm/src/singlestore-core/session.ts @@ -3,47 +3,47 @@ import { TransactionRollbackError } from '~/errors.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { type Query, type SQL, sql } from '~/sql/sql.ts'; import type { Assume, Equal } from '~/utils.ts'; -import { MySqlDatabase } from './db.ts'; -import type { MySqlDialect } from './dialect.ts'; +import { SingleStoreDatabase } from './db.ts'; +import type { SingleStoreDialect } from './dialect.ts'; import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; export type Mode = 'default' | 'planetscale'; -export interface MySqlQueryResultHKT { - readonly $brand: 'MySqlQueryResultHKT'; +export interface SingleStoreQueryResultHKT { + readonly $brand: 'SingleStoreQueryResultHKT'; readonly row: unknown; readonly type: unknown; } -export interface AnyMySqlQueryResultHKT extends MySqlQueryResultHKT { +export interface AnySingleStoreQueryResultHKT extends SingleStoreQueryResultHKT { readonly type: any; } -export type MySqlQueryResultKind = (TKind & { +export type SingleStoreQueryResultKind = (TKind & { readonly row: TRow; })['type']; -export interface MySqlPreparedQueryConfig { +export interface SingleStorePreparedQueryConfig { execute: unknown; iterator: unknown; } -export interface MySqlPreparedQueryHKT { - readonly $brand: 'MySqlPreparedQueryHKT'; +export interface SingleStorePreparedQueryHKT { + readonly $brand: 'SingleStorePreparedQueryHKT'; readonly config: unknown; readonly type: unknown; } export type PreparedQueryKind< - TKind extends MySqlPreparedQueryHKT, - TConfig extends MySqlPreparedQueryConfig, + TKind extends SingleStorePreparedQueryHKT, + TConfig extends SingleStorePreparedQueryConfig, TAssume extends boolean = false, > = Equal extends true - ? Assume<(TKind & { readonly config: TConfig })['type'], MySqlPreparedQuery> + ? Assume<(TKind & { readonly config: TConfig })['type'], SingleStorePreparedQuery> : (TKind & { readonly config: TConfig })['type']; -export abstract class MySqlPreparedQuery { - static readonly [entityKind]: string = 'MySqlPreparedQuery'; +export abstract class SingleStorePreparedQuery { + static readonly [entityKind]: string = 'SingleStorePreparedQuery'; /** @internal */ joinsNotNullableMap?: Record; @@ -53,23 +53,26 @@ export abstract class MySqlPreparedQuery { abstract iterator(placeholderValues?: Record): AsyncGenerator; } -export interface MySqlTransactionConfig { +export interface SingleStoreTransactionConfig { withConsistentSnapshot?: boolean; accessMode?: 'read only' | 'read write'; isolationLevel: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable'; } -export abstract class MySqlSession< - TQueryResult extends MySqlQueryResultHKT = MySqlQueryResultHKT, +export abstract class SingleStoreSession< + TQueryResult extends SingleStoreQueryResultHKT = SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, TFullSchema extends Record = Record, TSchema extends TablesRelationalConfig = Record, > { - static readonly [entityKind]: string = 'MySqlSession'; + static readonly [entityKind]: string = 'SingleStoreSession'; - constructor(protected dialect: MySqlDialect) {} + constructor(protected dialect: SingleStoreDialect) {} - abstract prepareQuery( + abstract prepareQuery< + T extends SingleStorePreparedQueryConfig, + TPreparedQueryHKT extends SingleStorePreparedQueryHKT, + >( query: Query, fields: SelectedFieldsOrdered | undefined, customResultMapper?: (rows: unknown[][]) => T['execute'], @@ -78,7 +81,7 @@ export abstract class MySqlSession< ): PreparedQueryKind; execute(query: SQL): Promise { - return this.prepareQuery( + return this.prepareQuery( this.dialect.sqlToQuery(query), undefined, ).execute(); @@ -87,11 +90,11 @@ export abstract class MySqlSession< abstract all(query: SQL): Promise; abstract transaction( - transaction: (tx: MySqlTransaction) => Promise, - config?: MySqlTransactionConfig, + transaction: (tx: SingleStoreTransaction) => Promise, + config?: SingleStoreTransactionConfig, ): Promise; - protected getSetTransactionSQL(config: MySqlTransactionConfig): SQL | undefined { + protected getSetTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { const parts: string[] = []; if (config.isolationLevel) { @@ -101,7 +104,7 @@ export abstract class MySqlSession< return parts.length ? sql.join(['set transaction ', parts.join(' ')]) : undefined; } - protected getStartTransactionSQL(config: MySqlTransactionConfig): SQL | undefined { + protected getStartTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { const parts: string[] = []; if (config.withConsistentSnapshot) { @@ -116,17 +119,17 @@ export abstract class MySqlSession< } } -export abstract class MySqlTransaction< - TQueryResult extends MySqlQueryResultHKT, +export abstract class SingleStoreTransaction< + TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, TFullSchema extends Record = Record, TSchema extends TablesRelationalConfig = Record, -> extends MySqlDatabase { - static readonly [entityKind]: string = 'MySqlTransaction'; +> extends SingleStoreDatabase { + static readonly [entityKind]: string = 'SingleStoreTransaction'; constructor( - dialect: MySqlDialect, - session: MySqlSession, + dialect: SingleStoreDialect, + session: SingleStoreSession, protected schema: RelationalSchemaConfig | undefined, protected readonly nestedIndex: number, mode: Mode, @@ -140,10 +143,10 @@ export abstract class MySqlTransaction< /** Nested transactions (aka savepoints) only work with InnoDB engine. */ abstract override transaction( - transaction: (tx: MySqlTransaction) => Promise, + transaction: (tx: SingleStoreTransaction) => Promise, ): Promise; } -export interface PreparedQueryHKTBase extends MySqlPreparedQueryHKT { - type: MySqlPreparedQuery>; +export interface PreparedQueryHKTBase extends SingleStorePreparedQueryHKT { + type: SingleStorePreparedQuery>; } diff --git a/drizzle-orm/src/singlestore-core/subquery.ts b/drizzle-orm/src/singlestore-core/subquery.ts index 9d2c1828c5..a4605c56d0 100644 --- a/drizzle-orm/src/singlestore-core/subquery.ts +++ b/drizzle-orm/src/singlestore-core/subquery.ts @@ -6,12 +6,12 @@ export type SubqueryWithSelection< TSelection extends ColumnsSelection, TAlias extends string, > = - & Subquery> - & AddAliasToSelection; + & Subquery> + & AddAliasToSelection; export type WithSubqueryWithSelection< TSelection extends ColumnsSelection, TAlias extends string, > = - & WithSubquery> - & AddAliasToSelection; + & WithSubquery> + & AddAliasToSelection; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 3b1d4c3a39..040e3981fb 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -2,13 +2,13 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts' import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { CheckBuilder } from './checks.ts'; -import type { MySqlColumn, MySqlColumnBuilder, MySqlColumnBuilderBase } from './columns/common.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -export type MySqlTableExtraConfig = Record< +export type SingleStoreTableExtraConfig = Record< string, | AnyIndexBuilder | CheckBuilder @@ -17,13 +17,13 @@ export type MySqlTableExtraConfig = Record< | UniqueConstraintBuilder >; -export type TableConfig = TableConfigBase; +export type TableConfig = TableConfigBase; /** @internal */ -export const InlineForeignKeys = Symbol.for('drizzle:MySqlInlineForeignKeys'); +export const InlineForeignKeys = Symbol.for('drizzle:SingleStoreInlineForeignKeys'); -export class MySqlTable extends Table { - static readonly [entityKind]: string = 'MySqlTable'; +export class SingleStoreTable extends Table { + static readonly [entityKind]: string = 'SingleStoreTable'; declare protected $columns: T['columns']; @@ -40,51 +40,53 @@ export class MySqlTable extends Table { /** @internal */ override [Table.Symbol.ExtraConfigBuilder]: - | ((self: Record) => MySqlTableExtraConfig) + | ((self: Record) => SingleStoreTableExtraConfig) | undefined = undefined; } -export type AnyMySqlTable = {}> = MySqlTable< +export type AnySingleStoreTable = {}> = SingleStoreTable< UpdateTableConfig >; -export type MySqlTableWithColumns = - & MySqlTable +export type SingleStoreTableWithColumns = + & SingleStoreTable & { [Key in keyof T['columns']]: T['columns'][Key]; }; -export function mysqlTableWithSchema< +export function singlestoreTableWithSchema< TTableName extends string, TSchemaName extends string | undefined, - TColumnsMap extends Record, + TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig: ((self: BuildColumns) => MySqlTableExtraConfig) | undefined, + extraConfig: + | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | undefined, schema: TSchemaName, baseName = name, -): MySqlTableWithColumns<{ +): SingleStoreTableWithColumns<{ name: TTableName; schema: TSchemaName; - columns: BuildColumns; - dialect: 'mysql'; + columns: BuildColumns; + dialect: 'singlestore'; }> { - const rawTable = new MySqlTable<{ + const rawTable = new SingleStoreTable<{ name: TTableName; schema: TSchemaName; - columns: BuildColumns; - dialect: 'mysql'; + columns: BuildColumns; + dialect: 'singlestore'; }>(name, schema, baseName); const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { - const colBuilder = colBuilderBase as MySqlColumnBuilder; + const colBuilder = colBuilderBase as SingleStoreColumnBuilder; const column = colBuilder.build(rawTable); rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable)); return [name, column]; }), - ) as unknown as BuildColumns; + ) as unknown as BuildColumns; const table = Object.assign(rawTable, builtColumns); @@ -92,40 +94,40 @@ export function mysqlTableWithSchema< table[Table.Symbol.ExtraConfigColumns] = builtColumns as unknown as BuildExtraConfigColumns< TTableName, TColumnsMap, - 'mysql' + 'singlestore' >; if (extraConfig) { - table[MySqlTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( - self: Record, - ) => MySqlTableExtraConfig; + table[SingleStoreTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( + self: Record, + ) => SingleStoreTableExtraConfig; } return table; } -export interface MySqlTableFn { +export interface SingleStoreTableFn { < TTableName extends string, - TColumnsMap extends Record, + TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig?: (self: BuildColumns) => MySqlTableExtraConfig, - ): MySqlTableWithColumns<{ + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + ): SingleStoreTableWithColumns<{ name: TTableName; schema: TSchemaName; - columns: BuildColumns; - dialect: 'mysql'; + columns: BuildColumns; + dialect: 'singlestore'; }>; } -export const mysqlTable: MySqlTableFn = (name, columns, extraConfig) => { - return mysqlTableWithSchema(name, columns, extraConfig, undefined, name); +export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); }; -export function mysqlTableCreator(customizeTableName: (name: string) => string): MySqlTableFn { +export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { return (name, columns, extraConfig) => { - return mysqlTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); }; } diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts index 66ed65198a..faa4f3216f 100644 --- a/drizzle-orm/src/singlestore-core/unique-constraint.ts +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -1,36 +1,36 @@ import { entityKind } from '~/entity.ts'; -import type { MySqlColumn } from './columns/index.ts'; -import { MySqlTable } from './table.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); } -export function uniqueKeyName(table: MySqlTable, columns: string[]) { - return `${table[MySqlTable.Symbol.Name]}_${columns.join('_')}_unique`; +export function uniqueKeyName(table: SingleStoreTable, columns: string[]) { + return `${table[SingleStoreTable.Symbol.Name]}_${columns.join('_')}_unique`; } export class UniqueConstraintBuilder { - static readonly [entityKind]: string = 'MySqlUniqueConstraintBuilder'; + static readonly [entityKind]: string = 'SingleStoreUniqueConstraintBuilder'; /** @internal */ - columns: MySqlColumn[]; + columns: SingleStoreColumn[]; constructor( - columns: MySqlColumn[], + columns: SingleStoreColumn[], private name?: string, ) { this.columns = columns; } /** @internal */ - build(table: MySqlTable): UniqueConstraint { + build(table: SingleStoreTable): UniqueConstraint { return new UniqueConstraint(table, this.columns, this.name); } } export class UniqueOnConstraintBuilder { - static readonly [entityKind]: string = 'MySqlUniqueOnConstraintBuilder'; + static readonly [entityKind]: string = 'SingleStoreUniqueOnConstraintBuilder'; /** @internal */ name?: string; @@ -41,19 +41,19 @@ export class UniqueOnConstraintBuilder { this.name = name; } - on(...columns: [MySqlColumn, ...MySqlColumn[]]) { + on(...columns: [SingleStoreColumn, ...SingleStoreColumn[]]) { return new UniqueConstraintBuilder(columns, this.name); } } export class UniqueConstraint { - static readonly [entityKind]: string = 'MySqlUniqueConstraint'; + static readonly [entityKind]: string = 'SingleStoreUniqueConstraint'; - readonly columns: MySqlColumn[]; + readonly columns: SingleStoreColumn[]; readonly name?: string; readonly nullsNotDistinct: boolean = false; - constructor(readonly table: MySqlTable, columns: MySqlColumn[], name?: string) { + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { this.columns = columns; this.name = name ?? uniqueKeyName(this.table, this.columns.map((column) => column.name)); } diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts index f09f65f3e9..e90c5ae404 100644 --- a/drizzle-orm/src/singlestore-core/utils.ts +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -9,26 +9,26 @@ import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; -import { MySqlTable } from './table.ts'; +import { SingleStoreTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; -import { MySqlViewConfig } from './view-common.ts'; -import type { MySqlView } from './view.ts'; +import { SingleStoreViewConfig } from './view-common.ts'; +import type { SingleStoreView } from './view.ts'; -export function getTableConfig(table: MySqlTable) { - const columns = Object.values(table[MySqlTable.Symbol.Columns]); +export function getTableConfig(table: SingleStoreTable) { + const columns = Object.values(table[SingleStoreTable.Symbol.Columns]); const indexes: Index[] = []; const checks: Check[] = []; const primaryKeys: PrimaryKey[] = []; const uniqueConstraints: UniqueConstraint[] = []; - const foreignKeys: ForeignKey[] = Object.values(table[MySqlTable.Symbol.InlineForeignKeys]); + const foreignKeys: ForeignKey[] = Object.values(table[SingleStoreTable.Symbol.InlineForeignKeys]); const name = table[Table.Symbol.Name]; const schema = table[Table.Symbol.Schema]; const baseName = table[Table.Symbol.BaseName]; - const extraConfigBuilder = table[MySqlTable.Symbol.ExtraConfigBuilder]; + const extraConfigBuilder = table[SingleStoreTable.Symbol.ExtraConfigBuilder]; if (extraConfigBuilder !== undefined) { - const extraConfig = extraConfigBuilder(table[MySqlTable.Symbol.Columns]); + const extraConfig = extraConfigBuilder(table[SingleStoreTable.Symbol.Columns]); for (const builder of Object.values(extraConfig)) { if (is(builder, IndexBuilder)) { indexes.push(builder.build(table)); @@ -60,9 +60,9 @@ export function getTableConfig(table: MySqlTable) { export function getViewConfig< TName extends string = string, TExisting extends boolean = boolean, ->(view: MySqlView) { +>(view: SingleStoreView) { return { ...view[ViewBaseConfig], - ...view[MySqlViewConfig], + ...view[SingleStoreViewConfig], }; } diff --git a/drizzle-orm/src/singlestore-core/view-base.ts b/drizzle-orm/src/singlestore-core/view-base.ts index 46b1527d90..f71536e289 100644 --- a/drizzle-orm/src/singlestore-core/view-base.ts +++ b/drizzle-orm/src/singlestore-core/view-base.ts @@ -2,14 +2,14 @@ import { entityKind } from '~/entity.ts'; import type { ColumnsSelection } from '~/sql/sql.ts'; import { View } from '~/sql/sql.ts'; -export abstract class MySqlViewBase< +export abstract class SingleStoreViewBase< TName extends string = string, TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends View { - static readonly [entityKind]: string = 'MySqlViewBase'; + static readonly [entityKind]: string = 'SingleStoreViewBase'; declare readonly _: View['_'] & { - readonly viewBrand: 'MySqlViewBase'; + readonly viewBrand: 'SingleStoreViewBase'; }; } diff --git a/drizzle-orm/src/singlestore-core/view-common.ts b/drizzle-orm/src/singlestore-core/view-common.ts index 9bbc130c33..d29c3d5ada 100644 --- a/drizzle-orm/src/singlestore-core/view-common.ts +++ b/drizzle-orm/src/singlestore-core/view-common.ts @@ -1 +1 @@ -export const MySqlViewConfig = Symbol.for('drizzle:MySqlViewConfig'); +export const SingleStoreViewConfig = Symbol.for('drizzle:SingleStoreViewConfig'); diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts index 4cc7d416c9..3c6c8d25ca 100644 --- a/drizzle-orm/src/singlestore-core/view.ts +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -5,12 +5,12 @@ import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; -import type { MySqlColumn, MySqlColumnBuilderBase } from './columns/index.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilderBase } from './columns/index.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; -import { mysqlTable } from './table.ts'; -import { MySqlViewBase } from './view-base.ts'; -import { MySqlViewConfig } from './view-common.ts'; +import { singlestoreTable } from './table.ts'; +import { SingleStoreViewBase } from './view-base.ts'; +import { SingleStoreViewConfig } from './view-common.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; @@ -20,7 +20,7 @@ export interface ViewBuilderConfig { } export class ViewBuilderCore { - static readonly [entityKind]: string = 'MySqlViewBuilder'; + static readonly [entityKind]: string = 'SingleStoreViewBuilder'; declare readonly _: { readonly name: TConfig['name']; @@ -64,11 +64,11 @@ export class ViewBuilderCore extends ViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'MySqlViewBuilder'; + static readonly [entityKind]: string = 'SingleStoreViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), - ): MySqlViewWithSelection> { + ): SingleStoreViewWithSelection> { if (typeof qb === 'function') { qb = qb(new QueryBuilder()); } @@ -80,8 +80,8 @@ export class ViewBuilder extends ViewBuilderCore< }); const aliasedSelection = new Proxy(qb.getSelectedFields(), selectionProxy); return new Proxy( - new MySqlView({ - mysqlConfig: this.config, + new SingleStoreView({ + singlestoreConfig: this.config, config: { name: this.name, schema: this.schema, @@ -90,17 +90,17 @@ export class ViewBuilder extends ViewBuilderCore< }, }), selectionProxy as any, - ) as MySqlViewWithSelection>; + ) as SingleStoreViewWithSelection>; } } export class ManualViewBuilder< TName extends string = string, - TColumns extends Record = Record, + TColumns extends Record = Record, > extends ViewBuilderCore<{ name: TName; columns: TColumns }> { - static readonly [entityKind]: string = 'MySqlManualViewBuilder'; + static readonly [entityKind]: string = 'SingleStoreManualViewBuilder'; - private columns: Record; + private columns: Record; constructor( name: TName, @@ -108,13 +108,13 @@ export class ManualViewBuilder< schema: string | undefined, ) { super(name, schema); - this.columns = getTableColumns(mysqlTable(name, columns)) as BuildColumns; + this.columns = getTableColumns(singlestoreTable(name, columns)) as BuildColumns; } - existing(): MySqlViewWithSelection> { + existing(): SingleStoreViewWithSelection> { return new Proxy( - new MySqlView({ - mysqlConfig: undefined, + new SingleStoreView({ + singlestoreConfig: undefined, config: { name: this.name, schema: this.schema, @@ -128,13 +128,13 @@ export class ManualViewBuilder< sqlAliasedBehavior: 'alias', replaceOriginalName: true, }), - ) as MySqlViewWithSelection>; + ) as SingleStoreViewWithSelection>; } - as(query: SQL): MySqlViewWithSelection> { + as(query: SQL): SingleStoreViewWithSelection> { return new Proxy( - new MySqlView({ - mysqlConfig: this.config, + new SingleStoreView({ + singlestoreConfig: this.config, config: { name: this.name, schema: this.schema, @@ -148,23 +148,23 @@ export class ManualViewBuilder< sqlAliasedBehavior: 'alias', replaceOriginalName: true, }), - ) as MySqlViewWithSelection>; + ) as SingleStoreViewWithSelection>; } } -export class MySqlView< +export class SingleStoreView< TName extends string = string, TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, -> extends MySqlViewBase { - static readonly [entityKind]: string = 'MySqlView'; +> extends SingleStoreViewBase { + static readonly [entityKind]: string = 'SingleStoreView'; - declare protected $MySqlViewBrand: 'MySqlView'; + declare protected $SingleStoreViewBrand: 'SingleStoreView'; - [MySqlViewConfig]: ViewBuilderConfig | undefined; + [SingleStoreViewConfig]: ViewBuilderConfig | undefined; - constructor({ mysqlConfig, config }: { - mysqlConfig: ViewBuilderConfig | undefined; + constructor({ singlestoreConfig, config }: { + singlestoreConfig: ViewBuilderConfig | undefined; config: { name: TName; schema: string | undefined; @@ -173,20 +173,20 @@ export class MySqlView< }; }) { super(config); - this[MySqlViewConfig] = mysqlConfig; + this[SingleStoreViewConfig] = singlestoreConfig; } } -export type MySqlViewWithSelection< +export type SingleStoreViewWithSelection< TName extends string, TExisting extends boolean, TSelectedFields extends ColumnsSelection, -> = MySqlView & TSelectedFields; +> = SingleStoreView & TSelectedFields; /** @internal */ -export function mysqlViewWithSchema( +export function singlestoreViewWithSchema( name: string, - selection: Record | undefined, + selection: Record | undefined, schema: string | undefined, ): ViewBuilder | ManualViewBuilder { if (selection) { @@ -195,14 +195,14 @@ export function mysqlViewWithSchema( return new ViewBuilder(name, schema); } -export function mysqlView(name: TName): ViewBuilder; -export function mysqlView>( +export function singlestoreView(name: TName): ViewBuilder; +export function singlestoreView>( name: TName, columns: TColumns, ): ManualViewBuilder; -export function mysqlView( +export function singlestoreView( name: string, - selection?: Record, + selection?: Record, ): ViewBuilder | ManualViewBuilder { - return mysqlViewWithSchema(name, selection, undefined); + return singlestoreViewWithSchema(name, selection, undefined); } From 7e1133f8ed2689e576554c77ea80ce4dca4ebfab Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Tue, 23 Jul 2024 18:53:58 +0100 Subject: [PATCH 005/152] test actions --- .github/workflows/release-latest-2.yaml | 238 ++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 .github/workflows/release-latest-2.yaml diff --git a/.github/workflows/release-latest-2.yaml b/.github/workflows/release-latest-2.yaml new file mode 100644 index 0000000000..5cf5f7fefe --- /dev/null +++ b/.github/workflows/release-latest-2.yaml @@ -0,0 +1,238 @@ +name: Release (latest) + +on: + push: + branches: + - master + workflow_dispatch: + +jobs: + release: + permissions: write-all + strategy: + fail-fast: false + matrix: + package: + - drizzle-orm + - drizzle-zod + - drizzle-typebox + - drizzle-valibot + - eslint-plugin-drizzle + runs-on: ubuntu-20.04 + services: + postgres-postgis: + image: postgis/postgis:16-3.4 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: drizzle + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 54322:5432 + postgres-vector: + image: pgvector/pgvector:pg16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: drizzle + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 54321:5432 + postgres: + image: postgres:14 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: drizzle + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 55433:5432 + mysql: + image: mysql:8 + env: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: drizzle + options: >- + --health-cmd "mysqladmin ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 33306:3306 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '18.18' + registry-url: 'https://registry.npmjs.org' + + - uses: pnpm/action-setup@v3 + name: Install pnpm + id: pnpm-install + with: + version: latest + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Check preconditions + id: checks + shell: bash + working-directory: ${{ matrix.package }} + run: | + latest="$(npm view --json ${{ matrix.package }} dist-tags.latest | jq -r)" + version="$(jq -r .version package.json)" + is_version_published="$(npm view ${{ matrix.package }} versions --json | jq -r '.[] | select(. == "'$version'") | . == "'$version'"')" + + if [[ "$is_version_published" == "true" ]]; then + echo "\`${{ matrix.package }}@$version\` already published, adding tag \`latest\`" >> $GITHUB_STEP_SUMMARY + npm dist-tag add ${{ matrix.package }}@$version latest + elif [[ "$latest" != "$version" ]]; then + echo "Latest: $latest" + echo "Current: $version" + + changelogPath=$(node -e "console.log(require('path').resolve('..', 'changelogs', '${{ matrix.package }}', '$version.md'))") + if [[ ! -f "$changelogPath" ]]; then + echo "::error::Changelog for version $version not found: $changelogPath" + exit 1 + fi + + { + echo "version=$version" + echo "has_new_release=true" + echo "changelog_path=$changelogPath" + } >> $GITHUB_OUTPUT + else + echo "Already up to date: $version" + echo "\`$version\` is already latest on NPM" >> $GITHUB_STEP_SUMMARY + fi + + - name: Build + if: steps.checks.outputs.has_new_release == 'true' + run: | + ( + cd drizzle-orm + pnpm prisma generate --schema src/prisma/schema.prisma + ) + ( + cd integration-tests + pnpm prisma generate --schema tests/prisma/pg/schema.prisma + pnpm prisma generate --schema tests/prisma/mysql/schema.prisma + pnpm prisma generate --schema tests/prisma/sqlite/schema.prisma + ) + pnpm build + + - name: Run tests + if: steps.checks.outputs.has_new_release == 'true' + env: + PG_CONNECTION_STRING: postgres://postgres:postgres@localhost:55433/drizzle + PG_VECTOR_CONNECTION_STRING: postgres://postgres:postgres@localhost:54321/drizzle + PG_POSTGIS_CONNECTION_STRING: postgres://postgres:postgres@localhost:54322/drizzle + MYSQL_CONNECTION_STRING: mysql://root:root@localhost:33306/drizzle + PLANETSCALE_CONNECTION_STRING: ${{ secrets.PLANETSCALE_CONNECTION_STRING }} + NEON_CONNECTION_STRING: ${{ secrets.NEON_CONNECTION_STRING }} + TIDB_CONNECTION_STRING: ${{ secrets.TIDB_CONNECTION_STRING }} + XATA_API_KEY: ${{ secrets.XATA_API_KEY }} + XATA_BRANCH: ${{ secrets.XATA_BRANCH }} + LIBSQL_URL: file:local.db + run: | + if [[ "${{ matrix.package }}" == "drizzle-orm" ]]; then + pnpm test --filter ${{ matrix.package }} --filter integration-tests + else + pnpm test --filter ${{ matrix.package }} + fi + + - name: Pack + if: steps.checks.outputs.has_new_release == 'true' + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + npm run pack + + - name: Run @arethetypeswrong/cli + if: steps.checks.outputs.has_new_release == 'true' + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + pnpm attw package.tgz + + - name: Publish + if: steps.checks.outputs.has_new_release == 'true' + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + version="${{ steps.checks.outputs.version }}" + + echo "Publishing ${{ matrix.package }}@$version" + npm run publish + + echo "npm: \`+ ${{ matrix.package }}@$version\`" >> $GITHUB_STEP_SUMMARY + + # Post release message to Discord + # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} + + - name: Create GitHub release for ORM package + uses: actions/github-script@v6 + if: matrix.package == 'drizzle-orm' && steps.checks.outputs.has_new_release == 'true' + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + const fs = require("fs"); + const path = require("path"); + + const version = "${{ steps.checks.outputs.version }}"; + const changelog = fs.readFileSync("${{ steps.checks.outputs.changelog_path }}", "utf8"); + + const release = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `${version}`, + name: `${version}`, + body: changelog, + }); + + await github.rest.repos.uploadReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.data.id, + name: `${{ matrix.package }}-${version}-dist.tgz`, + data: fs.readFileSync(path.resolve("${{ matrix.package }}", "package.tgz")), + }); + } catch (e) { + core.setFailed(e.message); + } From f7f75e4175ca0b2ec45ed59bc2427346dac735e7 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Tue, 23 Jul 2024 12:59:57 -0400 Subject: [PATCH 006/152] add uuid column --- .../src/singlestore-core/columns/uuid.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/columns/uuid.ts diff --git a/drizzle-orm/src/singlestore-core/columns/uuid.ts b/drizzle-orm/src/singlestore-core/columns/uuid.ts new file mode 100644 index 0000000000..a3d909c4ea --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/uuid.ts @@ -0,0 +1,45 @@ +import { ColumnBaseConfig } from "~/column"; +import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from "~/column-builder"; +import { entityKind } from "~/entity"; +import { SingleStoreColumn, SingleStoreColumnBuilder } from "./common"; +import { AnySingleStoreTable } from "~/singlestore-core/table"; + + +export type SingleStoreUUIDBuilderInitial = SingleStoreUUIDBuilder<{ + name: TName; + dataType: "string"; + columnType: "SingleStoreUUID"; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}> + +export class SingleStoreUUIDBuilder> extends SingleStoreColumnBuilder { + static readonly [entityKind]: string = "SingleStoreUUIDBuilder" + + constructor(name: T["name"]) { + super(name, "string", "SingleStoreUUID") + } + + /** @internal */ + build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreUUID> { + return new SingleStoreUUID(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreUUID> extends SingleStoreColumn { + static readonly [entityKind]: string = "SingleStoreUUID" + + constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreUUIDBuilder["config"]) { + super(table, config) + } + + getSQLType(): string { + return "varchar(36)" + } +} + +export function uuid(name: TName): SingleStoreUUIDBuilderInitial { + return new SingleStoreUUIDBuilder(name) +} \ No newline at end of file From ce7c09ea47253487f3be2c89f720f5a7b75cafad Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Tue, 23 Jul 2024 14:00:39 -0400 Subject: [PATCH 007/152] add guid --- .../src/singlestore-core/columns/guid.ts | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/columns/guid.ts diff --git a/drizzle-orm/src/singlestore-core/columns/guid.ts b/drizzle-orm/src/singlestore-core/columns/guid.ts new file mode 100644 index 0000000000..2266512522 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/guid.ts @@ -0,0 +1,111 @@ +import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from "~/column-builder"; +import { entityKind } from "~/entity"; +import { SingleStoreColumn, SingleStoreColumnBuilder } from "./common"; +import { AnySingleStoreTable } from "~/singlestore-core/table"; +import { ColumnBaseConfig } from "~/column"; +import { sql } from "~/sql/sql"; +import { Equal } from "~/utils"; + + +export type SingleStoreGUIDBuilderInitial = SingleStoreGUIDBuilder<{ + name: TName; + dataType: "buffer"; + columnType: "SingleStoreGUID"; + data: Uint8Array; + driverParam: string; + enumValues: undefined; + generated: undefined; +}> + +export class SingleStoreGUIDBuilder> extends SingleStoreColumnBuilder { + static readonly [entityKind]: string = "SingleStoreGUIDBuilder" + + constructor(name: T["name"], config?: SingleStoreGUIDConfig) { + super(name, "buffer", "SingleStoreGUID") + } + + /** @internal */ + build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUID> { + return new SingleStoreGUID(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreGUID> extends SingleStoreColumn { + static readonly [entityKind]: string = "SingleStoreGUID" + + constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreGUIDBuilder["config"]) { + super(table, config) + } + + getSQLType(): string { + return "binary(16)" + } + + override mapToDriverValue(value: string) { + return sql`UNHEX(REPLACE(${value}, "-", ""))` + } +} + +export type SingleStoreGUIDStringBuilderInitial = SingleStoreGUIDStringBuilder<{ + name: TName; + dataType: "string"; + columnType: "SingleStoreGUIDString"; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}> + +export class SingleStoreGUIDStringBuilder> extends SingleStoreColumnBuilder { + static readonly [entityKind]: string = "SingleStoreGUIDStringBuilder" + + constructor(name: T["name"], config?: SingleStoreGUIDConfig) { + super(name, "string", "SingleStoreGUIDString") + } + + /** @internal */ + build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUIDString> { + return new SingleStoreGUIDString(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreGUIDString> extends SingleStoreColumn { + static readonly [entityKind]: string = "SingleStoreGUIDString" + + constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreGUIDStringBuilder["config"]) { + super(table, config) + } + + getSQLType(): string { + return "binary(16)" + } + + override mapToDriverValue(value: string) { + return sql`UNHEX(REPLACE(${value}, "-", ""))` + } + + override mapFromDriverValue(value: Uint8Array): string { + const hex = Buffer.from(value).toString("hex"); + return `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`; + } +} + +export interface SingleStoreGUIDConfig { + mode?: TMode; +} + +/** + * Creates a column with the data type `BINARY(16)` + * + * Use config `{ mode: "string" }` for a string representation of the GUID + */ +export function guid( + name: TName, + config?: SingleStoreGUIDConfig +): Equal extends true ? SingleStoreGUIDStringBuilderInitial : SingleStoreGUIDBuilderInitial; +export function guid(name: string, config?: SingleStoreGUIDConfig) { + if (config?.mode === "string") { + return new SingleStoreGUIDStringBuilder(name, config) + } + return new SingleStoreGUIDBuilder(name, config) +} \ No newline at end of file From 783fc766ae0aa5ffc9eaa428ba3c201b8c3cd946 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Tue, 23 Jul 2024 14:02:05 -0400 Subject: [PATCH 008/152] add override tag to `build` --- drizzle-orm/src/singlestore-core/columns/guid.ts | 4 ++-- drizzle-orm/src/singlestore-core/columns/uuid.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/guid.ts b/drizzle-orm/src/singlestore-core/columns/guid.ts index 2266512522..f8fac9816e 100644 --- a/drizzle-orm/src/singlestore-core/columns/guid.ts +++ b/drizzle-orm/src/singlestore-core/columns/guid.ts @@ -25,7 +25,7 @@ export class SingleStoreGUIDBuilder(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUID> { + override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUID> { return new SingleStoreGUID(table, this.config as ColumnBuilderRuntimeConfig); } } @@ -64,7 +64,7 @@ export class SingleStoreGUIDStringBuilder(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUIDString> { + override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUIDString> { return new SingleStoreGUIDString(table, this.config as ColumnBuilderRuntimeConfig); } } diff --git a/drizzle-orm/src/singlestore-core/columns/uuid.ts b/drizzle-orm/src/singlestore-core/columns/uuid.ts index a3d909c4ea..6886087b86 100644 --- a/drizzle-orm/src/singlestore-core/columns/uuid.ts +++ b/drizzle-orm/src/singlestore-core/columns/uuid.ts @@ -23,7 +23,7 @@ export class SingleStoreUUIDBuilder(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreUUID> { + override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreUUID> { return new SingleStoreUUID(table, this.config as ColumnBuilderRuntimeConfig); } } From dd8b12a073b5be748e83f43616dd23abffcd6e54 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Tue, 23 Jul 2024 19:08:28 +0100 Subject: [PATCH 009/152] more actions tests --- .github/workflows/release-latest-2.yaml | 238 ------------------------ 1 file changed, 238 deletions(-) delete mode 100644 .github/workflows/release-latest-2.yaml diff --git a/.github/workflows/release-latest-2.yaml b/.github/workflows/release-latest-2.yaml deleted file mode 100644 index 5cf5f7fefe..0000000000 --- a/.github/workflows/release-latest-2.yaml +++ /dev/null @@ -1,238 +0,0 @@ -name: Release (latest) - -on: - push: - branches: - - master - workflow_dispatch: - -jobs: - release: - permissions: write-all - strategy: - fail-fast: false - matrix: - package: - - drizzle-orm - - drizzle-zod - - drizzle-typebox - - drizzle-valibot - - eslint-plugin-drizzle - runs-on: ubuntu-20.04 - services: - postgres-postgis: - image: postgis/postgis:16-3.4 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: drizzle - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 54322:5432 - postgres-vector: - image: pgvector/pgvector:pg16 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: drizzle - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 54321:5432 - postgres: - image: postgres:14 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: drizzle - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 55433:5432 - mysql: - image: mysql:8 - env: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: drizzle - options: >- - --health-cmd "mysqladmin ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 33306:3306 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: '18.18' - registry-url: 'https://registry.npmjs.org' - - - uses: pnpm/action-setup@v3 - name: Install pnpm - id: pnpm-install - with: - version: latest - run_install: false - - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT - - - uses: actions/cache@v4 - name: Setup pnpm cache - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - - name: Install dependencies - run: pnpm install - - - name: Check preconditions - id: checks - shell: bash - working-directory: ${{ matrix.package }} - run: | - latest="$(npm view --json ${{ matrix.package }} dist-tags.latest | jq -r)" - version="$(jq -r .version package.json)" - is_version_published="$(npm view ${{ matrix.package }} versions --json | jq -r '.[] | select(. == "'$version'") | . == "'$version'"')" - - if [[ "$is_version_published" == "true" ]]; then - echo "\`${{ matrix.package }}@$version\` already published, adding tag \`latest\`" >> $GITHUB_STEP_SUMMARY - npm dist-tag add ${{ matrix.package }}@$version latest - elif [[ "$latest" != "$version" ]]; then - echo "Latest: $latest" - echo "Current: $version" - - changelogPath=$(node -e "console.log(require('path').resolve('..', 'changelogs', '${{ matrix.package }}', '$version.md'))") - if [[ ! -f "$changelogPath" ]]; then - echo "::error::Changelog for version $version not found: $changelogPath" - exit 1 - fi - - { - echo "version=$version" - echo "has_new_release=true" - echo "changelog_path=$changelogPath" - } >> $GITHUB_OUTPUT - else - echo "Already up to date: $version" - echo "\`$version\` is already latest on NPM" >> $GITHUB_STEP_SUMMARY - fi - - - name: Build - if: steps.checks.outputs.has_new_release == 'true' - run: | - ( - cd drizzle-orm - pnpm prisma generate --schema src/prisma/schema.prisma - ) - ( - cd integration-tests - pnpm prisma generate --schema tests/prisma/pg/schema.prisma - pnpm prisma generate --schema tests/prisma/mysql/schema.prisma - pnpm prisma generate --schema tests/prisma/sqlite/schema.prisma - ) - pnpm build - - - name: Run tests - if: steps.checks.outputs.has_new_release == 'true' - env: - PG_CONNECTION_STRING: postgres://postgres:postgres@localhost:55433/drizzle - PG_VECTOR_CONNECTION_STRING: postgres://postgres:postgres@localhost:54321/drizzle - PG_POSTGIS_CONNECTION_STRING: postgres://postgres:postgres@localhost:54322/drizzle - MYSQL_CONNECTION_STRING: mysql://root:root@localhost:33306/drizzle - PLANETSCALE_CONNECTION_STRING: ${{ secrets.PLANETSCALE_CONNECTION_STRING }} - NEON_CONNECTION_STRING: ${{ secrets.NEON_CONNECTION_STRING }} - TIDB_CONNECTION_STRING: ${{ secrets.TIDB_CONNECTION_STRING }} - XATA_API_KEY: ${{ secrets.XATA_API_KEY }} - XATA_BRANCH: ${{ secrets.XATA_BRANCH }} - LIBSQL_URL: file:local.db - run: | - if [[ "${{ matrix.package }}" == "drizzle-orm" ]]; then - pnpm test --filter ${{ matrix.package }} --filter integration-tests - else - pnpm test --filter ${{ matrix.package }} - fi - - - name: Pack - if: steps.checks.outputs.has_new_release == 'true' - working-directory: ${{ matrix.package }} - shell: bash - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} - run: | - npm run pack - - - name: Run @arethetypeswrong/cli - if: steps.checks.outputs.has_new_release == 'true' - working-directory: ${{ matrix.package }} - shell: bash - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} - run: | - pnpm attw package.tgz - - - name: Publish - if: steps.checks.outputs.has_new_release == 'true' - working-directory: ${{ matrix.package }} - shell: bash - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} - run: | - version="${{ steps.checks.outputs.version }}" - - echo "Publishing ${{ matrix.package }}@$version" - npm run publish - - echo "npm: \`+ ${{ matrix.package }}@$version\`" >> $GITHUB_STEP_SUMMARY - - # Post release message to Discord - # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} - - - name: Create GitHub release for ORM package - uses: actions/github-script@v6 - if: matrix.package == 'drizzle-orm' && steps.checks.outputs.has_new_release == 'true' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - try { - const fs = require("fs"); - const path = require("path"); - - const version = "${{ steps.checks.outputs.version }}"; - const changelog = fs.readFileSync("${{ steps.checks.outputs.changelog_path }}", "utf8"); - - const release = await github.rest.repos.createRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - tag_name: `${version}`, - name: `${version}`, - body: changelog, - }); - - await github.rest.repos.uploadReleaseAsset({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: release.data.id, - name: `${{ matrix.package }}-${version}-dist.tgz`, - data: fs.readFileSync(path.resolve("${{ matrix.package }}", "package.tgz")), - }); - } catch (e) { - core.setFailed(e.message); - } From 21529bbf37d2ffa8d32b06d18da48b87bab005d2 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Tue, 23 Jul 2024 19:28:47 +0100 Subject: [PATCH 010/152] release to github --- .github/workflows/release-to-github.yaml | 197 +++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 .github/workflows/release-to-github.yaml diff --git a/.github/workflows/release-to-github.yaml b/.github/workflows/release-to-github.yaml new file mode 100644 index 0000000000..f92d6ecd6e --- /dev/null +++ b/.github/workflows/release-to-github.yaml @@ -0,0 +1,197 @@ +name: Release to GitHub + +on: workflow_dispatch + +jobs: + release: + permissions: write-all + strategy: + fail-fast: false + matrix: + package: + - drizzle-orm + - drizzle-zod + - drizzle-typebox + - drizzle-valibot + - eslint-plugin-drizzle + runs-on: ubuntu-20.04 + services: + postgres-postgis: + image: postgis/postgis:16-3.4 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: drizzle + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 54322:5432 + postgres-vector: + image: pgvector/pgvector:pg16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: drizzle + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 54321:5432 + postgres: + image: postgres:14 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: drizzle + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 55433:5432 + mysql: + image: mysql:8 + env: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: drizzle + options: >- + --health-cmd "mysqladmin ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 33306:3306 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '18.18' + registry-url: 'https://registry.npmjs.org' + + - uses: pnpm/action-setup@v3 + name: Install pnpm + id: pnpm-install + with: + version: latest + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Build + run: | + ( + cd drizzle-orm + pnpm prisma generate --schema src/prisma/schema.prisma + ) + ( + cd integration-tests + pnpm prisma generate --schema tests/prisma/pg/schema.prisma + pnpm prisma generate --schema tests/prisma/mysql/schema.prisma + pnpm prisma generate --schema tests/prisma/sqlite/schema.prisma + ) + pnpm build + + - name: Run tests + env: + PG_CONNECTION_STRING: postgres://postgres:postgres@localhost:55433/drizzle + PG_VECTOR_CONNECTION_STRING: postgres://postgres:postgres@localhost:54321/drizzle + PG_POSTGIS_CONNECTION_STRING: postgres://postgres:postgres@localhost:54322/drizzle + MYSQL_CONNECTION_STRING: mysql://root:root@localhost:33306/drizzle + PLANETSCALE_CONNECTION_STRING: ${{ secrets.PLANETSCALE_CONNECTION_STRING }} + NEON_CONNECTION_STRING: ${{ secrets.NEON_CONNECTION_STRING }} + TIDB_CONNECTION_STRING: ${{ secrets.TIDB_CONNECTION_STRING }} + XATA_API_KEY: ${{ secrets.XATA_API_KEY }} + XATA_BRANCH: ${{ secrets.XATA_BRANCH }} + LIBSQL_URL: file:local.db + run: | + if [[ "${{ matrix.package }}" == "drizzle-orm" ]]; then + pnpm test --filter ${{ matrix.package }} --filter integration-tests + else + pnpm test --filter ${{ matrix.package }} + fi + + - name: Pack + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + npm run pack + + - name: Run @arethetypeswrong/cli + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + pnpm attw package.tgz + + - name: Publish + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + version="${{ steps.checks.outputs.version }}" + + echo "Publishing ${{ matrix.package }}@$version" + npm run publish + + echo "npm: \`+ ${{ matrix.package }}@$version\`" >> $GITHUB_STEP_SUMMARY + + # Post release message to Discord + # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} + + - name: Create GitHub release for ORM package + uses: actions/github-script@v6 + if: matrix.package == 'drizzle-orm' && steps.checks.outputs.has_new_release == 'true' + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + const fs = require("fs"); + const path = require("path"); + + const version = "${{ steps.checks.outputs.version }}"; + const changelog = fs.readFileSync("${{ steps.checks.outputs.changelog_path }}", "utf8"); + + const release = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `${version}`, + name: `${version}`, + body: changelog, + }); + + await github.rest.repos.uploadReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.data.id, + name: `${{ matrix.package }}-${version}-dist.tgz`, + data: fs.readFileSync(path.resolve("${{ matrix.package }}", "package.tgz")), + }); + } catch (e) { + core.setFailed(e.message); + } From 278347987673cc3cff0b7f5d72b56cac1d9224b3 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Tue, 23 Jul 2024 14:30:37 -0400 Subject: [PATCH 011/152] add vector data type, operator experessions --- .../src/singlestore-core/columns/vector.ts | 67 +++++++++++++++++++ .../src/singlestore-core/expressions.ts | 10 +++ 2 files changed, 77 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/columns/vector.ts diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts new file mode 100644 index 0000000000..ad1a09780a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -0,0 +1,67 @@ +import { ColumnBaseConfig } from "~/column"; +import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from "~/column-builder"; +import { entityKind } from "~/entity"; +import { SingleStoreColumn, SingleStoreColumnBuilder } from "./common"; +import { AnySingleStoreTable } from "~/singlestore-core/table"; + +export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ + name: TName; + dataType: "array"; + columnType: "SingleStoreVector"; + data: Array; + driverParam: Array; + enumValues: undefined; + generated: undefined; +}> + +export class SingleStoreVectorBuilder> extends SingleStoreColumnBuilder { + static readonly [entityKind]: string = "SingleStoreVectorBuilder" + + constructor(name: T["name"], config: SingleStoreVectorConfig) { + super(name, "array", "SingleStoreVector") + this.config.dimensions = config.dimensions + this.config.elementType = config.elementType + } + + /** @internal */ + override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreVector> { + return new SingleStoreVector(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreVector> extends SingleStoreColumn { + static readonly [entityKind]: string = "SingleStoreVector" + + readonly dimensions: number; + readonly elementType: ElementType | undefined; + + constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreVectorBuilder["config"]) { + super(table, config) + this.dimensions = config.dimensions + this.elementType = config.elementType + } + + getSQLType(): string { + const et = this.elementType === undefined ? "" : `, ${this.elementType}`; + return `vector(${this.dimensions}${et})` + } + + override mapToDriverValue(value: Array) { + return JSON.stringify(value) + } + + override mapFromDriverValue(value: string): Array { + return JSON.parse(value) + } +} + +type ElementType = "I8" | "I16" | "I32" | "I64" | "F32" | "F64"; + +export interface SingleStoreVectorConfig { + dimensions: number; + elementType: ElementType; +} + +export function vector(name: TName, config: SingleStoreVectorConfig): SingleStoreVectorBuilderInitial { + return new SingleStoreVectorBuilder(name, config) +} \ No newline at end of file diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts index 6d4284d180..aa77fbd480 100644 --- a/drizzle-orm/src/singlestore-core/expressions.ts +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -23,3 +23,13 @@ export function substring( chunks.push(sql`)`); return sql.join(chunks); } + +// Vectors + +export function dotProduct(column: SingleStoreColumn | SQL.Aliased, value: Array) { + return sql`${column} <*> ${JSON.stringify(value)}` +} + +export function euclideanDistance(column: SingleStoreColumn | SQL.Aliased, value: Array) { + return sql`${column} <-> ${JSON.stringify(value)}` +} From 5bce7e5c5426122699b749efbfb5bf3e9295eb00 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Tue, 23 Jul 2024 20:05:32 +0100 Subject: [PATCH 012/152] nits --- .github/workflows/release-to-github.yaml | 36 ---- .../src/singlestore-core/columns/guid.ts | 192 ++++++++++-------- .../src/singlestore-core/columns/uuid.ts | 75 +++---- .../src/singlestore-core/columns/vector.ts | 105 +++++----- .../src/singlestore-core/expressions.ts | 4 +- 5 files changed, 199 insertions(+), 213 deletions(-) diff --git a/.github/workflows/release-to-github.yaml b/.github/workflows/release-to-github.yaml index f92d6ecd6e..7e4419fec5 100644 --- a/.github/workflows/release-to-github.yaml +++ b/.github/workflows/release-to-github.yaml @@ -10,10 +10,6 @@ jobs: matrix: package: - drizzle-orm - - drizzle-zod - - drizzle-typebox - - drizzle-valibot - - eslint-plugin-drizzle runs-on: ubuntu-20.04 services: postgres-postgis: @@ -163,35 +159,3 @@ jobs: # Post release message to Discord # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} - - - name: Create GitHub release for ORM package - uses: actions/github-script@v6 - if: matrix.package == 'drizzle-orm' && steps.checks.outputs.has_new_release == 'true' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - try { - const fs = require("fs"); - const path = require("path"); - - const version = "${{ steps.checks.outputs.version }}"; - const changelog = fs.readFileSync("${{ steps.checks.outputs.changelog_path }}", "utf8"); - - const release = await github.rest.repos.createRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - tag_name: `${version}`, - name: `${version}`, - body: changelog, - }); - - await github.rest.repos.uploadReleaseAsset({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: release.data.id, - name: `${{ matrix.package }}-${version}-dist.tgz`, - data: fs.readFileSync(path.resolve("${{ matrix.package }}", "package.tgz")), - }); - } catch (e) { - core.setFailed(e.message); - } diff --git a/drizzle-orm/src/singlestore-core/columns/guid.ts b/drizzle-orm/src/singlestore-core/columns/guid.ts index f8fac9816e..5f2cd175e0 100644 --- a/drizzle-orm/src/singlestore-core/columns/guid.ts +++ b/drizzle-orm/src/singlestore-core/columns/guid.ts @@ -1,111 +1,123 @@ -import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from "~/column-builder"; -import { entityKind } from "~/entity"; -import { SingleStoreColumn, SingleStoreColumnBuilder } from "./common"; -import { AnySingleStoreTable } from "~/singlestore-core/table"; -import { ColumnBaseConfig } from "~/column"; -import { sql } from "~/sql/sql"; -import { Equal } from "~/utils"; - +import { ColumnBaseConfig } from '~/column'; +import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import { entityKind } from '~/entity'; +import { AnySingleStoreTable } from '~/singlestore-core/table'; +import { sql } from '~/sql/sql'; +import { Equal } from '~/utils'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common'; export type SingleStoreGUIDBuilderInitial = SingleStoreGUIDBuilder<{ - name: TName; - dataType: "buffer"; - columnType: "SingleStoreGUID"; - data: Uint8Array; - driverParam: string; - enumValues: undefined; - generated: undefined; -}> - -export class SingleStoreGUIDBuilder> extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = "SingleStoreGUIDBuilder" - - constructor(name: T["name"], config?: SingleStoreGUIDConfig) { - super(name, "buffer", "SingleStoreGUID") - } - - /** @internal */ - override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUID> { - return new SingleStoreGUID(table, this.config as ColumnBuilderRuntimeConfig); - } + name: TName; + dataType: 'buffer'; + columnType: 'SingleStoreGUID'; + data: Uint8Array; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreGUIDBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreGUIDBuilder'; + + constructor(name: T['name'], config?: SingleStoreGUIDConfig) { + super(name, 'buffer', 'SingleStoreGUID'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreGUID> { + return new SingleStoreGUID(table, this.config as ColumnBuilderRuntimeConfig); + } } -export class SingleStoreGUID> extends SingleStoreColumn { - static readonly [entityKind]: string = "SingleStoreGUID" +export class SingleStoreGUID> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreGUID'; - constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreGUIDBuilder["config"]) { - super(table, config) - } + constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreGUIDBuilder['config']) { + super(table, config); + } - getSQLType(): string { - return "binary(16)" - } + getSQLType(): string { + return 'binary(16)'; + } - override mapToDriverValue(value: string) { - return sql`UNHEX(REPLACE(${value}, "-", ""))` - } + override mapToDriverValue(value: string) { + return sql`UNHEX(REPLACE(${value}, "-", ""))`; + } } export type SingleStoreGUIDStringBuilderInitial = SingleStoreGUIDStringBuilder<{ - name: TName; - dataType: "string"; - columnType: "SingleStoreGUIDString"; - data: string; - driverParam: string; - enumValues: undefined; - generated: undefined; -}> - -export class SingleStoreGUIDStringBuilder> extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = "SingleStoreGUIDStringBuilder" - - constructor(name: T["name"], config?: SingleStoreGUIDConfig) { - super(name, "string", "SingleStoreGUIDString") - } - - /** @internal */ - override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreGUIDString> { - return new SingleStoreGUIDString(table, this.config as ColumnBuilderRuntimeConfig); - } + name: TName; + dataType: 'string'; + columnType: 'SingleStoreGUIDString'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreGUIDStringBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreGUIDStringBuilder'; + + constructor(name: T['name'], config?: SingleStoreGUIDConfig) { + super(name, 'string', 'SingleStoreGUIDString'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreGUIDString> { + return new SingleStoreGUIDString(table, this.config as ColumnBuilderRuntimeConfig); + } } -export class SingleStoreGUIDString> extends SingleStoreColumn { - static readonly [entityKind]: string = "SingleStoreGUIDString" - - constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreGUIDStringBuilder["config"]) { - super(table, config) - } - - getSQLType(): string { - return "binary(16)" - } - - override mapToDriverValue(value: string) { - return sql`UNHEX(REPLACE(${value}, "-", ""))` - } - - override mapFromDriverValue(value: Uint8Array): string { - const hex = Buffer.from(value).toString("hex"); - return `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`; - } +export class SingleStoreGUIDString> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreGUIDString'; + + constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreGUIDStringBuilder['config']) { + super(table, config); + } + + getSQLType(): string { + return 'binary(16)'; + } + + override mapToDriverValue(value: string) { + return sql`UNHEX(REPLACE(${value}, "-", ""))`; + } + + override mapFromDriverValue(value: Uint8Array): string { + const hex = Buffer.from(value).toString('hex'); + return `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${ + hex.substring(20) + }`; + } } -export interface SingleStoreGUIDConfig { - mode?: TMode; +export interface SingleStoreGUIDConfig { + mode?: TMode; } /** * Creates a column with the data type `BINARY(16)` - * + * * Use config `{ mode: "string" }` for a string representation of the GUID */ -export function guid( - name: TName, - config?: SingleStoreGUIDConfig -): Equal extends true ? SingleStoreGUIDStringBuilderInitial : SingleStoreGUIDBuilderInitial; +export function guid( + name: TName, + config?: SingleStoreGUIDConfig, +): Equal extends true ? SingleStoreGUIDStringBuilderInitial + : SingleStoreGUIDBuilderInitial; export function guid(name: string, config?: SingleStoreGUIDConfig) { - if (config?.mode === "string") { - return new SingleStoreGUIDStringBuilder(name, config) - } - return new SingleStoreGUIDBuilder(name, config) -} \ No newline at end of file + if (config?.mode === 'string') { + return new SingleStoreGUIDStringBuilder(name, config); + } + return new SingleStoreGUIDBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/uuid.ts b/drizzle-orm/src/singlestore-core/columns/uuid.ts index 6886087b86..0179bba26b 100644 --- a/drizzle-orm/src/singlestore-core/columns/uuid.ts +++ b/drizzle-orm/src/singlestore-core/columns/uuid.ts @@ -1,45 +1,48 @@ -import { ColumnBaseConfig } from "~/column"; -import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from "~/column-builder"; -import { entityKind } from "~/entity"; -import { SingleStoreColumn, SingleStoreColumnBuilder } from "./common"; -import { AnySingleStoreTable } from "~/singlestore-core/table"; - +import { ColumnBaseConfig } from '~/column'; +import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import { entityKind } from '~/entity'; +import { AnySingleStoreTable } from '~/singlestore-core/table'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common'; export type SingleStoreUUIDBuilderInitial = SingleStoreUUIDBuilder<{ - name: TName; - dataType: "string"; - columnType: "SingleStoreUUID"; - data: string; - driverParam: string; - enumValues: undefined; - generated: undefined; -}> - -export class SingleStoreUUIDBuilder> extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = "SingleStoreUUIDBuilder" - - constructor(name: T["name"]) { - super(name, "string", "SingleStoreUUID") - } - - /** @internal */ - override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreUUID> { - return new SingleStoreUUID(table, this.config as ColumnBuilderRuntimeConfig); - } + name: TName; + dataType: 'string'; + columnType: 'SingleStoreUUID'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreUUIDBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreUUIDBuilder'; + + constructor(name: T['name']) { + super(name, 'string', 'SingleStoreUUID'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreUUID> { + return new SingleStoreUUID(table, this.config as ColumnBuilderRuntimeConfig); + } } -export class SingleStoreUUID> extends SingleStoreColumn { - static readonly [entityKind]: string = "SingleStoreUUID" +export class SingleStoreUUID> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreUUID'; - constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreUUIDBuilder["config"]) { - super(table, config) - } + constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreUUIDBuilder['config']) { + super(table, config); + } - getSQLType(): string { - return "varchar(36)" - } + getSQLType(): string { + return 'varchar(36)'; + } } export function uuid(name: TName): SingleStoreUUIDBuilderInitial { - return new SingleStoreUUIDBuilder(name) -} \ No newline at end of file + return new SingleStoreUUIDBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index ad1a09780a..988496a88e 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -1,67 +1,74 @@ -import { ColumnBaseConfig } from "~/column"; -import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from "~/column-builder"; -import { entityKind } from "~/entity"; -import { SingleStoreColumn, SingleStoreColumnBuilder } from "./common"; -import { AnySingleStoreTable } from "~/singlestore-core/table"; +import { ColumnBaseConfig } from '~/column'; +import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import { entityKind } from '~/entity'; +import { AnySingleStoreTable } from '~/singlestore-core/table'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common'; export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ - name: TName; - dataType: "array"; - columnType: "SingleStoreVector"; - data: Array; - driverParam: Array; - enumValues: undefined; - generated: undefined; -}> + name: TName; + dataType: 'array'; + columnType: 'SingleStoreVector'; + data: Array; + driverParam: Array; + enumValues: undefined; + generated: undefined; +}>; -export class SingleStoreVectorBuilder> extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = "SingleStoreVectorBuilder" +export class SingleStoreVectorBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreVectorBuilder'; - constructor(name: T["name"], config: SingleStoreVectorConfig) { - super(name, "array", "SingleStoreVector") - this.config.dimensions = config.dimensions - this.config.elementType = config.elementType - } + constructor(name: T['name'], config: SingleStoreVectorConfig) { + super(name, 'array', 'SingleStoreVector'); + this.config.dimensions = config.dimensions; + this.config.elementType = config.elementType; + } - /** @internal */ - override build(table: AnySingleStoreTable<{name: TTableName}>): SingleStoreVector> { - return new SingleStoreVector(table, this.config as ColumnBuilderRuntimeConfig); - } + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVector> { + return new SingleStoreVector(table, this.config as ColumnBuilderRuntimeConfig); + } } -export class SingleStoreVector> extends SingleStoreColumn { - static readonly [entityKind]: string = "SingleStoreVector" +export class SingleStoreVector> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreVector'; - readonly dimensions: number; - readonly elementType: ElementType | undefined; + readonly dimensions: number; + readonly elementType: ElementType | undefined; - constructor(table: AnySingleStoreTable<{name: T["tableName"]}>, config: SingleStoreVectorBuilder["config"]) { - super(table, config) - this.dimensions = config.dimensions - this.elementType = config.elementType - } + constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreVectorBuilder['config']) { + super(table, config); + this.dimensions = config.dimensions; + this.elementType = config.elementType; + } - getSQLType(): string { - const et = this.elementType === undefined ? "" : `, ${this.elementType}`; - return `vector(${this.dimensions}${et})` - } + getSQLType(): string { + const et = this.elementType === undefined ? '' : `, ${this.elementType}`; + return `vector(${this.dimensions}${et})`; + } - override mapToDriverValue(value: Array) { - return JSON.stringify(value) - } + override mapToDriverValue(value: Array) { + return JSON.stringify(value); + } - override mapFromDriverValue(value: string): Array { - return JSON.parse(value) - } + override mapFromDriverValue(value: string): Array { + return JSON.parse(value); + } } -type ElementType = "I8" | "I16" | "I32" | "I64" | "F32" | "F64"; +type ElementType = 'I8' | 'I16' | 'I32' | 'I64' | 'F32' | 'F64'; export interface SingleStoreVectorConfig { - dimensions: number; - elementType: ElementType; + dimensions: number; + elementType: ElementType; } -export function vector(name: TName, config: SingleStoreVectorConfig): SingleStoreVectorBuilderInitial { - return new SingleStoreVectorBuilder(name, config) -} \ No newline at end of file +export function vector( + name: TName, + config: SingleStoreVectorConfig, +): SingleStoreVectorBuilderInitial { + return new SingleStoreVectorBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts index aa77fbd480..5f70c5c5a1 100644 --- a/drizzle-orm/src/singlestore-core/expressions.ts +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -27,9 +27,9 @@ export function substring( // Vectors export function dotProduct(column: SingleStoreColumn | SQL.Aliased, value: Array) { - return sql`${column} <*> ${JSON.stringify(value)}` + return sql`${column} <*> ${JSON.stringify(value)}`; } export function euclideanDistance(column: SingleStoreColumn | SQL.Aliased, value: Array) { - return sql`${column} <-> ${JSON.stringify(value)}` + return sql`${column} <-> ${JSON.stringify(value)}`; } From f7068dc1714b3e9c30da2fb5cd410e9f6620f873 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Tue, 23 Jul 2024 20:26:17 +0100 Subject: [PATCH 013/152] nits --- .github/workflows/release-to-github.yaml | 19 +++++++++++++--- .../src/singlestore-core/columns/guid.ts | 22 +++++++++---------- .../src/singlestore-core/columns/uuid.ts | 10 ++++----- .../src/singlestore-core/columns/vector.ts | 10 ++++----- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/.github/workflows/release-to-github.yaml b/.github/workflows/release-to-github.yaml index 7e4419fec5..b0c71bf142 100644 --- a/.github/workflows/release-to-github.yaml +++ b/.github/workflows/release-to-github.yaml @@ -95,7 +95,7 @@ jobs: - name: Install dependencies run: pnpm install - - name: Build + - name: Generate prisma schemas run: | ( cd drizzle-orm @@ -107,9 +107,18 @@ jobs: pnpm prisma generate --schema tests/prisma/mysql/schema.prisma pnpm prisma generate --schema tests/prisma/sqlite/schema.prisma ) + + - name: Build + working-directory: ${{ matrix.package }} + run: | + jq '.name="@singlestore-labs/${{ matrix.package }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + # jq '.publishConfig.registry="https://npm.pkg.github.com/"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + jq 'del(.publishConfig.provenance)' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + pnpm build - name: Run tests + if: 0 env: PG_CONNECTION_STRING: postgres://postgres:postgres@localhost:55433/drizzle PG_VECTOR_CONNECTION_STRING: postgres://postgres:postgres@localhost:54321/drizzle @@ -137,6 +146,7 @@ jobs: npm run pack - name: Run @arethetypeswrong/cli + if: 0 working-directory: ${{ matrix.package }} shell: bash env: @@ -148,9 +158,12 @@ jobs: working-directory: ${{ matrix.package }} shell: bash env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - version="${{ steps.checks.outputs.version }}" + version=latest + + echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" > .npmrc + echo "@singlestore-labs:registry=https://npm.pkg.github.com" >> .npmrc echo "Publishing ${{ matrix.package }}@$version" npm run publish diff --git a/drizzle-orm/src/singlestore-core/columns/guid.ts b/drizzle-orm/src/singlestore-core/columns/guid.ts index 5f2cd175e0..855e63bc88 100644 --- a/drizzle-orm/src/singlestore-core/columns/guid.ts +++ b/drizzle-orm/src/singlestore-core/columns/guid.ts @@ -1,10 +1,10 @@ -import { ColumnBaseConfig } from '~/column'; -import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; -import { entityKind } from '~/entity'; -import { AnySingleStoreTable } from '~/singlestore-core/table'; -import { sql } from '~/sql/sql'; -import { Equal } from '~/utils'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import { sql } from '~/sql/sql.ts'; +import type { Equal } from '~/utils'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreGUIDBuilderInitial = SingleStoreGUIDBuilder<{ name: TName; @@ -21,7 +21,7 @@ export class SingleStoreGUIDBuilder = SingleStoreUUIDBuilder<{ name: TName; diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index 988496a88e..95c46976d0 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -1,8 +1,8 @@ -import { ColumnBaseConfig } from '~/column'; -import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; -import { entityKind } from '~/entity'; -import { AnySingleStoreTable } from '~/singlestore-core/table'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common'; +import type { ColumnBaseConfig } from '~/column'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ name: TName; From ab00e2a2c03648def65f935be02922b8aa8b0ee3 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Tue, 23 Jul 2024 22:55:14 +0100 Subject: [PATCH 014/152] add geographypoint type --- .../columns/geographypoint.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/columns/geographypoint.ts diff --git a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts new file mode 100644 index 0000000000..0edcc405c7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts @@ -0,0 +1,65 @@ +import type { ColumnBaseConfig } from '~/column'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import { sql } from '~/sql/sql.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +type GeographyPoint = [number, number]; + +export type SingleStoreGeographyPointBuilderInitial = SingleStoreGeographyPointBuilder<{ + name: TName; + dataType: 'array'; + columnType: 'SingleStoreGeographyPoint'; + data: GeographyPoint; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreGeographyPointBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreGeographyPointBuilder'; + + constructor(name: T['name']) { + super(name, 'array', 'SingleStoreGeographyPoint'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreGeographyPoint> { + return new SingleStoreGeographyPoint(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreGeographyPoint> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreGeographyPoint'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreGeographyPointBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return 'geographypoint'; + } + + override mapToDriverValue([lon, lat]: GeographyPoint) { + return sql`"POINT(${lon} ${lat})"`; + } + + override mapFromDriverValue(value: string): GeographyPoint { + const numbers = value.slice(value.indexOf('(') + 1, -1); + return numbers.split(' ').map(Number) as GeographyPoint; // driver value will look like `POINT(lon lat)` + } +} + +export function geographypoint(name: TName): SingleStoreGeographyPointBuilderInitial { + return new SingleStoreGeographyPointBuilder(name); +} From 0c14e0f17d3ef1ef70efcf6611a08434afd3b1b9 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Tue, 23 Jul 2024 23:34:54 +0100 Subject: [PATCH 015/152] Push to NPM instead --- ...ease-to-github.yaml => release-fork-to-npm.yaml} | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) rename .github/workflows/{release-to-github.yaml => release-fork-to-npm.yaml} (91%) diff --git a/.github/workflows/release-to-github.yaml b/.github/workflows/release-fork-to-npm.yaml similarity index 91% rename from .github/workflows/release-to-github.yaml rename to .github/workflows/release-fork-to-npm.yaml index b0c71bf142..90427b9021 100644 --- a/.github/workflows/release-to-github.yaml +++ b/.github/workflows/release-fork-to-npm.yaml @@ -1,4 +1,4 @@ -name: Release to GitHub +name: Release fork to NPM on: workflow_dispatch @@ -111,8 +111,8 @@ jobs: - name: Build working-directory: ${{ matrix.package }} run: | - jq '.name="@singlestore-labs/${{ matrix.package }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json - # jq '.publishConfig.registry="https://npm.pkg.github.com/"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + jq '.name="@drodrigues4/${{ matrix.package }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + jq '.version="0.32.1-${{ github.sha }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json jq 'del(.publishConfig.provenance)' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json pnpm build @@ -158,15 +158,14 @@ jobs: working-directory: ${{ matrix.package }} shell: bash env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} run: | version=latest - echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" > .npmrc - echo "@singlestore-labs:registry=https://npm.pkg.github.com" >> .npmrc + echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > .npmrc echo "Publishing ${{ matrix.package }}@$version" - npm run publish + npm publish package.tgz --access public echo "npm: \`+ ${{ matrix.package }}@$version\`" >> $GITHUB_STEP_SUMMARY From da0f7e49ac01f6d6814bc85107dce78095e41d25 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 01:02:08 +0100 Subject: [PATCH 016/152] Corrected version --- .github/workflows/release-fork-to-npm.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release-fork-to-npm.yaml b/.github/workflows/release-fork-to-npm.yaml index 90427b9021..60802b0974 100644 --- a/.github/workflows/release-fork-to-npm.yaml +++ b/.github/workflows/release-fork-to-npm.yaml @@ -2,6 +2,9 @@ name: Release fork to NPM on: workflow_dispatch +env: + VERSION: 0.32.1-${{ github.sha }} + jobs: release: permissions: write-all @@ -112,7 +115,7 @@ jobs: working-directory: ${{ matrix.package }} run: | jq '.name="@drodrigues4/${{ matrix.package }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json - jq '.version="0.32.1-${{ github.sha }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + jq '.version="$VERSION"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json jq 'del(.publishConfig.provenance)' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json pnpm build @@ -160,14 +163,12 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} run: | - version=latest - echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > .npmrc - echo "Publishing ${{ matrix.package }}@$version" + echo "Publishing ${{ matrix.package }}@$VERSION" npm publish package.tgz --access public - echo "npm: \`+ ${{ matrix.package }}@$version\`" >> $GITHUB_STEP_SUMMARY + echo "npm: \`+ ${{ matrix.package }}@$VERSION\`" >> $GITHUB_STEP_SUMMARY # Post release message to Discord # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} From 23aa8d20173dc9c9ce15eaca36fcae4392c1399d Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 10:44:13 +0100 Subject: [PATCH 017/152] Removed foreign keys --- .../src/singlestore-core/columns/common.ts | 36 ----- .../src/singlestore-core/foreign-keys.ts | 128 ------------------ 2 files changed, 164 deletions(-) delete mode 100644 drizzle-orm/src/singlestore-core/foreign-keys.ts diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index baa33abbdd..176265677b 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -13,21 +13,11 @@ import type { import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { ForeignKey, UpdateDeleteAction } from '~/singlestore-core/foreign-keys.ts'; -import { ForeignKeyBuilder } from '~/singlestore-core/foreign-keys.ts'; import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; -export interface ReferenceConfig { - ref: () => SingleStoreColumn; - actions: { - onUpdate?: UpdateDeleteAction; - onDelete?: UpdateDeleteAction; - }; -} - export interface SingleStoreColumnBuilderBase< T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, TTypeConfig extends object = object, @@ -49,13 +39,6 @@ export abstract class SingleStoreColumnBuilder< { static readonly [entityKind]: string = 'SingleStoreColumnBuilder'; - private foreignKeyConfigs: ReferenceConfig[] = []; - - references(ref: ReferenceConfig['ref'], actions: ReferenceConfig['actions'] = {}): this { - this.foreignKeyConfigs.push({ ref, actions }); - return this; - } - unique(name?: string): this { this.config.isUnique = true; this.config.uniqueName = name; @@ -71,25 +54,6 @@ export abstract class SingleStoreColumnBuilder< return this as any; } - /** @internal */ - buildForeignKeys(column: SingleStoreColumn, table: SingleStoreTable): ForeignKey[] { - return this.foreignKeyConfigs.map(({ ref, actions }) => { - return ((ref, actions) => { - const builder = new ForeignKeyBuilder(() => { - const foreignColumn = ref(); - return { columns: [column], foreignColumns: [foreignColumn] }; - }); - if (actions.onUpdate) { - builder.onUpdate(actions.onUpdate); - } - if (actions.onDelete) { - builder.onDelete(actions.onDelete); - } - return builder.build(table); - })(ref, actions); - }); - } - /** @internal */ abstract build( table: AnySingleStoreTable<{ name: TTableName }>, diff --git a/drizzle-orm/src/singlestore-core/foreign-keys.ts b/drizzle-orm/src/singlestore-core/foreign-keys.ts deleted file mode 100644 index fbebd684cb..0000000000 --- a/drizzle-orm/src/singlestore-core/foreign-keys.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; -import { SingleStoreTable } from './table.ts'; - -export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; - -export type Reference = () => { - readonly name?: string; - readonly columns: SingleStoreColumn[]; - readonly foreignTable: SingleStoreTable; - readonly foreignColumns: SingleStoreColumn[]; -}; - -export class ForeignKeyBuilder { - static readonly [entityKind]: string = 'SingleStoreForeignKeyBuilder'; - - /** @internal */ - reference: Reference; - - /** @internal */ - _onUpdate: UpdateDeleteAction | undefined; - - /** @internal */ - _onDelete: UpdateDeleteAction | undefined; - - constructor( - config: () => { - name?: string; - columns: SingleStoreColumn[]; - foreignColumns: SingleStoreColumn[]; - }, - actions?: { - onUpdate?: UpdateDeleteAction; - onDelete?: UpdateDeleteAction; - } | undefined, - ) { - this.reference = () => { - const { name, columns, foreignColumns } = config(); - return { name, columns, foreignTable: foreignColumns[0]!.table as SingleStoreTable, foreignColumns }; - }; - if (actions) { - this._onUpdate = actions.onUpdate; - this._onDelete = actions.onDelete; - } - } - - onUpdate(action: UpdateDeleteAction): this { - this._onUpdate = action; - return this; - } - - onDelete(action: UpdateDeleteAction): this { - this._onDelete = action; - return this; - } - - /** @internal */ - build(table: SingleStoreTable): ForeignKey { - return new ForeignKey(table, this); - } -} - -export type AnyForeignKeyBuilder = ForeignKeyBuilder; - -export class ForeignKey { - static readonly [entityKind]: string = 'SingleStoreForeignKey'; - - readonly reference: Reference; - readonly onUpdate: UpdateDeleteAction | undefined; - readonly onDelete: UpdateDeleteAction | undefined; - - constructor(readonly table: SingleStoreTable, builder: ForeignKeyBuilder) { - this.reference = builder.reference; - this.onUpdate = builder._onUpdate; - this.onDelete = builder._onDelete; - } - - getName(): string { - const { name, columns, foreignColumns } = this.reference(); - const columnNames = columns.map((column) => column.name); - const foreignColumnNames = foreignColumns.map((column) => column.name); - const chunks = [ - this.table[SingleStoreTable.Symbol.Name], - ...columnNames, - foreignColumns[0]!.table[SingleStoreTable.Symbol.Name], - ...foreignColumnNames, - ]; - return name ?? `${chunks.join('_')}_fk`; - } -} - -type ColumnsWithTable< - TTableName extends string, - TColumns extends SingleStoreColumn[], -> = { [Key in keyof TColumns]: AnySingleStoreColumn<{ tableName: TTableName }> }; - -export type GetColumnsTable = ( - TColumns extends SingleStoreColumn ? TColumns - : TColumns extends SingleStoreColumn[] ? TColumns[number] - : never -) extends AnySingleStoreColumn<{ tableName: infer TTableName extends string }> ? TTableName - : never; - -export function foreignKey< - TTableName extends string, - TForeignTableName extends string, - TColumns extends [ - AnySingleStoreColumn<{ tableName: TTableName }>, - ...AnySingleStoreColumn<{ tableName: TTableName }>[], - ], ->( - config: { - name?: string; - columns: TColumns; - foreignColumns: ColumnsWithTable; - }, -): ForeignKeyBuilder { - function mappedConfig() { - const { name, columns, foreignColumns } = config; - return { - name, - columns, - foreignColumns, - }; - } - - return new ForeignKeyBuilder(mappedConfig); -} From d4e4045dacb48f6c01ea238d5cf695e483453a15 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 11:10:55 +0100 Subject: [PATCH 018/152] Disallow INTERSECT ALL and EXCEPT ALL; Allow MINUS --- .../singlestore-core/query-builders/select.ts | 183 +++--------------- .../query-builders/select.types.ts | 3 +- 2 files changed, 33 insertions(+), 153 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts index 419aafca03..9b26edfb2d 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -494,48 +494,6 @@ export abstract class SingleStoreSelectQueryBuilderBase< */ intersect = this.createSetOperator('intersect', false); - /** - * Adds `intersect all` set operator to the query. - * - * Calling this method will retain only the rows that are present in both result sets including all duplicates. - * - * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect-all} - * - * @example - * - * ```ts - * // Select all products and quantities that are ordered by both regular and VIP customers - * await db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered - * }) - * .from(regularCustomerOrders) - * .intersectAll( - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered - * }) - * .from(vipCustomerOrders) - * ); - * // or - * import { intersectAll } from 'drizzle-orm/singlestore-core' - * - * await intersectAll( - * db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered - * }) - * .from(regularCustomerOrders), - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered - * }) - * .from(vipCustomerOrders) - * ); - * ``` - */ - intersectAll = this.createSetOperator('intersect', true); - /** * Adds `except` set operator to the query. * @@ -564,46 +522,29 @@ export abstract class SingleStoreSelectQueryBuilderBase< except = this.createSetOperator('except', false); /** - * Adds `except all` set operator to the query. - * - * Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query. - * - * See docs: {@link https://orm.drizzle.team/docs/set-operations#except-all} - * + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * * @example * * ```ts - * // Select all products that are ordered by regular customers but not by VIP customers - * await db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered, - * }) - * .from(regularCustomerOrders) - * .exceptAll( - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered, - * }) - * .from(vipCustomerOrders) - * ); + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); * // or - * import { exceptAll } from 'drizzle-orm/singlestore-core' - * - * await exceptAll( - * db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered - * }) - * .from(regularCustomerOrders), - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered - * }) - * .from(vipCustomerOrders) + * import { minus } from 'drizzle-orm/singlestore-core' + * + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) * ); * ``` */ - exceptAll = this.createSetOperator('except', true); + minus = this.createSetOperator('except', false); /** @internal */ addSetOperators(setOperators: SingleStoreSelectConfig['setOperators']): SingleStoreSelectWithout< @@ -1002,9 +943,8 @@ const getSingleStoreSetOperators = () => ({ union, unionAll, intersect, - intersectAll, except, - exceptAll, + minus, }); /** @@ -1088,48 +1028,6 @@ export const unionAll = createSetOperator('union', true); */ export const intersect = createSetOperator('intersect', false); -/** - * Adds `intersect all` set operator to the query. - * - * Calling this method will retain only the rows that are present in both result sets including all duplicates. - * - * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect-all} - * - * @example - * - * ```ts - * // Select all products and quantities that are ordered by both regular and VIP customers - * import { intersectAll } from 'drizzle-orm/singlestore-core' - * - * await intersectAll( - * db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered - * }) - * .from(regularCustomerOrders), - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered - * }) - * .from(vipCustomerOrders) - * ); - * // or - * await db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered - * }) - * .from(regularCustomerOrders) - * .intersectAll( - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered - * }) - * .from(vipCustomerOrders) - * ); - * ``` - */ -export const intersectAll = createSetOperator('intersect', true); - /** * Adds `except` set operator to the query. * @@ -1158,43 +1056,26 @@ export const intersectAll = createSetOperator('intersect', true); export const except = createSetOperator('except', false); /** - * Adds `except all` set operator to the query. - * - * Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query. - * - * See docs: {@link https://orm.drizzle.team/docs/set-operations#except-all} - * + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * * @example * * ```ts - * // Select all products that are ordered by regular customers but not by VIP customers - * import { exceptAll } from 'drizzle-orm/singlestore-core' + * // Select all courses offered in department A but not in department B + * import { minus } from 'drizzle-orm/singlestore-core' * - * await exceptAll( - * db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered - * }) - * .from(regularCustomerOrders), - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered - * }) - * .from(vipCustomerOrders) + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) * ); * // or - * await db.select({ - * productId: regularCustomerOrders.productId, - * quantityOrdered: regularCustomerOrders.quantityOrdered, - * }) - * .from(regularCustomerOrders) - * .exceptAll( - * db.select({ - * productId: vipCustomerOrders.productId, - * quantityOrdered: vipCustomerOrders.quantityOrdered, - * }) - * .from(vipCustomerOrders) - * ); + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); * ``` */ -export const exceptAll = createSetOperator('except', true); +export const minus = createSetOperator('except', true); diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts index 26f177634b..6db1cc3575 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -453,6 +453,5 @@ export type GetSingleStoreSetOperators = { intersect: SingleStoreCreateSetOperatorFn; except: SingleStoreCreateSetOperatorFn; unionAll: SingleStoreCreateSetOperatorFn; - intersectAll: SingleStoreCreateSetOperatorFn; - exceptAll: SingleStoreCreateSetOperatorFn; + minus: SingleStoreCreateSetOperatorFn; }; From 1ed0d8060716b43a16467af8326ed93c110bbb9f Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 11:13:43 +0100 Subject: [PATCH 019/152] Removed more stuff of foreign keys --- drizzle-orm/src/singlestore-core/index.ts | 1 - drizzle-orm/src/singlestore-core/table.ts | 10 ---------- drizzle-orm/src/singlestore-core/utils.ts | 6 ------ 3 files changed, 17 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts index 204e0af3c4..20e3c3b299 100644 --- a/drizzle-orm/src/singlestore-core/index.ts +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -3,7 +3,6 @@ export * from './checks.ts'; export * from './columns/index.ts'; export * from './db.ts'; export * from './dialect.ts'; -export * from './foreign-keys.ts'; export * from './indexes.ts'; export * from './primary-keys.ts'; export * from './query-builders/index.ts'; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 040e3981fb..16db288e93 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -3,7 +3,6 @@ import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { CheckBuilder } from './checks.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; -import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; @@ -12,16 +11,12 @@ export type SingleStoreTableExtraConfig = Record< string, | AnyIndexBuilder | CheckBuilder - | ForeignKeyBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; export type TableConfig = TableConfigBase; -/** @internal */ -export const InlineForeignKeys = Symbol.for('drizzle:SingleStoreInlineForeignKeys'); - export class SingleStoreTable extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; @@ -29,15 +24,11 @@ export class SingleStoreTable extends Table /** @internal */ static override readonly Symbol = Object.assign({}, Table.Symbol, { - InlineForeignKeys: InlineForeignKeys as typeof InlineForeignKeys, }); /** @internal */ override [Table.Symbol.Columns]!: NonNullable; - /** @internal */ - [InlineForeignKeys]: ForeignKey[] = []; - /** @internal */ override [Table.Symbol.ExtraConfigBuilder]: | ((self: Record) => SingleStoreTableExtraConfig) @@ -83,7 +74,6 @@ export function singlestoreTableWithSchema< Object.entries(columns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as SingleStoreColumnBuilder; const column = colBuilder.build(rawTable); - rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable)); return [name, column]; }), ) as unknown as BuildColumns; diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts index e90c5ae404..00e464f302 100644 --- a/drizzle-orm/src/singlestore-core/utils.ts +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -3,8 +3,6 @@ import { Table } from '~/table.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { Check } from './checks.ts'; import { CheckBuilder } from './checks.ts'; -import type { ForeignKey } from './foreign-keys.ts'; -import { ForeignKeyBuilder } from './foreign-keys.ts'; import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; import type { PrimaryKey } from './primary-keys.ts'; @@ -20,7 +18,6 @@ export function getTableConfig(table: SingleStoreTable) { const checks: Check[] = []; const primaryKeys: PrimaryKey[] = []; const uniqueConstraints: UniqueConstraint[] = []; - const foreignKeys: ForeignKey[] = Object.values(table[SingleStoreTable.Symbol.InlineForeignKeys]); const name = table[Table.Symbol.Name]; const schema = table[Table.Symbol.Schema]; const baseName = table[Table.Symbol.BaseName]; @@ -38,8 +35,6 @@ export function getTableConfig(table: SingleStoreTable) { uniqueConstraints.push(builder.build(table)); } else if (is(builder, PrimaryKeyBuilder)) { primaryKeys.push(builder.build(table)); - } else if (is(builder, ForeignKeyBuilder)) { - foreignKeys.push(builder.build(table)); } } } @@ -47,7 +42,6 @@ export function getTableConfig(table: SingleStoreTable) { return { columns, indexes, - foreignKeys, checks, primaryKeys, uniqueConstraints, From 2903d1afdae900436518afb4e60feb37a613da1b Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 11:17:21 +0100 Subject: [PATCH 020/152] Build fork when pushing to main --- .github/workflows/release-fork-to-npm.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-fork-to-npm.yaml b/.github/workflows/release-fork-to-npm.yaml index 60802b0974..f2b842e40f 100644 --- a/.github/workflows/release-fork-to-npm.yaml +++ b/.github/workflows/release-fork-to-npm.yaml @@ -1,6 +1,10 @@ name: Release fork to NPM -on: workflow_dispatch +on: + push: + branches: + - main + workflow_dispatch: env: VERSION: 0.32.1-${{ github.sha }} From 2df9688ac6aebc1790a9d62fe82e1ea997dd208b Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 11:23:05 +0100 Subject: [PATCH 021/152] Changed name of version var --- .github/workflows/release-fork-to-npm.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-fork-to-npm.yaml b/.github/workflows/release-fork-to-npm.yaml index f2b842e40f..018aa8e24e 100644 --- a/.github/workflows/release-fork-to-npm.yaml +++ b/.github/workflows/release-fork-to-npm.yaml @@ -7,7 +7,7 @@ on: workflow_dispatch: env: - VERSION: 0.32.1-${{ github.sha }} + PACKAGE_VERSION: 0.32.1-${{ github.sha }} jobs: release: @@ -119,7 +119,7 @@ jobs: working-directory: ${{ matrix.package }} run: | jq '.name="@drodrigues4/${{ matrix.package }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json - jq '.version="$VERSION"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + jq '.version="$PACKAGE_VERSION"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json jq 'del(.publishConfig.provenance)' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json pnpm build @@ -169,10 +169,10 @@ jobs: run: | echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > .npmrc - echo "Publishing ${{ matrix.package }}@$VERSION" + echo "Publishing ${{ matrix.package }}@$PACKAGE_VERSION" npm publish package.tgz --access public - echo "npm: \`+ ${{ matrix.package }}@$VERSION\`" >> $GITHUB_STEP_SUMMARY + echo "npm: \`+ ${{ matrix.package }}@$PACKAGE_VERSION\`" >> $GITHUB_STEP_SUMMARY # Post release message to Discord # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} From 4b186e6743592a3abdc2907a725dfded0dda2c0c Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 11:30:26 +0100 Subject: [PATCH 022/152] fixed action --- .github/workflows/release-fork-to-npm.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-fork-to-npm.yaml b/.github/workflows/release-fork-to-npm.yaml index 018aa8e24e..376a19826a 100644 --- a/.github/workflows/release-fork-to-npm.yaml +++ b/.github/workflows/release-fork-to-npm.yaml @@ -119,7 +119,7 @@ jobs: working-directory: ${{ matrix.package }} run: | jq '.name="@drodrigues4/${{ matrix.package }}"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json - jq '.version="$PACKAGE_VERSION"' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json + jq --arg version "$PACKAGE_VERSION" '.version=$version' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json jq 'del(.publishConfig.provenance)' package.json --tab > tmp.$$.json && mv tmp.$$.json package.json pnpm build From b42d3cb7b7e6fa10e274e6f31d2ff61e168dd48c Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 12:00:17 +0100 Subject: [PATCH 023/152] Added detach --- drizzle-orm/src/singlestore-core/db.ts | 7 + drizzle-orm/src/singlestore-core/dialect.ts | 7 + .../singlestore-core/query-builders/detach.ts | 145 ++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/query-builders/detach.ts diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 7157bc6f4f..d322e8950f 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -27,6 +27,7 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; +import { SingleStoreDetachBase } from './query-builders/detach.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, @@ -473,6 +474,12 @@ export class SingleStoreDatabase< ): Promise { return this.session.transaction(transaction, config); } + + detach( + db: TDatabase, + ): SingleStoreDetachBase { + return new SingleStoreDetachBase(db, this.session, this.dialect); + } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index d72424c8e6..68a5227bca 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -34,6 +34,7 @@ import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; +import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -1078,4 +1079,10 @@ export class SingleStoreDialect { selection, }; } + + buildDetachQuery({ database, milestone }: SingleStoreDetachConfig): SQL { + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + + return sql`detach database ${database}${milestoneSql}`; + } } diff --git a/drizzle-orm/src/singlestore-core/query-builders/detach.ts b/drizzle-orm/src/singlestore-core/query-builders/detach.ts new file mode 100644 index 0000000000..f3a2308557 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/detach.ts @@ -0,0 +1,145 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreDetach< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDetachBase; + +export interface SingleStoreDetachConfig { + database: string; + milestone?: string | undefined; +} + +export type SingleStoreDetachPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDetachDynamic = SingleStoreDetach< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDetachBase = SingleStoreDetachBase; + +export interface SingleStoreDetachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDetachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreDetach'; + + private config: SingleStoreDetachConfig; + + constructor( + private database: TDatabase, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Delete all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Delete all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Delete all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // atMilestone(milestone: string | undefined): SingleStoreDetach { + // this.config.milestone = milestone; + // return this as any; + // } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDetachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDetachPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreDetachPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDetachDynamic { + return this as any; + } +} From da7e81fec8229dd8a12e6f6feeb130d6378bff25 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 12:43:31 +0100 Subject: [PATCH 024/152] Renamed driver --- drizzle-orm/src/singlestore-core/db.ts | 12 ++-- drizzle-orm/src/singlestore/driver.ts | 48 +++++++------- drizzle-orm/src/singlestore/migrator.ts | 4 +- drizzle-orm/src/singlestore/session.ts | 88 ++++++++++++------------- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index d322e8950f..8047122d90 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -27,7 +27,7 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; -import { SingleStoreDetachBase } from './query-builders/detach.ts'; +// import { SingleStoreDetachBase } from './query-builders/detach.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, @@ -475,11 +475,11 @@ export class SingleStoreDatabase< return this.session.transaction(transaction, config); } - detach( - db: TDatabase, - ): SingleStoreDetachBase { - return new SingleStoreDetachBase(db, this.session, this.dialect); - } + // detach( + // db: TDatabase, + // ): SingleStoreDetachBase { + // return new SingleStoreDetachBase(db, this.session, this.dialect); + // } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts index 3b21bf11dd..dca2cabb90 100644 --- a/drizzle-orm/src/singlestore/driver.ts +++ b/drizzle-orm/src/singlestore/driver.ts @@ -2,9 +2,9 @@ import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mys import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MySqlDatabase } from '~/mysql-core/db.ts'; -import { MySqlDialect } from '~/mysql-core/dialect.ts'; -import type { Mode } from '~/mysql-core/session.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { Mode } from '~/singlestore-core/session.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, @@ -13,46 +13,46 @@ import { } from '~/relations.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { DrizzleError } from '../index.ts'; -import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; -import { MySql2Session } from './session.ts'; +import type { SingleStore2Client, SingleStore2PreparedQueryHKT, SingleStore2QueryResultHKT } from './session.ts'; +import { SingleStore2Session } from './session.ts'; -export interface MySqlDriverOptions { +export interface SingleStoreDriverOptions { logger?: Logger; } -export class MySql2Driver { - static readonly [entityKind]: string = 'MySql2Driver'; +export class SingleStore2Driver { + static readonly [entityKind]: string = 'SingleStore2Driver'; constructor( - private client: MySql2Client, - private dialect: MySqlDialect, - private options: MySqlDriverOptions = {}, + private client: SingleStore2Client, + private dialect: SingleStoreDialect, + private options: SingleStoreDriverOptions = {}, ) { } createSession( schema: RelationalSchemaConfig | undefined, mode: Mode, - ): MySql2Session, TablesRelationalConfig> { - return new MySql2Session(this.client, this.dialect, schema, { logger: this.options.logger, mode }); + ): SingleStore2Session, TablesRelationalConfig> { + return new SingleStore2Session(this.client, this.dialect, schema, { logger: this.options.logger, mode }); } } -export { MySqlDatabase } from '~/mysql-core/db.ts'; +export { SingleStoreDatabase } from '~/singlestore-core/db.ts'; -export type MySql2Database< +export type SingleStore2Database< TSchema extends Record = Record, -> = MySqlDatabase; +> = SingleStoreDatabase; -export type MySql2DrizzleConfig = Record> = +export type SingleStore2DrizzleConfig = Record> = & Omit, 'schema'> & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); export function drizzle = Record>( - client: MySql2Client | CallbackConnection | CallbackPool, - config: MySql2DrizzleConfig = {}, -): MySql2Database { - const dialect = new MySqlDialect(); + client: SingleStore2Client | CallbackConnection | CallbackPool, + config: SingleStore2DrizzleConfig = {}, +): SingleStore2Database { + const dialect = new SingleStoreDialect(); let logger; if (config.logger === true) { logger = new DefaultLogger(); @@ -85,13 +85,13 @@ export function drizzle = Record; + return new SingleStoreDatabase(dialect, session, schema, mode) as SingleStore2Database; } interface CallbackClient { - promise(): MySql2Client; + promise(): SingleStore2Client; } function isCallbackClient(client: any): client is CallbackClient { diff --git a/drizzle-orm/src/singlestore/migrator.ts b/drizzle-orm/src/singlestore/migrator.ts index 2f3c9c3dcf..600b4dd106 100644 --- a/drizzle-orm/src/singlestore/migrator.ts +++ b/drizzle-orm/src/singlestore/migrator.ts @@ -1,9 +1,9 @@ import type { MigrationConfig } from '~/migrator.ts'; import { readMigrationFiles } from '~/migrator.ts'; -import type { MySql2Database } from './driver.ts'; +import type { SingleStore2Database } from './driver.ts'; export async function migrate>( - db: MySql2Database, + db: SingleStore2Database, config: MigrationConfig, ) { const migrations = readMigrationFiles(config); diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts index ab11d1f175..267610d9db 100644 --- a/drizzle-orm/src/singlestore/session.ts +++ b/drizzle-orm/src/singlestore/session.ts @@ -14,40 +14,40 @@ import { Column } from '~/column.ts'; import { entityKind, is } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; -import type { MySqlDialect } from '~/mysql-core/dialect.ts'; -import type { SelectedFieldsOrdered } from '~/mysql-core/query-builders/select.types.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; import { type Mode, - MySqlPreparedQuery, - type MySqlPreparedQueryConfig, - type MySqlPreparedQueryHKT, - type MySqlQueryResultHKT, - MySqlSession, - MySqlTransaction, - type MySqlTransactionConfig, + SingleStorePreparedQuery, + type SingleStorePreparedQueryConfig, + type SingleStorePreparedQueryHKT, + type SingleStoreQueryResultHKT, + SingleStoreSession, + SingleStoreTransaction, + type SingleStoreTransactionConfig, type PreparedQueryKind, -} from '~/mysql-core/session.ts'; +} from '~/singlestore-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { fillPlaceholders, sql } from '~/sql/sql.ts'; import type { Query, SQL } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; -export type MySql2Client = Pool | Connection; +export type SingleStore2Client = Pool | Connection; -export type MySqlRawQueryResult = [ResultSetHeader, FieldPacket[]]; -export type MySqlQueryResultType = RowDataPacket[][] | RowDataPacket[] | OkPacket | OkPacket[] | ResultSetHeader; -export type MySqlQueryResult< +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; +export type SingleStoreQueryResultType = RowDataPacket[][] | RowDataPacket[] | OkPacket | OkPacket[] | ResultSetHeader; +export type SingleStoreQueryResult< T = any, > = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; -export class MySql2PreparedQuery extends MySqlPreparedQuery { - static readonly [entityKind]: string = 'MySql2PreparedQuery'; +export class SingleStore2PreparedQuery extends SingleStorePreparedQuery { + static readonly [entityKind]: string = 'SingleStore2PreparedQuery'; private rawQuery: QueryOptions; private query: QueryOptions; constructor( - private client: MySql2Client, + private client: SingleStore2Client, queryString: string, private params: unknown[], private logger: Logger, @@ -181,41 +181,41 @@ export class MySql2PreparedQuery extends MyS } } -export interface MySql2SessionOptions { +export interface SingleStore2SessionOptions { logger?: Logger; mode: Mode; } -export class MySql2Session< +export class SingleStore2Session< TFullSchema extends Record, TSchema extends TablesRelationalConfig, -> extends MySqlSession { - static readonly [entityKind]: string = 'MySql2Session'; +> extends SingleStoreSession { + static readonly [entityKind]: string = 'SingleStore2Session'; private logger: Logger; private mode: Mode; constructor( - private client: MySql2Client, - dialect: MySqlDialect, + private client: SingleStore2Client, + dialect: SingleStoreDialect, private schema: RelationalSchemaConfig | undefined, - private options: MySql2SessionOptions, + private options: SingleStore2SessionOptions, ) { super(dialect); this.logger = options.logger ?? new NoopLogger(); this.mode = options.mode; } - prepareQuery( + prepareQuery( query: Query, fields: SelectedFieldsOrdered | undefined, customResultMapper?: (rows: unknown[][]) => T['execute'], generatedIds?: Record[], returningIds?: SelectedFieldsOrdered, - ): PreparedQueryKind { + ): PreparedQueryKind { // Add returningId fields // Each driver gets them from response from database - return new MySql2PreparedQuery( + return new SingleStore2PreparedQuery( this.client, query.sql, query.params, @@ -224,14 +224,14 @@ export class MySql2Session< customResultMapper, generatedIds, returningIds, - ) as PreparedQueryKind; + ) as PreparedQueryKind; } /** * @internal * What is its purpose? */ - async query(query: string, params: unknown[]): Promise { + async query(query: string, params: unknown[]): Promise { this.logger.logQuery(query, params); const result = await this.client.query({ sql: query, @@ -254,20 +254,20 @@ export class MySql2Session< } override async transaction( - transaction: (tx: MySql2Transaction) => Promise, - config?: MySqlTransactionConfig, + transaction: (tx: SingleStore2Transaction) => Promise, + config?: SingleStoreTransactionConfig, ): Promise { const session = isPool(this.client) - ? new MySql2Session( + ? new SingleStore2Session( await this.client.getConnection(), this.dialect, this.schema, this.options, ) : this; - const tx = new MySql2Transaction( + const tx = new SingleStore2Transaction( this.dialect, - session as MySqlSession, + session as SingleStoreSession, this.schema, 0, this.mode, @@ -297,15 +297,15 @@ export class MySql2Session< } } -export class MySql2Transaction< +export class SingleStore2Transaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, -> extends MySqlTransaction { - static readonly [entityKind]: string = 'MySql2Transaction'; +> extends SingleStoreTransaction { + static readonly [entityKind]: string = 'SingleStore2Transaction'; - override async transaction(transaction: (tx: MySql2Transaction) => Promise): Promise { + override async transaction(transaction: (tx: SingleStore2Transaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; - const tx = new MySql2Transaction( + const tx = new SingleStore2Transaction( this.dialect, this.session, this.schema, @@ -324,14 +324,14 @@ export class MySql2Transaction< } } -function isPool(client: MySql2Client): client is Pool { +function isPool(client: SingleStore2Client): client is Pool { return 'getConnection' in client; } -export interface MySql2QueryResultHKT extends MySqlQueryResultHKT { - type: MySqlRawQueryResult; +export interface SingleStore2QueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; } -export interface MySql2PreparedQueryHKT extends MySqlPreparedQueryHKT { - type: MySql2PreparedQuery>; +export interface SingleStore2PreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: SingleStore2PreparedQuery>; } From f662fb4ebd04c85aa3e7729c0ff79e8b1662191a Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 13:11:19 +0100 Subject: [PATCH 025/152] Fixed detach --- drizzle-orm/src/singlestore-core/db.ts | 12 ++--- drizzle-orm/src/singlestore-core/dialect.ts | 14 +++--- .../singlestore-core/query-builders/detach.ts | 46 +++++++++++++++---- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 8047122d90..652670ab4f 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -27,7 +27,7 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; -// import { SingleStoreDetachBase } from './query-builders/detach.ts'; +import { SingleStoreDetachBase } from './query-builders/detach.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, @@ -475,11 +475,11 @@ export class SingleStoreDatabase< return this.session.transaction(transaction, config); } - // detach( - // db: TDatabase, - // ): SingleStoreDetachBase { - // return new SingleStoreDetachBase(db, this.session, this.dialect); - // } + detach( + database: TDatabase, + ): SingleStoreDetachBase { + return new SingleStoreDetachBase(database, this.session, this.dialect); + } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 68a5227bca..7309e78c33 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -117,6 +117,14 @@ export class SingleStoreDialect { return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; } + buildDetachQuery({ database, milestone, workspace }: SingleStoreDetachConfig): SQL { + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + + const workspaceSql = workspace ? sql` from workspace ${workspace}` : undefined; + + return sql`detach database ${database}${milestoneSql}${workspaceSql}`; + } + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { const tableColumns = table[Table.Symbol.Columns]; @@ -1079,10 +1087,4 @@ export class SingleStoreDialect { selection, }; } - - buildDetachQuery({ database, milestone }: SingleStoreDetachConfig): SQL { - const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; - - return sql`detach database ${database}${milestoneSql}`; - } } diff --git a/drizzle-orm/src/singlestore-core/query-builders/detach.ts b/drizzle-orm/src/singlestore-core/query-builders/detach.ts index f3a2308557..8420bd9902 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/detach.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/detach.ts @@ -12,15 +12,32 @@ import type { } from '~/singlestore-core/session.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +export type SingleStoreDetachWithout< + T extends AnySingleStoreDetachBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDetachBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + export type SingleStoreDetach< TDatabase extends string = string, TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = SingleStoreDetachBase; +> = SingleStoreDetachBase; export interface SingleStoreDetachConfig { - database: string; milestone?: string | undefined; + database: string; + workspace?: string | undefined; } export type SingleStoreDetachPrepare = PreparedQueryKind< @@ -38,18 +55,20 @@ type SingleStoreDetachDynamic = SingleStoreD T['_']['preparedQueryHKT'] >; -type AnySingleStoreDetachBase = SingleStoreDetachBase; +type AnySingleStoreDetachBase = SingleStoreDetachBase; export interface SingleStoreDetachBase< TDatabase extends string, TQueryResult extends SingleStoreQueryResultHKT, TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, TExcludedMethods extends string = never, > extends QueryPromise> { readonly _: { readonly database: TDatabase; readonly queryResult: TQueryResult; readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; readonly excludedMethods: TExcludedMethods; }; } @@ -59,6 +78,7 @@ export class SingleStoreDetachBase< TQueryResult extends SingleStoreQueryResultHKT, // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { @@ -88,7 +108,7 @@ export class SingleStoreDetachBase< * You can use conditional operators and `sql function` to filter the rows to be deleted. * * ```ts - * // Delete all cars with green color + * // Detach all cars with green color * db.delete(cars).where(eq(cars.color, 'green')); * // or * db.delete(cars).where(sql`${cars.color} = 'green'`) @@ -97,17 +117,23 @@ export class SingleStoreDetachBase< * You can logically combine conditional operators with `and()` and `or()` operators: * * ```ts - * // Delete all BMW cars with a green color + * // Detach all BMW cars with a green color * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); * - * // Delete all cars with the green or blue color + * // Detach all cars with the green or blue color * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); * ``` */ - // atMilestone(milestone: string | undefined): SingleStoreDetach { - // this.config.milestone = milestone; - // return this as any; - // } + atMilestone(milestone: string | undefined): SingleStoreDetachWithout { + this.config.milestone = milestone; + return this as any; + } + + // TODO: docs + fromWorkspace(workspace: string | undefined): SingleStoreDetachWithout { + this.config.workspace = workspace; + return this as any; + } /** @internal */ getSQL(): SQL { From 4a15249066e53ec6da8babaa6f5e202c074d3418 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 14:40:53 +0100 Subject: [PATCH 026/152] Added attach --- drizzle-orm/src/singlestore-core/db.ts | 7 + drizzle-orm/src/singlestore-core/dialect.ts | 7 + .../singlestore-core/query-builders/attach.ts | 164 ++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/query-builders/attach.ts diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 652670ab4f..76adbb32a5 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -28,6 +28,7 @@ import type { import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; import { SingleStoreDetachBase } from './query-builders/detach.ts'; +import { SingleStoreAttachBase } from './query-builders/attach.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, @@ -480,6 +481,12 @@ export class SingleStoreDatabase< ): SingleStoreDetachBase { return new SingleStoreDetachBase(database, this.session, this.dialect); } + + attach( + database: TDatabase, + ): SingleStoreAttachBase { + return new SingleStoreAttachBase(database, this.session, this.dialect); + } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 7309e78c33..c9bfda5f21 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -35,6 +35,7 @@ import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; +import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -125,6 +126,12 @@ export class SingleStoreDialect { return sql`detach database ${database}${milestoneSql}${workspaceSql}`; } + buildAttachQuery({ database, milestone }: SingleStoreAttachConfig): SQL { + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + + return sql`attach database ${database}${milestoneSql}`; + } + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { const tableColumns = table[Table.Symbol.Columns]; diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts new file mode 100644 index 0000000000..cd26a73b66 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/attach.ts @@ -0,0 +1,164 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreAttachWithout< + T extends AnySingleStoreAttachBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreAttachBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreAttach< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreAttachBase; + +export interface SingleStoreAttachConfig { + milestone?: string | undefined; + database: string; +} + +export type SingleStoreAttachPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreAttachDynamic = SingleStoreAttach< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreAttachBase = SingleStoreAttachBase; + +export interface SingleStoreAttachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreAttachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreAttach'; + + private config: SingleStoreAttachConfig; + + constructor( + private database: TDatabase, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Attach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Attach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Attach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + atMilestone(milestone: string | undefined): SingleStoreAttachWithout { + this.config.milestone = milestone; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildAttachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreAttachPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreAttachPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreAttachDynamic { + return this as any; + } +} From b9dccbe5d56c5665bbe0341799ec28cc11baaaa4 Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Wed, 24 Jul 2024 14:57:12 +0100 Subject: [PATCH 027/152] Differentiate rowstore and columnstore on creation and block btree indexes on columnstore --- drizzle-orm/src/singlestore-core/indexes.ts | 14 ++++- drizzle-orm/src/singlestore-core/schema.ts | 4 +- drizzle-orm/src/singlestore-core/table.ts | 61 +++++++++++++++++---- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 59d2bfb11f..013ec816de 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -1,9 +1,9 @@ import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; -import type { SingleStoreTable } from './table.ts'; +import type { SingleStoreColumnstoreTable, SingleStoreRowstoreTable, SingleStoreTable } from './table.ts'; -interface IndexConfig { +interface IndexCommonConfig { name: string; columns: IndexColumn[]; @@ -29,6 +29,12 @@ interface IndexConfig { lock?: 'default' | 'none' | 'shared' | 'exclusive'; } +type IndexColumnstoreConfig = IndexCommonConfig & { + using?: 'hash'; +}; +type IndexRowstoreConfig = IndexCommonConfig; +type IndexConfig = IndexColumnstoreConfig | IndexRowstoreConfig; + export type IndexColumn = SingleStoreColumn | SQL; export class IndexBuilderOn { @@ -86,7 +92,9 @@ export class IndexBuilder implements AnyIndexBuilder { export class Index { static readonly [entityKind]: string = 'SingleStoreIndex'; - readonly config: IndexConfig & { table: SingleStoreTable }; + readonly config: + | (IndexColumnstoreConfig & { table: SingleStoreColumnstoreTable }) + | (IndexRowstoreConfig & { table: SingleStoreRowstoreTable }); constructor(config: IndexConfig, table: SingleStoreTable) { this.config = { ...config, table }; diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index 82da44a49e..2a278e4e0e 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,5 +1,5 @@ import { entityKind, is } from '~/entity.ts'; -import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; +import { type SingleStoreTableFn, SinglestoreTableType, singlestoreTableWithSchema } from './table.ts'; import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; export class SingleStoreSchema { @@ -10,7 +10,7 @@ export class SingleStoreSchema { ) {} table: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); + return singlestoreTableWithSchema(SinglestoreTableType.columnstore, name, columns, extraConfig, this.schemaName); }; view = ((name, columns) => { diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 16db288e93..4c40cd5b96 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -17,14 +17,13 @@ export type SingleStoreTableExtraConfig = Record< export type TableConfig = TableConfigBase; -export class SingleStoreTable extends Table { +export abstract class SingleStoreTable extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; declare protected $columns: T['columns']; /** @internal */ - static override readonly Symbol = Object.assign({}, Table.Symbol, { - }); + static override readonly Symbol = Object.assign({}, Table.Symbol, {}); /** @internal */ override [Table.Symbol.Columns]!: NonNullable; @@ -35,6 +34,14 @@ export class SingleStoreTable extends Table | undefined = undefined; } +export class SingleStoreRowstoreTable extends SingleStoreTable { + static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; +} + +export class SingleStoreColumnstoreTable extends SingleStoreTable { + static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; +} + export type AnySingleStoreTable = {}> = SingleStoreTable< UpdateTableConfig >; @@ -45,11 +52,17 @@ export type SingleStoreTableWithColumns = [Key in keyof T['columns']]: T['columns'][Key]; }; +export enum SinglestoreTableType { + rowstore, + columnstore, +} + export function singlestoreTableWithSchema< TTableName extends string, TSchemaName extends string | undefined, TColumnsMap extends Record, >( + type: SinglestoreTableType, name: TTableName, columns: TColumnsMap, extraConfig: @@ -63,12 +76,27 @@ export function singlestoreTableWithSchema< columns: BuildColumns; dialect: 'singlestore'; }> { - const rawTable = new SingleStoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); + let rawTable; + switch (type) { + case SinglestoreTableType.columnstore: { + rawTable = new SingleStoreColumnstoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + break; + } + case SinglestoreTableType.rowstore: { + rawTable = new SingleStoreRowstoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + break; + } + } const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { @@ -113,11 +141,22 @@ export interface SingleStoreTableFn { - return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); + return singlestoreTableWithSchema(SinglestoreTableType.columnstore, name, columns, extraConfig, undefined, name); +}; + +export const singlestoreRowstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(SinglestoreTableType.rowstore, name, columns, extraConfig, undefined, name); }; export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { return (name, columns, extraConfig) => { - return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + return singlestoreTableWithSchema( + SinglestoreTableType.columnstore, + customizeTableName(name) as typeof name, + columns, + extraConfig, + undefined, + name, + ); }; } From 00ee412ddbff4e2e7669dc67ac963f3dcda7f44e Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Wed, 24 Jul 2024 14:58:04 +0100 Subject: [PATCH 028/152] Formatted files --- drizzle-orm/src/singlestore-core/db.ts | 4 ++-- drizzle-orm/src/singlestore-core/dialect.ts | 4 ++-- drizzle-orm/src/singlestore-core/query-builders/select.ts | 8 ++++---- drizzle-orm/src/singlestore/driver.ts | 6 +++--- drizzle-orm/src/singlestore/session.ts | 8 +++++--- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 76adbb32a5..e8b7963634 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -7,6 +7,8 @@ import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { SingleStoreDialect } from './dialect.ts'; +import { SingleStoreAttachBase } from './query-builders/attach.ts'; +import { SingleStoreDetachBase } from './query-builders/detach.ts'; import { QueryBuilder, SingleStoreDeleteBase, @@ -27,8 +29,6 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; -import { SingleStoreDetachBase } from './query-builders/detach.ts'; -import { SingleStoreAttachBase } from './query-builders/attach.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index c9bfda5f21..2363d6db35 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -23,7 +23,9 @@ import { getTableName, getTableUniqueName, Table } from '~/table.ts'; import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import { SingleStoreColumn } from './columns/common.ts'; +import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; +import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; import type { SelectedFieldsOrdered, @@ -34,8 +36,6 @@ import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; -import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; -import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts index 9b26edfb2d..78cba92e05 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -523,9 +523,9 @@ export abstract class SingleStoreSelectQueryBuilderBase< /** * Adds `minus` set operator to the query. - * + * * This is an alias of `except` supported by SingleStore. - * + * * @example * * ```ts @@ -1057,9 +1057,9 @@ export const except = createSetOperator('except', false); /** * Adds `minus` set operator to the query. - * + * * This is an alias of `except` supported by SingleStore. - * + * * @example * * ```ts diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts index dca2cabb90..0cda875937 100644 --- a/drizzle-orm/src/singlestore/driver.ts +++ b/drizzle-orm/src/singlestore/driver.ts @@ -2,15 +2,15 @@ import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mys import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; -import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { Mode } from '~/singlestore-core/session.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { Mode } from '~/singlestore-core/session.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { DrizzleError } from '../index.ts'; import type { SingleStore2Client, SingleStore2PreparedQueryHKT, SingleStore2QueryResultHKT } from './session.ts'; diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts index 267610d9db..7a4be52576 100644 --- a/drizzle-orm/src/singlestore/session.ts +++ b/drizzle-orm/src/singlestore/session.ts @@ -14,10 +14,12 @@ import { Column } from '~/column.ts'; import { entityKind, is } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; import { type Mode, + type PreparedQueryKind, SingleStorePreparedQuery, type SingleStorePreparedQueryConfig, type SingleStorePreparedQueryHKT, @@ -25,9 +27,7 @@ import { SingleStoreSession, SingleStoreTransaction, type SingleStoreTransactionConfig, - type PreparedQueryKind, } from '~/singlestore-core/session.ts'; -import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { fillPlaceholders, sql } from '~/sql/sql.ts'; import type { Query, SQL } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; @@ -303,7 +303,9 @@ export class SingleStore2Transaction< > extends SingleStoreTransaction { static readonly [entityKind]: string = 'SingleStore2Transaction'; - override async transaction(transaction: (tx: SingleStore2Transaction) => Promise): Promise { + override async transaction( + transaction: (tx: SingleStore2Transaction) => Promise, + ): Promise { const savepointName = `sp${this.nestedIndex + 1}`; const tx = new SingleStore2Transaction( this.dialect, From 92268c1f8f15b53e1966aa29a886fe935c406043 Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Wed, 24 Jul 2024 15:00:02 +0100 Subject: [PATCH 029/152] Make index types difference clearer --- drizzle-orm/src/singlestore-core/indexes.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 013ec816de..b74b682900 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -13,11 +13,6 @@ interface IndexCommonConfig { */ unique?: boolean; - /** - * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. - */ - using?: 'btree' | 'hash'; - /** * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. */ @@ -30,9 +25,17 @@ interface IndexCommonConfig { } type IndexColumnstoreConfig = IndexCommonConfig & { + /** + * If set, the index will be created as `create index ... using { 'hash' }`. + */ using?: 'hash'; }; -type IndexRowstoreConfig = IndexCommonConfig; +type IndexRowstoreConfig = IndexCommonConfig & { + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; +}; type IndexConfig = IndexColumnstoreConfig | IndexRowstoreConfig; export type IndexColumn = SingleStoreColumn | SQL; From c88a60a0bd653b73232a5941f5b16c33aa44cdc1 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 15:41:40 +0100 Subject: [PATCH 030/152] Apparently ATTACH does not support prepared statements, so we give the database name in raw format --- drizzle-orm/src/singlestore-core/dialect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 2363d6db35..bf96bbdaff 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -129,7 +129,7 @@ export class SingleStoreDialect { buildAttachQuery({ database, milestone }: SingleStoreAttachConfig): SQL { const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; - return sql`attach database ${database}${milestoneSql}`; + return sql`attach database ${sql.raw(database)}${milestoneSql}`; } buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { From b6a7853f53aeeee422e9376b5977515d26dfdfbc Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 16:00:16 +0100 Subject: [PATCH 031/152] Added ATTACH AT TIME --- drizzle-orm/src/singlestore-core/dialect.ts | 5 +++-- .../singlestore-core/query-builders/attach.ts | 17 ++++++++++++++++- .../singlestore-core/query-builders/detach.ts | 7 ++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index bf96bbdaff..e0829926c0 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -126,10 +126,11 @@ export class SingleStoreDialect { return sql`detach database ${database}${milestoneSql}${workspaceSql}`; } - buildAttachQuery({ database, milestone }: SingleStoreAttachConfig): SQL { + buildAttachQuery({ database, milestone, time }: SingleStoreAttachConfig): SQL { const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + const timeSql = time ? sql` at time ${time}` : undefined; - return sql`attach database ${sql.raw(database)}${milestoneSql}`; + return sql`attach database ${sql.raw(database)}${milestoneSql}${timeSql}`; } buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts index cd26a73b66..58d9b91a79 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/attach.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/attach.ts @@ -1,4 +1,5 @@ import { entityKind } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { @@ -36,6 +37,7 @@ export type SingleStoreAttach< export interface SingleStoreAttachConfig { milestone?: string | undefined; + time?: Date | undefined; database: string; } @@ -123,11 +125,24 @@ export class SingleStoreAttachBase< * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); * ``` */ - atMilestone(milestone: string | undefined): SingleStoreAttachWithout { + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreAttachWithout { + if (this.config.time) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } this.config.milestone = milestone; return this as any; } + // TODO(singlestore): docs + atTime(time: Date): SingleStoreAttachWithout { + if (this.config.milestone) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.time = time; + return this as any; + } + /** @internal */ getSQL(): SQL { return this.dialect.buildAttachQuery(this.config); diff --git a/drizzle-orm/src/singlestore-core/query-builders/detach.ts b/drizzle-orm/src/singlestore-core/query-builders/detach.ts index 8420bd9902..df3452074c 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/detach.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/detach.ts @@ -124,13 +124,14 @@ export class SingleStoreDetachBase< * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); * ``` */ - atMilestone(milestone: string | undefined): SingleStoreDetachWithout { + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreDetachWithout { this.config.milestone = milestone; return this as any; } - // TODO: docs - fromWorkspace(workspace: string | undefined): SingleStoreDetachWithout { + // TODO(singlestore): docs + fromWorkspace(workspace: string): SingleStoreDetachWithout { this.config.workspace = workspace; return this as any; } From 6a73e72690e0472ec97b10f62b6651f216a2ac7f Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 17:08:00 +0100 Subject: [PATCH 032/152] Added ATTACH AS --- drizzle-orm/src/singlestore-core/dialect.ts | 5 +++-- drizzle-orm/src/singlestore-core/query-builders/attach.ts | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index e0829926c0..bf39611574 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -126,11 +126,12 @@ export class SingleStoreDialect { return sql`detach database ${database}${milestoneSql}${workspaceSql}`; } - buildAttachQuery({ database, milestone, time }: SingleStoreAttachConfig): SQL { + buildAttachQuery({ database, milestone, time, databaseAlias }: SingleStoreAttachConfig): SQL { + const asSql = databaseAlias ? sql` as ${sql.identifier(databaseAlias)}` : undefined; const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; const timeSql = time ? sql` at time ${time}` : undefined; - return sql`attach database ${sql.raw(database)}${milestoneSql}${timeSql}`; + return sql`attach database ${sql.raw(database)}${asSql}${milestoneSql}${timeSql}`; } buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts index 58d9b91a79..3c79d9adf9 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/attach.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/attach.ts @@ -39,6 +39,7 @@ export interface SingleStoreAttachConfig { milestone?: string | undefined; time?: Date | undefined; database: string; + databaseAlias?: string | undefined; } export type SingleStoreAttachPrepare = PreparedQueryKind< @@ -96,6 +97,11 @@ export class SingleStoreAttachBase< this.config = { database }; } + as(dabataseAlias: string): SingleStoreAttachWithout { + this.config.databaseAlias = dabataseAlias; + return this as any; + } + /** * Adds a `where` clause to the query. * From 94df1b36cbff928e2f5c7a7fee7b6fcdc190b1c6 Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Wed, 24 Jul 2024 17:22:36 +0100 Subject: [PATCH 033/152] Trying another approach for type checking index input --- drizzle-orm/src/singlestore-core/indexes.ts | 33 +++++++------ drizzle-orm/src/singlestore-core/table.ts | 53 ++++++++++++++++----- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index b74b682900..4fc25f8406 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; -import type { SingleStoreColumnstoreTable, SingleStoreRowstoreTable, SingleStoreTable } from './table.ts'; +import type { SingleStoreTable } from './table.ts'; interface IndexCommonConfig { name: string; @@ -50,38 +50,31 @@ export class IndexBuilderOn { } } -export interface AnyIndexBuilder { - build(table: SingleStoreTable): Index; -} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IndexBuilder extends AnyIndexBuilder {} - -export class IndexBuilder implements AnyIndexBuilder { +export class IndexBuilder { static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; /** @internal */ - config: IndexConfig; + config: TConfig; constructor(name: string, columns: IndexColumn[], unique: boolean) { this.config = { name, columns, unique, - }; + } as TConfig; } - using(using: IndexConfig['using']): this { + using(using: TConfig['using']): this { this.config.using = using; return this; } - algorythm(algorythm: IndexConfig['algorythm']): this { + algorythm(algorythm: TConfig['algorythm']): this { this.config.algorythm = algorythm; return this; } - lock(lock: IndexConfig['lock']): this { + lock(lock: TConfig['lock']): this { this.config.lock = lock; return this; } @@ -92,12 +85,18 @@ export class IndexBuilder implements AnyIndexBuilder { } } +export class IndexColumnstoreBuilder extends IndexBuilder { + static readonly [entityKind]: string = 'SingleStoreColumnstoreIndexBuilder'; +} + +export class IndexRowstoreBuilder extends IndexBuilder { + static readonly [entityKind]: string = 'SingleStoreRowstoreIndexBuilder'; +} + export class Index { static readonly [entityKind]: string = 'SingleStoreIndex'; - readonly config: - | (IndexColumnstoreConfig & { table: SingleStoreColumnstoreTable }) - | (IndexRowstoreConfig & { table: SingleStoreRowstoreTable }); + readonly config: IndexConfig & { table: SingleStoreTable }; constructor(config: IndexConfig, table: SingleStoreTable) { this.config = { ...config, table }; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 4c40cd5b96..cca6fc6311 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -3,42 +3,57 @@ import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { CheckBuilder } from './checks.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; -import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; +import type { IndexColumnstoreBuilder, IndexRowstoreBuilder } from './indexes.ts'; -export type SingleStoreTableExtraConfig = Record< +export type SingleStoreColumnstoreTableExtraConfig = Record< string, - | AnyIndexBuilder + | IndexColumnstoreBuilder | CheckBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; +export type SingleStoreRowstoreTableExtraConfig = Record< + string, + | IndexRowstoreBuilder + | CheckBuilder + | PrimaryKeyBuilder + | UniqueConstraintBuilder +>; +export type SingleStoreTableExtraConfig = SingleStoreColumnstoreTableExtraConfig | SingleStoreRowstoreTableExtraConfig; export type TableConfig = TableConfigBase; -export abstract class SingleStoreTable extends Table { +export abstract class SingleStoreTable< + TColumn extends TableConfig = TableConfig, + TExtraConfig extends SingleStoreTableExtraConfig = SingleStoreTableExtraConfig, +> extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; - declare protected $columns: T['columns']; + declare protected $columns: TColumn['columns']; /** @internal */ static override readonly Symbol = Object.assign({}, Table.Symbol, {}); /** @internal */ - override [Table.Symbol.Columns]!: NonNullable; + override [Table.Symbol.Columns]!: NonNullable; /** @internal */ override [Table.Symbol.ExtraConfigBuilder]: - | ((self: Record) => SingleStoreTableExtraConfig) + | ((self: Record) => TExtraConfig) | undefined = undefined; } -export class SingleStoreRowstoreTable extends SingleStoreTable { +export class SingleStoreRowstoreTable + extends SingleStoreTable +{ static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; } -export class SingleStoreColumnstoreTable extends SingleStoreTable { +export class SingleStoreColumnstoreTable + extends SingleStoreTable +{ static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; } @@ -124,14 +139,17 @@ export function singlestoreTableWithSchema< return table; } -export interface SingleStoreTableFn { +export interface SingleStoreTableFn< + TSchemaName extends string | undefined = undefined, + TExtraConfig extends SingleStoreTableExtraConfig = SingleStoreTableExtraConfig, +> { < TTableName extends string, TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + extraConfig?: (self: BuildColumns) => TExtraConfig, ): SingleStoreTableWithColumns<{ name: TTableName; schema: TSchemaName; @@ -140,11 +158,20 @@ export interface SingleStoreTableFn; } -export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { +export const singlestoreTable: SingleStoreTableFn = ( + name, + columns, + extraConfig, +) => { return singlestoreTableWithSchema(SinglestoreTableType.columnstore, name, columns, extraConfig, undefined, name); }; -export const singlestoreRowstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { +// TODO: Need to access drizzle kit to add rowstore support on migrations +export const singlestoreRowstoreTable: SingleStoreTableFn = ( + name, + columns, + extraConfig, +) => { return singlestoreTableWithSchema(SinglestoreTableType.rowstore, name, columns, extraConfig, undefined, name); }; From fbf33ec0a4cd20a9a7e533e6907af20aed283917 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 24 Jul 2024 13:03:11 -0400 Subject: [PATCH 034/152] initial geography implementation --- .../src/singlestore-core/columns/geography.ts | 131 ++++++++++++++++++ .../columns/geographypoint.ts | 11 +- 2 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 drizzle-orm/src/singlestore-core/columns/geography.ts diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts new file mode 100644 index 0000000000..267dc0457e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -0,0 +1,131 @@ +import type { ColumnBaseConfig } from '~/column'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import { sql } from '~/sql/sql.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type LngLat = [lng: number, lat: number]; + +type GeographyPoint = LngLat; +type GeographyLineString = Array; +type GeographyPolygon = Array>; + +type Geography = { + __type: 'POINT'; + data: GeographyPoint; +} | { + __type: 'LINESTRING'; + data: GeographyLineString; +} | { + __type: 'POLYGON'; + data: GeographyPolygon; +}; + +export type SingleStoreGeographyBuilderInitial = SingleStoreGeographyBuilder<{ + name: TName; + dataType: 'array'; + columnType: 'SingleStoreGeography'; + data: GeographyPoint | GeographyLineString | GeographyPolygon; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreGeographyBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreGeographyBuilder'; + + constructor(name: T['name']) { + super(name, 'array', 'SingleStoreGeography'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreGeography> { + return new SingleStoreGeography(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreGeography> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreGeography'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreGeographyBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return 'text'; + // TODO `geography` is only supported on rowstore tables. Geography data + // on columnstore should be stored as `text` + // return 'geography'; + } + + override mapToDriverValue(value: GeographyPoint | GeographyLineString | GeographyPolygon) { + const test = value[0]; + if (typeof test === 'number') { + const [lng, lat] = value as GeographyPoint; + return sql`"POINT(${lng} ${lat})"`; + } else if (Array.isArray(test)) { + if (typeof test[0] === 'number') { + const linestring = value as GeographyLineString; + const points = linestring.map((ls) => sql`${ls[0]} ${ls[1]}`); + return sql`"LINESTRING(${points.join(', ')})"`; + } else { + const polygon = value as GeographyPolygon; + const rings = polygon.map((ring) => { + const points = ring.map((point) => sql`${point[0]} ${point[1]}`); + return sql`(${points.join(', ')})`; + }); + return sql`"POLYGON(${rings.join(', ')})`; + } + } else { + throw new Error('value is not Array'); + } + } + + override mapFromDriverValue(value: string): Geography { + const firstParenIndex = value.indexOf('('); + const __type = value.slice(0, firstParenIndex); + const inner = value.slice(firstParenIndex + 1, -1); + switch (__type) { + case 'POINT': { + return { + __type, + data: inner.split(' ').map(Number) as LngLat, + }; + } + case 'LINESTRING': { + const pairs = inner.split(', '); + return { + __type, + data: pairs.map((pair) => pair.split(' ').map(Number)) as GeographyLineString, + }; + } + case 'POLYGON': { + const rings = inner.slice(1, -1).split('), ('); + return { + __type, + data: rings.map((ring) => { + const pairs = ring.split(', '); + return pairs.map((pair) => pair.split(' ').map(Number)); + }) as GeographyPolygon, + }; + } + default: { + throw new Error('unexpected Geography type'); + } + } + } +} + +export function geography(name: TName): SingleStoreGeographyBuilderInitial { + return new SingleStoreGeographyBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts index 0edcc405c7..46a2c594ca 100644 --- a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts +++ b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts @@ -4,14 +4,13 @@ import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; - -type GeographyPoint = [number, number]; +import type { LngLat } from './geography'; export type SingleStoreGeographyPointBuilderInitial = SingleStoreGeographyPointBuilder<{ name: TName; dataType: 'array'; columnType: 'SingleStoreGeographyPoint'; - data: GeographyPoint; + data: LngLat; driverParam: string; enumValues: undefined; generated: undefined; @@ -50,13 +49,13 @@ export class SingleStoreGeographyPoint Date: Wed, 24 Jul 2024 18:38:27 +0100 Subject: [PATCH 035/152] Reverth all columnstore and rowstore work --- drizzle-orm/src/singlestore-core/indexes.ts | 48 ++++----- drizzle-orm/src/singlestore-core/schema.ts | 4 +- drizzle-orm/src/singlestore-core/table.ts | 106 ++++---------------- 3 files changed, 41 insertions(+), 117 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 4fc25f8406..59d2bfb11f 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -3,7 +3,7 @@ import type { SQL } from '~/sql/sql.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; import type { SingleStoreTable } from './table.ts'; -interface IndexCommonConfig { +interface IndexConfig { name: string; columns: IndexColumn[]; @@ -13,6 +13,11 @@ interface IndexCommonConfig { */ unique?: boolean; + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; + /** * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. */ @@ -24,20 +29,6 @@ interface IndexCommonConfig { lock?: 'default' | 'none' | 'shared' | 'exclusive'; } -type IndexColumnstoreConfig = IndexCommonConfig & { - /** - * If set, the index will be created as `create index ... using { 'hash' }`. - */ - using?: 'hash'; -}; -type IndexRowstoreConfig = IndexCommonConfig & { - /** - * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. - */ - using?: 'btree' | 'hash'; -}; -type IndexConfig = IndexColumnstoreConfig | IndexRowstoreConfig; - export type IndexColumn = SingleStoreColumn | SQL; export class IndexBuilderOn { @@ -50,31 +41,38 @@ export class IndexBuilderOn { } } -export class IndexBuilder { +export interface AnyIndexBuilder { + build(table: SingleStoreTable): Index; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface IndexBuilder extends AnyIndexBuilder {} + +export class IndexBuilder implements AnyIndexBuilder { static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; /** @internal */ - config: TConfig; + config: IndexConfig; constructor(name: string, columns: IndexColumn[], unique: boolean) { this.config = { name, columns, unique, - } as TConfig; + }; } - using(using: TConfig['using']): this { + using(using: IndexConfig['using']): this { this.config.using = using; return this; } - algorythm(algorythm: TConfig['algorythm']): this { + algorythm(algorythm: IndexConfig['algorythm']): this { this.config.algorythm = algorythm; return this; } - lock(lock: TConfig['lock']): this { + lock(lock: IndexConfig['lock']): this { this.config.lock = lock; return this; } @@ -85,14 +83,6 @@ export class IndexBuilder { } } -export class IndexColumnstoreBuilder extends IndexBuilder { - static readonly [entityKind]: string = 'SingleStoreColumnstoreIndexBuilder'; -} - -export class IndexRowstoreBuilder extends IndexBuilder { - static readonly [entityKind]: string = 'SingleStoreRowstoreIndexBuilder'; -} - export class Index { static readonly [entityKind]: string = 'SingleStoreIndex'; diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index 2a278e4e0e..82da44a49e 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,5 +1,5 @@ import { entityKind, is } from '~/entity.ts'; -import { type SingleStoreTableFn, SinglestoreTableType, singlestoreTableWithSchema } from './table.ts'; +import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; export class SingleStoreSchema { @@ -10,7 +10,7 @@ export class SingleStoreSchema { ) {} table: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreTableWithSchema(SinglestoreTableType.columnstore, name, columns, extraConfig, this.schemaName); + return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); }; view = ((name, columns) => { diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index cca6fc6311..16db288e93 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -3,60 +3,38 @@ import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { CheckBuilder } from './checks.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; +import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -import type { IndexColumnstoreBuilder, IndexRowstoreBuilder } from './indexes.ts'; -export type SingleStoreColumnstoreTableExtraConfig = Record< +export type SingleStoreTableExtraConfig = Record< string, - | IndexColumnstoreBuilder + | AnyIndexBuilder | CheckBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; -export type SingleStoreRowstoreTableExtraConfig = Record< - string, - | IndexRowstoreBuilder - | CheckBuilder - | PrimaryKeyBuilder - | UniqueConstraintBuilder ->; -export type SingleStoreTableExtraConfig = SingleStoreColumnstoreTableExtraConfig | SingleStoreRowstoreTableExtraConfig; export type TableConfig = TableConfigBase; -export abstract class SingleStoreTable< - TColumn extends TableConfig = TableConfig, - TExtraConfig extends SingleStoreTableExtraConfig = SingleStoreTableExtraConfig, -> extends Table { +export class SingleStoreTable extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; - declare protected $columns: TColumn['columns']; + declare protected $columns: T['columns']; /** @internal */ - static override readonly Symbol = Object.assign({}, Table.Symbol, {}); + static override readonly Symbol = Object.assign({}, Table.Symbol, { + }); /** @internal */ - override [Table.Symbol.Columns]!: NonNullable; + override [Table.Symbol.Columns]!: NonNullable; /** @internal */ override [Table.Symbol.ExtraConfigBuilder]: - | ((self: Record) => TExtraConfig) + | ((self: Record) => SingleStoreTableExtraConfig) | undefined = undefined; } -export class SingleStoreRowstoreTable - extends SingleStoreTable -{ - static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; -} - -export class SingleStoreColumnstoreTable - extends SingleStoreTable -{ - static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; -} - export type AnySingleStoreTable = {}> = SingleStoreTable< UpdateTableConfig >; @@ -67,17 +45,11 @@ export type SingleStoreTableWithColumns = [Key in keyof T['columns']]: T['columns'][Key]; }; -export enum SinglestoreTableType { - rowstore, - columnstore, -} - export function singlestoreTableWithSchema< TTableName extends string, TSchemaName extends string | undefined, TColumnsMap extends Record, >( - type: SinglestoreTableType, name: TTableName, columns: TColumnsMap, extraConfig: @@ -91,27 +63,12 @@ export function singlestoreTableWithSchema< columns: BuildColumns; dialect: 'singlestore'; }> { - let rawTable; - switch (type) { - case SinglestoreTableType.columnstore: { - rawTable = new SingleStoreColumnstoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); - break; - } - case SinglestoreTableType.rowstore: { - rawTable = new SingleStoreRowstoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); - break; - } - } + const rawTable = new SingleStoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { @@ -139,17 +96,14 @@ export function singlestoreTableWithSchema< return table; } -export interface SingleStoreTableFn< - TSchemaName extends string | undefined = undefined, - TExtraConfig extends SingleStoreTableExtraConfig = SingleStoreTableExtraConfig, -> { +export interface SingleStoreTableFn { < TTableName extends string, TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig?: (self: BuildColumns) => TExtraConfig, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, ): SingleStoreTableWithColumns<{ name: TTableName; schema: TSchemaName; @@ -158,32 +112,12 @@ export interface SingleStoreTableFn< }>; } -export const singlestoreTable: SingleStoreTableFn = ( - name, - columns, - extraConfig, -) => { - return singlestoreTableWithSchema(SinglestoreTableType.columnstore, name, columns, extraConfig, undefined, name); -}; - -// TODO: Need to access drizzle kit to add rowstore support on migrations -export const singlestoreRowstoreTable: SingleStoreTableFn = ( - name, - columns, - extraConfig, -) => { - return singlestoreTableWithSchema(SinglestoreTableType.rowstore, name, columns, extraConfig, undefined, name); +export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); }; export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { return (name, columns, extraConfig) => { - return singlestoreTableWithSchema( - SinglestoreTableType.columnstore, - customizeTableName(name) as typeof name, - columns, - extraConfig, - undefined, - name, - ); + return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); }; } From 1cb055ff1362ba4b09cc5aa0001ad43ca042d921 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 24 Jul 2024 13:44:35 -0400 Subject: [PATCH 036/152] add types to index, fix? geography --- drizzle-orm/src/singlestore-core/columns/geography.ts | 6 +++--- drizzle-orm/src/singlestore-core/columns/index.ts | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 267dc0457e..3af49f3832 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -77,14 +77,14 @@ export class SingleStoreGeography sql`${ls[0]} ${ls[1]}`); - return sql`"LINESTRING(${points.join(', ')})"`; + return sql`"LINESTRING(${sql.join(points, sql.raw(', '))})"`; } else { const polygon = value as GeographyPolygon; const rings = polygon.map((ring) => { const points = ring.map((point) => sql`${point[0]} ${point[1]}`); - return sql`(${points.join(', ')})`; + return sql`(${sql.join(points, sql.raw(', '))})`; }); - return sql`"POLYGON(${rings.join(', ')})`; + return sql`"POLYGON(${sql.join(rings, sql.raw(', '))})`; } } else { throw new Error('value is not Array'); diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts index 0dcb41be94..18d27e0fba 100644 --- a/drizzle-orm/src/singlestore-core/columns/index.ts +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -11,6 +11,9 @@ export * from './decimal.ts'; export * from './double.ts'; export * from './enum.ts'; export * from './float.ts'; +export * from './geography.ts'; +export * from './geographypoint.ts'; +export * from './guid.ts'; export * from './int.ts'; export * from './json.ts'; export * from './mediumint.ts'; @@ -21,6 +24,7 @@ export * from './text.ts'; export * from './time.ts'; export * from './timestamp.ts'; export * from './tinyint.ts'; +export * from './uuid.ts'; export * from './varbinary.ts'; export * from './varchar.ts'; export * from './year.ts'; From 7ec390164f42a4fef3eb62172512c008f4ebe799 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 24 Jul 2024 13:46:43 -0400 Subject: [PATCH 037/152] fix polygon --- drizzle-orm/src/singlestore-core/columns/geography.ts | 2 +- drizzle-orm/src/singlestore-core/table.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 3af49f3832..2ae6195d88 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -84,7 +84,7 @@ export class SingleStoreGeography sql`${point[0]} ${point[1]}`); return sql`(${sql.join(points, sql.raw(', '))})`; }); - return sql`"POLYGON(${sql.join(rings, sql.raw(', '))})`; + return sql`"POLYGON(${sql.join(rings, sql.raw(', '))})"`; } } else { throw new Error('value is not Array'); diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 16db288e93..54284184d3 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -23,8 +23,7 @@ export class SingleStoreTable extends Table declare protected $columns: T['columns']; /** @internal */ - static override readonly Symbol = Object.assign({}, Table.Symbol, { - }); + static override readonly Symbol = Object.assign({}, Table.Symbol, {}); /** @internal */ override [Table.Symbol.Columns]!: NonNullable; From 9621d957e56a1c7112abc971a96d6f261acede0a Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Wed, 24 Jul 2024 18:53:55 +0100 Subject: [PATCH 038/152] Remove check --- drizzle-orm/src/singlestore-core/checks.ts | 32 ---------------------- drizzle-orm/src/singlestore-core/index.ts | 1 - drizzle-orm/src/singlestore-core/table.ts | 2 -- drizzle-orm/src/singlestore-core/utils.ts | 6 ---- 4 files changed, 41 deletions(-) delete mode 100644 drizzle-orm/src/singlestore-core/checks.ts diff --git a/drizzle-orm/src/singlestore-core/checks.ts b/drizzle-orm/src/singlestore-core/checks.ts deleted file mode 100644 index 29fdb76802..0000000000 --- a/drizzle-orm/src/singlestore-core/checks.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import type { SQL } from '~/sql/sql.ts'; -import type { SingleStoreTable } from './table.ts'; - -export class CheckBuilder { - static readonly [entityKind]: string = 'SingleStoreCheckBuilder'; - - protected brand!: 'SingleStoreConstraintBuilder'; - - constructor(public name: string, public value: SQL) {} - - /** @internal */ - build(table: SingleStoreTable): Check { - return new Check(table, this); - } -} - -export class Check { - static readonly [entityKind]: string = 'SingleStoreCheck'; - - readonly name: string; - readonly value: SQL; - - constructor(public table: SingleStoreTable, builder: CheckBuilder) { - this.name = builder.name; - this.value = builder.value; - } -} - -export function check(name: string, value: SQL): CheckBuilder { - return new CheckBuilder(name, value); -} diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts index 20e3c3b299..92c6b9a203 100644 --- a/drizzle-orm/src/singlestore-core/index.ts +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -1,5 +1,4 @@ export * from './alias.ts'; -export * from './checks.ts'; export * from './columns/index.ts'; export * from './db.ts'; export * from './dialect.ts'; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 54284184d3..529a95fe9c 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -1,7 +1,6 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; -import type { CheckBuilder } from './checks.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; @@ -10,7 +9,6 @@ import type { UniqueConstraintBuilder } from './unique-constraint.ts'; export type SingleStoreTableExtraConfig = Record< string, | AnyIndexBuilder - | CheckBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts index 00e464f302..e6412161d6 100644 --- a/drizzle-orm/src/singlestore-core/utils.ts +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -1,8 +1,6 @@ import { is } from '~/entity.ts'; import { Table } from '~/table.ts'; import { ViewBaseConfig } from '~/view-common.ts'; -import type { Check } from './checks.ts'; -import { CheckBuilder } from './checks.ts'; import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; import type { PrimaryKey } from './primary-keys.ts'; @@ -15,7 +13,6 @@ import type { SingleStoreView } from './view.ts'; export function getTableConfig(table: SingleStoreTable) { const columns = Object.values(table[SingleStoreTable.Symbol.Columns]); const indexes: Index[] = []; - const checks: Check[] = []; const primaryKeys: PrimaryKey[] = []; const uniqueConstraints: UniqueConstraint[] = []; const name = table[Table.Symbol.Name]; @@ -29,8 +26,6 @@ export function getTableConfig(table: SingleStoreTable) { for (const builder of Object.values(extraConfig)) { if (is(builder, IndexBuilder)) { indexes.push(builder.build(table)); - } else if (is(builder, CheckBuilder)) { - checks.push(builder.build(table)); } else if (is(builder, UniqueConstraintBuilder)) { uniqueConstraints.push(builder.build(table)); } else if (is(builder, PrimaryKeyBuilder)) { @@ -42,7 +37,6 @@ export function getTableConfig(table: SingleStoreTable) { return { columns, indexes, - checks, primaryKeys, uniqueConstraints, name, From 4cd60b7515b06c0aac0380aeb46ed10a72090545 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 24 Jul 2024 14:09:13 -0400 Subject: [PATCH 039/152] improve geography type narrowing --- .../src/singlestore-core/columns/geography.ts | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 2ae6195d88..b2bc8ac6b0 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -69,23 +69,18 @@ export class SingleStoreGeography sql`${ls[0]} ${ls[1]}`); - return sql`"LINESTRING(${sql.join(points, sql.raw(', '))})"`; - } else { - const polygon = value as GeographyPolygon; - const rings = polygon.map((ring) => { - const points = ring.map((point) => sql`${point[0]} ${point[1]}`); - return sql`(${sql.join(points, sql.raw(', '))})`; - }); - return sql`"POLYGON(${sql.join(rings, sql.raw(', '))})"`; - } + } else if (_isLineString(value)) { + const points = value.map((ls) => sql`${ls[0]} ${ls[1]}`); + return sql`"LINESTRING(${sql.join(points, sql.raw(', '))})"`; + } else if (_isPolygon(value)) { + const rings = value.map((ring) => { + const points = ring.map((point) => sql`${point[0]} ${point[1]}`); + return sql`(${sql.join(points, sql.raw(', '))})`; + }); + return sql`"POLYGON(${sql.join(rings, sql.raw(', '))})"`; } else { throw new Error('value is not Array'); } @@ -129,3 +124,25 @@ export class SingleStoreGeography(name: TName): SingleStoreGeographyBuilderInitial { return new SingleStoreGeographyBuilder(name); } + +function _isPoint(value: GeographyPoint | GeographyLineString | GeographyPolygon): value is GeographyPoint { + return value.length === 2 && typeof value[0] === 'number'; +} + +function _isLineString(value: GeographyPoint | GeographyLineString | GeographyPolygon): value is GeographyLineString { + try { + const test = value as GeographyLineString; + return typeof test[0]![0] === 'number'; + } catch { + return false; + } +} + +function _isPolygon(value: GeographyPoint | GeographyLineString | GeographyPolygon): value is GeographyPolygon { + try { + const test = value as GeographyPolygon; + return typeof test[0]![0]![0] === 'number'; + } catch { + return false; + } +} From a5749894e310563929b22ffeea1c667db91bc0da Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 24 Jul 2024 15:08:19 -0400 Subject: [PATCH 040/152] error -> drizzleerror --- drizzle-orm/src/singlestore-core/columns/geography.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index b2bc8ac6b0..8c4358e01d 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -1,6 +1,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -82,7 +83,7 @@ export class SingleStoreGeography Date: Wed, 24 Jul 2024 15:24:28 -0400 Subject: [PATCH 041/152] add branching --- drizzle-orm/src/singlestore-core/db.ts | 8 + drizzle-orm/src/singlestore-core/dialect.ts | 20 +- .../singlestore-core/query-builders/attach.ts | 7 + .../singlestore-core/query-builders/branch.ts | 195 ++++++++++++++++++ 4 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 drizzle-orm/src/singlestore-core/query-builders/branch.ts diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index e8b7963634..5574ad14ad 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -8,6 +8,7 @@ import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { SingleStoreDialect } from './dialect.ts'; import { SingleStoreAttachBase } from './query-builders/attach.ts'; +import { SingleStoreBranchBase } from './query-builders/branch.ts'; import { SingleStoreDetachBase } from './query-builders/detach.ts'; import { QueryBuilder, @@ -487,6 +488,13 @@ export class SingleStoreDatabase< ): SingleStoreAttachBase { return new SingleStoreAttachBase(database, this.session, this.dialect); } + + branch( + database: TDatabase, + branchName: string, + ): SingleStoreBranchBase { + return new SingleStoreBranchBase(database, branchName, this.session, this.dialect); + } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index bf39611574..e2784a16da 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -24,6 +24,7 @@ import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import { SingleStoreColumn } from './columns/common.ts'; import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; +import type { SingleStoreBranchConfig } from './query-builders/branch.ts'; import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; @@ -126,12 +127,27 @@ export class SingleStoreDialect { return sql`detach database ${database}${milestoneSql}${workspaceSql}`; } - buildAttachQuery({ database, milestone, time, databaseAlias }: SingleStoreAttachConfig): SQL { + buildAttachQuery({ database, milestone, time, databaseAlias, readOnly }: SingleStoreAttachConfig): SQL { const asSql = databaseAlias ? sql` as ${sql.identifier(databaseAlias)}` : undefined; const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; const timeSql = time ? sql` at time ${time}` : undefined; + const readOnlySql = readOnly ? sql` READ ONLY` : undefined; - return sql`attach database ${sql.raw(database)}${asSql}${milestoneSql}${timeSql}`; + return sql`attach database ${sql.raw(database)}${readOnlySql}${asSql}${milestoneSql}${timeSql}`; + } + + buildBranchQuery( + { database, databaseAlias, fromWorkspaceGroup, milestone, readOnly, time }: SingleStoreBranchConfig, + ): SQL { + const asSql = sql` as ${sql.identifier(databaseAlias)}`; + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + const timeSql = time ? sql` at time ${time}` : undefined; + const fromWorkspaceGroupSql = fromWorkspaceGroup ? sql` from workspace group ${fromWorkspaceGroup}` : undefined; + const readOnlySql = readOnly ? sql` READ ONLY` : undefined; + + return sql`attach database ${ + sql.raw(database) + }${fromWorkspaceGroupSql}${readOnlySql}${asSql}${milestoneSql}${timeSql}`; } buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts index 3c79d9adf9..63416693e3 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/attach.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/attach.ts @@ -40,6 +40,7 @@ export interface SingleStoreAttachConfig { time?: Date | undefined; database: string; databaseAlias?: string | undefined; + readOnly?: boolean | undefined; } export type SingleStoreAttachPrepare = PreparedQueryKind< @@ -149,6 +150,12 @@ export class SingleStoreAttachBase< return this as any; } + // TODO(singlestore): docs + readOnly(): SingleStoreAttachWithout { + this.config.readOnly = true; + return this as any; + } + /** @internal */ getSQL(): SQL { return this.dialect.buildAttachQuery(this.config); diff --git a/drizzle-orm/src/singlestore-core/query-builders/branch.ts b/drizzle-orm/src/singlestore-core/query-builders/branch.ts new file mode 100644 index 0000000000..baa1ea2470 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/branch.ts @@ -0,0 +1,195 @@ +import { entityKind } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreBranchWithout< + T extends AnySingleStoreBranchBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreBranchBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreBranch< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreBranchBase; + +export interface SingleStoreBranchConfig { + milestone?: string | undefined; + time?: Date | undefined; + database: string; + databaseAlias: string; + fromWorkspaceGroup?: string | undefined; + readOnly?: boolean | undefined; +} + +export type SingleStoreBranchPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreBranchDynamic = SingleStoreBranch< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreBranchBase = SingleStoreBranchBase; + +export interface SingleStoreBranchBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreBranchBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreBranch'; + + private config: SingleStoreBranchConfig; + + constructor( + private database: TDatabase, + private branchName: string, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database, databaseAlias: branchName }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Attach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Attach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Attach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreBranchWithout { + if (this.config.time) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.milestone = milestone; + return this as any; + } + + // TODO(singlestore): docs + atTime(time: Date): SingleStoreBranchWithout { + if (this.config.milestone) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.time = time; + return this as any; + } + + // TODO(singlestore): docs + fromWorkspaceGroup(groupID: string): SingleStoreBranchWithout { + this.config.fromWorkspaceGroup = groupID; + return this as any; + } + + // TODO(singlestore): docs + readOnly(): SingleStoreBranchWithout { + this.config.readOnly = true; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildBranchQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreBranchPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreBranchPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreBranchDynamic { + return this as any; + } +} From feffcfd56b871439079d6993ef9412d3b6c9278f Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 21:23:01 +0100 Subject: [PATCH 042/152] CREATE and DROP MILESTONE --- drizzle-orm/src/singlestore-core/db.ts | 14 ++ drizzle-orm/src/singlestore-core/dialect.ts | 14 ++ .../query-builders/createMilestone.ts | 136 ++++++++++++++++++ .../query-builders/dropMilestone.ts | 136 ++++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 5574ad14ad..99aa673aa4 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -30,6 +30,8 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; +import { SingleStoreCreateMilestoneBase } from './query-builders/createMilestone.ts'; +import { SingleStoreDropMilestoneBase } from './query-builders/dropMilestone.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, @@ -495,6 +497,18 @@ export class SingleStoreDatabase< ): SingleStoreBranchBase { return new SingleStoreBranchBase(database, branchName, this.session, this.dialect); } + + createMilestone( + milestone: TMilestone, + ): SingleStoreCreateMilestoneBase { + return new SingleStoreCreateMilestoneBase(milestone, this.session, this.dialect); + } + + dropMilestone( + milestone: TMilestone, + ): SingleStoreDropMilestoneBase { + return new SingleStoreDropMilestoneBase(milestone, this.session, this.dialect); + } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index e2784a16da..7716a9e8cc 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -37,6 +37,8 @@ import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; +import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; +import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -150,6 +152,18 @@ export class SingleStoreDialect { }${fromWorkspaceGroupSql}${readOnlySql}${asSql}${milestoneSql}${timeSql}`; } + buildCreateMilestoneQuery({ database, milestone }: SingleStoreCreateMilestoneConfig): SQL { + const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; + + return sql`create milestone ${milestone}${forSql}`; + } + + buildDropMilestoneQuery({ database, milestone }: SingleStoreDropMilestoneConfig): SQL { + const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; + + return sql`drop milestone ${milestone}${forSql}`; + } + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { const tableColumns = table[Table.Symbol.Columns]; diff --git a/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts new file mode 100644 index 0000000000..7922e39a16 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts @@ -0,0 +1,136 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreCreateMilestoneWithout< + T extends AnySingleStoreCreateMilestoneBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreCreateMilestoneBase< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreCreateMilestone< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreCreateMilestoneBase; + +export interface SingleStoreCreateMilestoneConfig { + milestone: string; + database?: string | undefined; +} + +export type SingleStoreCreateMilestonePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreCreateMilestoneDynamic = SingleStoreCreateMilestone< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreCreateMilestoneBase = SingleStoreCreateMilestoneBase; + +export interface SingleStoreCreateMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly milestone: TMilestone; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreCreateMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreCreateMilestone'; + + private config: SingleStoreCreateMilestoneConfig; + + constructor( + private milestone: TMilestone, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { milestone }; + } + + // TODO(singlestore): docs + for(database: string): SingleStoreCreateMilestoneWithout { + this.config.database = database; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildCreateMilestoneQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreCreateMilestonePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreCreateMilestonePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreCreateMilestoneDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts new file mode 100644 index 0000000000..7fba4f05ef --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts @@ -0,0 +1,136 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreDropMilestoneWithout< + T extends AnySingleStoreDropMilestoneBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDropMilestoneBase< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDropMilestone< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDropMilestoneBase; + +export interface SingleStoreDropMilestoneConfig { + milestone: string; + database?: string | undefined; +} + +export type SingleStoreDropMilestonePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDropMilestoneDynamic = SingleStoreDropMilestone< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDropMilestoneBase = SingleStoreDropMilestoneBase; + +export interface SingleStoreDropMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly milestone: TMilestone; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDropMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreDropMilestone'; + + private config: SingleStoreDropMilestoneConfig; + + constructor( + private milestone: TMilestone, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { milestone }; + } + + // TODO(singlestore): docs + for(database: string): SingleStoreDropMilestoneWithout { + this.config.database = database; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDropMilestoneQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDropMilestonePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreDropMilestonePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDropMilestoneDynamic { + return this as any; + } +} From 01334cc74b1e889b0b1d5e2f6303a8e1afbbfa78 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 24 Jul 2024 16:50:49 -0400 Subject: [PATCH 043/152] combine buildAttachQuery and buildBranchQuery --- drizzle-orm/src/singlestore-core/dialect.ts | 21 +++++++------------ .../singlestore-core/query-builders/attach.ts | 8 ++++++- .../singlestore-core/query-builders/branch.ts | 17 ++++----------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 7716a9e8cc..596e23e9a3 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -129,23 +129,16 @@ export class SingleStoreDialect { return sql`detach database ${database}${milestoneSql}${workspaceSql}`; } - buildAttachQuery({ database, milestone, time, databaseAlias, readOnly }: SingleStoreAttachConfig): SQL { - const asSql = databaseAlias ? sql` as ${sql.identifier(databaseAlias)}` : undefined; - const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; - const timeSql = time ? sql` at time ${time}` : undefined; - const readOnlySql = readOnly ? sql` READ ONLY` : undefined; - - return sql`attach database ${sql.raw(database)}${readOnlySql}${asSql}${milestoneSql}${timeSql}`; - } - - buildBranchQuery( - { database, databaseAlias, fromWorkspaceGroup, milestone, readOnly, time }: SingleStoreBranchConfig, + buildAttachQuery( + { database, milestone, time, databaseAlias, readOnly, ...rest }: SingleStoreAttachConfig | SingleStoreBranchConfig, ): SQL { - const asSql = sql` as ${sql.identifier(databaseAlias)}`; + const asSql = databaseAlias ? sql` as ${sql.identifier(databaseAlias)}` : undefined; const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; const timeSql = time ? sql` at time ${time}` : undefined; - const fromWorkspaceGroupSql = fromWorkspaceGroup ? sql` from workspace group ${fromWorkspaceGroup}` : undefined; - const readOnlySql = readOnly ? sql` READ ONLY` : undefined; + const readOnlySql = readOnly ? sql` read only` : undefined; + const fromWorkspaceGroupSql = 'fromWorkspaceGroup' in rest + ? sql` from workspace group ${rest.fromWorkspaceGroup}` + : undefined; return sql`attach database ${ sql.raw(database) diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts index 63416693e3..0b5bbac1a3 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/attach.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/attach.ts @@ -99,6 +99,9 @@ export class SingleStoreAttachBase< } as(dabataseAlias: string): SingleStoreAttachWithout { + if (this.config.readOnly) { + throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); + } this.config.databaseAlias = dabataseAlias; return this as any; } @@ -151,7 +154,10 @@ export class SingleStoreAttachBase< } // TODO(singlestore): docs - readOnly(): SingleStoreAttachWithout { + readOnly(): SingleStoreAttachWithout { + if (this.config.databaseAlias) { + throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); + } this.config.readOnly = true; return this as any; } diff --git a/drizzle-orm/src/singlestore-core/query-builders/branch.ts b/drizzle-orm/src/singlestore-core/query-builders/branch.ts index baa1ea2470..5ed8b6831c 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/branch.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/branch.ts @@ -12,6 +12,7 @@ import type { SingleStoreSession, } from '~/singlestore-core/session.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreAttachConfig } from './attach.ts'; export type SingleStoreBranchWithout< T extends AnySingleStoreBranchBase, @@ -35,13 +36,9 @@ export type SingleStoreBranch< TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, > = SingleStoreBranchBase; -export interface SingleStoreBranchConfig { - milestone?: string | undefined; - time?: Date | undefined; - database: string; +export interface SingleStoreBranchConfig extends SingleStoreAttachConfig { databaseAlias: string; fromWorkspaceGroup?: string | undefined; - readOnly?: boolean | undefined; } export type SingleStoreBranchPrepare = PreparedQueryKind< @@ -148,20 +145,14 @@ export class SingleStoreBranchBase< } // TODO(singlestore): docs - fromWorkspaceGroup(groupID: string): SingleStoreBranchWithout { + fromWorkspaceGroup(groupID: string): SingleStoreBranchWithout { this.config.fromWorkspaceGroup = groupID; return this as any; } - // TODO(singlestore): docs - readOnly(): SingleStoreBranchWithout { - this.config.readOnly = true; - return this as any; - } - /** @internal */ getSQL(): SQL { - return this.dialect.buildBranchQuery(this.config); + return this.dialect.buildAttachQuery(this.config); } toSQL(): Query { From 4afb283daea89e778c6248c2aea71ee5f4ea1896 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 23:18:28 +0100 Subject: [PATCH 044/152] OPTIMIZE TABLE --- drizzle-orm/src/singlestore-core/db.ts | 12 ++ drizzle-orm/src/singlestore-core/dialect.ts | 5 + .../query-builders/optimizeTable.ts | 150 ++++++++++++++++++ .../query-builders/optimizeTable.types.ts | 5 + 4 files changed, 172 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 99aa673aa4..3b18ded3da 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -32,6 +32,8 @@ import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; import { SingleStoreCreateMilestoneBase } from './query-builders/createMilestone.ts'; import { SingleStoreDropMilestoneBase } from './query-builders/dropMilestone.ts'; +import { SingleStoreOptimizeTableBase } from './query-builders/optimizeTable.ts'; +import type { OptimizeTableArgument } from './query-builders/optimizeTable.types.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, @@ -509,6 +511,16 @@ export class SingleStoreDatabase< ): SingleStoreDropMilestoneBase { return new SingleStoreDropMilestoneBase(milestone, this.session, this.dialect); } + + optimizeTable< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + >( + table: TTable, + arg: TArg | undefined = undefined, + ): SingleStoreOptimizeTableBase { + return new SingleStoreOptimizeTableBase(table, arg, this.session, this.dialect); + } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 596e23e9a3..fc25d6041b 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -39,6 +39,7 @@ import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; +import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -157,6 +158,10 @@ export class SingleStoreDialect { return sql`drop milestone ${milestone}${forSql}`; } + buildOptimizeTable({ table }: SingleStoreOptimizeTableConfig): SQL { + return sql`optimize table ${table}`; + } + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { const tableColumns = table[Table.Symbol.Columns]; diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts new file mode 100644 index 0000000000..69ad092650 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -0,0 +1,150 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreTable } from '../table.ts'; +import type { SelectedFields } from './select.types.ts'; +import type { OptimizeTableArgument } from './optimizeTable.types.ts'; + +export type SingleStoreOptimizeTableWithout< + T extends AnySingleStoreOptimizeTableBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreOptimizeTableBase< + T['_']['table'], + T['_']['arg'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreOptimizeTable< + TTable extends SingleStoreTable = SingleStoreTable, + TArg extends OptimizeTableArgument = OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreOptimizeTableBase; + +export interface SingleStoreOptimizeTableConfig { + table: SingleStoreTable; + arg?: OptimizeTableArgument | undefined; + selection?: SelectedFields | undefined; +} + +export type SingleStoreOptimizeTablePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreOptimizeTableDynamic = SingleStoreOptimizeTable< + T['_']['table'], + T['_']['arg'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreOptimizeTableBase = SingleStoreOptimizeTableBase; + +export interface SingleStoreOptimizeTableBase< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly arg: TArg | undefined; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreOptimizeTableBase< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static readonly [entityKind]: string = 'SingleStoreOptimizeTable'; + + private config: SingleStoreOptimizeTableConfig; + + constructor( + private table: TTable, + private arg: TArg | undefined, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { table, arg }; + } + + // TODO(singlestore): docs + warmBlobCacheForColumn(selection: SelectedFields): SingleStoreOptimizeTableWithout { + if (this.config.arg) { + throw new Error('Cannot call warmBlobCacheForColumn with an argument'); + } + this.config.selection = selection; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildOptimizeTable(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreOptimizeTablePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreOptimizeTablePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreOptimizeTableDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts new file mode 100644 index 0000000000..1c734f1ba1 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts @@ -0,0 +1,5 @@ +export type OptimizeTableArgument = + | 'FULL' + | 'FLUSH' + | 'FIX_ALTER' + | 'INDEX' From d09afccba4e4f646dbab798401f4e3f3c25be6d0 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 23:36:38 +0100 Subject: [PATCH 045/152] nits to OPTIMIZE TABLE --- drizzle-orm/src/singlestore-core/dialect.ts | 8 ++++++-- .../src/singlestore-core/query-builders/optimizeTable.ts | 7 +++---- .../query-builders/optimizeTable.types.ts | 5 +++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index fc25d6041b..7c6848cfa1 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -158,8 +158,12 @@ export class SingleStoreDialect { return sql`drop milestone ${milestone}${forSql}`; } - buildOptimizeTable({ table }: SingleStoreOptimizeTableConfig): SQL { - return sql`optimize table ${table}`; + buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { + const warmBlobCacheForColumnSql = selection ? + sql`warm blob cache for column ${selection}` + : undefined; + + return sql`optimize table ${table}${arg}${warmBlobCacheForColumnSql}`; } buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts index 69ad092650..65481dffc8 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -12,8 +12,7 @@ import type { } from '~/singlestore-core/session.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SingleStoreTable } from '../table.ts'; -import type { SelectedFields } from './select.types.ts'; -import type { OptimizeTableArgument } from './optimizeTable.types.ts'; +import type { OptimizeTableArgument, SelectedColumns } from './optimizeTable.types.ts'; export type SingleStoreOptimizeTableWithout< T extends AnySingleStoreOptimizeTableBase, @@ -42,7 +41,7 @@ export type SingleStoreOptimizeTable< export interface SingleStoreOptimizeTableConfig { table: SingleStoreTable; arg?: OptimizeTableArgument | undefined; - selection?: SelectedFields | undefined; + selection?: SelectedColumns | undefined; } export type SingleStoreOptimizeTablePrepare = PreparedQueryKind< @@ -106,7 +105,7 @@ export class SingleStoreOptimizeTableBase< } // TODO(singlestore): docs - warmBlobCacheForColumn(selection: SelectedFields): SingleStoreOptimizeTableWithout { + warmBlobCacheForColumn(...selection: SelectedColumns): SingleStoreOptimizeTableWithout { if (this.config.arg) { throw new Error('Cannot call warmBlobCacheForColumn with an argument'); } diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts index 1c734f1ba1..fb82fd2a9e 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts @@ -1,5 +1,10 @@ +import type { SingleStoreColumn } from ".." +import type { ColumnBaseConfig, ColumnDataType } from "~/index" + export type OptimizeTableArgument = | 'FULL' | 'FLUSH' | 'FIX_ALTER' | 'INDEX' + +export type SelectedColumns = [SingleStoreColumn, object>] From f11e5715b1e2c43d86c12692a84da5babbc6c78b Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Wed, 24 Jul 2024 23:54:33 +0100 Subject: [PATCH 046/152] more nits --- .../src/singlestore-core/query-builders/optimizeTable.ts | 8 +++++--- .../query-builders/optimizeTable.types.ts | 4 ---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts index 65481dffc8..7d1189ba84 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -12,7 +12,9 @@ import type { } from '~/singlestore-core/session.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SingleStoreTable } from '../table.ts'; -import type { OptimizeTableArgument, SelectedColumns } from './optimizeTable.types.ts'; +import type { OptimizeTableArgument } from './optimizeTable.types.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { ColumnBaseConfig, ColumnDataType } from '~/index.ts'; export type SingleStoreOptimizeTableWithout< T extends AnySingleStoreOptimizeTableBase, @@ -41,7 +43,7 @@ export type SingleStoreOptimizeTable< export interface SingleStoreOptimizeTableConfig { table: SingleStoreTable; arg?: OptimizeTableArgument | undefined; - selection?: SelectedColumns | undefined; + selection?: SingleStoreColumn, object>[] | undefined; } export type SingleStoreOptimizeTablePrepare = PreparedQueryKind< @@ -105,7 +107,7 @@ export class SingleStoreOptimizeTableBase< } // TODO(singlestore): docs - warmBlobCacheForColumn(...selection: SelectedColumns): SingleStoreOptimizeTableWithout { + warmBlobCacheForColumn(...selection: SingleStoreColumn, object>[]): SingleStoreOptimizeTableWithout { if (this.config.arg) { throw new Error('Cannot call warmBlobCacheForColumn with an argument'); } diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts index fb82fd2a9e..e82597337c 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts @@ -1,10 +1,6 @@ -import type { SingleStoreColumn } from ".." -import type { ColumnBaseConfig, ColumnDataType } from "~/index" - export type OptimizeTableArgument = | 'FULL' | 'FLUSH' | 'FIX_ALTER' | 'INDEX' -export type SelectedColumns = [SingleStoreColumn, object>] From a72e61cdaaed23333f33c5d40fc51bcc34c175a9 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Thu, 25 Jul 2024 00:00:21 +0100 Subject: [PATCH 047/152] even more nits --- drizzle-orm/src/singlestore-core/dialect.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 7c6848cfa1..476eea87ab 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -159,11 +159,13 @@ export class SingleStoreDialect { } buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { + const argSql = arg ? sql` ${sql.raw(arg)}` : undefined; + const warmBlobCacheForColumnSql = selection ? - sql`warm blob cache for column ${selection}` + sql` warm blob cache for column ${selection}` : undefined; - return sql`optimize table ${table}${arg}${warmBlobCacheForColumnSql}`; + return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; } buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { From 52963af0caea59cb999776bf100cc521cd622296 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Thu, 25 Jul 2024 01:18:41 +0100 Subject: [PATCH 048/152] more nits to OPTIMIZE TABLE --- drizzle-orm/src/singlestore-core/dialect.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 476eea87ab..0f6bb4063e 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -161,9 +161,11 @@ export class SingleStoreDialect { buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { const argSql = arg ? sql` ${sql.raw(arg)}` : undefined; - const warmBlobCacheForColumnSql = selection ? - sql` warm blob cache for column ${selection}` - : undefined; + let warmBlobCacheForColumnSql = undefined; + if (selection) { + const selectionField = selection.map((column) => { return { path: [], field: column } }); + warmBlobCacheForColumnSql = sql` warm blob cache for column ${this.buildSelection(selectionField, { isSingleTable: true })}`; + } return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; } From a623dce4c21e8cdbd3bd35d13e8b583ce906ad1d Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 24 Jul 2024 16:36:20 +0100 Subject: [PATCH 049/152] stringify BSON column --- .../src/singlestore-core/columns/blob.ts | 121 ++++++++++++++++++ .../src/singlestore-core/columns/bson.ts | 6 +- drizzle-orm/src/singlestore-core/db.ts | 8 +- drizzle-orm/src/singlestore-core/dialect.ts | 14 +- .../query-builders/optimizeTable.ts | 8 +- .../query-builders/optimizeTable.types.ts | 3 +- 6 files changed, 144 insertions(+), 16 deletions(-) create mode 100644 drizzle-orm/src/singlestore-core/columns/blob.ts diff --git a/drizzle-orm/src/singlestore-core/columns/blob.ts b/drizzle-orm/src/singlestore-core/columns/blob.ts new file mode 100644 index 0000000000..c1327a8ec8 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/blob.ts @@ -0,0 +1,121 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import { sql } from '~/sql/sql.ts'; +import type { Equal } from '~/utils'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreBlobBuilderInitial = SingleStoreBlobBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreBlob'; + data: Uint8Array; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBlobBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreBlobBuilder'; + + constructor(name: T['name'], _config?: SingleStoreBlobConfig) { + super(name, 'string', 'SingleStoreBlob'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBlob> { + return new SingleStoreBlob(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreBlob> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreBlob'; + + constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreBlobBuilder['config']) { + super(table, config); + } + + getSQLType(): string { + return 'binary(16)'; + } + + override mapToDriverValue(value: string) { + return sql`UNHEX(REPLACE(${value}, "-", ""))`; + } +} + +export type SingleStoreBlobStringBuilderInitial = SingleStoreBlobStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreBlobString'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBlobStringBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreBlobStringBuilder'; + + constructor(name: T['name'], _config?: SingleStoreBlobConfig) { + super(name, 'string', 'SingleStoreBlobString'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBlobString> { + return new SingleStoreBlobString(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreBlobString> + extends SingleStoreColumn +{ + static readonly [entityKind]: string = 'SingleStoreBlobString'; + + constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreBlobStringBuilder['config']) { + super(table, config); + } + + getSQLType(): string { + return 'binary(16)'; + } + + override mapToDriverValue(value: string) { + return sql`UNHEX(REPLACE(${value}, "-", ""))`; + } + + override mapFromDriverValue(value: Uint8Array): string { + const hex = Buffer.from(value).toString('hex'); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; + } +} + +export interface SingleStoreBlobConfig { + mode?: TMode; +} + +/** + * Creates a column with the data type `BINARY(16)` + * + * Use config `{ mode: "string" }` for a string representation of the Blob + */ +export function blob( + name: TName, + config?: SingleStoreBlobConfig, +): Equal extends true ? SingleStoreBlobStringBuilderInitial + : SingleStoreBlobBuilderInitial; +export function blob(name: string, config?: SingleStoreBlobConfig) { + if (config?.mode === 'string') { + return new SingleStoreBlobStringBuilder(name, config); + } + return new SingleStoreBlobBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/bson.ts b/drizzle-orm/src/singlestore-core/columns/bson.ts index cc12f23088..1f20778959 100644 --- a/drizzle-orm/src/singlestore-core/columns/bson.ts +++ b/drizzle-orm/src/singlestore-core/columns/bson.ts @@ -2,6 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreBsonBuilderInitial = SingleStoreBsonBuilder<{ @@ -41,8 +42,9 @@ export class SingleStoreBsonBSON`; } } diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 3b18ded3da..7c2c16ec4d 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -9,7 +9,9 @@ import type { DrizzleTypeError } from '~/utils.ts'; import type { SingleStoreDialect } from './dialect.ts'; import { SingleStoreAttachBase } from './query-builders/attach.ts'; import { SingleStoreBranchBase } from './query-builders/branch.ts'; +import { SingleStoreCreateMilestoneBase } from './query-builders/createMilestone.ts'; import { SingleStoreDetachBase } from './query-builders/detach.ts'; +import { SingleStoreDropMilestoneBase } from './query-builders/dropMilestone.ts'; import { QueryBuilder, SingleStoreDeleteBase, @@ -17,6 +19,8 @@ import { SingleStoreSelectBuilder, SingleStoreUpdateBuilder, } from './query-builders/index.ts'; +import { SingleStoreOptimizeTableBase } from './query-builders/optimizeTable.ts'; +import type { OptimizeTableArgument } from './query-builders/optimizeTable.types.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { @@ -30,10 +34,6 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { SingleStoreTable } from './table.ts'; -import { SingleStoreCreateMilestoneBase } from './query-builders/createMilestone.ts'; -import { SingleStoreDropMilestoneBase } from './query-builders/dropMilestone.ts'; -import { SingleStoreOptimizeTableBase } from './query-builders/optimizeTable.ts'; -import type { OptimizeTableArgument } from './query-builders/optimizeTable.types.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 0f6bb4063e..0f7fe64ab7 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -25,9 +25,12 @@ import { ViewBaseConfig } from '~/view-common.ts'; import { SingleStoreColumn } from './columns/common.ts'; import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; import type { SingleStoreBranchConfig } from './query-builders/branch.ts'; +import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; +import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; +import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; import type { SelectedFieldsOrdered, SingleStoreSelectConfig, @@ -37,9 +40,6 @@ import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; -import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; -import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; -import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -163,8 +163,12 @@ export class SingleStoreDialect { let warmBlobCacheForColumnSql = undefined; if (selection) { - const selectionField = selection.map((column) => { return { path: [], field: column } }); - warmBlobCacheForColumnSql = sql` warm blob cache for column ${this.buildSelection(selectionField, { isSingleTable: true })}`; + const selectionField = selection.map((column) => { + return { path: [], field: column }; + }); + warmBlobCacheForColumnSql = sql` warm blob cache for column ${ + this.buildSelection(selectionField, { isSingleTable: true }) + }`; } return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts index 7d1189ba84..daecb90e9c 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -1,4 +1,5 @@ import { entityKind } from '~/entity.ts'; +import type { ColumnBaseConfig, ColumnDataType } from '~/index.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { @@ -11,10 +12,9 @@ import type { SingleStoreSession, } from '~/singlestore-core/session.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; import type { SingleStoreTable } from '../table.ts'; import type { OptimizeTableArgument } from './optimizeTable.types.ts'; -import type { SingleStoreColumn } from '../columns/common.ts'; -import type { ColumnBaseConfig, ColumnDataType } from '~/index.ts'; export type SingleStoreOptimizeTableWithout< T extends AnySingleStoreOptimizeTableBase, @@ -107,7 +107,9 @@ export class SingleStoreOptimizeTableBase< } // TODO(singlestore): docs - warmBlobCacheForColumn(...selection: SingleStoreColumn, object>[]): SingleStoreOptimizeTableWithout { + warmBlobCacheForColumn( + ...selection: SingleStoreColumn, object>[] + ): SingleStoreOptimizeTableWithout { if (this.config.arg) { throw new Error('Cannot call warmBlobCacheForColumn with an argument'); } diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts index e82597337c..bb5993ab70 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.types.ts @@ -2,5 +2,4 @@ export type OptimizeTableArgument = | 'FULL' | 'FLUSH' | 'FIX_ALTER' - | 'INDEX' - + | 'INDEX'; From 10aec3341f4899c4478cb51540eeca5f6ad6c6b1 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 25 Jul 2024 11:15:15 +0100 Subject: [PATCH 050/152] new blob column type --- .../src/singlestore-core/columns/blob.ts | 155 +++++++++++------- 1 file changed, 96 insertions(+), 59 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/blob.ts b/drizzle-orm/src/singlestore-core/columns/blob.ts index c1327a8ec8..67de7cbf12 100644 --- a/drizzle-orm/src/singlestore-core/columns/blob.ts +++ b/drizzle-orm/src/singlestore-core/columns/blob.ts @@ -1,121 +1,158 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table'; -import { sql } from '~/sql/sql.ts'; import type { Equal } from '~/utils'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '../table'; -export type SingleStoreBlobBuilderInitial = SingleStoreBlobBuilder<{ +type BlobMode = 'buffer' | 'json' | 'bigint'; + +export type SingleStoreBigIntBuilderInitial = SingleStoreBigIntBuilder<{ name: TName; - dataType: 'string'; - columnType: 'SingleStoreBlob'; - data: Uint8Array; - driverParam: string; + dataType: 'bigint'; + columnType: 'SingleStoreBigInt'; + data: bigint; + driverParam: Buffer; enumValues: undefined; generated: undefined; }>; -export class SingleStoreBlobBuilder> - extends SingleStoreColumnBuilder +export class SingleStoreBigIntBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'SingleStoreBlobBuilder'; + static readonly [entityKind]: string = 'SingleStoreBigIntBuilder'; - constructor(name: T['name'], _config?: SingleStoreBlobConfig) { - super(name, 'string', 'SingleStoreBlob'); + constructor(name: T['name']) { + super(name, 'bigint', 'SingleStoreBigInt'); } /** @internal */ override build( table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreBlob> { - return new SingleStoreBlob(table, this.config as ColumnBuilderRuntimeConfig); + ): SingleStoreBigInt> { + return new SingleStoreBigInt>(table, this.config as ColumnBuilderRuntimeConfig); } } -export class SingleStoreBlob> extends SingleStoreColumn { - static readonly [entityKind]: string = 'SingleStoreBlob'; +export class SingleStoreBigInt> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreBigInt'; - constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreBlobBuilder['config']) { - super(table, config); + getSQLType(): string { + return 'blob'; } - getSQLType(): string { - return 'binary(16)'; + override mapFromDriverValue(value: Buffer): bigint { + return BigInt(value.toString()); } - override mapToDriverValue(value: string) { - return sql`UNHEX(REPLACE(${value}, "-", ""))`; + override mapToDriverValue(value: bigint): Buffer { + return Buffer.from(value.toString()); } } -export type SingleStoreBlobStringBuilderInitial = SingleStoreBlobStringBuilder<{ +export type SingleStoreBlobJsonBuilderInitial = SingleStoreBlobJsonBuilder<{ name: TName; - dataType: 'string'; - columnType: 'SingleStoreBlobString'; - data: string; - driverParam: string; + dataType: 'json'; + columnType: 'SingleStoreBlobJson'; + data: unknown; + driverParam: Buffer; enumValues: undefined; generated: undefined; }>; -export class SingleStoreBlobStringBuilder> - extends SingleStoreColumnBuilder +export class SingleStoreBlobJsonBuilder> + extends SingleStoreColumnBuilder { - static readonly [entityKind]: string = 'SingleStoreBlobStringBuilder'; + static readonly [entityKind]: string = 'SingleStoreBlobJsonBuilder'; - constructor(name: T['name'], _config?: SingleStoreBlobConfig) { - super(name, 'string', 'SingleStoreBlobString'); + constructor(name: T['name']) { + super(name, 'json', 'SingleStoreBlobJson'); } /** @internal */ override build( table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreBlobString> { - return new SingleStoreBlobString(table, this.config as ColumnBuilderRuntimeConfig); + ): SingleStoreBlobJson> { + return new SingleStoreBlobJson>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class SingleStoreBlobString> - extends SingleStoreColumn -{ - static readonly [entityKind]: string = 'SingleStoreBlobString'; +export class SingleStoreBlobJson> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreBlobJson'; - constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreBlobStringBuilder['config']) { - super(table, config); + getSQLType(): string { + return 'blob'; } - getSQLType(): string { - return 'binary(16)'; + override mapFromDriverValue(value: Buffer): T['data'] { + return JSON.parse(value.toString()); } - override mapToDriverValue(value: string) { - return sql`UNHEX(REPLACE(${value}, "-", ""))`; + override mapToDriverValue(value: T['data']): Buffer { + return Buffer.from(JSON.stringify(value)); } +} - override mapFromDriverValue(value: Uint8Array): string { - const hex = Buffer.from(value).toString('hex'); - return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; +export type SingleStoreBlobBufferBuilderInitial = SingleStoreBlobBufferBuilder<{ + name: TName; + dataType: 'buffer'; + columnType: 'SingleStoreBlobBuffer'; + data: Buffer; + driverParam: Buffer; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBlobBufferBuilder> + extends SingleStoreColumnBuilder +{ + static readonly [entityKind]: string = 'SingleStoreBlobBufferBuilder'; + + constructor(name: T['name']) { + super(name, 'buffer', 'SingleStoreBlobBuffer'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBlobBuffer> { + return new SingleStoreBlobBuffer>(table, this.config as ColumnBuilderRuntimeConfig); } } -export interface SingleStoreBlobConfig { - mode?: TMode; +export class SingleStoreBlobBuffer> extends SingleStoreColumn { + static readonly [entityKind]: string = 'SingleStoreBlobBuffer'; + + getSQLType(): string { + return 'blob'; + } +} + +export interface BlobConfig { + mode: TMode; } /** - * Creates a column with the data type `BINARY(16)` + * It's recommended to use `text('...', { mode: 'json' })` instead of `blob` in JSON mode, because it supports JSON functions: + * >All JSON functions currently throw an error if any of their arguments are BLOBs because BLOBs are reserved for a future enhancement in which BLOBs will store the binary encoding for JSON. * - * Use config `{ mode: "string" }` for a string representation of the Blob + * https://www.sqlite.org/json1.html */ -export function blob( +export function blob( name: TName, - config?: SingleStoreBlobConfig, -): Equal extends true ? SingleStoreBlobStringBuilderInitial - : SingleStoreBlobBuilderInitial; -export function blob(name: string, config?: SingleStoreBlobConfig) { - if (config?.mode === 'string') { - return new SingleStoreBlobStringBuilder(name, config); + config?: BlobConfig, +): Equal extends true ? SingleStoreBigIntBuilderInitial + : Equal extends true ? SingleStoreBlobBufferBuilderInitial + : SingleStoreBlobJsonBuilderInitial; +export function blob(name: string, config?: BlobConfig) { + if (config?.mode === 'json') { + return new SingleStoreBlobJsonBuilder(name); + } + if (config?.mode === 'bigint') { + return new SingleStoreBigIntBuilder(name); } - return new SingleStoreBlobBuilder(name, config); + return new SingleStoreBlobBufferBuilder(name); } From fba59c0de56cb7eba778c2f0ef796bf2df01346d Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 11:37:56 +0100 Subject: [PATCH 051/152] Try another approach for table type related typecheck --- drizzle-orm/src/singlestore-core/indexes.ts | 34 ++++-- drizzle-orm/src/singlestore-core/schema.ts | 4 +- drizzle-orm/src/singlestore-core/table.ts | 122 +++++++++++++++----- 3 files changed, 120 insertions(+), 40 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 59d2bfb11f..1fefaf3cc4 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -3,7 +3,7 @@ import type { SQL } from '~/sql/sql.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; import type { SingleStoreTable } from './table.ts'; -interface IndexConfig { +interface IndexCommonConfig { name: string; columns: IndexColumn[]; @@ -13,11 +13,6 @@ interface IndexConfig { */ unique?: boolean; - /** - * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. - */ - using?: 'btree' | 'hash'; - /** * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. */ @@ -29,6 +24,21 @@ interface IndexConfig { lock?: 'default' | 'none' | 'shared' | 'exclusive'; } +export type IndexColumnstoreConfig = IndexCommonConfig & { + /** + * If set, the index will be created as `create index ... using { 'hash' }`. + */ + using?: 'hash'; +}; +export type IndexRowstoreConfig = IndexCommonConfig & { + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; +}; + +type IndexConfig = IndexColumnstoreConfig | IndexRowstoreConfig; + export type IndexColumn = SingleStoreColumn | SQL; export class IndexBuilderOn { @@ -48,31 +58,31 @@ export interface AnyIndexBuilder { // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface IndexBuilder extends AnyIndexBuilder {} -export class IndexBuilder implements AnyIndexBuilder { +export class IndexBuilder implements AnyIndexBuilder { static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; /** @internal */ - config: IndexConfig; + config: TConfig; constructor(name: string, columns: IndexColumn[], unique: boolean) { this.config = { name, columns, unique, - }; + } as TConfig; } - using(using: IndexConfig['using']): this { + using(using: TConfig['using']): this { this.config.using = using; return this; } - algorythm(algorythm: IndexConfig['algorythm']): this { + algorythm(algorythm: TConfig['algorythm']): this { this.config.algorythm = algorythm; return this; } - lock(lock: IndexConfig['lock']): this { + lock(lock: TConfig['lock']): this { this.config.lock = lock; return this; } diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index 82da44a49e..77e4ee9f86 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -9,8 +9,8 @@ export class SingleStoreSchema { public readonly schemaName: TName, ) {} - table: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); + table: SingleStoreTableFn<'columnstore', TName> = (name, columns, extraConfig) => { + return singlestoreTableWithSchema('columnstore', name, columns, extraConfig, this.schemaName); }; view = ((name, columns) => { diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 529a95fe9c..f27ea0efff 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -2,20 +2,40 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts' import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; -import type { AnyIndexBuilder } from './indexes.ts'; +import type { IndexBuilder, IndexColumnstoreConfig, IndexRowstoreConfig } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -export type SingleStoreTableExtraConfig = Record< +type SinglestoreTableTypeTypes = { + columnstore: { + extraconfig: SingleStoreColumnstoreTableExtraConfig; + }; + rowstore: { + extraconfig: SingleStoreRowstoreTableExtraConfig; + }; +}; +type SinglestoreTableTypes = 'columnstore' | 'rowstore'; + +export type SingleStoreColumnstoreTableExtraConfig = Record< string, - | AnyIndexBuilder + | IndexBuilder + | PrimaryKeyBuilder + | UniqueConstraintBuilder +>; + +export type SingleStoreRowstoreTableExtraConfig = Record< + string, + | IndexBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; export type TableConfig = TableConfigBase; -export class SingleStoreTable extends Table { +export abstract class SingleStoreTable< + TTableType extends SinglestoreTableTypes = SinglestoreTableTypes, + T extends TableConfig = TableConfig, +> extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; declare protected $columns: T['columns']; @@ -28,44 +48,76 @@ export class SingleStoreTable extends Table /** @internal */ override [Table.Symbol.ExtraConfigBuilder]: - | ((self: Record) => SingleStoreTableExtraConfig) + | ((self: Record) => SinglestoreTableTypeTypes[TTableType]['extraconfig']) | undefined = undefined; } -export type AnySingleStoreTable = {}> = SingleStoreTable< - UpdateTableConfig ->; +export class SingleStoreColumnstoreTable + extends SingleStoreTable<'columnstore', T> +{ + static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; +} -export type SingleStoreTableWithColumns = - & SingleStoreTable +export class SingleStoreRowstoreTable extends SingleStoreTable<'rowstore', T> { + static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; +} + +export type AnySingleStoreTable = {}> = + | SingleStoreColumnstoreTable> + | SingleStoreRowstoreTable>; + +export type SingleStoreTableWithColumns = + & (SingleStoreTable) & { [Key in keyof T['columns']]: T['columns'][Key]; }; export function singlestoreTableWithSchema< + TTableType extends SinglestoreTableTypes, TTableName extends string, TSchemaName extends string | undefined, TColumnsMap extends Record, >( + tableType: TTableType, name: TTableName, columns: TColumnsMap, extraConfig: - | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | (( + self: BuildColumns, + ) => SinglestoreTableTypeTypes[TTableType]['extraconfig']) | undefined, schema: TSchemaName, baseName = name, -): SingleStoreTableWithColumns<{ +): SingleStoreTableWithColumns; dialect: 'singlestore'; }> { - const rawTable = new SingleStoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); + let rawTable; + switch (tableType) { + case 'columnstore': { + rawTable = new SingleStoreColumnstoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + break; + } + case 'rowstore': { + rawTable = new SingleStoreRowstoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + break; + } + default: { + throw new Error('Invalid table type'); + } + } const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { @@ -87,21 +139,26 @@ export function singlestoreTableWithSchema< if (extraConfig) { table[SingleStoreTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( self: Record, - ) => SingleStoreTableExtraConfig; + ) => SinglestoreTableTypeTypes[TTableType]['extraconfig']; } return table; } -export interface SingleStoreTableFn { +export interface SingleStoreTableFn< + TTableType extends SinglestoreTableTypes, + TSchemaName extends string | undefined = undefined, +> { < TTableName extends string, TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, - ): SingleStoreTableWithColumns<{ + extraConfig?: ( + self: BuildColumns, + ) => SinglestoreTableTypeTypes[TTableType]['extraconfig'], + ): SingleStoreTableWithColumns; @@ -109,12 +166,25 @@ export interface SingleStoreTableFn; } -export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); +export const singlestoreTable: SingleStoreTableFn<'columnstore'> = (name, columns, extraConfig) => { + return singlestoreTableWithSchema('columnstore', name, columns, extraConfig, undefined, name); +}; + +export const singlestoreRowstoreTable: SingleStoreTableFn<'rowstore'> = (name, columns, extraConfig) => { + return singlestoreTableWithSchema('rowstore', name, columns, extraConfig, undefined, name); }; -export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { +export function singlestoreTableCreator( + customizeTableName: (name: string) => string, +): SingleStoreTableFn<'columnstore'> { return (name, columns, extraConfig) => { - return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + return singlestoreTableWithSchema( + 'columnstore', + customizeTableName(name) as typeof name, + columns, + extraConfig, + undefined, + name, + ); }; } From fcddec02f8b510881e477033124da4d594dafb45 Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 11:41:58 +0100 Subject: [PATCH 052/152] Fixed build --- drizzle-orm/src/singlestore-core/table.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index f27ea0efff..bed4bc7a4d 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -66,7 +66,7 @@ export type AnySingleStoreTable = {}> = | SingleStoreColumnstoreTable> | SingleStoreRowstoreTable>; -export type SingleStoreTableWithColumns = +export type SingleStoreTableWithColumns = & (SingleStoreTable) & { [Key in keyof T['columns']]: T['columns'][Key]; @@ -88,12 +88,12 @@ export function singlestoreTableWithSchema< | undefined, schema: TSchemaName, baseName = name, -): SingleStoreTableWithColumns; dialect: 'singlestore'; -}> { +}, TTableType> { let rawTable; switch (tableType) { case 'columnstore': { @@ -158,12 +158,12 @@ export interface SingleStoreTableFn< extraConfig?: ( self: BuildColumns, ) => SinglestoreTableTypeTypes[TTableType]['extraconfig'], - ): SingleStoreTableWithColumns; dialect: 'singlestore'; - }>; + }, TTableType>; } export const singlestoreTable: SingleStoreTableFn<'columnstore'> = (name, columns, extraConfig) => { From 3b088706579246ed0535e25b00917256d4884000 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Thu, 25 Jul 2024 11:43:08 +0100 Subject: [PATCH 053/152] Even more nits to OPTIMIZE TABLE --- drizzle-orm/src/singlestore-core/dialect.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 0f7fe64ab7..b9eaa63efa 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -163,12 +163,10 @@ export class SingleStoreDialect { let warmBlobCacheForColumnSql = undefined; if (selection) { - const selectionField = selection.map((column) => { - return { path: [], field: column }; - }); - warmBlobCacheForColumnSql = sql` warm blob cache for column ${ - this.buildSelection(selectionField, { isSingleTable: true }) - }`; + const selectionField = selection.length > 0 ? + selection.map((column) => { return { path: [], field: column } }) + : [{ path: [], field: sql.raw('*') }]; + warmBlobCacheForColumnSql = sql` warm blob cache for column ${this.buildSelection(selectionField, { isSingleTable: true })}`; } return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; From 73486a0545f579dfb973d69f43265d4e843eaa9e Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 12:22:28 +0100 Subject: [PATCH 054/152] Revert table changes --- drizzle-orm/src/singlestore-core/indexes.ts | 34 ++---- drizzle-orm/src/singlestore-core/schema.ts | 4 +- drizzle-orm/src/singlestore-core/table.ts | 122 +++++--------------- 3 files changed, 40 insertions(+), 120 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 1fefaf3cc4..59d2bfb11f 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -3,7 +3,7 @@ import type { SQL } from '~/sql/sql.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; import type { SingleStoreTable } from './table.ts'; -interface IndexCommonConfig { +interface IndexConfig { name: string; columns: IndexColumn[]; @@ -13,6 +13,11 @@ interface IndexCommonConfig { */ unique?: boolean; + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; + /** * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. */ @@ -24,21 +29,6 @@ interface IndexCommonConfig { lock?: 'default' | 'none' | 'shared' | 'exclusive'; } -export type IndexColumnstoreConfig = IndexCommonConfig & { - /** - * If set, the index will be created as `create index ... using { 'hash' }`. - */ - using?: 'hash'; -}; -export type IndexRowstoreConfig = IndexCommonConfig & { - /** - * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. - */ - using?: 'btree' | 'hash'; -}; - -type IndexConfig = IndexColumnstoreConfig | IndexRowstoreConfig; - export type IndexColumn = SingleStoreColumn | SQL; export class IndexBuilderOn { @@ -58,31 +48,31 @@ export interface AnyIndexBuilder { // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface IndexBuilder extends AnyIndexBuilder {} -export class IndexBuilder implements AnyIndexBuilder { +export class IndexBuilder implements AnyIndexBuilder { static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; /** @internal */ - config: TConfig; + config: IndexConfig; constructor(name: string, columns: IndexColumn[], unique: boolean) { this.config = { name, columns, unique, - } as TConfig; + }; } - using(using: TConfig['using']): this { + using(using: IndexConfig['using']): this { this.config.using = using; return this; } - algorythm(algorythm: TConfig['algorythm']): this { + algorythm(algorythm: IndexConfig['algorythm']): this { this.config.algorythm = algorythm; return this; } - lock(lock: TConfig['lock']): this { + lock(lock: IndexConfig['lock']): this { this.config.lock = lock; return this; } diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index 77e4ee9f86..82da44a49e 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -9,8 +9,8 @@ export class SingleStoreSchema { public readonly schemaName: TName, ) {} - table: SingleStoreTableFn<'columnstore', TName> = (name, columns, extraConfig) => { - return singlestoreTableWithSchema('columnstore', name, columns, extraConfig, this.schemaName); + table: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); }; view = ((name, columns) => { diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index bed4bc7a4d..529a95fe9c 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -2,40 +2,20 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts' import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; -import type { IndexBuilder, IndexColumnstoreConfig, IndexRowstoreConfig } from './indexes.ts'; +import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -type SinglestoreTableTypeTypes = { - columnstore: { - extraconfig: SingleStoreColumnstoreTableExtraConfig; - }; - rowstore: { - extraconfig: SingleStoreRowstoreTableExtraConfig; - }; -}; -type SinglestoreTableTypes = 'columnstore' | 'rowstore'; - -export type SingleStoreColumnstoreTableExtraConfig = Record< +export type SingleStoreTableExtraConfig = Record< string, - | IndexBuilder - | PrimaryKeyBuilder - | UniqueConstraintBuilder ->; - -export type SingleStoreRowstoreTableExtraConfig = Record< - string, - | IndexBuilder + | AnyIndexBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; export type TableConfig = TableConfigBase; -export abstract class SingleStoreTable< - TTableType extends SinglestoreTableTypes = SinglestoreTableTypes, - T extends TableConfig = TableConfig, -> extends Table { +export class SingleStoreTable extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; declare protected $columns: T['columns']; @@ -48,43 +28,29 @@ export abstract class SingleStoreTable< /** @internal */ override [Table.Symbol.ExtraConfigBuilder]: - | ((self: Record) => SinglestoreTableTypeTypes[TTableType]['extraconfig']) + | ((self: Record) => SingleStoreTableExtraConfig) | undefined = undefined; } -export class SingleStoreColumnstoreTable - extends SingleStoreTable<'columnstore', T> -{ - static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; -} - -export class SingleStoreRowstoreTable extends SingleStoreTable<'rowstore', T> { - static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; -} - -export type AnySingleStoreTable = {}> = - | SingleStoreColumnstoreTable> - | SingleStoreRowstoreTable>; +export type AnySingleStoreTable = {}> = SingleStoreTable< + UpdateTableConfig +>; -export type SingleStoreTableWithColumns = - & (SingleStoreTable) +export type SingleStoreTableWithColumns = + & SingleStoreTable & { [Key in keyof T['columns']]: T['columns'][Key]; }; export function singlestoreTableWithSchema< - TTableType extends SinglestoreTableTypes, TTableName extends string, TSchemaName extends string | undefined, TColumnsMap extends Record, >( - tableType: TTableType, name: TTableName, columns: TColumnsMap, extraConfig: - | (( - self: BuildColumns, - ) => SinglestoreTableTypeTypes[TTableType]['extraconfig']) + | ((self: BuildColumns) => SingleStoreTableExtraConfig) | undefined, schema: TSchemaName, baseName = name, @@ -93,31 +59,13 @@ export function singlestoreTableWithSchema< schema: TSchemaName; columns: BuildColumns; dialect: 'singlestore'; -}, TTableType> { - let rawTable; - switch (tableType) { - case 'columnstore': { - rawTable = new SingleStoreColumnstoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); - break; - } - case 'rowstore': { - rawTable = new SingleStoreRowstoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); - break; - } - default: { - throw new Error('Invalid table type'); - } - } +}> { + const rawTable = new SingleStoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { @@ -139,52 +87,34 @@ export function singlestoreTableWithSchema< if (extraConfig) { table[SingleStoreTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( self: Record, - ) => SinglestoreTableTypeTypes[TTableType]['extraconfig']; + ) => SingleStoreTableExtraConfig; } return table; } -export interface SingleStoreTableFn< - TTableType extends SinglestoreTableTypes, - TSchemaName extends string | undefined = undefined, -> { +export interface SingleStoreTableFn { < TTableName extends string, TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig?: ( - self: BuildColumns, - ) => SinglestoreTableTypeTypes[TTableType]['extraconfig'], + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, ): SingleStoreTableWithColumns<{ name: TTableName; schema: TSchemaName; columns: BuildColumns; dialect: 'singlestore'; - }, TTableType>; + }>; } -export const singlestoreTable: SingleStoreTableFn<'columnstore'> = (name, columns, extraConfig) => { - return singlestoreTableWithSchema('columnstore', name, columns, extraConfig, undefined, name); -}; - -export const singlestoreRowstoreTable: SingleStoreTableFn<'rowstore'> = (name, columns, extraConfig) => { - return singlestoreTableWithSchema('rowstore', name, columns, extraConfig, undefined, name); +export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); }; -export function singlestoreTableCreator( - customizeTableName: (name: string) => string, -): SingleStoreTableFn<'columnstore'> { +export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { return (name, columns, extraConfig) => { - return singlestoreTableWithSchema( - 'columnstore', - customizeTableName(name) as typeof name, - columns, - extraConfig, - undefined, - name, - ); + return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); }; } From 24097f80ad6bc4b6f2c44bb95f8c9bb864a97473 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Thu, 25 Jul 2024 13:02:21 +0100 Subject: [PATCH 055/152] Add defaultCurrentTimestamp and fsp to defaultNow --- .../src/singlestore-core/columns/date.common.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts index 45dd668c91..9d3733ea60 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.common.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -8,6 +8,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { DatetimeFsp } from './datetime.ts'; export interface SingleStoreDateColumnBaseConfig { hasOnUpdateNow: boolean; @@ -20,8 +21,16 @@ export abstract class SingleStoreDateColumnBaseBuilder< > extends SingleStoreColumnBuilder { static readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; - defaultNow() { - return this.default(sql`(now())`); + defaultNow(fsp?: DatetimeFsp | undefined) { + return fsp ? + this.default(sql`(now(${fsp}))`) : + this.default(sql`(now())`); + } + + defaultCurrentTimestamp(fsp?: DatetimeFsp | undefined) { + return fsp ? + this.default(sql`(current_timestamp(${fsp}))`) : + this.default(sql`(current_timestamp())`); } // "on update now" also adds an implicit default value to the column - https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html From 43188c399d992cd935ff39fa8488c8eba31f2a7a Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 16:10:05 +0100 Subject: [PATCH 056/152] Separated tables into columnstore and rowstore --- drizzle-orm/src/singlestore-core/alias.ts | 2 +- .../src/singlestore-core/columns/bigint.ts | 2 +- .../src/singlestore-core/columns/binary.ts | 2 +- .../src/singlestore-core/columns/blob.ts | 2 +- .../src/singlestore-core/columns/boolean.ts | 2 +- .../src/singlestore-core/columns/bson.ts | 2 +- .../src/singlestore-core/columns/char.ts | 2 +- .../src/singlestore-core/columns/common.ts | 2 +- .../src/singlestore-core/columns/custom.ts | 2 +- .../src/singlestore-core/columns/date.ts | 2 +- .../src/singlestore-core/columns/datetime.ts | 2 +- .../src/singlestore-core/columns/decimal.ts | 2 +- .../src/singlestore-core/columns/double.ts | 2 +- .../src/singlestore-core/columns/enum.ts | 2 +- .../src/singlestore-core/columns/float.ts | 2 +- .../src/singlestore-core/columns/int.ts | 2 +- .../src/singlestore-core/columns/json.ts | 2 +- .../src/singlestore-core/columns/mediumint.ts | 2 +- .../src/singlestore-core/columns/real.ts | 2 +- .../src/singlestore-core/columns/serial.ts | 2 +- .../src/singlestore-core/columns/smallint.ts | 2 +- .../src/singlestore-core/columns/text.ts | 2 +- .../src/singlestore-core/columns/time.ts | 2 +- .../src/singlestore-core/columns/timestamp.ts | 2 +- .../src/singlestore-core/columns/tinyint.ts | 2 +- .../src/singlestore-core/columns/varbinary.ts | 2 +- .../src/singlestore-core/columns/varchar.ts | 2 +- .../src/singlestore-core/columns/year.ts | 2 +- drizzle-orm/src/singlestore-core/db.ts | 2 +- drizzle-orm/src/singlestore-core/dialect.ts | 2 +- drizzle-orm/src/singlestore-core/index.ts | 2 +- drizzle-orm/src/singlestore-core/indexes.ts | 2 +- .../src/singlestore-core/primary-keys.ts | 2 +- .../singlestore-core/query-builders/delete.ts | 2 +- .../singlestore-core/query-builders/insert.ts | 2 +- .../query-builders/optimizeTable.ts | 2 +- .../singlestore-core/query-builders/query.ts | 2 +- .../singlestore-core/query-builders/select.ts | 2 +- .../query-builders/select.types.ts | 2 +- .../singlestore-core/query-builders/update.ts | 2 +- drizzle-orm/src/singlestore-core/schema.ts | 2 +- .../singlestore-core/tables/columnstore.ts | 41 +++++++++++++++++++ .../{table.ts => tables/common.ts} | 33 +++++++-------- .../src/singlestore-core/tables/rowstore.ts | 41 +++++++++++++++++++ .../src/singlestore-core/unique-constraint.ts | 2 +- drizzle-orm/src/singlestore-core/utils.ts | 2 +- drizzle-orm/src/singlestore-core/view.ts | 2 +- 47 files changed, 140 insertions(+), 63 deletions(-) create mode 100644 drizzle-orm/src/singlestore-core/tables/columnstore.ts rename drizzle-orm/src/singlestore-core/{table.ts => tables/common.ts} (81%) create mode 100644 drizzle-orm/src/singlestore-core/tables/rowstore.ts diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts index 08e7ecc67a..2dc37f1c11 100644 --- a/drizzle-orm/src/singlestore-core/alias.ts +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -1,6 +1,6 @@ import { TableAliasProxyHandler } from '~/alias.ts'; import type { BuildAliasTable } from './query-builders/select.types.ts'; -import type { SingleStoreTable } from './table.ts'; +import type { SingleStoreTable } from './tables/common.ts'; import type { SingleStoreViewBase } from './view-base.ts'; export function alias( diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts index 6ea4a72978..c7b727b9d5 100644 --- a/drizzle-orm/src/singlestore-core/columns/bigint.ts +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts index 9cb05ac531..7fac9b78fc 100644 --- a/drizzle-orm/src/singlestore-core/columns/binary.ts +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/blob.ts b/drizzle-orm/src/singlestore-core/columns/blob.ts index 67de7cbf12..fbc8f3805b 100644 --- a/drizzle-orm/src/singlestore-core/columns/blob.ts +++ b/drizzle-orm/src/singlestore-core/columns/blob.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { Equal } from '~/utils'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import type { AnySingleStoreTable } from '../table'; +import type { AnySingleStoreTable } from '../tables/common.ts'; type BlobMode = 'buffer' | 'json' | 'bigint'; diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts index 795b12e7fa..37b528b74d 100644 --- a/drizzle-orm/src/singlestore-core/columns/boolean.ts +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/bson.ts b/drizzle-orm/src/singlestore-core/columns/bson.ts index 1f20778959..869e8f5276 100644 --- a/drizzle-orm/src/singlestore-core/columns/bson.ts +++ b/drizzle-orm/src/singlestore-core/columns/bson.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts index f59c173cb4..19e36791ed 100644 --- a/drizzle-orm/src/singlestore-core/columns/char.ts +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index 176265677b..2be8c012a7 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -13,7 +13,7 @@ import type { import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { SQL } from '~/sql/sql.ts'; import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts index 727099884f..35068994b2 100644 --- a/drizzle-orm/src/singlestore-core/columns/custom.ts +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { SQL } from '~/sql/sql.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts index 1c64fe3f16..2acc566994 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index f5d45629bd..f9f8fc9084 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index e5095c4d82..06251cfdb4 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts index 6ca945431c..6a618653fc 100644 --- a/drizzle-orm/src/singlestore-core/columns/double.ts +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts index af04c50a59..cb2076a557 100644 --- a/drizzle-orm/src/singlestore-core/columns/enum.ts +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index a54ee06a1a..f7af2829e2 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts index e9ca0a6822..9d1a8905ec 100644 --- a/drizzle-orm/src/singlestore-core/columns/int.ts +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts index 0b069f256d..69a1d1f9ea 100644 --- a/drizzle-orm/src/singlestore-core/columns/json.ts +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts index b963ee6e5d..52726cc2ac 100644 --- a/drizzle-orm/src/singlestore-core/columns/mediumint.ts +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts index cc66f6c569..7b60061ac9 100644 --- a/drizzle-orm/src/singlestore-core/columns/real.ts +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts index 30fb7a40ed..dd8722d349 100644 --- a/drizzle-orm/src/singlestore-core/columns/serial.ts +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -9,7 +9,7 @@ import type { } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreSerialBuilderInitial = IsAutoincrement< diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts index 02e1726081..616f09181c 100644 --- a/drizzle-orm/src/singlestore-core/columns/smallint.ts +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts index 8c40039f04..c7c2c2033e 100644 --- a/drizzle-orm/src/singlestore-core/columns/text.ts +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts index a5259adbb0..e4195c46ea 100644 --- a/drizzle-orm/src/singlestore-core/columns/time.ts +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index db770b6c73..6740d019dc 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts index d911cae96e..aa100a7c73 100644 --- a/drizzle-orm/src/singlestore-core/columns/tinyint.ts +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts index 545b87476f..516f5e8bc5 100644 --- a/drizzle-orm/src/singlestore-core/columns/varbinary.ts +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreVarBinaryBuilderInitial = SingleStoreVarBinaryBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts index 415b3c27bb..98df4c1fa6 100644 --- a/drizzle-orm/src/singlestore-core/columns/varchar.ts +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts index c774b44d81..7dc7047735 100644 --- a/drizzle-orm/src/singlestore-core/columns/year.ts +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 7c2c16ec4d..edb34d8df8 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -33,7 +33,7 @@ import type { SingleStoreTransactionConfig, } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; -import type { SingleStoreTable } from './table.ts'; +import type { SingleStoreTable } from './tables/common.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index b9eaa63efa..785320f442 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -38,7 +38,7 @@ import type { } from './query-builders/select.types.ts'; import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; -import { SingleStoreTable } from './table.ts'; +import { SingleStoreTable } from './tables/common.ts'; import { SingleStoreViewBase } from './view-base.ts'; export class SingleStoreDialect { diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts index 92c6b9a203..caa602f5b5 100644 --- a/drizzle-orm/src/singlestore-core/index.ts +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -8,7 +8,7 @@ export * from './query-builders/index.ts'; export * from './schema.ts'; export * from './session.ts'; export * from './subquery.ts'; -export * from './table.ts'; +export * from './tables/common.ts'; export * from './unique-constraint.ts'; export * from './utils.ts'; export * from './view-common.ts'; diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 59d2bfb11f..03ba82e5c8 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; -import type { SingleStoreTable } from './table.ts'; +import type { SingleStoreTable } from './tables/common.ts'; interface IndexConfig { name: string; diff --git a/drizzle-orm/src/singlestore-core/primary-keys.ts b/drizzle-orm/src/singlestore-core/primary-keys.ts index 47dc0a19cc..fb3b056079 100644 --- a/drizzle-orm/src/singlestore-core/primary-keys.ts +++ b/drizzle-orm/src/singlestore-core/primary-keys.ts @@ -1,6 +1,6 @@ import { entityKind } from '~/entity.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; -import { SingleStoreTable } from './table.ts'; +import { SingleStoreTable } from './tables/common.ts'; export function primaryKey< TTableName extends string, diff --git a/drizzle-orm/src/singlestore-core/query-builders/delete.ts b/drizzle-orm/src/singlestore-core/query-builders/delete.ts index e0a4637841..2c2e9bf518 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/delete.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/delete.ts @@ -10,7 +10,7 @@ import type { SingleStoreQueryResultKind, SingleStoreSession, } from '~/singlestore-core/session.ts'; -import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts index 129bf22146..79bc12a5a9 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/insert.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -11,7 +11,7 @@ import type { SingleStoreQueryResultKind, SingleStoreSession, } from '~/singlestore-core/session.ts'; -import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { InferModelFromColumns } from '~/table.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts index daecb90e9c..7e05788698 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -13,7 +13,7 @@ import type { } from '~/singlestore-core/session.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SingleStoreColumn } from '../columns/common.ts'; -import type { SingleStoreTable } from '../table.ts'; +import type { SingleStoreTable } from '../tables/common.ts'; import type { OptimizeTableArgument } from './optimizeTable.types.ts'; export type SingleStoreOptimizeTableWithout< diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts index 40d3f05adc..0678ff97b8 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/query.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -18,7 +18,7 @@ import type { SingleStorePreparedQueryConfig, SingleStoreSession, } from '../session.ts'; -import type { SingleStoreTable } from '../table.ts'; +import type { SingleStoreTable } from '../tables/common.ts'; export class RelationalQueryBuilder< TPreparedQueryHKT extends PreparedQueryHKTBase, diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts index 78cba92e05..ec2e97b3a4 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -20,7 +20,7 @@ import type { SingleStoreSession, } from '~/singlestore-core/session.ts'; import type { SubqueryWithSelection } from '~/singlestore-core/subquery.ts'; -import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { ColumnsSelection, Query } from '~/sql/sql.ts'; import { SQL, View } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts index 6db1cc3575..2b0ae666e3 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -17,7 +17,7 @@ import type { SetOperator, } from '~/query-builders/select.types.ts'; import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; -import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/table.ts'; +import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/tables/common.ts'; import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { Table, UpdateTableConfig } from '~/table.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts index d26394dfe5..a4b8b8296f 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/update.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -11,7 +11,7 @@ import type { SingleStoreQueryResultKind, SingleStoreSession, } from '~/singlestore-core/session.ts'; -import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import { mapUpdateSet, type UpdateSet } from '~/utils.ts'; diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index 82da44a49e..d6cdf057cc 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,5 +1,5 @@ import { entityKind, is } from '~/entity.ts'; -import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; +import { type SingleStoreTableFn, singlestoreTableWithSchema } from './tables/common.ts'; import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; export class SingleStoreSchema { diff --git a/drizzle-orm/src/singlestore-core/tables/columnstore.ts b/drizzle-orm/src/singlestore-core/tables/columnstore.ts new file mode 100644 index 0000000000..1604e3bfd6 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/tables/columnstore.ts @@ -0,0 +1,41 @@ +import { entityKind } from '~/entity.ts'; +import type { SingleStoreTableExtraConfig, SingleStoreTableFn, SingleStoreTableWithColumns, TableConfig } from './common.ts'; +import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; +import type { BuildColumns } from '~/column-builder.ts'; +import type { SingleStoreColumnBuilderBase } from '../columns/common.ts'; + +export class SingleStoreColumnstoreTable extends SingleStoreTable { + static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; +} + +export function singlestoreColumnstoreTableWithSchema< + TTableName extends string, + TSchemaName extends string | undefined, + TColumnsMap extends Record, +>( + name: TTableName, + columns: TColumnsMap, + extraConfig: + | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | undefined, + schema: TSchemaName, + baseName = name, +): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; +}> { + const rawTable = new SingleStoreColumnstoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + + return singlestoreTableWithSchema(rawTable, columns, extraConfig) +} + +export const singlestoreColumnstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreColumnstoreTableWithSchema(name, columns, extraConfig, undefined, name); +}; \ No newline at end of file diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/tables/common.ts similarity index 81% rename from drizzle-orm/src/singlestore-core/table.ts rename to drizzle-orm/src/singlestore-core/tables/common.ts index 529a95fe9c..586b833a97 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/tables/common.ts @@ -1,10 +1,11 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; -import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; -import type { AnyIndexBuilder } from './indexes.ts'; -import type { PrimaryKeyBuilder } from './primary-keys.ts'; -import type { UniqueConstraintBuilder } from './unique-constraint.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from '../columns/common.ts'; +import type { AnyIndexBuilder } from '../indexes.ts'; +import type { PrimaryKeyBuilder } from '../primary-keys.ts'; +import type { UniqueConstraintBuilder } from '../unique-constraint.ts'; +import { singlestoreColumnstoreTable } from './columnstore.ts'; export type SingleStoreTableExtraConfig = Record< string, @@ -15,7 +16,7 @@ export type SingleStoreTableExtraConfig = Record< export type TableConfig = TableConfigBase; -export class SingleStoreTable extends Table { +export abstract class SingleStoreTable extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; declare protected $columns: T['columns']; @@ -47,26 +48,22 @@ export function singlestoreTableWithSchema< TSchemaName extends string | undefined, TColumnsMap extends Record, >( - name: TTableName, + rawTable: SingleStoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>, columns: TColumnsMap, extraConfig: | ((self: BuildColumns) => SingleStoreTableExtraConfig) | undefined, - schema: TSchemaName, - baseName = name, ): SingleStoreTableWithColumns<{ name: TTableName; schema: TSchemaName; columns: BuildColumns; dialect: 'singlestore'; }> { - const rawTable = new SingleStoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); - const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as SingleStoreColumnBuilder; @@ -109,12 +106,10 @@ export interface SingleStoreTableFn; } -export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); -}; +export const singlestoreTable: SingleStoreTableFn = singlestoreColumnstoreTable; export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { return (name, columns, extraConfig) => { - return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + return singlestoreTable(customizeTableName(name) as typeof name, columns, extraConfig); }; } diff --git a/drizzle-orm/src/singlestore-core/tables/rowstore.ts b/drizzle-orm/src/singlestore-core/tables/rowstore.ts new file mode 100644 index 0000000000..d6efc04360 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/tables/rowstore.ts @@ -0,0 +1,41 @@ +import { entityKind } from '~/entity.ts'; +import type { SingleStoreTableExtraConfig, SingleStoreTableFn, SingleStoreTableWithColumns, TableConfig } from './common.ts'; +import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; +import type { BuildColumns } from '~/column-builder.ts'; +import type { SingleStoreColumnBuilderBase } from '../columns/common.ts'; + +export class SingleStoreRowstoreTable extends SingleStoreTable { + static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; +} + +export function singlestoreRowstoreTableWithSchema< + TTableName extends string, + TSchemaName extends string | undefined, + TColumnsMap extends Record, +>( + name: TTableName, + columns: TColumnsMap, + extraConfig: + | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | undefined, + schema: TSchemaName, + baseName = name, +): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; +}> { + const rawTable = new SingleStoreRowstoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + + return singlestoreTableWithSchema(rawTable, columns, extraConfig) +} + +export const singlestoreRowstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreRowstoreTableWithSchema(name, columns, extraConfig, undefined, name); +}; \ No newline at end of file diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts index faa4f3216f..6789206c0c 100644 --- a/drizzle-orm/src/singlestore-core/unique-constraint.ts +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -1,6 +1,6 @@ import { entityKind } from '~/entity.ts'; import type { SingleStoreColumn } from './columns/index.ts'; -import { SingleStoreTable } from './table.ts'; +import { SingleStoreTable } from './tables/common.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts index e6412161d6..8ae6fd80e6 100644 --- a/drizzle-orm/src/singlestore-core/utils.ts +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -5,7 +5,7 @@ import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; -import { SingleStoreTable } from './table.ts'; +import { SingleStoreTable } from './tables/common.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; import { SingleStoreViewConfig } from './view-common.ts'; import type { SingleStoreView } from './view.ts'; diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts index 3c6c8d25ca..c6262a5629 100644 --- a/drizzle-orm/src/singlestore-core/view.ts +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -8,7 +8,7 @@ import { getTableColumns } from '~/utils.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilderBase } from './columns/index.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; -import { singlestoreTable } from './table.ts'; +import { singlestoreTable } from './tables/common.ts'; import { SingleStoreViewBase } from './view-base.ts'; import { SingleStoreViewConfig } from './view-common.ts'; From 5f86590a3044b4e80e3340fdf57ce82ada2db49c Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 16:13:10 +0100 Subject: [PATCH 057/152] Fix build --- drizzle-orm/src/singlestore-core/columns/geography.ts | 2 +- drizzle-orm/src/singlestore-core/columns/geographypoint.ts | 2 +- drizzle-orm/src/singlestore-core/columns/guid.ts | 2 +- drizzle-orm/src/singlestore-core/columns/uuid.ts | 2 +- drizzle-orm/src/singlestore-core/columns/vector.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 8c4358e01d..8ccc03f99a 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -2,7 +2,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; import { DrizzleError } from '~/errors.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts index 46a2c594ca..4154c26718 100644 --- a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts +++ b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts @@ -1,7 +1,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; import type { LngLat } from './geography'; diff --git a/drizzle-orm/src/singlestore-core/columns/guid.ts b/drizzle-orm/src/singlestore-core/columns/guid.ts index 855e63bc88..1052331080 100644 --- a/drizzle-orm/src/singlestore-core/columns/guid.ts +++ b/drizzle-orm/src/singlestore-core/columns/guid.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { sql } from '~/sql/sql.ts'; import type { Equal } from '~/utils'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/uuid.ts b/drizzle-orm/src/singlestore-core/columns/uuid.ts index 41237ff802..8a551d79a7 100644 --- a/drizzle-orm/src/singlestore-core/columns/uuid.ts +++ b/drizzle-orm/src/singlestore-core/columns/uuid.ts @@ -1,7 +1,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreUUIDBuilderInitial = SingleStoreUUIDBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index 95c46976d0..768ef7f5a2 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -1,7 +1,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table'; +import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ From 08b4c4d249e951928ff2bd9d5a9c4b8a304b367b Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 16:18:41 +0100 Subject: [PATCH 058/152] Fix build v2 --- drizzle-orm/src/singlestore-core/schema.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index d6cdf057cc..c7fe072c8d 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,6 +1,7 @@ import { entityKind, is } from '~/entity.ts'; -import { type SingleStoreTableFn, singlestoreTableWithSchema } from './tables/common.ts'; +import type { SingleStoreTableFn } from './tables/common.ts'; import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; +import { singlestoreColumnstoreTableWithSchema } from './tables/columnstore.ts'; export class SingleStoreSchema { static readonly [entityKind]: string = 'SingleStoreSchema'; @@ -10,7 +11,7 @@ export class SingleStoreSchema { ) {} table: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); + return singlestoreColumnstoreTableWithSchema(name, columns, extraConfig, this.schemaName); }; view = ((name, columns) => { From b83f2b7ca53353af94d52a9c938afca8d4fb9e46 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 11:54:44 -0400 Subject: [PATCH 059/152] fix geography data type --- drizzle-orm/src/singlestore-core/columns/geography.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 8ccc03f99a..58c455c7ef 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -27,7 +27,7 @@ export type SingleStoreGeographyBuilderInitial = SingleSto name: TName; dataType: 'array'; columnType: 'SingleStoreGeography'; - data: GeographyPoint | GeographyLineString | GeographyPolygon; + data: Geography; driverParam: string; enumValues: undefined; generated: undefined; From 021bf75660d9d8af8a40852438eb5b7204435a24 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 12:06:30 -0400 Subject: [PATCH 060/152] fix geography type v2 --- .../src/singlestore-core/columns/geography.ts | 36 +++++-------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 58c455c7ef..5275f4da81 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -12,22 +12,11 @@ type GeographyPoint = LngLat; type GeographyLineString = Array; type GeographyPolygon = Array>; -type Geography = { - __type: 'POINT'; - data: GeographyPoint; -} | { - __type: 'LINESTRING'; - data: GeographyLineString; -} | { - __type: 'POLYGON'; - data: GeographyPolygon; -}; - export type SingleStoreGeographyBuilderInitial = SingleStoreGeographyBuilder<{ name: TName; dataType: 'array'; columnType: 'SingleStoreGeography'; - data: Geography; + data: GeographyPoint | GeographyLineString | GeographyPolygon; driverParam: string; enumValues: undefined; generated: undefined; @@ -87,33 +76,24 @@ export class SingleStoreGeography pair.split(' ').map(Number)) as GeographyLineString, - }; + return pairs.map((pair) => pair.split(' ').map(Number)) as GeographyLineString; } case 'POLYGON': { const rings = inner.slice(1, -1).split('), ('); - return { - __type, - data: rings.map((ring) => { - const pairs = ring.split(', '); - return pairs.map((pair) => pair.split(' ').map(Number)); - }) as GeographyPolygon, - }; + return rings.map((ring) => { + const pairs = ring.split(', '); + return pairs.map((pair) => pair.split(' ').map(Number)); + }) as GeographyPolygon; } default: { throw new DrizzleError({ message: 'Unexpected Geography type' }); From d1dbe61e5c6dfe4f84a3604de56e830ecf7414ad Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 12:06:39 -0400 Subject: [PATCH 061/152] lint/fmt --- .../src/singlestore-core/columns/blob.ts | 20 ++++++++++++++----- .../singlestore-core/columns/date.common.ts | 12 +++++------ drizzle-orm/src/singlestore-core/dialect.ts | 10 +++++++--- drizzle-orm/src/singlestore-core/schema.ts | 2 +- .../singlestore-core/tables/columnstore.ts | 15 +++++++++----- .../src/singlestore-core/tables/rowstore.ts | 15 +++++++++----- 6 files changed, 49 insertions(+), 25 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/blob.ts b/drizzle-orm/src/singlestore-core/columns/blob.ts index fbc8f3805b..1e42f33324 100644 --- a/drizzle-orm/src/singlestore-core/columns/blob.ts +++ b/drizzle-orm/src/singlestore-core/columns/blob.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { Equal } from '~/utils'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; import type { AnySingleStoreTable } from '../tables/common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; type BlobMode = 'buffer' | 'json' | 'bigint'; @@ -30,7 +30,10 @@ export class SingleStoreBigIntBuilder( table: AnySingleStoreTable<{ name: TTableName }>, ): SingleStoreBigInt> { - return new SingleStoreBigInt>(table, this.config as ColumnBuilderRuntimeConfig); + return new SingleStoreBigInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } @@ -80,7 +83,9 @@ export class SingleStoreBlobJsonBuilder> extends SingleStoreColumn { +export class SingleStoreBlobJson> + extends SingleStoreColumn +{ static readonly [entityKind]: string = 'SingleStoreBlobJson'; getSQLType(): string { @@ -119,11 +124,16 @@ export class SingleStoreBlobBufferBuilder( table: AnySingleStoreTable<{ name: TTableName }>, ): SingleStoreBlobBuffer> { - return new SingleStoreBlobBuffer>(table, this.config as ColumnBuilderRuntimeConfig); + return new SingleStoreBlobBuffer>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class SingleStoreBlobBuffer> extends SingleStoreColumn { +export class SingleStoreBlobBuffer> + extends SingleStoreColumn +{ static readonly [entityKind]: string = 'SingleStoreBlobBuffer'; getSQLType(): string { diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts index 9d3733ea60..a02e7cc003 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.common.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -22,15 +22,15 @@ export abstract class SingleStoreDateColumnBaseBuilder< static readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; defaultNow(fsp?: DatetimeFsp | undefined) { - return fsp ? - this.default(sql`(now(${fsp}))`) : - this.default(sql`(now())`); + return fsp + ? this.default(sql`(now(${fsp}))`) + : this.default(sql`(now())`); } defaultCurrentTimestamp(fsp?: DatetimeFsp | undefined) { - return fsp ? - this.default(sql`(current_timestamp(${fsp}))`) : - this.default(sql`(current_timestamp())`); + return fsp + ? this.default(sql`(current_timestamp(${fsp}))`) + : this.default(sql`(current_timestamp())`); } // "on update now" also adds an implicit default value to the column - https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 785320f442..4858b88653 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -163,10 +163,14 @@ export class SingleStoreDialect { let warmBlobCacheForColumnSql = undefined; if (selection) { - const selectionField = selection.length > 0 ? - selection.map((column) => { return { path: [], field: column } }) + const selectionField = selection.length > 0 + ? selection.map((column) => { + return { path: [], field: column }; + }) : [{ path: [], field: sql.raw('*') }]; - warmBlobCacheForColumnSql = sql` warm blob cache for column ${this.buildSelection(selectionField, { isSingleTable: true })}`; + warmBlobCacheForColumnSql = sql` warm blob cache for column ${ + this.buildSelection(selectionField, { isSingleTable: true }) + }`; } return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index c7fe072c8d..71dbda4cab 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,7 +1,7 @@ import { entityKind, is } from '~/entity.ts'; +import { singlestoreColumnstoreTableWithSchema } from './tables/columnstore.ts'; import type { SingleStoreTableFn } from './tables/common.ts'; import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; -import { singlestoreColumnstoreTableWithSchema } from './tables/columnstore.ts'; export class SingleStoreSchema { static readonly [entityKind]: string = 'SingleStoreSchema'; diff --git a/drizzle-orm/src/singlestore-core/tables/columnstore.ts b/drizzle-orm/src/singlestore-core/tables/columnstore.ts index 1604e3bfd6..34a18bca0e 100644 --- a/drizzle-orm/src/singlestore-core/tables/columnstore.ts +++ b/drizzle-orm/src/singlestore-core/tables/columnstore.ts @@ -1,8 +1,13 @@ -import { entityKind } from '~/entity.ts'; -import type { SingleStoreTableExtraConfig, SingleStoreTableFn, SingleStoreTableWithColumns, TableConfig } from './common.ts'; -import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; import type { BuildColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; import type { SingleStoreColumnBuilderBase } from '../columns/common.ts'; +import type { + SingleStoreTableExtraConfig, + SingleStoreTableFn, + SingleStoreTableWithColumns, + TableConfig, +} from './common.ts'; +import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; export class SingleStoreColumnstoreTable extends SingleStoreTable { static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; @@ -33,9 +38,9 @@ export function singlestoreColumnstoreTableWithSchema< dialect: 'singlestore'; }>(name, schema, baseName); - return singlestoreTableWithSchema(rawTable, columns, extraConfig) + return singlestoreTableWithSchema(rawTable, columns, extraConfig); } export const singlestoreColumnstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { return singlestoreColumnstoreTableWithSchema(name, columns, extraConfig, undefined, name); -}; \ No newline at end of file +}; diff --git a/drizzle-orm/src/singlestore-core/tables/rowstore.ts b/drizzle-orm/src/singlestore-core/tables/rowstore.ts index d6efc04360..c6302b3878 100644 --- a/drizzle-orm/src/singlestore-core/tables/rowstore.ts +++ b/drizzle-orm/src/singlestore-core/tables/rowstore.ts @@ -1,8 +1,13 @@ -import { entityKind } from '~/entity.ts'; -import type { SingleStoreTableExtraConfig, SingleStoreTableFn, SingleStoreTableWithColumns, TableConfig } from './common.ts'; -import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; import type { BuildColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; import type { SingleStoreColumnBuilderBase } from '../columns/common.ts'; +import type { + SingleStoreTableExtraConfig, + SingleStoreTableFn, + SingleStoreTableWithColumns, + TableConfig, +} from './common.ts'; +import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; export class SingleStoreRowstoreTable extends SingleStoreTable { static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; @@ -33,9 +38,9 @@ export function singlestoreRowstoreTableWithSchema< dialect: 'singlestore'; }>(name, schema, baseName); - return singlestoreTableWithSchema(rawTable, columns, extraConfig) + return singlestoreTableWithSchema(rawTable, columns, extraConfig); } export const singlestoreRowstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { return singlestoreRowstoreTableWithSchema(name, columns, extraConfig, undefined, name); -}; \ No newline at end of file +}; From b8686fafb6323bd71f1e291f6eb6e8d021768106 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Thu, 25 Jul 2024 17:11:59 +0100 Subject: [PATCH 062/152] nits with datetime --- .../src/singlestore-core/columns/datetime.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index f9f8fc9084..700fce96ef 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -4,6 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import { sql } from '~/sql/sql.ts'; export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ name: TName; @@ -25,6 +26,18 @@ export class SingleStoreDateTimeBuilder( table: AnySingleStoreTable<{ name: TTableName }>, From dd8ffbdf81feedb01ffd965b50c190fdebde18f3 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 14:30:48 -0400 Subject: [PATCH 063/152] improve geography code readability --- .../src/singlestore-core/columns/geography.ts | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 5275f4da81..dabfdea5f0 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -82,18 +82,13 @@ export class SingleStoreGeography pair.split(' ').map(Number)) as GeographyLineString; + return _linestringToGeographyLineString(inner); } case 'POLYGON': { - const rings = inner.slice(1, -1).split('), ('); - return rings.map((ring) => { - const pairs = ring.split(', '); - return pairs.map((pair) => pair.split(' ').map(Number)); - }) as GeographyPolygon; + return _polygonToGeographyPolygon(inner); } default: { throw new DrizzleError({ message: 'Unexpected Geography type' }); @@ -106,6 +101,20 @@ export function geography(name: TName): SingleStoreGeograp return new SingleStoreGeographyBuilder(name); } +function _pointToGeographyPoint(value: string): GeographyPoint { + return value.split(' ').map(Number) as GeographyPoint; +} + +function _linestringToGeographyLineString(value: string): GeographyLineString { + const pairs = value.split(', '); + return pairs.map((pair) => _pointToGeographyPoint(pair)); +} + +function _polygonToGeographyPolygon(value: string): GeographyPolygon { + const rings = value.slice(1, -1).split('), ('); + return rings.map((ring) => _linestringToGeographyLineString(ring)); +} + function _isPoint(value: GeographyPoint | GeographyLineString | GeographyPolygon): value is GeographyPoint { return value.length === 2 && typeof value[0] === 'number'; } From 1d7e53b69c998535bc1271c326d7cffe61afcd18 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 14:30:58 -0400 Subject: [PATCH 064/152] lint/fmt datetime --- .../src/singlestore-core/columns/datetime.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index 700fce96ef..6aa237627e 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import { sql } from '~/sql/sql.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import { sql } from '~/sql/sql.ts'; export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ name: TName; @@ -27,15 +27,15 @@ export class SingleStoreDateTimeBuilder Date: Thu, 25 Jul 2024 14:41:59 -0400 Subject: [PATCH 065/152] improve readability in geography mapToDriverValue --- .../src/singlestore-core/columns/geography.ts | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index dabfdea5f0..65a6148137 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -3,6 +3,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import { entityKind } from '~/entity.ts'; import { DrizzleError } from '~/errors.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { SQL} from '~/sql/sql.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -60,17 +61,11 @@ export class SingleStoreGeography sql`${ls[0]} ${ls[1]}`); - return sql`"LINESTRING(${sql.join(points, sql.raw(', '))})"`; + return sql`"LINESTRING(${_toLineStringSQL(value)})"`; } else if (_isPolygon(value)) { - const rings = value.map((ring) => { - const points = ring.map((point) => sql`${point[0]} ${point[1]}`); - return sql`(${sql.join(points, sql.raw(', '))})`; - }); - return sql`"POLYGON(${sql.join(rings, sql.raw(', '))})"`; + return sql`"POLYGON((${_toPolygonSQL(value)}))"`; } else { throw new DrizzleError({ message: 'value is not Array' }); } @@ -101,6 +96,20 @@ export function geography(name: TName): SingleStoreGeograp return new SingleStoreGeographyBuilder(name); } +function _toPointSQL([lng, lat]: GeographyPoint): SQL { + return sql`${lng} ${lat}`; +} + +function _toLineStringSQL(linestring: GeographyLineString): SQL { + const points = linestring.map((point) => _toPointSQL(point)); + return sql.join(points, sql.raw(', ')); +} + +function _toPolygonSQL(polygon: GeographyPolygon): SQL { + const rings = polygon.map((linestring) => _toLineStringSQL(linestring)); + return sql.join(rings, sql.raw(', ')); +} + function _pointToGeographyPoint(value: string): GeographyPoint { return value.split(' ').map(Number) as GeographyPoint; } From f2b712818c67e3797fae6db2ae86210cf4947249 Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 19:47:02 +0100 Subject: [PATCH 066/152] Undo changes to differentiate tables --- drizzle-orm/src/singlestore-core/alias.ts | 2 +- .../src/singlestore-core/columns/bigint.ts | 2 +- .../src/singlestore-core/columns/binary.ts | 2 +- .../src/singlestore-core/columns/blob.ts | 2 +- .../src/singlestore-core/columns/boolean.ts | 2 +- .../src/singlestore-core/columns/bson.ts | 2 +- .../src/singlestore-core/columns/char.ts | 2 +- .../src/singlestore-core/columns/common.ts | 2 +- .../src/singlestore-core/columns/custom.ts | 2 +- .../src/singlestore-core/columns/date.ts | 2 +- .../src/singlestore-core/columns/datetime.ts | 3 +- .../src/singlestore-core/columns/decimal.ts | 2 +- .../src/singlestore-core/columns/double.ts | 2 +- .../src/singlestore-core/columns/enum.ts | 2 +- .../src/singlestore-core/columns/float.ts | 2 +- .../src/singlestore-core/columns/int.ts | 2 +- .../src/singlestore-core/columns/json.ts | 2 +- .../src/singlestore-core/columns/mediumint.ts | 2 +- .../src/singlestore-core/columns/real.ts | 2 +- .../src/singlestore-core/columns/serial.ts | 2 +- .../src/singlestore-core/columns/smallint.ts | 2 +- .../src/singlestore-core/columns/text.ts | 2 +- .../src/singlestore-core/columns/time.ts | 2 +- .../src/singlestore-core/columns/timestamp.ts | 2 +- .../src/singlestore-core/columns/tinyint.ts | 2 +- .../src/singlestore-core/columns/varbinary.ts | 2 +- .../src/singlestore-core/columns/varchar.ts | 2 +- .../src/singlestore-core/columns/year.ts | 2 +- drizzle-orm/src/singlestore-core/db.ts | 2 +- drizzle-orm/src/singlestore-core/dialect.ts | 2 +- drizzle-orm/src/singlestore-core/index.ts | 2 +- drizzle-orm/src/singlestore-core/indexes.ts | 2 +- .../src/singlestore-core/primary-keys.ts | 2 +- .../singlestore-core/query-builders/delete.ts | 2 +- .../singlestore-core/query-builders/insert.ts | 2 +- .../query-builders/optimizeTable.ts | 2 +- .../singlestore-core/query-builders/query.ts | 2 +- .../singlestore-core/query-builders/select.ts | 2 +- .../query-builders/select.types.ts | 2 +- .../singlestore-core/query-builders/update.ts | 2 +- drizzle-orm/src/singlestore-core/schema.ts | 5 +- .../{tables/common.ts => table.ts} | 33 +++++++------ .../singlestore-core/tables/columnstore.ts | 46 ------------------- .../src/singlestore-core/tables/rowstore.ts | 46 ------------------- .../src/singlestore-core/unique-constraint.ts | 2 +- drizzle-orm/src/singlestore-core/utils.ts | 2 +- drizzle-orm/src/singlestore-core/view.ts | 2 +- 47 files changed, 64 insertions(+), 153 deletions(-) rename drizzle-orm/src/singlestore-core/{tables/common.ts => table.ts} (81%) delete mode 100644 drizzle-orm/src/singlestore-core/tables/columnstore.ts delete mode 100644 drizzle-orm/src/singlestore-core/tables/rowstore.ts diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts index 2dc37f1c11..08e7ecc67a 100644 --- a/drizzle-orm/src/singlestore-core/alias.ts +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -1,6 +1,6 @@ import { TableAliasProxyHandler } from '~/alias.ts'; import type { BuildAliasTable } from './query-builders/select.types.ts'; -import type { SingleStoreTable } from './tables/common.ts'; +import type { SingleStoreTable } from './table.ts'; import type { SingleStoreViewBase } from './view-base.ts'; export function alias( diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts index c7b727b9d5..6ea4a72978 100644 --- a/drizzle-orm/src/singlestore-core/columns/bigint.ts +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts index 7fac9b78fc..9cb05ac531 100644 --- a/drizzle-orm/src/singlestore-core/columns/binary.ts +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/blob.ts b/drizzle-orm/src/singlestore-core/columns/blob.ts index 1e42f33324..c30e2c0c97 100644 --- a/drizzle-orm/src/singlestore-core/columns/blob.ts +++ b/drizzle-orm/src/singlestore-core/columns/blob.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { Equal } from '~/utils'; -import type { AnySingleStoreTable } from '../tables/common.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { AnySingleStoreTable } from '../table'; type BlobMode = 'buffer' | 'json' | 'bigint'; diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts index 37b528b74d..795b12e7fa 100644 --- a/drizzle-orm/src/singlestore-core/columns/boolean.ts +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/bson.ts b/drizzle-orm/src/singlestore-core/columns/bson.ts index 869e8f5276..1f20778959 100644 --- a/drizzle-orm/src/singlestore-core/columns/bson.ts +++ b/drizzle-orm/src/singlestore-core/columns/bson.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts index 19e36791ed..f59c173cb4 100644 --- a/drizzle-orm/src/singlestore-core/columns/char.ts +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index 2be8c012a7..176265677b 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -13,7 +13,7 @@ import type { import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts index 35068994b2..727099884f 100644 --- a/drizzle-orm/src/singlestore-core/columns/custom.ts +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts index 2acc566994..1c64fe3f16 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index 6aa237627e..2557e26b58 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -1,8 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; -import { sql } from '~/sql/sql.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index 06251cfdb4..e5095c4d82 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts index 6a618653fc..6ca945431c 100644 --- a/drizzle-orm/src/singlestore-core/columns/double.ts +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts index cb2076a557..af04c50a59 100644 --- a/drizzle-orm/src/singlestore-core/columns/enum.ts +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index f7af2829e2..a54ee06a1a 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts index 9d1a8905ec..e9ca0a6822 100644 --- a/drizzle-orm/src/singlestore-core/columns/int.ts +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts index 69a1d1f9ea..0b069f256d 100644 --- a/drizzle-orm/src/singlestore-core/columns/json.ts +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts index 52726cc2ac..b963ee6e5d 100644 --- a/drizzle-orm/src/singlestore-core/columns/mediumint.ts +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts index 7b60061ac9..cc66f6c569 100644 --- a/drizzle-orm/src/singlestore-core/columns/real.ts +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts index dd8722d349..30fb7a40ed 100644 --- a/drizzle-orm/src/singlestore-core/columns/serial.ts +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -9,7 +9,7 @@ import type { } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreSerialBuilderInitial = IsAutoincrement< diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts index 616f09181c..02e1726081 100644 --- a/drizzle-orm/src/singlestore-core/columns/smallint.ts +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts index c7c2c2033e..8c40039f04 100644 --- a/drizzle-orm/src/singlestore-core/columns/text.ts +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts index e4195c46ea..a5259adbb0 100644 --- a/drizzle-orm/src/singlestore-core/columns/time.ts +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index 6740d019dc..db770b6c73 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts index aa100a7c73..d911cae96e 100644 --- a/drizzle-orm/src/singlestore-core/columns/tinyint.ts +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts index 516f5e8bc5..545b87476f 100644 --- a/drizzle-orm/src/singlestore-core/columns/varbinary.ts +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreVarBinaryBuilderInitial = SingleStoreVarBinaryBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts index 98df4c1fa6..415b3c27bb 100644 --- a/drizzle-orm/src/singlestore-core/columns/varchar.ts +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import type { Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts index 7dc7047735..c774b44d81 100644 --- a/drizzle-orm/src/singlestore-core/columns/year.ts +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index edb34d8df8..7c2c16ec4d 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -33,7 +33,7 @@ import type { SingleStoreTransactionConfig, } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; -import type { SingleStoreTable } from './tables/common.ts'; +import type { SingleStoreTable } from './table.ts'; export class SingleStoreDatabase< TQueryResult extends SingleStoreQueryResultHKT, diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 4858b88653..453c2dacf5 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -38,7 +38,7 @@ import type { } from './query-builders/select.types.ts'; import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; -import { SingleStoreTable } from './tables/common.ts'; +import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; export class SingleStoreDialect { diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts index caa602f5b5..92c6b9a203 100644 --- a/drizzle-orm/src/singlestore-core/index.ts +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -8,7 +8,7 @@ export * from './query-builders/index.ts'; export * from './schema.ts'; export * from './session.ts'; export * from './subquery.ts'; -export * from './tables/common.ts'; +export * from './table.ts'; export * from './unique-constraint.ts'; export * from './utils.ts'; export * from './view-common.ts'; diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 03ba82e5c8..59d2bfb11f 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; -import type { SingleStoreTable } from './tables/common.ts'; +import type { SingleStoreTable } from './table.ts'; interface IndexConfig { name: string; diff --git a/drizzle-orm/src/singlestore-core/primary-keys.ts b/drizzle-orm/src/singlestore-core/primary-keys.ts index fb3b056079..47dc0a19cc 100644 --- a/drizzle-orm/src/singlestore-core/primary-keys.ts +++ b/drizzle-orm/src/singlestore-core/primary-keys.ts @@ -1,6 +1,6 @@ import { entityKind } from '~/entity.ts'; import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; -import { SingleStoreTable } from './tables/common.ts'; +import { SingleStoreTable } from './table.ts'; export function primaryKey< TTableName extends string, diff --git a/drizzle-orm/src/singlestore-core/query-builders/delete.ts b/drizzle-orm/src/singlestore-core/query-builders/delete.ts index 2c2e9bf518..e0a4637841 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/delete.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/delete.ts @@ -10,7 +10,7 @@ import type { SingleStoreQueryResultKind, SingleStoreSession, } from '~/singlestore-core/session.ts'; -import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts index 79bc12a5a9..129bf22146 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/insert.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -11,7 +11,7 @@ import type { SingleStoreQueryResultKind, SingleStoreSession, } from '~/singlestore-core/session.ts'; -import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { InferModelFromColumns } from '~/table.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts index 7e05788698..daecb90e9c 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -13,7 +13,7 @@ import type { } from '~/singlestore-core/session.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SingleStoreColumn } from '../columns/common.ts'; -import type { SingleStoreTable } from '../tables/common.ts'; +import type { SingleStoreTable } from '../table.ts'; import type { OptimizeTableArgument } from './optimizeTable.types.ts'; export type SingleStoreOptimizeTableWithout< diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts index 0678ff97b8..40d3f05adc 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/query.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -18,7 +18,7 @@ import type { SingleStorePreparedQueryConfig, SingleStoreSession, } from '../session.ts'; -import type { SingleStoreTable } from '../tables/common.ts'; +import type { SingleStoreTable } from '../table.ts'; export class RelationalQueryBuilder< TPreparedQueryHKT extends PreparedQueryHKTBase, diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts index ec2e97b3a4..78cba92e05 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -20,7 +20,7 @@ import type { SingleStoreSession, } from '~/singlestore-core/session.ts'; import type { SubqueryWithSelection } from '~/singlestore-core/subquery.ts'; -import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { ColumnsSelection, Query } from '~/sql/sql.ts'; import { SQL, View } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts index 2b0ae666e3..6db1cc3575 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -17,7 +17,7 @@ import type { SetOperator, } from '~/query-builders/select.types.ts'; import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; -import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/tables/common.ts'; +import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/table.ts'; import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { Table, UpdateTableConfig } from '~/table.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts index a4b8b8296f..d26394dfe5 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/update.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -11,7 +11,7 @@ import type { SingleStoreQueryResultKind, SingleStoreSession, } from '~/singlestore-core/session.ts'; -import type { SingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import { mapUpdateSet, type UpdateSet } from '~/utils.ts'; diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index 71dbda4cab..82da44a49e 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,6 +1,5 @@ import { entityKind, is } from '~/entity.ts'; -import { singlestoreColumnstoreTableWithSchema } from './tables/columnstore.ts'; -import type { SingleStoreTableFn } from './tables/common.ts'; +import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; export class SingleStoreSchema { @@ -11,7 +10,7 @@ export class SingleStoreSchema { ) {} table: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreColumnstoreTableWithSchema(name, columns, extraConfig, this.schemaName); + return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); }; view = ((name, columns) => { diff --git a/drizzle-orm/src/singlestore-core/tables/common.ts b/drizzle-orm/src/singlestore-core/table.ts similarity index 81% rename from drizzle-orm/src/singlestore-core/tables/common.ts rename to drizzle-orm/src/singlestore-core/table.ts index 586b833a97..529a95fe9c 100644 --- a/drizzle-orm/src/singlestore-core/tables/common.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -1,11 +1,10 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; -import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from '../columns/common.ts'; -import type { AnyIndexBuilder } from '../indexes.ts'; -import type { PrimaryKeyBuilder } from '../primary-keys.ts'; -import type { UniqueConstraintBuilder } from '../unique-constraint.ts'; -import { singlestoreColumnstoreTable } from './columnstore.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; +import type { AnyIndexBuilder } from './indexes.ts'; +import type { PrimaryKeyBuilder } from './primary-keys.ts'; +import type { UniqueConstraintBuilder } from './unique-constraint.ts'; export type SingleStoreTableExtraConfig = Record< string, @@ -16,7 +15,7 @@ export type SingleStoreTableExtraConfig = Record< export type TableConfig = TableConfigBase; -export abstract class SingleStoreTable extends Table { +export class SingleStoreTable extends Table { static readonly [entityKind]: string = 'SingleStoreTable'; declare protected $columns: T['columns']; @@ -48,22 +47,26 @@ export function singlestoreTableWithSchema< TSchemaName extends string | undefined, TColumnsMap extends Record, >( - rawTable: SingleStoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>, + name: TTableName, columns: TColumnsMap, extraConfig: | ((self: BuildColumns) => SingleStoreTableExtraConfig) | undefined, + schema: TSchemaName, + baseName = name, ): SingleStoreTableWithColumns<{ name: TTableName; schema: TSchemaName; columns: BuildColumns; dialect: 'singlestore'; }> { + const rawTable = new SingleStoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as SingleStoreColumnBuilder; @@ -106,10 +109,12 @@ export interface SingleStoreTableFn; } -export const singlestoreTable: SingleStoreTableFn = singlestoreColumnstoreTable; +export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); +}; export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { return (name, columns, extraConfig) => { - return singlestoreTable(customizeTableName(name) as typeof name, columns, extraConfig); + return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); }; } diff --git a/drizzle-orm/src/singlestore-core/tables/columnstore.ts b/drizzle-orm/src/singlestore-core/tables/columnstore.ts deleted file mode 100644 index 34a18bca0e..0000000000 --- a/drizzle-orm/src/singlestore-core/tables/columnstore.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { BuildColumns } from '~/column-builder.ts'; -import { entityKind } from '~/entity.ts'; -import type { SingleStoreColumnBuilderBase } from '../columns/common.ts'; -import type { - SingleStoreTableExtraConfig, - SingleStoreTableFn, - SingleStoreTableWithColumns, - TableConfig, -} from './common.ts'; -import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; - -export class SingleStoreColumnstoreTable extends SingleStoreTable { - static readonly [entityKind]: string = 'SingleStoreColumnstoreTable'; -} - -export function singlestoreColumnstoreTableWithSchema< - TTableName extends string, - TSchemaName extends string | undefined, - TColumnsMap extends Record, ->( - name: TTableName, - columns: TColumnsMap, - extraConfig: - | ((self: BuildColumns) => SingleStoreTableExtraConfig) - | undefined, - schema: TSchemaName, - baseName = name, -): SingleStoreTableWithColumns<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; -}> { - const rawTable = new SingleStoreColumnstoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); - - return singlestoreTableWithSchema(rawTable, columns, extraConfig); -} - -export const singlestoreColumnstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreColumnstoreTableWithSchema(name, columns, extraConfig, undefined, name); -}; diff --git a/drizzle-orm/src/singlestore-core/tables/rowstore.ts b/drizzle-orm/src/singlestore-core/tables/rowstore.ts deleted file mode 100644 index c6302b3878..0000000000 --- a/drizzle-orm/src/singlestore-core/tables/rowstore.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { BuildColumns } from '~/column-builder.ts'; -import { entityKind } from '~/entity.ts'; -import type { SingleStoreColumnBuilderBase } from '../columns/common.ts'; -import type { - SingleStoreTableExtraConfig, - SingleStoreTableFn, - SingleStoreTableWithColumns, - TableConfig, -} from './common.ts'; -import { SingleStoreTable, singlestoreTableWithSchema } from './common.ts'; - -export class SingleStoreRowstoreTable extends SingleStoreTable { - static readonly [entityKind]: string = 'SingleStoreRowstoreTable'; -} - -export function singlestoreRowstoreTableWithSchema< - TTableName extends string, - TSchemaName extends string | undefined, - TColumnsMap extends Record, ->( - name: TTableName, - columns: TColumnsMap, - extraConfig: - | ((self: BuildColumns) => SingleStoreTableExtraConfig) - | undefined, - schema: TSchemaName, - baseName = name, -): SingleStoreTableWithColumns<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; -}> { - const rawTable = new SingleStoreRowstoreTable<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'singlestore'; - }>(name, schema, baseName); - - return singlestoreTableWithSchema(rawTable, columns, extraConfig); -} - -export const singlestoreRowstoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { - return singlestoreRowstoreTableWithSchema(name, columns, extraConfig, undefined, name); -}; diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts index 6789206c0c..faa4f3216f 100644 --- a/drizzle-orm/src/singlestore-core/unique-constraint.ts +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -1,6 +1,6 @@ import { entityKind } from '~/entity.ts'; import type { SingleStoreColumn } from './columns/index.ts'; -import { SingleStoreTable } from './tables/common.ts'; +import { SingleStoreTable } from './table.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts index 8ae6fd80e6..e6412161d6 100644 --- a/drizzle-orm/src/singlestore-core/utils.ts +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -5,7 +5,7 @@ import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; -import { SingleStoreTable } from './tables/common.ts'; +import { SingleStoreTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; import { SingleStoreViewConfig } from './view-common.ts'; import type { SingleStoreView } from './view.ts'; diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts index c6262a5629..3c6c8d25ca 100644 --- a/drizzle-orm/src/singlestore-core/view.ts +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -8,7 +8,7 @@ import { getTableColumns } from '~/utils.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilderBase } from './columns/index.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; -import { singlestoreTable } from './tables/common.ts'; +import { singlestoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; import { SingleStoreViewConfig } from './view-common.ts'; From 337ee343f9de28cecc05633bee72c2f3bad479f9 Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 19:48:29 +0100 Subject: [PATCH 067/152] Fix build --- drizzle-orm/src/singlestore-core/columns/geography.ts | 2 +- drizzle-orm/src/singlestore-core/columns/geographypoint.ts | 2 +- drizzle-orm/src/singlestore-core/columns/guid.ts | 2 +- drizzle-orm/src/singlestore-core/columns/uuid.ts | 2 +- drizzle-orm/src/singlestore-core/columns/vector.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 65a6148137..cd849a5212 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -2,7 +2,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; import { DrizzleError } from '~/errors.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table'; import type { SQL} from '~/sql/sql.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts index 4154c26718..3c027ebe5e 100644 --- a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts +++ b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts @@ -1,7 +1,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; import type { LngLat } from './geography'; diff --git a/drizzle-orm/src/singlestore-core/columns/guid.ts b/drizzle-orm/src/singlestore-core/columns/guid.ts index 1052331080..39d939fead 100644 --- a/drizzle-orm/src/singlestore-core/columns/guid.ts +++ b/drizzle-orm/src/singlestore-core/columns/guid.ts @@ -1,7 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { sql } from '~/sql/sql.ts'; import type { Equal } from '~/utils'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/uuid.ts b/drizzle-orm/src/singlestore-core/columns/uuid.ts index 8a551d79a7..aec204e126 100644 --- a/drizzle-orm/src/singlestore-core/columns/uuid.ts +++ b/drizzle-orm/src/singlestore-core/columns/uuid.ts @@ -1,7 +1,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreUUIDBuilderInitial = SingleStoreUUIDBuilder<{ diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index 768ef7f5a2..033e4115dc 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -1,7 +1,7 @@ import type { ColumnBaseConfig } from '~/column'; import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/tables/common.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ From ac24dc3c6034c79f1022ab7f2b06f84f0b214c82 Mon Sep 17 00:00:00 2001 From: Tiago Castro Date: Thu, 25 Jul 2024 19:50:06 +0100 Subject: [PATCH 068/152] Fix datetime merge error --- drizzle-orm/src/singlestore-core/columns/datetime.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index 2557e26b58..0b000c030a 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -2,6 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { sql } from '~/sql/sql.ts'; import type { Equal } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; From 404d4200146b24a1f140be729cee1cf5cc67299d Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 14:56:46 -0400 Subject: [PATCH 069/152] fix polygon generator --- drizzle-orm/src/singlestore-core/columns/geography.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index cd849a5212..7af8852dc4 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -65,7 +65,7 @@ export class SingleStoreGeography _toLineStringSQL(linestring)); + const rings = polygon.map((linestring) => sql`(${_toLineStringSQL(linestring)})`); return sql.join(rings, sql.raw(', ')); } From bc86043e171159ed0e7bfd7cb3888f46e0a6f5d9 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 15:42:31 -0400 Subject: [PATCH 070/152] fix relational query? --- drizzle-orm/src/singlestore-core/dialect.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 453c2dacf5..29f0230d90 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -754,7 +754,7 @@ export class SingleStoreDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_to_array(${ + let field = sql`json_agg(${ sql.join( selection.map(({ field, tsKey, isJson }) => isJson @@ -767,7 +767,7 @@ export class SingleStoreDialect { ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`coalesce(json_to_arrayagg(${field}), json_to_array())`; + field = sql`coalesce(json_agg(${field}), json_agg())`; } const nestedSelection = [{ dbKey: 'data', @@ -1025,8 +1025,7 @@ export class SingleStoreDialect { }); let fieldSql = sql`(${builtRelation.sql})`; if (is(relation, Many)) { - fieldSql = sql`coalesce(${fieldSql}, json_to_array())`; - } + fieldSql = sql`coalesce(${fieldSql}, json_agg())`; } const field = fieldSql.as(selectedRelationTsKey); selection.push({ dbKey: selectedRelationTsKey, @@ -1051,7 +1050,7 @@ export class SingleStoreDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_to_array(${ + let field = sql`json_agg(${ sql.join( selection.map(({ field }) => is(field, SingleStoreColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field @@ -1060,7 +1059,7 @@ export class SingleStoreDialect { ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`json_to_arrayagg(${field})`; + field = sql`json_agg(${field})`; } const nestedSelection = [{ dbKey: 'data', From 46e88647cd19230ce6a07f6f780ba7645218c123 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 25 Jul 2024 15:58:32 -0400 Subject: [PATCH 071/152] revert --- drizzle-orm/src/singlestore-core/dialect.ts | 34 +++++---------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 29f0230d90..596e23e9a3 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -25,12 +25,9 @@ import { ViewBaseConfig } from '~/view-common.ts'; import { SingleStoreColumn } from './columns/common.ts'; import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; import type { SingleStoreBranchConfig } from './query-builders/branch.ts'; -import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; -import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; -import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; import type { SelectedFieldsOrdered, SingleStoreSelectConfig, @@ -40,6 +37,8 @@ import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; +import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; +import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -158,24 +157,6 @@ export class SingleStoreDialect { return sql`drop milestone ${milestone}${forSql}`; } - buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { - const argSql = arg ? sql` ${sql.raw(arg)}` : undefined; - - let warmBlobCacheForColumnSql = undefined; - if (selection) { - const selectionField = selection.length > 0 - ? selection.map((column) => { - return { path: [], field: column }; - }) - : [{ path: [], field: sql.raw('*') }]; - warmBlobCacheForColumnSql = sql` warm blob cache for column ${ - this.buildSelection(selectionField, { isSingleTable: true }) - }`; - } - - return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; - } - buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { const tableColumns = table[Table.Symbol.Columns]; @@ -754,7 +735,7 @@ export class SingleStoreDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_agg(${ + let field = sql`json_to_array(${ sql.join( selection.map(({ field, tsKey, isJson }) => isJson @@ -767,7 +748,7 @@ export class SingleStoreDialect { ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`coalesce(json_agg(${field}), json_agg())`; + field = sql`coalesce(json_to_arrayagg(${field}), json_to_array())`; } const nestedSelection = [{ dbKey: 'data', @@ -1025,7 +1006,8 @@ export class SingleStoreDialect { }); let fieldSql = sql`(${builtRelation.sql})`; if (is(relation, Many)) { - fieldSql = sql`coalesce(${fieldSql}, json_agg())`; } + fieldSql = sql`coalesce(${fieldSql}, json_to_array())`; + } const field = fieldSql.as(selectedRelationTsKey); selection.push({ dbKey: selectedRelationTsKey, @@ -1050,7 +1032,7 @@ export class SingleStoreDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_agg(${ + let field = sql`json_to_array(${ sql.join( selection.map(({ field }) => is(field, SingleStoreColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field @@ -1059,7 +1041,7 @@ export class SingleStoreDialect { ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`json_agg(${field})`; + field = sql`json_to_arrayagg(${field})`; } const nestedSelection = [{ dbKey: 'data', From 9daf249d97d00b17b93a2607f9474373a18b0d30 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 00:51:30 +0100 Subject: [PATCH 072/152] fixed revert of 46e88647cd19230ce6a07f6f780ba7645218c123 --- drizzle-orm/src/singlestore-core/dialect.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 596e23e9a3..5e3ba50715 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -39,6 +39,7 @@ import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; +import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -157,6 +158,24 @@ export class SingleStoreDialect { return sql`drop milestone ${milestone}${forSql}`; } + buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { + const argSql = arg ? sql` ${sql.raw(arg)}` : undefined; + + let warmBlobCacheForColumnSql = undefined; + if (selection) { + const selectionField = selection.length > 0 + ? selection.map((column) => { + return { path: [], field: column }; + }) + : [{ path: [], field: sql.raw('*') }]; + warmBlobCacheForColumnSql = sql` warm blob cache for column ${ + this.buildSelection(selectionField, { isSingleTable: true }) + }`; + } + + return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; + } + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { const tableColumns = table[Table.Symbol.Columns]; From 893caa4dfe1ffbfdd4e75a874b99e54bcd420ce3 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 00:52:04 +0100 Subject: [PATCH 073/152] Fix relational queries for S2 --- drizzle-orm/src/singlestore-core/dialect.ts | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 5e3ba50715..0d6cc54035 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -726,7 +726,7 @@ export class SingleStoreDialect { joinOn, nestedQueryRelation: relation, }); - const field = sql`${sql.identifier(relationTableAlias)}.${sql.identifier('data')}`.as(selectedRelationTsKey); + const field = sql`coalesce(${sql.identifier(relationTableAlias)}.${sql.identifier('data')}, "[]")`.as(selectedRelationTsKey); joins.push({ on: sql`true`, table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias), @@ -754,20 +754,20 @@ export class SingleStoreDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_to_array(${ + let field = sql`JSON_BUILD_OBJECT(${ sql.join( - selection.map(({ field, tsKey, isJson }) => + selection.map(({ field, tsKey, isJson }, index) => isJson - ? sql`${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` + ? sql`${index}, ${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` : is(field, SQL.Aliased) - ? field.sql - : field + ? sql`${index}, ${field.sql}` + : sql`${index}, ${field}` ), sql`, `, ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`coalesce(json_to_arrayagg(${field}), json_to_array())`; + field = sql`json_agg(${field})`; } const nestedSelection = [{ dbKey: 'data', @@ -1025,7 +1025,7 @@ export class SingleStoreDialect { }); let fieldSql = sql`(${builtRelation.sql})`; if (is(relation, Many)) { - fieldSql = sql`coalesce(${fieldSql}, json_to_array())`; + fieldSql = sql`coalesce(${fieldSql}, "[]")`; } const field = fieldSql.as(selectedRelationTsKey); selection.push({ @@ -1051,16 +1051,20 @@ export class SingleStoreDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`json_to_array(${ + let field = sql`JSON_BUILD_OBJECT(${ sql.join( - selection.map(({ field }) => - is(field, SingleStoreColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field + selection.map(({ field }, index) => + is(field, SingleStoreColumn) + ? sql`${index}, ${sql.identifier(field.name)}` + : is(field, SQL.Aliased) + ? sql`${index}, ${field.sql}` + : sql`${index}, ${field}` ), sql`, `, ) })`; if (is(nestedQueryRelation, Many)) { - field = sql`json_to_arrayagg(${field})`; + field = sql`json_agg(${field})`; } const nestedSelection = [{ dbKey: 'data', From d13c2a3cf334f3036e6daab3b8e039c2601236da Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 18:09:26 +0100 Subject: [PATCH 074/152] stuff --- drizzle-orm/src/singlestore-core/dialect.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 0d6cc54035..933aba90b8 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -163,14 +163,10 @@ export class SingleStoreDialect { let warmBlobCacheForColumnSql = undefined; if (selection) { - const selectionField = selection.length > 0 - ? selection.map((column) => { - return { path: [], field: column }; - }) + const selectionField = selection.length > 0 ? + selection.map((column) => { return { path: [], field: column } }) : [{ path: [], field: sql.raw('*') }]; - warmBlobCacheForColumnSql = sql` warm blob cache for column ${ - this.buildSelection(selectionField, { isSingleTable: true }) - }`; + warmBlobCacheForColumnSql = sql` warm blob cache for column ${this.buildSelection(selectionField, { isSingleTable: true })}`; } return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; From e20125744ca5ea6fc48eebb55ef6c5feb8181a5e Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 18:11:01 +0100 Subject: [PATCH 075/152] Full text --- drizzle-orm/src/singlestore-core/indexes.ts | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 59d2bfb11f..1e800db271 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -106,3 +106,59 @@ export function index(name: string): IndexBuilderOn { export function uniqueIndex(name: string): IndexBuilderOn { return new IndexBuilderOn(name, true); } + +interface FullTextIndexConfig { + name: string; + + columns: IndexColumn[]; + + version?: number; +} + +export class FullTextIndexBuilderOn { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilderOn'; + + constructor(private config: FullTextIndexConfig) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): FullTextIndexBuilder { + return new FullTextIndexBuilder({ + ...this.config, + columns: columns, + }); + } +} + +export interface FullTextIndexBuilder extends AnyIndexBuilder {} + +export class FullTextIndexBuilder implements AnyIndexBuilder { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilder'; + + /** @internal */ + config: FullTextIndexConfig; + + constructor(config: FullTextIndexConfig) { + this.config = config; + } + + /** @internal */ + build(table: SingleStoreTable): FullTextIndex { + return new FullTextIndex(this.config, table); + } +} + +export class FullTextIndex { + static readonly [entityKind]: string = 'SingleStoreFullTextIndex'; + + readonly config: FullTextIndexConfig & { table: SingleStoreTable }; + + constructor(config: FullTextIndexConfig, table: SingleStoreTable) { + this.config = { ...config, table }; + } +} + +export function fulltext(name: string, config: FullTextIndexConfig): FullTextIndexBuilderOn { + return new FullTextIndexBuilderOn({ + ...config, + name: name, + }); +} From 89ebe115d163c86b3285f0e772809bb62fee5b7b Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 18:32:36 +0100 Subject: [PATCH 076/152] nits with fulltext index --- drizzle-orm/src/singlestore-core/indexes.ts | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 1e800db271..9253a10ef9 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -45,6 +45,10 @@ export interface AnyIndexBuilder { build(table: SingleStoreTable): Index; } +export interface AnyFullTextIndexBuilder { + build(table: SingleStoreTable): FullTextIndex; +} + // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface IndexBuilder extends AnyIndexBuilder {} @@ -108,35 +112,38 @@ export function uniqueIndex(name: string): IndexBuilderOn { } interface FullTextIndexConfig { - name: string; + version?: number; +} +interface FullTextIndexFullConfig extends FullTextIndexConfig { columns: IndexColumn[]; - version?: number; + name: string; } export class FullTextIndexBuilderOn { static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilderOn'; - constructor(private config: FullTextIndexConfig) {} + constructor(private name: string, private config: FullTextIndexConfig) {} on(...columns: [IndexColumn, ...IndexColumn[]]): FullTextIndexBuilder { return new FullTextIndexBuilder({ - ...this.config, + name: this.name, columns: columns, + ...this.config, }); } } -export interface FullTextIndexBuilder extends AnyIndexBuilder {} +export interface FullTextIndexBuilder extends AnyFullTextIndexBuilder {} -export class FullTextIndexBuilder implements AnyIndexBuilder { +export class FullTextIndexBuilder implements AnyFullTextIndexBuilder { static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilder'; /** @internal */ - config: FullTextIndexConfig; + config: FullTextIndexFullConfig; - constructor(config: FullTextIndexConfig) { + constructor(config: FullTextIndexFullConfig) { this.config = config; } @@ -157,8 +164,5 @@ export class FullTextIndex { } export function fulltext(name: string, config: FullTextIndexConfig): FullTextIndexBuilderOn { - return new FullTextIndexBuilderOn({ - ...config, - name: name, - }); + return new FullTextIndexBuilderOn(name, config); } From b7e596f67d5ce24987fe20469993f5b372ae71f1 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 19:00:42 +0100 Subject: [PATCH 077/152] MATCH AGAINST --- .../sql/expressions/conditions.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts new file mode 100644 index 0000000000..6cc3840f6d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts @@ -0,0 +1,20 @@ +import { sql, type SQL, type SQLWrapper } from "~/sql/sql.ts"; +import { bindIfParam } from "~/sql/expressions/conditions.ts"; +import type { BinaryOperator } from "~/sql/expressions"; + +/** + * Test that two values match. + * + * ## Examples + * + * ```ts + * // Select cars made by Ford + * db.select().from(cars) + * .where(match(cars.make, 'Ford')) + * ``` + * + * @see isNull for a way to test equality to NULL. + */ +export const match: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => { + return sql`MATCH ${left} AGAINST ${bindIfParam(right, left)}`; +}; From f0bf136198000a472c53ac85f260e8f65cc383ba Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 19:10:50 +0100 Subject: [PATCH 078/152] nits --- drizzle-orm/src/singlestore-core/sql/expressions/index.ts | 1 + drizzle-orm/src/singlestore-core/sql/index.ts | 1 + 2 files changed, 2 insertions(+) create mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/index.ts create mode 100644 drizzle-orm/src/singlestore-core/sql/index.ts diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/index.ts b/drizzle-orm/src/singlestore-core/sql/expressions/index.ts new file mode 100644 index 0000000000..81cb13770a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/expressions/index.ts @@ -0,0 +1 @@ +export * from './conditions.ts'; diff --git a/drizzle-orm/src/singlestore-core/sql/index.ts b/drizzle-orm/src/singlestore-core/sql/index.ts new file mode 100644 index 0000000000..16ca766799 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/index.ts @@ -0,0 +1 @@ +export * from './expressions/index.ts'; From 7068637c3b5932a834aad59f7290ecf32f97a49f Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 19:15:32 +0100 Subject: [PATCH 079/152] more nits --- drizzle-orm/src/singlestore-core/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts index 92c6b9a203..3110460fed 100644 --- a/drizzle-orm/src/singlestore-core/index.ts +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -7,6 +7,7 @@ export * from './primary-keys.ts'; export * from './query-builders/index.ts'; export * from './schema.ts'; export * from './session.ts'; +export * from './sql/index.ts' export * from './subquery.ts'; export * from './table.ts'; export * from './unique-constraint.ts'; From 80e0bb07fd28805f20e33bcdb5da628668dcde1b Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 20:06:49 +0100 Subject: [PATCH 080/152] nits with MATCH AGAINST --- drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts index 6cc3840f6d..d3846f43df 100644 --- a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts +++ b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts @@ -16,5 +16,5 @@ import type { BinaryOperator } from "~/sql/expressions"; * @see isNull for a way to test equality to NULL. */ export const match: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => { - return sql`MATCH ${left} AGAINST ${bindIfParam(right, left)}`; + return sql`MATCH (${left}) AGAINST (${bindIfParam(right, left)})`; }; From 5d01131afaa051542ab503561b8a539023b9f31a Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Fri, 26 Jul 2024 20:16:54 +0100 Subject: [PATCH 081/152] nits of MATCH AGAINST --- .../singlestore-core/sql/expressions/conditions.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts index d3846f43df..4a005faaef 100644 --- a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts +++ b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts @@ -1,6 +1,6 @@ -import { sql, type SQL, type SQLWrapper } from "~/sql/sql.ts"; +import { sql, type SQL } from "~/sql/sql.ts"; import { bindIfParam } from "~/sql/expressions/conditions.ts"; -import type { BinaryOperator } from "~/sql/expressions"; +import type { Table } from "~/table"; /** * Test that two values match. @@ -15,6 +15,8 @@ import type { BinaryOperator } from "~/sql/expressions"; * * @see isNull for a way to test equality to NULL. */ -export const match: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => { - return sql`MATCH (${left}) AGAINST (${bindIfParam(right, left)})`; -}; +export function match< + TTable extends Table +>(left: TTable, right: unknown): SQL { + return sql`MATCH (TABLE ${left}) AGAINST (${bindIfParam(right, left)})`; +} From 2e846a6de86babb70becec0d8124af668e671cf5 Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Sat, 27 Jul 2024 15:12:22 +0100 Subject: [PATCH 082/152] Sort key --- drizzle-orm/src/singlestore-core/indexes.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 9253a10ef9..6de375ab0d 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -166,3 +166,24 @@ export class FullTextIndex { export function fulltext(name: string, config: FullTextIndexConfig): FullTextIndexBuilderOn { return new FullTextIndexBuilderOn(name, config); } + +export class SortKeyBuilder { + static readonly [entityKind]: string = 'SingleStoreSortKeyBuilder'; + + constructor(private columns: IndexColumn[]) {} + + /** @internal */ + build(table: SingleStoreTable): SortKey { + return new SortKey(this.columns, table); + } +} + +export class SortKey { + static readonly [entityKind]: string = 'SingleStoreSortKey'; + + constructor(public columns: IndexColumn[], public table: SingleStoreTable) {} +} + +export function sortKey(...columns: [IndexColumn, ...IndexColumn[]]): SortKeyBuilder { + return new SortKeyBuilder(columns); +} From d20e3cab3b317009c3c390699a161f96e54ea75f Mon Sep 17 00:00:00 2001 From: Diogo Rodrigues Date: Sat, 27 Jul 2024 15:30:09 +0100 Subject: [PATCH 083/152] Fixed sortKey --- drizzle-orm/src/singlestore-core/indexes.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 6de375ab0d..172f524f54 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -167,10 +167,12 @@ export function fulltext(name: string, config: FullTextIndexConfig): FullTextInd return new FullTextIndexBuilderOn(name, config); } +export type SortKeyColumn = SingleStoreColumn | SQL; + export class SortKeyBuilder { static readonly [entityKind]: string = 'SingleStoreSortKeyBuilder'; - constructor(private columns: IndexColumn[]) {} + constructor(private columns: SortKeyColumn[]) {} /** @internal */ build(table: SingleStoreTable): SortKey { @@ -181,9 +183,9 @@ export class SortKeyBuilder { export class SortKey { static readonly [entityKind]: string = 'SingleStoreSortKey'; - constructor(public columns: IndexColumn[], public table: SingleStoreTable) {} + constructor(public columns: SortKeyColumn[], public table: SingleStoreTable) {} } -export function sortKey(...columns: [IndexColumn, ...IndexColumn[]]): SortKeyBuilder { +export function sortKey(...columns: SortKeyColumn[]): SortKeyBuilder { return new SortKeyBuilder(columns); } From ba24167543ecaaf8de2753370ae7ea927bad44a9 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Sun, 28 Jul 2024 10:53:17 +0100 Subject: [PATCH 084/152] fix lint issues and add lint:fix command --- .../src/singlestore-core/columns/blob.ts | 2 +- .../src/singlestore-core/columns/geography.ts | 2 +- drizzle-orm/src/singlestore-core/dialect.ts | 20 ++++++++++++------- drizzle-orm/src/singlestore-core/index.ts | 2 +- .../sql/expressions/conditions.ts | 8 ++++---- package.json | 3 ++- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/blob.ts b/drizzle-orm/src/singlestore-core/columns/blob.ts index c30e2c0c97..0885253f1e 100644 --- a/drizzle-orm/src/singlestore-core/columns/blob.ts +++ b/drizzle-orm/src/singlestore-core/columns/blob.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { Equal } from '~/utils'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; import type { AnySingleStoreTable } from '../table'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; type BlobMode = 'buffer' | 'json' | 'bigint'; diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts index 7af8852dc4..b7798b4a4c 100644 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ b/drizzle-orm/src/singlestore-core/columns/geography.ts @@ -3,7 +3,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import { entityKind } from '~/entity.ts'; import { DrizzleError } from '~/errors.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table'; -import type { SQL} from '~/sql/sql.ts'; +import type { SQL } from '~/sql/sql.ts'; import { sql } from '~/sql/sql.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 933aba90b8..7ae21b418b 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -25,9 +25,12 @@ import { ViewBaseConfig } from '~/view-common.ts'; import { SingleStoreColumn } from './columns/common.ts'; import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; import type { SingleStoreBranchConfig } from './query-builders/branch.ts'; +import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; +import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; +import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; import type { SelectedFieldsOrdered, SingleStoreSelectConfig, @@ -37,9 +40,6 @@ import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; import { SingleStoreViewBase } from './view-base.ts'; -import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; -import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; -import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; export class SingleStoreDialect { static readonly [entityKind]: string = 'SingleStoreDialect'; @@ -163,10 +163,14 @@ export class SingleStoreDialect { let warmBlobCacheForColumnSql = undefined; if (selection) { - const selectionField = selection.length > 0 ? - selection.map((column) => { return { path: [], field: column } }) + const selectionField = selection.length > 0 + ? selection.map((column) => { + return { path: [], field: column }; + }) : [{ path: [], field: sql.raw('*') }]; - warmBlobCacheForColumnSql = sql` warm blob cache for column ${this.buildSelection(selectionField, { isSingleTable: true })}`; + warmBlobCacheForColumnSql = sql` warm blob cache for column ${ + this.buildSelection(selectionField, { isSingleTable: true }) + }`; } return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; @@ -722,7 +726,9 @@ export class SingleStoreDialect { joinOn, nestedQueryRelation: relation, }); - const field = sql`coalesce(${sql.identifier(relationTableAlias)}.${sql.identifier('data')}, "[]")`.as(selectedRelationTsKey); + const field = sql`coalesce(${sql.identifier(relationTableAlias)}.${sql.identifier('data')}, "[]")`.as( + selectedRelationTsKey, + ); joins.push({ on: sql`true`, table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias), diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts index 3110460fed..4da014404d 100644 --- a/drizzle-orm/src/singlestore-core/index.ts +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -7,7 +7,7 @@ export * from './primary-keys.ts'; export * from './query-builders/index.ts'; export * from './schema.ts'; export * from './session.ts'; -export * from './sql/index.ts' +export * from './sql/index.ts'; export * from './subquery.ts'; export * from './table.ts'; export * from './unique-constraint.ts'; diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts index 4a005faaef..95cffabdd8 100644 --- a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts +++ b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts @@ -1,6 +1,6 @@ -import { sql, type SQL } from "~/sql/sql.ts"; -import { bindIfParam } from "~/sql/expressions/conditions.ts"; -import type { Table } from "~/table"; +import { bindIfParam } from '~/sql/expressions/conditions.ts'; +import { type SQL, sql } from '~/sql/sql.ts'; +import type { Table } from '~/table'; /** * Test that two values match. @@ -16,7 +16,7 @@ import type { Table } from "~/table"; * @see isNull for a way to test equality to NULL. */ export function match< - TTable extends Table + TTable extends Table, >(left: TTable, right: unknown): SQL { return sql`MATCH (TABLE ${left}) AGAINST (${bindIfParam(right, left)})`; } diff --git a/package.json b/package.json index 3327aad18e..642121e541 100755 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "test": "turbo run test --color", "t": "pnpm test", "test:types": "turbo run test:types --color", - "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"" + "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"", + "lint:fix": "npx dprint fmt" }, "devDependencies": { "@arethetypeswrong/cli": "^0.15.3", From b93062b4f0d165e95435042f5cd97717b9aef17e Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 8 Aug 2024 13:21:35 +0100 Subject: [PATCH 085/152] add singlestore dialect to drizzle-kit --- drizzle-kit/package.json | 2 +- drizzle-kit/pnpm-lock.yaml | 7603 ----------------- drizzle-kit/src/api.ts | 107 +- drizzle-kit/src/cli/commands/introspect.ts | 102 +- drizzle-kit/src/cli/commands/migrate.ts | 148 + drizzle-kit/src/cli/commands/push.ts | 148 +- .../src/cli/commands/singlestoreIntrospect.ts | 53 + .../src/cli/commands/singlestorePushUtils.ts | 352 + drizzle-kit/src/cli/commands/utils.ts | 83 +- drizzle-kit/src/cli/connections.ts | 80 + drizzle-kit/src/cli/validations/outputs.ts | 11 +- .../src/cli/validations/singlestore.ts | 61 + drizzle-kit/src/index.ts | 19 +- drizzle-kit/src/introspect-singlestore.ts | 787 ++ drizzle-kit/src/jsonStatements.ts | 461 +- drizzle-kit/src/migrationPreparator.ts | 45 +- drizzle-kit/src/schemaValidator.ts | 6 +- drizzle-kit/src/serializer/index.ts | 16 + .../src/serializer/singlestoreImports.ts | 31 + .../src/serializer/singlestoreSchema.ts | 213 + .../src/serializer/singlestoreSerializer.ts | 592 ++ drizzle-kit/src/serializer/studio.ts | 91 +- drizzle-kit/src/snapshotsDiffer.ts | 425 + drizzle-kit/src/sqlgenerator.ts | 717 +- pnpm-lock.yaml | 41 +- 25 files changed, 4483 insertions(+), 7711 deletions(-) delete mode 100644 drizzle-kit/pnpm-lock.yaml create mode 100644 drizzle-kit/src/cli/commands/singlestoreIntrospect.ts create mode 100644 drizzle-kit/src/cli/commands/singlestorePushUtils.ts create mode 100644 drizzle-kit/src/cli/validations/singlestore.ts create mode 100644 drizzle-kit/src/introspect-singlestore.ts create mode 100644 drizzle-kit/src/serializer/singlestoreImports.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSchema.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSerializer.ts diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index c3f8857224..3b479496c5 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -92,7 +92,7 @@ "hono": "^4.1.5", "json-diff": "1.0.6", "minimatch": "^7.4.3", - "mysql2": "2.3.3", + "mysql2": "^3.3.3", "node-fetch": "^3.3.2", "pg": "^8.11.5", "pluralize": "^8.0.0", diff --git a/drizzle-kit/pnpm-lock.yaml b/drizzle-kit/pnpm-lock.yaml deleted file mode 100644 index 8f4d58f55d..0000000000 --- a/drizzle-kit/pnpm-lock.yaml +++ /dev/null @@ -1,7603 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -patchedDependencies: - difflib@0.2.4: - hash: jq4t3ysdpnbunjeje4v7nrqn2q - path: patches/difflib@0.2.4.patch - -importers: - - .: - dependencies: - '@esbuild-kit/esm-loader': - specifier: ^2.5.5 - version: 2.6.5 - esbuild: - specifier: ^0.19.7 - version: 0.19.12 - esbuild-register: - specifier: ^3.5.0 - version: 3.5.0(esbuild@0.19.12) - devDependencies: - '@arethetypeswrong/cli': - specifier: ^0.15.3 - version: 0.15.3 - '@aws-sdk/client-rds-data': - specifier: ^3.556.0 - version: 3.577.0 - '@cloudflare/workers-types': - specifier: ^4.20230518.0 - version: 4.20240512.0 - '@electric-sql/pglite': - specifier: ^0.1.5 - version: 0.1.5 - '@hono/node-server': - specifier: ^1.9.0 - version: 1.11.1 - '@hono/zod-validator': - specifier: ^0.2.1 - version: 0.2.1(hono@4.3.9)(zod@3.23.8) - '@libsql/client': - specifier: ^0.4.2 - version: 0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@neondatabase/serverless': - specifier: ^0.9.1 - version: 0.9.3 - '@originjs/vite-plugin-commonjs': - specifier: ^1.0.3 - version: 1.0.3 - '@planetscale/database': - specifier: ^1.16.0 - version: 1.18.0 - '@types/better-sqlite3': - specifier: ^7.6.4 - version: 7.6.10 - '@types/dockerode': - specifier: ^3.3.28 - version: 3.3.29 - '@types/glob': - specifier: ^8.1.0 - version: 8.1.0 - '@types/json-diff': - specifier: ^1.0.3 - version: 1.0.3 - '@types/minimatch': - specifier: ^5.1.2 - version: 5.1.2 - '@types/node': - specifier: ^18.11.15 - version: 18.19.33 - '@types/pg': - specifier: ^8.10.7 - version: 8.11.6 - '@types/pluralize': - specifier: ^0.0.33 - version: 0.0.33 - '@types/semver': - specifier: ^7.5.5 - version: 7.5.8 - '@types/uuid': - specifier: ^9.0.8 - version: 9.0.8 - '@types/ws': - specifier: ^8.5.10 - version: 8.5.10 - '@typescript-eslint/eslint-plugin': - specifier: ^7.2.0 - version: 7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': - specifier: ^7.2.0 - version: 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@vercel/postgres': - specifier: ^0.8.0 - version: 0.8.0 - ava: - specifier: ^5.1.0 - version: 5.3.1 - better-sqlite3: - specifier: ^9.4.3 - version: 9.6.0 - camelcase: - specifier: ^7.0.1 - version: 7.0.1 - chalk: - specifier: ^5.2.0 - version: 5.3.0 - commander: - specifier: ^12.1.0 - version: 12.1.0 - dockerode: - specifier: ^3.3.4 - version: 3.3.5 - dotenv: - specifier: ^16.0.3 - version: 16.4.5 - drizzle-kit: - specifier: 0.21.2 - version: 0.21.2 - drizzle-orm: - specifier: 0.32.0-85c8008 - version: 0.32.0-85c8008(@aws-sdk/client-rds-data@3.577.0)(@cloudflare/workers-types@4.20240512.0)(@electric-sql/pglite@0.1.5)(@libsql/client@0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(mysql2@2.3.3)(pg@8.11.5)(postgres@3.4.4) - env-paths: - specifier: ^3.0.0 - version: 3.0.0 - esbuild-node-externals: - specifier: ^1.9.0 - version: 1.13.1(esbuild@0.19.12) - eslint: - specifier: ^8.57.0 - version: 8.57.0 - eslint-config-prettier: - specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.0) - eslint-plugin-prettier: - specifier: ^5.1.3 - version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) - get-port: - specifier: ^6.1.2 - version: 6.1.2 - glob: - specifier: ^8.1.0 - version: 8.1.0 - hanji: - specifier: ^0.0.5 - version: 0.0.5 - hono: - specifier: ^4.1.5 - version: 4.3.9 - json-diff: - specifier: 1.0.6 - version: 1.0.6 - minimatch: - specifier: ^7.4.3 - version: 7.4.6 - mysql2: - specifier: 2.3.3 - version: 2.3.3 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 - pg: - specifier: ^8.11.5 - version: 8.11.5 - pluralize: - specifier: ^8.0.0 - version: 8.0.0 - postgres: - specifier: ^3.4.4 - version: 3.4.4 - prettier: - specifier: ^2.8.1 - version: 2.8.8 - semver: - specifier: ^7.5.4 - version: 7.6.2 - superjson: - specifier: ^2.2.1 - version: 2.2.1 - tsup: - specifier: ^8.0.2 - version: 8.0.2(postcss@8.4.38)(typescript@5.4.5) - tsx: - specifier: ^3.12.1 - version: 3.14.0 - typescript: - specifier: ^5.4.3 - version: 5.4.5 - uuid: - specifier: ^9.0.1 - version: 9.0.1 - vite-tsconfig-paths: - specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5)(vite@5.2.11(@types/node@18.19.33)) - vitest: - specifier: ^1.4.0 - version: 1.6.0(@types/node@18.19.33) - wrangler: - specifier: ^3.22.1 - version: 3.57.0(@cloudflare/workers-types@4.20240512.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) - ws: - specifier: ^8.16.0 - version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - zod: - specifier: ^3.20.2 - version: 3.23.8 - zx: - specifier: ^7.2.2 - version: 7.2.3 - -packages: - - '@andrewbranch/untar.js@1.0.3': - resolution: {integrity: sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==} - - '@arethetypeswrong/cli@0.15.3': - resolution: {integrity: sha512-sIMA9ZJBWDEg1+xt5RkAEflZuf8+PO8SdKj17x6PtETuUho+qlZJg4DgmKc3q+QwQ9zOB5VLK6jVRbFdNLdUIA==} - engines: {node: '>=18'} - hasBin: true - - '@arethetypeswrong/core@0.15.1': - resolution: {integrity: sha512-FYp6GBAgsNz81BkfItRz8RLZO03w5+BaeiPma1uCfmxTnxbtuMrI/dbzGiOk8VghO108uFI0oJo0OkewdSHw7g==} - engines: {node: '>=18'} - - '@aws-crypto/ie11-detection@3.0.0': - resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} - - '@aws-crypto/sha256-browser@3.0.0': - resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} - - '@aws-crypto/sha256-js@3.0.0': - resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} - - '@aws-crypto/supports-web-crypto@3.0.0': - resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} - - '@aws-crypto/util@3.0.0': - resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} - - '@aws-sdk/client-rds-data@3.577.0': - resolution: {integrity: sha512-24a27II6UkNhe2RB6ZwtQPcM3QB/DuRcKvzMmfvipgWS72Q5FEtuq3CO66IObWUel/pxi3ucE6mSvVCFnm7tBQ==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso-oidc@3.577.0': - resolution: {integrity: sha512-njmKSPDWueWWYVFpFcZ2P3fI6/pdQVDa0FgCyYZhOnJLgEHZIcBBg1AsnkVWacBuLopp9XVt2m+7hO6ugY1/1g==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso@3.577.0': - resolution: {integrity: sha512-BwujdXrydlk6UEyPmewm5GqG4nkQ6OVyRhS/SyZP/6UKSFv2/sf391Cmz0hN0itUTH1rR4XeLln8XCOtarkrzg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sts@3.577.0': - resolution: {integrity: sha512-509Kklimva1XVlhGbpTpeX3kOP6ORpm44twJxDHpa9TURbmoaxj7veWlnLCbDorxDTrbsDghvYZshvcLsojVpg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/core@3.576.0': - resolution: {integrity: sha512-KDvDlbeipSTIf+ffKtTg1m419TK7s9mZSWC8bvuZ9qx6/sjQFOXIKOVqyuli6DnfxGbvRcwoRuY99OcCH1N/0w==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-env@3.577.0': - resolution: {integrity: sha512-Jxu255j0gToMGEiqufP8ZtKI8HW90lOLjwJ3LrdlD/NLsAY0tOQf1fWc53u28hWmmNGMxmCrL2p66IOgMDhDUw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-http@3.577.0': - resolution: {integrity: sha512-n++yhCp67b9+ZRGEdY1jhamB5E/O+QsIDOPSuRmdaSGMCOd82oUEKPgIVEU1bkqxDsBxgiEWuvtfhK6sNiDS0A==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-ini@3.577.0': - resolution: {integrity: sha512-q7lHPtv6BjRvChUE3m0tIaEZKxPTaZ1B3lKxGYsFl3VLAu5N8yGCUKwuA1izf4ucT+LyKscVGqK6VDZx1ev3nw==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.577.0 - - '@aws-sdk/credential-provider-node@3.577.0': - resolution: {integrity: sha512-epZ1HOMsrXBNczc0HQpv0VMjqAEpc09DUA7Rg3gUJfn8umhML7A7bXnUyqPA+S54q397UYg1leQKdSn23OiwQQ==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-process@3.577.0': - resolution: {integrity: sha512-Gin6BWtOiXxIgITrJ3Nwc+Y2P1uVT6huYR4EcbA/DJUPWyO0n9y5UFLewPvVbLkRn15JeEqErBLUrHclkiOKtw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-sso@3.577.0': - resolution: {integrity: sha512-iVm5SQvS7EgZTJsRaqUOmDQpBQPPPat42SCbWFvFQOLrl8qewq8OP94hFS5w2mP62zngeYzqhJnDel79HXbxew==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-web-identity@3.577.0': - resolution: {integrity: sha512-ZGHGNRaCtJJmszb9UTnC7izNCtRUttdPlLdMkh41KPS32vfdrBDHs1JrpbZijItRj1xKuOXsiYSXLAaHGcLh8Q==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.577.0 - - '@aws-sdk/middleware-host-header@3.577.0': - resolution: {integrity: sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/middleware-logger@3.577.0': - resolution: {integrity: sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/middleware-recursion-detection@3.577.0': - resolution: {integrity: sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/middleware-user-agent@3.577.0': - resolution: {integrity: sha512-P55HAXgwmiHHpFx5JEPvOnAbfhN7v6sWv9PBQs+z2tC7QiBcPS0cdJR6PfV7J1n4VPK52/OnrK3l9VxdQ7Ms0g==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/region-config-resolver@3.577.0': - resolution: {integrity: sha512-4ChCFACNwzqx/xjg3zgFcW8Ali6R9C95cFECKWT/7CUM1D0MGvkclSH2cLarmHCmJgU6onKkJroFtWp0kHhgyg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/token-providers@3.577.0': - resolution: {integrity: sha512-0CkIZpcC3DNQJQ1hDjm2bdSy/Xjs7Ny5YvSsacasGOkNfk+FdkiQy6N67bZX3Zbc9KIx+Nz4bu3iDeNSNplnnQ==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.577.0 - - '@aws-sdk/types@3.577.0': - resolution: {integrity: sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/util-endpoints@3.577.0': - resolution: {integrity: sha512-FjuUz1Kdy4Zly2q/c58tpdqHd6z7iOdU/caYzoc8jwgAHBDBbIJNQLCU9hXJnPV2M8pWxQDyIZsoVwtmvErPzw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/util-locate-window@3.568.0': - resolution: {integrity: sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/util-user-agent-browser@3.577.0': - resolution: {integrity: sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==} - - '@aws-sdk/util-user-agent-node@3.577.0': - resolution: {integrity: sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA==} - engines: {node: '>=16.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - - '@aws-sdk/util-utf8-browser@3.259.0': - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} - - '@balena/dockerignore@1.0.2': - resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} - - '@cloudflare/kv-asset-handler@0.3.2': - resolution: {integrity: sha512-EeEjMobfuJrwoctj7FA1y1KEbM0+Q1xSjobIEyie9k4haVEBB7vkDvsasw1pM3rO39mL2akxIAzLMUAtrMHZhA==} - engines: {node: '>=16.13'} - - '@cloudflare/workerd-darwin-64@1.20240512.0': - resolution: {integrity: sha512-VMp+CsSHFALQiBzPdQ5dDI4T1qwLu0mQ0aeKVNDosXjueN0f3zj/lf+mFil5/9jBbG3t4mG0y+6MMnalP9Lobw==} - engines: {node: '>=16'} - cpu: [x64] - os: [darwin] - - '@cloudflare/workerd-darwin-arm64@1.20240512.0': - resolution: {integrity: sha512-lZktXGmzMrB5rJqY9+PmnNfv1HKlj/YLZwMjPfF0WVKHUFdvQbAHsi7NlKv6mW9uIvlZnS+K4sIkWc0MDXcRnA==} - engines: {node: '>=16'} - cpu: [arm64] - os: [darwin] - - '@cloudflare/workerd-linux-64@1.20240512.0': - resolution: {integrity: sha512-wrHvqCZZqXz6Y3MUTn/9pQNsvaoNjbJpuA6vcXsXu8iCzJi911iVW2WUEBX+MpUWD+mBIP0oXni5tTlhkokOPw==} - engines: {node: '>=16'} - cpu: [x64] - os: [linux] - - '@cloudflare/workerd-linux-arm64@1.20240512.0': - resolution: {integrity: sha512-YPezHMySL9J9tFdzxz390eBswQ//QJNYcZolz9Dgvb3FEfdpK345cE/bsWbMOqw5ws2f82l388epoenghtYvAg==} - engines: {node: '>=16'} - cpu: [arm64] - os: [linux] - - '@cloudflare/workerd-windows-64@1.20240512.0': - resolution: {integrity: sha512-SxKapDrIYSscMR7lGIp/av0l6vokjH4xQ9ACxHgXh+OdOus9azppSmjaPyw4/ePvg7yqpkaNjf9o258IxWtvKQ==} - engines: {node: '>=16'} - cpu: [x64] - os: [win32] - - '@cloudflare/workers-types@4.20240512.0': - resolution: {integrity: sha512-o2yTEWg+YK/I1t/Me+dA0oarO0aCbjibp6wSeaw52DSE9tDyKJ7S+Qdyw/XsMrKn4t8kF6f/YOba+9O4MJfW9w==} - - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - - '@electric-sql/pglite@0.1.5': - resolution: {integrity: sha512-eymv4ONNvoPZQTvOQIi5dbpR+J5HzEv0qQH9o/y3gvNheJV/P/NFcrbsfJZYTsDKoq7DKrTiFNexsRkJKy8x9Q==} - - '@esbuild-kit/core-utils@3.3.2': - resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} - - '@esbuild-kit/esm-loader@2.6.5': - resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} - - '@esbuild-plugins/node-globals-polyfill@0.2.3': - resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} - peerDependencies: - esbuild: '*' - - '@esbuild-plugins/node-modules-polyfill@0.2.2': - resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} - peerDependencies: - esbuild: '*' - - '@esbuild/aix-ppc64@0.19.12': - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.17.19': - resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.18.20': - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.19.12': - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.17.19': - resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.18.20': - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.19.12': - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.17.19': - resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.18.20': - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.19.12': - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.17.19': - resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.18.20': - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.19.12': - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.17.19': - resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.18.20': - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.19.12': - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.17.19': - resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.18.20': - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.19.12': - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.17.19': - resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.18.20': - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.19.12': - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.17.19': - resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.18.20': - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.19.12': - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.17.19': - resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.18.20': - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.19.12': - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.17.19': - resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.18.20': - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.19.12': - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.14.54': - resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.17.19': - resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.18.20': - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.19.12': - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.17.19': - resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.18.20': - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.19.12': - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.17.19': - resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.18.20': - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.19.12': - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.17.19': - resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.18.20': - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.19.12': - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.17.19': - resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.18.20': - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.19.12': - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.17.19': - resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.18.20': - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.19.12': - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-x64@0.17.19': - resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.18.20': - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.19.12': - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-x64@0.17.19': - resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.18.20': - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.19.12': - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.17.19': - resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.18.20': - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.19.12': - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.17.19': - resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.18.20': - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.19.12': - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.17.19': - resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.18.20': - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.19.12': - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.17.19': - resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.18.20': - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.19.12': - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@ewoudenberg/difflib@0.1.0': - resolution: {integrity: sha512-OU5P5mJyD3OoWYMWY+yIgwvgNS9cFAU10f+DDuvtogcWQOoJIsQ4Hy2McSfUfhKjq8L0FuWVb4Rt7kgA+XK86A==} - - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - - '@hono/node-server@1.11.1': - resolution: {integrity: sha512-GW1Iomhmm1o4Z+X57xGby8A35Cu9UZLL7pSMdqDBkD99U5cywff8F+8hLk5aBTzNubnsFAvWQ/fZjNwPsEn9lA==} - engines: {node: '>=18.14.1'} - - '@hono/zod-validator@0.2.1': - resolution: {integrity: sha512-HFoxln7Q6JsE64qz2WBS28SD33UB2alp3aRKmcWnNLDzEL1BLsWfbdX6e1HIiUprHYTIXf5y7ax8eYidKUwyaA==} - peerDependencies: - hono: '>=3.9.0' - zod: ^3.19.1 - - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/gen-mapping@0.3.5': - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - - '@libsql/client@0.4.3': - resolution: {integrity: sha512-AUYKnSPqAsFBVWBvmtrb4dG3pQlvTKT92eztAest9wQU2iJkabH8WzHLDb3dKFWKql7/kiCqvBQUVpozDwhekQ==} - - '@libsql/core@0.4.3': - resolution: {integrity: sha512-r28iYBtaLBW9RRgXPFh6cGCsVI/rwRlOzSOpAu/1PVTm6EJ3t233pUf97jETVHU0vjdr1d8VvV6fKAvJkokqCw==} - - '@libsql/darwin-arm64@0.2.0': - resolution: {integrity: sha512-+qyT2W/n5CFH1YZWv2mxW4Fsoo4dX9Z9M/nvbQqZ7H84J8hVegvVAsIGYzcK8xAeMEcpU5yGKB1Y9NoDY4hOSQ==} - cpu: [arm64] - os: [darwin] - - '@libsql/darwin-x64@0.2.0': - resolution: {integrity: sha512-hwmO2mF1n8oDHKFrUju6Jv+n9iFtTf5JUK+xlnIE3Td0ZwGC/O1R/Z/btZTd9nD+vsvakC8SJT7/Q6YlWIkhEw==} - cpu: [x64] - os: [darwin] - - '@libsql/hrana-client@0.5.6': - resolution: {integrity: sha512-mjQoAmejZ1atG+M3YR2ZW+rg6ceBByH/S/h17ZoYZkqbWrvohFhXyz2LFxj++ARMoY9m6w3RJJIRdJdmnEUlFg==} - - '@libsql/isomorphic-fetch@0.1.12': - resolution: {integrity: sha512-MRo4UcmjAGAa3ac56LoD5OE13m2p0lu0VEtZC2NZMcogM/jc5fU9YtMQ3qbPjFJ+u2BBjFZgMPkQaLS1dlMhpg==} - - '@libsql/isomorphic-ws@0.1.5': - resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - - '@libsql/linux-arm64-gnu@0.2.0': - resolution: {integrity: sha512-1w2lPXIYtnBaK5t/Ej5E8x7lPiE+jP3KATI/W4yei5Z/ONJh7jQW5PJ7sYU95vTME3hWEM1FXN6kvzcpFAte7w==} - cpu: [arm64] - os: [linux] - - '@libsql/linux-arm64-musl@0.2.0': - resolution: {integrity: sha512-lkblBEJ7xuNiWNjP8DDq0rqoWccszfkUS7Efh5EjJ+GDWdCBVfh08mPofIZg0fZVLWQCY3j+VZCG1qZfATBizg==} - cpu: [arm64] - os: [linux] - - '@libsql/linux-x64-gnu@0.2.0': - resolution: {integrity: sha512-+x/d289KeJydwOhhqSxKT+6MSQTCfLltzOpTzPccsvdt5fxg8CBi+gfvEJ4/XW23Sa+9bc7zodFP0i6MOlxX7w==} - cpu: [x64] - os: [linux] - - '@libsql/linux-x64-musl@0.2.0': - resolution: {integrity: sha512-5Xn0c5A6vKf9D1ASpgk7mef//FuY7t5Lktj/eiU4n3ryxG+6WTpqstTittJUgepVjcleLPYxIhQAYeYwTYH1IQ==} - cpu: [x64] - os: [linux] - - '@libsql/win32-x64-msvc@0.2.0': - resolution: {integrity: sha512-rpK+trBIpRST15m3cMYg5aPaX7kvCIottxY7jZPINkKAaScvfbn9yulU/iZUM9YtuK96Y1ZmvwyVIK/Y5DzoMQ==} - cpu: [x64] - os: [win32] - - '@neon-rs/load@0.0.4': - resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} - - '@neondatabase/serverless@0.7.2': - resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==} - - '@neondatabase/serverless@0.9.3': - resolution: {integrity: sha512-6ZBK8asl2Z3+ADEaELvbaVVGVlmY1oAzkxxZfpmXPKFuJhbDN+5fU3zYBamsahS/Ch1zE+CVWB3R+8QEI2LMSw==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@originjs/vite-plugin-commonjs@1.0.3': - resolution: {integrity: sha512-KuEXeGPptM2lyxdIEJ4R11+5ztipHoE7hy8ClZt3PYaOVQ/pyngd2alaSrPnwyFeOW1UagRBaQ752aA1dTMdOQ==} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@pkgr/core@0.1.1': - resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - - '@planetscale/database@1.18.0': - resolution: {integrity: sha512-t2XdOfrVgcF7AW791FtdPS27NyNqcE1SpoXgk3HpziousvUMsJi4Q6NL3JyOBpsMOrvk94749o8yyonvX5quPw==} - engines: {node: '>=16'} - - '@rollup/rollup-android-arm-eabi@4.17.2': - resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.17.2': - resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.17.2': - resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.17.2': - resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': - resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.17.2': - resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.17.2': - resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.17.2': - resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': - resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.17.2': - resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.17.2': - resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.17.2': - resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.17.2': - resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.17.2': - resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.17.2': - resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.17.2': - resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==} - cpu: [x64] - os: [win32] - - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@smithy/abort-controller@3.0.0': - resolution: {integrity: sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==} - engines: {node: '>=16.0.0'} - - '@smithy/config-resolver@3.0.0': - resolution: {integrity: sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw==} - engines: {node: '>=16.0.0'} - - '@smithy/core@2.0.1': - resolution: {integrity: sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg==} - engines: {node: '>=16.0.0'} - - '@smithy/credential-provider-imds@3.0.0': - resolution: {integrity: sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA==} - engines: {node: '>=16.0.0'} - - '@smithy/fetch-http-handler@3.0.1': - resolution: {integrity: sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==} - - '@smithy/hash-node@3.0.0': - resolution: {integrity: sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==} - engines: {node: '>=16.0.0'} - - '@smithy/invalid-dependency@3.0.0': - resolution: {integrity: sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==} - - '@smithy/is-array-buffer@3.0.0': - resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-content-length@3.0.0': - resolution: {integrity: sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-endpoint@3.0.0': - resolution: {integrity: sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-retry@3.0.1': - resolution: {integrity: sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-serde@3.0.0': - resolution: {integrity: sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-stack@3.0.0': - resolution: {integrity: sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==} - engines: {node: '>=16.0.0'} - - '@smithy/node-config-provider@3.0.0': - resolution: {integrity: sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g==} - engines: {node: '>=16.0.0'} - - '@smithy/node-http-handler@3.0.0': - resolution: {integrity: sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==} - engines: {node: '>=16.0.0'} - - '@smithy/property-provider@3.0.0': - resolution: {integrity: sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ==} - engines: {node: '>=16.0.0'} - - '@smithy/protocol-http@4.0.0': - resolution: {integrity: sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==} - engines: {node: '>=16.0.0'} - - '@smithy/querystring-builder@3.0.0': - resolution: {integrity: sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==} - engines: {node: '>=16.0.0'} - - '@smithy/querystring-parser@3.0.0': - resolution: {integrity: sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==} - engines: {node: '>=16.0.0'} - - '@smithy/service-error-classification@3.0.0': - resolution: {integrity: sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==} - engines: {node: '>=16.0.0'} - - '@smithy/shared-ini-file-loader@3.0.0': - resolution: {integrity: sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog==} - engines: {node: '>=16.0.0'} - - '@smithy/signature-v4@3.0.0': - resolution: {integrity: sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==} - engines: {node: '>=16.0.0'} - - '@smithy/smithy-client@3.0.1': - resolution: {integrity: sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw==} - engines: {node: '>=16.0.0'} - - '@smithy/types@3.0.0': - resolution: {integrity: sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==} - engines: {node: '>=16.0.0'} - - '@smithy/url-parser@3.0.0': - resolution: {integrity: sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==} - - '@smithy/util-base64@3.0.0': - resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-body-length-browser@3.0.0': - resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} - - '@smithy/util-body-length-node@3.0.0': - resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} - engines: {node: '>=16.0.0'} - - '@smithy/util-buffer-from@3.0.0': - resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} - engines: {node: '>=16.0.0'} - - '@smithy/util-config-provider@3.0.0': - resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-defaults-mode-browser@3.0.1': - resolution: {integrity: sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg==} - engines: {node: '>= 10.0.0'} - - '@smithy/util-defaults-mode-node@3.0.1': - resolution: {integrity: sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q==} - engines: {node: '>= 10.0.0'} - - '@smithy/util-endpoints@2.0.0': - resolution: {integrity: sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-hex-encoding@3.0.0': - resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-middleware@3.0.0': - resolution: {integrity: sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-retry@3.0.0': - resolution: {integrity: sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==} - engines: {node: '>=16.0.0'} - - '@smithy/util-stream@3.0.1': - resolution: {integrity: sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==} - engines: {node: '>=16.0.0'} - - '@smithy/util-uri-escape@3.0.0': - resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} - engines: {node: '>=16.0.0'} - - '@smithy/util-utf8@3.0.0': - resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} - engines: {node: '>=16.0.0'} - - '@types/better-sqlite3@7.6.10': - resolution: {integrity: sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==} - - '@types/docker-modem@3.0.6': - resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} - - '@types/dockerode@3.3.29': - resolution: {integrity: sha512-5PRRq/yt5OT/Jf77ltIdz4EiR9+VLnPF+HpU4xGFwUqmV24Co2HKBNW3w+slqZ1CYchbcDeqJASHDYWzZCcMiQ==} - - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - - '@types/fs-extra@11.0.4': - resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - - '@types/glob@8.1.0': - resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} - - '@types/json-diff@1.0.3': - resolution: {integrity: sha512-Qvxm8fpRMv/1zZR3sQWImeRK2mBYJji20xF51Fq9Gt//Ed18u0x6/FNLogLS1xhfUWTEmDyqveJqn95ltB6Kvw==} - - '@types/jsonfile@6.1.4': - resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} - - '@types/minimatch@5.1.2': - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - - '@types/minimist@1.2.5': - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - - '@types/node-fetch@2.6.11': - resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} - - '@types/node-forge@1.3.11': - resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - - '@types/node@18.19.33': - resolution: {integrity: sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==} - - '@types/pg@8.11.6': - resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} - - '@types/pg@8.6.6': - resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} - - '@types/pluralize@0.0.33': - resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} - - '@types/ps-tree@1.1.6': - resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} - - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - - '@types/ssh2@1.15.0': - resolution: {integrity: sha512-YcT8jP5F8NzWeevWvcyrrLB3zcneVjzYY9ZDSMAMboI+2zR1qYWFhwsyOFVzT7Jorn67vqxC0FRiw8YyG9P1ww==} - - '@types/uuid@9.0.8': - resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - - '@types/which@3.0.3': - resolution: {integrity: sha512-2C1+XoY0huExTbs8MQv1DuS5FS86+SEjdM9F/+GS61gg5Hqbtj8ZiDSx8MfWcyei907fIPbfPGCOrNUTnVHY1g==} - - '@types/ws@8.5.10': - resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} - - '@typescript-eslint/eslint-plugin@7.10.0': - resolution: {integrity: sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@7.10.0': - resolution: {integrity: sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@7.10.0': - resolution: {integrity: sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/type-utils@7.10.0': - resolution: {integrity: sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@7.10.0': - resolution: {integrity: sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/typescript-estree@7.10.0': - resolution: {integrity: sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@7.10.0': - resolution: {integrity: sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - - '@typescript-eslint/visitor-keys@7.10.0': - resolution: {integrity: sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - - '@vercel/postgres@0.8.0': - resolution: {integrity: sha512-/QUV9ExwaNdKooRjOQqvrKNVnRvsaXeukPNI5DB1ovUTesglfR/fparw7ngo1KUWWKIVpEj2TRrA+ObRHRdaLg==} - engines: {node: '>=14.6'} - - '@vitest/expect@1.6.0': - resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} - - '@vitest/runner@1.6.0': - resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} - - '@vitest/snapshot@1.6.0': - resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} - - '@vitest/spy@1.6.0': - resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} - - '@vitest/utils@1.6.0': - resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - - aggregate-error@4.0.1: - resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} - engines: {node: '>=12'} - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ansi-escapes@6.2.1: - resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} - engines: {node: '>=14.16'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - ansicolors@0.3.2: - resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-find-index@1.0.2: - resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} - engines: {node: '>=0.10.0'} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - arrgv@1.0.2: - resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} - engines: {node: '>=8.0.0'} - - arrify@3.0.0: - resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} - engines: {node: '>=12'} - - as-table@1.0.55: - resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} - - asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - ava@5.3.1: - resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} - engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} - hasBin: true - peerDependencies: - '@ava/typescript': '*' - peerDependenciesMeta: - '@ava/typescript': - optional: true - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - - better-sqlite3@9.6.0: - resolution: {integrity: sha512-yR5HATnqeYNVnkaUTf4bOP2dJSnyhP4puJN/QPRyx4YkBEEUxib422n2XzPqDEHjQQqazoYoADdAm5vE15+dAQ==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - blake3-wasm@2.1.5: - resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - - blueimp-md5@2.19.0: - resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} - - bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - bufferutil@4.0.8: - resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} - engines: {node: '>=6.14.2'} - - buildcheck@0.0.6: - resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} - engines: {node: '>=10.0.0'} - - bundle-require@4.1.0: - resolution: {integrity: sha512-FeArRFM+ziGkRViKRnSTbHZc35dgmR9yNog05Kn0+ItI59pOAISGvnnIwW1WgFZQW59IxD9QpJnUPkdIPfZuXg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.17' - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - callsites@4.1.0: - resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} - engines: {node: '>=12.20'} - - camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - - capnp-ts@0.7.0: - resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} - - cardinal@2.1.1: - resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} - hasBin: true - - cbor@8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} - - chai@4.4.1: - resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - - chunkd@2.0.1: - resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - ci-parallel-vars@1.0.1: - resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} - - clean-stack@4.2.0: - resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} - engines: {node: '>=12'} - - clean-yaml-object@0.1.0: - resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} - engines: {node: '>=0.10.0'} - - cli-color@2.0.4: - resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} - engines: {node: '>=0.10'} - - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} - engines: {node: 10.* || >= 12.*} - - cli-truncate@3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - code-excerpt@4.0.0: - resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - common-path-prefix@3.0.0: - resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concordance@5.0.4: - resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} - engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} - - confbox@0.1.7: - resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} - - convert-to-spaces@2.0.1: - resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} - engines: {node: '>= 0.6'} - - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - - cpu-features@0.0.10: - resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} - engines: {node: '>=10.0.0'} - - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - - currently-unhandled@0.4.1: - resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} - engines: {node: '>=0.10.0'} - - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - - data-uri-to-buffer@2.0.2: - resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} - - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - - date-time@3.1.0: - resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} - engines: {node: '>=6'} - - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} - engines: {node: '>=6'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - - detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} - engines: {node: '>=8'} - - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} - - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - docker-modem@3.0.8: - resolution: {integrity: sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==} - engines: {node: '>= 8.0'} - - dockerode@3.3.5: - resolution: {integrity: sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==} - engines: {node: '>= 8.0'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - dotenv@16.4.5: - resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} - engines: {node: '>=12'} - - dreamopt@0.8.0: - resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} - engines: {node: '>=0.4.0'} - - drizzle-kit@0.21.2: - resolution: {integrity: sha512-U87IhZyCt/9d0ZT/Na3KFJVY31tSxtTx/n9UMcWFpW/5c2Ede39xiCG5efNV/0iimsv97UIRtDI0ldLBW5lbcg==} - hasBin: true - - drizzle-orm@0.32.0-85c8008: - resolution: {integrity: sha512-gHLqGZz0eqAvSw4vq46sHRV8qLHxrbuCVlwaVZ1t4ntyH8csyCKEXTWO78cBJwYUpz7BCSzqVX+5ZYa/QM+/Gw==} - peerDependencies: - '@aws-sdk/client-rds-data': '>=3' - '@cloudflare/workers-types': '>=3' - '@electric-sql/pglite': '>=0.1.1' - '@libsql/client': '*' - '@neondatabase/serverless': '>=0.1' - '@op-engineering/op-sqlite': '>=2' - '@opentelemetry/api': ^1.4.1 - '@planetscale/database': '>=1' - '@tidbcloud/serverless': '*' - '@types/better-sqlite3': '*' - '@types/pg': '*' - '@types/react': '>=18' - '@types/sql.js': '*' - '@vercel/postgres': '>=0.8.0' - '@xata.io/client': '*' - better-sqlite3: '>=7' - bun-types: '*' - expo-sqlite: '>=13.2.0' - knex: '*' - kysely: '*' - mysql2: '>=2' - pg: '>=8' - postgres: '>=3' - react: '>=18' - sql.js: '>=1' - sqlite3: '>=5' - peerDependenciesMeta: - '@aws-sdk/client-rds-data': - optional: true - '@cloudflare/workers-types': - optional: true - '@electric-sql/pglite': - optional: true - '@libsql/client': - optional: true - '@neondatabase/serverless': - optional: true - '@op-engineering/op-sqlite': - optional: true - '@opentelemetry/api': - optional: true - '@planetscale/database': - optional: true - '@tidbcloud/serverless': - optional: true - '@types/better-sqlite3': - optional: true - '@types/pg': - optional: true - '@types/react': - optional: true - '@types/sql.js': - optional: true - '@vercel/postgres': - optional: true - '@xata.io/client': - optional: true - better-sqlite3: - optional: true - bun-types: - optional: true - expo-sqlite: - optional: true - knex: - optional: true - kysely: - optional: true - mysql2: - optional: true - pg: - optional: true - postgres: - optional: true - react: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - - duplexer@0.1.2: - resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - emittery@1.0.3: - resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} - engines: {node: '>=14.16'} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - emojilib@2.4.0: - resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} - - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - - es6-weak-map@2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - - esbuild-android-64@0.14.54: - resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - esbuild-android-arm64@0.14.54: - resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - esbuild-darwin-64@0.14.54: - resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - esbuild-darwin-arm64@0.14.54: - resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - esbuild-freebsd-64@0.14.54: - resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - esbuild-freebsd-arm64@0.14.54: - resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - esbuild-linux-32@0.14.54: - resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - esbuild-linux-64@0.14.54: - resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - esbuild-linux-arm64@0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - esbuild-linux-arm@0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - esbuild-linux-mips64le@0.14.54: - resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - esbuild-linux-ppc64le@0.14.54: - resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - esbuild-linux-riscv64@0.14.54: - resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - esbuild-linux-s390x@0.14.54: - resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - esbuild-netbsd-64@0.14.54: - resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - esbuild-node-externals@1.13.1: - resolution: {integrity: sha512-ho4Lokc6iMB1lWbb2tWJ6otien+3Kfoaxe0fy7NUNgVuLnfmlW+GRINftTVUGtTVY/dapuwUu/CvFylYNwzkMA==} - engines: {node: '>=12'} - peerDependencies: - esbuild: 0.12 - 0.21 - - esbuild-openbsd-64@0.14.54: - resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - esbuild-register@3.5.0: - resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} - peerDependencies: - esbuild: '>=0.12 <1' - - esbuild-sunos-64@0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - esbuild-windows-32@0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - esbuild-windows-64@0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - esbuild-windows-arm64@0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - esbuild@0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.17.19: - resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} - engines: {node: '>=12'} - hasBin: true - - escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} - - escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-prettier@5.1.3: - resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '*' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@0.6.1: - resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - - event-stream@3.3.4: - resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} - - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - exit-hook@2.2.1: - resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} - engines: {node: '>=6'} - - expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-xml-parser@4.2.5: - resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} - hasBin: true - - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - - figures@5.0.0: - resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} - engines: {node: '>=14'} - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - find-up@6.3.0: - resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - - foreground-child@3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} - engines: {node: '>=14'} - - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - - from@0.1.7: - resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} - - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} - engines: {node: '>=14.14'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - fx@34.0.0: - resolution: {integrity: sha512-/fZih3/WLsrtlaj2mahjWxAmyuikmcl3D5kKPqLtFmEilLsy9wp0+/vEmfvYXXhwJc+ajtCFDCf+yttXmPMHSQ==} - hasBin: true - - generate-function@2.3.1: - resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - - get-port@6.1.2: - resolution: {integrity: sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - get-source@2.0.12: - resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} - - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - get-tsconfig@4.7.5: - resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} - - github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - - glob@10.3.15: - resolution: {integrity: sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==} - engines: {node: '>=16 || 14 >=14.18'} - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - globby@13.2.2: - resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - hanji@0.0.5: - resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - - hono@4.3.9: - resolution: {integrity: sha512-6c5LVE23HnIS8iBhY+XPmYJlPeeClznOi7mBNsAsJCgxo8Ciz75LTjqRUf5wv4RYq8kL+1KPLUZHCtKmbZssNg==} - engines: {node: '>=16.0.0'} - - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore-by-default@2.1.0: - resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} - engines: {node: '>=10 <11 || >=12 <13 || >=14'} - - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - irregular-plurals@3.5.0: - resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} - engines: {node: '>=8'} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - - is-error@2.2.2: - resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-fullwidth-code-point@4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-property@1.0.2: - resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-unicode-supported@1.3.0: - resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} - engines: {node: '>=12'} - - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jackspeak@2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} - - joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - - js-base64@3.7.7: - resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} - - js-string-escape@1.0.1: - resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} - engines: {node: '>= 0.8'} - - js-tokens@9.0.0: - resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} - - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-diff@0.9.0: - resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==} - hasBin: true - - json-diff@1.0.6: - resolution: {integrity: sha512-tcFIPRdlc35YkYdGxcamJjllUhXWv4n2rK9oJ2RsAzV4FBkuV4ojKEDgcZ+kpKxDmJKv+PFK65+1tVVOnSeEqA==} - hasBin: true - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - libsql@0.2.0: - resolution: {integrity: sha512-ELBRqhpJx5Dap0187zKQnntZyk4EjlDHSrjIVL8t+fQ5e8IxbQTeYgZgigMjB1EvrETdkm0Y0VxBGhzPQ+t0Jg==} - cpu: [x64, arm64] - os: [darwin, linux, win32] - - lilconfig@3.1.1: - resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} - engines: {node: '>=14'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - load-json-file@7.0.1: - resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - local-pkg@0.5.0: - resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} - engines: {node: '>=14'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - - lodash.throttle@4.1.1: - resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - - lru-cache@10.2.2: - resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} - engines: {node: 14 || >=16.14} - - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - - lru-queue@0.1.0: - resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} - - magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - - magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} - - map-age-cleaner@0.1.3: - resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} - engines: {node: '>=6'} - - map-stream@0.1.0: - resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} - - marked-terminal@6.2.0: - resolution: {integrity: sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==} - engines: {node: '>=16.0.0'} - peerDependencies: - marked: '>=1 <12' - - marked@9.1.6: - resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} - engines: {node: '>= 16'} - hasBin: true - - matcher@5.0.0: - resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - md5-hex@3.0.1: - resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} - engines: {node: '>=8'} - - mem@9.0.2: - resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} - engines: {node: '>=12.20'} - - memoizee@0.4.15: - resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - miniflare@3.20240512.0: - resolution: {integrity: sha512-X0PlKR0AROKpxFoJNmRtCMIuJxj+ngEcyTOlEokj2rAQ0TBwUhB4/1uiPvdI6ofW5NugPOD1uomAv+gLjwsLDQ==} - engines: {node: '>=16.13'} - hasBin: true - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} - - minimatch@9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.1: - resolution: {integrity: sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==} - engines: {node: '>=16 || 14 >=14.17'} - - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - - mlly@1.7.0: - resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} - - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mustache@4.2.0: - resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} - hasBin: true - - mysql2@2.3.3: - resolution: {integrity: sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==} - engines: {node: '>= 8.0'} - - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - - named-placeholders@1.1.3: - resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} - engines: {node: '>=12.0.0'} - - nan@2.19.0: - resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} - - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - napi-build-utils@1.0.2: - resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - - node-abi@3.62.0: - resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==} - engines: {node: '>=10'} - - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - - node-emoji@2.1.3: - resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} - engines: {node: '>=18'} - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-fetch@3.3.1: - resolution: {integrity: sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - - node-gyp-build@4.8.1: - resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} - hasBin: true - - nofilter@3.1.0: - resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} - engines: {node: '>=12.19'} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-defer@1.0.0: - resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} - engines: {node: '>=4'} - - p-event@5.0.1: - resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - p-limit@5.0.0: - resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} - engines: {node: '>=18'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - p-map@5.5.0: - resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} - engines: {node: '>=12'} - - p-timeout@5.1.0: - resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} - engines: {node: '>=12'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-ms@3.0.0: - resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} - engines: {node: '>=12'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-to-regexp@6.2.2: - resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - - pause-stream@0.0.11: - resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} - - pg-cloudflare@1.1.1: - resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} - - pg-connection-string@2.6.4: - resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-numeric@1.0.2: - resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} - engines: {node: '>=4'} - - pg-pool@3.6.2: - resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} - peerDependencies: - pg: '>=8.0' - - pg-protocol@1.6.1: - resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - - pg-types@4.0.2: - resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} - engines: {node: '>=10'} - - pg@8.11.5: - resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} - engines: {node: '>= 8.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - - pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - - picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - - pkg-conf@4.0.0: - resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - pkg-types@1.1.1: - resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==} - - plur@5.1.0: - resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} - engines: {node: ^10 || ^12 || >=14} - - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-array@3.0.2: - resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} - engines: {node: '>=12'} - - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} - engines: {node: '>=0.10.0'} - - postgres-bytea@3.0.0: - resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} - engines: {node: '>= 6'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-date@2.1.0: - resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} - engines: {node: '>=12'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} - - postgres-interval@3.0.0: - resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} - engines: {node: '>=12'} - - postgres-range@1.1.4: - resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - - postgres@3.4.4: - resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==} - engines: {node: '>=12'} - - prebuild-install@7.1.2: - resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} - engines: {node: '>=10'} - hasBin: true - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - pretty-ms@8.0.0: - resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} - engines: {node: '>=14.16'} - - printable-characters@1.0.42: - resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} - - ps-tree@1.2.0: - resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} - engines: {node: '>= 0.10'} - hasBin: true - - pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - redeyed@2.1.1: - resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - - rollup-plugin-inject@3.0.2: - resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} - deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. - - rollup-plugin-node-polyfills@0.2.1: - resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} - - rollup-pluginutils@2.8.2: - resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - - rollup@4.17.2: - resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - selfsigned@2.4.1: - resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} - engines: {node: '>=10'} - - semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} - engines: {node: '>=10'} - hasBin: true - - seq-queue@0.0.5: - resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - - serialize-error@7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - skin-tone@2.0.0: - resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} - engines: {node: '>=8'} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slash@4.0.0: - resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} - engines: {node: '>=12'} - - slice-ansi@5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} - engines: {node: '>=12'} - - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - - sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - - split-ca@1.0.1: - resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - split@0.3.3: - resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - sqlstring@2.3.3: - resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} - engines: {node: '>= 0.6'} - - ssh2@1.15.0: - resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} - engines: {node: '>=10.16.0'} - - stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - stacktracey@2.1.8: - resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} - - std-env@3.7.0: - resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} - - stoppable@1.1.0: - resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} - engines: {node: '>=4', npm: '>=6'} - - stream-combiner@0.0.4: - resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strip-literal@2.1.0: - resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} - - strnum@1.0.5: - resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} - - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - superjson@2.2.1: - resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} - engines: {node: '>=16'} - - supertap@3.0.1: - resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-hyperlinks@3.0.0: - resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} - engines: {node: '>=14.18'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - synckit@0.8.8: - resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} - engines: {node: ^14.18.0 || >=16.0.0} - - tar-fs@2.0.1: - resolution: {integrity: sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==} - - tar-fs@2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} - - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - - temp-dir@3.0.0: - resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} - engines: {node: '>=14.16'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - - time-zone@1.0.0: - resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} - engines: {node: '>=4'} - - timers-ext@0.1.7: - resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} - - tinybench@2.8.0: - resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} - - tinypool@0.8.4: - resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} - engines: {node: '>=14.0.0'} - - tinyspy@2.2.1: - resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} - engines: {node: '>=14.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - - ts-expose-internals-conditionally@1.0.0-empty.0: - resolution: {integrity: sha512-F8m9NOF6ZhdOClDVdlM8gj3fDCav4ZIFSs/EI3ksQbAAXVSCN/Jh5OCJDDZWBuBy9psFc6jULGDlPwjMYMhJDw==} - - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - - tsconfck@3.0.3: - resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - - tsup@8.0.2: - resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - - tsx@3.14.0: - resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} - hasBin: true - - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - type@2.7.2: - resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} - - typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} - engines: {node: '>=14.17'} - hasBin: true - - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.5.3: - resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} - - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - - undici@5.28.4: - resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} - engines: {node: '>=14.0'} - - unicode-emoji-modifier-base@1.0.0: - resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} - engines: {node: '>=4'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - utf-8-validate@6.0.3: - resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==} - engines: {node: '>=6.14.2'} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - - validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - vite-node@1.6.0: - resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - - vite-tsconfig-paths@4.3.2: - resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - - vite@5.2.11: - resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vitest@1.6.0: - resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.0 - '@vitest/ui': 1.6.0 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - - webpod@0.0.2: - resolution: {integrity: sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg==} - hasBin: true - - well-known-symbols@2.0.0: - resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} - engines: {node: '>=6'} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - which@3.0.1: - resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - hasBin: true - - why-is-node-running@2.2.2: - resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - - workerd@1.20240512.0: - resolution: {integrity: sha512-VUBmR1PscAPHEE0OF/G2K7/H1gnr9aDWWZzdkIgWfNKkv8dKFCT75H+GJtUHjfwqz3rYCzaNZmatSXOpLGpF8A==} - engines: {node: '>=16'} - hasBin: true - - wrangler@3.57.0: - resolution: {integrity: sha512-izK3AZtlFoTq8N0EZjLOQ7hqwsjaXCc1cbNKuhsLJjDX1jB1YZBDPhIhtXL4VVzkJAcH+0Zw2gguOePFCHNaxw==} - engines: {node: '>=16.17.0'} - hasBin: true - peerDependencies: - '@cloudflare/workers-types': ^4.20240512.0 - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - ws@8.14.2: - resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.17.0: - resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - xxhash-wasm@1.0.2: - resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yaml@2.4.2: - resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} - engines: {node: '>= 14'} - hasBin: true - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} - engines: {node: '>=12.20'} - - youch@3.3.3: - resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} - - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} - - zx@7.2.3: - resolution: {integrity: sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==} - engines: {node: '>= 16.0.0'} - hasBin: true - -snapshots: - - '@andrewbranch/untar.js@1.0.3': {} - - '@arethetypeswrong/cli@0.15.3': - dependencies: - '@arethetypeswrong/core': 0.15.1 - chalk: 4.1.2 - cli-table3: 0.6.5 - commander: 10.0.1 - marked: 9.1.6 - marked-terminal: 6.2.0(marked@9.1.6) - semver: 7.6.2 - - '@arethetypeswrong/core@0.15.1': - dependencies: - '@andrewbranch/untar.js': 1.0.3 - fflate: 0.8.2 - semver: 7.6.2 - ts-expose-internals-conditionally: 1.0.0-empty.0 - typescript: 5.3.3 - validate-npm-package-name: 5.0.1 - - '@aws-crypto/ie11-detection@3.0.0': - dependencies: - tslib: 1.14.1 - - '@aws-crypto/sha256-browser@3.0.0': - dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-locate-window': 3.568.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-crypto/sha256-js@3.0.0': - dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.577.0 - tslib: 1.14.1 - - '@aws-crypto/supports-web-crypto@3.0.0': - dependencies: - tslib: 1.14.1 - - '@aws-crypto/util@3.0.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-sdk/client-rds-data@3.577.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sts' - - aws-crt - - '@aws-sdk/client-sso@3.577.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.576.0 - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sts@3.577.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/core@3.576.0': - dependencies: - '@smithy/core': 2.0.1 - '@smithy/protocol-http': 4.0.0 - '@smithy/signature-v4': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-env@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-http@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/node-http-handler': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-ini@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/credential-provider-env': 3.577.0 - '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) - '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - - '@aws-sdk/credential-provider-node@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-sdk/credential-provider-env': 3.577.0 - '@aws-sdk/credential-provider-http': 3.577.0 - '@aws-sdk/credential-provider-ini': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) - '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - - '@aws-sdk/credential-provider-process@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-sso@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))': - dependencies: - '@aws-sdk/client-sso': 3.577.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - - '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-host-header@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-logger@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-recursion-detection@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-user-agent@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/region-config-resolver@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))': - dependencies: - '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/types@3.577.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/util-endpoints@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - '@smithy/util-endpoints': 2.0.0 - tslib: 2.6.2 - - '@aws-sdk/util-locate-window@3.568.0': - dependencies: - tslib: 2.6.2 - - '@aws-sdk/util-user-agent-browser@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - bowser: 2.11.0 - tslib: 2.6.2 - - '@aws-sdk/util-user-agent-node@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/util-utf8-browser@3.259.0': - dependencies: - tslib: 2.6.2 - - '@balena/dockerignore@1.0.2': {} - - '@cloudflare/kv-asset-handler@0.3.2': - dependencies: - mime: 3.0.0 - - '@cloudflare/workerd-darwin-64@1.20240512.0': - optional: true - - '@cloudflare/workerd-darwin-arm64@1.20240512.0': - optional: true - - '@cloudflare/workerd-linux-64@1.20240512.0': - optional: true - - '@cloudflare/workerd-linux-arm64@1.20240512.0': - optional: true - - '@cloudflare/workerd-windows-64@1.20240512.0': - optional: true - - '@cloudflare/workers-types@4.20240512.0': {} - - '@colors/colors@1.5.0': - optional: true - - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - '@electric-sql/pglite@0.1.5': {} - - '@esbuild-kit/core-utils@3.3.2': - dependencies: - esbuild: 0.18.20 - source-map-support: 0.5.21 - - '@esbuild-kit/esm-loader@2.6.5': - dependencies: - '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.7.5 - - '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': - dependencies: - esbuild: 0.17.19 - - '@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19)': - dependencies: - esbuild: 0.17.19 - escape-string-regexp: 4.0.0 - rollup-plugin-node-polyfills: 0.2.1 - - '@esbuild/aix-ppc64@0.19.12': - optional: true - - '@esbuild/aix-ppc64@0.20.2': - optional: true - - '@esbuild/android-arm64@0.17.19': - optional: true - - '@esbuild/android-arm64@0.18.20': - optional: true - - '@esbuild/android-arm64@0.19.12': - optional: true - - '@esbuild/android-arm64@0.20.2': - optional: true - - '@esbuild/android-arm@0.17.19': - optional: true - - '@esbuild/android-arm@0.18.20': - optional: true - - '@esbuild/android-arm@0.19.12': - optional: true - - '@esbuild/android-arm@0.20.2': - optional: true - - '@esbuild/android-x64@0.17.19': - optional: true - - '@esbuild/android-x64@0.18.20': - optional: true - - '@esbuild/android-x64@0.19.12': - optional: true - - '@esbuild/android-x64@0.20.2': - optional: true - - '@esbuild/darwin-arm64@0.17.19': - optional: true - - '@esbuild/darwin-arm64@0.18.20': - optional: true - - '@esbuild/darwin-arm64@0.19.12': - optional: true - - '@esbuild/darwin-arm64@0.20.2': - optional: true - - '@esbuild/darwin-x64@0.17.19': - optional: true - - '@esbuild/darwin-x64@0.18.20': - optional: true - - '@esbuild/darwin-x64@0.19.12': - optional: true - - '@esbuild/darwin-x64@0.20.2': - optional: true - - '@esbuild/freebsd-arm64@0.17.19': - optional: true - - '@esbuild/freebsd-arm64@0.18.20': - optional: true - - '@esbuild/freebsd-arm64@0.19.12': - optional: true - - '@esbuild/freebsd-arm64@0.20.2': - optional: true - - '@esbuild/freebsd-x64@0.17.19': - optional: true - - '@esbuild/freebsd-x64@0.18.20': - optional: true - - '@esbuild/freebsd-x64@0.19.12': - optional: true - - '@esbuild/freebsd-x64@0.20.2': - optional: true - - '@esbuild/linux-arm64@0.17.19': - optional: true - - '@esbuild/linux-arm64@0.18.20': - optional: true - - '@esbuild/linux-arm64@0.19.12': - optional: true - - '@esbuild/linux-arm64@0.20.2': - optional: true - - '@esbuild/linux-arm@0.17.19': - optional: true - - '@esbuild/linux-arm@0.18.20': - optional: true - - '@esbuild/linux-arm@0.19.12': - optional: true - - '@esbuild/linux-arm@0.20.2': - optional: true - - '@esbuild/linux-ia32@0.17.19': - optional: true - - '@esbuild/linux-ia32@0.18.20': - optional: true - - '@esbuild/linux-ia32@0.19.12': - optional: true - - '@esbuild/linux-ia32@0.20.2': - optional: true - - '@esbuild/linux-loong64@0.14.54': - optional: true - - '@esbuild/linux-loong64@0.17.19': - optional: true - - '@esbuild/linux-loong64@0.18.20': - optional: true - - '@esbuild/linux-loong64@0.19.12': - optional: true - - '@esbuild/linux-loong64@0.20.2': - optional: true - - '@esbuild/linux-mips64el@0.17.19': - optional: true - - '@esbuild/linux-mips64el@0.18.20': - optional: true - - '@esbuild/linux-mips64el@0.19.12': - optional: true - - '@esbuild/linux-mips64el@0.20.2': - optional: true - - '@esbuild/linux-ppc64@0.17.19': - optional: true - - '@esbuild/linux-ppc64@0.18.20': - optional: true - - '@esbuild/linux-ppc64@0.19.12': - optional: true - - '@esbuild/linux-ppc64@0.20.2': - optional: true - - '@esbuild/linux-riscv64@0.17.19': - optional: true - - '@esbuild/linux-riscv64@0.18.20': - optional: true - - '@esbuild/linux-riscv64@0.19.12': - optional: true - - '@esbuild/linux-riscv64@0.20.2': - optional: true - - '@esbuild/linux-s390x@0.17.19': - optional: true - - '@esbuild/linux-s390x@0.18.20': - optional: true - - '@esbuild/linux-s390x@0.19.12': - optional: true - - '@esbuild/linux-s390x@0.20.2': - optional: true - - '@esbuild/linux-x64@0.17.19': - optional: true - - '@esbuild/linux-x64@0.18.20': - optional: true - - '@esbuild/linux-x64@0.19.12': - optional: true - - '@esbuild/linux-x64@0.20.2': - optional: true - - '@esbuild/netbsd-x64@0.17.19': - optional: true - - '@esbuild/netbsd-x64@0.18.20': - optional: true - - '@esbuild/netbsd-x64@0.19.12': - optional: true - - '@esbuild/netbsd-x64@0.20.2': - optional: true - - '@esbuild/openbsd-x64@0.17.19': - optional: true - - '@esbuild/openbsd-x64@0.18.20': - optional: true - - '@esbuild/openbsd-x64@0.19.12': - optional: true - - '@esbuild/openbsd-x64@0.20.2': - optional: true - - '@esbuild/sunos-x64@0.17.19': - optional: true - - '@esbuild/sunos-x64@0.18.20': - optional: true - - '@esbuild/sunos-x64@0.19.12': - optional: true - - '@esbuild/sunos-x64@0.20.2': - optional: true - - '@esbuild/win32-arm64@0.17.19': - optional: true - - '@esbuild/win32-arm64@0.18.20': - optional: true - - '@esbuild/win32-arm64@0.19.12': - optional: true - - '@esbuild/win32-arm64@0.20.2': - optional: true - - '@esbuild/win32-ia32@0.17.19': - optional: true - - '@esbuild/win32-ia32@0.18.20': - optional: true - - '@esbuild/win32-ia32@0.19.12': - optional: true - - '@esbuild/win32-ia32@0.20.2': - optional: true - - '@esbuild/win32-x64@0.17.19': - optional: true - - '@esbuild/win32-x64@0.18.20': - optional: true - - '@esbuild/win32-x64@0.19.12': - optional: true - - '@esbuild/win32-x64@0.20.2': - optional: true - - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': - dependencies: - eslint: 8.57.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.10.0': {} - - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@8.57.0': {} - - '@ewoudenberg/difflib@0.1.0': - dependencies: - heap: 0.2.7 - - '@fastify/busboy@2.1.1': {} - - '@hono/node-server@1.11.1': {} - - '@hono/zod-validator@0.2.1(hono@4.3.9)(zod@3.23.8)': - dependencies: - hono: 4.3.9 - zod: 3.23.8 - - '@humanwhocodes/config-array@0.11.14': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/object-schema@2.0.3': {} - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - - '@jridgewell/gen-mapping@0.3.5': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/set-array@1.2.1': {} - - '@jridgewell/sourcemap-codec@1.4.15': {} - - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - '@libsql/client@0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/core': 0.4.3 - '@libsql/hrana-client': 0.5.6(bufferutil@4.0.8)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - optionalDependencies: - libsql: 0.2.0 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - - '@libsql/core@0.4.3': - dependencies: - js-base64: 3.7.7 - - '@libsql/darwin-arm64@0.2.0': - optional: true - - '@libsql/darwin-x64@0.2.0': - optional: true - - '@libsql/hrana-client@0.5.6(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/isomorphic-fetch': 0.1.12 - '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - node-fetch: 3.3.2 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - - '@libsql/isomorphic-fetch@0.1.12': - dependencies: - '@types/node-fetch': 2.6.11 - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@types/ws': 8.5.10 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@libsql/linux-arm64-gnu@0.2.0': - optional: true - - '@libsql/linux-arm64-musl@0.2.0': - optional: true - - '@libsql/linux-x64-gnu@0.2.0': - optional: true - - '@libsql/linux-x64-musl@0.2.0': - optional: true - - '@libsql/win32-x64-msvc@0.2.0': - optional: true - - '@neon-rs/load@0.0.4': - optional: true - - '@neondatabase/serverless@0.7.2': - dependencies: - '@types/pg': 8.6.6 - - '@neondatabase/serverless@0.9.3': - dependencies: - '@types/pg': 8.11.6 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - - '@originjs/vite-plugin-commonjs@1.0.3': - dependencies: - esbuild: 0.14.54 - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@pkgr/core@0.1.1': {} - - '@planetscale/database@1.18.0': {} - - '@rollup/rollup-android-arm-eabi@4.17.2': - optional: true - - '@rollup/rollup-android-arm64@4.17.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.17.2': - optional: true - - '@rollup/rollup-darwin-x64@4.17.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.17.2': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.17.2': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-x64-musl@4.17.2': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.17.2': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.17.2': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.17.2': - optional: true - - '@sinclair/typebox@0.27.8': {} - - '@sindresorhus/is@4.6.0': {} - - '@smithy/abort-controller@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/config-resolver@3.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@smithy/core@2.0.1': - dependencies: - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@smithy/credential-provider-imds@3.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - tslib: 2.6.2 - - '@smithy/fetch-http-handler@3.0.1': - dependencies: - '@smithy/protocol-http': 4.0.0 - '@smithy/querystring-builder': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-base64': 3.0.0 - tslib: 2.6.2 - - '@smithy/hash-node@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/invalid-dependency@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/is-array-buffer@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/middleware-content-length@3.0.0': - dependencies: - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/middleware-endpoint@3.0.0': - dependencies: - '@smithy/middleware-serde': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@smithy/middleware-retry@3.0.1': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/service-error-classification': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - tslib: 2.6.2 - uuid: 9.0.1 - - '@smithy/middleware-serde@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/middleware-stack@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/node-config-provider@3.0.0': - dependencies: - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/node-http-handler@3.0.0': - dependencies: - '@smithy/abort-controller': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/querystring-builder': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/property-provider@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/protocol-http@4.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/querystring-builder@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - '@smithy/util-uri-escape': 3.0.0 - tslib: 2.6.2 - - '@smithy/querystring-parser@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/service-error-classification@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - - '@smithy/shared-ini-file-loader@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/signature-v4@3.0.0': - dependencies: - '@smithy/is-array-buffer': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-uri-escape': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/smithy-client@3.0.1': - dependencies: - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 - - '@smithy/types@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/url-parser@3.0.0': - dependencies: - '@smithy/querystring-parser': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-base64@3.0.0': - dependencies: - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-body-length-browser@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-body-length-node@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-buffer-from@3.0.0': - dependencies: - '@smithy/is-array-buffer': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-config-provider@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-defaults-mode-browser@3.0.1': - dependencies: - '@smithy/property-provider': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - bowser: 2.11.0 - tslib: 2.6.2 - - '@smithy/util-defaults-mode-node@3.0.1': - dependencies: - '@smithy/config-resolver': 3.0.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-endpoints@2.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-hex-encoding@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-middleware@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-retry@3.0.0': - dependencies: - '@smithy/service-error-classification': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-stream@3.0.1': - dependencies: - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/node-http-handler': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-uri-escape@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-utf8@3.0.0': - dependencies: - '@smithy/util-buffer-from': 3.0.0 - tslib: 2.6.2 - - '@types/better-sqlite3@7.6.10': - dependencies: - '@types/node': 18.19.33 - - '@types/docker-modem@3.0.6': - dependencies: - '@types/node': 18.19.33 - '@types/ssh2': 1.15.0 - - '@types/dockerode@3.3.29': - dependencies: - '@types/docker-modem': 3.0.6 - '@types/node': 18.19.33 - '@types/ssh2': 1.15.0 - - '@types/estree@1.0.5': {} - - '@types/fs-extra@11.0.4': - dependencies: - '@types/jsonfile': 6.1.4 - '@types/node': 18.19.33 - - '@types/glob@8.1.0': - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 18.19.33 - - '@types/json-diff@1.0.3': {} - - '@types/jsonfile@6.1.4': - dependencies: - '@types/node': 18.19.33 - - '@types/minimatch@5.1.2': {} - - '@types/minimist@1.2.5': {} - - '@types/node-fetch@2.6.11': - dependencies: - '@types/node': 18.19.33 - form-data: 4.0.0 - - '@types/node-forge@1.3.11': - dependencies: - '@types/node': 18.19.33 - - '@types/node@18.19.33': - dependencies: - undici-types: 5.26.5 - - '@types/pg@8.11.6': - dependencies: - '@types/node': 18.19.33 - pg-protocol: 1.6.1 - pg-types: 4.0.2 - - '@types/pg@8.6.6': - dependencies: - '@types/node': 18.19.33 - pg-protocol: 1.6.1 - pg-types: 2.2.0 - - '@types/pluralize@0.0.33': {} - - '@types/ps-tree@1.1.6': {} - - '@types/semver@7.5.8': {} - - '@types/ssh2@1.15.0': - dependencies: - '@types/node': 18.19.33 - - '@types/uuid@9.0.8': {} - - '@types/which@3.0.3': {} - - '@types/ws@8.5.10': - dependencies: - '@types/node': 18.19.33 - - '@typescript-eslint/eslint-plugin@7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.10.0 - '@typescript-eslint/type-utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.10.0 - eslint: 8.57.0 - graphemer: 1.4.0 - ignore: 5.3.1 - natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@typescript-eslint/scope-manager': 7.10.0 - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.10.0 - debug: 4.3.4 - eslint: 8.57.0 - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@7.10.0': - dependencies: - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/visitor-keys': 7.10.0 - - '@typescript-eslint/type-utils@7.10.0(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.4 - eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@7.10.0': {} - - '@typescript-eslint/typescript-estree@7.10.0(typescript@5.4.5)': - dependencies: - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/visitor-keys': 7.10.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.4 - semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@7.10.0(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.10.0 - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) - eslint: 8.57.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@7.10.0': - dependencies: - '@typescript-eslint/types': 7.10.0 - eslint-visitor-keys: 3.4.3 - - '@ungap/structured-clone@1.2.0': {} - - '@vercel/postgres@0.8.0': - dependencies: - '@neondatabase/serverless': 0.7.2 - bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) - - '@vitest/expect@1.6.0': - dependencies: - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - chai: 4.4.1 - - '@vitest/runner@1.6.0': - dependencies: - '@vitest/utils': 1.6.0 - p-limit: 5.0.0 - pathe: 1.1.2 - - '@vitest/snapshot@1.6.0': - dependencies: - magic-string: 0.30.10 - pathe: 1.1.2 - pretty-format: 29.7.0 - - '@vitest/spy@1.6.0': - dependencies: - tinyspy: 2.2.1 - - '@vitest/utils@1.6.0': - dependencies: - diff-sequences: 29.6.3 - estree-walker: 3.0.3 - loupe: 2.3.7 - pretty-format: 29.7.0 - - acorn-jsx@5.3.2(acorn@8.11.3): - dependencies: - acorn: 8.11.3 - - acorn-walk@8.3.2: {} - - acorn@8.11.3: {} - - aggregate-error@4.0.1: - dependencies: - clean-stack: 4.2.0 - indent-string: 5.0.0 - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-escapes@6.2.1: {} - - ansi-regex@5.0.1: {} - - ansi-regex@6.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - ansi-styles@6.2.1: {} - - ansicolors@0.3.2: {} - - any-promise@1.3.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - array-find-index@1.0.2: {} - - array-union@2.1.0: {} - - arrgv@1.0.2: {} - - arrify@3.0.0: {} - - as-table@1.0.55: - dependencies: - printable-characters: 1.0.42 - - asn1@0.2.6: - dependencies: - safer-buffer: 2.1.2 - - assertion-error@1.1.0: {} - - asynckit@0.4.0: {} - - ava@5.3.1: - dependencies: - acorn: 8.11.3 - acorn-walk: 8.3.2 - ansi-styles: 6.2.1 - arrgv: 1.0.2 - arrify: 3.0.0 - callsites: 4.1.0 - cbor: 8.1.0 - chalk: 5.3.0 - chokidar: 3.6.0 - chunkd: 2.0.1 - ci-info: 3.9.0 - ci-parallel-vars: 1.0.1 - clean-yaml-object: 0.1.0 - cli-truncate: 3.1.0 - code-excerpt: 4.0.0 - common-path-prefix: 3.0.0 - concordance: 5.0.4 - currently-unhandled: 0.4.1 - debug: 4.3.4 - emittery: 1.0.3 - figures: 5.0.0 - globby: 13.2.2 - ignore-by-default: 2.1.0 - indent-string: 5.0.0 - is-error: 2.2.2 - is-plain-object: 5.0.0 - is-promise: 4.0.0 - matcher: 5.0.0 - mem: 9.0.2 - ms: 2.1.3 - p-event: 5.0.1 - p-map: 5.5.0 - picomatch: 2.3.1 - pkg-conf: 4.0.0 - plur: 5.1.0 - pretty-ms: 8.0.0 - resolve-cwd: 3.0.0 - stack-utils: 2.0.6 - strip-ansi: 7.1.0 - supertap: 3.0.1 - temp-dir: 3.0.0 - write-file-atomic: 5.0.1 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - - balanced-match@1.0.2: {} - - base64-js@1.5.1: {} - - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 - - better-sqlite3@9.6.0: - dependencies: - bindings: 1.5.0 - prebuild-install: 7.1.2 - - binary-extensions@2.3.0: {} - - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - - blake3-wasm@2.1.5: {} - - blueimp-md5@2.19.0: {} - - bowser@2.11.0: {} - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.2: - dependencies: - fill-range: 7.1.1 - - buffer-from@1.1.2: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bufferutil@4.0.8: - dependencies: - node-gyp-build: 4.8.1 - - buildcheck@0.0.6: - optional: true - - bundle-require@4.1.0(esbuild@0.19.12): - dependencies: - esbuild: 0.19.12 - load-tsconfig: 0.2.5 - - cac@6.7.14: {} - - callsites@3.1.0: {} - - callsites@4.1.0: {} - - camelcase@7.0.1: {} - - capnp-ts@0.7.0: - dependencies: - debug: 4.3.4 - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - - cardinal@2.1.1: - dependencies: - ansicolors: 0.3.2 - redeyed: 2.1.1 - - cbor@8.1.0: - dependencies: - nofilter: 3.1.0 - - chai@4.4.1: - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.3 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.0.8 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chalk@5.3.0: {} - - char-regex@1.0.2: {} - - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - chownr@1.1.4: {} - - chunkd@2.0.1: {} - - ci-info@3.9.0: {} - - ci-parallel-vars@1.0.1: {} - - clean-stack@4.2.0: - dependencies: - escape-string-regexp: 5.0.0 - - clean-yaml-object@0.1.0: {} - - cli-color@2.0.4: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - memoizee: 0.4.15 - timers-ext: 0.1.7 - - cli-table3@0.6.5: - dependencies: - string-width: 4.2.3 - optionalDependencies: - '@colors/colors': 1.5.0 - - cli-truncate@3.1.0: - dependencies: - slice-ansi: 5.0.0 - string-width: 5.1.2 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - code-excerpt@4.0.0: - dependencies: - convert-to-spaces: 2.0.1 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - colors@1.4.0: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@10.0.1: {} - - commander@12.1.0: {} - - commander@4.1.1: {} - - commander@9.5.0: {} - - common-path-prefix@3.0.0: {} - - concat-map@0.0.1: {} - - concordance@5.0.4: - dependencies: - date-time: 3.1.0 - esutils: 2.0.3 - fast-diff: 1.3.0 - js-string-escape: 1.0.1 - lodash: 4.17.21 - md5-hex: 3.0.1 - semver: 7.6.2 - well-known-symbols: 2.0.0 - - confbox@0.1.7: {} - - convert-to-spaces@2.0.1: {} - - cookie@0.5.0: {} - - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - - cpu-features@0.0.10: - dependencies: - buildcheck: 0.0.6 - nan: 2.19.0 - optional: true - - cross-spawn@7.0.3: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - currently-unhandled@0.4.1: - dependencies: - array-find-index: 1.0.2 - - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.2 - - data-uri-to-buffer@2.0.2: {} - - data-uri-to-buffer@4.0.1: {} - - date-time@3.1.0: - dependencies: - time-zone: 1.0.0 - - debug@4.3.4: - dependencies: - ms: 2.1.2 - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - deep-eql@4.1.3: - dependencies: - type-detect: 4.0.8 - - deep-extend@0.6.0: {} - - deep-is@0.1.4: {} - - delayed-stream@1.0.0: {} - - denque@2.1.0: {} - - detect-libc@2.0.2: - optional: true - - detect-libc@2.0.3: {} - - diff-sequences@29.6.3: {} - - difflib@0.2.4(patch_hash=jq4t3ysdpnbunjeje4v7nrqn2q): - dependencies: - heap: 0.2.7 - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - docker-modem@3.0.8: - dependencies: - debug: 4.3.4 - readable-stream: 3.6.2 - split-ca: 1.0.1 - ssh2: 1.15.0 - transitivePeerDependencies: - - supports-color - - dockerode@3.3.5: - dependencies: - '@balena/dockerignore': 1.0.2 - docker-modem: 3.0.8 - tar-fs: 2.0.1 - transitivePeerDependencies: - - supports-color - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dotenv@16.4.5: {} - - dreamopt@0.8.0: - dependencies: - wordwrap: 1.0.0 - - drizzle-kit@0.21.2: - dependencies: - '@esbuild-kit/esm-loader': 2.6.5 - commander: 9.5.0 - env-paths: 3.0.0 - esbuild: 0.19.12 - esbuild-register: 3.5.0(esbuild@0.19.12) - glob: 8.1.0 - hanji: 0.0.5 - json-diff: 0.9.0 - zod: 3.23.8 - transitivePeerDependencies: - - supports-color - - drizzle-orm@0.32.0-85c8008(@aws-sdk/client-rds-data@3.577.0)(@cloudflare/workers-types@4.20240512.0)(@electric-sql/pglite@0.1.5)(@libsql/client@0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(mysql2@2.3.3)(pg@8.11.5)(postgres@3.4.4): - optionalDependencies: - '@aws-sdk/client-rds-data': 3.577.0 - '@cloudflare/workers-types': 4.20240512.0 - '@electric-sql/pglite': 0.1.5 - '@libsql/client': 0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@neondatabase/serverless': 0.9.3 - '@planetscale/database': 1.18.0 - '@types/better-sqlite3': 7.6.10 - '@types/pg': 8.11.6 - '@vercel/postgres': 0.8.0 - better-sqlite3: 9.6.0 - mysql2: 2.3.3 - pg: 8.11.5 - postgres: 3.4.4 - - duplexer@0.1.2: {} - - eastasianwidth@0.2.0: {} - - emittery@1.0.3: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - emojilib@2.4.0: {} - - end-of-stream@1.4.4: - dependencies: - once: 1.4.0 - - env-paths@3.0.0: {} - - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - - es6-weak-map@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - - esbuild-android-64@0.14.54: - optional: true - - esbuild-android-arm64@0.14.54: - optional: true - - esbuild-darwin-64@0.14.54: - optional: true - - esbuild-darwin-arm64@0.14.54: - optional: true - - esbuild-freebsd-64@0.14.54: - optional: true - - esbuild-freebsd-arm64@0.14.54: - optional: true - - esbuild-linux-32@0.14.54: - optional: true - - esbuild-linux-64@0.14.54: - optional: true - - esbuild-linux-arm64@0.14.54: - optional: true - - esbuild-linux-arm@0.14.54: - optional: true - - esbuild-linux-mips64le@0.14.54: - optional: true - - esbuild-linux-ppc64le@0.14.54: - optional: true - - esbuild-linux-riscv64@0.14.54: - optional: true - - esbuild-linux-s390x@0.14.54: - optional: true - - esbuild-netbsd-64@0.14.54: - optional: true - - esbuild-node-externals@1.13.1(esbuild@0.19.12): - dependencies: - esbuild: 0.19.12 - find-up: 5.0.0 - tslib: 2.6.2 - - esbuild-openbsd-64@0.14.54: - optional: true - - esbuild-register@3.5.0(esbuild@0.19.12): - dependencies: - debug: 4.3.4 - esbuild: 0.19.12 - transitivePeerDependencies: - - supports-color - - esbuild-sunos-64@0.14.54: - optional: true - - esbuild-windows-32@0.14.54: - optional: true - - esbuild-windows-64@0.14.54: - optional: true - - esbuild-windows-arm64@0.14.54: - optional: true - - esbuild@0.14.54: - optionalDependencies: - '@esbuild/linux-loong64': 0.14.54 - esbuild-android-64: 0.14.54 - esbuild-android-arm64: 0.14.54 - esbuild-darwin-64: 0.14.54 - esbuild-darwin-arm64: 0.14.54 - esbuild-freebsd-64: 0.14.54 - esbuild-freebsd-arm64: 0.14.54 - esbuild-linux-32: 0.14.54 - esbuild-linux-64: 0.14.54 - esbuild-linux-arm: 0.14.54 - esbuild-linux-arm64: 0.14.54 - esbuild-linux-mips64le: 0.14.54 - esbuild-linux-ppc64le: 0.14.54 - esbuild-linux-riscv64: 0.14.54 - esbuild-linux-s390x: 0.14.54 - esbuild-netbsd-64: 0.14.54 - esbuild-openbsd-64: 0.14.54 - esbuild-sunos-64: 0.14.54 - esbuild-windows-32: 0.14.54 - esbuild-windows-64: 0.14.54 - esbuild-windows-arm64: 0.14.54 - - esbuild@0.17.19: - optionalDependencies: - '@esbuild/android-arm': 0.17.19 - '@esbuild/android-arm64': 0.17.19 - '@esbuild/android-x64': 0.17.19 - '@esbuild/darwin-arm64': 0.17.19 - '@esbuild/darwin-x64': 0.17.19 - '@esbuild/freebsd-arm64': 0.17.19 - '@esbuild/freebsd-x64': 0.17.19 - '@esbuild/linux-arm': 0.17.19 - '@esbuild/linux-arm64': 0.17.19 - '@esbuild/linux-ia32': 0.17.19 - '@esbuild/linux-loong64': 0.17.19 - '@esbuild/linux-mips64el': 0.17.19 - '@esbuild/linux-ppc64': 0.17.19 - '@esbuild/linux-riscv64': 0.17.19 - '@esbuild/linux-s390x': 0.17.19 - '@esbuild/linux-x64': 0.17.19 - '@esbuild/netbsd-x64': 0.17.19 - '@esbuild/openbsd-x64': 0.17.19 - '@esbuild/sunos-x64': 0.17.19 - '@esbuild/win32-arm64': 0.17.19 - '@esbuild/win32-ia32': 0.17.19 - '@esbuild/win32-x64': 0.17.19 - - esbuild@0.18.20: - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - - esbuild@0.19.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - - esbuild@0.20.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 - - escalade@3.1.2: {} - - escape-string-regexp@2.0.0: {} - - escape-string-regexp@4.0.0: {} - - escape-string-regexp@5.0.0: {} - - eslint-config-prettier@9.1.0(eslint@8.57.0): - dependencies: - eslint: 8.57.0 - - eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): - dependencies: - eslint: 8.57.0 - prettier: 2.8.8 - prettier-linter-helpers: 1.0.0 - synckit: 0.8.8 - optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@8.57.0) - - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint@8.57.0: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.1 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.2 - - espree@9.6.1: - dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 3.4.3 - - esprima@4.0.1: {} - - esquery@1.5.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - estree-walker@0.6.1: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.5 - - esutils@2.0.3: {} - - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - - event-stream@3.3.4: - dependencies: - duplexer: 0.1.2 - from: 0.1.7 - map-stream: 0.1.0 - pause-stream: 0.0.11 - split: 0.3.3 - stream-combiner: 0.0.4 - through: 2.3.8 - - execa@5.1.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - - execa@8.0.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - exit-hook@2.2.1: {} - - expand-template@2.0.3: {} - - ext@1.7.0: - dependencies: - type: 2.7.2 - - fast-deep-equal@3.1.3: {} - - fast-diff@1.3.0: {} - - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-xml-parser@4.2.5: - dependencies: - strnum: 1.0.5 - - fastq@1.17.1: - dependencies: - reusify: 1.0.4 - - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - - fflate@0.8.2: {} - - figures@5.0.0: - dependencies: - escape-string-regexp: 5.0.0 - is-unicode-supported: 1.3.0 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - - file-uri-to-path@1.0.0: {} - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - find-up@6.3.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - - flat-cache@3.2.0: - dependencies: - flatted: 3.3.1 - keyv: 4.5.4 - rimraf: 3.0.2 - - flatted@3.3.1: {} - - foreground-child@3.1.1: - dependencies: - cross-spawn: 7.0.3 - signal-exit: 4.1.0 - - form-data@4.0.0: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - - from@0.1.7: {} - - fs-constants@1.0.0: {} - - fs-extra@11.2.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - fx@34.0.0: {} - - generate-function@2.3.1: - dependencies: - is-property: 1.0.2 - - get-caller-file@2.0.5: {} - - get-func-name@2.0.2: {} - - get-port@6.1.2: {} - - get-source@2.0.12: - dependencies: - data-uri-to-buffer: 2.0.2 - source-map: 0.6.1 - - get-stream@6.0.1: {} - - get-stream@8.0.1: {} - - get-tsconfig@4.7.5: - dependencies: - resolve-pkg-maps: 1.0.0 - - github-from-package@0.0.0: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob-to-regexp@0.4.1: {} - - glob@10.3.15: - dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.6 - minimatch: 9.0.4 - minipass: 7.1.1 - path-scurry: 1.11.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 3.0.0 - - globby@13.2.2: - dependencies: - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 4.0.0 - - globrex@0.1.2: {} - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - hanji@0.0.5: - dependencies: - lodash.throttle: 4.1.1 - sisteransi: 1.0.5 - - has-flag@4.0.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - heap@0.2.7: {} - - hono@4.3.9: {} - - human-signals@2.1.0: {} - - human-signals@5.0.0: {} - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: {} - - ignore-by-default@2.1.0: {} - - ignore@5.3.1: {} - - import-fresh@3.3.0: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - indent-string@5.0.0: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ini@1.3.8: {} - - irregular-plurals@3.5.0: {} - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-core-module@2.13.1: - dependencies: - hasown: 2.0.2 - - is-error@2.2.2: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-fullwidth-code-point@4.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-path-inside@3.0.3: {} - - is-plain-object@5.0.0: {} - - is-promise@2.2.2: {} - - is-promise@4.0.0: {} - - is-property@1.0.2: {} - - is-stream@2.0.1: {} - - is-stream@3.0.0: {} - - is-unicode-supported@1.3.0: {} - - is-what@4.1.16: {} - - isexe@2.0.0: {} - - jackspeak@2.3.6: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - joycon@3.1.1: {} - - js-base64@3.7.7: {} - - js-string-escape@1.0.1: {} - - js-tokens@9.0.0: {} - - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-diff@0.9.0: - dependencies: - cli-color: 2.0.4 - difflib: 0.2.4(patch_hash=jq4t3ysdpnbunjeje4v7nrqn2q) - dreamopt: 0.8.0 - - json-diff@1.0.6: - dependencies: - '@ewoudenberg/difflib': 0.1.0 - colors: 1.4.0 - dreamopt: 0.8.0 - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - libsql@0.2.0: - dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - optionalDependencies: - '@libsql/darwin-arm64': 0.2.0 - '@libsql/darwin-x64': 0.2.0 - '@libsql/linux-arm64-gnu': 0.2.0 - '@libsql/linux-arm64-musl': 0.2.0 - '@libsql/linux-x64-gnu': 0.2.0 - '@libsql/linux-x64-musl': 0.2.0 - '@libsql/win32-x64-msvc': 0.2.0 - optional: true - - lilconfig@3.1.1: {} - - lines-and-columns@1.2.4: {} - - load-json-file@7.0.1: {} - - load-tsconfig@0.2.5: {} - - local-pkg@0.5.0: - dependencies: - mlly: 1.7.0 - pkg-types: 1.1.1 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - - lodash.merge@4.6.2: {} - - lodash.sortby@4.7.0: {} - - lodash.throttle@4.1.1: {} - - lodash@4.17.21: {} - - long@4.0.0: {} - - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 - - lru-cache@10.2.2: {} - - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - lru-cache@7.18.3: {} - - lru-queue@0.1.0: - dependencies: - es5-ext: 0.10.64 - - magic-string@0.25.9: - dependencies: - sourcemap-codec: 1.4.8 - - magic-string@0.30.10: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - - map-age-cleaner@0.1.3: - dependencies: - p-defer: 1.0.0 - - map-stream@0.1.0: {} - - marked-terminal@6.2.0(marked@9.1.6): - dependencies: - ansi-escapes: 6.2.1 - cardinal: 2.1.1 - chalk: 5.3.0 - cli-table3: 0.6.5 - marked: 9.1.6 - node-emoji: 2.1.3 - supports-hyperlinks: 3.0.0 - - marked@9.1.6: {} - - matcher@5.0.0: - dependencies: - escape-string-regexp: 5.0.0 - - md5-hex@3.0.1: - dependencies: - blueimp-md5: 2.19.0 - - mem@9.0.2: - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 4.0.0 - - memoizee@0.4.15: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-weak-map: 2.0.3 - event-emitter: 0.3.5 - is-promise: 2.2.2 - lru-queue: 0.1.0 - next-tick: 1.1.0 - timers-ext: 0.1.7 - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.5: - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@3.0.0: {} - - mimic-fn@2.1.0: {} - - mimic-fn@4.0.0: {} - - mimic-response@3.1.0: {} - - miniflare@3.20240512.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - acorn: 8.11.3 - acorn-walk: 8.3.2 - capnp-ts: 0.7.0 - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - stoppable: 1.1.0 - undici: 5.28.4 - workerd: 1.20240512.0 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - youch: 3.3.3 - zod: 3.23.8 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@7.4.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.4: - dependencies: - brace-expansion: 2.0.1 - - minimist@1.2.8: {} - - minipass@7.1.1: {} - - mkdirp-classic@0.5.3: {} - - mlly@1.7.0: - dependencies: - acorn: 8.11.3 - pathe: 1.1.2 - pkg-types: 1.1.1 - ufo: 1.5.3 - - ms@2.1.2: {} - - ms@2.1.3: {} - - mustache@4.2.0: {} - - mysql2@2.3.3: - dependencies: - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.6.3 - long: 4.0.0 - lru-cache: 6.0.0 - named-placeholders: 1.1.3 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - - named-placeholders@1.1.3: - dependencies: - lru-cache: 7.18.3 - - nan@2.19.0: - optional: true - - nanoid@3.3.7: {} - - napi-build-utils@1.0.2: {} - - natural-compare@1.4.0: {} - - next-tick@1.1.0: {} - - node-abi@3.62.0: - dependencies: - semver: 7.6.2 - - node-domexception@1.0.0: {} - - node-emoji@2.1.3: - dependencies: - '@sindresorhus/is': 4.6.0 - char-regex: 1.0.2 - emojilib: 2.4.0 - skin-tone: 2.0.0 - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-fetch@3.3.1: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - - node-forge@1.3.1: {} - - node-gyp-build@4.8.1: {} - - nofilter@3.1.0: {} - - normalize-path@3.0.0: {} - - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - object-assign@4.1.1: {} - - obuf@1.1.2: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-defer@1.0.0: {} - - p-event@5.0.1: - dependencies: - p-timeout: 5.1.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-limit@4.0.0: - dependencies: - yocto-queue: 1.0.0 - - p-limit@5.0.0: - dependencies: - yocto-queue: 1.0.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - - p-map@5.5.0: - dependencies: - aggregate-error: 4.0.1 - - p-timeout@5.1.0: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-ms@3.0.0: {} - - path-exists@4.0.0: {} - - path-exists@5.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - path-parse@1.0.7: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.2.2 - minipass: 7.1.1 - - path-to-regexp@6.2.2: {} - - path-type@4.0.0: {} - - pathe@1.1.2: {} - - pathval@1.1.1: {} - - pause-stream@0.0.11: - dependencies: - through: 2.3.8 - - pg-cloudflare@1.1.1: - optional: true - - pg-connection-string@2.6.4: {} - - pg-int8@1.0.1: {} - - pg-numeric@1.0.2: {} - - pg-pool@3.6.2(pg@8.11.5): - dependencies: - pg: 8.11.5 - - pg-protocol@1.6.1: {} - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.0 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - - pg-types@4.0.2: - dependencies: - pg-int8: 1.0.1 - pg-numeric: 1.0.2 - postgres-array: 3.0.2 - postgres-bytea: 3.0.0 - postgres-date: 2.1.0 - postgres-interval: 3.0.0 - postgres-range: 1.1.4 - - pg@8.11.5: - dependencies: - pg-connection-string: 2.6.4 - pg-pool: 3.6.2(pg@8.11.5) - pg-protocol: 1.6.1 - pg-types: 2.2.0 - pgpass: 1.0.5 - optionalDependencies: - pg-cloudflare: 1.1.1 - - pgpass@1.0.5: - dependencies: - split2: 4.2.0 - - picocolors@1.0.1: {} - - picomatch@2.3.1: {} - - pirates@4.0.6: {} - - pkg-conf@4.0.0: - dependencies: - find-up: 6.3.0 - load-json-file: 7.0.1 - - pkg-types@1.1.1: - dependencies: - confbox: 0.1.7 - mlly: 1.7.0 - pathe: 1.1.2 - - plur@5.1.0: - dependencies: - irregular-plurals: 3.5.0 - - pluralize@8.0.0: {} - - postcss-load-config@4.0.2(postcss@8.4.38): - dependencies: - lilconfig: 3.1.1 - yaml: 2.4.2 - optionalDependencies: - postcss: 8.4.38 - - postcss@8.4.38: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - - postgres-array@2.0.0: {} - - postgres-array@3.0.2: {} - - postgres-bytea@1.0.0: {} - - postgres-bytea@3.0.0: - dependencies: - obuf: 1.1.2 - - postgres-date@1.0.7: {} - - postgres-date@2.1.0: {} - - postgres-interval@1.2.0: - dependencies: - xtend: 4.0.2 - - postgres-interval@3.0.0: {} - - postgres-range@1.1.4: {} - - postgres@3.4.4: {} - - prebuild-install@7.1.2: - dependencies: - detect-libc: 2.0.3 - expand-template: 2.0.3 - github-from-package: 0.0.0 - minimist: 1.2.8 - mkdirp-classic: 0.5.3 - napi-build-utils: 1.0.2 - node-abi: 3.62.0 - pump: 3.0.0 - rc: 1.2.8 - simple-get: 4.0.1 - tar-fs: 2.1.1 - tunnel-agent: 0.6.0 - - prelude-ls@1.2.1: {} - - prettier-linter-helpers@1.0.0: - dependencies: - fast-diff: 1.3.0 - - prettier@2.8.8: {} - - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - pretty-ms@8.0.0: - dependencies: - parse-ms: 3.0.0 - - printable-characters@1.0.42: {} - - ps-tree@1.2.0: - dependencies: - event-stream: 3.3.4 - - pump@3.0.0: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - punycode@2.3.1: {} - - queue-microtask@1.2.3: {} - - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - - react-is@18.3.1: {} - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - - redeyed@2.1.1: - dependencies: - esprima: 4.0.1 - - require-directory@2.1.1: {} - - resolve-cwd@3.0.0: - dependencies: - resolve-from: 5.0.0 - - resolve-from@4.0.0: {} - - resolve-from@5.0.0: {} - - resolve-pkg-maps@1.0.0: {} - - resolve.exports@2.0.2: {} - - resolve@1.22.8: - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - reusify@1.0.4: {} - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - rollup-plugin-inject@3.0.2: - dependencies: - estree-walker: 0.6.1 - magic-string: 0.25.9 - rollup-pluginutils: 2.8.2 - - rollup-plugin-node-polyfills@0.2.1: - dependencies: - rollup-plugin-inject: 3.0.2 - - rollup-pluginutils@2.8.2: - dependencies: - estree-walker: 0.6.1 - - rollup@4.17.2: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.17.2 - '@rollup/rollup-android-arm64': 4.17.2 - '@rollup/rollup-darwin-arm64': 4.17.2 - '@rollup/rollup-darwin-x64': 4.17.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.17.2 - '@rollup/rollup-linux-arm-musleabihf': 4.17.2 - '@rollup/rollup-linux-arm64-gnu': 4.17.2 - '@rollup/rollup-linux-arm64-musl': 4.17.2 - '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2 - '@rollup/rollup-linux-riscv64-gnu': 4.17.2 - '@rollup/rollup-linux-s390x-gnu': 4.17.2 - '@rollup/rollup-linux-x64-gnu': 4.17.2 - '@rollup/rollup-linux-x64-musl': 4.17.2 - '@rollup/rollup-win32-arm64-msvc': 4.17.2 - '@rollup/rollup-win32-ia32-msvc': 4.17.2 - '@rollup/rollup-win32-x64-msvc': 4.17.2 - fsevents: 2.3.3 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - selfsigned@2.4.1: - dependencies: - '@types/node-forge': 1.3.11 - node-forge: 1.3.1 - - semver@7.6.2: {} - - seq-queue@0.0.5: {} - - serialize-error@7.0.1: - dependencies: - type-fest: 0.13.1 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - siginfo@2.0.0: {} - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - simple-concat@1.0.1: {} - - simple-get@4.0.1: - dependencies: - decompress-response: 6.0.0 - once: 1.4.0 - simple-concat: 1.0.1 - - sisteransi@1.0.5: {} - - skin-tone@2.0.0: - dependencies: - unicode-emoji-modifier-base: 1.0.0 - - slash@3.0.0: {} - - slash@4.0.0: {} - - slice-ansi@5.0.0: - dependencies: - ansi-styles: 6.2.1 - is-fullwidth-code-point: 4.0.0 - - source-map-js@1.2.0: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 - - sourcemap-codec@1.4.8: {} - - split-ca@1.0.1: {} - - split2@4.2.0: {} - - split@0.3.3: - dependencies: - through: 2.3.8 - - sprintf-js@1.0.3: {} - - sqlstring@2.3.3: {} - - ssh2@1.15.0: - dependencies: - asn1: 0.2.6 - bcrypt-pbkdf: 1.0.2 - optionalDependencies: - cpu-features: 0.0.10 - nan: 2.19.0 - - stack-utils@2.0.6: - dependencies: - escape-string-regexp: 2.0.0 - - stackback@0.0.2: {} - - stacktracey@2.1.8: - dependencies: - as-table: 1.0.55 - get-source: 2.0.12 - - std-env@3.7.0: {} - - stoppable@1.1.0: {} - - stream-combiner@0.0.4: - dependencies: - duplexer: 0.1.2 - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.0.1 - - strip-final-newline@2.0.0: {} - - strip-final-newline@3.0.0: {} - - strip-json-comments@2.0.1: {} - - strip-json-comments@3.1.1: {} - - strip-literal@2.1.0: - dependencies: - js-tokens: 9.0.0 - - strnum@1.0.5: {} - - sucrase@3.35.0: - dependencies: - '@jridgewell/gen-mapping': 0.3.5 - commander: 4.1.1 - glob: 10.3.15 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.6 - ts-interface-checker: 0.1.13 - - superjson@2.2.1: - dependencies: - copy-anything: 3.0.5 - - supertap@3.0.1: - dependencies: - indent-string: 5.0.0 - js-yaml: 3.14.1 - serialize-error: 7.0.1 - strip-ansi: 7.1.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-hyperlinks@3.0.0: - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - synckit@0.8.8: - dependencies: - '@pkgr/core': 0.1.1 - tslib: 2.6.2 - - tar-fs@2.0.1: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.0 - tar-stream: 2.2.0 - - tar-fs@2.1.1: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.0 - tar-stream: 2.2.0 - - tar-stream@2.2.0: - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.4 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - - temp-dir@3.0.0: {} - - text-table@0.2.0: {} - - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - - through@2.3.8: {} - - time-zone@1.0.0: {} - - timers-ext@0.1.7: - dependencies: - es5-ext: 0.10.64 - next-tick: 1.1.0 - - tinybench@2.8.0: {} - - tinypool@0.8.4: {} - - tinyspy@2.2.1: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tr46@0.0.3: {} - - tr46@1.0.1: - dependencies: - punycode: 2.3.1 - - tree-kill@1.2.2: {} - - ts-api-utils@1.3.0(typescript@5.4.5): - dependencies: - typescript: 5.4.5 - - ts-expose-internals-conditionally@1.0.0-empty.0: {} - - ts-interface-checker@0.1.13: {} - - tsconfck@3.0.3(typescript@5.4.5): - optionalDependencies: - typescript: 5.4.5 - - tslib@1.14.1: {} - - tslib@2.6.2: {} - - tsup@8.0.2(postcss@8.4.38)(typescript@5.4.5): - dependencies: - bundle-require: 4.1.0(esbuild@0.19.12) - cac: 6.7.14 - chokidar: 3.6.0 - debug: 4.3.4 - esbuild: 0.19.12 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - postcss-load-config: 4.0.2(postcss@8.4.38) - resolve-from: 5.0.0 - rollup: 4.17.2 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 - tree-kill: 1.2.2 - optionalDependencies: - postcss: 8.4.38 - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - ts-node - - tsx@3.14.0: - dependencies: - esbuild: 0.18.20 - get-tsconfig: 4.7.5 - source-map-support: 0.5.21 - optionalDependencies: - fsevents: 2.3.3 - - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - - tweetnacl@0.14.5: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-detect@4.0.8: {} - - type-fest@0.13.1: {} - - type-fest@0.20.2: {} - - type@2.7.2: {} - - typescript@5.3.3: {} - - typescript@5.4.5: {} - - ufo@1.5.3: {} - - undici-types@5.26.5: {} - - undici@5.28.4: - dependencies: - '@fastify/busboy': 2.1.1 - - unicode-emoji-modifier-base@1.0.0: {} - - universalify@2.0.1: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - utf-8-validate@6.0.3: - dependencies: - node-gyp-build: 4.8.1 - - util-deprecate@1.0.2: {} - - uuid@9.0.1: {} - - validate-npm-package-name@5.0.1: {} - - vite-node@1.6.0(@types/node@18.19.33): - dependencies: - cac: 6.7.14 - debug: 4.3.4 - pathe: 1.1.2 - picocolors: 1.0.1 - vite: 5.2.11(@types/node@18.19.33) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser - - vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.2.11(@types/node@18.19.33)): - dependencies: - debug: 4.3.4 - globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5) - optionalDependencies: - vite: 5.2.11(@types/node@18.19.33) - transitivePeerDependencies: - - supports-color - - typescript - - vite@5.2.11(@types/node@18.19.33): - dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.17.2 - optionalDependencies: - '@types/node': 18.19.33 - fsevents: 2.3.3 - - vitest@1.6.0(@types/node@18.19.33): - dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 - chai: 4.4.1 - debug: 4.3.4 - execa: 8.0.1 - local-pkg: 0.5.0 - magic-string: 0.30.10 - pathe: 1.1.2 - picocolors: 1.0.1 - std-env: 3.7.0 - strip-literal: 2.1.0 - tinybench: 2.8.0 - tinypool: 0.8.4 - vite: 5.2.11(@types/node@18.19.33) - vite-node: 1.6.0(@types/node@18.19.33) - why-is-node-running: 2.2.2 - optionalDependencies: - '@types/node': 18.19.33 - transitivePeerDependencies: - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser - - web-streams-polyfill@3.3.3: {} - - webidl-conversions@3.0.1: {} - - webidl-conversions@4.0.2: {} - - webpod@0.0.2: {} - - well-known-symbols@2.0.0: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - whatwg-url@7.1.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - which@3.0.1: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.2.2: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - word-wrap@1.2.5: {} - - wordwrap@1.0.0: {} - - workerd@1.20240512.0: - optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20240512.0 - '@cloudflare/workerd-darwin-arm64': 1.20240512.0 - '@cloudflare/workerd-linux-64': 1.20240512.0 - '@cloudflare/workerd-linux-arm64': 1.20240512.0 - '@cloudflare/workerd-windows-64': 1.20240512.0 - - wrangler@3.57.0(@cloudflare/workers-types@4.20240512.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): - dependencies: - '@cloudflare/kv-asset-handler': 0.3.2 - '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) - '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) - blake3-wasm: 2.1.5 - chokidar: 3.6.0 - esbuild: 0.17.19 - miniflare: 3.20240512.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - nanoid: 3.3.7 - path-to-regexp: 6.2.2 - resolve: 1.22.8 - resolve.exports: 2.0.2 - selfsigned: 2.4.1 - source-map: 0.6.1 - xxhash-wasm: 1.0.2 - optionalDependencies: - '@cloudflare/workers-types': 4.20240512.0 - fsevents: 2.3.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - wrappy@1.0.2: {} - - write-file-atomic@5.0.1: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 4.1.0 - - ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - - ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - - xtend@4.0.2: {} - - xxhash-wasm@1.0.2: {} - - y18n@5.0.8: {} - - yallist@4.0.0: {} - - yaml@2.4.2: {} - - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.1.2 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yocto-queue@0.1.0: {} - - yocto-queue@1.0.0: {} - - youch@3.3.3: - dependencies: - cookie: 0.5.0 - mustache: 4.2.0 - stacktracey: 2.1.8 - - zod@3.23.8: {} - - zx@7.2.3: - dependencies: - '@types/fs-extra': 11.0.4 - '@types/minimist': 1.2.5 - '@types/node': 18.19.33 - '@types/ps-tree': 1.1.6 - '@types/which': 3.0.3 - chalk: 5.3.0 - fs-extra: 11.2.0 - fx: 34.0.0 - globby: 13.2.2 - minimist: 1.2.8 - node-fetch: 3.3.1 - ps-tree: 1.2.0 - webpod: 0.0.2 - which: 3.0.1 - yaml: 2.4.2 diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 06f6dc1c0f..663ccb80ad 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -1,8 +1,8 @@ import { randomUUID } from 'crypto'; -import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; import { LibSQLDatabase } from 'drizzle-orm/libsql'; import type { MySql2Database } from 'drizzle-orm/mysql2'; import { PgDatabase } from 'drizzle-orm/pg-core'; +import { SingleStore2Database } from 'drizzle-orm/singlestore'; import { columnsResolver, enumsResolver, @@ -22,12 +22,15 @@ import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; import { prepareFromExports } from './serializer/pgImports'; import { PgSchema as PgSchemaKit, pgSchema, squashPgScheme } from './serializer/pgSchema'; import { generatePgSnapshot } from './serializer/pgSerializer'; +import { SingleStoreSchema as SingleStoreSchemaKit, singlestoreSchema, squashSingleStoreScheme } from './serializer/singlestoreSchema'; +import { generateSingleStoreSnapshot } from './serializer/singlestoreSerializer'; import { SQLiteSchema as SQLiteSchemaKit, sqliteSchema, squashSqliteScheme } from './serializer/sqliteSchema'; import { generateSqliteSnapshot } from './serializer/sqliteSerializer'; import type { DB, SQLiteDB } from './utils'; export type DrizzleSnapshotJSON = PgSchemaKit; export type DrizzleSQLiteSnapshotJSON = SQLiteSchemaKit; export type DrizzleMySQLSnapshotJSON = MySQLSchemaKit; +export type DrizzleSingleStoreSnapshotJSON = SingleStoreSchemaKit; export const generateDrizzleJson = ( imports: Record, @@ -340,6 +343,108 @@ export const pushMySQLSchema = async ( }; }; +// SingleStore + +export const generateSingleStoreDrizzleJson = async ( + imports: Record, + prevId?: string, +): Promise => { + const { prepareFromExports } = await import('./serializer/singlestoreImports'); + + const prepared = prepareFromExports(imports); + + const id = randomUUID(); + + const snapshot = generateSingleStoreSnapshot(prepared.tables); + + return { + ...snapshot, + id, + prevId: prevId ?? originUUID, + }; +}; + +export const generateSingleStoreMigration = async ( + prev: DrizzleSingleStoreSnapshotJSON, + cur: DrizzleSingleStoreSnapshotJSON, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + return sqlStatements; +}; + +export const pushSingleStoreSchema = async ( + imports: Record, + drizzleInstance: SingleStore2Database, + databaseName: string, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + const { logSuggestionsAndReturn } = await import( + './cli/commands/singlestorePushUtils' + ); + const { singlestorePushIntrospect } = await import( + './cli/commands/singlestoreIntrospect' + ); + const { sql } = await import('drizzle-orm'); + + const db: DB = { + query: async (query: string, params?: any[]) => { + const res = await drizzleInstance.execute(sql.raw(query)); + return res[0] as unknown as any[]; + }, + }; + const cur = await generateSingleStoreDrizzleJson(imports); + const { schema: prev } = await singlestorePushIntrospect(db, databaseName, []); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); + + const { shouldAskForApprove, statementsToExecute, infoToPrint } = await logSuggestionsAndReturn( + db, + statements, + validatedCur, + ); + + return { + hasDataLoss: shouldAskForApprove, + warnings: infoToPrint, + statementsToExecute, + apply: async () => { + for (const dStmnt of statementsToExecute) { + await db.query(dStmnt); + } + }, + }; +}; + export const upPgSnapshot = (snapshot: Record) => { return upPgV6(snapshot); }; diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 61ba0b44a1..c00ca42140 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -6,15 +6,17 @@ import { join } from 'path'; import { plural, singular } from 'pluralize'; import { assertUnreachable, originUUID } from '../../global'; import { schemaToTypeScript as mysqlSchemaToTypeScript } from '../../introspect-mysql'; +import { schemaToTypeScript as singlestoreSchemaToTypeScript } from '../../introspect-singlestore'; import { paramNameFor, schemaToTypeScript as postgresSchemaToTypeScript } from '../../introspect-pg'; import { schemaToTypeScript as sqliteSchemaToTypeScript } from '../../introspect-sqlite'; import { dryMySql, MySqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; import { fromDatabase as fromMysqlDatabase } from '../../serializer/mysqlSerializer'; +import { fromDatabase as fromSingleStoreDatabase } from '../../serializer/singlestoreSerializer'; import { dryPg, type PgSchema, squashPgScheme } from '../../serializer/pgSchema'; import { fromDatabase as fromPostgresDatabase } from '../../serializer/pgSerializer'; import { drySQLite, type SQLiteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSerializer'; -import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySqliteSnapshotsDiff } from '../../snapshotsDiffer'; +import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff } from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; import type { Casing, Prefix } from '../validations/common'; import type { MysqlCredentials } from '../validations/mysql'; @@ -29,6 +31,8 @@ import { tablesResolver, writeResult, } from './migrate'; +import { SingleStoreCredentials } from '../validations/singlestore'; +import { drySingleStore, SingleStoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; export const introspectPostgres = async ( casing: Casing, @@ -254,6 +258,102 @@ export const introspectMysql = async ( process.exit(0); }; +export const introspectSingleStore = async ( + casing: Casing, + out: string, + breakpoints: boolean, + credentials: SingleStoreCredentials, + tablesFilter: string[], + prefix: Prefix, +) => { + const { connectToSingleStore } = await import('../connections'); + const { db, database } = await connectToSingleStore(credentials); + + const matchers = tablesFilter.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new IntrospectProgress(); + const res = await renderWithTask( + progress, + fromSingleStoreDatabase(db, database, filter, (stage, count, status) => { + progress.update(stage, count, status); + }), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const ts = singlestoreSchemaToTypeScript(schema, casing); + const { internal, ...schemaWithoutInternals } = schema; + + const schemaFile = join(out, 'schema.ts'); + writeFileSync(schemaFile, ts.file); + console.log(); + + const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + + if (snapshots.length === 0) { + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( + squashSingleStoreScheme(drySingleStore), + squashSingleStoreScheme(schema), + tablesResolver, + columnsResolver, + drySingleStore, + schema, + ); + + writeResult({ + cur: schema, + sqlStatements, + journal, + _meta, + outFolder: out, + breakpoints, + type: 'introspect', + prefixMode: prefix, + }); + } else { + render( + `[${ + chalk.blue( + 'i', + ) + }] No SQL generated, you already have migrations in project`, + ); + } + + render( + `[${ + chalk.green( + '✓', + ) + }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + ); + process.exit(0); +}; + export const introspectSqlite = async ( casing: Casing, out: string, diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 8ef469fa19..c3614869b7 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -4,6 +4,8 @@ import { prepareMySqlMigrationSnapshot, preparePgDbPushSnapshot, preparePgMigrationSnapshot, + prepareSingleStoreDbPushSnapshot, + prepareSingleStoreMigrationSnapshot, prepareSQLiteDbPushSnapshot, prepareSqliteMigrationSnapshot, } from '../../migrationPreparator'; @@ -19,6 +21,7 @@ import { SQLiteSchema, sqliteSchema, squashSqliteScheme } from '../../serializer import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -43,6 +46,7 @@ import { schema, } from '../views'; import { GenerateConfig } from './utils'; +import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; export type Named = { name: string; @@ -391,6 +395,150 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { } }; +// Not needed for now +function mySingleStoreSchemaSuggestions( + curSchema: TypeOf, + prevSchema: TypeOf, +) { + const suggestions: string[] = []; + const usedSuggestions: string[] = []; + const suggestionTypes = { + // TODO: Check if SingleStore has serial type + serial: withStyle.errorWarning( + `We deprecated the use of 'serial' for SingleStore starting from version 0.20.0. In SingleStore, 'serial' is simply an alias for 'bigint unsigned not null auto_increment unique,' which creates all constraints and indexes for you. This may make the process less explicit for both users and drizzle-kit push commands`, + ), + }; + + for (const table of Object.values(curSchema.tables)) { + for (const column of Object.values(table.columns)) { + if (column.type === 'serial') { + if (!usedSuggestions.includes('serial')) { + suggestions.push(suggestionTypes['serial']); + } + + const uniqueForSerial = Object.values( + prevSchema.tables[table.name].uniqueConstraints, + ).find((it) => it.columns[0] === column.name); + + suggestions.push( + `\n` + + withStyle.suggestion( + `We are suggesting to change ${ + chalk.blue( + column.name, + ) + } column in ${ + chalk.blueBright( + table.name, + ) + } table from serial to bigint unsigned\n\n${ + chalk.blueBright( + `bigint("${column.name}", { mode: "number", unsigned: true }).notNull().autoincrement().unique(${ + uniqueForSerial?.name ? `"${uniqueForSerial?.name}"` : '' + })`, + ) + }`, + ), + ); + } + } + } + + return suggestions; +} + +// Intersect with prepareAnMigrate +export const prepareSingleStorePush = async ( + schemaPath: string | string[], + snapshot: SingleStoreSchema, +) => { + try { + const { prev, cur } = await prepareSingleStoreDbPushSnapshot( + snapshot, + schemaPath, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); + + return { sqlStatements, statements, validatedCur, validatedPrev }; + } catch (e) { + console.error(e); + process.exit(1); + } +}; + +export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { + const outFolder = config.out; + const schemaPath = config.schema; + + try { + // TODO: remove + assertV1OutFolder(outFolder); + + const { snapshots, journal } = prepareMigrationFolder(outFolder, 'singlestore'); + const { prev, cur, custom } = await prepareSingleStoreMigrationSnapshot( + snapshots, + schemaPath, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + if (config.custom) { + writeResult({ + cur: custom, + sqlStatements: [], + journal, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + type: 'custom', + prefixMode: config.prefix, + }); + return; + } + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, statements, _meta } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + writeResult({ + cur, + sqlStatements, + journal, + _meta, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + prefixMode: config.prefix, + }); + } catch (e) { + console.error(e); + } +}; + export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index e48a5da9e1..1c97ee75f5 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -6,9 +6,11 @@ import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; import type { SqliteCredentials } from '../validations/sqlite'; -import { filterStatements, logSuggestionsAndReturn } from './mysqlPushUtils'; +import { filterStatements as mySqlFilterStatements, logSuggestionsAndReturn as mySqlLogSuggestionsAndReturn } from './mysqlPushUtils'; +import { filterStatements as singleStoreFilterStatements, logSuggestionsAndReturn as singleStoreLogSuggestionsAndReturn } from './singlestorePushUtils'; import { pgSuggestions } from './pgPushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; +import { SingleStoreCredentials } from '../validations/singlestore'; export const mysqlPush = async ( schemaPath: string | string[], @@ -28,7 +30,7 @@ export const mysqlPush = async ( const statements = await prepareMySQLPush(schemaPath, schema); - const filteredStatements = filterStatements( + const filteredStatements = mySqlFilterStatements( statements.statements ?? [], statements.validatedCur, statements.validatedPrev, @@ -46,7 +48,7 @@ export const mysqlPush = async ( tablesToTruncate, infoToPrint, schemasToRemove, - } = await logSuggestionsAndReturn( + } = await mySqlLogSuggestionsAndReturn( db, filteredStatements, statements.validatedCur, @@ -150,6 +152,146 @@ export const mysqlPush = async ( } }; +export const singlestorePush = async ( + schemaPath: string | string[], + credentials: SingleStoreCredentials, + tablesFilter: string[], + strict: boolean, + verbose: boolean, + force: boolean, +) => { + const { connectToSingleStore } = await import('../connections'); + const { singlestorePushIntrospect } = await import('./singlestoreIntrospect'); + + const { db, database } = await connectToSingleStore(credentials); + + const { schema } = await singlestorePushIntrospect(db, database, tablesFilter); + const { prepareSingleStorePush } = await import('./migrate'); + + const statements = await prepareSingleStorePush(schemaPath, schema); + + const filteredStatements = singleStoreFilterStatements( + statements.statements ?? [], + statements.validatedCur, + statements.validatedPrev, + ); + + try { + if (filteredStatements.length === 0) { + render(`[${chalk.blue('i')}] No changes detected`); + } else { + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + } = await singleStoreLogSuggestionsAndReturn( + db, + filteredStatements, + statements.validatedCur, + ); + + const filteredSqlStatements = fromJson(filteredStatements, 'singlestore'); + + const uniqueSqlStatementsToExecute: string[] = []; + statementsToExecute.forEach((ss) => { + if (!uniqueSqlStatementsToExecute.includes(ss)) { + uniqueSqlStatementsToExecute.push(ss); + } + }); + const uniqueFilteredSqlStatements: string[] = []; + filteredSqlStatements.forEach((ss) => { + if (!uniqueFilteredSqlStatements.includes(ss)) { + uniqueFilteredSqlStatements.push(ss); + } + }); + + if (verbose) { + console.log(); + // console.log(chalk.gray('Verbose logs:')); + console.log( + withStyle.warning('You are about to execute current statements:'), + ); + console.log(); + console.log( + [...uniqueSqlStatementsToExecute, ...uniqueFilteredSqlStatements] + .map((s) => chalk.blue(s)) + .join('\n'), + ); + console.log(); + } + + if (!force && strict) { + if (!shouldAskForApprove) { + const { status, data } = await render( + new Select(['No, abort', `Yes, I want to execute all statements`]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + } + + if (!force && shouldAskForApprove) { + console.log(withStyle.warning('Found data-loss statements:')); + console.log(infoToPrint.join('\n')); + console.log(); + console.log( + chalk.red.bold( + 'THIS ACTION WILL CAUSE DATA LOSS AND CANNOT BE REVERTED\n', + ), + ); + + console.log(chalk.white('Do you still want to push changes?')); + + const { status, data } = await render( + new Select([ + 'No, abort', + `Yes, I want to${ + tablesToRemove.length > 0 + ? ` remove ${tablesToRemove.length} ${tablesToRemove.length > 1 ? 'tables' : 'table'},` + : ' ' + }${ + columnsToRemove.length > 0 + ? ` remove ${columnsToRemove.length} ${columnsToRemove.length > 1 ? 'columns' : 'column'},` + : ' ' + }${ + tablesToTruncate.length > 0 + ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` + : '' + }` + .replace(/(^,)|(,$)/g, '') + .replace(/ +(?= )/g, ''), + ]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + + for (const dStmnt of uniqueSqlStatementsToExecute) { + await db.query(dStmnt); + } + + for (const statement of uniqueFilteredSqlStatements) { + await db.query(statement); + } + if (filteredStatements.length > 0) { + render(`[${chalk.green('✓')}] Changes applied`); + } else { + render(`[${chalk.blue('i')}] No changes detected`); + } + } + } catch (e) { + console.log(e); + } +}; + export const pgPush = async ( schemaPath: string | string[], verbose: boolean, diff --git a/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts new file mode 100644 index 0000000000..27d8c59c50 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts @@ -0,0 +1,53 @@ +import { renderWithTask } from 'hanji'; +import { Minimatch } from 'minimatch'; +import { originUUID } from '../../global'; +import type { SingleStoreSchema } from '../../serializer/singlestoreSchema'; +import { fromDatabase } from '../../serializer/singlestoreSerializer'; +import type { DB } from '../../utils'; +import { ProgressView } from '../views'; + +export const singlestorePushIntrospect = async ( + db: DB, + databaseName: string, + filters: string[], +) => { + const matchers = filters.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new ProgressView( + 'Pulling schema from database...', + 'Pulling schema from database...', + ); + const res = await renderWithTask( + progress, + fromDatabase(db, databaseName, filter), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const { internal, ...schemaWithoutInternals } = schema; + return { schema: schemaWithoutInternals }; +}; diff --git a/drizzle-kit/src/cli/commands/singlestorePushUtils.ts b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts new file mode 100644 index 0000000000..80fad9b2dc --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts @@ -0,0 +1,352 @@ +import chalk from 'chalk'; +import { render } from 'hanji'; +import { TypeOf } from 'zod'; +import { JsonAlterColumnTypeStatement, JsonStatement } from '../../jsonStatements'; +import { singlestoreSchema, SingleStoreSquasher } from '../../serializer/singlestoreSchema'; +import type { DB } from '../../utils'; +import { Select } from '../selector-ui'; +import { withStyle } from '../validations/outputs'; + +export const filterStatements = ( + statements: JsonStatement[], + currentSchema: TypeOf, + prevSchema: TypeOf, +) => { + return statements.filter((statement) => { + if (statement.type === 'alter_table_alter_column_set_type') { + // Don't need to handle it on migrations step and introspection + // but for both it should be skipped + if ( + statement.oldDataType.startsWith('tinyint') + && statement.newDataType.startsWith('boolean') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('bigint unsigned') + && statement.newDataType.startsWith('serial') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('serial') + && statement.newDataType.startsWith('bigint unsigned') + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_set_default') { + if ( + statement.newDefaultValue === false + && statement.oldDefaultValue === 0 + && statement.newDataType === 'boolean' + ) { + return false; + } + if ( + statement.newDefaultValue === true + && statement.oldDefaultValue === 1 + && statement.newDataType === 'boolean' + ) { + return false; + } + } else if (statement.type === 'delete_unique_constraint') { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + // only if constraint was removed from a serial column, than treat it as removed + // const serialStatement = statements.find( + // (it) => it.type === "alter_table_alter_column_set_type" + // ) as JsonAlterColumnTypeStatement; + // if ( + // serialStatement?.oldDataType.startsWith("bigint unsigned") && + // serialStatement?.newDataType.startsWith("serial") && + // serialStatement.columnName === + // SingleStoreSquasher.unsquashUnique(statement.data).columns[0] + // ) { + // return false; + // } + // Check if uniqueindex was only on this column, that is serial + + // if now serial and was not serial and was unique index + if ( + unsquashed.columns.length === 1 + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && prevSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .name === unsquashed.columns[0] + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_drop_notnull') { + // only if constraint was removed from a serial column, than treat it as removed + const serialStatement = statements.find( + (it) => it.type === 'alter_table_alter_column_set_type', + ) as JsonAlterColumnTypeStatement; + if ( + serialStatement?.oldDataType.startsWith('bigint unsigned') + && serialStatement?.newDataType.startsWith('serial') + && serialStatement.columnName === statement.columnName + && serialStatement.tableName === statement.tableName + ) { + return false; + } + if (statement.newDataType === 'serial' && !statement.columnNotNull) { + return false; + } + if (statement.columnAutoIncrement) { + return false; + } + } + + return true; + }); +}; + +export const logSuggestionsAndReturn = async ( + db: DB, + statements: JsonStatement[], + json2: TypeOf, +) => { + let shouldAskForApprove = false; + const statementsToExecute: string[] = []; + const infoToPrint: string[] = []; + + const tablesToRemove: string[] = []; + const columnsToRemove: string[] = []; + const schemasToRemove: string[] = []; + const tablesToTruncate: string[] = []; + + for (const statement of statements) { + if (statement.type === 'drop_table') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.tableName, + ) + } table with ${count} items`, + ); + tablesToRemove.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_drop_column') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${statement.tableName} table with ${count} items`, + ); + columnsToRemove.push(`${statement.tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + } else if (statement.type === 'drop_schema') { + const res = await db.query( + `select count(*) as count from information_schema.tables where table_schema = \`${statement.name}\`;`, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.name, + ) + } schema with ${count} tables`, + ); + schemasToRemove.push(statement.name); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_set_type') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.columnName, + ) + } column type from ${ + chalk.underline( + statement.oldDataType, + ) + } to ${chalk.underline(statement.newDataType)} with ${count} items`, + ); + statementsToExecute.push(`truncate table ${statement.tableName};`); + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_drop_default') { + if (statement.columnNotNull) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to remove default value from ${ + chalk.underline( + statement.columnName, + ) + } not-null column with ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + // shouldAskForApprove = true; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + if (typeof statement.columnDefault === 'undefined') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to set not-null constraint to ${ + chalk.underline( + statement.columnName, + ) + } column without default, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'alter_table_alter_column_drop_pk') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.tableName, + ) + } primary key. This statements may fail and you table may left without primary key`, + ); + + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'delete_composite_pk') { + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + } else if (statement.type === 'alter_table_add_column') { + if ( + statement.column.notNull + && typeof statement.column.default === 'undefined' + ) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + statement.column.name, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'create_unique_constraint') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(statement.data); + console.log( + `· You're about to add ${ + chalk.underline( + unsquashedUnique.name, + ) + } unique constraint to the table, which contains ${count} items. If this statement fails, you will receive an error from the database. Do you want to truncate ${ + chalk.underline( + statement.tableName, + ) + } table?\n`, + ); + const { status, data } = await render( + new Select([ + 'No, add the constraint without truncating the table', + `Yes, truncate the table`, + ]), + ); + if (data?.index === 1) { + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + shouldAskForApprove = true; + } + } + } + } + + return { + statementsToExecute, + shouldAskForApprove, + infoToPrint, + columnsToRemove: [...new Set(columnsToRemove)], + schemasToRemove: [...new Set(schemasToRemove)], + tablesToTruncate: [...new Set(tablesToTruncate)], + tablesToRemove: [...new Set(tablesToRemove)], + }; +}; diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 9f65318a61..3ae05a73b4 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -27,13 +27,14 @@ import { postgresCredentials, printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; +import { printConfigConnectionIssues as printIssuesSingleStore, singlestoreCredentials, SingleStoreCredentials } from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSqlite, SqliteCredentials, sqliteCredentials, } from '../validations/sqlite'; import { studioCliParams, studioConfig } from '../validations/studio'; -import { error, grey } from '../views'; +import { error } from '../views'; // NextJs default config is target: es5, which esbuild-register can't consume const assertES5 = async (unregister: () => void) => { @@ -211,6 +212,10 @@ export const preparePushConfig = async ( dialect: 'sqlite'; credentials: SqliteCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { schemaPath: string | string[]; verbose: boolean; @@ -309,6 +314,25 @@ export const preparePushConfig = async ( }; } + if (config.dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesPg(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + schemaPath: config.schema, + strict: config.strict ?? false, + verbose: config.verbose ?? false, + force: (options.force as boolean) ?? false, + credentials: parsed.data, + tablesFilter, + schemasFilter, + }; + } + if (config.dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -347,6 +371,10 @@ export const preparePullConfig = async ( dialect: 'sqlite'; credentials: SqliteCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { out: string; breakpoints: boolean; @@ -434,6 +462,25 @@ export const preparePullConfig = async ( }; } + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesPg(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + out: config.out, + breakpoints: config.breakpoints, + casing: config.introspectCasing, + credentials: parsed.data, + tablesFilter, + schemasFilter, + prefix: config.database?.prefix || 'index', + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -505,6 +552,23 @@ export const prepareStudioConfig = async (options: Record) => { credentials, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesPg(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + schema, + host, + port, + credentials, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { @@ -574,6 +638,23 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => { table, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesSingleStore(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + out, + credentials, + schema, + table, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 02f3e84112..fe7c2083ff 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -11,6 +11,7 @@ import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; import type { SqliteCredentials } from './validations/sqlite'; +import { SingleStoreCredentials } from './validations/singlestore'; export const preparePostgresDB = async ( credentials: PostgresCredentials, @@ -655,3 +656,82 @@ export const connectToSQLite = async ( ); process.exit(1); }; + +const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { + if ('url' in credentials) { + const url = credentials.url; + + const connectionUrl = new URL(url); + const pathname = connectionUrl.pathname; + + const database = pathname.split('/')[pathname.split('/').length - 1]; + if (!database) { + console.error( + 'You should specify a database name in connection string (singlestore://USER:PASSWORD@HOST:PORT/DATABASE)', + ); + process.exit(1); + } + return { database, url }; + } else { + return { + database: credentials.database, + credentials, + }; + } +}; + +export const connectToSingleStore = async ( + it: SingleStoreCredentials, +): Promise<{ + db: DB; + proxy: Proxy; + database: string; + migrate: (config: MigrationConfig) => Promise; +}> => { + const result = parseSingleStoreCredentials(it); + + if (await checkPackage('singlestore')) { + const { createConnection } = await import('mysql2/promise'); + const { drizzle } = await import('drizzle-orm/singlestore'); + const { migrate } = await import('drizzle-orm/singlestore/migrator'); + + const connection = result.url + ? await createConnection(result.url) + : await createConnection(result.credentials!); // needed for some reason! + + const db = drizzle(connection); + const migrateFn = async (config: MigrationConfig) => { + return migrate(db, config); + }; + + await connection.connect(); + const query: DB['query'] = async ( + sql: string, + params?: any[], + ): Promise => { + const res = await connection.execute(sql, params); + return res[0] as any; + }; + + const proxy: Proxy = async (params: ProxyParams) => { + const result = await connection.query({ + sql: params.sql, + values: params.params, + rowsAsArray: params.mode === 'array', + }); + return result[0] as any[]; + }; + + return { + db: { query }, + proxy, + database: result.database, + migrate: migrateFn, + }; + } + + console.error( + "To connect to SingleStore database - please install 'mysql2' drivers", + ); + process.exit(1); +}; diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index 6b92829d57..8bb0f08ef8 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'pg', 'mysql' or 'sqlite'`, + `Please specify 'dialect' param in config, either of 'pg', 'mysql', 'sqlite' of 'singlestore'. It will help drizzle to know how to query you database. You can read more about drizzle.config: https://orm.drizzle.team/kit-docs/config-reference`, ), }, common: { @@ -79,4 +79,13 @@ export const outputs = { introspect: {}, push: {}, }, + singlestore: { + connection: { + driver: () => withStyle.error(`Only "mysql2" is available options for "--driver"`), + required: () => + withStyle.error( + `Either "url" or "host", "database" are required for database connection`, + ), + }, + }, }; diff --git a/drizzle-kit/src/cli/validations/singlestore.ts b/drizzle-kit/src/cli/validations/singlestore.ts new file mode 100644 index 0000000000..ebe0cc5f01 --- /dev/null +++ b/drizzle-kit/src/cli/validations/singlestore.ts @@ -0,0 +1,61 @@ +import { boolean, coerce, object, string, TypeOf, union } from 'zod'; +import { error } from '../views'; +import { wrapParam } from './common'; +import { outputs } from './outputs'; + +export const singlestoreCredentials = union([ + object({ + host: string().min(1), + port: coerce.number().min(1).optional(), + user: string().min(1).optional(), + password: string().min(1).optional(), + database: string().min(1), + ssl: union([ + string(), + object({ + pfx: string().optional(), + key: string().optional(), + passphrase: string().optional(), + cert: string().optional(), + ca: union([string(), string().array()]).optional(), + crl: union([string(), string().array()]).optional(), + ciphers: string().optional(), + rejectUnauthorized: boolean().optional(), + }), + ]).optional(), + }), + object({ + url: string().min(1), + }), +]); + +export type SingleStoreCredentials = TypeOf; + +export const printCliConnectionIssues = (options: any) => { + const { uri, host, database } = options || {}; + + if (!uri && (!host || !database)) { + console.log(outputs.singlestore.connection.required()); + } +}; + +export const printConfigConnectionIssues = ( + options: Record, +) => { + if ('url' in options) { + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('url', options.url, false, 'url')); + process.exit(1); + } + + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('host', options.host)); + console.log(wrapParam('port', options.port, true)); + console.log(wrapParam('user', options.user, true)); + console.log(wrapParam('password', options.password, true, 'secret')); + console.log(wrapParam('database', options.database)); + console.log(wrapParam('ssl', options.ssl, true)); + process.exit(1); +}; diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 08c302ac38..b99ac204a7 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -23,7 +23,7 @@ type Verify = U; * **Config** usage: * * `dialect` - mandatory and is responsible for explicitly providing a databse dialect you are using for all the commands - * *Possible values*: `postgresql`, `mysql`, `sqlite` + * *Possible values*: `postgresql`, `mysql`, `sqlite`, `singlestore * * See https://orm.drizzle.team/kit-docs/config-reference#dialect * @@ -64,7 +64,7 @@ type Verify = U; * * `breakpoints` - param lets you enable/disable SQL statement breakpoints in generated migrations. * It’s optional and true by default, it’s necessary to properly apply migrations on databases, - * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite) and + * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite, SingleStore) and * Drizzle ORM has to apply them sequentially one by one. * * See https://orm.drizzle.team/kit-docs/config-reference#breakpoints @@ -200,6 +200,21 @@ export type Config = driver: Verify; } | {} + | { + dialect: Verify; + dbCredentials: + | { + host: string; + port?: number; + user?: string; + password?: string; + database: string; + ssl?: string | SslOptions; + } + | { + url: string; + }; + } ); /** diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts new file mode 100644 index 0000000000..37e0a68fab --- /dev/null +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -0,0 +1,787 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import './@types/utils'; +import type { Casing } from './cli/validations/common'; +import { indexName } from './serializer/singlestoreSerializer'; +import { + Column, + Index, + PrimaryKey, + SingleStoreSchemaInternal, + UniqueConstraint +} from './serializer/singlestoreSchema'; + +// time precision to fsp +// {mode: "string"} for timestamp by default + +const singlestoreImportsList = new Set([ + 'singlestoreTable', + 'singlestoreEnum', + 'bigint', + 'binary', + 'boolean', + 'char', + 'date', + 'datetime', + 'decimal', + 'double', + 'float', + 'int', + 'json', + // TODO: add new type BSON + // TODO: add new type Blob + // TODO: add new type UUID + // TODO: add new type GUID + // TODO: add new type Vector + // TODO: add new type GeoPoint + 'mediumint', + 'real', + 'serial', + 'smallint', + 'text', + 'tinytext', + 'mediumtext', + 'longtext', + 'time', + 'timestamp', + 'tinyint', + 'varbinary', + 'varchar', + 'year', + 'enum', +]); + +const objToStatement = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `"${it}": "${json[it]}"`).join(', '); + statement += ' }'; + return statement; +}; + +const objToStatement2 = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: "${json[it]}"`).join(', '); // no "" for keys + statement += ' }'; + return statement; +}; + +const timeConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const binaryConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const importsPatch = { + 'double precision': 'doublePrecision', + 'timestamp without time zone': 'timestamp', +} as Record; + +const relations = new Set(); + +const prepareCasing = (casing?: Casing) => (value: string) => { + if (typeof casing === 'undefined') { + return value; + } + if (casing === 'camel') { + return value.camelCase(); + } + + return value; +}; + +export const schemaToTypeScript = ( + schema: SingleStoreSchemaInternal, + casing: Casing, +) => { + const withCasing = prepareCasing(casing); + + const imports = Object.values(schema.tables).reduce( + (res, it) => { + const idxImports = Object.values(it.indexes).map((idx) => idx.isUnique ? 'uniqueIndex' : 'index'); + const pkImports = Object.values(it.compositePrimaryKeys).map( + (it) => 'primaryKey', + ); + const uniqueImports = Object.values(it.uniqueConstraints).map( + (it) => 'unique', + ); + + res.singlestore.push(...idxImports); + res.singlestore.push(...pkImports); + res.singlestore.push(...uniqueImports); + + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'singlestoreEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + return patched; + }) + .filter((type) => { + return singlestoreImportsList.has(type); + }); + + res.singlestore.push(...columnImports); + return res; + }, + { singlestore: [] as string[] }, + ); + + const tableStatements = Object.values(schema.tables).map((table) => { + const func = 'singlestoreTable'; + let statement = ''; + if (imports.singlestore.includes(withCasing(table.name))) { + statement = `// Table name is in conflict with ${ + withCasing( + table.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(table.name)} = ${func}("${table.name}", {\n`; + statement += createTableColumns( + Object.values(table.columns), + withCasing, + table.name, + schema, + ); + statement += '}'; + + if ( + Object.keys(table.indexes).length > 0 + || Object.keys(table.compositePrimaryKeys).length > 0 + || Object.keys(table.uniqueConstraints).length > 0 + ) { + statement += ',\n'; + statement += '(table) => {\n'; + statement += '\treturn {\n'; + statement += createTableIndexes( + table.name, + Object.values(table.indexes), + withCasing, + ); + statement += createTablePKs( + Object.values(table.compositePrimaryKeys), + withCasing, + ); + statement += createTableUniques( + Object.values(table.uniqueConstraints), + withCasing, + ); + statement += '\t}\n'; + statement += '}'; + } + + statement += ');'; + return statement; + }); + + const uniqueSingleStoreImports = [ + 'singlestoreTable', + 'singlestoreSchema', + 'AnySingleStoreColumn', + ...new Set(imports.singlestore), + ]; + const importsTs = `import { ${ + uniqueSingleStoreImports.join( + ', ', + ) + } } from "drizzle-orm/singlestore-core"\nimport { sql } from "drizzle-orm"\n\n`; + + let decalrations = ''; + decalrations += tableStatements.join('\n\n'); + + const file = importsTs + decalrations; + + const schemaEntry = ` + { + ${ + Object.values(schema.tables) + .map((it) => withCasing(it.name)) + .join(',') + } + } + `; + + return { + file, // backward compatible, print to file + imports: importsTs, + decalrations, + schemaEntry, + }; +}; + +const mapColumnDefault = (defaultValue: any, isExpression?: boolean) => { + if (isExpression) { + return `sql\`${defaultValue}\``; + } + + return defaultValue; +}; + +const mapColumnDefaultForJson = (defaultValue: any) => { + if ( + typeof defaultValue === 'string' + && defaultValue.startsWith("('") + && defaultValue.endsWith("')") + ) { + return defaultValue.substring(2, defaultValue.length - 2); + } + + return defaultValue; +}; + +const column = ( + type: string, + name: string, + casing: (value: string) => string, + defaultValue?: any, + autoincrement?: boolean, + onUpdate?: boolean, + isExpression?: boolean, +) => { + let lowered = type; + if (!type.startsWith('enum(')) { + lowered = type.toLowerCase(); + } + + if (lowered === 'serial') { + return `${casing(name)}: serial("${name}")`; + } + + if (lowered.startsWith('int')) { + const isUnsigned = lowered.startsWith('int unsigned'); + let out = `${casing(name)}: int("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('tinyint')) { + const isUnsigned = lowered.startsWith('tinyint unsigned'); + // let out = `${name.camelCase()}: tinyint("${name}")`; + let out: string = `${casing(name)}: tinyint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('smallint')) { + const isUnsigned = lowered.startsWith('smallint unsigned'); + let out = `${casing(name)}: smallint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('mediumint')) { + const isUnsigned = lowered.startsWith('mediumint unsigned'); + let out = `${casing(name)}: mediumint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('bigint')) { + const isUnsigned = lowered.startsWith('bigint unsigned'); + let out = `${casing(name)}: bigint("${name}", { mode: "number"${isUnsigned ? ', unsigned: true' : ''} })`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'boolean') { + let out = `${casing(name)}: boolean("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('double')) { + let params: + | { precision: string | undefined; scale: string | undefined } + | undefined; + + if (lowered.length > 6) { + const [precision, scale] = lowered + .slice(7, lowered.length - 1) + .split(','); + params = { precision, scale }; + } + + let out = params + ? `${casing(name)}: double("${name}", ${timeConfig(params)})` + : `${casing(name)}: double("${name}")`; + + // let out = `${name.camelCase()}: double("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'float') { + let out = `${casing(name)}: float("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'real') { + let out = `${casing(name)}: real("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('timestamp')) { + const keyLength = 'timestamp'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp, mode: "'string'" }); + + let out = params + ? `${casing(name)}: timestamp("${name}", ${params})` + : `${casing(name)}: timestamp("${name}")`; + + + // TODO: check if SingleStore has defaultNow() or now() + defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + + // TODO: check if SingleStore has onUpdateNow() + let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; + out += onUpdateNow; + + return out; + } + + if (lowered.startsWith('time')) { + const keyLength = 'time'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp }); + + let out = params + ? `${casing(name)}: time("${name}", ${params})` + : `${casing(name)}: time("${name}")`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered === 'date') { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t${ + casing( + name, + ) + }: date("${name}", { mode: 'string' })`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has text can't have default value + if (lowered === 'text') { + let out = `${casing(name)}: text("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has tinytext can't have default value + if (lowered === 'tinytext') { + let out = `${casing(name)}: tinytext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has mediumtext can't have default value + if (lowered === 'mediumtext') { + let out = `${casing(name)}: mediumtext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has longtext can't have default value + if (lowered === 'longtext') { + let out = `${casing(name)}: longtext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'year') { + let out = `${casing(name)}: year("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql json can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has json can't have default value + if (lowered === 'json') { + let out = `${casing(name)}: json("${name}")`; + + out += defaultValue + ? `.default(${mapColumnDefaultForJson(defaultValue)})` + : ''; + + return out; + } + + // TODO: add new type BSON + + // TODO: add new type Blob + + // TODO: add new type UUID + + // TODO: add new type GUID + + // TODO: add new type Vector + + // TODO: add new type GeoPoint + + if (lowered.startsWith('varchar')) { + let out: string = `${ + casing( + name, + ) + }: varchar("${name}", { length: ${ + lowered.substring( + 'varchar'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('char')) { + let out: string = `${ + casing( + name, + ) + }: char("${name}", { length: ${ + lowered.substring( + 'char'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('datetime')) { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t`; + + const fsp = lowered.startsWith('datetime(') + ? lowered.substring('datetime'.length + 1, lowered.length - 1) + : undefined; + + out = fsp + ? `${ + casing( + name, + ) + }: datetime("${name}", { mode: 'string', fsp: ${ + lowered.substring( + 'datetime'.length + 1, + lowered.length - 1, + ) + } })` + : `${casing(name)}: datetime("${name}", { mode: 'string'})`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('decimal')) { + let params: + | { precision: string | undefined; scale: string | undefined } + | undefined; + + if (lowered.length > 7) { + const [precision, scale] = lowered + .slice(8, lowered.length - 1) + .split(','); + params = { precision, scale }; + } + + let out = params + ? `${casing(name)}: decimal("${name}", ${timeConfig(params)})` + : `${casing(name)}: decimal("${name}")`; + + defaultValue = typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('binary')) { + const keyLength = 'binary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: binary("${name}", ${params})` + : `${casing(name)}: binary("${name}")`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('enum')) { + const values = lowered.substring('enum'.length + 1, lowered.length - 1); + let out = `${casing(name)}: singlestoreEnum("${name}", [${values}])`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('varbinary')) { + const keyLength = 'varbinary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: varbinary("${name}", ${params})` + : `${casing(name)}: varbinary("${name}")`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + console.log('uknown', type); + return `// Warning: Can't parse ${type} from database\n\t// ${type}Type: ${type}("${name}")`; +}; + +const createTableColumns = ( + columns: Column[], + casing: (val: string) => string, + tableName: string, + schema: SingleStoreSchemaInternal, +): string => { + let statement = ''; + + columns.forEach((it) => { + statement += '\t'; + statement += column( + it.type, + it.name, + casing, + it.default, + it.autoincrement, + it.onUpdate, + schema.internal?.tables![tableName]?.columns[it.name] + ?.isDefaultAnExpression ?? false, + ); + statement += it.primaryKey ? '.primaryKey()' : ''; + statement += it.notNull ? '.notNull()' : ''; + + statement += it.generated + ? `.generatedAlwaysAs(sql\`${ + it.generated.as.replace( + /`/g, + '\\`', + ) + }\`, { mode: "${it.generated.type}" })` + : ''; + + statement += ',\n'; + }); + + return statement; +}; + +const createTableIndexes = ( + tableName: string, + idxs: Index[], + casing: (value: string) => string, +): string => { + let statement = ''; + + idxs.forEach((it) => { + let idxKey = it.name.startsWith(tableName) && it.name !== tableName + ? it.name.slice(tableName.length + 1) + : it.name; + idxKey = idxKey.endsWith('_index') + ? idxKey.slice(0, -'_index'.length) + '_idx' + : idxKey; + + idxKey = casing(idxKey); + + const indexGeneratedName = indexName(tableName, it.columns); + const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; + + statement += `\t\t${idxKey}: `; + statement += it.isUnique ? 'uniqueIndex(' : 'index('; + statement += `${escapedIndexName})`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTableUniques = ( + unqs: UniqueConstraint[], + casing: (value: string) => string, +): string => { + let statement = ''; + + unqs.forEach((it) => { + const idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'unique('; + statement += `"${it.name}")`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTablePKs = ( + pks: PrimaryKey[], + casing: (value: string) => string, +): string => { + let statement = ''; + + pks.forEach((it) => { + let idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'primaryKey({ columns: ['; + statement += `${ + it.columns + .map((c) => { + return `table.${casing(c)}`; + }) + .join(', ') + }]${it.name ? `, name: "${it.name}"` : ''}}`; + statement += '),'; + statement += `\n`; + }); + + return statement; +}; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index ad2afea7f5..e1ed41f586 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -3,6 +3,7 @@ import { table } from 'console'; import { warning } from './cli/views'; import { CommonSquashedSchema, Dialect } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; import { SQLiteKitInternals, SQLiteSquasher } from './serializer/sqliteSchema'; import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer'; @@ -32,7 +33,7 @@ export interface JsonCreateTableStatement { compositePKs: string[]; compositePkName?: string; uniqueConstraints?: string[]; - internals?: MySqlKitInternals; + internals?: MySqlKitInternals | SingleStoreKitInternals; } export interface JsonDropTableStatement { @@ -158,7 +159,7 @@ export interface JsonCreateIndexStatement { tableName: string; data: string; schema: string; - internal?: MySqlKitInternals | SQLiteKitInternals; + internal?: MySqlKitInternals | SQLiteKitInternals | SingleStoreKitInternals; } export interface JsonPgCreateIndexStatement { @@ -611,6 +612,34 @@ export const prepareMySqlCreateTableJson = ( }; }; +export const prepareSingleStoreCreateTableJson = ( + table: Table, + // TODO: remove? + json2: SingleStoreSchema, + // we need it to know if some of the indexes(and in future other parts) are expressions or columns + // didn't change singlestoreserialaizer, because it will break snapshots and diffs and it's hard to detect + // if previously it was an expression or column + internals: SingleStoreKitInternals, +): JsonCreateTableStatement => { + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + + return { + type: 'create_table', + tableName: name, + schema, + columns: Object.values(columns), + compositePKs: Object.values(compositePrimaryKeys), + compositePkName: Object.values(compositePrimaryKeys).length > 0 + ? json2.tables[name].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(Object.values(compositePrimaryKeys)[0]) + .name + ].name + : '', + uniqueConstraints: Object.values(uniqueConstraints), + internals, + }; +}; + export const prepareSQLiteCreateTable = ( table: Table, action?: 'push' | undefined, @@ -830,7 +859,7 @@ export const prepareDeleteSchemasJson = ( export const prepareRenameColumns = ( tableName: string, - // TODO: split for pg and mysql+sqlite without schema + // TODO: split for pg and mysql+sqlite and singlestore without schema schema: string, pairs: { from: Column; to: Column }[], ): JsonRenameColumnStatement[] => { @@ -1260,6 +1289,363 @@ export const prepareAlterColumnsMysql = ( return [...dropPkStatements, ...setPkStatements, ...statements]; }; +export const prepareAlterColumnsSingleStore = ( + tableName: string, + schema: string, + columns: AlteredColumn[], + // TODO: remove? + json1: CommonSquashedSchema, + json2: CommonSquashedSchema, + action?: 'push' | undefined, +): JsonAlterColumnStatement[] => { + let statements: JsonAlterColumnStatement[] = []; + let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; + let setPkStatements: JsonAlterColumnSetPrimaryKeyStatement[] = []; + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + const table = json2.tables[tableName]; + const snapshotColumn = table.columns[columnName]; + + const columnType = snapshotColumn.type; + const columnDefault = snapshotColumn.default; + const columnOnUpdate = 'onUpdate' in snapshotColumn ? snapshotColumn.onUpdate : undefined; + const columnNotNull = table.columns[columnName].notNull; + + const columnAutoIncrement = 'autoincrement' in snapshotColumn + ? snapshotColumn.autoincrement ?? false + : false; + + const columnPk = table.columns[columnName].primaryKey; + + if (column.autoincrement?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'changed') { + const type = column.autoincrement.new + ? 'alter_table_alter_column_set_autoincrement' + : 'alter_table_alter_column_drop_autoincrement'; + + statements.push({ + type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + // I used any, because those fields are available only for mysql and singlestore dialect + // For other dialects it will become undefined, that is fine for json statements + const columnType = json2.tables[tableName].columns[columnName].type; + const columnDefault = json2.tables[tableName].columns[columnName].default; + const columnGenerated = json2.tables[tableName].columns[columnName].generated; + const columnOnUpdate = (json2.tables[tableName].columns[columnName] as any) + .onUpdate; + const columnNotNull = json2.tables[tableName].columns[columnName].notNull; + const columnAutoIncrement = ( + json2.tables[tableName].columns[columnName] as any + ).autoincrement; + const columnPk = (json2.tables[tableName].columns[columnName] as any) + .primaryKey; + + const compositePk = json2.tables[tableName].compositePrimaryKeys[ + `${tableName}_${columnName}` + ]; + + if (typeof column.name !== 'string') { + statements.push({ + type: 'alter_table_rename_column', + tableName, + oldColumnName: column.name.old, + newColumnName: column.name.new, + schema, + }); + } + + if (column.type?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_type', + tableName, + columnName, + newDataType: column.type.new, + oldDataType: column.type.old, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if ( + column.primaryKey?.type === 'deleted' + || (column.primaryKey?.type === 'changed' + && !column.primaryKey.new + && typeof compositePk === 'undefined') + ) { + dropPkStatements.push({ + //// + type: 'alter_table_alter_column_drop_pk', + tableName, + columnName, + schema, + }); + } + + if (column.default?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.value, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.new, + oldDefaultValue: column.default.old, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_default', + tableName, + columnName, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.notNull?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'changed') { + const type = column.notNull.new + ? 'alter_table_alter_column_set_notnull' + : 'alter_table_alter_column_drop_notnull'; + statements.push({ + type: type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.generated?.type === 'added') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to add virtual generated constraint to ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Nongenerated columns can be altered to stored but not virtual generated columns". We will drop an existing column and add it with a virtual generated statement. This means that the data previously stored in this column will be wiped, and new data will be generated on each read for this column\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_set_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'changed' && action !== 'push') { + statements.push({ + type: 'alter_table_alter_column_alter_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'deleted') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to remove virtual generated constraint from ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Stored but not virtual generated columns can be altered to nongenerated columns. The stored generated values become the values of the nongenerated column". We will drop an existing column and add it without a virtual generated statement. This means that this column will have no data after migration\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_drop_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + oldColumn: json1.tables[tableName].columns[columnName], + }); + } + + if ( + column.primaryKey?.type === 'added' + || (column.primaryKey?.type === 'changed' && column.primaryKey.new) + ) { + const wasAutoincrement = statements.filter( + (it) => it.type === 'alter_table_alter_column_set_autoincrement', + ); + if (wasAutoincrement.length === 0) { + setPkStatements.push({ + type: 'alter_table_alter_column_set_pk', + tableName, + schema, + columnName, + }); + } + } + + if (column.onUpdate?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.onUpdate?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + return [...dropPkStatements, ...setPkStatements, ...statements]; +}; + export const preparePgAlterColumns = ( _tableName: string, schema: string, @@ -2230,3 +2616,72 @@ export const prepareAlterCompositePrimaryKeyMySql = ( } as JsonAlterCompositePK; }); }; + +export const prepareAddCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, + json2: SingleStoreSchema, +): JsonCreateCompositePK[] => { + const res: JsonCreateCompositePK[] = []; + for (const it of Object.values(pks)) { + const unsquashed = SingleStoreSquasher.unsquashPK(it); + + if ( + unsquashed.columns.length === 1 + && json1.tables[tableName]?.columns[unsquashed.columns[0]]?.primaryKey + ) { + continue; + } + + res.push({ + type: 'create_composite_pk', + tableName, + data: it, + constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + } as JsonCreateCompositePK); + } + return res; +}; + +export const prepareDeleteCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, +): JsonDeleteCompositePK[] => { + return Object.values(pks).map((it) => { + return { + type: 'delete_composite_pk', + tableName, + data: it, + constraintName: json1.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it).name + ].name, + } as JsonDeleteCompositePK; + }); +}; + +export const prepareAlterCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, + json2: SingleStoreSchema, +): JsonAlterCompositePK[] => { + return Object.values(pks).map((it) => { + return { + type: 'alter_composite_pk', + tableName, + old: it.__old, + new: it.__new, + oldConstraintName: json1.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it.__old).name + ].name, + newConstraintName: json2.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it.__new).name + ].name, + } as JsonAlterCompositePK; + }); +}; diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 687cfdb7c9..80a07d6c15 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -1,9 +1,10 @@ import { randomUUID } from 'crypto'; import fs from 'fs'; -import { serializeMySql, serializePg, serializeSQLite } from './serializer'; +import { serializeMySql, serializePg, serializeSingleStore, serializeSQLite } from './serializer'; import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; +import { drySingleStore, singlestoreSchema, SingleStoreSchema } from './serializer/singlestoreSchema'; export const prepareMySqlDbPushSnapshot = async ( prev: MySqlSchema, @@ -20,6 +21,21 @@ export const prepareMySqlDbPushSnapshot = async ( return { prev, cur: result }; }; +export const prepareSingleStoreDbPushSnapshot = async ( + prev: SingleStoreSchema, + schemaPath: string | string[], +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema }> => { + const serialized = await serializeSingleStore(schemaPath); + + const id = randomUUID(); + const idPrev = prev.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + return { prev, cur: result }; +}; + export const prepareSQLiteDbPushSnapshot = async ( prev: SQLiteSchema, schemaPath: string | string[], @@ -84,6 +100,33 @@ export const prepareMySqlMigrationSnapshot = async ( return { prev: prevSnapshot, cur: result, custom }; }; +export const prepareSingleStoreMigrationSnapshot = async ( + migrationFolders: string[], + schemaPath: string | string[], +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema; custom: SingleStoreSchema }> => { + const prevSnapshot = singlestoreSchema.parse( + preparePrevSnapshot(migrationFolders, drySingleStore), + ); + const serialized = await serializeSingleStore(schemaPath); + + const id = randomUUID(); + const idPrev = prevSnapshot.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + const { id: _ignoredId, prevId: _ignoredPrevId, ...prevRest } = prevSnapshot; + + // that's for custom migrations, when we need new IDs, but old snapshot + const custom: SingleStoreSchema = { + id, + prevId: idPrev, + ...prevRest, + }; + + return { prev: prevSnapshot, cur: result, custom }; +}; + export const prepareSqliteMigrationSnapshot = async ( snapshots: string[], schemaPath: string | string[], diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index 9c1f4dcfce..a414b37d7d 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -2,8 +2,9 @@ import { enum as enumType, TypeOf, union } from 'zod'; import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; +import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; -export const dialects = ['postgresql', 'mysql', 'sqlite'] as const; +export const dialects = ['postgresql', 'mysql', 'sqlite', 'singlestore'] as const; export const dialect = enumType(dialects); export type Dialect = (typeof dialects)[number]; @@ -13,9 +14,10 @@ const commonSquashedSchema = union([ pgSchemaSquashed, mysqlSchemaSquashed, SQLiteSchemaSquashed, + singlestoreSchemaSquashed, ]); -const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema]); +const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema, singlestoreSchema]); export type CommonSquashedSchema = TypeOf; export type CommonSchema = TypeOf; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 214ca38c72..6eb55c6f69 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -6,6 +6,7 @@ import Path from 'path'; import { error } from '../cli/views'; import type { MySqlSchemaInternal } from './mysqlSchema'; import type { PgSchemaInternal } from './pgSchema'; +import { SingleStoreSchemaInternal } from './singlestoreSchema'; import type { SQLiteSchemaInternal } from './sqliteSchema'; export const sqlToStr = (sql: SQL) => { @@ -78,6 +79,21 @@ export const serializeSQLite = async ( return generateSqliteSnapshot(tables); }; +export const serializeSingleStore = async ( + path: string | string[], +): Promise => { + const filenames = prepareFilenames(path); + + console.log(chalk.gray(`Reading schema files:\n${filenames.join('\n')}\n`)); + + const { prepareFromSingleStoreImports } = await import('./singlestoreImports'); + const { generateSingleStoreSnapshot } = await import('./singlestoreSerializer'); + + const { tables } = await prepareFromSingleStoreImports(filenames); + + return generateSingleStoreSnapshot(tables); +}; + export const prepareFilenames = (path: string | string[]) => { if (typeof path === 'string') { path = [path]; diff --git a/drizzle-kit/src/serializer/singlestoreImports.ts b/drizzle-kit/src/serializer/singlestoreImports.ts new file mode 100644 index 0000000000..3fcb1e65f7 --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreImports.ts @@ -0,0 +1,31 @@ +import { is } from 'drizzle-orm'; +import { AnySingleStoreTable, SingleStoreTable } from 'drizzle-orm/singlestore-core'; +import { safeRegister } from '../cli/commands/utils'; + +export const prepareFromExports = (exports: Record) => { + const tables: AnySingleStoreTable[] = []; + + const i0values = Object.values(exports); + i0values.forEach((t) => { + if (is(t, SingleStoreTable)) { + tables.push(t); + } + }); + + return { tables }; +}; + +export const prepareFromSingleStoreImports = async (imports: string[]) => { + const tables: AnySingleStoreTable[] = []; + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + const i0: Record = require(`${it}`); + const prepared = prepareFromExports(i0); + + tables.push(...prepared.tables); + } + unregister(); + return { tables: Array.from(new Set(tables)) }; +}; diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts new file mode 100644 index 0000000000..2527ddd0f8 --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -0,0 +1,213 @@ +import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; +import { mapValues, originUUID, snapshotVersion } from '../global'; + +// ------- V3 -------- +const index = object({ + name: string(), + columns: string().array(), + isUnique: boolean(), + using: enumType(['btree', 'hash']).optional(), + algorithm: enumType(['default', 'inplace', 'copy']).optional(), + lock: enumType(['default', 'none', 'shared', 'exclusive']).optional(), +}).strict(); + +const fk = object({ + name: string(), + tableFrom: string(), + columnsFrom: string().array(), + tableTo: string(), + columnsTo: string().array(), + onUpdate: string().optional(), + onDelete: string().optional(), +}).strict(); + +const column = object({ + name: string(), + type: string(), + primaryKey: boolean(), + notNull: boolean(), + autoincrement: boolean().optional(), + default: any().optional(), + onUpdate: any().optional(), + generated: object({ + type: enumType(['stored', 'virtual']), + as: string(), + }).optional(), +}).strict(); + +const compositePK = object({ + name: string(), + columns: string().array(), +}).strict(); + +const uniqueConstraint = object({ + name: string(), + columns: string().array(), +}).strict(); + +const table = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), index), + compositePrimaryKeys: record(string(), compositePK), + uniqueConstraints: record(string(), uniqueConstraint).default({}), +}).strict(); + +export const kitInternals = object({ + tables: record( + string(), + object({ + columns: record( + string(), + object({ isDefaultAnExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), + indexes: record( + string(), + object({ + columns: record( + string(), + object({ isExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), +}).optional(); + +// use main dialect +const dialect = literal('singlestore'); + +const schemaHash = object({ + id: string(), + prevId: string(), +}); + +export const schemaInternal = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), table), + _meta: object({ + tables: record(string(), string()), + columns: record(string(), string()), + }), + internal: kitInternals, +}).strict(); + +export const schema = schemaInternal.merge(schemaHash); + +const tableSquashed = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), string()), + compositePrimaryKeys: record(string(), string()), + uniqueConstraints: record(string(), string()).default({}), +}).strict(); + +export const schemaSquashed = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), tableSquashed), +}).strict(); + +export type Dialect = TypeOf; +export type Column = TypeOf; +export type Table = TypeOf; +export type SingleStoreSchema = TypeOf; +export type SingleStoreSchemaInternal = TypeOf; +export type SingleStoreKitInternals = TypeOf; +export type SingleStoreSchemaSquashed = TypeOf; +export type Index = TypeOf; +export type PrimaryKey = TypeOf; +export type UniqueConstraint = TypeOf; + +export const SingleStoreSquasher = { + squashIdx: (idx: Index) => { + index.parse(idx); + return `${idx.name};${idx.columns.join(',')};${idx.isUnique};${idx.using ?? ''};${idx.algorithm ?? ''};${ + idx.lock ?? '' + }`; + }, + unsquashIdx: (input: string): Index => { + const [name, columnsString, isUnique, using, algorithm, lock] = input.split(';'); + const destructed = { + name, + columns: columnsString.split(','), + isUnique: isUnique === 'true', + using: using ? using : undefined, + algorithm: algorithm ? algorithm : undefined, + lock: lock ? lock : undefined, + }; + return index.parse(destructed); + }, + squashPK: (pk: PrimaryKey) => { + return `${pk.name};${pk.columns.join(',')}`; + }, + unsquashPK: (pk: string): PrimaryKey => { + const splitted = pk.split(';'); + return { name: splitted[0], columns: splitted[1].split(',') }; + }, + squashUnique: (unq: UniqueConstraint) => { + return `${unq.name};${unq.columns.join(',')}`; + }, + unsquashUnique: (unq: string): UniqueConstraint => { + const [name, columns] = unq.split(';'); + return { name, columns: columns.split(',') }; + }, +}; + +export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSchemaSquashed => { + const mappedTables = Object.fromEntries( + Object.entries(json.tables).map((it) => { + const squashedIndexes = mapValues(it[1].indexes, (index) => { + return SingleStoreSquasher.squashIdx(index); + }); + + const squashedPKs = mapValues(it[1].compositePrimaryKeys, (pk) => { + return SingleStoreSquasher.squashPK(pk); + }); + + const squashedUniqueConstraints = mapValues( + it[1].uniqueConstraints, + (unq) => { + return SingleStoreSquasher.squashUnique(unq); + }, + ); + + return [ + it[0], + { + name: it[1].name, + columns: it[1].columns, + indexes: squashedIndexes, + compositePrimaryKeys: squashedPKs, + uniqueConstraints: squashedUniqueConstraints, + }, + ]; + }), + ); + return { + version: '1', + dialect: json.dialect, + tables: mappedTables, + }; +}; + +export const singlestoreSchema = schema; +export const singlestoreSchemaSquashed = schemaSquashed; + +// no prev version +export const backwardCompatibleSingleStoreSchema = union([singlestoreSchema, schema]); + +export const drySingleStore = singlestoreSchema.parse({ + version: '1', + dialect: 'singlestore', + id: originUUID, + prevId: '', + tables: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, +}); diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts new file mode 100644 index 0000000000..98f7bd5ee0 --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -0,0 +1,592 @@ +import chalk from 'chalk'; +import { getTableName, is } from 'drizzle-orm'; +import { SQL } from 'drizzle-orm'; +import { SingleStoreDialect, AnySingleStoreTable, type PrimaryKey as PrimaryKeyORM, uniqueKeyName } from 'drizzle-orm/singlestore-core'; +import { getTableConfig } from 'drizzle-orm/singlestore-core'; +import { RowDataPacket } from 'mysql2/promise'; +import { withStyle } from '../cli/validations/outputs'; +import { IntrospectStage, IntrospectStatus } from '../cli/views'; + +import type { DB } from '../utils'; +import { sqlToStr } from '.'; +import { Column, Index, PrimaryKey, SingleStoreKitInternals, SingleStoreSchemaInternal, Table, UniqueConstraint } from './singlestoreSchema'; +// import { SingleStoreColumnWithAutoIncrement } from "drizzle-orm/mysql-core"; +// import { SingleStoreDateBaseColumn } from "drizzle-orm/mysql-core"; + +const dialect = new SingleStoreDialect(); + +export const indexName = (tableName: string, columns: string[]) => { + return `${tableName}_${columns.join('_')}_index`; +}; + +export const generateSingleStoreSnapshot = ( + tables: AnySingleStoreTable[], +): SingleStoreSchemaInternal => { + const result: Record = {}; + const internal: SingleStoreKitInternals = { tables: {}, indexes: {} }; + for (const table of tables) { + const { + name: tableName, + columns, + indexes, + schema, + primaryKeys, + uniqueConstraints, + } = getTableConfig(table); + const columnsObject: Record = {}; + const indexesObject: Record = {}; + const primaryKeysObject: Record = {}; + const uniqueConstraintObject: Record = {}; + + columns.forEach((column) => { + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.primary) { + primaryKeysObject[`${tableName}_${column.name}`] = { + name: `${tableName}_${column.name}`, + columns: [column.name], + }; + } + + if (column.isUnique) { + const existingUnique = uniqueConstraintObject[column.uniqueName!]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. + The unique constraint ${ + chalk.underline.blue( + column.uniqueName, + ) + } on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`) + }`, + ); + process.exit(1); + } + uniqueConstraintObject[column.uniqueName!] = { + name: column.uniqueName!, + columns: [columnToSet.name], + }; + } + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + if (['blob', 'text', 'json'].includes(column.getSQLType())) { + columnToSet.default = `(${columnToSet.default})`; + } + } + } + columnsObject[column.name] = columnToSet; + }); + + primaryKeys.map((pk: PrimaryKeyORM) => { + const columnNames = pk.columns.map((c: any) => c.name); + primaryKeysObject[pk.getName()] = { + name: pk.getName(), + columns: columnNames, + }; + + // all composite pk's should be treated as notNull + for (const column of pk.columns) { + columnsObject[column.name].notNull = true; + } + }); + + uniqueConstraints?.map((unq) => { + const columnNames = unq.columns.map((c) => c.name); + + const name = unq.name ?? uniqueKeyName(table, columnNames); + + const existingUnique = uniqueConstraintObject[name]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + + uniqueConstraintObject[name] = { + name: unq.name!, + columns: columnNames, + }; + }); + + indexes.forEach((value) => { + const columns = value.config.columns; + const name = value.config.name; + + let indexColumns = columns.map((it) => { + if (is(it, SQL)) { + const sql = dialect.sqlToQuery(it, 'indexes').sql; + if (typeof internal!.indexes![name] === 'undefined') { + internal!.indexes![name] = { + columns: { + [sql]: { + isExpression: true, + }, + }, + }; + } else { + if (typeof internal!.indexes![name]?.columns[sql] === 'undefined') { + internal!.indexes![name]!.columns[sql] = { + isExpression: true, + }; + } else { + internal!.indexes![name]!.columns[sql]!.isExpression = true; + } + } + return sql; + } else { + return `${it.name}`; + } + }); + + if (value.config.unique) { + if (typeof uniqueConstraintObject[name] !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique index ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + indexColumns.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + uniqueConstraintObject[name].columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + } + + indexesObject[name] = { + name, + columns: indexColumns, + isUnique: value.config.unique ?? false, + using: value.config.using, + algorithm: value.config.algorythm, + lock: value.config.lock, + }; + }); + + // only handle tables without schemas + if (!schema) { + result[tableName] = { + name: tableName, + columns: columnsObject, + indexes: indexesObject, + compositePrimaryKeys: primaryKeysObject, + uniqueConstraints: uniqueConstraintObject, + }; + } + } + + return { + version: '1', + dialect: 'singlestore', + tables: result, + _meta: { + tables: {}, + columns: {}, + }, + internal, + }; +}; + +function clearDefaults(defaultValue: any, collate: string) { + if (typeof collate === 'undefined' || collate === null) { + collate = `utf8mb4`; + } + + let resultDefault = defaultValue; + collate = `_${collate}`; + if (defaultValue.startsWith(collate)) { + resultDefault = resultDefault + .substring(collate.length, defaultValue.length) + .replace(/\\/g, ''); + if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { + return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + } else { + return `'${resultDefault}'`; + } + } else { + return `(${resultDefault})`; + } +} + +export const fromDatabase = async ( + db: DB, + inputSchema: string, + tablesFilter: (table: string) => boolean = (table) => true, + progressCallback?: ( + stage: IntrospectStage, + count: number, + status: IntrospectStatus, + ) => void, +): Promise => { + const result: Record = {}; + const internals: SingleStoreKitInternals = { tables: {}, indexes: {} }; + + const columns = await db.query(`select * from information_schema.columns + where table_schema = '${inputSchema}' and table_name != '__drizzle_migrations' + order by table_name, ordinal_position;`); + + const response = columns as RowDataPacket[]; + + const schemas: string[] = []; + + let columnsCount = 0; + let tablesCount = new Set(); + let indexesCount = 0; + let foreignKeysCount = 0; + + const idxs = await db.query( + `select * from INFORMATION_SCHEMA.STATISTICS + WHERE INFORMATION_SCHEMA.STATISTICS.TABLE_SCHEMA = '${inputSchema}' and INFORMATION_SCHEMA.STATISTICS.INDEX_NAME != 'PRIMARY';`, + ); + + const idxRows = idxs as RowDataPacket[]; + + for (const column of response) { + if (!tablesFilter(column['TABLE_NAME'] as string)) continue; + + columnsCount += 1; + if (progressCallback) { + progressCallback('columns', columnsCount, 'fetching'); + } + const schema: string = column['TABLE_SCHEMA']; + const tableName = column['TABLE_NAME']; + + tablesCount.add(`${schema}.${tableName}`); + if (progressCallback) { + progressCallback('columns', tablesCount.size, 'fetching'); + } + const columnName: string = column['COLUMN_NAME']; + const isNullable = column['IS_NULLABLE'] === 'YES'; // 'YES', 'NO' + const dataType = column['DATA_TYPE']; // varchar + const columnType = column['COLUMN_TYPE']; // varchar(256) + const isPrimary = column['COLUMN_KEY'] === 'PRI'; // 'PRI', '' + const columnDefault: string = column['COLUMN_DEFAULT']; + const collation: string = column['CHARACTER_SET_NAME']; + const geenratedExpression: string = column['GENERATION_EXPRESSION']; + + let columnExtra = column['EXTRA']; + let isAutoincrement = false; // 'auto_increment', '' + let isDefaultAnExpression = false; // 'auto_increment', '' + + if (typeof column['EXTRA'] !== 'undefined') { + columnExtra = column['EXTRA']; + isAutoincrement = column['EXTRA'] === 'auto_increment'; // 'auto_increment', '' + isDefaultAnExpression = column['EXTRA'].includes('DEFAULT_GENERATED'); // 'auto_increment', '' + } + + // if (isPrimary) { + // if (typeof tableToPk[tableName] === "undefined") { + // tableToPk[tableName] = [columnName]; + // } else { + // tableToPk[tableName].push(columnName); + // } + // } + + if (schema !== inputSchema) { + schemas.push(schema); + } + + const table = result[tableName]; + + // let changedType = columnType.replace("bigint unsigned", "serial") + let changedType = columnType; + + if (columnType === 'bigint unsigned' && !isNullable && isAutoincrement) { + // check unique here + const uniqueIdx = idxRows.filter( + (it) => + it['COLUMN_NAME'] === columnName + && it['TABLE_NAME'] === tableName + && it['NON_UNIQUE'] === 0, + ); + if (uniqueIdx && uniqueIdx.length === 1) { + changedType = columnType.replace('bigint unsigned', 'serial'); + } + } + + if (columnType.startsWith('tinyint')) { + changedType = 'tinyint'; + } + + let onUpdate: boolean | undefined = undefined; + if ( + columnType.startsWith('timestamp') + && typeof columnExtra !== 'undefined' + && columnExtra.includes('on update CURRENT_TIMESTAMP') + ) { + onUpdate = true; + } + + const newColumn: Column = { + default: columnDefault === null + ? undefined + : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) + && !columnType.startsWith('decimal') + ? Number(columnDefault) + : isDefaultAnExpression + ? clearDefaults(columnDefault, collation) + : `'${columnDefault}'`, + autoincrement: isAutoincrement, + name: columnName, + type: changedType, + primaryKey: false, + notNull: !isNullable, + onUpdate, + generated: geenratedExpression + ? { + as: geenratedExpression, + type: columnExtra === 'VIRTUAL GENERATED' ? 'virtual' : 'stored', + } + : undefined, + }; + + // Set default to internal object + if (isDefaultAnExpression) { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![tableName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + } + + if (!table) { + result[tableName] = { + name: tableName, + columns: { + [columnName]: newColumn, + }, + compositePrimaryKeys: {}, + indexes: {}, + uniqueConstraints: {}, + }; + } else { + result[tableName]!.columns[columnName] = newColumn; + } + } + + const tablePks = await db.query( + `SELECT table_name, column_name, ordinal_position + FROM information_schema.table_constraints t + LEFT JOIN information_schema.key_column_usage k + USING(constraint_name,table_schema,table_name) + WHERE t.constraint_type='PRIMARY KEY' + and table_name != '__drizzle_migrations' + AND t.table_schema = '${inputSchema}' + ORDER BY ordinal_position`, + ); + + const tableToPk: { [tname: string]: string[] } = {}; + + const tableToPkRows = tablePks as RowDataPacket[]; + for (const tableToPkRow of tableToPkRows) { + const tableName: string = tableToPkRow['TABLE_NAME']; + const columnName: string = tableToPkRow['COLUMN_NAME']; + const position: string = tableToPkRow['ordinal_position']; + + if (typeof result[tableName] === 'undefined') { + continue; + } + + if (typeof tableToPk[tableName] === 'undefined') { + tableToPk[tableName] = [columnName]; + } else { + tableToPk[tableName].push(columnName); + } + } + + for (const [key, value] of Object.entries(tableToPk)) { + // if (value.length > 1) { + result[key].compositePrimaryKeys = { + [`${key}_${value.join('_')}`]: { + name: `${key}_${value.join('_')}`, + columns: value, + }, + }; + // } else if (value.length === 1) { + // result[key].columns[value[0]].primaryKey = true; + // } else { + // } + } + if (progressCallback) { + progressCallback('columns', columnsCount, 'done'); + progressCallback('tables', tablesCount.size, 'done'); + } + + for (const idxRow of idxRows) { + const tableSchema = idxRow['TABLE_SCHEMA']; + const tableName = idxRow['TABLE_NAME']; + const constraintName = idxRow['INDEX_NAME']; + const columnName: string = idxRow['COLUMN_NAME']; + const isUnique = idxRow['NON_UNIQUE'] === 0; + + const tableInResult = result[tableName]; + if (typeof tableInResult === 'undefined') continue; + + // if (tableInResult.columns[columnName].type === "serial") continue; + + indexesCount += 1; + if (progressCallback) { + progressCallback('indexes', indexesCount, 'fetching'); + } + + if (isUnique) { + if ( + typeof tableInResult.uniqueConstraints[constraintName] !== 'undefined' + ) { + tableInResult.uniqueConstraints[constraintName]!.columns.push( + columnName, + ); + } else { + tableInResult.uniqueConstraints[constraintName] = { + name: constraintName, + columns: [columnName], + }; + } + } else { + if (typeof tableInResult.indexes[constraintName] !== 'undefined') { + tableInResult.indexes[constraintName]!.columns.push(columnName); + } else { + tableInResult.indexes[constraintName] = { + name: constraintName, + columns: [columnName], + isUnique: isUnique, + }; + } + } + } + + if (progressCallback) { + progressCallback('indexes', indexesCount, 'done'); + // progressCallback("enums", 0, "fetching"); + progressCallback('enums', 0, 'done'); + } + + return { + version: '1', + dialect: 'singlestore', + tables: result, + _meta: { + tables: {}, + columns: {}, + }, + internal: internals, + }; +}; diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index 4b7b12c1e6..350e4c9b83 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -13,9 +13,10 @@ import { Relations, TablesRelationalConfig, } from 'drizzle-orm'; -import { AnyMySqlTable, getTableConfig as mysqlTableConfig, MySqlTable } from 'drizzle-orm/mysql-core'; -import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-orm/pg-core'; -import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { AnyMySqlTable, MySqlTable, getTableConfig as mysqlTableConfig } from 'drizzle-orm/mysql-core'; +import { AnyPgTable, PgTable, getTableConfig as pgTableConfig } from 'drizzle-orm/pg-core'; +import { AnySingleStoreTable, SingleStoreTable, getTableConfig as singlestoreTableConfig} from 'drizzle-orm/singlestore-core'; +import { AnySQLiteTable, SQLiteTable, getTableConfig as sqliteTableConfig } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; import { cors } from 'hono/cors'; @@ -23,11 +24,12 @@ import { createServer } from 'node:https'; import { assertUnreachable } from 'src/global'; import superjson from 'superjson'; import { z } from 'zod'; +import { prepareFilenames } from '.'; import { safeRegister } from '../cli/commands/utils'; import type { MysqlCredentials } from '../cli/validations/mysql'; import type { PostgresCredentials } from '../cli/validations/postgres'; +import type { SingleStoreCredentials } from '../cli/validations/singlestore'; import type { SqliteCredentials } from '../cli/validations/sqlite'; -import { prepareFilenames } from '.'; type CustomDefault = { schema: string; @@ -43,7 +45,7 @@ type SchemaFile = { export type Setup = { dbHash: string; - dialect: 'postgresql' | 'mysql' | 'sqlite'; + dialect: 'postgresql' | 'mysql' | 'sqlite' | 'singlestore'; driver?: 'aws-data-api' | 'd1-http' | 'turso'; proxy: (params: ProxyParams) => Promise; customDefaults: CustomDefault[]; @@ -170,6 +172,43 @@ export const prepareSQLiteSchema = async (path: string | string[]) => { return { schema: sqliteSchema, relations, files }; }; +export const prepareSingleStoreSchema = async (path: string | string[]) => { + const imports = prepareFilenames(path); + const singlestoreSchema: Record> = { + public: {}, + }; + const relations: Record = {}; + + // files content as string + const files = imports.map((it, index) => ({ + // get the file name from the path + name: it.split('/').pop() || `schema${index}.ts`, + content: fs.readFileSync(it, 'utf-8'), + })); + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + + const i0: Record = require(`${it}`); + const i0values = Object.entries(i0); + + i0values.forEach(([k, t]) => { + if (is(t, SingleStoreTable)) { + const schema = singlestoreTableConfig(t).schema || 'public'; + singlestoreSchema[schema][k] = t; + } + + if (is(t, Relations)) { + relations[k] = t; + } + }); + } + unregister(); + + return { schema: singlestoreSchema, relations, files }; +}; + const getCustomDefaults = >( schema: Record>, ): CustomDefault[] => { @@ -185,8 +224,10 @@ const getCustomDefaults = >( tableConfig = pgTableConfig(table); } else if (is(table, MySqlTable)) { tableConfig = mysqlTableConfig(table); - } else { + } else if (is(table, SQLiteTable)) { tableConfig = sqliteTableConfig(table); + } else { + tableConfig = singlestoreTableConfig(table); } tableConfig.columns.map((column) => { @@ -318,6 +359,39 @@ export const drizzleForSQLite = async ( }; }; +export const drizzleForSingleStore = async ( + credentials: SingleStoreCredentials, + singlestoreSchema: Record>, + relations: Record, + schemaFiles?: SchemaFile[], +): Promise => { + const { connectToSingleStore } = await import('../cli/connections'); + const { proxy } = await connectToSingleStore(credentials); + + const customDefaults = getCustomDefaults(singlestoreSchema); + + let dbUrl: string; + + if ('url' in credentials) { + dbUrl = credentials.url; + } else { + dbUrl = + `singlestore://${credentials.user}:${credentials.password}@${credentials.host}:${credentials.port}/${credentials.database}`; + } + + const dbHash = createHash('sha256').update(dbUrl).digest('hex'); + + return { + dbHash, + dialect: 'singlestore', + proxy, + customDefaults, + schema: singlestoreSchema, + relations, + schemaFiles, + }; +}; + export const extractRelations = (tablesConfig: { tables: TablesRelationalConfig; tableNamesMap: Record; @@ -343,7 +417,10 @@ export const extractRelations = (tablesConfig: { refSchema = mysqlTableConfig(refTable).schema; } else if (is(refTable, SQLiteTable)) { refSchema = undefined; - } else { + } else if (is(refTable, SingleStoreTable)) { + refSchema = singlestoreTableConfig(refTable).schema; + } + else { throw new Error('unsupported dialect'); } diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 9ad2d9e32f..b959e705e5 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -73,11 +73,17 @@ import { prepareRenameTableJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, + prepareSingleStoreCreateTableJson, + prepareAddCompositePrimaryKeySingleStore, + prepareDeleteCompositePrimaryKeySingleStore, + prepareAlterCompositePrimaryKeySingleStore, + prepareAlterColumnsSingleStore, } from './jsonStatements'; import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; +import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { PgSchema, PgSchemaSquashed, PgSquasher, sequenceSchema, sequenceSquashed } from './serializer/pgSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { copy, prepareMigrationMeta } from './utils'; @@ -259,6 +265,11 @@ export const diffResultSchemeMysql = object({ alteredEnums: never().array(), }); +export const diffResultSchemeSingleStore = object({ + alteredTablesWithColumns: alteredTableScheme.array(), + alteredEnums: never().array(), +}); + export const diffResultSchemeSQLite = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), @@ -272,6 +283,7 @@ export type Table = TypeOf; export type AlteredTable = TypeOf; export type DiffResult = TypeOf; export type DiffResultMysql = TypeOf; +export type DiffResultSingleStore = TypeOf; export type DiffResultSQLite = TypeOf; export interface ResolverInput { @@ -1651,6 +1663,419 @@ export const applyMysqlSnapshotsDiff = async ( }; }; +export const applySingleStoreSnapshotsDiff = async ( + json1: SingleStoreSchemaSquashed, + json2: SingleStoreSchemaSquashed, + tablesResolver: ( + input: ResolverInput, + ) => Promise>, + columnsResolver: ( + input: ColumnsResolverInput, + ) => Promise>, + prevFull: SingleStoreSchema, + curFull: SingleStoreSchema, + action?: 'push' | undefined, +): Promise<{ + statements: JsonStatement[]; + sqlStatements: string[]; + _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; +}> => { + // squash indexes and fks + + // squash uniqueIndexes and uniqueConstraint into constraints object + // it should be done for singlestore only because it has no diffs for it + for (const tableName in json1.tables) { + const table = json1.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json1.tables[tableName].indexes[index.name]; + } + } + } + + for (const tableName in json2.tables) { + const table = json2.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json2.tables[tableName].indexes[index.name]; + } + } + } + + const tablesDiff = diffSchemasOrTables(json1.tables, json2.tables); + + const { + created: createdTables, + deleted: deletedTables, + renamed: renamedTables, // renamed or moved + } = await tablesResolver({ + created: tablesDiff.added, + deleted: tablesDiff.deleted, + }); + + const tablesPatchedSnap1 = copy(json1); + tablesPatchedSnap1.tables = mapEntries(tablesPatchedSnap1.tables, (_, it) => { + const { name } = nameChangeFor(it, renamedTables); + it.name = name; + return [name, it]; + }); + + const res = diffColumns(tablesPatchedSnap1.tables, json2.tables); + const columnRenames = [] as { + table: string; + renames: { from: Column; to: Column }[]; + }[]; + + const columnCreates = [] as { + table: string; + columns: Column[]; + }[]; + + const columnDeletes = [] as { + table: string; + columns: Column[]; + }[]; + + for (let entry of Object.values(res)) { + const { renamed, created, deleted } = await columnsResolver({ + tableName: entry.name, + schema: entry.schema, + deleted: entry.columns.deleted, + created: entry.columns.added, + }); + + if (created.length > 0) { + columnCreates.push({ + table: entry.name, + columns: created, + }); + } + + if (deleted.length > 0) { + columnDeletes.push({ + table: entry.name, + columns: deleted, + }); + } + + if (renamed.length > 0) { + columnRenames.push({ + table: entry.name, + renames: renamed, + }); + } + } + + const columnRenamesDict = columnRenames.reduce( + (acc, it) => { + acc[it.table] = it.renames; + return acc; + }, + {} as Record< + string, + { + from: Named; + to: Named; + }[] + >, + ); + + const columnsPatchedSnap1 = copy(tablesPatchedSnap1); + columnsPatchedSnap1.tables = mapEntries( + columnsPatchedSnap1.tables, + (tableKey, tableValue) => { + const patchedColumns = mapKeys( + tableValue.columns, + (columnKey, column) => { + const rens = columnRenamesDict[tableValue.name] || []; + const newName = columnChangeFor(columnKey, rens); + column.name = newName; + return newName; + }, + ); + + tableValue.columns = patchedColumns; + return [tableKey, tableValue]; + }, + ); + + const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + + const typedResult: DiffResultSingleStore = diffResultSchemeSingleStore.parse(diffResult); + + const jsonStatements: JsonStatement[] = []; + + const jsonCreateIndexesForCreatedTables = createdTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.indexes, + curFull.internal, + ); + }) + .flat(); + + const jsonDropTables = deletedTables.map((it) => { + return prepareDropTableJson(it); + }); + + const jsonRenameTables = renamedTables.map((it) => { + return prepareRenameTableJson(it.from, it.to); + }); + + const alteredTables = typedResult.alteredTablesWithColumns; + + const jsonAddedCompositePKs: JsonCreateCompositePK[] = []; + const jsonDeletedCompositePKs: JsonDeleteCompositePK[] = []; + const jsonAlteredCompositePKs: JsonAlterCompositePK[] = []; + + const jsonAddedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames + .map((it) => prepareRenameColumns(it.table, '', it.renames)) + .flat(); + + const jsonAddColumnsStatemets: JsonAddColumnStatement[] = columnCreates + .map((it) => _prepareAddColumns(it.table, '', it.columns)) + .flat(); + + const jsonDropColumnsStatemets: JsonDropColumnStatement[] = columnDeletes + .map((it) => _prepareDropColumns(it.table, '', it.columns)) + .flat(); + + alteredTables.forEach((it) => { + // This part is needed to make sure that same columns in a table are not triggered for change + // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name + // We double-check that pk with same set of columns are both in added and deleted diffs + let addedColumns: string[] = []; + for (const addedPkName of Object.keys(it.addedCompositePKs)) { + const addedPkColumns = it.addedCompositePKs[addedPkName]; + addedColumns = SingleStoreSquasher.unsquashPK(addedPkColumns).columns; + } + + let deletedColumns: string[] = []; + for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { + const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; + deletedColumns = SingleStoreSquasher.unsquashPK(deletedPkColumns).columns; + } + + // Don't need to sort, but need to add tests for it + // addedColumns.sort(); + // deletedColumns.sort(); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + + let addedCompositePKs: JsonCreateCompositePK[] = []; + let deletedCompositePKs: JsonDeleteCompositePK[] = []; + let alteredCompositePKs: JsonAlterCompositePK[] = []; + + addedCompositePKs = prepareAddCompositePrimaryKeySingleStore( + it.name, + it.addedCompositePKs, + prevFull, + curFull, + ); + deletedCompositePKs = prepareDeleteCompositePrimaryKeySingleStore( + it.name, + it.deletedCompositePKs, + prevFull, + ); + // } + alteredCompositePKs = prepareAlterCompositePrimaryKeySingleStore( + it.name, + it.alteredCompositePKs, + prevFull, + curFull, + ); + + // add logic for unique constraints + let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + jsonAddedCompositePKs.push(...addedCompositePKs); + jsonDeletedCompositePKs.push(...deletedCompositePKs); + jsonAlteredCompositePKs.push(...alteredCompositePKs); + + jsonAddedUniqueConstraints.push(...addedUniqueConstraints); + jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); + jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + }); + + const rColumns = jsonRenameColumnsStatements.map((it) => { + const tableName = it.tableName; + const schema = it.schema; + return { + from: { schema, table: tableName, column: it.oldColumnName }, + to: { schema, table: tableName, column: it.newColumnName }, + }; + }); + + const jsonTableAlternations = alteredTables + .map((it) => { + return prepareAlterColumnsSingleStore( + it.name, + it.schema, + it.altered, + json1, + json2, + action, + ); + }) + .flat(); + + const jsonCreateIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.addedIndexes || {}, + curFull.internal, + ); + }) + .flat(); + + const jsonDropIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareDropIndexesJson( + it.name, + it.schema, + it.deletedIndexes || {}, + ); + }) + .flat(); + + alteredTables.forEach((it) => { + const droppedIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__old; + return current; + }, + {} as Record, + ); + const createdIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__new; + return current; + }, + {} as Record, + ); + + jsonCreateIndexesForAllAlteredTables.push( + ...prepareCreateIndexesJson(it.name, it.schema, createdIndexes || {}), + ); + jsonDropIndexesForAllAlteredTables.push( + ...prepareDropIndexesJson(it.name, it.schema, droppedIndexes || {}), + ); + }); + + const jsonSingleStoreCreateTables = createdTables.map((it) => { + return prepareSingleStoreCreateTableJson( + it, + curFull as SingleStoreSchema, + curFull.internal, + ); + }); + jsonStatements.push(...jsonSingleStoreCreateTables); + + jsonStatements.push(...jsonDropTables); + jsonStatements.push(...jsonRenameTables); + jsonStatements.push(...jsonRenameColumnsStatements); + + jsonStatements.push(...jsonDeletedUniqueConstraints); + + // Will need to drop indexes before changing any columns in table + // Then should go column alternations and then index creation + jsonStatements.push(...jsonDropIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDeletedCompositePKs); + jsonStatements.push(...jsonTableAlternations); + jsonStatements.push(...jsonAddedCompositePKs); + + jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...jsonDeletedUniqueConstraints); + + jsonStatements.push(...jsonAddColumnsStatemets); + + jsonStatements.push(...jsonCreateIndexesForCreatedTables); + + jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDropColumnsStatemets); + + // jsonStatements.push(...jsonDeletedCompositePKs); + // jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAlteredCompositePKs); + + jsonStatements.push(...jsonAddedUniqueConstraints); + + jsonStatements.push(...jsonAlteredUniqueConstraints); + + const sqlStatements = fromJson(jsonStatements, 'singlestore'); + + const uniqueSqlStatements: string[] = []; + sqlStatements.forEach((ss) => { + if (!uniqueSqlStatements.includes(ss)) { + uniqueSqlStatements.push(ss); + } + }); + + const rTables = renamedTables.map((it) => { + return { from: it.from, to: it.to }; + }); + + const _meta = prepareMigrationMeta([], rTables, rColumns); + + return { + statements: jsonStatements, + sqlStatements: uniqueSqlStatements, + _meta, + }; +}; + export const applySqliteSnapshotsDiff = async ( json1: SQLiteSchemaSquashed, json2: SQLiteSchemaSquashed, diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 769da7c5a6..ba3cb7c785 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -25,7 +25,6 @@ import { JsonAlterTableRemoveFromSchema, JsonAlterTableSetNewSchema, JsonAlterTableSetSchema, - JsonAlterUniqueConstraint, JsonCreateCompositePK, JsonCreateEnumStatement, JsonCreateIndexStatement, @@ -49,11 +48,12 @@ import { JsonRenameTableStatement, JsonSqliteAddColumnStatement, JsonSqliteCreateTableStatement, - JsonStatement, + JsonStatement } from './jsonStatements'; import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher } from './serializer/pgSchema'; +import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSquasher } from './serializer/sqliteSchema'; export const pgNativeTypes = new Set([ @@ -305,6 +305,81 @@ class MySqlCreateTableConvertor extends Convertor { return statement; } } +class SingleStoreCreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_table' && dialect === 'singlestore'; + } + + convert(st: JsonCreateTableStatement) { + const { + tableName, + columns, + schema, + compositePKs, + uniqueConstraints, + internals, + } = st; + + let statement = ''; + statement += `CREATE TABLE \`${tableName}\` (\n`; + for (let i = 0; i < columns.length; i++) { + const column = columns[i]; + + const primaryKeyStatement = column.primaryKey ? ' PRIMARY KEY' : ''; + const notNullStatement = column.notNull ? ' NOT NULL' : ''; + const defaultStatement = column.default !== undefined ? ` DEFAULT ${column.default}` : ''; + + const onUpdateStatement = column.onUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + + const autoincrementStatement = column.autoincrement + ? ' AUTO_INCREMENT' + : ''; + + const generatedStatement = column.generated + ? ` GENERATED ALWAYS AS (${column.generated?.as}) ${column.generated?.type.toUpperCase()}` + : ''; + + statement += '\t' + + `\`${column.name}\` ${column.type}${autoincrementStatement}${primaryKeyStatement}${notNullStatement}${defaultStatement}${onUpdateStatement}${generatedStatement}`; + statement += i === columns.length - 1 ? '' : ',\n'; + } + + if (typeof compositePKs !== 'undefined' && compositePKs.length > 0) { + statement += ',\n'; + const compositePK = SingleStoreSquasher.unsquashPK(compositePKs[0]); + statement += `\tCONSTRAINT \`${st.compositePkName}\` PRIMARY KEY(\`${compositePK.columns.join(`\`,\``)}\`)`; + } + + if ( + typeof uniqueConstraints !== 'undefined' + && uniqueConstraints.length > 0 + ) { + for (const uniqueConstraint of uniqueConstraints) { + statement += ',\n'; + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(uniqueConstraint); + + const uniqueString = unsquashedUnique.columns + .map((it) => { + return internals?.indexes + ? internals?.indexes[unsquashedUnique.name]?.columns[it] + ?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + statement += `\tCONSTRAINT \`${unsquashedUnique.name}\` UNIQUE(${uniqueString})`; + } + } + + statement += `\n);`; + statement += `\n`; + return statement; + } +} export class SQLiteCreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { @@ -585,6 +660,29 @@ class MySQLAlterTableDropUniqueConstraintConvertor extends Convertor { } convert(statement: JsonDeleteUniqueConstraint): string { const unsquashed = MySqlSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` DROP INDEX \`${unsquashed.name}\`;`; + } +} + +class SingleStoreAlterTableAddUniqueConstraintConvertor extends Convertor { + can(statement: JsonCreateUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'create_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonCreateUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` ADD CONSTRAINT \`${unsquashed.name}\` UNIQUE(\`${ + unsquashed.columns.join('`,`') + }\`);`; + } +} +class SingleStoreAlterTableDropUniqueConstraintConvertor extends Convertor { + can(statement: JsonDeleteUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'delete_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonDeleteUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); return `ALTER TABLE \`${statement.tableName}\` DROP INDEX \`${unsquashed.name}\`;`; } @@ -778,6 +876,17 @@ class MySQLDropTableConvertor extends Convertor { } } +class SingleStoreDropTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_table' && dialect === 'singlestore'; + } + + convert(statement: JsonDropTableStatement) { + const { tableName } = statement; + return `DROP TABLE \`${tableName}\`;`; + } +} + export class SQLiteDropTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'drop_table' && dialect === 'sqlite'; @@ -826,6 +935,17 @@ class MySqlRenameTableConvertor extends Convertor { } } +class SingleStoreRenameTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_table' && dialect === 'singlestore'; + } + + convert(statement: JsonRenameTableStatement) { + const { tableNameFrom, tableNameTo } = statement; + return `RENAME TABLE \`${tableNameFrom}\` TO \`${tableNameTo}\`;`; + } +} + class PgAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -857,6 +977,19 @@ class MySqlAlterTableRenameColumnConvertor extends Convertor { } } +class SingleStoreAlterTableRenameColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_rename_column' && dialect === 'singlestore' + ); + } + + convert(statement: JsonRenameColumnStatement) { + const { tableName, oldColumnName, newColumnName } = statement; + return `ALTER TABLE \`${tableName}\` RENAME COLUMN \`${oldColumnName}\` TO \`${newColumnName}\`;`; + } +} + class SQLiteAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -899,6 +1032,17 @@ class MySqlAlterTableDropColumnConvertor extends Convertor { } } +class SingleStoreAlterTableDropColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_drop_column' && dialect === 'singlestore'; + } + + convert(statement: JsonDropColumnStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` DROP COLUMN \`${columnName}\`;`; + } +} + class SQLiteAlterTableDropColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_table_drop_column' && dialect === 'sqlite'; @@ -1010,6 +1154,37 @@ class MySqlAlterTableAddColumnConvertor extends Convertor { } } +class SingleStoreAlterTableAddColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_add_column' && dialect === 'singlestore'; + } + + convert(statement: JsonAddColumnStatement) { + const { tableName, column } = statement; + const { + name, + type, + notNull, + primaryKey, + autoincrement, + onUpdate, + generated, + } = column; + + const defaultStatement = `${column.default !== undefined ? ` DEFAULT ${column.default}` : ''}`; + const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; + const primaryKeyStatement = `${primaryKey ? ' PRIMARY KEY' : ''}`; + const autoincrementStatement = `${autoincrement ? ' AUTO_INCREMENT' : ''}`; + const onUpdateStatement = `${onUpdate ? ' ON UPDATE CURRENT_TIMESTAMP' : ''}`; + + const generatedStatement = generated + ? ` GENERATED ALWAYS AS (${generated?.as}) ${generated?.type.toUpperCase()}` + : ''; + + return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${notNullStatement}${onUpdateStatement}${generatedStatement};`; + } +} + export class SQLiteAlterTableAddColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1738,83 +1913,419 @@ class MySqlModifyColumn extends Convertor { } } -class SqliteAlterTableAlterColumnDropDefaultConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return ( - statement.type === 'alter_table_alter_column_drop_default' - && dialect === 'sqlite' - ); - } - convert(statement: JsonAlterColumnDropDefaultStatement) { +class SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( - '/*\n SQLite does not support "Drop default from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' + statement.type === 'alter_table_alter_column_alter_generated' + && dialect === 'singlestore' ); } -} -class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'postgresql'; - } + convert(statement: JsonAlterColumnAlterGeneratedStatement) { + const { + tableName, + columnName, + schema, + columnNotNull: notNull, + columnDefault, + columnOnUpdate, + columnAutoIncrement, + columnPk, + columnGenerated, + } = statement; - convert(statement: JsonCreateCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); + const tableNameWithSchema = schema + ? `\`${schema}\`.\`${tableName}\`` + : `\`${tableName}\``; - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; + const addColumnStatement = new SingleStoreAlterTableAddColumnConvertor().convert({ + schema, + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull, + default: columnDefault, + onUpdate: columnOnUpdate, + autoincrement: columnAutoIncrement, + primaryKey: columnPk, + generated: columnGenerated, + }, + type: 'alter_table_add_column', + }); - return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ - columns.join('","') - }");`; + return [ + `ALTER TABLE ${tableNameWithSchema} drop column \`${columnName}\`;`, + addColumnStatement, + ]; } } -class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + +class SingleStoreAlterTableAlterColumnSetDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; + return ( + statement.type === 'alter_table_alter_column_set_default' + && dialect === 'singlestore' + ); } - convert(statement: JsonDeleteCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); - - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + convert(statement: JsonAlterColumnSetDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` SET DEFAULT ${statement.newDefaultValue};`; } } -class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnDropDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; - } - - convert(statement: JsonAlterCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.old); - const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( - statement.new, + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'singlestore' ); + } - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ - newColumns.join(',') - });`; + convert(statement: JsonAlterColumnDropDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` DROP DEFAULT;`; } } -class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { +class SingleStoreAlterTableAddPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_set_pk' + && dialect === 'singlestore' + ); + } + convert(statement: JsonAlterColumnSetPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY (\`${statement.columnName}\`);`; + } +} + +class SingleStoreAlterTableDropPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_pk' + && dialect === 'singlestore' + ); + } + convert(statement: JsonAlterColumnDropPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY`; + } +} + +type SingleStoreModifyColumnStatement = + | JsonAlterColumnDropNotNullStatement + | JsonAlterColumnSetNotNullStatement + | JsonAlterColumnTypeStatement + | JsonAlterColumnDropOnUpdateStatement + | JsonAlterColumnSetOnUpdateStatement + | JsonAlterColumnDropAutoincrementStatement + | JsonAlterColumnSetAutoincrementStatement + | JsonAlterColumnSetDefaultStatement + | JsonAlterColumnDropDefaultStatement + | JsonAlterColumnSetGeneratedStatement + | JsonAlterColumnDropGeneratedStatement; + +class SingleStoreModifyColumn extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + (statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_drop_on_update' + || statement.type === 'alter_table_alter_column_set_on_update' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'alter_table_alter_column_set_generated' + || statement.type === 'alter_table_alter_column_drop_generated') + && dialect === 'singlestore' + ); + } + + convert(statement: SingleStoreModifyColumnStatement) { + const { tableName, columnName } = statement; + let columnType = ``; + let columnDefault: any = ''; + let columnNotNull = ''; + let columnOnUpdate = ''; + let columnAutoincrement = ''; + let primaryKey = statement.columnPk ? ' PRIMARY KEY' : ''; + let columnGenerated = ''; + + if (statement.type === 'alter_table_alter_column_drop_notnull') { + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + columnNotNull = ` NOT NULL`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = ` ON UPDATE CURRENT_TIMESTAMP`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if ( + statement.type === 'alter_table_alter_column_set_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ' AUTO_INCREMENT'; + } else if ( + statement.type === 'alter_table_alter_column_drop_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ''; + } else if (statement.type === 'alter_table_alter_column_set_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ` DEFAULT ${statement.newDefaultValue}`; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.columnGenerated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } else { + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + } else if (statement.type === 'alter_table_alter_column_drop_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.oldColumn?.generated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } + } else { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + + // Seems like getting value from simple json2 shanpshot makes dates be dates + columnDefault = columnDefault instanceof Date + ? columnDefault.toISOString() + : columnDefault; + + return `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\`${columnType}${columnAutoincrement}${columnNotNull}${columnDefault}${columnOnUpdate}${columnGenerated};`; + } +} +class SqliteAlterTableAlterColumnDropDefaultConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'sqlite' + ); + } + + convert(statement: JsonAlterColumnDropDefaultStatement) { + return ( + '/*\n SQLite does not support "Drop default from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } +} + +class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ + columns.join('","') + }");`; + } +} + +class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonDeleteCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + } +} + +class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonAlterCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.old); + const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( + statement.new, + ); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ + newColumns.join(',') + });`; + } +} + +class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_composite_pk' && dialect === 'mysql'; } @@ -1849,6 +2360,42 @@ class MySqlAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { } } +class SingleStoreAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + } +} + +class SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonDeleteCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY;`; + } +} + +class SingleStoreAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonAlterCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.old); + const { name: newName, columns: newColumns } = SingleStoreSquasher.unsquashPK( + statement.new, + ); + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY, ADD PRIMARY KEY(\`${newColumns.join('`,`')}\`);`; + } +} + class SqliteAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_composite_pk' && dialect === 'sqlite'; @@ -2369,6 +2916,32 @@ class CreateMySqlIndexConvertor extends Convertor { } } +class CreateSingleStoreIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_index' && dialect === 'singlestore'; + } + + convert(statement: JsonCreateIndexStatement): string { + // should be changed + const { name, columns, isUnique } = SingleStoreSquasher.unsquashIdx( + statement.data, + ); + const indexPart = isUnique ? 'UNIQUE INDEX' : 'INDEX'; + + const uniqueString = columns + .map((it) => { + return statement.internal?.indexes + ? statement.internal?.indexes[name]?.columns[it]?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + return `CREATE ${indexPart} \`${name}\` ON \`${statement.tableName}\` (${uniqueString});`; + } +} + export class CreateSqliteIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_index' && dialect === 'sqlite'; @@ -2513,9 +3086,21 @@ class MySqlDropIndexConvertor extends Convertor { } } +class SingleStoreDropIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_index' && dialect === 'singlestore'; + } + + convert(statement: JsonDropIndexStatement): string { + const { name } = SingleStoreSquasher.unsquashIdx(statement.data); + return `DROP INDEX \`${name}\` ON \`${statement.tableName}\`;`; + } +} + const convertors: Convertor[] = []; convertors.push(new PgCreateTableConvertor()); convertors.push(new MySqlCreateTableConvertor()); +convertors.push(new SingleStoreCreateTableConvertor()); convertors.push(new SQLiteCreateTableConvertor()); convertors.push(new CreateTypeEnumConvertor()); @@ -2528,22 +3113,27 @@ convertors.push(new AlterPgSequenceConvertor()); convertors.push(new PgDropTableConvertor()); convertors.push(new MySQLDropTableConvertor()); +convertors.push(new SingleStoreDropTableConvertor()); convertors.push(new SQLiteDropTableConvertor()); convertors.push(new PgRenameTableConvertor()); convertors.push(new MySqlRenameTableConvertor()); +convertors.push(new SingleStoreRenameTableConvertor()); convertors.push(new SqliteRenameTableConvertor()); convertors.push(new PgAlterTableRenameColumnConvertor()); convertors.push(new MySqlAlterTableRenameColumnConvertor()); +convertors.push(new SingleStoreAlterTableRenameColumnConvertor()); convertors.push(new SQLiteAlterTableRenameColumnConvertor()); convertors.push(new PgAlterTableDropColumnConvertor()); convertors.push(new MySqlAlterTableDropColumnConvertor()); +convertors.push(new SingleStoreAlterTableDropColumnConvertor()); convertors.push(new SQLiteAlterTableDropColumnConvertor()); convertors.push(new PgAlterTableAddColumnConvertor()); convertors.push(new MySqlAlterTableAddColumnConvertor()); +convertors.push(new SingleStoreAlterTableAddColumnConvertor()); convertors.push(new SQLiteAlterTableAddColumnConvertor()); convertors.push(new PgAlterTableAlterColumnSetTypeConvertor()); @@ -2554,13 +3144,18 @@ convertors.push(new PgAlterTableDropUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableAddUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableDropUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableAddUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableDropUniqueConstraintConvertor()); + convertors.push(new CreatePgIndexConvertor()); convertors.push(new CreateMySqlIndexConvertor()); +convertors.push(new CreateSingleStoreIndexConvertor()); convertors.push(new CreateSqliteIndexConvertor()); convertors.push(new PgDropIndexConvertor()); convertors.push(new SqliteDropIndexConvertor()); convertors.push(new MySqlDropIndexConvertor()); +convertors.push(new SingleStoreDropIndexConvertor()); convertors.push(new AlterTypeAddValueConvertor()); @@ -2578,6 +3173,8 @@ convertors.push(new PgAlterTableAlterColumnAlterrGeneratedConvertor()); convertors.push(new MySqlAlterTableAlterColumnAlterrGeneratedConvertor()); +convertors.push(new SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor()); + convertors.push(new SqliteAlterTableAlterColumnDropGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnAlterGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnSetExpressionConvertor()); @@ -2586,6 +3183,8 @@ convertors.push(new MySqlModifyColumn()); // convertors.push(new MySqlAlterTableAlterColumnSetDefaultConvertor()); // convertors.push(new MySqlAlterTableAlterColumnDropDefaultConvertor()); +convertors.push(new SingleStoreModifyColumn()); + convertors.push(new PgCreateForeignKeyConvertor()); convertors.push(new MySqlCreateForeignKeyConvertor()); @@ -2636,6 +3235,12 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableDropPk()); +convertors.push(new SingleStoreAlterTableCreateCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableAddPk()); +convertors.push(new SingleStoreAlterTableAlterCompositePrimaryKeyConvertor()); + export const fromJson = (statements: JsonStatement[], dialect: Dialect) => { const result = statements .flatMap((statement) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fb00d93d6..388f8017c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -237,8 +237,8 @@ importers: specifier: ^7.4.3 version: 7.4.6 mysql2: - specifier: 2.3.3 - version: 2.3.3 + specifier: ^3.3.3 + version: 3.3.3 node-fetch: specifier: ^3.3.2 version: 3.3.2 @@ -2974,10 +2974,12 @@ packages: '@humanwhocodes/config-array@0.11.11': resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} @@ -2990,9 +2992,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.1': resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} @@ -4521,6 +4525,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -6286,6 +6291,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. generate-function@2.3.1: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} @@ -7142,6 +7148,7 @@ packages: libsql@0.3.18: resolution: {integrity: sha512-lvhKr7WV3NLWRbXkjn/MeKqXOAqWKU0PX9QYrvDh7fneukapj+iUQ4qgJASrQyxcCrEsClXCQiiK5W6OoYPAlA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7323,9 +7330,6 @@ packages: resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} hasBin: true - long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -7355,10 +7359,6 @@ packages: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} - lru-cache@9.1.2: - resolution: {integrity: sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==} - engines: {node: 14 || >=16.14} - lru-queue@0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} @@ -7672,10 +7672,6 @@ packages: resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} engines: {node: '>=0.8.0'} - mysql2@2.3.3: - resolution: {integrity: sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==} - engines: {node: '>= 8.0'} - mysql2@3.3.3: resolution: {integrity: sha512-MxDQJztArk4JFX1PKVjDhIXRzAmVJfuqZrVU+my6NeYBAA/XZRaDw5q7vga8TNvgyy3Lv3rivBFBBuJFbsdjaw==} engines: {node: '>= 8.0'} @@ -7835,6 +7831,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. npx-import@1.1.4: resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} @@ -8651,6 +8648,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.0: @@ -18613,8 +18611,6 @@ snapshots: dayjs: 1.11.11 yargs: 15.4.1 - long@4.0.0: {} - long@5.2.3: {} loose-envify@1.4.0: @@ -18639,8 +18635,6 @@ snapshots: lru-cache@8.0.5: {} - lru-cache@9.1.2: {} - lru-queue@0.1.0: dependencies: es5-ext: 0.10.62 @@ -19079,17 +19073,6 @@ snapshots: rimraf: 2.4.5 optional: true - mysql2@2.3.3: - dependencies: - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.6.3 - long: 4.0.0 - lru-cache: 6.0.0 - named-placeholders: 1.1.3 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - mysql2@3.3.3: dependencies: denque: 2.1.0 @@ -19514,7 +19497,7 @@ snapshots: path-scurry@1.10.1: dependencies: - lru-cache: 9.1.2 + lru-cache: 10.2.2 minipass: 5.0.0 path-scurry@1.11.1: From fb90045ba49846de543c3ac77983b58206afb28d Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 8 Aug 2024 13:51:05 +0100 Subject: [PATCH 086/152] create new singlestore-schemas.test.ts file --- .../src/serializer/singlestoreSchema.ts | 10 - drizzle-kit/tests/schemaDiffer.ts | 207 +++++++++++++++++- drizzle-kit/tests/singlestore-schemas.test.ts | 155 +++++++++++++ 3 files changed, 358 insertions(+), 14 deletions(-) create mode 100644 drizzle-kit/tests/singlestore-schemas.test.ts diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts index 2527ddd0f8..a0bbae1bfc 100644 --- a/drizzle-kit/src/serializer/singlestoreSchema.ts +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -11,16 +11,6 @@ const index = object({ lock: enumType(['default', 'none', 'shared', 'exclusive']).optional(), }).strict(); -const fk = object({ - name: string(), - tableFrom: string(), - columnsFrom: string().array(), - tableTo: string(), - columnsTo: string().array(), - onUpdate: string().optional(), - onDelete: string().optional(), -}).strict(); - const column = object({ name: string(), type: string(), diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 4a14d920b2..4c2512a292 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -2,7 +2,9 @@ import { PGlite } from '@electric-sql/pglite'; import { Database } from 'better-sqlite3'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; +import { SingleStoreSchema } from 'drizzle-orm/singlestore-core'; import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; +import { SingleStoreTable } from 'drizzle-orm/singlestore-core'; import { SQLiteTable } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; @@ -17,21 +19,24 @@ import { import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; +import { schemaToTypeScript as schemaToTypeScriptSingleStore } from 'src/introspect-singlestore'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; import { mysqlSchema, squashMysqlScheme } from 'src/serializer/mysqlSchema'; -import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; -import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; +import { fromDatabase as fromMySqlDatabase, generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; import { pgSchema, squashPgScheme } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; +import { prepareFromSingleStoreImports } from 'src/serializer/singlestoreImports'; +import { singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; +import { fromDatabase as fromSingleStoreDatabase, generateSingleStoreSnapshot } from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme } from 'src/serializer/sqliteSchema'; -import { fromDatabase as fromSqliteDatabase } from 'src/serializer/sqliteSerializer'; -import { generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; +import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -49,6 +54,7 @@ export type PostgresSchema = Record< PgTable | PgEnum | PgSchema | PgSequence >; export type MysqlSchema = Record | MySqlSchema>; +export type SinglestoreSchema = Record | SingleStoreSchema>; export type SqliteSchema = Record>; export const testSchemasResolver = @@ -835,6 +841,116 @@ export const diffTestSchemasMysql = async ( return { sqlStatements, statements }; }; +export const diffTestSchemasSingleStore = async ( + left: SinglestoreSchema, + right: SinglestoreSchema, + renamesArr: string[], + cli: boolean = false, +) => { + const leftTables = Object.values(left).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const rightTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const serialized1 = generateSingleStoreSnapshot(leftTables); + const serialized2 = generateSingleStoreSnapshot(rightTables); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + const sn2 = squashSingleStoreScheme(sch2); + + const validatedPrev = singlestoreSchema.parse(sch1); + const validatedCur = singlestoreSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; + } + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + + +export const applySingleStoreDiffs = async (sn: SingleStoreSchema) => { + const dryRun = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + tables: {}, + enums: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, + } as const; + + const tables = Object.values(sn).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const serialized1 = generateSingleStoreSnapshot(tables); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + + const validatedPrev = singlestoreSchema.parse(dryRun); + const validatedCur = singlestoreSchema.parse(sch1); + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + dryRun, + sn1, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + export const diffTestSchemasPushSqlite = async ( client: Database, left: SqliteSchema, @@ -1224,6 +1340,89 @@ export const introspectMySQLToFile = async ( }; }; +export const introspectSingleStoreToFile = async ( + client: Connection, + initSchema: SingleStoreSchema, + testName: string, + schema: string, +) => { + // put in db + const { sqlStatements } = await applySingleStoreDiffs(initSchema); + for (const st of sqlStatements) { + await client.query(st); + } + + // introspect to schema + const introspectedSchema = await fromSingleStoreDatabase( + { + query: async (sql: string, params?: any[] | undefined) => { + const res = await client.execute(sql, params); + return res[0] as any; + }, + }, + schema, + ); + + const file = schemaToTypeScriptSingleStore(introspectedSchema, 'camel'); + + fs.writeFileSync(`tests/introspect/singlestore/${testName}.ts`, file.file); + + const response = await prepareFromSingleStoreImports([ + `tests/introspect/singlestore/${testName}.ts`, + ]); + + const afterFileImports = generateSingleStoreSnapshot(response.tables); + + const { version: v2, dialect: d2, ...rest2 } = afterFileImports; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn2AfterIm = squashSingleStoreScheme(sch2); + const validatedCurAfterImport = singlestoreSchema.parse(sch2); + + const leftTables = Object.values(initSchema).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const initSnapshot = generateSingleStoreSnapshot(leftTables); + + const { version: initV, dialect: initD, ...initRest } = initSnapshot; + + const initSch = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashSingleStoreScheme(initSch); + const validatedCur = singlestoreSchema.parse(initSch); + + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applySingleStoreSnapshotsDiff( + sn2AfterIm, + initSn, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + validatedCurAfterImport, + validatedCur, + ); + + fs.rmSync(`tests/introspect/singlestore/${testName}.ts`); + + return { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + }; +}; + export const introspectSQLiteToFile = async ( client: Database, initSchema: SqliteSchema, diff --git a/drizzle-kit/tests/singlestore-schemas.test.ts b/drizzle-kit/tests/singlestore-schemas.test.ts new file mode 100644 index 0000000000..db9fe04804 --- /dev/null +++ b/drizzle-kit/tests/singlestore-schemas.test.ts @@ -0,0 +1,155 @@ +import { singlestoreSchema, singlestoreTable } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +// We don't manage databases(schemas) in MySQL with Drizzle Kit +test('add schema #1', async () => { + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('add schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, {}, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('rename schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev->dev2']); + + expect(statements.length).toBe(0); +}); + +test('rename schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema1: singlestoreSchema('dev1'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = {}; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #3', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + usersInDev: dev.table('users', {}), + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + compositePKs: [], + }); +}); + +test('remove table from schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = { + dev, + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('remove table from schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = {}; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); From 0dd478beb9ce1a45e2f8a1bef7e94db079a1e527 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 8 Aug 2024 15:09:50 +0100 Subject: [PATCH 087/152] adapt validations.test.ts to singlestore dialect --- drizzle-kit/tests/validations.test.ts | 169 ++++++++++++++++++++++++++ drizzle-kit/tests/wrap-param.test.ts | 3 + 2 files changed, 172 insertions(+) diff --git a/drizzle-kit/tests/validations.test.ts b/drizzle-kit/tests/validations.test.ts index 04d0096ff8..49dfc832c0 100644 --- a/drizzle-kit/tests/validations.test.ts +++ b/drizzle-kit/tests/validations.test.ts @@ -1,4 +1,5 @@ import { mysqlCredentials } from 'src/cli/validations/mysql'; +import { singlestoreCredentials } from 'src/cli/validations/singlestore'; import { postgresCredentials } from 'src/cli/validations/postgres'; import { sqliteCredentials } from 'src/cli/validations/sqlite'; import { expect, test } from 'vitest'; @@ -666,3 +667,171 @@ test('mysql #17', () => { }); }).toThrowError(); }); + +test('singlestore #1', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #2', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #3', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }), + ).toStrictEqual({ + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }); +}); + +test('singlestore #4', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: 'allow', + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: 'allow', + }); +}); + +test('singlestore #5', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }); +}); + +test('singlestore #6', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + }); + }).toThrowError(); +}); + +test('singlestore #7', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: undefined, + }); + }).toThrowError(); +}); + +test('singlestore #8', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: '', + }); + }).toThrowError(); +}); + +test('singlestore #9', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #10', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #11', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #12', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #13', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + host: ' ', + }); + }).toThrowError(); +}); + +test('singlestore #14', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: ' ', + port: '', + }); + }).toThrowError(); +}); diff --git a/drizzle-kit/tests/wrap-param.test.ts b/drizzle-kit/tests/wrap-param.test.ts index 542998bdac..a27d27d450 100644 --- a/drizzle-kit/tests/wrap-param.test.ts +++ b/drizzle-kit/tests/wrap-param.test.ts @@ -7,6 +7,9 @@ test('wrapParam', () => { expect(wrapParam('url', 'mysql://user:password@localhost:3306/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'mysql://user:****@localhost:3306/database'`, ); + expect(wrapParam('url', 'singlestore://user:password@localhost:3306/database', false, 'url')).toBe( + ` [${chalk.green('✓')}] url: 'singlestore://user:****@localhost:3306/database'`, + ); expect(wrapParam('url', 'postgresql://user:password@localhost:5432/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'postgresql://user:****@localhost:5432/database'`, ); From a861f5d2c8455b7ecf1a0becd1819d81ae89d869 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 8 Aug 2024 15:28:38 +0100 Subject: [PATCH 088/152] replicate generate tables and general singlestore migrations test --- .../tests/singlestore-generated.test.ts | 1290 +++++++++++++++++ drizzle-kit/tests/singlestore.test.ts | 569 ++++++++ drizzle-kit/tests/testsinglestore.ts | 29 + 3 files changed, 1888 insertions(+) create mode 100644 drizzle-kit/tests/singlestore-generated.test.ts create mode 100644 drizzle-kit/tests/singlestore.test.ts create mode 100644 drizzle-kit/tests/testsinglestore.ts diff --git a/drizzle-kit/tests/singlestore-generated.test.ts b/drizzle-kit/tests/singlestore-generated.test.ts new file mode 100644 index 0000000000..8944f3b211 --- /dev/null +++ b/drizzle-kit/tests/singlestore-generated.test.ts @@ -0,0 +1,1290 @@ +import { SQL, sql } from 'drizzle-orm'; +import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('generated as callback: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as callback: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as callback: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as callback: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as callback: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as sql: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as sql: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as sql: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as sql: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as sql: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as string: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as string: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as string: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as string: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``, { + mode: 'virtual', + }), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as string: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts new file mode 100644 index 0000000000..4000c1bffb --- /dev/null +++ b/drizzle-kit/tests/singlestore.test.ts @@ -0,0 +1,569 @@ +import { sql } from 'drizzle-orm'; +import { index, json, singlestoreSchema, singlestoreTable, primaryKey, serial, text, uniqueIndex } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('add table #1', async () => { + const to = { + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #2', async () => { + const to = { + users: singlestoreTable('users', { + id: serial('id').primaryKey(), + }), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_id;id'], + compositePkName: 'users_id', + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #3', async () => { + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id'), + }, + (t) => { + return { + pk: primaryKey({ + name: 'users_pk', + columns: [t.id], + }), + }; + }, + ), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_pk;id'], + uniqueConstraints: [], + compositePkName: 'users_pk', + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #4', async () => { + const to = { + users: singlestoreTable('users', {}), + posts: singlestoreTable('posts', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_table', + tableName: 'posts', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #5', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + }; + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('add table #6', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users2', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'drop_table', + tableName: 'users1', + schema: undefined, + }); +}); + +test('add table #7', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users: singlestoreTable('users', {}), + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users1->public.users2', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'rename_table', + tableNameFrom: 'users1', + tableNameTo: 'users2', + fromSchema: undefined, + toSchema: undefined, + }); +}); + +test('add schema + table #1', async () => { + const schema = singlestoreSchema('folder'); + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('change schema with tables #1', async () => { + const schema = singlestoreSchema('folder'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder->folder2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #1', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: singlestoreTable('users', {}), + }; + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users->folder.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_table', + tableName: 'users', + schema: undefined, + }); +}); + +test('change table schema #2', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema, + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder.users->public.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + compositePkName: '', + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('change table schema #3', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #4', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, // remove schema + users: schema1.table('users', {}), + }; + const to = { + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users2', {}), // rename and move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #6', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema2, // rename schema + users: schema2.table('users2', {}), // rename table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1->folder2', + 'folder2.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('add table #10', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({}), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('{}')\n);\n", + ); +}); + +test('add table #11', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[]')\n);\n", + ); +}); + +test('add table #12', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([1, 2, 3]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[1,2,3]')\n);\n", + ); +}); + +test('add table #13', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ key: 'value' }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value"}\')\n);\n', + ); +}); + +test('add table #14', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ + key: 'value', + arr: [1, 2, 3], + }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value","arr":[1,2,3]}\')\n);\n', + ); +}); + +// TODO: add bson type tests + +// TODO: add blob type tests + +// TODO: add uuid type tests + +// TODO: add guid type tests + +// TODO: add vector type tests + +// TODO: add geopoint type tests + +test('drop index', async () => { + const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), + }; + + const to = { + users: singlestoreTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); +}); + +test('add table with indexes', async () => { + const from = {}; + + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id').primaryKey(), + name: text('name'), + email: text('email'), + }, + (t) => ({ + uniqueExpr: uniqueIndex('uniqueExpr').on(sql`(lower(${t.email}))`), + indexExpr: index('indexExpr').on(sql`(lower(${t.email}))`), + indexExprMultiple: index('indexExprMultiple').on( + sql`(lower(${t.email}))`, + sql`(lower(${t.email}))`, + ), + + uniqueCol: uniqueIndex('uniqueCol').on(t.email), + indexCol: index('indexCol').on(t.email), + indexColMultiple: index('indexColMultiple').on(t.email, t.email), + + indexColExpr: index('indexColExpr').on( + sql`(lower(${t.email}))`, + t.email, + ), + }), + ), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements).toStrictEqual([ + `CREATE TABLE \`users\` (\n\t\`id\` serial AUTO_INCREMENT NOT NULL,\n\t\`name\` text,\n\t\`email\` text,\n\tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`),\n\tCONSTRAINT \`uniqueExpr\` UNIQUE((lower(\`email\`))),\n\tCONSTRAINT \`uniqueCol\` UNIQUE(\`email\`) +); +`, + 'CREATE INDEX `indexExpr` ON `users` ((lower(`email`)));', + 'CREATE INDEX `indexExprMultiple` ON `users` ((lower(`email`)),(lower(`email`)));', + 'CREATE INDEX `indexCol` ON `users` (`email`);', + 'CREATE INDEX `indexColMultiple` ON `users` (`email`,`email`);', + 'CREATE INDEX `indexColExpr` ON `users` ((lower(`email`)),`email`);', + ]); +}); diff --git a/drizzle-kit/tests/testsinglestore.ts b/drizzle-kit/tests/testsinglestore.ts new file mode 100644 index 0000000000..1dc97d9c32 --- /dev/null +++ b/drizzle-kit/tests/testsinglestore.ts @@ -0,0 +1,29 @@ +import { index, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), +}; + +const to = { + users: singlestoreTable('table', { + name: text('name'), + }), +}; + +diffTestSchemasSingleStore(from, to, []).then((res) => { + const { statements, sqlStatements } = res; + + console.log(statements); + console.log(sqlStatements); +}); From 8084ad63f522f8d127417b9f3a4514c2c052f682 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 8 Aug 2024 15:28:38 +0100 Subject: [PATCH 089/152] replicate generate tables and general singlestore migrations test --- drizzle-kit/src/cli/commands/migrate.ts | 52 ------------------------- 1 file changed, 52 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index c3614869b7..45e05201a1 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -395,58 +395,6 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { } }; -// Not needed for now -function mySingleStoreSchemaSuggestions( - curSchema: TypeOf, - prevSchema: TypeOf, -) { - const suggestions: string[] = []; - const usedSuggestions: string[] = []; - const suggestionTypes = { - // TODO: Check if SingleStore has serial type - serial: withStyle.errorWarning( - `We deprecated the use of 'serial' for SingleStore starting from version 0.20.0. In SingleStore, 'serial' is simply an alias for 'bigint unsigned not null auto_increment unique,' which creates all constraints and indexes for you. This may make the process less explicit for both users and drizzle-kit push commands`, - ), - }; - - for (const table of Object.values(curSchema.tables)) { - for (const column of Object.values(table.columns)) { - if (column.type === 'serial') { - if (!usedSuggestions.includes('serial')) { - suggestions.push(suggestionTypes['serial']); - } - - const uniqueForSerial = Object.values( - prevSchema.tables[table.name].uniqueConstraints, - ).find((it) => it.columns[0] === column.name); - - suggestions.push( - `\n` - + withStyle.suggestion( - `We are suggesting to change ${ - chalk.blue( - column.name, - ) - } column in ${ - chalk.blueBright( - table.name, - ) - } table from serial to bigint unsigned\n\n${ - chalk.blueBright( - `bigint("${column.name}", { mode: "number", unsigned: true }).notNull().autoincrement().unique(${ - uniqueForSerial?.name ? `"${uniqueForSerial?.name}"` : '' - })`, - ) - }`, - ), - ); - } - } - } - - return suggestions; -} - // Intersect with prepareAnMigrate export const prepareSingleStorePush = async ( schemaPath: string | string[], From a2d0c411dc15ebd99de499f2503e62538764e62c Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 13 Aug 2024 11:20:06 +0100 Subject: [PATCH 090/152] lint fix on drizzle-kit files --- drizzle-kit/src/api.ts | 6 +++- drizzle-kit/src/cli/commands/introspect.ts | 15 +++++--- drizzle-kit/src/cli/commands/migrate.ts | 2 +- drizzle-kit/src/cli/commands/push.ts | 12 +++++-- drizzle-kit/src/cli/commands/utils.ts | 6 +++- drizzle-kit/src/cli/connections.ts | 2 +- drizzle-kit/src/introspect-singlestore.ts | 19 ++++------ drizzle-kit/src/jsonStatements.ts | 2 +- drizzle-kit/src/migrationPreparator.ts | 2 +- drizzle-kit/src/schemaValidator.ts | 2 +- .../src/serializer/singlestoreSerializer.ts | 35 +++++++++++++------ drizzle-kit/src/serializer/studio.ts | 17 +++++---- drizzle-kit/src/snapshotsDiffer.ts | 12 +++---- drizzle-kit/src/sqlgenerator.ts | 6 ++-- drizzle-kit/tests/schemaDiffer.ts | 8 +++-- drizzle-kit/tests/singlestore.test.ts | 11 +++++- drizzle-kit/tests/validations.test.ts | 2 +- 17 files changed, 98 insertions(+), 61 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 663ccb80ad..fe2c162c56 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -22,7 +22,11 @@ import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; import { prepareFromExports } from './serializer/pgImports'; import { PgSchema as PgSchemaKit, pgSchema, squashPgScheme } from './serializer/pgSchema'; import { generatePgSnapshot } from './serializer/pgSerializer'; -import { SingleStoreSchema as SingleStoreSchemaKit, singlestoreSchema, squashSingleStoreScheme } from './serializer/singlestoreSchema'; +import { + SingleStoreSchema as SingleStoreSchemaKit, + singlestoreSchema, + squashSingleStoreScheme, +} from './serializer/singlestoreSchema'; import { generateSingleStoreSnapshot } from './serializer/singlestoreSerializer'; import { SQLiteSchema as SQLiteSchemaKit, sqliteSchema, squashSqliteScheme } from './serializer/sqliteSchema'; import { generateSqliteSnapshot } from './serializer/sqliteSerializer'; diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index c00ca42140..4e51d6b496 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -4,23 +4,30 @@ import { render, renderWithTask } from 'hanji'; import { Minimatch } from 'minimatch'; import { join } from 'path'; import { plural, singular } from 'pluralize'; +import { drySingleStore, SingleStoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { assertUnreachable, originUUID } from '../../global'; import { schemaToTypeScript as mysqlSchemaToTypeScript } from '../../introspect-mysql'; -import { schemaToTypeScript as singlestoreSchemaToTypeScript } from '../../introspect-singlestore'; import { paramNameFor, schemaToTypeScript as postgresSchemaToTypeScript } from '../../introspect-pg'; +import { schemaToTypeScript as singlestoreSchemaToTypeScript } from '../../introspect-singlestore'; import { schemaToTypeScript as sqliteSchemaToTypeScript } from '../../introspect-sqlite'; import { dryMySql, MySqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; import { fromDatabase as fromMysqlDatabase } from '../../serializer/mysqlSerializer'; -import { fromDatabase as fromSingleStoreDatabase } from '../../serializer/singlestoreSerializer'; import { dryPg, type PgSchema, squashPgScheme } from '../../serializer/pgSchema'; import { fromDatabase as fromPostgresDatabase } from '../../serializer/pgSerializer'; +import { fromDatabase as fromSingleStoreDatabase } from '../../serializer/singlestoreSerializer'; import { drySQLite, type SQLiteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSerializer'; -import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff } from '../../snapshotsDiffer'; +import { + applyMysqlSnapshotsDiff, + applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, + applySqliteSnapshotsDiff, +} from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; import type { Casing, Prefix } from '../validations/common'; import type { MysqlCredentials } from '../validations/mysql'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; import { IntrospectProgress } from '../views'; import { @@ -31,8 +38,6 @@ import { tablesResolver, writeResult, } from './migrate'; -import { SingleStoreCredentials } from '../validations/singlestore'; -import { drySingleStore, SingleStoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; export const introspectPostgres = async ( casing: Casing, diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 45e05201a1..0672fe734a 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,6 +13,7 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; +import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; @@ -46,7 +47,6 @@ import { schema, } from '../views'; import { GenerateConfig } from './utils'; -import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; export type Named = { name: string; diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 1c97ee75f5..d54f8c6ebe 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -5,12 +5,18 @@ import { Select } from '../selector-ui'; import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; -import { filterStatements as mySqlFilterStatements, logSuggestionsAndReturn as mySqlLogSuggestionsAndReturn } from './mysqlPushUtils'; -import { filterStatements as singleStoreFilterStatements, logSuggestionsAndReturn as singleStoreLogSuggestionsAndReturn } from './singlestorePushUtils'; +import { + filterStatements as mySqlFilterStatements, + logSuggestionsAndReturn as mySqlLogSuggestionsAndReturn, +} from './mysqlPushUtils'; import { pgSuggestions } from './pgPushUtils'; +import { + filterStatements as singleStoreFilterStatements, + logSuggestionsAndReturn as singleStoreLogSuggestionsAndReturn, +} from './singlestorePushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; -import { SingleStoreCredentials } from '../validations/singlestore'; export const mysqlPush = async ( schemaPath: string | string[], diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 3ae05a73b4..62be14b354 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -27,7 +27,11 @@ import { postgresCredentials, printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; -import { printConfigConnectionIssues as printIssuesSingleStore, singlestoreCredentials, SingleStoreCredentials } from '../validations/singlestore'; +import { + printConfigConnectionIssues as printIssuesSingleStore, + SingleStoreCredentials, + singlestoreCredentials, +} from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSqlite, SqliteCredentials, diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index fe7c2083ff..18c9b04a1a 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -10,8 +10,8 @@ import { assertPackages, checkPackage } from './utils'; import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; -import type { SqliteCredentials } from './validations/sqlite'; import { SingleStoreCredentials } from './validations/singlestore'; +import type { SqliteCredentials } from './validations/sqlite'; export const preparePostgresDB = async ( credentials: PostgresCredentials, diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 37e0a68fab..8aa6e3dd72 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -1,14 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ import './@types/utils'; import type { Casing } from './cli/validations/common'; +import { Column, Index, PrimaryKey, SingleStoreSchemaInternal, UniqueConstraint } from './serializer/singlestoreSchema'; import { indexName } from './serializer/singlestoreSerializer'; -import { - Column, - Index, - PrimaryKey, - SingleStoreSchemaInternal, - UniqueConstraint -} from './serializer/singlestoreSchema'; // time precision to fsp // {mode: "string"} for timestamp by default @@ -392,16 +386,15 @@ const column = ( ? `${casing(name)}: timestamp("${name}", ${params})` : `${casing(name)}: timestamp("${name}")`; - - // TODO: check if SingleStore has defaultNow() or now() - defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + // TODO: check if SingleStore has defaultNow() or now() + defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' ? '.defaultNow()' : defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; - - out += defaultValue; - + + out += defaultValue; + // TODO: check if SingleStore has onUpdateNow() let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; out += onUpdateNow; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index e1ed41f586..c099a9a69e 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -3,8 +3,8 @@ import { table } from 'console'; import { warning } from './cli/views'; import { CommonSquashedSchema, Dialect } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; -import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSquasher } from './serializer/sqliteSchema'; import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer'; diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 80a07d6c15..4e5664290b 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -3,8 +3,8 @@ import fs from 'fs'; import { serializeMySql, serializePg, serializeSingleStore, serializeSQLite } from './serializer'; import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; +import { drySingleStore, SingleStoreSchema, singlestoreSchema } from './serializer/singlestoreSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; -import { drySingleStore, singlestoreSchema, SingleStoreSchema } from './serializer/singlestoreSchema'; export const prepareMySqlDbPushSnapshot = async ( prev: MySqlSchema, diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index a414b37d7d..712252f379 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -1,8 +1,8 @@ import { enum as enumType, TypeOf, union } from 'zod'; import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; -import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; +import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; export const dialects = ['postgresql', 'mysql', 'sqlite', 'singlestore'] as const; export const dialect = enumType(dialects); diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 98f7bd5ee0..f275273f40 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -1,7 +1,12 @@ import chalk from 'chalk'; import { getTableName, is } from 'drizzle-orm'; import { SQL } from 'drizzle-orm'; -import { SingleStoreDialect, AnySingleStoreTable, type PrimaryKey as PrimaryKeyORM, uniqueKeyName } from 'drizzle-orm/singlestore-core'; +import { + AnySingleStoreTable, + type PrimaryKey as PrimaryKeyORM, + SingleStoreDialect, + uniqueKeyName, +} from 'drizzle-orm/singlestore-core'; import { getTableConfig } from 'drizzle-orm/singlestore-core'; import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; @@ -9,7 +14,15 @@ import { IntrospectStage, IntrospectStatus } from '../cli/views'; import type { DB } from '../utils'; import { sqlToStr } from '.'; -import { Column, Index, PrimaryKey, SingleStoreKitInternals, SingleStoreSchemaInternal, Table, UniqueConstraint } from './singlestoreSchema'; +import { + Column, + Index, + PrimaryKey, + SingleStoreKitInternals, + SingleStoreSchemaInternal, + Table, + UniqueConstraint, +} from './singlestoreSchema'; // import { SingleStoreColumnWithAutoIncrement } from "drizzle-orm/mysql-core"; // import { SingleStoreDateBaseColumn } from "drizzle-orm/mysql-core"; @@ -561,15 +574,15 @@ export const fromDatabase = async ( }; } } else { - if (typeof tableInResult.indexes[constraintName] !== 'undefined') { - tableInResult.indexes[constraintName]!.columns.push(columnName); - } else { - tableInResult.indexes[constraintName] = { - name: constraintName, - columns: [columnName], - isUnique: isUnique, - }; - } + if (typeof tableInResult.indexes[constraintName] !== 'undefined') { + tableInResult.indexes[constraintName]!.columns.push(columnName); + } else { + tableInResult.indexes[constraintName] = { + name: constraintName, + columns: [columnName], + isUnique: isUnique, + }; + } } } diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index 350e4c9b83..c85950ad75 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -13,10 +13,14 @@ import { Relations, TablesRelationalConfig, } from 'drizzle-orm'; -import { AnyMySqlTable, MySqlTable, getTableConfig as mysqlTableConfig } from 'drizzle-orm/mysql-core'; -import { AnyPgTable, PgTable, getTableConfig as pgTableConfig } from 'drizzle-orm/pg-core'; -import { AnySingleStoreTable, SingleStoreTable, getTableConfig as singlestoreTableConfig} from 'drizzle-orm/singlestore-core'; -import { AnySQLiteTable, SQLiteTable, getTableConfig as sqliteTableConfig } from 'drizzle-orm/sqlite-core'; +import { AnyMySqlTable, getTableConfig as mysqlTableConfig, MySqlTable } from 'drizzle-orm/mysql-core'; +import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-orm/pg-core'; +import { + AnySingleStoreTable, + getTableConfig as singlestoreTableConfig, + SingleStoreTable, +} from 'drizzle-orm/singlestore-core'; +import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; import { cors } from 'hono/cors'; @@ -24,12 +28,12 @@ import { createServer } from 'node:https'; import { assertUnreachable } from 'src/global'; import superjson from 'superjson'; import { z } from 'zod'; -import { prepareFilenames } from '.'; import { safeRegister } from '../cli/commands/utils'; import type { MysqlCredentials } from '../cli/validations/mysql'; import type { PostgresCredentials } from '../cli/validations/postgres'; import type { SingleStoreCredentials } from '../cli/validations/singlestore'; import type { SqliteCredentials } from '../cli/validations/sqlite'; +import { prepareFilenames } from '.'; type CustomDefault = { schema: string; @@ -419,8 +423,7 @@ export const extractRelations = (tablesConfig: { refSchema = undefined; } else if (is(refTable, SingleStoreTable)) { refSchema = singlestoreTableConfig(refTable).schema; - } - else { + } else { throw new Error('unsupported dialect'); } diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index b959e705e5..5b6c782c2d 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -36,12 +36,15 @@ import { JsonStatement, prepareAddCompositePrimaryKeyMySql, prepareAddCompositePrimaryKeyPg, + prepareAddCompositePrimaryKeySingleStore, prepareAddCompositePrimaryKeySqlite, prepareAddUniqueConstraintPg as prepareAddUniqueConstraint, prepareAddValuesToEnumJson, prepareAlterColumnsMysql, + prepareAlterColumnsSingleStore, prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, + prepareAlterCompositePrimaryKeySingleStore, prepareAlterCompositePrimaryKeySqlite, prepareAlterReferencesJson, prepareAlterSequenceJson, @@ -52,6 +55,7 @@ import { prepareCreateSequenceJson, prepareDeleteCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyPg, + prepareDeleteCompositePrimaryKeySingleStore, prepareDeleteCompositePrimaryKeySqlite, prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, @@ -71,20 +75,16 @@ import { prepareRenameSchemasJson, prepareRenameSequenceJson, prepareRenameTableJson, + prepareSingleStoreCreateTableJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, - prepareSingleStoreCreateTableJson, - prepareAddCompositePrimaryKeySingleStore, - prepareDeleteCompositePrimaryKeySingleStore, - prepareAlterCompositePrimaryKeySingleStore, - prepareAlterColumnsSingleStore, } from './jsonStatements'; import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; -import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { PgSchema, PgSchemaSquashed, PgSquasher, sequenceSchema, sequenceSquashed } from './serializer/pgSchema'; +import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { copy, prepareMigrationMeta } from './utils'; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index ba3cb7c785..be1f53bf79 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -48,7 +48,7 @@ import { JsonRenameTableStatement, JsonSqliteAddColumnStatement, JsonSqliteCreateTableStatement, - JsonStatement + JsonStatement, } from './jsonStatements'; import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; @@ -660,7 +660,7 @@ class MySQLAlterTableDropUniqueConstraintConvertor extends Convertor { } convert(statement: JsonDeleteUniqueConstraint): string { const unsquashed = MySqlSquasher.unsquashUnique(statement.data); - + return `ALTER TABLE \`${statement.tableName}\` DROP INDEX \`${unsquashed.name}\`;`; } } @@ -1913,7 +1913,6 @@ class MySqlModifyColumn extends Convertor { } } - class SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1962,7 +1961,6 @@ class SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor extends Convertor } } - class SingleStoreAlterTableAlterColumnSetDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 4c2512a292..58f6a8f642 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -2,8 +2,8 @@ import { PGlite } from '@electric-sql/pglite'; import { Database } from 'better-sqlite3'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; -import { SingleStoreSchema } from 'drizzle-orm/singlestore-core'; import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; +import { SingleStoreSchema } from 'drizzle-orm/singlestore-core'; import { SingleStoreTable } from 'drizzle-orm/singlestore-core'; import { SQLiteTable } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; @@ -29,7 +29,10 @@ import { pgSchema, squashPgScheme } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; import { prepareFromSingleStoreImports } from 'src/serializer/singlestoreImports'; import { singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; -import { fromDatabase as fromSingleStoreDatabase, generateSingleStoreSnapshot } from 'src/serializer/singlestoreSerializer'; +import { + fromDatabase as fromSingleStoreDatabase, + generateSingleStoreSnapshot, +} from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; @@ -904,7 +907,6 @@ export const diffTestSchemasSingleStore = async ( return { sqlStatements, statements }; }; - export const applySingleStoreDiffs = async (sn: SingleStoreSchema) => { const dryRun = { version: '1', diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts index 4000c1bffb..63abf17553 100644 --- a/drizzle-kit/tests/singlestore.test.ts +++ b/drizzle-kit/tests/singlestore.test.ts @@ -1,5 +1,14 @@ import { sql } from 'drizzle-orm'; -import { index, json, singlestoreSchema, singlestoreTable, primaryKey, serial, text, uniqueIndex } from 'drizzle-orm/singlestore-core'; +import { + index, + json, + primaryKey, + serial, + singlestoreSchema, + singlestoreTable, + text, + uniqueIndex, +} from 'drizzle-orm/singlestore-core'; import { expect, test } from 'vitest'; import { diffTestSchemasSingleStore } from './schemaDiffer'; diff --git a/drizzle-kit/tests/validations.test.ts b/drizzle-kit/tests/validations.test.ts index 49dfc832c0..b56603fb45 100644 --- a/drizzle-kit/tests/validations.test.ts +++ b/drizzle-kit/tests/validations.test.ts @@ -1,6 +1,6 @@ import { mysqlCredentials } from 'src/cli/validations/mysql'; -import { singlestoreCredentials } from 'src/cli/validations/singlestore'; import { postgresCredentials } from 'src/cli/validations/postgres'; +import { singlestoreCredentials } from 'src/cli/validations/singlestore'; import { sqliteCredentials } from 'src/cli/validations/sqlite'; import { expect, test } from 'vitest'; From 67c9680e7f5916752bd09c0e2ba5ab6e75b2a035 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Thu, 15 Aug 2024 14:02:24 -0400 Subject: [PATCH 091/152] vector elementType optional --- drizzle-orm/src/singlestore-core/columns/vector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index 033e4115dc..cae2b22059 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -63,7 +63,7 @@ type ElementType = 'I8' | 'I16' | 'I32' | 'I64' | 'F32' | 'F64'; export interface SingleStoreVectorConfig { dimensions: number; - elementType: ElementType; + elementType?: ElementType; } export function vector( From bee314c5e4aebf248f3f745e5543f1a4456fa976 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 20 Aug 2024 13:55:16 +0100 Subject: [PATCH 092/152] define intersectAll and excludeAll sql functions for SingleStore --- .../singlestore-core/query-builders/select.ts | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts index 78cba92e05..a7652412e9 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -494,6 +494,48 @@ export abstract class SingleStoreSelectQueryBuilderBase< */ intersect = this.createSetOperator('intersect', false); + /** + * Adds `intersect all` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets including all duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect-all} + * + * @example + * + * ```ts + * // Select all products and quantities that are ordered by both regular and VIP customers + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders) + * .intersectAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * // or + * import { intersectAll } from 'drizzle-orm/pg-core' + * + * await intersectAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ + intersectAll = this.createSetOperator('intersect', true); + /** * Adds `except` set operator to the query. * @@ -521,6 +563,48 @@ export abstract class SingleStoreSelectQueryBuilderBase< */ except = this.createSetOperator('except', false); + /** + * Adds `except all` set operator to the query. + * + * Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except-all} + * + * @example + * + * ```ts + * // Select all products that are ordered by regular customers but not by VIP customers + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered, + * }) + * .from(regularCustomerOrders) + * .exceptAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered, + * }) + * .from(vipCustomerOrders) + * ); + * // or + * import { exceptAll } from 'drizzle-orm/pg-core' + * + * await exceptAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ + exceptAll = this.createSetOperator('except', true); + /** * Adds `minus` set operator to the query. * @@ -943,7 +1027,9 @@ const getSingleStoreSetOperators = () => ({ union, unionAll, intersect, + intersectAll, except, + exceptAll, minus, }); @@ -1028,6 +1114,48 @@ export const unionAll = createSetOperator('union', true); */ export const intersect = createSetOperator('intersect', false); +/** + * Adds `intersect all` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets including all duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect-all} + * + * @example + * + * ```ts + * // Select all products and quantities that are ordered by both regular and VIP customers + * import { intersectAll } from 'drizzle-orm/mysql-core' + * + * await intersectAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * // or + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders) + * .intersectAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ +export const intersectAll = createSetOperator('intersect', true); + /** * Adds `except` set operator to the query. * @@ -1055,6 +1183,48 @@ export const intersect = createSetOperator('intersect', false); */ export const except = createSetOperator('except', false); +/** + * Adds `except all` set operator to the query. + * + * Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except-all} + * + * @example + * + * ```ts + * // Select all products that are ordered by regular customers but not by VIP customers + * import { exceptAll } from 'drizzle-orm/mysql-core' + * + * await exceptAll( + * db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered + * }) + * .from(regularCustomerOrders), + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered + * }) + * .from(vipCustomerOrders) + * ); + * // or + * await db.select({ + * productId: regularCustomerOrders.productId, + * quantityOrdered: regularCustomerOrders.quantityOrdered, + * }) + * .from(regularCustomerOrders) + * .exceptAll( + * db.select({ + * productId: vipCustomerOrders.productId, + * quantityOrdered: vipCustomerOrders.quantityOrdered, + * }) + * .from(vipCustomerOrders) + * ); + * ``` + */ +export const exceptAll = createSetOperator('except', true); + /** * Adds `minus` set operator to the query. * From 2df01ebc599f61c82e1dffa192eb6f06422dc883 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 20 Aug 2024 14:02:11 +0100 Subject: [PATCH 093/152] created singlestore-proxy from mysql-proxy --- drizzle-orm/src/singlestore-proxy/driver.ts | 54 ++++++ drizzle-orm/src/singlestore-proxy/index.ts | 2 + drizzle-orm/src/singlestore-proxy/migrator.ts | 52 +++++ drizzle-orm/src/singlestore-proxy/session.ts | 178 ++++++++++++++++++ 4 files changed, 286 insertions(+) create mode 100644 drizzle-orm/src/singlestore-proxy/driver.ts create mode 100644 drizzle-orm/src/singlestore-proxy/index.ts create mode 100644 drizzle-orm/src/singlestore-proxy/migrator.ts create mode 100644 drizzle-orm/src/singlestore-proxy/session.ts diff --git a/drizzle-orm/src/singlestore-proxy/driver.ts b/drizzle-orm/src/singlestore-proxy/driver.ts new file mode 100644 index 0000000000..f61040c9f0 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/driver.ts @@ -0,0 +1,54 @@ +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { + type SingleStoreRemotePreparedQueryHKT, + type SingleStoreRemoteQueryResultHKT, + SingleStoreRemoteSession, +} from './session.ts'; + +export type SingleStoreRemoteDatabase< + TSchema extends Record = Record, +> = SingleStoreDatabase; + +export type RemoteCallback = ( + sql: string, + params: any[], + method: 'all' | 'execute', +) => Promise<{ rows: any[]; insertId?: number; affectedRows?: number }>; + +export function drizzle = Record>( + callback: RemoteCallback, + config: DrizzleConfig = {}, +): SingleStoreRemoteDatabase { + const dialect = new SingleStoreDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new SingleStoreRemoteSession(callback, dialect, schema, { logger }); + return new SingleStoreDatabase(dialect, session, schema, 'default') as SingleStoreRemoteDatabase; +} diff --git a/drizzle-orm/src/singlestore-proxy/index.ts b/drizzle-orm/src/singlestore-proxy/index.ts new file mode 100644 index 0000000000..b1b6a52e71 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore-proxy/migrator.ts b/drizzle-orm/src/singlestore-proxy/migrator.ts new file mode 100644 index 0000000000..2ed0172fb3 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/migrator.ts @@ -0,0 +1,52 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SingleStoreRemoteDatabase } from './driver.ts'; + +export type ProxyMigrator = (migrationQueries: string[]) => Promise; + +export async function migrate>( + db: SingleStoreRemoteDatabase, + callback: ProxyMigrator, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await db.execute(migrationTableCreate); + + const dbMigrations = await db.select({ + id: sql.raw('id'), + hash: sql.raw('hash'), + created_at: sql.raw('created_at'), + }).from(sql.identifier(migrationsTable).getSQL()).orderBy( + sql.raw('created_at desc'), + ).limit(1); + + const lastDbMigration = dbMigrations[0]; + + const queriesToRun: string[] = []; + + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + queriesToRun.push( + ...migration.sql, + `insert into ${ + sql.identifier(migrationsTable).value + } (\`hash\`, \`created_at\`) values('${migration.hash}', '${migration.folderMillis}')`, + ); + } + } + + await callback(queriesToRun); +} diff --git a/drizzle-orm/src/singlestore-proxy/session.ts b/drizzle-orm/src/singlestore-proxy/session.ts new file mode 100644 index 0000000000..cf73f7c71c --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/session.ts @@ -0,0 +1,178 @@ +import type { FieldPacket, ResultSetHeader } from 'mysql2/promise'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import { SingleStoreTransaction } from '~/singlestore-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; +import type { + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStorePreparedQueryHKT, + SingleStoreQueryResultHKT, + SingleStoreTransactionConfig, +} from '~/singlestore-core/session.ts'; +import { SingleStorePreparedQuery as PreparedQueryBase, SingleStoreSession } from '~/singlestore-core/session.ts'; +import { fillPlaceholders } from '~/sql/sql.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; +import type { RemoteCallback } from './driver.ts'; + +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; + +export interface SingleStoreRemoteSessionOptions { + logger?: Logger; +} + +export class SingleStoreRemoteSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreSession { + static readonly [entityKind]: string = 'SingleStoreRemoteSession'; + + private logger: Logger; + + constructor( + private client: RemoteCallback, + dialect: SingleStoreDialect, + private schema: RelationalSchemaConfig | undefined, + options: SingleStoreRemoteSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + return new PreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client(querySql.sql, querySql.params, 'all').then(({ rows }) => rows) as Promise; + } + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + _config?: SingleStoreTransactionConfig, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class SingleStoreProxyTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreTransaction< + SingleStoreRemoteQueryResultHKT, + SingleStoreRemotePreparedQueryHKT, + TFullSchema, + TSchema +> { + static readonly [entityKind]: string = 'SingleStoreProxyTransaction'; + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class PreparedQuery extends PreparedQueryBase { + static readonly [entityKind]: string = 'SingleStoreProxyPreparedQuery'; + + constructor( + private client: RemoteCallback, + private queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + const { fields, client, queryString, logger, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + + logger.logQuery(queryString, params); + + if (!fields && !customResultMapper) { + const { rows: data } = await client(queryString, params, 'execute'); + + const insertId = data[0].insertId as number; + const affectedRows = data[0].affectedRows; + + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + + return data; + } + + const { rows } = await client(queryString, params, 'all'); + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + override iterator( + _placeholderValues: Record = {}, + ): AsyncGenerator { + throw new Error('Streaming is not supported by the SingleStore Proxy driver'); + } +} + +export interface SingleStoreRemoteQueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; +} + +export interface SingleStoreRemotePreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: PreparedQuery>; +} From ae78e0489475f9491864e7a72af6108ca0a0b09e Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 20 Aug 2024 15:01:06 +0100 Subject: [PATCH 094/152] add type-tests for SingleStore dialect --- .../type-tests/singlestore/1000columns.ts | 904 ++++++++++++++++++ drizzle-orm/type-tests/singlestore/db.ts | 14 + drizzle-orm/type-tests/singlestore/delete.ts | 61 ++ .../singlestore/generated-columns.ts | 158 +++ drizzle-orm/type-tests/singlestore/insert.ts | 135 +++ drizzle-orm/type-tests/singlestore/select.ts | 606 ++++++++++++ .../type-tests/singlestore/set-operators.ts | 286 ++++++ .../type-tests/singlestore/subquery.ts | 97 ++ drizzle-orm/type-tests/singlestore/tables.ts | 751 +++++++++++++++ drizzle-orm/type-tests/singlestore/update.ts | 26 + drizzle-orm/type-tests/singlestore/with.ts | 80 ++ 11 files changed, 3118 insertions(+) create mode 100644 drizzle-orm/type-tests/singlestore/1000columns.ts create mode 100644 drizzle-orm/type-tests/singlestore/db.ts create mode 100644 drizzle-orm/type-tests/singlestore/delete.ts create mode 100644 drizzle-orm/type-tests/singlestore/generated-columns.ts create mode 100644 drizzle-orm/type-tests/singlestore/insert.ts create mode 100644 drizzle-orm/type-tests/singlestore/select.ts create mode 100644 drizzle-orm/type-tests/singlestore/set-operators.ts create mode 100644 drizzle-orm/type-tests/singlestore/subquery.ts create mode 100644 drizzle-orm/type-tests/singlestore/tables.ts create mode 100644 drizzle-orm/type-tests/singlestore/update.ts create mode 100644 drizzle-orm/type-tests/singlestore/with.ts diff --git a/drizzle-orm/type-tests/singlestore/1000columns.ts b/drizzle-orm/type-tests/singlestore/1000columns.ts new file mode 100644 index 0000000000..f846408581 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/1000columns.ts @@ -0,0 +1,904 @@ +import { bigint, double, singlestoreTable, varchar } from '~/singlestore-core/index.ts'; + +singlestoreTable('test', { + col0: double('col1').primaryKey().autoincrement().default(0), + col1: double('col1').primaryKey().autoincrement().default(0), + col2: double('col1').primaryKey().autoincrement().default(0), + col3: double('col1').primaryKey().autoincrement().default(0), + col4: double('col1').primaryKey().autoincrement().default(0), + col5: double('col1').primaryKey().autoincrement().default(0), + col6: double('col1').primaryKey().autoincrement().default(0), + col8: double('col1').primaryKey().autoincrement().default(0), + col9: double('col1').primaryKey().autoincrement().default(0), + col10: double('col1').primaryKey().autoincrement().default(0), + col11: double('col1').primaryKey().autoincrement().default(0), + col12: double('col1').primaryKey().autoincrement().default(0), + col13: double('col1').primaryKey().autoincrement().default(0), + col14: double('col1').primaryKey().autoincrement().default(0), + col15: double('col1').primaryKey().autoincrement().default(0), + col16: double('col1').primaryKey().autoincrement().default(0), + col18: double('col1').primaryKey().autoincrement().default(0), + col19: double('col1').primaryKey().autoincrement().default(0), + col20: double('col1').primaryKey().autoincrement().default(0), + col21: double('col1').primaryKey().autoincrement().default(0), + col22: double('col1').primaryKey().autoincrement().default(0), + col23: double('col1').primaryKey().autoincrement().default(0), + col24: double('col1').primaryKey().autoincrement().default(0), + col25: double('col1').primaryKey().autoincrement().default(0), + col26: double('col1').primaryKey().autoincrement().default(0), + col28: double('col1').primaryKey().autoincrement().default(0), + col29: double('col1').primaryKey().autoincrement().default(0), + col30: double('col1').primaryKey().autoincrement().default(0), + col31: double('col1').primaryKey().autoincrement().default(0), + col32: double('col1').primaryKey().autoincrement().default(0), + col33: double('col1').primaryKey().autoincrement().default(0), + col34: double('col1').primaryKey().autoincrement().default(0), + col35: double('col1').primaryKey().autoincrement().default(0), + col36: double('col1').primaryKey().autoincrement().default(0), + col38: double('col1').primaryKey().autoincrement().default(0), + col39: double('col1').primaryKey().autoincrement().default(0), + col40: double('col1').primaryKey().autoincrement().default(0), + col41: double('col1').primaryKey().autoincrement().default(0), + col42: double('col1').primaryKey().autoincrement().default(0), + col43: double('col1').primaryKey().autoincrement().default(0), + col44: double('col1').primaryKey().autoincrement().default(0), + col45: double('col1').primaryKey().autoincrement().default(0), + col46: double('col1').primaryKey().autoincrement().default(0), + col48: double('col1').primaryKey().autoincrement().default(0), + col49: double('col1').primaryKey().autoincrement().default(0), + col50: double('col1').primaryKey().autoincrement().default(0), + col51: double('col1').primaryKey().autoincrement().default(0), + col52: double('col1').primaryKey().autoincrement().default(0), + col53: double('col1').primaryKey().autoincrement().default(0), + col54: double('col1').primaryKey().autoincrement().default(0), + col55: double('col1').primaryKey().autoincrement().default(0), + col56: double('col1').primaryKey().autoincrement().default(0), + col58: double('col1').primaryKey().autoincrement().default(0), + col59: double('col1').primaryKey().autoincrement().default(0), + col60: double('col1').primaryKey().autoincrement().default(0), + col61: double('col1').primaryKey().autoincrement().default(0), + col62: double('col1').primaryKey().autoincrement().default(0), + col63: double('col1').primaryKey().autoincrement().default(0), + col64: double('col1').primaryKey().autoincrement().default(0), + col65: double('col1').primaryKey().autoincrement().default(0), + col66: double('col1').primaryKey().autoincrement().default(0), + col68: double('col1').primaryKey().autoincrement().default(0), + col69: double('col1').primaryKey().autoincrement().default(0), + col70: double('col1').primaryKey().autoincrement().default(0), + col71: double('col1').primaryKey().autoincrement().default(0), + col72: double('col1').primaryKey().autoincrement().default(0), + col73: double('col1').primaryKey().autoincrement().default(0), + col74: double('col1').primaryKey().autoincrement().default(0), + col75: double('col1').primaryKey().autoincrement().default(0), + col76: double('col1').primaryKey().autoincrement().default(0), + col78: double('col1').primaryKey().autoincrement().default(0), + col79: double('col1').primaryKey().autoincrement().default(0), + col80: double('col1').primaryKey().autoincrement().default(0), + col81: double('col1').primaryKey().autoincrement().default(0), + col82: double('col1').primaryKey().autoincrement().default(0), + col83: double('col1').primaryKey().autoincrement().default(0), + col84: double('col1').primaryKey().autoincrement().default(0), + col85: double('col1').primaryKey().autoincrement().default(0), + col86: double('col1').primaryKey().autoincrement().default(0), + col88: double('col1').primaryKey().autoincrement().default(0), + col89: double('col1').primaryKey().autoincrement().default(0), + col90: double('col1').primaryKey().autoincrement().default(0), + col91: double('col1').primaryKey().autoincrement().default(0), + col92: double('col1').primaryKey().autoincrement().default(0), + col93: double('col1').primaryKey().autoincrement().default(0), + col94: double('col1').primaryKey().autoincrement().default(0), + col95: double('col1').primaryKey().autoincrement().default(0), + col96: double('col1').primaryKey().autoincrement().default(0), + col98: double('col1').primaryKey().autoincrement().default(0), + col99: double('col1').primaryKey().autoincrement().default(0), + col100: double('col1').primaryKey().autoincrement().default(0), + col101: double('col1').primaryKey().autoincrement().default(0), + col102: double('col1').primaryKey().autoincrement().default(0), + col103: double('col1').primaryKey().autoincrement().default(0), + col104: double('col1').primaryKey().autoincrement().default(0), + col105: double('col1').primaryKey().autoincrement().default(0), + col106: double('col1').primaryKey().autoincrement().default(0), + col108: double('col1').primaryKey().autoincrement().default(0), + col109: double('col1').primaryKey().autoincrement().default(0), + col110: double('col11').primaryKey().autoincrement().default(0), + col111: double('col11').primaryKey().autoincrement().default(0), + col112: double('col11').primaryKey().autoincrement().default(0), + col113: double('col11').primaryKey().autoincrement().default(0), + col114: double('col11').primaryKey().autoincrement().default(0), + col115: double('col11').primaryKey().autoincrement().default(0), + col116: double('col11').primaryKey().autoincrement().default(0), + col118: double('col11').primaryKey().autoincrement().default(0), + col119: double('col11').primaryKey().autoincrement().default(0), + col120: double('col11').primaryKey().autoincrement().default(0), + col121: double('col11').primaryKey().autoincrement().default(0), + col122: double('col11').primaryKey().autoincrement().default(0), + col123: double('col11').primaryKey().autoincrement().default(0), + col124: double('col11').primaryKey().autoincrement().default(0), + col125: double('col11').primaryKey().autoincrement().default(0), + col126: double('col11').primaryKey().autoincrement().default(0), + col128: double('col11').primaryKey().autoincrement().default(0), + col129: double('col11').primaryKey().autoincrement().default(0), + col130: double('col11').primaryKey().autoincrement().default(0), + col131: double('col11').primaryKey().autoincrement().default(0), + col132: double('col11').primaryKey().autoincrement().default(0), + col133: double('col11').primaryKey().autoincrement().default(0), + col134: double('col11').primaryKey().autoincrement().default(0), + col135: double('col11').primaryKey().autoincrement().default(0), + col136: double('col11').primaryKey().autoincrement().default(0), + col138: double('col11').primaryKey().autoincrement().default(0), + col139: double('col11').primaryKey().autoincrement().default(0), + col140: double('col11').primaryKey().autoincrement().default(0), + col141: double('col11').primaryKey().autoincrement().default(0), + col142: double('col11').primaryKey().autoincrement().default(0), + col143: double('col11').primaryKey().autoincrement().default(0), + col144: double('col11').primaryKey().autoincrement().default(0), + col145: double('col11').primaryKey().autoincrement().default(0), + col146: double('col11').primaryKey().autoincrement().default(0), + col148: double('col11').primaryKey().autoincrement().default(0), + col149: double('col11').primaryKey().autoincrement().default(0), + col150: double('col11').primaryKey().autoincrement().default(0), + col151: double('col11').primaryKey().autoincrement().default(0), + col152: double('col11').primaryKey().autoincrement().default(0), + col153: double('col11').primaryKey().autoincrement().default(0), + col154: double('col11').primaryKey().autoincrement().default(0), + col155: double('col11').primaryKey().autoincrement().default(0), + col156: double('col11').primaryKey().autoincrement().default(0), + col158: double('col11').primaryKey().autoincrement().default(0), + col159: double('col11').primaryKey().autoincrement().default(0), + col160: double('col11').primaryKey().autoincrement().default(0), + col161: double('col11').primaryKey().autoincrement().default(0), + col162: double('col11').primaryKey().autoincrement().default(0), + col163: double('col11').primaryKey().autoincrement().default(0), + col164: double('col11').primaryKey().autoincrement().default(0), + col165: double('col11').primaryKey().autoincrement().default(0), + col166: double('col11').primaryKey().autoincrement().default(0), + col168: double('col11').primaryKey().autoincrement().default(0), + col169: double('col11').primaryKey().autoincrement().default(0), + col170: double('col11').primaryKey().autoincrement().default(0), + col171: double('col11').primaryKey().autoincrement().default(0), + col172: double('col11').primaryKey().autoincrement().default(0), + col173: double('col11').primaryKey().autoincrement().default(0), + col174: double('col11').primaryKey().autoincrement().default(0), + col175: double('col11').primaryKey().autoincrement().default(0), + col176: double('col11').primaryKey().autoincrement().default(0), + col178: double('col11').primaryKey().autoincrement().default(0), + col179: double('col11').primaryKey().autoincrement().default(0), + col180: double('col11').primaryKey().autoincrement().default(0), + col181: double('col11').primaryKey().autoincrement().default(0), + col182: double('col11').primaryKey().autoincrement().default(0), + col183: double('col11').primaryKey().autoincrement().default(0), + col184: double('col11').primaryKey().autoincrement().default(0), + col185: double('col11').primaryKey().autoincrement().default(0), + col186: double('col11').primaryKey().autoincrement().default(0), + col188: double('col11').primaryKey().autoincrement().default(0), + col189: double('col11').primaryKey().autoincrement().default(0), + col190: double('col11').primaryKey().autoincrement().default(0), + col191: double('col11').primaryKey().autoincrement().default(0), + col192: double('col11').primaryKey().autoincrement().default(0), + col193: double('col11').primaryKey().autoincrement().default(0), + col194: double('col11').primaryKey().autoincrement().default(0), + col195: double('col11').primaryKey().autoincrement().default(0), + col196: double('col11').primaryKey().autoincrement().default(0), + col198: double('col11').primaryKey().autoincrement().default(0), + col199: double('col11').primaryKey().autoincrement().default(0), + col200: double('col2').primaryKey().autoincrement().default(0), + col201: double('col2').primaryKey().autoincrement().default(0), + col202: double('col2').primaryKey().autoincrement().default(0), + col203: double('col2').primaryKey().autoincrement().default(0), + col204: double('col2').primaryKey().autoincrement().default(0), + col205: double('col2').primaryKey().autoincrement().default(0), + col206: double('col2').primaryKey().autoincrement().default(0), + col208: double('col2').primaryKey().autoincrement().default(0), + col209: double('col2').primaryKey().autoincrement().default(0), + col210: double('col21').primaryKey().autoincrement().default(0), + col211: double('col21').primaryKey().autoincrement().default(0), + col212: double('col21').primaryKey().autoincrement().default(0), + col213: double('col21').primaryKey().autoincrement().default(0), + col214: double('col21').primaryKey().autoincrement().default(0), + col215: double('col21').primaryKey().autoincrement().default(0), + col216: double('col21').primaryKey().autoincrement().default(0), + col218: double('col21').primaryKey().autoincrement().default(0), + col219: double('col21').primaryKey().autoincrement().default(0), + col220: double('col21').primaryKey().autoincrement().default(0), + col221: double('col21').primaryKey().autoincrement().default(0), + col222: double('col21').primaryKey().autoincrement().default(0), + col223: double('col21').primaryKey().autoincrement().default(0), + col224: double('col21').primaryKey().autoincrement().default(0), + col225: double('col21').primaryKey().autoincrement().default(0), + col226: double('col21').primaryKey().autoincrement().default(0), + col228: double('col21').primaryKey().autoincrement().default(0), + col229: double('col21').primaryKey().autoincrement().default(0), + col230: double('col21').primaryKey().autoincrement().default(0), + col231: double('col21').primaryKey().autoincrement().default(0), + col232: double('col21').primaryKey().autoincrement().default(0), + col233: double('col21').primaryKey().autoincrement().default(0), + col234: double('col21').primaryKey().autoincrement().default(0), + col235: double('col21').primaryKey().autoincrement().default(0), + col236: double('col21').primaryKey().autoincrement().default(0), + col238: double('col21').primaryKey().autoincrement().default(0), + col239: double('col21').primaryKey().autoincrement().default(0), + col240: double('col21').primaryKey().autoincrement().default(0), + col241: double('col21').primaryKey().autoincrement().default(0), + col242: double('col21').primaryKey().autoincrement().default(0), + col243: double('col21').primaryKey().autoincrement().default(0), + col244: double('col21').primaryKey().autoincrement().default(0), + col245: double('col21').primaryKey().autoincrement().default(0), + col246: double('col21').primaryKey().autoincrement().default(0), + col248: double('col21').primaryKey().autoincrement().default(0), + col249: double('col21').primaryKey().autoincrement().default(0), + col250: double('col21').primaryKey().autoincrement().default(0), + col251: double('col21').primaryKey().autoincrement().default(0), + col252: double('col21').primaryKey().autoincrement().default(0), + col253: double('col21').primaryKey().autoincrement().default(0), + col254: double('col21').primaryKey().autoincrement().default(0), + col255: double('col21').primaryKey().autoincrement().default(0), + col256: double('col21').primaryKey().autoincrement().default(0), + col258: double('col21').primaryKey().autoincrement().default(0), + col259: double('col21').primaryKey().autoincrement().default(0), + col260: double('col21').primaryKey().autoincrement().default(0), + col261: double('col21').primaryKey().autoincrement().default(0), + col262: double('col21').primaryKey().autoincrement().default(0), + col263: double('col21').primaryKey().autoincrement().default(0), + col264: double('col21').primaryKey().autoincrement().default(0), + col265: double('col21').primaryKey().autoincrement().default(0), + col266: double('col21').primaryKey().autoincrement().default(0), + col268: double('col21').primaryKey().autoincrement().default(0), + col269: double('col21').primaryKey().autoincrement().default(0), + col270: double('col21').primaryKey().autoincrement().default(0), + col271: double('col21').primaryKey().autoincrement().default(0), + col272: double('col21').primaryKey().autoincrement().default(0), + col273: double('col21').primaryKey().autoincrement().default(0), + col274: double('col21').primaryKey().autoincrement().default(0), + col275: double('col21').primaryKey().autoincrement().default(0), + col276: double('col21').primaryKey().autoincrement().default(0), + col278: double('col21').primaryKey().autoincrement().default(0), + col279: double('col21').primaryKey().autoincrement().default(0), + col280: double('col21').primaryKey().autoincrement().default(0), + col281: double('col21').primaryKey().autoincrement().default(0), + col282: double('col21').primaryKey().autoincrement().default(0), + col283: double('col21').primaryKey().autoincrement().default(0), + col284: double('col21').primaryKey().autoincrement().default(0), + col285: double('col21').primaryKey().autoincrement().default(0), + col286: double('col21').primaryKey().autoincrement().default(0), + col288: double('col21').primaryKey().autoincrement().default(0), + col289: double('col21').primaryKey().autoincrement().default(0), + col290: double('col21').primaryKey().autoincrement().default(0), + col291: double('col21').primaryKey().autoincrement().default(0), + col292: double('col21').primaryKey().autoincrement().default(0), + col293: double('col21').primaryKey().autoincrement().default(0), + col294: double('col21').primaryKey().autoincrement().default(0), + col295: double('col21').primaryKey().autoincrement().default(0), + col296: double('col21').primaryKey().autoincrement().default(0), + col298: double('col21').primaryKey().autoincrement().default(0), + col299: double('col21').primaryKey().autoincrement().default(0), + col300: double('col3').primaryKey().autoincrement().default(0), + col301: double('col3').primaryKey().autoincrement().default(0), + col302: double('col3').primaryKey().autoincrement().default(0), + col303: double('col3').primaryKey().autoincrement().default(0), + col304: double('col3').primaryKey().autoincrement().default(0), + col305: double('col3').primaryKey().autoincrement().default(0), + col306: double('col3').primaryKey().autoincrement().default(0), + col308: double('col3').primaryKey().autoincrement().default(0), + col309: double('col3').primaryKey().autoincrement().default(0), + col310: double('col31').primaryKey().autoincrement().default(0), + col311: double('col31').primaryKey().autoincrement().default(0), + col312: double('col31').primaryKey().autoincrement().default(0), + col313: double('col31').primaryKey().autoincrement().default(0), + col314: double('col31').primaryKey().autoincrement().default(0), + col315: double('col31').primaryKey().autoincrement().default(0), + col316: double('col31').primaryKey().autoincrement().default(0), + col318: double('col31').primaryKey().autoincrement().default(0), + col319: double('col31').primaryKey().autoincrement().default(0), + col320: double('col31').primaryKey().autoincrement().default(0), + col321: double('col31').primaryKey().autoincrement().default(0), + col322: double('col31').primaryKey().autoincrement().default(0), + col323: double('col31').primaryKey().autoincrement().default(0), + col324: double('col31').primaryKey().autoincrement().default(0), + col325: double('col31').primaryKey().autoincrement().default(0), + col326: double('col31').primaryKey().autoincrement().default(0), + col328: double('col31').primaryKey().autoincrement().default(0), + col329: double('col31').primaryKey().autoincrement().default(0), + col330: double('col31').primaryKey().autoincrement().default(0), + col331: double('col31').primaryKey().autoincrement().default(0), + col332: double('col31').primaryKey().autoincrement().default(0), + col333: double('col31').primaryKey().autoincrement().default(0), + col334: double('col31').primaryKey().autoincrement().default(0), + col335: double('col31').primaryKey().autoincrement().default(0), + col336: double('col31').primaryKey().autoincrement().default(0), + col338: double('col31').primaryKey().autoincrement().default(0), + col339: double('col31').primaryKey().autoincrement().default(0), + col340: double('col31').primaryKey().autoincrement().default(0), + col341: double('col31').primaryKey().autoincrement().default(0), + col342: double('col31').primaryKey().autoincrement().default(0), + col343: double('col31').primaryKey().autoincrement().default(0), + col344: double('col31').primaryKey().autoincrement().default(0), + col345: double('col31').primaryKey().autoincrement().default(0), + col346: double('col31').primaryKey().autoincrement().default(0), + col348: double('col31').primaryKey().autoincrement().default(0), + col349: double('col31').primaryKey().autoincrement().default(0), + col350: double('col31').primaryKey().autoincrement().default(0), + col351: double('col31').primaryKey().autoincrement().default(0), + col352: double('col31').primaryKey().autoincrement().default(0), + col353: double('col31').primaryKey().autoincrement().default(0), + col354: double('col31').primaryKey().autoincrement().default(0), + col355: double('col31').primaryKey().autoincrement().default(0), + col356: double('col31').primaryKey().autoincrement().default(0), + col358: double('col31').primaryKey().autoincrement().default(0), + col359: double('col31').primaryKey().autoincrement().default(0), + col360: double('col31').primaryKey().autoincrement().default(0), + col361: double('col31').primaryKey().autoincrement().default(0), + col362: double('col31').primaryKey().autoincrement().default(0), + col363: double('col31').primaryKey().autoincrement().default(0), + col364: double('col31').primaryKey().autoincrement().default(0), + col365: double('col31').primaryKey().autoincrement().default(0), + col366: double('col31').primaryKey().autoincrement().default(0), + col368: double('col31').primaryKey().autoincrement().default(0), + col369: double('col31').primaryKey().autoincrement().default(0), + col370: double('col31').primaryKey().autoincrement().default(0), + col371: double('col31').primaryKey().autoincrement().default(0), + col372: double('col31').primaryKey().autoincrement().default(0), + col373: double('col31').primaryKey().autoincrement().default(0), + col374: double('col31').primaryKey().autoincrement().default(0), + col375: double('col31').primaryKey().autoincrement().default(0), + col376: double('col31').primaryKey().autoincrement().default(0), + col378: double('col31').primaryKey().autoincrement().default(0), + col379: double('col31').primaryKey().autoincrement().default(0), + col380: double('col31').primaryKey().autoincrement().default(0), + col381: double('col31').primaryKey().autoincrement().default(0), + col382: double('col31').primaryKey().autoincrement().default(0), + col383: double('col31').primaryKey().autoincrement().default(0), + col384: double('col31').primaryKey().autoincrement().default(0), + col385: double('col31').primaryKey().autoincrement().default(0), + col386: double('col31').primaryKey().autoincrement().default(0), + col388: double('col31').primaryKey().autoincrement().default(0), + col389: double('col31').primaryKey().autoincrement().default(0), + col390: double('col31').primaryKey().autoincrement().default(0), + col391: double('col31').primaryKey().autoincrement().default(0), + col392: double('col31').primaryKey().autoincrement().default(0), + col393: double('col31').primaryKey().autoincrement().default(0), + col394: double('col31').primaryKey().autoincrement().default(0), + col395: double('col31').primaryKey().autoincrement().default(0), + col396: double('col31').primaryKey().autoincrement().default(0), + col398: double('col31').primaryKey().autoincrement().default(0), + col399: double('col31').primaryKey().autoincrement().default(0), + col400: double('col4').primaryKey().autoincrement().default(0), + col401: double('col4').primaryKey().autoincrement().default(0), + col402: double('col4').primaryKey().autoincrement().default(0), + col403: double('col4').primaryKey().autoincrement().default(0), + col404: double('col4').primaryKey().autoincrement().default(0), + col405: double('col4').primaryKey().autoincrement().default(0), + col406: double('col4').primaryKey().autoincrement().default(0), + col408: double('col4').primaryKey().autoincrement().default(0), + col409: double('col4').primaryKey().autoincrement().default(0), + col410: double('col41').primaryKey().autoincrement().default(0), + col411: double('col41').primaryKey().autoincrement().default(0), + col412: double('col41').primaryKey().autoincrement().default(0), + col413: double('col41').primaryKey().autoincrement().default(0), + col414: double('col41').primaryKey().autoincrement().default(0), + col415: double('col41').primaryKey().autoincrement().default(0), + col416: double('col41').primaryKey().autoincrement().default(0), + col418: double('col41').primaryKey().autoincrement().default(0), + col419: double('col41').primaryKey().autoincrement().default(0), + col420: double('col41').primaryKey().autoincrement().default(0), + col421: double('col41').primaryKey().autoincrement().default(0), + col422: double('col41').primaryKey().autoincrement().default(0), + col423: double('col41').primaryKey().autoincrement().default(0), + col424: double('col41').primaryKey().autoincrement().default(0), + col425: double('col41').primaryKey().autoincrement().default(0), + col426: double('col41').primaryKey().autoincrement().default(0), + col428: double('col41').primaryKey().autoincrement().default(0), + col429: double('col41').primaryKey().autoincrement().default(0), + col430: double('col41').primaryKey().autoincrement().default(0), + col431: double('col41').primaryKey().autoincrement().default(0), + col432: double('col41').primaryKey().autoincrement().default(0), + col433: double('col41').primaryKey().autoincrement().default(0), + col434: double('col41').primaryKey().autoincrement().default(0), + col435: double('col41').primaryKey().autoincrement().default(0), + col436: double('col41').primaryKey().autoincrement().default(0), + col438: double('col41').primaryKey().autoincrement().default(0), + col439: double('col41').primaryKey().autoincrement().default(0), + col440: double('col41').primaryKey().autoincrement().default(0), + col441: double('col41').primaryKey().autoincrement().default(0), + col442: double('col41').primaryKey().autoincrement().default(0), + col443: double('col41').primaryKey().autoincrement().default(0), + col444: double('col41').primaryKey().autoincrement().default(0), + col445: double('col41').primaryKey().autoincrement().default(0), + col446: double('col41').primaryKey().autoincrement().default(0), + col448: double('col41').primaryKey().autoincrement().default(0), + col449: double('col41').primaryKey().autoincrement().default(0), + col450: double('col41').primaryKey().autoincrement().default(0), + col451: double('col41').primaryKey().autoincrement().default(0), + col452: double('col41').primaryKey().autoincrement().default(0), + col453: double('col41').primaryKey().autoincrement().default(0), + col454: double('col41').primaryKey().autoincrement().default(0), + col455: double('col41').primaryKey().autoincrement().default(0), + col456: double('col41').primaryKey().autoincrement().default(0), + col458: double('col41').primaryKey().autoincrement().default(0), + col459: double('col41').primaryKey().autoincrement().default(0), + col460: double('col41').primaryKey().autoincrement().default(0), + col461: double('col41').primaryKey().autoincrement().default(0), + col462: double('col41').primaryKey().autoincrement().default(0), + col463: double('col41').primaryKey().autoincrement().default(0), + col464: double('col41').primaryKey().autoincrement().default(0), + col465: double('col41').primaryKey().autoincrement().default(0), + col466: double('col41').primaryKey().autoincrement().default(0), + col468: double('col41').primaryKey().autoincrement().default(0), + col469: double('col41').primaryKey().autoincrement().default(0), + col470: double('col41').primaryKey().autoincrement().default(0), + col471: double('col41').primaryKey().autoincrement().default(0), + col472: double('col41').primaryKey().autoincrement().default(0), + col473: double('col41').primaryKey().autoincrement().default(0), + col474: double('col41').primaryKey().autoincrement().default(0), + col475: double('col41').primaryKey().autoincrement().default(0), + col476: double('col41').primaryKey().autoincrement().default(0), + col478: double('col41').primaryKey().autoincrement().default(0), + col479: double('col41').primaryKey().autoincrement().default(0), + col480: double('col41').primaryKey().autoincrement().default(0), + col481: double('col41').primaryKey().autoincrement().default(0), + col482: double('col41').primaryKey().autoincrement().default(0), + col483: double('col41').primaryKey().autoincrement().default(0), + col484: double('col41').primaryKey().autoincrement().default(0), + col485: double('col41').primaryKey().autoincrement().default(0), + col486: double('col41').primaryKey().autoincrement().default(0), + col488: double('col41').primaryKey().autoincrement().default(0), + col489: double('col41').primaryKey().autoincrement().default(0), + col490: double('col41').primaryKey().autoincrement().default(0), + col491: double('col41').primaryKey().autoincrement().default(0), + col492: double('col41').primaryKey().autoincrement().default(0), + col493: double('col41').primaryKey().autoincrement().default(0), + col494: double('col41').primaryKey().autoincrement().default(0), + col495: double('col41').primaryKey().autoincrement().default(0), + col496: double('col41').primaryKey().autoincrement().default(0), + col498: double('col41').primaryKey().autoincrement().default(0), + col499: double('col41').primaryKey().autoincrement().default(0), + col500: double('col5').primaryKey().autoincrement().default(0), + col501: double('col5').primaryKey().autoincrement().default(0), + col502: double('col5').primaryKey().autoincrement().default(0), + col503: double('col5').primaryKey().autoincrement().default(0), + col504: double('col5').primaryKey().autoincrement().default(0), + col505: double('col5').primaryKey().autoincrement().default(0), + col506: double('col5').primaryKey().autoincrement().default(0), + col508: double('col5').primaryKey().autoincrement().default(0), + col509: double('col5').primaryKey().autoincrement().default(0), + col510: double('col51').primaryKey().autoincrement().default(0), + col511: double('col51').primaryKey().autoincrement().default(0), + col512: double('col51').primaryKey().autoincrement().default(0), + col513: double('col51').primaryKey().autoincrement().default(0), + col514: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col515: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col516: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col518: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col519: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col520: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col521: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col522: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col523: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col524: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col525: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col526: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col528: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col529: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col530: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col531: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col532: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col533: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col534: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col535: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col536: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col538: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col539: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col540: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col541: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col542: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col543: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col544: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col545: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col546: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col548: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col549: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col550: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col551: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col552: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col553: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col554: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col555: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col556: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col558: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col559: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col560: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col561: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col562: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col563: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col564: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col565: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col566: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col568: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col569: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col570: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col571: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col572: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col573: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col574: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col575: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col576: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col578: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col579: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col580: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col581: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col582: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col583: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col584: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col585: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col586: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col588: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col589: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col590: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col591: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col592: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col593: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col594: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col595: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col596: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col598: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col599: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col600: bigint('col6', { mode: 'number' }).primaryKey().autoincrement().default(0), + col601: double('col6').primaryKey().autoincrement().default(0), + col602: double('col6').primaryKey().autoincrement().default(0), + col603: double('col6').primaryKey().autoincrement().default(0), + col604: double('col6').primaryKey().autoincrement().default(0), + col605: double('col6').primaryKey().autoincrement().default(0), + col606: double('col6').primaryKey().autoincrement().default(0), + col608: double('col6').primaryKey().autoincrement().default(0), + col609: double('col6').primaryKey().autoincrement().default(0), + col610: double('col61').primaryKey().autoincrement().default(0), + col611: double('col61').primaryKey().autoincrement().default(0), + col612: double('col61').primaryKey().autoincrement().default(0), + col613: double('col61').primaryKey().autoincrement().default(0), + col614: double('col61').primaryKey().autoincrement().default(0), + col615: double('col61').primaryKey().autoincrement().default(0), + col616: double('col61').primaryKey().autoincrement().default(0), + col618: double('col61').primaryKey().autoincrement().default(0), + col619: double('col61').primaryKey().autoincrement().default(0), + col620: double('col61').primaryKey().autoincrement().default(0), + col621: double('col61').primaryKey().autoincrement().default(0), + col622: double('col61').primaryKey().autoincrement().default(0), + col623: double('col61').primaryKey().autoincrement().default(0), + col624: double('col61').primaryKey().autoincrement().default(0), + col625: double('col61').primaryKey().autoincrement().default(0), + col626: double('col61').primaryKey().autoincrement().default(0), + col628: double('col61').primaryKey().autoincrement().default(0), + col629: double('col61').primaryKey().autoincrement().default(0), + col630: double('col61').primaryKey().autoincrement().default(0), + col631: double('col61').primaryKey().autoincrement().default(0), + col632: double('col61').primaryKey().autoincrement().default(0), + col633: double('col61').primaryKey().autoincrement().default(0), + col634: double('col61').primaryKey().autoincrement().default(0), + col635: double('col61').primaryKey().autoincrement().default(0), + col636: double('col61').primaryKey().autoincrement().default(0), + col638: double('col61').primaryKey().autoincrement().default(0), + col639: double('col61').primaryKey().autoincrement().default(0), + col640: double('col61').primaryKey().autoincrement().default(0), + col641: double('col61').primaryKey().autoincrement().default(0), + col642: double('col61').primaryKey().autoincrement().default(0), + col643: double('col61').primaryKey().autoincrement().default(0), + col644: double('col61').primaryKey().autoincrement().default(0), + col645: double('col61').primaryKey().autoincrement().default(0), + col646: double('col61').primaryKey().autoincrement().default(0), + col648: double('col61').primaryKey().autoincrement().default(0), + col649: double('col61').primaryKey().autoincrement().default(0), + col650: double('col61').primaryKey().autoincrement().default(0), + col651: double('col61').primaryKey().autoincrement().default(0), + col652: double('col61').primaryKey().autoincrement().default(0), + col653: double('col61').primaryKey().autoincrement().default(0), + col654: double('col61').primaryKey().autoincrement().default(0), + col655: double('col61').primaryKey().autoincrement().default(0), + col656: double('col61').primaryKey().autoincrement().default(0), + col658: double('col61').primaryKey().autoincrement().default(0), + col659: double('col61').primaryKey().autoincrement().default(0), + col660: double('col61').primaryKey().autoincrement().default(0), + col661: double('col61').primaryKey().autoincrement().default(0), + col662: double('col61').primaryKey().autoincrement().default(0), + col663: double('col61').primaryKey().autoincrement().default(0), + col664: double('col61').primaryKey().autoincrement().default(0), + col665: double('col61').primaryKey().autoincrement().default(0), + col666: double('col61').primaryKey().autoincrement().default(0), + col668: double('col61').primaryKey().autoincrement().default(0), + col669: double('col61').primaryKey().autoincrement().default(0), + col670: double('col61').primaryKey().autoincrement().default(0), + col671: double('col61').primaryKey().autoincrement().default(0), + col672: double('col61').primaryKey().autoincrement().default(0), + col673: double('col61').primaryKey().autoincrement().default(0), + col674: double('col61').primaryKey().autoincrement().default(0), + col675: double('col61').primaryKey().autoincrement().default(0), + col676: double('col61').primaryKey().autoincrement().default(0), + col678: double('col61').primaryKey().autoincrement().default(0), + col679: double('col61').primaryKey().autoincrement().default(0), + col680: double('col61').primaryKey().autoincrement().default(0), + col681: double('col61').primaryKey().autoincrement().default(0), + col682: double('col61').primaryKey().autoincrement().default(0), + col683: double('col61').primaryKey().autoincrement().default(0), + col684: double('col61').primaryKey().autoincrement().default(0), + col685: double('col61').primaryKey().autoincrement().default(0), + col686: double('col61').primaryKey().autoincrement().default(0), + col688: double('col61').primaryKey().autoincrement().default(0), + col689: double('col61').primaryKey().autoincrement().default(0), + col690: double('col61').primaryKey().autoincrement().default(0), + col691: double('col61').primaryKey().autoincrement().default(0), + col692: double('col61').primaryKey().autoincrement().default(0), + col693: double('col61').primaryKey().autoincrement().default(0), + col694: double('col61').primaryKey().autoincrement().default(0), + col695: double('col61').primaryKey().autoincrement().default(0), + col696: double('col61').primaryKey().autoincrement().default(0), + col698: double('col61').primaryKey().autoincrement().default(0), + col699: double('col61').primaryKey().autoincrement().default(0), + col700: double('col7').primaryKey().autoincrement().default(0), + col701: double('col7').primaryKey().autoincrement().default(0), + col702: double('col7').primaryKey().autoincrement().default(0), + col703: double('col7').primaryKey().autoincrement().default(0), + col704: double('col7').primaryKey().autoincrement().default(0), + col705: double('col7').primaryKey().autoincrement().default(0), + col706: double('col7').primaryKey().autoincrement().default(0), + col708: double('col7').primaryKey().autoincrement().default(0), + col709: double('col7').primaryKey().autoincrement().default(0), + col710: double('col71').primaryKey().autoincrement().default(0), + col711: double('col71').primaryKey().autoincrement().default(0), + col712: double('col71').primaryKey().autoincrement().default(0), + col713: double('col71').primaryKey().autoincrement().default(0), + col714: double('col71').primaryKey().autoincrement().default(0), + col715: double('col71').primaryKey().autoincrement().default(0), + col716: double('col71').primaryKey().autoincrement().default(0), + col718: double('col71').primaryKey().autoincrement().default(0), + col719: double('col71').primaryKey().autoincrement().default(0), + col720: double('col71').primaryKey().autoincrement().default(0), + col721: double('col71').primaryKey().autoincrement().default(0), + col722: double('col71').primaryKey().autoincrement().default(0), + col723: double('col71').primaryKey().autoincrement().default(0), + col724: double('col71').primaryKey().autoincrement().default(0), + col725: double('col71').primaryKey().autoincrement().default(0), + col726: double('col71').primaryKey().autoincrement().default(0), + col728: double('col71').primaryKey().autoincrement().default(0), + col729: double('col71').primaryKey().autoincrement().default(0), + col730: double('col71').primaryKey().autoincrement().default(0), + col731: double('col71').primaryKey().autoincrement().default(0), + col732: double('col71').primaryKey().autoincrement().default(0), + col733: double('col71').primaryKey().autoincrement().default(0), + col734: double('col71').primaryKey().autoincrement().default(0), + col735: double('col71').primaryKey().autoincrement().default(0), + col736: double('col71').primaryKey().autoincrement().default(0), + col738: double('col71').primaryKey().autoincrement().default(0), + col739: double('col71').primaryKey().autoincrement().default(0), + col740: double('col71').primaryKey().autoincrement().default(0), + col741: double('col71').primaryKey().autoincrement().default(0), + col742: double('col71').primaryKey().autoincrement().default(0), + col743: double('col71').primaryKey().autoincrement().default(0), + col744: double('col71').primaryKey().autoincrement().default(0), + col745: double('col71').primaryKey().autoincrement().default(0), + col746: double('col71').primaryKey().autoincrement().default(0), + col748: double('col71').primaryKey().autoincrement().default(0), + col749: double('col71').primaryKey().autoincrement().default(0), + col750: double('col71').primaryKey().autoincrement().default(0), + col751: double('col71').primaryKey().autoincrement().default(0), + col752: double('col71').primaryKey().autoincrement().default(0), + col753: double('col71').primaryKey().autoincrement().default(0), + col754: double('col71').primaryKey().autoincrement().default(0), + col755: double('col71').primaryKey().autoincrement().default(0), + col756: double('col71').primaryKey().autoincrement().default(0), + col758: double('col71').primaryKey().autoincrement().default(0), + col759: double('col71').primaryKey().autoincrement().default(0), + col760: double('col71').primaryKey().autoincrement().default(0), + col761: double('col71').primaryKey().autoincrement().default(0), + col762: double('col71').primaryKey().autoincrement().default(0), + col763: double('col71').primaryKey().autoincrement().default(0), + col764: double('col71').primaryKey().autoincrement().default(0), + col765: double('col71').primaryKey().autoincrement().default(0), + col766: double('col71').primaryKey().autoincrement().default(0), + col768: double('col71').primaryKey().autoincrement().default(0), + col769: double('col71').primaryKey().autoincrement().default(0), + col770: double('col71').primaryKey().autoincrement().default(0), + col771: double('col71').primaryKey().autoincrement().default(0), + col772: double('col71').primaryKey().autoincrement().default(0), + col773: double('col71').primaryKey().autoincrement().default(0), + col774: double('col71').primaryKey().autoincrement().default(0), + col775: double('col71').primaryKey().autoincrement().default(0), + col776: double('col71').primaryKey().autoincrement().default(0), + col778: double('col71').primaryKey().autoincrement().default(0), + col779: double('col71').primaryKey().autoincrement().default(0), + col780: double('col71').primaryKey().autoincrement().default(0), + col781: double('col71').primaryKey().autoincrement().default(0), + col782: double('col71').primaryKey().autoincrement().default(0), + col783: double('col71').primaryKey().autoincrement().default(0), + col784: double('col71').primaryKey().autoincrement().default(0), + col785: double('col71').primaryKey().autoincrement().default(0), + col786: double('col71').primaryKey().autoincrement().default(0), + col788: double('col71').primaryKey().autoincrement().default(0), + col789: double('col71').primaryKey().autoincrement().default(0), + col790: double('col71').primaryKey().autoincrement().default(0), + col791: double('col71').primaryKey().autoincrement().default(0), + col792: double('col71').primaryKey().autoincrement().default(0), + col793: double('col71').primaryKey().autoincrement().default(0), + col794: double('col71').primaryKey().autoincrement().default(0), + col795: double('col71').primaryKey().autoincrement().default(0), + col796: double('col71').primaryKey().autoincrement().default(0), + col798: double('col71').primaryKey().autoincrement().default(0), + col799: double('col71').primaryKey().autoincrement().default(0), + col800: double('col8').primaryKey().autoincrement().default(0), + col801: double('col8').primaryKey().autoincrement().default(0), + col802: double('col8').primaryKey().autoincrement().default(0), + col803: double('col8').primaryKey().autoincrement().default(0), + col804: double('col8').primaryKey().autoincrement().default(0), + col805: double('col8').primaryKey().autoincrement().default(0), + col806: double('col8').primaryKey().autoincrement().default(0), + col808: double('col8').primaryKey().autoincrement().default(0), + col809: double('col8').primaryKey().autoincrement().default(0), + col810: double('col81').primaryKey().autoincrement().default(0), + col811: double('col81').primaryKey().autoincrement().default(0), + col812: double('col81').primaryKey().autoincrement().default(0), + col813: double('col81').primaryKey().autoincrement().default(0), + col814: double('col81').primaryKey().autoincrement().default(0), + col815: double('col81').primaryKey().autoincrement().default(0), + col816: double('col81').primaryKey().autoincrement().default(0), + col818: double('col81').primaryKey().autoincrement().default(0), + col819: double('col81').primaryKey().autoincrement().default(0), + col820: double('col81').primaryKey().autoincrement().default(0), + col821: double('col81').primaryKey().autoincrement().default(0), + col822: double('col81').primaryKey().autoincrement().default(0), + col823: double('col81').primaryKey().autoincrement().default(0), + col824: double('col81').primaryKey().autoincrement().default(0), + col825: double('col81').primaryKey().autoincrement().default(0), + col826: double('col81').primaryKey().autoincrement().default(0), + col828: double('col81').primaryKey().autoincrement().default(0), + col829: double('col81').primaryKey().autoincrement().default(0), + col830: double('col81').primaryKey().autoincrement().default(0), + col831: double('col81').primaryKey().autoincrement().default(0), + col832: double('col81').primaryKey().autoincrement().default(0), + col833: double('col81').primaryKey().autoincrement().default(0), + col834: double('col81').primaryKey().autoincrement().default(0), + col835: double('col81').primaryKey().autoincrement().default(0), + col836: double('col81').primaryKey().autoincrement().default(0), + col838: double('col81').primaryKey().autoincrement().default(0), + col839: double('col81').primaryKey().autoincrement().default(0), + col840: double('col81').primaryKey().autoincrement().default(0), + col841: double('col81').primaryKey().autoincrement().default(0), + col842: double('col81').primaryKey().autoincrement().default(0), + col843: double('col81').primaryKey().autoincrement().default(0), + col844: double('col81').primaryKey().autoincrement().default(0), + col845: double('col81').primaryKey().autoincrement().default(0), + col846: double('col81').primaryKey().autoincrement().default(0), + col848: double('col81').primaryKey().autoincrement().default(0), + col849: double('col81').primaryKey().autoincrement().default(0), + col850: double('col81').primaryKey().autoincrement().default(0), + col851: double('col81').primaryKey().autoincrement().default(0), + col852: double('col81').primaryKey().autoincrement().default(0), + col853: double('col81').primaryKey().autoincrement().default(0), + col854: double('col81').primaryKey().autoincrement().default(0), + col855: double('col81').primaryKey().autoincrement().default(0), + col856: double('col81').primaryKey().autoincrement().default(0), + col858: double('col81').primaryKey().autoincrement().default(0), + col859: double('col81').primaryKey().autoincrement().default(0), + col860: double('col81').primaryKey().autoincrement().default(0), + col861: double('col81').primaryKey().autoincrement().default(0), + col862: double('col81').primaryKey().autoincrement().default(0), + col863: double('col81').primaryKey().autoincrement().default(0), + col864: double('col81').primaryKey().autoincrement().default(0), + col865: double('col81').primaryKey().autoincrement().default(0), + col866: double('col81').primaryKey().autoincrement().default(0), + col868: double('col81').primaryKey().autoincrement().default(0), + col869: double('col81').primaryKey().autoincrement().default(0), + col870: double('col81').primaryKey().autoincrement().default(0), + col871: double('col81').primaryKey().autoincrement().default(0), + col872: double('col81').primaryKey().autoincrement().default(0), + col873: double('col81').primaryKey().autoincrement().default(0), + col874: double('col81').primaryKey().autoincrement().default(0), + col875: double('col81').primaryKey().autoincrement().default(0), + col876: double('col81').primaryKey().autoincrement().default(0), + col878: double('col81').primaryKey().autoincrement().default(0), + col879: double('col81').primaryKey().autoincrement().default(0), + col880: double('col81').primaryKey().autoincrement().default(0), + col881: double('col81').primaryKey().autoincrement().default(0), + col882: double('col81').primaryKey().autoincrement().default(0), + col883: double('col81').primaryKey().autoincrement().default(0), + col884: double('col81').primaryKey().autoincrement().default(0), + col885: double('col81').primaryKey().autoincrement().default(0), + col886: double('col81').primaryKey().autoincrement().default(0), + col888: double('col81').primaryKey().autoincrement().default(0), + col889: double('col81').primaryKey().autoincrement().default(0), + col890: double('col81').primaryKey().autoincrement().default(0), + col891: double('col81').primaryKey().autoincrement().default(0), + col892: double('col81').primaryKey().autoincrement().default(0), + col893: double('col81').primaryKey().autoincrement().default(0), + col894: double('col81').primaryKey().autoincrement().default(0), + col895: double('col81').primaryKey().autoincrement().default(0), + col896: double('col81').primaryKey().autoincrement().default(0), + col898: double('col81').primaryKey().autoincrement().default(0), + col899: double('col81').primaryKey().autoincrement().default(0), + col900: double('col9').primaryKey().autoincrement().default(0), + col901: double('col9').primaryKey().autoincrement().default(0), + col902: double('col9').primaryKey().autoincrement().default(0), + col903: double('col9').primaryKey().autoincrement().default(0), + col904: double('col9').primaryKey().autoincrement().default(0), + col905: double('col9').primaryKey().autoincrement().default(0), + col906: double('col9').primaryKey().autoincrement().default(0), + col908: double('col9').primaryKey().autoincrement().default(0), + col909: double('col9').primaryKey().autoincrement().default(0), + col910: double('col91').primaryKey().autoincrement().default(0), + col911: double('col91').primaryKey().autoincrement().default(0), + col912: double('col91').primaryKey().autoincrement().default(0), + col913: double('col91').primaryKey().autoincrement().default(0), + col914: double('col91').primaryKey().autoincrement().default(0), + col915: double('col91').primaryKey().autoincrement().default(0), + col916: double('col91').primaryKey().autoincrement().default(0), + col918: double('col91').primaryKey().autoincrement().default(0), + col919: double('col91').primaryKey().autoincrement().default(0), + col920: double('col91').primaryKey().autoincrement().default(0), + col921: double('col91').primaryKey().autoincrement().default(0), + col922: double('col91').primaryKey().autoincrement().default(0), + col923: double('col91').primaryKey().autoincrement().default(0), + col924: double('col91').primaryKey().autoincrement().default(0), + col925: double('col91').primaryKey().autoincrement().default(0), + col926: double('col91').primaryKey().autoincrement().default(0), + col928: double('col91').primaryKey().autoincrement().default(0), + col929: double('col91').primaryKey().autoincrement().default(0), + col930: double('col91').primaryKey().autoincrement().default(0), + col931: double('col91').primaryKey().autoincrement().default(0), + col932: double('col91').primaryKey().autoincrement().default(0), + col933: double('col91').primaryKey().autoincrement().default(0), + col934: double('col91').primaryKey().autoincrement().default(0), + col935: double('col91').primaryKey().autoincrement().default(0), + col936: double('col91').primaryKey().autoincrement().default(0), + col938: double('col91').primaryKey().autoincrement().default(0), + col939: double('col91').primaryKey().autoincrement().default(0), + col940: double('col91').primaryKey().autoincrement().default(0), + col941: double('col91').primaryKey().autoincrement().default(0), + col942: double('col91').primaryKey().autoincrement().default(0), + col943: double('col91').primaryKey().autoincrement().default(0), + col944: varchar('col91', { length: 200 }).primaryKey().default('0'), + col945: varchar('col91', { length: 200 }).primaryKey().default('0'), + col946: varchar('col91', { length: 200 }).primaryKey().default('0'), + col948: varchar('col91', { length: 200 }).primaryKey().default('0'), + col949: varchar('col91', { length: 200 }).primaryKey().default('0'), + col950: varchar('col91', { length: 200 }).primaryKey().default('0'), + col951: varchar('col91', { length: 200 }).primaryKey().default('0'), + col952: varchar('col91', { length: 200 }).primaryKey().default('0'), + col953: varchar('col91', { length: 200 }).primaryKey().default('0'), + col954: varchar('col91', { length: 200 }).primaryKey().default('0'), + col955: varchar('col91', { length: 200 }).primaryKey().default('0'), + col956: varchar('col91', { length: 200 }).primaryKey().default('0'), + col958: varchar('col91', { length: 200 }).primaryKey().default('0'), + col959: varchar('col91', { length: 200 }).primaryKey().default('0'), + col960: varchar('col91', { length: 200 }).primaryKey().default('0'), + col961: varchar('col91', { length: 200 }).primaryKey().default('0'), + col962: varchar('col91', { length: 200 }).primaryKey().default('0'), + col963: varchar('col91', { length: 200 }).primaryKey().default('0'), + col964: varchar('col91', { length: 200 }).primaryKey().default('0'), + col965: varchar('col91', { length: 200 }).primaryKey().default('0'), + col966: varchar('col91', { length: 200 }).primaryKey().default('0'), + col968: varchar('col91', { length: 200 }).primaryKey().default('0'), + col969: varchar('col91', { length: 200 }).primaryKey().default('0'), + col970: varchar('col91', { length: 200 }).primaryKey().default('0'), + col971: varchar('col91', { length: 200 }).primaryKey().default('0'), + col972: varchar('col91', { length: 200 }).primaryKey().default('0'), + col973: varchar('col91', { length: 200 }).primaryKey().default('0'), + col974: varchar('col91', { length: 200 }).primaryKey().default('0'), + col975: varchar('col91', { length: 200 }).primaryKey().default('0'), + col976: varchar('col91', { length: 200 }).primaryKey().default('0'), + col978: varchar('col91', { length: 200 }).primaryKey().default('0'), + col979: varchar('col91', { length: 200 }).primaryKey().default('0'), + col980: varchar('col91', { length: 200 }).primaryKey().default('0'), + col981: varchar('col91', { length: 200 }).primaryKey().default('0'), + col982: varchar('col91', { length: 200 }).primaryKey().default('0'), + col983: varchar('col91', { length: 200 }).primaryKey().default('0'), + col984: varchar('col91', { length: 200 }).primaryKey().default('0'), + col985: varchar('col91', { length: 200 }).primaryKey().default('0'), + col986: varchar('col91', { length: 200 }).primaryKey().default('0'), + col988: varchar('col91', { length: 200 }).primaryKey().default('0'), + col989: varchar('col91', { length: 200 }).primaryKey().default('0'), + col990: varchar('col91', { length: 200 }).primaryKey().default('0'), + col991: varchar('col91', { length: 200 }).primaryKey().default('0'), + col992: varchar('col91', { length: 200 }).primaryKey().default('0'), + col993: varchar('col91', { length: 200 }).primaryKey().default('0'), + col994: varchar('col91', { length: 200 }).primaryKey().default('0'), + col995: varchar('col91', { length: 200 }).primaryKey().default('0'), + col996: varchar('col91', { length: 200 }).primaryKey().default('0'), + col998: varchar('col91', { length: 200 }).primaryKey().default('0'), + col999: varchar('col91', { length: 200 }).primaryKey().default('0'), +}); diff --git a/drizzle-orm/type-tests/singlestore/db.ts b/drizzle-orm/type-tests/singlestore/db.ts new file mode 100644 index 0000000000..bde149b08a --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/db.ts @@ -0,0 +1,14 @@ +import { createPool } from 'mysql2/promise'; +import { drizzle } from '~/singlestore/index.ts'; + +const pool = createPool({}); + +export const db = drizzle(pool); + +{ + drizzle(pool); + // @ts-expect-error - missing mode + drizzle(pool, { schema: {} }); + drizzle(pool, { schema: {}, mode: 'default' }); + drizzle(pool, { mode: 'default' }); +} diff --git a/drizzle-orm/type-tests/singlestore/delete.ts b/drizzle-orm/type-tests/singlestore/delete.ts new file mode 100644 index 0000000000..0fce8882ef --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/delete.ts @@ -0,0 +1,61 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import type { SingleStoreDelete } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const deleteAll = await db.delete(users); +Expect>; + +const deleteAllStmt = db.delete(users).prepare(); +const deleteAllPrepared = await deleteAllStmt.execute(); +Expect>; + +const deleteWhere = await db.delete(users).where(eq(users.id, 1)); +Expect>; + +const deleteWhereStmt = db.delete(users).where(eq(users.id, 1)).prepare(); +const deleteWherePrepared = await deleteWhereStmt.execute(); +Expect>; + +const deleteReturningAll = await db.delete(users); +Expect>; + +const deleteReturningAllStmt = db.delete(users).prepare(); +const deleteReturningAllPrepared = await deleteReturningAllStmt.execute(); +Expect>; + +const deleteReturningPartial = await db.delete(users); +Expect>; + +const deleteReturningPartialStmt = db.delete(users).prepare(); +const deleteReturningPartialPrepared = await deleteReturningPartialStmt.execute(); +Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .delete(users) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); + + db + .delete(users) + .$dynamic() + .where(sql``) + .where(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/generated-columns.ts b/drizzle-orm/type-tests/singlestore/generated-columns.ts new file mode 100644 index 0000000000..e33a9d61b6 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/generated-columns.ts @@ -0,0 +1,158 @@ +import { type Equal, Expect } from 'type-tests/utils'; +import { type InferInsertModel, type InferSelectModel, sql } from '~/index'; +import { drizzle } from '~/singlestore'; +import { serial, singlestoreTable, text, varchar } from '~/singlestore-core'; +import { db } from './db'; + +const users = singlestoreTable( + 'users', + { + id: serial('id').primaryKey(), + firstName: varchar('first_name', { length: 255 }), + lastName: varchar('last_name', { length: 255 }), + email: text('email').notNull(), + fullName: text('full_name').generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), + upperName: text('upper_name').generatedAlwaysAs( + sql` case when first_name is null then null else upper(first_name) end `, + ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it + }, +); +{ + type User = typeof users.$inferSelect; + type NewUser = typeof users.$inferInsert; + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }, + User + > + >(); + + Expect< + Equal< + { + email: string; + id?: number | undefined; + firstName?: string | null | undefined; + lastName?: string | null | undefined; + }, + NewUser + > + >(); +} + +{ + type User = InferSelectModel; + type NewUser = InferInsertModel; + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }, + User + > + >(); + + Expect< + Equal< + { + email: string; + id?: number | undefined; + firstName?: string | null | undefined; + lastName?: string | null | undefined; + }, + NewUser + > + >(); +} + +{ + const dbUsers = await db.select().from(users); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }[], + typeof dbUsers + > + >(); +} + +{ + const db = drizzle({} as any, { schema: { users }, mode: 'default' }); + + const dbUser = await db.query.users.findFirst(); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + } | undefined, + typeof dbUser + > + >(); +} + +{ + const db = drizzle({} as any, { schema: { users }, mode: 'default' }); + + const dbUser = await db.query.users.findMany(); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }[], + typeof dbUser + > + >(); +} + +{ + // @ts-expect-error - Can't use the fullName because it's a generated column + await db.insert(users).values({ + firstName: 'test', + lastName: 'test', + email: 'test', + fullName: 'test', + }); +} + +{ + await db.update(users).set({ + firstName: 'test', + lastName: 'test', + email: 'test', + // @ts-expect-error - Can't use the fullName because it's a generated column + fullName: 'test', + }); +} diff --git a/drizzle-orm/type-tests/singlestore/insert.ts b/drizzle-orm/type-tests/singlestore/insert.ts new file mode 100644 index 0000000000..738bf669df --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/insert.ts @@ -0,0 +1,135 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { int, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import type { SingleStoreInsert } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const singlestoreInsertReturning = await db.insert(users).values({ + // ^? + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).$returningId(); + +Expect>; + +const insert = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertPrepared = await insertStmt.execute(); +Expect>; + +const insertSql = await db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}); +Expect>; + +const insertSqlStmt = db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}).prepare(); +const insertSqlPrepared = await insertSqlStmt.execute(); +Expect>; + +const insertReturning = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPrepared = await insertReturningStmt.execute(); +Expect>; + +const insertReturningPartial = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningPartialStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPartialPrepared = await insertReturningPartialStmt.execute(); +Expect>; + +const insertReturningSql = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}); +Expect>; + +const insertReturningSqlStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}).prepare(); +const insertReturningSqlPrepared = await insertReturningSqlStmt.execute(); +Expect>; + +{ + const users = singlestoreTable('users', { + id: int('id').autoincrement().primaryKey(), + name: text('name').notNull(), + age: int('age'), + occupation: text('occupation'), + }); + + await db.insert(users).values({ name: 'John Wick', age: 58, occupation: 'housekeeper' }); +} + +{ + function dynamic(qb: T) { + return qb.onDuplicateKeyUpdate({ set: {} }); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + + Expect>; +} + +{ + db + .insert(users) + .values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }) + .onDuplicateKeyUpdate({ set: {} }) + // @ts-expect-error method was already called + .onDuplicateKeyUpdate({ set: {} }); +} diff --git a/drizzle-orm/type-tests/singlestore/select.ts b/drizzle-orm/type-tests/singlestore/select.ts new file mode 100644 index 0000000000..10a7551a7c --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/select.ts @@ -0,0 +1,606 @@ +import { + and, + between, + eq, + exists, + gt, + gte, + ilike, + inArray, + isNotNull, + isNull, + like, + lt, + lte, + ne, + not, + notBetween, + notExists, + notIlike, + notInArray, + notLike, + or, +} from '~/expressions.ts'; +import { alias } from '~/singlestore-core/alias.ts'; +import { param, sql } from '~/sql/sql.ts'; + +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { QueryBuilder, type SingleStoreSelect, type SingleStoreSelectQueryBuilder } from '~/singlestore-core/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const city = alias(cities, 'city'); +const city1 = alias(cities, 'city1'); + +const join = await db + .select({ + users, + cities, + city, + city1: { + id: city1.id, + }, + }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)) + .rightJoin(city, eq(city.id, users.id)) + .rightJoin(city1, eq(city1.id, users.id)); + +Expect< + Equal< + { + users: { + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + } | null; + cities: { + id: number; + name: string; + population: number | null; + } | null; + city: { + id: number; + name: string; + population: number | null; + } | null; + city1: { + id: number; + }; + }[], + typeof join + > +>; + +const join2 = await db + .select({ + userId: users.id, + cityId: cities.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + }[], + typeof join2 + > +>; + +const join3 = await db + .select({ + userId: users.id, + cityId: cities.id, + classId: classes.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)) + .rightJoin(classes, eq(users.id, classes.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + classId: number; + }[], + typeof join3 + > +>; + +db + .select() + .from(users) + .where(exists(db.select().from(cities).where(eq(users.homeCity, cities.id)))); + +function mapFunkyFuncResult(valueFromDriver: unknown) { + return { + foo: (valueFromDriver as Record)['foo'], + }; +} + +const age = 1; + +const allOperators = await db + .select({ + col2: sql`5 - ${users.id} + 1`, // unknown + col3: sql`${users.id} + 1`, // number + col33: sql`${users.id} + 1`.mapWith(users.id), // number + col34: sql`${users.id} + 1`.mapWith(mapFunkyFuncResult), // number + col4: sql`one_or_another(${users.id}, ${users.class})`, // string | number + col5: sql`true`, // unknown + col6: sql`true`, // boolean + col7: sql`random()`, // number + col8: sql`some_funky_func(${users.id})`.mapWith(mapFunkyFuncResult), // { foo: string } + col9: sql`greatest(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // unknown + col10: sql`date_or_false(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // Date | boolean + col11: sql`${users.age1} + ${age}`, // unknown + col12: sql`${users.age1} + ${param(age, users.age1)}`, // unknown + col13: sql`lower(${users.class})`, // unknown + col14: sql`length(${users.class})`, // number + count: sql`count(*)::int`, // number + }) + .from(users) + .where(and( + eq(users.id, 1), + ne(users.id, 1), + or(eq(users.id, 1), ne(users.id, 1)), + not(eq(users.id, 1)), + gt(users.id, 1), + gte(users.id, 1), + lt(users.id, 1), + lte(users.id, 1), + inArray(users.id, [1, 2, 3]), + inArray(users.id, db.select({ id: users.id }).from(users)), + inArray(users.id, sql`select id from ${users}`), + notInArray(users.id, [1, 2, 3]), + notInArray(users.id, db.select({ id: users.id }).from(users)), + notInArray(users.id, sql`select id from ${users}`), + isNull(users.subClass), + isNotNull(users.id), + exists(db.select({ id: users.id }).from(users)), + exists(sql`select id from ${users}`), + notExists(db.select({ id: users.id }).from(users)), + notExists(sql`select id from ${users}`), + between(users.id, 1, 2), + notBetween(users.id, 1, 2), + like(users.id, '%1%'), + notLike(users.id, '%1%'), + ilike(users.id, '%1%'), + notIlike(users.id, '%1%'), + )); + +Expect< + Equal<{ + col2: unknown; + col3: number; + col33: number; + col34: { foo: any }; + col4: string | number; + col5: unknown; + col6: boolean; + col7: number; + col8: { + foo: any; + }; + col9: unknown; + col10: boolean | Date; + col11: unknown; + col12: unknown; + col13: unknown; + col14: number; + count: number; + }[], typeof allOperators> +>; + +const textSelect = await db + .select({ + t: users.text, + }) + .from(users); + +Expect>; + +const homeCity = alias(cities, 'homeCity'); +const c = alias(classes, 'c'); +const otherClass = alias(classes, 'otherClass'); +const anotherClass = alias(classes, 'anotherClass'); +const friend = alias(users, 'friend'); +const currentCity = alias(cities, 'currentCity'); +const subscriber = alias(users, 'subscriber'); +const closestCity = alias(cities, 'closestCity'); + +const megaJoin = await db + .select({ + user: { + id: users.id, + maxAge: sql`max(${users.age1})`, + }, + city: { + id: cities.id, + }, + homeCity, + c, + otherClass, + anotherClass, + friend, + currentCity, + subscriber, + closestCity, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(homeCity, sql`${users.homeCity} = ${homeCity.id}`) + .innerJoin(c, eq(c.id, users.class)) + .innerJoin(otherClass, sql`${c.id} = ${otherClass.id}`) + .innerJoin(anotherClass, sql`${users.class} = ${anotherClass.id}`) + .innerJoin(friend, sql`${users.id} = ${friend.id}`) + .innerJoin(currentCity, sql`${homeCity.id} = ${currentCity.id}`) + .innerJoin(subscriber, sql`${users.class} = ${subscriber.id}`) + .innerJoin(closestCity, sql`${users.currentCity} = ${closestCity.id}`) + .where(and(sql`${users.age1} > 0`, eq(cities.id, 1))) + .limit(1) + .offset(1); + +Expect< + Equal< + { + user: { + id: number; + maxAge: unknown; + }; + city: { + id: number; + }; + homeCity: { + id: number; + name: string; + population: number | null; + }; + c: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + otherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + anotherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + currentCity: { + id: number; + name: string; + population: number | null; + }; + subscriber: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + closestCity: { + id: number; + name: string; + population: number | null; + }; + }[], + typeof megaJoin + > +>; + +const friends = alias(users, 'friends'); + +const join4 = await db + .select({ + user: { + id: users.id, + }, + city: { + id: cities.id, + }, + class: classes, + friend: friends, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(classes, sql`${cities.id} = ${classes.id}`) + .innerJoin(friends, sql`${friends.id} = ${users.id}`) + .where(sql`${users.age1} > 0`); + +Expect< + Equal<{ + user: { + id: number; + }; + city: { + id: number; + }; + class: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + }[], typeof join4> +>; + +{ + const authenticated = false as boolean; + + const result = await db + .select({ + id: users.id, + ...(authenticated ? { city: users.homeCity } : {}), + }) + .from(users); + + Expect< + Equal< + { + id: number; + city?: number; + }[], + typeof result + > + >; +} + +await db.select().from(users).for('update'); +await db.select().from(users).for('share', { skipLocked: true }); +await db.select().from(users).for('update', { noWait: true }); +await db + .select() + .from(users) + // @ts-expect-error - can't use both skipLocked and noWait + .for('share', { noWait: true, skipLocked: true }); + +{ + const result = await db.select().from(newYorkers); + Expect< + Equal< + { + userId: number; + cityId: number | null; + }[], + typeof result + > + >; +} + +{ + const result = await db.select({ userId: newYorkers.userId }).from(newYorkers); + Expect< + Equal< + { + userId: number; + }[], + typeof result + > + >; +} + +{ + const query = db.select().from(users).prepare().iterator(); + for await (const row of query) { + Expect>(); + } +} + +{ + db + .select() + .from(users) + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + .limit(10) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const qb = db.select().from(users).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +{ + // TODO: add to docs + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const query = new QueryBuilder().select().from(users).$dynamic(); + dynamic(query); +} + +{ + // TODO: add to docs + function paginated(qb: T, page: number) { + return qb.limit(10).offset((page - 1) * 10); + } + + const qb = db.select().from(users).$dynamic(); + const result = await paginated(qb, 1); + + Expect>; +} + +{ + db + .select() + .from(users) + .where(sql``) + .limit(10) + // @ts-expect-error method was already called + .where(sql``); + + db + .select() + .from(users) + .having(sql``) + .limit(10) + // @ts-expect-error method was already called + .having(sql``); + + db + .select() + .from(users) + .groupBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .groupBy(sql``); + + db + .select() + .from(users) + .orderBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .orderBy(sql``); + + db + .select() + .from(users) + .limit(10) + .where(sql``) + // @ts-expect-error method was already called + .limit(10); + + db + .select() + .from(users) + .offset(10) + .limit(10) + // @ts-expect-error method was already called + .offset(10); + + db + .select() + .from(users) + .for('update') + .limit(10) + // @ts-expect-error method was already called + .for('update'); +} diff --git a/drizzle-orm/type-tests/singlestore/set-operators.ts b/drizzle-orm/type-tests/singlestore/set-operators.ts new file mode 100644 index 0000000000..8bd434262f --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/set-operators.ts @@ -0,0 +1,286 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import { + except, + exceptAll, + intersect, + intersectAll, + type SingleStoreSetOperator, + union, + unionAll, +} from '~/singlestore-core/index.ts'; +import { desc, sql } from '~/sql/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const unionTest = await db + .select({ id: users.id }) + .from(users) + .union( + db + .select({ id: users.id }) + .from(users), + ); + +Expect>; + +const unionAllTest = await db + .select({ id: users.id, age: users.age1 }) + .from(users) + .unionAll( + db.select({ id: users.id, age: users.age1 }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const intersectTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .intersect(({ intersect }) => + intersect( + db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users), + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ) + ); + +Expect>; + +const intersectAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .intersect( + db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const exceptTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const exceptAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql<'A' | 'C'>`${users.class}` }) + .from(users), + ); + +Expect>; + +const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); + +Expect>; + +const unionAll2Test = await unionAll( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select().from(cities), +); + +Expect>; + +const intersect2Test = await intersect( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), +); + +Expect>; + +const intersectAll2Test = await intersectAll( + union( + db.select({ + id: cities.id, + }).from(cities), + db.select({ + id: cities.id, + }) + .from(cities).where(sql``), + ), + db.select({ + id: cities.id, + }) + .from(cities), +).orderBy(desc(cities.id)).limit(23); + +Expect>; + +const except2Test = await except( + db.select({ + userId: newYorkers.userId, + }) + .from(newYorkers), + db.select({ + userId: newYorkers.userId, + }).from(newYorkers), +); + +Expect>; + +const exceptAll2Test = await exceptAll( + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }) + .from(newYorkers).where(sql``), + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }).from(newYorkers).leftJoin(users, sql``), +); + +Expect>; + +const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); + +Expect< + Equal<{ + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }[], typeof unionfull> +>; + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +union(db.select().from(users), db.select().from(users)) + .offset(1) + // @ts-expect-error - method was already called + .offset(2); + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +{ + function dynamic(qb: T) { + return qb.orderBy(sql``).limit(1).offset(2); + } + + const qb = union(db.select().from(users), db.select().from(users)).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + .intersect(({ intersect }) => intersect(db.select().from(users), db.select().from(users))); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select().from(classes).union(db.select({ id: classes.id }).from(classes)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes).where(sql``)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes)); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + db.select({ id: cities.id, name: cities.name }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select().from(cities), +); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities), + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``).limit(3).$dynamic(), + db.select({ id: cities.id, name: cities.name }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: newYorkers.userId }).from(newYorkers), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities).where(sql``), + db.select({ id: sql`${cities.id}` }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities).where(sql``), +); diff --git a/drizzle-orm/type-tests/singlestore/subquery.ts b/drizzle-orm/type-tests/singlestore/subquery.ts new file mode 100644 index 0000000000..e8ee4e80b3 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/subquery.ts @@ -0,0 +1,97 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, eq } from '~/expressions.ts'; +import { alias, int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import type { DrizzleTypeError, Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = singlestoreTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const n1 = db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: sql`count(1)::int`.as('count1'), + }) + .from(names) + .groupBy(names.id, names.name, names.authorId) + .as('n1'); + +const n2 = db + .select({ + id: names.id, + authorId: names.authorId, + totalCount: sql`count(1)::int`.as('totalCount'), + }) + .from(names) + .groupBy(names.id, names.authorId) + .as('n2'); + +const result = await db + .select({ + name: n1.name, + authorId: n1.authorId, + count1: n1.count1, + totalCount: n2.totalCount, + }) + .from(n1) + .innerJoin(n2, and(eq(n2.id, n1.id), eq(n2.authorId, n1.authorId))); + +Expect< + Equal< + { + name: string | null; + authorId: number | null; + count1: number; + totalCount: number; + }[], + typeof result + > +>; + +const names2 = alias(names, 'names2'); + +const sq1 = db + .select({ + id: names.id, + name: names.name, + id2: names2.id, + }) + .from(names) + .leftJoin(names2, eq(names.name, names2.name)) + .as('sq1'); + +const res = await db.select().from(sq1); + +Expect< + Equal< + { + id: number; + name: string | null; + id2: number | null; + }[], + typeof res + > +>; + +{ + const sq = db.select({ count: sql`count(1)::int` }).from(names).as('sq'); + Expect ? true : false>; +} + +const sqUnion = db.select().from(names).union(db.select().from(names2)).as('sqUnion'); + +const resUnion = await db.select().from(sqUnion); + +Expect< + Equal<{ + id: number; + name: string | null; + authorId: number | null; + }[], typeof resUnion> +>; diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts new file mode 100644 index 0000000000..18ed96a302 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -0,0 +1,751 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq, gt } from '~/expressions.ts'; +import type { BuildColumn, InferSelectModel, Simplify } from '~/index.ts'; +import { + bigint, + char, + customType, + date, + datetime, + decimal, + index, + int, + json, + longtext, + mediumtext, + primaryKey, + serial, + type SingleStoreColumn, + singlestoreEnum, + singlestoreSchema, + singlestoreTable, + text, + timestamp, + tinytext, + unique, + uniqueIndex, + varchar, +} from '~/singlestore-core/index.ts'; + +import { singlestoreView, type SingleStoreViewWithSelection } from '~/singlestore-core/view.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; + +export const users = singlestoreTable( + 'users_table', + { + id: serial('id').primaryKey(), + homeCity: int('home_city') + .notNull(), + currentCity: int('current_city'), + serialNullable: serial('serial1'), + serialNotNull: serial('serial2').notNull(), + class: text('class', { enum: ['A', 'C'] }).notNull(), + subClass: text('sub_class', { enum: ['B', 'D'] }), + text: text('text'), + age1: int('age1').notNull(), + createdAt: timestamp('created_at', { mode: 'date' }).notNull().defaultNow(), + enumCol: singlestoreEnum('enum_col', ['a', 'b', 'c']).notNull(), + }, + (users) => ({ + usersAge1Idx: uniqueIndex('usersAge1Idx').on(users.class), + usersAge2Idx: index('usersAge2Idx').on(users.class), + uniqueClass: uniqueIndex('uniqueClass') + .on(users.class, users.subClass) + .lock('default') + .algorythm('copy') + .using(`btree`), + pk: primaryKey(users.age1, users.class), + }), +); + +export const cities = singlestoreTable('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect< + Equal< + { + id: SingleStoreColumn<{ + name: 'id'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + isPrimaryKey: true; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isAutoincrement: true; + hasRuntimeDefault: false; + }, object>; + name: SingleStoreColumn<{ + name: 'name_db'; + tableName: 'cities_table'; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: string; + driverParam: string; + notNull: true; + hasDefault: false; + isPrimaryKey: false; + enumValues: [string, ...string[]]; + baseColumn: never; + generated: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, object>; + population: SingleStoreColumn<{ + name: 'population'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + notNull: false; + hasDefault: true; + isPrimaryKey: false; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, object>; + }, + typeof cities._.columns + > +>; + +Expect< + Equal<{ + id: number; + name_db: string; + population: number | null; + }, InferSelectModel> +>; + +Expect< + Equal<{ + id?: number; + name: string; + population?: number | null; + }, typeof cities.$inferInsert> +>; + +export const customSchema = singlestoreSchema('custom_schema'); + +export const citiesCustom = customSchema.table('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect>; + +export const classes = singlestoreTable('classes_table', { + id: serial('id').primaryKey(), + class: text('class', { enum: ['A', 'C'] }), + subClass: text('sub_class', { enum: ['B', 'D'] }).notNull(), +}); + +/* export const classes2 = singlestoreTable('classes_table', { + id: serial().primaryKey(), + class: text({ enum: ['A', 'C'] }).$dbName('class_db'), + subClass: text({ enum: ['B', 'D'] }).notNull(), +}); */ + +export const newYorkers = singlestoreView('new_yorkers') + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + +Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > +>; + +{ + const newYorkers = customSchema.view('new_yorkers') + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const customText = customType<{ data: string }>({ + dataType() { + return 'text'; + }, + }); + + const t = customText('name').notNull(); + Expect< + Equal< + { + brand: 'Column'; + name: 'name'; + tableName: 'table'; + dataType: 'custom'; + columnType: 'SingleStoreCustomColumn'; + data: string; + driverParam: unknown; + notNull: true; + hasDefault: false; + enumValues: undefined; + baseColumn: never; + dialect: 'singlestore'; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }, + Simplify['_']> + > + >; +} + +{ + singlestoreTable('test', { + bigint: bigint('bigint', { mode: 'bigint' }), + number: bigint('number', { mode: 'number' }), + date: date('date').default(new Date()), + date2: date('date2', { mode: 'date' }).default(new Date()), + date3: date('date3', { mode: 'string' }).default('2020-01-01'), + date4: date('date4', { mode: undefined }).default(new Date()), + datetime: datetime('datetime').default(new Date()), + datetime2: datetime('datetime2', { mode: 'date' }).default(new Date()), + datetime3: datetime('datetime3', { mode: 'string' }).default('2020-01-01'), + datetime4: datetime('datetime4', { mode: undefined }).default(new Date()), + timestamp: timestamp('timestamp').default(new Date()), + timestamp2: timestamp('timestamp2', { mode: 'date' }).default(new Date()), + timestamp3: timestamp('timestamp3', { mode: 'string' }).default('2020-01-01'), + timestamp4: timestamp('timestamp4', { mode: undefined }).default(new Date()), + }); +} + +{ + singlestoreTable('test', { + col1: decimal('col1').default('1'), + }); +} + +{ + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).notNull(), + test2: singlestoreEnum('test', ['a', 'b', 'c']).notNull(), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).notNull(), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).notNull(), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test6: text('test', { enum: ['a', 'b', 'c'] }).notNull(), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test14: char('test', { enum: ['a', 'b', 'c'] }).notNull(), + test15: text('test').notNull(), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} + +{ // All types with generated columns + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).generatedAlwaysAs(sql``), + test2: singlestoreEnum('test', ['a', 'b', 'c']).generatedAlwaysAs(sql``), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test6: text('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test14: char('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test15: text('test').generatedAlwaysAs(sql``), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} + +{ + const getUsersTable = (schemaName: TSchema) => { + return singlestoreSchema(schemaName).table('users', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + }; + + const users1 = getUsersTable('id1'); + Expect>; + + const users2 = getUsersTable('id2'); + Expect>; +} + +{ + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin( + customUser, + eq(internalStaff.userId, customUser.id), + ).as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + Expect< + Equal<{ + internal_staff: { + internal_staff: { + userId: number; + }; + custom_user: { + id: number | null; + }; + } | null; + ticket: { + staffId: number; + }; + }[], typeof mainQuery> + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + await db.select().from(newYorkers).leftJoin(newYorkers, eq(newYorkers.userId, newYorkers.userId)); +} + +{ + const test = singlestoreTable('test', { + id: text('id').$defaultFn(() => crypto.randomUUID()).primaryKey(), + }); + + Expect< + Equal<{ + id?: string; + }, typeof test.$inferInsert> + >; +} + +{ + singlestoreTable('test', { + id: int('id').$default(() => 1), + id2: int('id').$defaultFn(() => 1), + // @ts-expect-error - should be number + id3: int('id').$default(() => '1'), + // @ts-expect-error - should be number + id4: int('id').$defaultFn(() => '1'), + }); +} +{ + const emailLog = singlestoreTable( + 'email_log', + { + id: int('id', { unsigned: true }).autoincrement().notNull(), + clientId: int('id_client', { unsigned: true }), + receiverEmail: varchar('receiver_email', { length: 255 }).notNull(), + messageId: varchar('message_id', { length: 255 }), + contextId: int('context_id', { unsigned: true }), + contextType: singlestoreEnum('context_type', ['test']).$type<['test']>(), + action: varchar('action', { length: 80 }).$type<['test']>(), + events: json('events').$type<{ t: 'test' }[]>(), + createdAt: timestamp('created_at', { mode: 'string' }).defaultNow().notNull(), + updatedAt: timestamp('updated_at', { mode: 'string' }).defaultNow().onUpdateNow(), + }, + (table) => { + return { + emailLogId: primaryKey({ columns: [table.id], name: 'email_log_id' }), + emailLogMessageIdUnique: unique('email_log_message_id_unique').on(table.messageId), + }; + }, + ); + + Expect< + Equal<{ + receiverEmail: string; + id?: number | undefined; + createdAt?: string | undefined; + clientId?: number | null | undefined; + messageId?: string | null | undefined; + contextId?: number | null | undefined; + contextType?: ['test'] | null | undefined; + action?: ['test'] | null | undefined; + events?: + | { + t: 'test'; + }[] + | null + | undefined; + updatedAt?: string | null | undefined; + }, typeof emailLog.$inferInsert> + >; +} diff --git a/drizzle-orm/type-tests/singlestore/update.ts b/drizzle-orm/type-tests/singlestore/update.ts new file mode 100644 index 0000000000..3f10ae2e44 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/update.ts @@ -0,0 +1,26 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { SingleStoreUpdate } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/session.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .update(users) + .set({}) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/with.ts b/drizzle-orm/type-tests/singlestore/with.ts new file mode 100644 index 0000000000..77309e32ae --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/with.ts @@ -0,0 +1,80 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { gt, inArray } from '~/expressions.ts'; +import { int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; + +const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull(), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), + generated: text('generatedText').generatedAlwaysAs(sql``), +}); + +{ + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: orders.region, + totalSales: orders.amount, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`sum(${orders.quantity})`, + productSales: sql`sum(${orders.amount})`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))); + + Expect< + Equal<{ + region: string; + product: string; + productUnits: number; + productSales: number; + }[], typeof result> + >; + + const allOrdersWith = db.$with('all_orders_with').as(db.select().from(orders)); + const allFromWith = await db.with(allOrdersWith).select().from(allOrdersWith); + + Expect< + Equal<{ + id: number; + region: string; + product: string; + amount: number; + quantity: number; + generated: string | null; + }[], typeof allFromWith> + >; +} From 3400b04e7e0edff93f84828ea1dcd455d3ff252e Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 4 Sep 2024 11:36:51 -0400 Subject: [PATCH 095/152] Remove new column types (#11) * rm new columns, will add back in alter PR * rm bson, index references --- .../src/singlestore-core/columns/bson.ts | 53 ------- .../src/singlestore-core/columns/geography.ts | 147 ------------------ .../columns/geographypoint.ts | 64 -------- .../src/singlestore-core/columns/guid.ts | 121 -------------- .../src/singlestore-core/columns/index.ts | 5 - .../src/singlestore-core/columns/uuid.ts | 48 ------ .../src/singlestore-core/columns/vector.ts | 74 --------- .../src/singlestore-core/expressions.ts | 10 -- 8 files changed, 522 deletions(-) delete mode 100644 drizzle-orm/src/singlestore-core/columns/bson.ts delete mode 100644 drizzle-orm/src/singlestore-core/columns/geography.ts delete mode 100644 drizzle-orm/src/singlestore-core/columns/geographypoint.ts delete mode 100644 drizzle-orm/src/singlestore-core/columns/guid.ts delete mode 100644 drizzle-orm/src/singlestore-core/columns/uuid.ts delete mode 100644 drizzle-orm/src/singlestore-core/columns/vector.ts diff --git a/drizzle-orm/src/singlestore-core/columns/bson.ts b/drizzle-orm/src/singlestore-core/columns/bson.ts deleted file mode 100644 index 1f20778959..0000000000 --- a/drizzle-orm/src/singlestore-core/columns/bson.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; -import type { ColumnBaseConfig } from '~/column.ts'; -import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { sql } from '~/sql/sql.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; - -export type SingleStoreBsonBuilderInitial = SingleStoreBsonBuilder<{ - name: TName; - dataType: 'json'; // The bson is stored as a json string the same way binary is stored as a string (check `./binary.ts`) - columnType: 'SingleStoreBson'; - data: unknown; - driverParam: string; - enumValues: undefined; - generated: undefined; -}>; - -export class SingleStoreBsonBuilder> - extends SingleStoreColumnBuilder -{ - static readonly [entityKind]: string = 'SingleStoreBsonBuilder'; - - constructor(name: T['name']) { - super(name, 'json', 'SingleStoreBson'); - } - - /** @internal */ - override build( - table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreBson> { - return new SingleStoreBson>( - table, - this.config as ColumnBuilderRuntimeConfig, - ); - } -} - -export class SingleStoreBson> extends SingleStoreColumn { - static readonly [entityKind]: string = 'SingleStoreBson'; - - getSQLType(): string { - return 'bson'; - } - - override mapToDriverValue(value: T['data']) { - const json = JSON.stringify(value); - return sql`${json}:>BSON`; - } -} - -export function bson(name: TName): SingleStoreBsonBuilderInitial { - return new SingleStoreBsonBuilder(name); -} diff --git a/drizzle-orm/src/singlestore-core/columns/geography.ts b/drizzle-orm/src/singlestore-core/columns/geography.ts deleted file mode 100644 index b7798b4a4c..0000000000 --- a/drizzle-orm/src/singlestore-core/columns/geography.ts +++ /dev/null @@ -1,147 +0,0 @@ -import type { ColumnBaseConfig } from '~/column'; -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; -import { entityKind } from '~/entity.ts'; -import { DrizzleError } from '~/errors.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table'; -import type { SQL } from '~/sql/sql.ts'; -import { sql } from '~/sql/sql.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; - -export type LngLat = [lng: number, lat: number]; - -type GeographyPoint = LngLat; -type GeographyLineString = Array; -type GeographyPolygon = Array>; - -export type SingleStoreGeographyBuilderInitial = SingleStoreGeographyBuilder<{ - name: TName; - dataType: 'array'; - columnType: 'SingleStoreGeography'; - data: GeographyPoint | GeographyLineString | GeographyPolygon; - driverParam: string; - enumValues: undefined; - generated: undefined; -}>; - -export class SingleStoreGeographyBuilder> - extends SingleStoreColumnBuilder -{ - static readonly [entityKind]: string = 'SingleStoreGeographyBuilder'; - - constructor(name: T['name']) { - super(name, 'array', 'SingleStoreGeography'); - } - - /** @internal */ - override build( - table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreGeography> { - return new SingleStoreGeography(table, this.config as ColumnBuilderRuntimeConfig); - } -} - -export class SingleStoreGeography> - extends SingleStoreColumn -{ - static readonly [entityKind]: string = 'SingleStoreGeography'; - - constructor( - table: AnySingleStoreTable<{ name: T['tableName'] }>, - config: SingleStoreGeographyBuilder['config'], - ) { - super(table, config); - } - - getSQLType(): string { - return 'text'; - // TODO `geography` is only supported on rowstore tables. Geography data - // on columnstore should be stored as `text` - // return 'geography'; - } - - override mapToDriverValue(value: GeographyPoint | GeographyLineString | GeographyPolygon) { - if (_isPoint(value)) { - return sql`"POINT(${_toPointSQL(value)})"`; - } else if (_isLineString(value)) { - return sql`"LINESTRING(${_toLineStringSQL(value)})"`; - } else if (_isPolygon(value)) { - return sql`"POLYGON(${_toPolygonSQL(value)})"`; - } else { - throw new DrizzleError({ message: 'value is not Array' }); - } - } - - override mapFromDriverValue(value: string): GeographyPoint | GeographyLineString | GeographyPolygon { - const firstParenIndex = value.indexOf('('); - const __type = value.slice(0, firstParenIndex); - const inner = value.slice(firstParenIndex + 1, -1); - switch (__type) { - case 'POINT': { - return _pointToGeographyPoint(inner); - } - case 'LINESTRING': { - return _linestringToGeographyLineString(inner); - } - case 'POLYGON': { - return _polygonToGeographyPolygon(inner); - } - default: { - throw new DrizzleError({ message: 'Unexpected Geography type' }); - } - } - } -} - -export function geography(name: TName): SingleStoreGeographyBuilderInitial { - return new SingleStoreGeographyBuilder(name); -} - -function _toPointSQL([lng, lat]: GeographyPoint): SQL { - return sql`${lng} ${lat}`; -} - -function _toLineStringSQL(linestring: GeographyLineString): SQL { - const points = linestring.map((point) => _toPointSQL(point)); - return sql.join(points, sql.raw(', ')); -} - -function _toPolygonSQL(polygon: GeographyPolygon): SQL { - const rings = polygon.map((linestring) => sql`(${_toLineStringSQL(linestring)})`); - return sql.join(rings, sql.raw(', ')); -} - -function _pointToGeographyPoint(value: string): GeographyPoint { - return value.split(' ').map(Number) as GeographyPoint; -} - -function _linestringToGeographyLineString(value: string): GeographyLineString { - const pairs = value.split(', '); - return pairs.map((pair) => _pointToGeographyPoint(pair)); -} - -function _polygonToGeographyPolygon(value: string): GeographyPolygon { - const rings = value.slice(1, -1).split('), ('); - return rings.map((ring) => _linestringToGeographyLineString(ring)); -} - -function _isPoint(value: GeographyPoint | GeographyLineString | GeographyPolygon): value is GeographyPoint { - return value.length === 2 && typeof value[0] === 'number'; -} - -function _isLineString(value: GeographyPoint | GeographyLineString | GeographyPolygon): value is GeographyLineString { - try { - const test = value as GeographyLineString; - return typeof test[0]![0] === 'number'; - } catch { - return false; - } -} - -function _isPolygon(value: GeographyPoint | GeographyLineString | GeographyPolygon): value is GeographyPolygon { - try { - const test = value as GeographyPolygon; - return typeof test[0]![0]![0] === 'number'; - } catch { - return false; - } -} diff --git a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts b/drizzle-orm/src/singlestore-core/columns/geographypoint.ts deleted file mode 100644 index 3c027ebe5e..0000000000 --- a/drizzle-orm/src/singlestore-core/columns/geographypoint.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { ColumnBaseConfig } from '~/column'; -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; -import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { sql } from '~/sql/sql.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import type { LngLat } from './geography'; - -export type SingleStoreGeographyPointBuilderInitial = SingleStoreGeographyPointBuilder<{ - name: TName; - dataType: 'array'; - columnType: 'SingleStoreGeographyPoint'; - data: LngLat; - driverParam: string; - enumValues: undefined; - generated: undefined; -}>; - -export class SingleStoreGeographyPointBuilder> - extends SingleStoreColumnBuilder -{ - static readonly [entityKind]: string = 'SingleStoreGeographyPointBuilder'; - - constructor(name: T['name']) { - super(name, 'array', 'SingleStoreGeographyPoint'); - } - - /** @internal */ - override build( - table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreGeographyPoint> { - return new SingleStoreGeographyPoint(table, this.config as ColumnBuilderRuntimeConfig); - } -} - -export class SingleStoreGeographyPoint> - extends SingleStoreColumn -{ - static readonly [entityKind]: string = 'SingleStoreGeographyPoint'; - - constructor( - table: AnySingleStoreTable<{ name: T['tableName'] }>, - config: SingleStoreGeographyPointBuilder['config'], - ) { - super(table, config); - } - - getSQLType(): string { - return 'geographypoint'; - } - - override mapToDriverValue([lon, lat]: LngLat) { - return sql`"POINT(${lon} ${lat})"`; - } - - override mapFromDriverValue(value: string): LngLat { - const numbers = value.slice(value.indexOf('(') + 1, -1); - return numbers.split(' ').map(Number) as LngLat; // driver value will look like `POINT(lon lat)` - } -} - -export function geographypoint(name: TName): SingleStoreGeographyPointBuilderInitial { - return new SingleStoreGeographyPointBuilder(name); -} diff --git a/drizzle-orm/src/singlestore-core/columns/guid.ts b/drizzle-orm/src/singlestore-core/columns/guid.ts deleted file mode 100644 index 39d939fead..0000000000 --- a/drizzle-orm/src/singlestore-core/columns/guid.ts +++ /dev/null @@ -1,121 +0,0 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; -import type { ColumnBaseConfig } from '~/column.ts'; -import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { sql } from '~/sql/sql.ts'; -import type { Equal } from '~/utils'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; - -export type SingleStoreGUIDBuilderInitial = SingleStoreGUIDBuilder<{ - name: TName; - dataType: 'buffer'; - columnType: 'SingleStoreGUID'; - data: Uint8Array; - driverParam: string; - enumValues: undefined; - generated: undefined; -}>; - -export class SingleStoreGUIDBuilder> - extends SingleStoreColumnBuilder -{ - static readonly [entityKind]: string = 'SingleStoreGUIDBuilder'; - - constructor(name: T['name'], _config?: SingleStoreGUIDConfig) { - super(name, 'buffer', 'SingleStoreGUID'); - } - - /** @internal */ - override build( - table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreGUID> { - return new SingleStoreGUID(table, this.config as ColumnBuilderRuntimeConfig); - } -} - -export class SingleStoreGUID> extends SingleStoreColumn { - static readonly [entityKind]: string = 'SingleStoreGUID'; - - constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreGUIDBuilder['config']) { - super(table, config); - } - - getSQLType(): string { - return 'binary(16)'; - } - - override mapToDriverValue(value: string) { - return sql`UNHEX(REPLACE(${value}, "-", ""))`; - } -} - -export type SingleStoreGUIDStringBuilderInitial = SingleStoreGUIDStringBuilder<{ - name: TName; - dataType: 'string'; - columnType: 'SingleStoreGUIDString'; - data: string; - driverParam: string; - enumValues: undefined; - generated: undefined; -}>; - -export class SingleStoreGUIDStringBuilder> - extends SingleStoreColumnBuilder -{ - static readonly [entityKind]: string = 'SingleStoreGUIDStringBuilder'; - - constructor(name: T['name'], _config?: SingleStoreGUIDConfig) { - super(name, 'string', 'SingleStoreGUIDString'); - } - - /** @internal */ - override build( - table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreGUIDString> { - return new SingleStoreGUIDString(table, this.config as ColumnBuilderRuntimeConfig); - } -} - -export class SingleStoreGUIDString> - extends SingleStoreColumn -{ - static readonly [entityKind]: string = 'SingleStoreGUIDString'; - - constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreGUIDStringBuilder['config']) { - super(table, config); - } - - getSQLType(): string { - return 'binary(16)'; - } - - override mapToDriverValue(value: string) { - return sql`UNHEX(REPLACE(${value}, "-", ""))`; - } - - override mapFromDriverValue(value: Uint8Array): string { - const hex = Buffer.from(value).toString('hex'); - return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; - } -} - -export interface SingleStoreGUIDConfig { - mode?: TMode; -} - -/** - * Creates a column with the data type `BINARY(16)` - * - * Use config `{ mode: "string" }` for a string representation of the GUID - */ -export function guid( - name: TName, - config?: SingleStoreGUIDConfig, -): Equal extends true ? SingleStoreGUIDStringBuilderInitial - : SingleStoreGUIDBuilderInitial; -export function guid(name: string, config?: SingleStoreGUIDConfig) { - if (config?.mode === 'string') { - return new SingleStoreGUIDStringBuilder(name, config); - } - return new SingleStoreGUIDBuilder(name, config); -} diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts index 18d27e0fba..b51f0fac48 100644 --- a/drizzle-orm/src/singlestore-core/columns/index.ts +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -1,7 +1,6 @@ export * from './bigint.ts'; export * from './binary.ts'; export * from './boolean.ts'; -export * from './bson.ts'; export * from './char.ts'; export * from './common.ts'; export * from './custom.ts'; @@ -11,9 +10,6 @@ export * from './decimal.ts'; export * from './double.ts'; export * from './enum.ts'; export * from './float.ts'; -export * from './geography.ts'; -export * from './geographypoint.ts'; -export * from './guid.ts'; export * from './int.ts'; export * from './json.ts'; export * from './mediumint.ts'; @@ -24,7 +20,6 @@ export * from './text.ts'; export * from './time.ts'; export * from './timestamp.ts'; export * from './tinyint.ts'; -export * from './uuid.ts'; export * from './varbinary.ts'; export * from './varchar.ts'; export * from './year.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/uuid.ts b/drizzle-orm/src/singlestore-core/columns/uuid.ts deleted file mode 100644 index aec204e126..0000000000 --- a/drizzle-orm/src/singlestore-core/columns/uuid.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { ColumnBaseConfig } from '~/column'; -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; -import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; - -export type SingleStoreUUIDBuilderInitial = SingleStoreUUIDBuilder<{ - name: TName; - dataType: 'string'; - columnType: 'SingleStoreUUID'; - data: string; - driverParam: string; - enumValues: undefined; - generated: undefined; -}>; - -export class SingleStoreUUIDBuilder> - extends SingleStoreColumnBuilder -{ - static readonly [entityKind]: string = 'SingleStoreUUIDBuilder'; - - constructor(name: T['name']) { - super(name, 'string', 'SingleStoreUUID'); - } - - /** @internal */ - override build( - table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreUUID> { - return new SingleStoreUUID(table, this.config as ColumnBuilderRuntimeConfig); - } -} - -export class SingleStoreUUID> extends SingleStoreColumn { - static readonly [entityKind]: string = 'SingleStoreUUID'; - - constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreUUIDBuilder['config']) { - super(table, config); - } - - getSQLType(): string { - return 'varchar(36)'; - } -} - -export function uuid(name: TName): SingleStoreUUIDBuilderInitial { - return new SingleStoreUUIDBuilder(name); -} diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts deleted file mode 100644 index cae2b22059..0000000000 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { ColumnBaseConfig } from '~/column'; -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; -import { entityKind } from '~/entity.ts'; -import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; - -export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ - name: TName; - dataType: 'array'; - columnType: 'SingleStoreVector'; - data: Array; - driverParam: Array; - enumValues: undefined; - generated: undefined; -}>; - -export class SingleStoreVectorBuilder> - extends SingleStoreColumnBuilder -{ - static readonly [entityKind]: string = 'SingleStoreVectorBuilder'; - - constructor(name: T['name'], config: SingleStoreVectorConfig) { - super(name, 'array', 'SingleStoreVector'); - this.config.dimensions = config.dimensions; - this.config.elementType = config.elementType; - } - - /** @internal */ - override build( - table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreVector> { - return new SingleStoreVector(table, this.config as ColumnBuilderRuntimeConfig); - } -} - -export class SingleStoreVector> extends SingleStoreColumn { - static readonly [entityKind]: string = 'SingleStoreVector'; - - readonly dimensions: number; - readonly elementType: ElementType | undefined; - - constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreVectorBuilder['config']) { - super(table, config); - this.dimensions = config.dimensions; - this.elementType = config.elementType; - } - - getSQLType(): string { - const et = this.elementType === undefined ? '' : `, ${this.elementType}`; - return `vector(${this.dimensions}${et})`; - } - - override mapToDriverValue(value: Array) { - return JSON.stringify(value); - } - - override mapFromDriverValue(value: string): Array { - return JSON.parse(value); - } -} - -type ElementType = 'I8' | 'I16' | 'I32' | 'I64' | 'F32' | 'F64'; - -export interface SingleStoreVectorConfig { - dimensions: number; - elementType?: ElementType; -} - -export function vector( - name: TName, - config: SingleStoreVectorConfig, -): SingleStoreVectorBuilderInitial { - return new SingleStoreVectorBuilder(name, config); -} diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts index 5f70c5c5a1..6d4284d180 100644 --- a/drizzle-orm/src/singlestore-core/expressions.ts +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -23,13 +23,3 @@ export function substring( chunks.push(sql`)`); return sql.join(chunks); } - -// Vectors - -export function dotProduct(column: SingleStoreColumn | SQL.Aliased, value: Array) { - return sql`${column} <*> ${JSON.stringify(value)}`; -} - -export function euclideanDistance(column: SingleStoreColumn | SQL.Aliased, value: Array) { - return sql`${column} <-> ${JSON.stringify(value)}`; -} From dd09dac67b83b2c77ee23927537f3e01fba90a7f Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 10:22:19 +0300 Subject: [PATCH 096/152] Test implementation --- drizzle-orm/src/monodriver.ts | 81 +++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 drizzle-orm/src/monodriver.ts diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts new file mode 100644 index 0000000000..c1b2b4df19 --- /dev/null +++ b/drizzle-orm/src/monodriver.ts @@ -0,0 +1,81 @@ +import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; +import type { VercelPostgresPoolConfig } from '@vercel/postgres'; +import type { PoolConfig } from 'pg'; +import type { Options, PostgresType } from 'postgres'; +import type { NodePgDatabase } from './node-postgres'; +import type { DrizzleConfig } from './utils'; + +type DatabaseClientType = + | 'node-postgres' + | 'postgres.js' + | 'neon-serverless' + | 'neon-http' + | 'vercel-postgres' + | 'aws-data-api' + | 'planetscale' + | 'mysql2' + | 'tidb-serverless' + | 'libsql' + | 'd1' + | 'bun-sqlite' + | 'better-sqlite3'; + +type ClientConfigMap = { + 'node-postgres': PoolConfig; + 'postgres.js': Options>; + 'neon-serverless': NeonServerlessConfig; + 'neon-http': NeonHttpConfig; + 'vercel-postgres': {}; + 'aws-data-api': {}; + planetscale: {}; + mysql2: {}; + 'tidb-serverless': {}; + 'mysql-http-proxy': {}; + libsql: {}; + d1: {}; + 'bun-sqlite': {}; + 'better-sqlite3': {}; + 'sqlite-http-proxy': {}; +}; + +type ClientDrizzleInstanceMap> = { + 'node-postgres': NodePgDatabase; + 'postgres.js': {}; + 'neon-serverless': {}; + 'neon-http': {}; + 'vercel-postgres': {}; + 'aws-data-api': {}; + planetscale: {}; + mysql2: {}; + 'tidb-serverless': {}; + 'mysql-http-proxy': {}; + libsql: {}; + d1: {}; + 'bun-sqlite': {}; + 'better-sqlite3': {}; + 'sqlite-http-proxy': {}; +}; + +type ClientParams = ClientConfigMap[TClientType]; + +type InitializerParams< + TClientType extends DatabaseClientType, + TSchema extends Record = Record, +> = { + client: TClientType; + connection: ClientParams; +} & DrizzleConfig; + +type DetermineClient< + TParams extends InitializerParams, + TSchema extends Record = TParams['schema'] extends Record ? TParams['schema'] + : Record, +> = ClientDrizzleInstanceMap[TParams['client']]; + +export const drizzle = < + TClientType extends DatabaseClientType, + TSchema extends Record, + TParams extends InitializerParams, +>(params: TParams): DetermineClient => { + return {} as any; +}; From 25d3753e0d3999d590c566880c907b56f1a613dc Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 11:06:47 +0300 Subject: [PATCH 097/152] Type-level implementation --- drizzle-orm/src/monodriver.ts | 114 +++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index c1b2b4df19..bc31f6893c 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,9 +1,60 @@ +import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { Config as LibsqlConfig } from '@libsql/client'; import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; -import type { VercelPostgresPoolConfig } from '@vercel/postgres'; -import type { PoolConfig } from 'pg'; -import type { Options, PostgresType } from 'postgres'; +import type { Config as PlanetscaleConfig } from '@planetscale/database'; +import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; +import type { VercelPostgresPoolConfig as VercelPostgresConfig } from '@vercel/postgres'; +import type { Options as BetterSQLite3Options } from 'better-sqlite3'; +import type { ConnectionConfig as Mysql2Config } from 'mysql2'; +import type { PoolConfig as NodePGPoolConfig } from 'pg'; +import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; +import type { AwsDataApiPgDatabase } from './aws-data-api/pg'; +import type { BetterSQLite3Database } from './better-sqlite3'; +import type { BunSQLiteDatabase } from './bun-sqlite'; +import type { DrizzleD1Database } from './d1'; +import type { LibSQLDatabase } from './libsql'; +import type { MySql2Database } from './mysql2'; +import type { NeonHttpDatabase } from './neon-http'; +import type { NeonDatabase } from './neon-serverless'; import type { NodePgDatabase } from './node-postgres'; +import type { PlanetScaleDatabase } from './planetscale-serverless'; +import type { PostgresJsDatabase } from './postgres-js'; +import type { TiDBServerlessDatabase } from './tidb-serverless'; import type { DrizzleConfig } from './utils'; +import type { VercelPgDatabase } from './vercel-postgres'; + +type BunSqliteDatabaseOptions = + | number + | { + /** + * Open the database as read-only (no write operations, no create). + * + * Equivalent to {@link constants.SQLITE_OPEN_READONLY} + */ + readonly?: boolean; + /** + * Allow creating a new database + * + * Equivalent to {@link constants.SQLITE_OPEN_CREATE} + */ + create?: boolean; + /** + * Open the database as read-write + * + * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} + */ + readwrite?: boolean; + }; + +type BunSqliteDatabaseConfig = { + filename?: string; + options?: BunSqliteDatabaseOptions; +}; + +type BetterSQLite3DatabaseConfig = { + filename?: string | Buffer; + options?: BetterSQLite3Options; +}; type DatabaseClientType = | 'node-postgres' @@ -21,39 +72,35 @@ type DatabaseClientType = | 'better-sqlite3'; type ClientConfigMap = { - 'node-postgres': PoolConfig; - 'postgres.js': Options>; + 'node-postgres': NodePGPoolConfig; + 'postgres.js': PostgresJSOptions>; 'neon-serverless': NeonServerlessConfig; 'neon-http': NeonHttpConfig; - 'vercel-postgres': {}; - 'aws-data-api': {}; - planetscale: {}; - mysql2: {}; - 'tidb-serverless': {}; - 'mysql-http-proxy': {}; - libsql: {}; - d1: {}; - 'bun-sqlite': {}; - 'better-sqlite3': {}; - 'sqlite-http-proxy': {}; + 'vercel-postgres': VercelPostgresConfig; + 'aws-data-api': RDSConfig; + planetscale: PlanetscaleConfig; + mysql2: Mysql2Config; + 'tidb-serverless': TiDBServerlessConfig; + libsql: LibsqlConfig; + d1: D1Database; + 'bun-sqlite': BunSqliteDatabaseConfig; + 'better-sqlite3': BetterSQLite3DatabaseConfig; }; type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; - 'postgres.js': {}; - 'neon-serverless': {}; - 'neon-http': {}; - 'vercel-postgres': {}; - 'aws-data-api': {}; - planetscale: {}; - mysql2: {}; - 'tidb-serverless': {}; - 'mysql-http-proxy': {}; - libsql: {}; - d1: {}; - 'bun-sqlite': {}; - 'better-sqlite3': {}; - 'sqlite-http-proxy': {}; + 'postgres.js': PostgresJsDatabase; + 'neon-serverless': NeonDatabase; + 'neon-http': NeonHttpDatabase; + 'vercel-postgres': VercelPgDatabase; + 'aws-data-api': AwsDataApiPgDatabase; + planetscale: PlanetScaleDatabase; + mysql2: MySql2Database; + 'tidb-serverless': TiDBServerlessDatabase; + libsql: LibSQLDatabase; + d1: DrizzleD1Database; + 'bun-sqlite': BunSQLiteDatabase; + 'better-sqlite3': BetterSQLite3Database; }; type ClientParams = ClientConfigMap[TClientType]; @@ -76,6 +123,11 @@ export const drizzle = < TClientType extends DatabaseClientType, TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): DetermineClient => { +>({ + client, + connection, + logger, + schema, +}: TParams): DetermineClient => { return {} as any; }; From 8439bf11d31fcb356aa603a6e1c701ba24fac0e1 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 12:26:50 +0300 Subject: [PATCH 098/152] Added functional runtimes for node-pg, aws-data-api-pg [custom drizzle config WIP] --- drizzle-orm/src/monodriver.ts | 70 +++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index bc31f6893c..298d9be340 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -8,7 +8,7 @@ import type { Options as BetterSQLite3Options } from 'better-sqlite3'; import type { ConnectionConfig as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; -import type { AwsDataApiPgDatabase } from './aws-data-api/pg'; +import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg'; import type { BetterSQLite3Database } from './better-sqlite3'; import type { BunSQLiteDatabase } from './bun-sqlite'; import type { DrizzleD1Database } from './d1'; @@ -62,7 +62,7 @@ type DatabaseClientType = | 'neon-serverless' | 'neon-http' | 'vercel-postgres' - | 'aws-data-api' + | 'aws-data-api-pg' | 'planetscale' | 'mysql2' | 'tidb-serverless' @@ -71,13 +71,13 @@ type DatabaseClientType = | 'bun-sqlite' | 'better-sqlite3'; -type ClientConfigMap = { +type ClientConnectionConfigMap = { 'node-postgres': NodePGPoolConfig; 'postgres.js': PostgresJSOptions>; 'neon-serverless': NeonServerlessConfig; 'neon-http': NeonHttpConfig; 'vercel-postgres': VercelPostgresConfig; - 'aws-data-api': RDSConfig; + 'aws-data-api-pg': RDSConfig; planetscale: PlanetscaleConfig; mysql2: Mysql2Config; 'tidb-serverless': TiDBServerlessConfig; @@ -87,13 +87,29 @@ type ClientConfigMap = { 'better-sqlite3': BetterSQLite3DatabaseConfig; }; +// type ClientDrizzleConfigMap> = { +// 'node-postgres': DrizzleConfig; +// 'postgres.js': DrizzleConfig; +// 'neon-serverless': DrizzleConfig; +// 'neon-http': DrizzleConfig; +// 'vercel-postgres': DrizzleConfig; +// 'aws-data-api-pg': DrizzleAwsDataApiPgConfig; +// planetscale: DrizzleConfig; +// mysql2: DrizzleConfig; +// 'tidb-serverless': DrizzleConfig; +// libsql: DrizzleConfig; +// d1: DrizzleConfig; +// 'bun-sqlite': DrizzleConfig; +// 'better-sqlite3': DrizzleConfig; +// }; + type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres.js': PostgresJsDatabase; 'neon-serverless': NeonDatabase; 'neon-http': NeonHttpDatabase; 'vercel-postgres': VercelPgDatabase; - 'aws-data-api': AwsDataApiPgDatabase; + 'aws-data-api-pg': AwsDataApiPgDatabase; planetscale: PlanetScaleDatabase; mysql2: MySql2Database; 'tidb-serverless': TiDBServerlessDatabase; @@ -103,7 +119,7 @@ type ClientDrizzleInstanceMap> = { 'better-sqlite3': BetterSQLite3Database; }; -type ClientParams = ClientConfigMap[TClientType]; +type ClientParams = ClientConnectionConfigMap[TClientType]; type InitializerParams< TClientType extends DatabaseClientType, @@ -115,19 +131,41 @@ type InitializerParams< type DetermineClient< TParams extends InitializerParams, - TSchema extends Record = TParams['schema'] extends Record ? TParams['schema'] + TSchema extends Record = TParams extends { schema: Record } ? TParams['schema'] : Record, -> = ClientDrizzleInstanceMap[TParams['client']]; +> = TParams extends { client: DatabaseClientType } ? ClientDrizzleInstanceMap[TParams['client']] + : never; + +import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; +import { drizzle as pgDrizzle } from './node-postgres/index.ts'; -export const drizzle = < +export const drizzle = async < TClientType extends DatabaseClientType, TSchema extends Record, TParams extends InitializerParams, ->({ - client, - connection, - logger, - schema, -}: TParams): DetermineClient => { - return {} as any; +>(params: TParams): Promise> => { + const { client, connection } = params; + const drizzleConfig = params as Omit; + // @ts-expect-error + delete drizzleConfig.client; + // @ts-expect-error + delete drizzleConfig.connection; + + switch (client) { + case 'node-postgres': { + const { Pool } = await import('pg'); + const instance = new Pool(connection as NodePGPoolConfig); + + return pgDrizzle(instance, drizzleConfig) as any; + } + case 'aws-data-api-pg': { + const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const instance = new RDSDataClient(connection); + + return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + } + } + + // @ts-ignore + return {}; }; From f2115f83916ca6e886427fa24f11c5f09aac04fb Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 13:51:44 +0300 Subject: [PATCH 099/152] Resolved bun type related build issues --- drizzle-kit/build.ts | 3 +++ drizzle-kit/package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/drizzle-kit/build.ts b/drizzle-kit/build.ts index 701e9c84c1..ec7fc76c00 100644 --- a/drizzle-kit/build.ts +++ b/drizzle-kit/build.ts @@ -1,3 +1,4 @@ +/// import * as esbuild from 'esbuild'; import { readFileSync, writeFileSync } from 'node:fs'; import * as tsup from 'tsup'; @@ -16,6 +17,7 @@ const driversPackages = [ // sqlite drivers '@libsql/client', 'better-sqlite3', + 'bun:sqlite', ]; esbuild.buildSync({ @@ -82,6 +84,7 @@ const main = async () => { await tsup.build({ entryPoints: ['./src/index.ts', './src/api.ts'], outDir: './dist', + external: ['bun:sqlite'], splitting: false, dts: true, format: ['cjs', 'esm'], diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 9d9e1d227d..552c14d0ec 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -74,6 +74,7 @@ "@vercel/postgres": "^0.8.0", "ava": "^5.1.0", "better-sqlite3": "^9.4.3", + "bun-types": "^0.6.6", "camelcase": "^7.0.1", "chalk": "^5.2.0", "commander": "^12.1.0", From ab07dd7f295416bd19bd08fd60b165601aef2d89 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 13:52:00 +0300 Subject: [PATCH 100/152] Implemented extra drivers --- drizzle-orm/src/index.ts | 1 + drizzle-orm/src/monodriver.ts | 93 ++++++++++++++++++++++++----------- pnpm-lock.yaml | 25 +++++----- 3 files changed, 78 insertions(+), 41 deletions(-) diff --git a/drizzle-orm/src/index.ts b/drizzle-orm/src/index.ts index bc72260b9f..5cabdb0d84 100644 --- a/drizzle-orm/src/index.ts +++ b/drizzle-orm/src/index.ts @@ -5,6 +5,7 @@ export * from './entity.ts'; export * from './errors.ts'; export * from './expressions.ts'; export * from './logger.ts'; +export * from './monodriver.ts'; export * from './operations.ts'; export * from './query-promise.ts'; export * from './relations.ts'; diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 298d9be340..b6b48c91b2 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,3 +1,4 @@ +/// import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; @@ -8,20 +9,20 @@ import type { Options as BetterSQLite3Options } from 'better-sqlite3'; import type { ConnectionConfig as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; -import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg'; -import type { BetterSQLite3Database } from './better-sqlite3'; -import type { BunSQLiteDatabase } from './bun-sqlite'; -import type { DrizzleD1Database } from './d1'; -import type { LibSQLDatabase } from './libsql'; -import type { MySql2Database } from './mysql2'; -import type { NeonHttpDatabase } from './neon-http'; -import type { NeonDatabase } from './neon-serverless'; -import type { NodePgDatabase } from './node-postgres'; -import type { PlanetScaleDatabase } from './planetscale-serverless'; -import type { PostgresJsDatabase } from './postgres-js'; -import type { TiDBServerlessDatabase } from './tidb-serverless'; -import type { DrizzleConfig } from './utils'; -import type { VercelPgDatabase } from './vercel-postgres'; +import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; +import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; +import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; +import type { DrizzleD1Database } from './d1/index.ts'; +import type { LibSQLDatabase } from './libsql/index.ts'; +import type { MySql2Database } from './mysql2/index.ts'; +import type { NeonHttpDatabase } from './neon-http/index.ts'; +import type { NeonDatabase } from './neon-serverless/index.ts'; +import type { NodePgDatabase } from './node-postgres/index.ts'; +import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; +import type { PostgresJsDatabase } from './postgres-js/index.ts'; +import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; +import type { DrizzleConfig } from './utils.ts'; +import type { VercelPgDatabase } from './vercel-postgres/index.ts'; type BunSqliteDatabaseOptions = | number @@ -87,22 +88,6 @@ type ClientConnectionConfigMap = { 'better-sqlite3': BetterSQLite3DatabaseConfig; }; -// type ClientDrizzleConfigMap> = { -// 'node-postgres': DrizzleConfig; -// 'postgres.js': DrizzleConfig; -// 'neon-serverless': DrizzleConfig; -// 'neon-http': DrizzleConfig; -// 'vercel-postgres': DrizzleConfig; -// 'aws-data-api-pg': DrizzleAwsDataApiPgConfig; -// planetscale: DrizzleConfig; -// mysql2: DrizzleConfig; -// 'tidb-serverless': DrizzleConfig; -// libsql: DrizzleConfig; -// d1: DrizzleConfig; -// 'bun-sqlite': DrizzleConfig; -// 'better-sqlite3': DrizzleConfig; -// }; - type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres.js': PostgresJsDatabase; @@ -137,7 +122,18 @@ type DetermineClient< : never; import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; +import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; +import { drizzle as bunSqliteDrizzle } from './bun-sqlite/index.ts'; +import { drizzle as d1Drizzle } from './d1/index.ts'; +import { drizzle as libsqlDrizzle } from './libsql/index.ts'; +// import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; +// import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; +// import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; import { drizzle as pgDrizzle } from './node-postgres/index.ts'; +// import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; +// import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; +// import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; +// import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; export const drizzle = async < TClientType extends DatabaseClientType, @@ -164,6 +160,43 @@ export const drizzle = async < return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } + case 'better-sqlite3': { + const { default: Client } = await import('better-sqlite3'); + const { filename, options } = connection as BetterSQLite3DatabaseConfig; + const instance = new Client(filename, options); + + return betterSqliteDrizzle(instance, drizzleConfig) as any; + } + case 'bun-sqlite': { + const { Database: Client } = await import('bun:sqlite'); + const { filename, options } = connection as BunSqliteDatabaseConfig; + const instance = new Client(filename, options); + + return bunSqliteDrizzle(instance, drizzleConfig) as any; + } + case 'd1': { + return d1Drizzle(connection as D1Database, drizzleConfig) as any; + } + case 'libsql': { + const { createClient } = await import('@libsql/client'); + const instance = createClient(connection as LibsqlConfig); + + return libsqlDrizzle(instance, drizzleConfig) as any; + } + // case 'mysql2': { + // } + // case 'neon-http': { + // } + // case 'neon-serverless': { + // } + // case 'planetscale': { + // } + // case 'postgres.js': { + // } + // case 'tidb-serverless': { + // } + // case 'vercel-postgres': { + // } } // @ts-ignore diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2d091ad6e..209d2db3bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -182,6 +182,9 @@ importers: better-sqlite3: specifier: ^9.4.3 version: 9.6.0 + bun-types: + specifier: ^0.6.6 + version: 0.6.14 camelcase: specifier: ^7.0.1 version: 7.0.1 @@ -10210,7 +10213,7 @@ snapshots: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10300,7 +10303,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10610,7 +10613,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10799,12 +10802,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10889,13 +10892,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-http': 3.582.0 - '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10970,10 +10973,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso': 3.583.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -11216,7 +11219,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 From 5f493794d0d234c12b0bfdedaf5d8c4253d7af92 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 27 Aug 2024 02:43:07 +0300 Subject: [PATCH 101/152] Complete runtime implementations [TO BE TESTED] --- drizzle-orm/src/monodriver.ts | 110 +++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 35 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index b6b48c91b2..33c9bddbef 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,10 +1,11 @@ -/// import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; -import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; +import type { + HTTPTransactionOptions as NeonHttpConfig, + PoolConfig as NeonServerlessConfig, +} from '@neondatabase/serverless'; import type { Config as PlanetscaleConfig } from '@planetscale/database'; import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; -import type { VercelPostgresPoolConfig as VercelPostgresConfig } from '@vercel/postgres'; import type { Options as BetterSQLite3Options } from 'better-sqlite3'; import type { ConnectionConfig as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; @@ -14,7 +15,7 @@ import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; -import type { MySql2Database } from './mysql2/index.ts'; +import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/index.ts'; @@ -57,6 +58,15 @@ type BetterSQLite3DatabaseConfig = { options?: BetterSQLite3Options; }; +type MonodriverMysql2Config = Mysql2Config & { + mode?: MySql2DrizzleConfig['mode']; +}; + +type MonodriverNeonHttpConfig = { + connectionString: string; + options?: NeonHttpConfig; +}; + type DatabaseClientType = | 'node-postgres' | 'postgres.js' @@ -76,11 +86,11 @@ type ClientConnectionConfigMap = { 'node-postgres': NodePGPoolConfig; 'postgres.js': PostgresJSOptions>; 'neon-serverless': NeonServerlessConfig; - 'neon-http': NeonHttpConfig; - 'vercel-postgres': VercelPostgresConfig; + 'neon-http': MonodriverNeonHttpConfig; + 'vercel-postgres': never; 'aws-data-api-pg': RDSConfig; planetscale: PlanetscaleConfig; - mysql2: Mysql2Config; + mysql2: MonodriverMysql2Config; 'tidb-serverless': TiDBServerlessConfig; libsql: LibsqlConfig; d1: D1Database; @@ -126,14 +136,14 @@ import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; import { drizzle as bunSqliteDrizzle } from './bun-sqlite/index.ts'; import { drizzle as d1Drizzle } from './d1/index.ts'; import { drizzle as libsqlDrizzle } from './libsql/index.ts'; -// import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; -// import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; -// import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; +import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; +import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; +import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; import { drizzle as pgDrizzle } from './node-postgres/index.ts'; -// import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; -// import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; -// import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; -// import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; +import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; +import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; +import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; +import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; export const drizzle = async < TClientType extends DatabaseClientType, @@ -141,11 +151,10 @@ export const drizzle = async < TParams extends InitializerParams, >(params: TParams): Promise> => { const { client, connection } = params; - const drizzleConfig = params as Omit; - // @ts-expect-error - delete drizzleConfig.client; - // @ts-expect-error - delete drizzleConfig.connection; + const drizzleConfig = { + logger: params.logger, + schema: params.schema, + }; switch (client) { case 'node-postgres': { @@ -183,22 +192,53 @@ export const drizzle = async < return libsqlDrizzle(instance, drizzleConfig) as any; } - // case 'mysql2': { - // } - // case 'neon-http': { - // } - // case 'neon-serverless': { - // } - // case 'planetscale': { - // } - // case 'postgres.js': { - // } - // case 'tidb-serverless': { - // } - // case 'vercel-postgres': { - // } + case 'mysql2': { + const { createConnection } = await import('mysql2/promise'); + const instance = await createConnection(connection as MonodriverMysql2Config); + const mode = (connection as MonodriverMysql2Config).mode ?? 'default'; + + return mysql2Drizzle(instance, { logger: params.logger, schema: params.schema, mode }) as any; + } + case 'neon-http': { + const { neon } = await import('@neondatabase/serverless'); + const { connectionString, options } = connection as MonodriverNeonHttpConfig; + const instance = neon(connectionString, options); + + return neonHttpDrizzle(instance, drizzleConfig) as any; + } + case 'neon-serverless': { + const { Pool } = await import('@neondatabase/serverless'); + const instance = new Pool(connection as NeonServerlessConfig); + + return neonDrizzle(instance, drizzleConfig) as any; + } + case 'planetscale': { + const { Client } = await import('@planetscale/database'); + const instance = new Client( + connection as PlanetscaleConfig, + ); + + return planetscaleDrizzle(instance, drizzleConfig) as any; + } + case 'postgres.js': { + const { default: client } = await import('postgres'); + const instance = client(connection as PostgresJSOptions>); + + return postgresJSDrizzle(instance, drizzleConfig) as any; + } + case 'tidb-serverless': { + const { connect } = await import('@tidbcloud/serverless'); + const instance = connect(connection as TiDBServerlessConfig); + + return tidbDrizzle(instance, drizzleConfig) as any; + } + case 'vercel-postgres': { + const { sql } = await import('@vercel/postgres'); + + return vercelDrizzle(sql, drizzleConfig) as any; + } } - // @ts-ignore - return {}; + // Shouldn't reach that point, but Typescript fails to infer that + return {} as any; }; From 45d2d13be1c33e35addbf4326b2ab1cc407cb826 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 13:09:28 +0300 Subject: [PATCH 102/152] Prototype implementation --- drizzle-orm/src/monodriver.ts | 160 ++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 75 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 33c9bddbef..6fe6de8a01 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -6,8 +6,9 @@ import type { } from '@neondatabase/serverless'; import type { Config as PlanetscaleConfig } from '@planetscale/database'; import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; +import type { VercelPool } from '@vercel/postgres'; import type { Options as BetterSQLite3Options } from 'better-sqlite3'; -import type { ConnectionConfig as Mysql2Config } from 'mysql2'; +import type { PoolOptions as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; @@ -58,46 +59,11 @@ type BetterSQLite3DatabaseConfig = { options?: BetterSQLite3Options; }; -type MonodriverMysql2Config = Mysql2Config & { - mode?: MySql2DrizzleConfig['mode']; -}; - type MonodriverNeonHttpConfig = { connectionString: string; options?: NeonHttpConfig; }; -type DatabaseClientType = - | 'node-postgres' - | 'postgres.js' - | 'neon-serverless' - | 'neon-http' - | 'vercel-postgres' - | 'aws-data-api-pg' - | 'planetscale' - | 'mysql2' - | 'tidb-serverless' - | 'libsql' - | 'd1' - | 'bun-sqlite' - | 'better-sqlite3'; - -type ClientConnectionConfigMap = { - 'node-postgres': NodePGPoolConfig; - 'postgres.js': PostgresJSOptions>; - 'neon-serverless': NeonServerlessConfig; - 'neon-http': MonodriverNeonHttpConfig; - 'vercel-postgres': never; - 'aws-data-api-pg': RDSConfig; - planetscale: PlanetscaleConfig; - mysql2: MonodriverMysql2Config; - 'tidb-serverless': TiDBServerlessConfig; - libsql: LibsqlConfig; - d1: D1Database; - 'bun-sqlite': BunSqliteDatabaseConfig; - 'better-sqlite3': BetterSQLite3DatabaseConfig; -}; - type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres.js': PostgresJsDatabase; @@ -106,7 +72,7 @@ type ClientDrizzleInstanceMap> = { 'vercel-postgres': VercelPgDatabase; 'aws-data-api-pg': AwsDataApiPgDatabase; planetscale: PlanetScaleDatabase; - mysql2: MySql2Database; + mysql2: Promise>; 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; @@ -114,22 +80,65 @@ type ClientDrizzleInstanceMap> = { 'better-sqlite3': BetterSQLite3Database; }; -type ClientParams = ClientConnectionConfigMap[TClientType]; - type InitializerParams< - TClientType extends DatabaseClientType, TSchema extends Record = Record, -> = { - client: TClientType; - connection: ClientParams; -} & DrizzleConfig; +> = + | ({ + client: 'node-postgres'; + connection: NodePGPoolConfig; + } & DrizzleConfig) + | ({ + client: 'postgres.js'; + connection: PostgresJSOptions>; + } & DrizzleConfig) + | ({ + client: 'neon-serverless'; + connection: NeonServerlessConfig; + } & DrizzleConfig) + | ({ + client: 'neon-http'; + connection: MonodriverNeonHttpConfig; + } & DrizzleConfig) + | ({ + client: 'vercel-postgres'; + connection: VercelPool; + } & DrizzleConfig) + | ({ + client: 'aws-data-api-pg'; + connection: RDSConfig; + } & DrizzleAwsDataApiPgConfig) + | ({ + client: 'planetscale'; + connection: PlanetscaleConfig; + } & DrizzleConfig) + | ({ + client: 'mysql2'; + connection: Mysql2Config; + } & MySql2DrizzleConfig) + | ({ + client: 'tidb-serverless'; + connection: TiDBServerlessConfig; + } & DrizzleConfig) + | ({ + client: 'libsql'; + connection: LibsqlConfig; + } & DrizzleConfig) + | ({ + client: 'd1'; + connection: D1Database; + } & DrizzleConfig) + | ({ + client: 'bun-sqlite'; + connection: BunSqliteDatabaseConfig; + } & DrizzleConfig) + | ({ + client: 'better-sqlite3'; + connection: BetterSQLite3DatabaseConfig; + } & DrizzleConfig); type DetermineClient< - TParams extends InitializerParams, - TSchema extends Record = TParams extends { schema: Record } ? TParams['schema'] - : Record, -> = TParams extends { client: DatabaseClientType } ? ClientDrizzleInstanceMap[TParams['client']] - : never; + TParams extends InitializerParams, +> = ClientDrizzleInstanceMap[TParams['client']]; import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; @@ -145,39 +154,37 @@ import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; -export const drizzle = async < - TClientType extends DatabaseClientType, +export const drizzle = < TSchema extends Record, - TParams extends InitializerParams, + TParams extends InitializerParams, >(params: TParams): Promise> => { const { client, connection } = params; - const drizzleConfig = { - logger: params.logger, - schema: params.schema, - }; + const drizzleConfig = params as DrizzleConfig; + delete ( drizzleConfig).client; + delete ( drizzleConfig).connection; switch (client) { case 'node-postgres': { - const { Pool } = await import('pg'); + const { Pool } = require('pg') as typeof import('pg'); const instance = new Pool(connection as NodePGPoolConfig); return pgDrizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { - const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const { RDSDataClient } = require('@aws-sdk/client-rds-data') as typeof import('@aws-sdk/client-rds-data'); const instance = new RDSDataClient(connection); return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { - const { default: Client } = await import('better-sqlite3'); + const Client = require('better-sqlite3') as typeof import('better-sqlite3'); const { filename, options } = connection as BetterSQLite3DatabaseConfig; const instance = new Client(filename, options); return betterSqliteDrizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - const { Database: Client } = await import('bun:sqlite'); + const { Database: Client } = require('bun:sqlite') as typeof import('bun:sqlite'); const { filename, options } = connection as BunSqliteDatabaseConfig; const instance = new Client(filename, options); @@ -187,33 +194,39 @@ export const drizzle = async < return d1Drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { - const { createClient } = await import('@libsql/client'); + const { createClient } = require('@libsql/client') as typeof import('@libsql/client'); const instance = createClient(connection as LibsqlConfig); return libsqlDrizzle(instance, drizzleConfig) as any; } case 'mysql2': { - const { createConnection } = await import('mysql2/promise'); - const instance = await createConnection(connection as MonodriverMysql2Config); - const mode = (connection as MonodriverMysql2Config).mode ?? 'default'; - - return mysql2Drizzle(instance, { logger: params.logger, schema: params.schema, mode }) as any; + const { createConnection } = require('mysql2/promise') as typeof import('mysql2/promise'); + + return new Promise((res, rej) => { + createConnection(connection as Mysql2Config).then((instance) => { + try { + res(mysql2Drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); + } catch (e) { + rej(e); + } + }).catch((e) => rej(e)); + }); } case 'neon-http': { - const { neon } = await import('@neondatabase/serverless'); + const { neon } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); const { connectionString, options } = connection as MonodriverNeonHttpConfig; const instance = neon(connectionString, options); return neonHttpDrizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { - const { Pool } = await import('@neondatabase/serverless'); + const { Pool } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); const instance = new Pool(connection as NeonServerlessConfig); return neonDrizzle(instance, drizzleConfig) as any; } case 'planetscale': { - const { Client } = await import('@planetscale/database'); + const { Client } = require('@planetscale/database') as typeof import('@planetscale/database'); const instance = new Client( connection as PlanetscaleConfig, ); @@ -221,24 +234,21 @@ export const drizzle = async < return planetscaleDrizzle(instance, drizzleConfig) as any; } case 'postgres.js': { - const { default: client } = await import('postgres'); + const client = require('postgres') as typeof import('postgres'); const instance = client(connection as PostgresJSOptions>); return postgresJSDrizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { - const { connect } = await import('@tidbcloud/serverless'); + const { connect } = require('@tidbcloud/serverless') as typeof import('@tidbcloud/serverless'); const instance = connect(connection as TiDBServerlessConfig); return tidbDrizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { - const { sql } = await import('@vercel/postgres'); + const { sql } = require('@vercel/postgres') as typeof import('@vercel/postgres'); return vercelDrizzle(sql, drizzleConfig) as any; } } - - // Shouldn't reach that point, but Typescript fails to infer that - return {} as any; }; From be0aab22d331d5f12c64ef31335a90e3d0aba3f4 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 14:25:50 +0300 Subject: [PATCH 103/152] switched bun to dynamic imports --- drizzle-orm/src/monodriver.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 6fe6de8a01..50106e4e96 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -76,7 +76,7 @@ type ClientDrizzleInstanceMap> = { 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; - 'bun-sqlite': BunSQLiteDatabase; + 'bun-sqlite': Promise>; 'better-sqlite3': BetterSQLite3Database; }; @@ -184,11 +184,18 @@ export const drizzle = < return betterSqliteDrizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - const { Database: Client } = require('bun:sqlite') as typeof import('bun:sqlite'); - const { filename, options } = connection as BunSqliteDatabaseConfig; - const instance = new Client(filename, options); + return new Promise((res, rej) => { + import('bun:sqlite').then(({ Database: Client }) => { + try { + const { filename, options } = connection as BunSqliteDatabaseConfig; + const instance = new Client(filename, options); - return bunSqliteDrizzle(instance, drizzleConfig) as any; + res(bunSqliteDrizzle(instance, drizzleConfig) as any); + } catch (e) { + rej(e); + } + }).catch((e) => rej(e)); + }); } case 'd1': { return d1Drizzle(connection as D1Database, drizzleConfig) as any; From 936b319090b22d9429f3100182bdd48fd40c5034 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 15:50:03 +0300 Subject: [PATCH 104/152] Removed static imports, removed promise wrapper --- drizzle-orm/src/monodriver.ts | 66 +++++++++++++++++------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 50106e4e96..81e7b7396e 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,3 +1,4 @@ +/* eslint-disable import/extensions */ import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; import type { @@ -66,7 +67,7 @@ type MonodriverNeonHttpConfig = { type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; - 'postgres.js': PostgresJsDatabase; + 'postgres-js': PostgresJsDatabase; 'neon-serverless': NeonDatabase; 'neon-http': NeonHttpDatabase; 'vercel-postgres': VercelPgDatabase; @@ -88,7 +89,7 @@ type InitializerParams< connection: NodePGPoolConfig; } & DrizzleConfig) | ({ - client: 'postgres.js'; + client: 'postgres-js'; connection: PostgresJSOptions>; } & DrizzleConfig) | ({ @@ -140,24 +141,10 @@ type DetermineClient< TParams extends InitializerParams, > = ClientDrizzleInstanceMap[TParams['client']]; -import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; -import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; -import { drizzle as bunSqliteDrizzle } from './bun-sqlite/index.ts'; -import { drizzle as d1Drizzle } from './d1/index.ts'; -import { drizzle as libsqlDrizzle } from './libsql/index.ts'; -import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; -import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; -import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; -import { drizzle as pgDrizzle } from './node-postgres/index.ts'; -import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; -import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; -import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; -import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; - export const drizzle = < TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): Promise> => { +>(params: TParams): DetermineClient => { const { client, connection } = params; const drizzleConfig = params as DrizzleConfig; delete ( drizzleConfig).client; @@ -166,45 +153,51 @@ export const drizzle = < switch (client) { case 'node-postgres': { const { Pool } = require('pg') as typeof import('pg'); + const { drizzle } = require('./node-postgres') as typeof import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); - return pgDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { const { RDSDataClient } = require('@aws-sdk/client-rds-data') as typeof import('@aws-sdk/client-rds-data'); + const { drizzle } = require('./aws-data-api/pg') as typeof import('./aws-data-api/pg'); const instance = new RDSDataClient(connection); - return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { const Client = require('better-sqlite3') as typeof import('better-sqlite3'); const { filename, options } = connection as BetterSQLite3DatabaseConfig; + const { drizzle } = require('./better-sqlite3') as typeof import('./better-sqlite3'); const instance = new Client(filename, options); - return betterSqliteDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { return new Promise((res, rej) => { import('bun:sqlite').then(({ Database: Client }) => { try { const { filename, options } = connection as BunSqliteDatabaseConfig; + const { drizzle } = require('./bun-sqlite') as typeof import('./bun-sqlite'); const instance = new Client(filename, options); - res(bunSqliteDrizzle(instance, drizzleConfig) as any); + res(drizzle(instance, drizzleConfig) as any); } catch (e) { rej(e); } }).catch((e) => rej(e)); - }); + }) as any; } case 'd1': { - return d1Drizzle(connection as D1Database, drizzleConfig) as any; + const { drizzle } = require('./d1') as typeof import('./d1'); + return drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { const { createClient } = require('@libsql/client') as typeof import('@libsql/client'); + const { drizzle } = require('./libsql') as typeof import('./libsql'); const instance = createClient(connection as LibsqlConfig); - return libsqlDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'mysql2': { const { createConnection } = require('mysql2/promise') as typeof import('mysql2/promise'); @@ -212,50 +205,57 @@ export const drizzle = < return new Promise((res, rej) => { createConnection(connection as Mysql2Config).then((instance) => { try { - res(mysql2Drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); + const { drizzle } = require('./mysql2') as typeof import('./mysql2'); + res(drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); } catch (e) { rej(e); } }).catch((e) => rej(e)); - }); + }) as any; } case 'neon-http': { const { neon } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); const { connectionString, options } = connection as MonodriverNeonHttpConfig; + const { drizzle } = require('./neon-http') as typeof import('./neon-http'); const instance = neon(connectionString, options); - return neonHttpDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { const { Pool } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); + const { drizzle } = require('./neon-serverless') as typeof import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); - return neonDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'planetscale': { const { Client } = require('@planetscale/database') as typeof import('@planetscale/database'); + const { drizzle } = require('./planetscale-serverless') as typeof import('./planetscale-serverless'); const instance = new Client( connection as PlanetscaleConfig, ); - return planetscaleDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } - case 'postgres.js': { + case 'postgres-js': { const client = require('postgres') as typeof import('postgres'); + const { drizzle } = require('./postgres-js') as typeof import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); - return postgresJSDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { const { connect } = require('@tidbcloud/serverless') as typeof import('@tidbcloud/serverless'); + const { drizzle } = require('./tidb-serverless') as typeof import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); - return tidbDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { const { sql } = require('@vercel/postgres') as typeof import('@vercel/postgres'); + const { drizzle } = require('./vercel-postgres') as typeof import('./vercel-postgres'); - return vercelDrizzle(sql, drizzleConfig) as any; + return drizzle(sql, drizzleConfig) as any; } } }; From 493dd13608d03e958038dfba3e612d7883732b57 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 16:33:41 +0300 Subject: [PATCH 105/152] Returned async imports due to conflicts --- drizzle-orm/src/monodriver.ts | 82 +++++++++++++++-------------------- 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 81e7b7396e..8729ec92d9 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -73,11 +73,11 @@ type ClientDrizzleInstanceMap> = { 'vercel-postgres': VercelPgDatabase; 'aws-data-api-pg': AwsDataApiPgDatabase; planetscale: PlanetScaleDatabase; - mysql2: Promise>; + mysql2: MySql2Database; 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; - 'bun-sqlite': Promise>; + 'bun-sqlite': BunSQLiteDatabase; 'better-sqlite3': BetterSQLite3Database; }; @@ -141,10 +141,10 @@ type DetermineClient< TParams extends InitializerParams, > = ClientDrizzleInstanceMap[TParams['client']]; -export const drizzle = < +export const drizzle = async < TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): DetermineClient => { +>(params: TParams): Promise> => { const { client, connection } = params; const drizzleConfig = params as DrizzleConfig; delete ( drizzleConfig).client; @@ -152,85 +152,71 @@ export const drizzle = < switch (client) { case 'node-postgres': { - const { Pool } = require('pg') as typeof import('pg'); - const { drizzle } = require('./node-postgres') as typeof import('./node-postgres'); + const { Pool } = await import('pg'); + const { drizzle } = await import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); return drizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { - const { RDSDataClient } = require('@aws-sdk/client-rds-data') as typeof import('@aws-sdk/client-rds-data'); - const { drizzle } = require('./aws-data-api/pg') as typeof import('./aws-data-api/pg'); + const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const { drizzle } = await import('./aws-data-api/pg'); const instance = new RDSDataClient(connection); return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { - const Client = require('better-sqlite3') as typeof import('better-sqlite3'); + const { default: Client } = await import('better-sqlite3'); const { filename, options } = connection as BetterSQLite3DatabaseConfig; - const { drizzle } = require('./better-sqlite3') as typeof import('./better-sqlite3'); + const { drizzle } = await import('./better-sqlite3'); const instance = new Client(filename, options); return drizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - return new Promise((res, rej) => { - import('bun:sqlite').then(({ Database: Client }) => { - try { - const { filename, options } = connection as BunSqliteDatabaseConfig; - const { drizzle } = require('./bun-sqlite') as typeof import('./bun-sqlite'); - const instance = new Client(filename, options); + const { Database: Client } = await import('bun:sqlite'); + const { filename, options } = connection as BunSqliteDatabaseConfig; + const { drizzle } = await import('./bun-sqlite'); + const instance = new Client(filename, options); - res(drizzle(instance, drizzleConfig) as any); - } catch (e) { - rej(e); - } - }).catch((e) => rej(e)); - }) as any; + return drizzle(instance, drizzleConfig) as any; } case 'd1': { - const { drizzle } = require('./d1') as typeof import('./d1'); + const { drizzle } = await import('./d1'); return drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { - const { createClient } = require('@libsql/client') as typeof import('@libsql/client'); - const { drizzle } = require('./libsql') as typeof import('./libsql'); + const { createClient } = await import('@libsql/client'); + const { drizzle } = await import('./libsql'); const instance = createClient(connection as LibsqlConfig); return drizzle(instance, drizzleConfig) as any; } case 'mysql2': { - const { createConnection } = require('mysql2/promise') as typeof import('mysql2/promise'); + const { createConnection } = await import('mysql2/promise'); + const instance = await createConnection(connection as Mysql2Config); + const { drizzle } = await import('./mysql2'); - return new Promise((res, rej) => { - createConnection(connection as Mysql2Config).then((instance) => { - try { - const { drizzle } = require('./mysql2') as typeof import('./mysql2'); - res(drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); - } catch (e) { - rej(e); - } - }).catch((e) => rej(e)); - }) as any; + return drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; } case 'neon-http': { - const { neon } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); + const { neon } = await import('@neondatabase/serverless'); const { connectionString, options } = connection as MonodriverNeonHttpConfig; - const { drizzle } = require('./neon-http') as typeof import('./neon-http'); + const { drizzle } = await import('./neon-http'); const instance = neon(connectionString, options); return drizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { - const { Pool } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); - const { drizzle } = require('./neon-serverless') as typeof import('./neon-serverless'); + const { Pool } = await import('@neondatabase/serverless'); + const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'planetscale': { - const { Client } = require('@planetscale/database') as typeof import('@planetscale/database'); - const { drizzle } = require('./planetscale-serverless') as typeof import('./planetscale-serverless'); + const { Client } = await import('@planetscale/database'); + const { drizzle } = await import('./planetscale-serverless'); const instance = new Client( connection as PlanetscaleConfig, ); @@ -238,22 +224,22 @@ export const drizzle = < return drizzle(instance, drizzleConfig) as any; } case 'postgres-js': { - const client = require('postgres') as typeof import('postgres'); - const { drizzle } = require('./postgres-js') as typeof import('./postgres-js'); + const { default: client } = await import('postgres'); + const { drizzle } = await import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); return drizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { - const { connect } = require('@tidbcloud/serverless') as typeof import('@tidbcloud/serverless'); - const { drizzle } = require('./tidb-serverless') as typeof import('./tidb-serverless'); + const { connect } = await import('@tidbcloud/serverless'); + const { drizzle } = await import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { - const { sql } = require('@vercel/postgres') as typeof import('@vercel/postgres'); - const { drizzle } = require('./vercel-postgres') as typeof import('./vercel-postgres'); + const { sql } = await import('@vercel/postgres'); + const { drizzle } = await import('./vercel-postgres'); return drizzle(sql, drizzleConfig) as any; } From 6c6394d7d4d9d1c945e9b4e2f5e57f06fe0e81f8 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 18:16:08 +0300 Subject: [PATCH 106/152] More comnprehensive import errors --- drizzle-orm/src/monodriver.ts | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 8729ec92d9..2f9557b01b 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -141,6 +141,12 @@ type DetermineClient< TParams extends InitializerParams, > = ClientDrizzleInstanceMap[TParams['client']]; +const importError = (libName: string) => { + throw new Error( + `Drizzle init error: unable to import selected database driver library '${libName}' - make sure it is installed.`, + ); +}; + export const drizzle = async < TSchema extends Record, TParams extends InitializerParams, @@ -152,21 +158,23 @@ export const drizzle = async < switch (client) { case 'node-postgres': { - const { Pool } = await import('pg'); + const { Pool } = await import('pg').catch(() => importError('pg')); const { drizzle } = await import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); return drizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { - const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => + importError('@aws-sdk/client-rds-data') + ); const { drizzle } = await import('./aws-data-api/pg'); const instance = new RDSDataClient(connection); return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { - const { default: Client } = await import('better-sqlite3'); + const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); const { filename, options } = connection as BetterSQLite3DatabaseConfig; const { drizzle } = await import('./better-sqlite3'); const instance = new Client(filename, options); @@ -174,7 +182,7 @@ export const drizzle = async < return drizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - const { Database: Client } = await import('bun:sqlite'); + const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); const { filename, options } = connection as BunSqliteDatabaseConfig; const { drizzle } = await import('./bun-sqlite'); const instance = new Client(filename, options); @@ -186,21 +194,21 @@ export const drizzle = async < return drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { - const { createClient } = await import('@libsql/client'); + const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); const { drizzle } = await import('./libsql'); const instance = createClient(connection as LibsqlConfig); return drizzle(instance, drizzleConfig) as any; } case 'mysql2': { - const { createConnection } = await import('mysql2/promise'); + const { createConnection } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); const instance = await createConnection(connection as Mysql2Config); const { drizzle } = await import('./mysql2'); return drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; } case 'neon-http': { - const { neon } = await import('@neondatabase/serverless'); + const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); const { connectionString, options } = connection as MonodriverNeonHttpConfig; const { drizzle } = await import('./neon-http'); const instance = neon(connectionString, options); @@ -208,14 +216,14 @@ export const drizzle = async < return drizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { - const { Pool } = await import('@neondatabase/serverless'); + const { Pool } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'planetscale': { - const { Client } = await import('@planetscale/database'); + const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); const { drizzle } = await import('./planetscale-serverless'); const instance = new Client( connection as PlanetscaleConfig, @@ -224,21 +232,21 @@ export const drizzle = async < return drizzle(instance, drizzleConfig) as any; } case 'postgres-js': { - const { default: client } = await import('postgres'); + const { default: client } = await import('postgres').catch(() => importError('postgres')); const { drizzle } = await import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); return drizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { - const { connect } = await import('@tidbcloud/serverless'); + const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); const { drizzle } = await import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { - const { sql } = await import('@vercel/postgres'); + const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); const { drizzle } = await import('./vercel-postgres'); return drizzle(sql, drizzleConfig) as any; From 1b580d8af79ebe0d519b49c1b97b65403f0b5e42 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 28 Aug 2024 13:08:09 +0300 Subject: [PATCH 107/152] Changed error messge --- drizzle-orm/src/monodriver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 2f9557b01b..2b9a8c2b5d 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -143,7 +143,7 @@ type DetermineClient< const importError = (libName: string) => { throw new Error( - `Drizzle init error: unable to import selected database driver library '${libName}' - make sure it is installed.`, + `Please install '${libName}' for Drizzle ORM to connect to database`, ); }; From b6b8258e341c01a89fdef4d42da4188443ec070e Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 29 Aug 2024 13:02:32 +0300 Subject: [PATCH 108/152] Improved params destructurization --- drizzle-orm/src/monodriver.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 2b9a8c2b5d..b2b82af3fd 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -151,10 +151,7 @@ export const drizzle = async < TSchema extends Record, TParams extends InitializerParams, >(params: TParams): Promise> => { - const { client, connection } = params; - const drizzleConfig = params as DrizzleConfig; - delete ( drizzleConfig).client; - delete ( drizzleConfig).connection; + const { client, connection, ...drizzleConfig } = params; switch (client) { case 'node-postgres': { From 4f7d70355138b0b44e98aea36555f9d9bda02f59 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Mon, 2 Sep 2024 05:10:29 +0300 Subject: [PATCH 109/152] Functional prototype of SQLite $count --- drizzle-orm/src/operations.ts | 1 + drizzle-orm/src/sqlite-core/db.ts | 11 ++- .../src/sqlite-core/query-builders/count.ts | 78 +++++++++++++++++++ .../sqlite-core/query-builders/count.types.ts | 8 ++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 drizzle-orm/src/sqlite-core/query-builders/count.ts create mode 100644 drizzle-orm/src/sqlite-core/query-builders/count.types.ts diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index 492bb3f2a4..6fb5cbd2ea 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -21,6 +21,7 @@ export type OptionalKeyOnly< : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey : never : never; +// TODO: SQL -> SQLWrapper export type SelectedFieldsFlat = Record< string, TColumn | SQL | SQL.Aliased diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 65f807d084..97347977ce 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -2,7 +2,7 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { QueryBuilder, @@ -21,10 +21,12 @@ import type { import type { SQLiteTable } from '~/sqlite-core/table.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; +import { SQLiteCountBuilderAsync } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import { SQLiteRaw } from './query-builders/raw.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { SQLiteViewBase } from './view-base.ts'; export class BaseSQLiteDatabase< TResultKind extends 'sync' | 'async', @@ -134,6 +136,13 @@ export class BaseSQLiteDatabase< }; } + $count( + source: TSource, + filters?: SQL, + ) { + return new SQLiteCountBuilderAsync({ source, filters, dialect: this.dialect, session: this.session }); + } + /** * Incorporates a previously defined CTE (using `$with`) into the main query. * diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts new file mode 100644 index 0000000000..6d6f16e788 --- /dev/null +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -0,0 +1,78 @@ +import { entityKind, sql } from '~/index.ts'; +import type { SQLWrapper } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; +import type { SQLiteDialect } from '../dialect.ts'; +import type { SQLiteSession } from '../session.ts'; +import type { SQLiteTable } from '../table.ts'; + +export class SQLiteCountBuilderAsync< + TSession extends SQLiteSession<'async' | 'sync', any, any, any>, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static readonly [entityKind] = 'SQLiteCountBuilderAsync'; + [Symbol.toStringTag] = 'SQLiteCountBuilderAsync'; + + private session: TSession; + + private static buildEmbeddedCount( + source: SQLiteTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: SQLiteTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; + } + + constructor( + readonly params: { + source: SQLiteTable | SQL | SQLWrapper; + filters?: SQL; + dialect: SQLiteDialect; + session: TSession; + }, + ) { + super(SQLiteCountBuilderAsync.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.session = params.session; + + this.sql = SQLiteCountBuilderAsync.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.values(this.sql)).then((it) => it![0]![0] as number).then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.types.ts b/drizzle-orm/src/sqlite-core/query-builders/count.types.ts new file mode 100644 index 0000000000..d346c187ce --- /dev/null +++ b/drizzle-orm/src/sqlite-core/query-builders/count.types.ts @@ -0,0 +1,8 @@ +import type { SQL, SQLWrapper } from '~/index'; +import type { SQLiteTable } from '../table'; +import type { SQLiteViewBase } from '../view-base'; + +export type SQLiteCountConfig = { + source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper; + filters?: SQL; +}; From e009be7a7b454668595176e23d25e4eba6b4254d Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 2 Sep 2024 14:29:41 +0300 Subject: [PATCH 110/152] Added pg, mysql; Added tests, type tests for $count --- drizzle-orm/src/mysql-core/db.ts | 11 ++- .../src/mysql-core/query-builders/count.ts | 82 +++++++++++++++++++ drizzle-orm/src/pg-core/db.ts | 11 ++- .../src/pg-core/query-builders/count.ts | 81 ++++++++++++++++++ drizzle-orm/src/sqlite-core/db.ts | 8 +- .../src/sqlite-core/query-builders/count.ts | 17 ++-- .../sqlite-core/query-builders/count.types.ts | 8 -- drizzle-orm/type-tests/mysql/count.ts | 61 ++++++++++++++ drizzle-orm/type-tests/pg/count.ts | 61 ++++++++++++++ drizzle-orm/type-tests/sqlite/count.ts | 61 ++++++++++++++ 10 files changed, 379 insertions(+), 22 deletions(-) create mode 100644 drizzle-orm/src/mysql-core/query-builders/count.ts create mode 100644 drizzle-orm/src/pg-core/query-builders/count.ts delete mode 100644 drizzle-orm/src/sqlite-core/query-builders/count.types.ts create mode 100644 drizzle-orm/type-tests/mysql/count.ts create mode 100644 drizzle-orm/type-tests/pg/count.ts create mode 100644 drizzle-orm/type-tests/sqlite/count.ts diff --git a/drizzle-orm/src/mysql-core/db.ts b/drizzle-orm/src/mysql-core/db.ts index 8df6ff3439..419359022c 100644 --- a/drizzle-orm/src/mysql-core/db.ts +++ b/drizzle-orm/src/mysql-core/db.ts @@ -3,10 +3,11 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { MySqlDialect } from './dialect.ts'; +import { MySqlCountBuilder } from './query-builders/count.ts'; import { MySqlDeleteBase, MySqlInsertBuilder, @@ -27,6 +28,7 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { MySqlTable } from './table.ts'; +import type { MySqlViewBase } from './view-base.ts'; export class MySqlDatabase< TQueryResult extends MySqlQueryResultHKT, @@ -134,6 +136,13 @@ export class MySqlDatabase< }; } + $count( + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, + filters?: SQL, + ) { + return new MySqlCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + } + /** * Incorporates a previously defined CTE (using `$with`) into the main query. * diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts new file mode 100644 index 0000000000..751ba61c72 --- /dev/null +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -0,0 +1,82 @@ +import { entityKind, sql } from '~/index.ts'; +import type { SQLWrapper } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; +import type { MySqlDialect } from '../dialect.ts'; +import type { MySqlSession } from '../session.ts'; +import type { MySqlTable } from '../table.ts'; +import type { MySqlViewBase } from '../view-base.ts'; + +export class MySqlCountBuilder< + TSession extends MySqlSession, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static readonly [entityKind] = 'MySqlCountBuilder'; + [Symbol.toStringTag] = 'MySqlCountBuilder'; + + private session: TSession; + + private static buildEmbeddedCount( + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; + } + + constructor( + readonly params: { + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper; + filters?: SQL; + dialect: MySqlDialect; + session: TSession; + }, + ) { + super(MySqlCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.session = params.session; + + this.sql = MySqlCountBuilder.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.all(this.sql)).then((it) => { + return (<[{ 'count(*)': number }]> it)[0]['count(*)']; + }) + .then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 4e8d2f354b..3c8da44f15 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -19,15 +19,17 @@ import type { PgTable } from '~/pg-core/table.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { PgColumn } from './columns/index.ts'; +import { PgCountBuilder } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import { PgRaw } from './query-builders/raw.ts'; import { PgRefreshMaterializedView } from './query-builders/refresh-materialized-view.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { PgViewBase } from './view-base.ts'; import type { PgMaterializedView } from './view.ts'; export class PgDatabase< @@ -135,6 +137,13 @@ export class PgDatabase< }; } + $count( + source: PgTable | PgViewBase | SQL | SQLWrapper, + filters?: SQL, + ) { + return new PgCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + } + /** * Incorporates a previously defined CTE (using `$with`) into the main query. * diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts new file mode 100644 index 0000000000..7ccd722a07 --- /dev/null +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -0,0 +1,81 @@ +import { entityKind, sql } from '~/index.ts'; +import type { SQLWrapper } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; +import type { PgDialect } from '../dialect.ts'; +import type { PgSession } from '../session.ts'; +import type { PgTable } from '../table.ts'; + +export class PgCountBuilder< + TSession extends PgSession, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static readonly [entityKind] = 'PgCountBuilder'; + [Symbol.toStringTag] = 'PgCountBuilder'; + + private session: TSession; + + private static buildEmbeddedCount( + source: PgTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: PgTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters};`; + } + + constructor( + readonly params: { + source: PgTable | SQL | SQLWrapper; + filters?: SQL; + dialect: PgDialect; + session: TSession; + }, + ) { + super(PgCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.session = params.session; + + this.sql = PgCountBuilder.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.all(this.sql)).then((it) => { + return (<[{ count: number }]> it)[0]['count'] as number; + }) + .then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 97347977ce..75b088f6de 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -21,7 +21,7 @@ import type { import type { SQLiteTable } from '~/sqlite-core/table.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; -import { SQLiteCountBuilderAsync } from './query-builders/count.ts'; +import { SQLiteCountBuilder } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import { SQLiteRaw } from './query-builders/raw.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; @@ -136,11 +136,11 @@ export class BaseSQLiteDatabase< }; } - $count( - source: TSource, + $count( + source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new SQLiteCountBuilderAsync({ source, filters, dialect: this.dialect, session: this.session }); + return new SQLiteCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); } /** diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 6d6f16e788..ed6cd9a1da 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -4,9 +4,10 @@ import { SQL } from '~/sql/sql.ts'; import type { SQLiteDialect } from '../dialect.ts'; import type { SQLiteSession } from '../session.ts'; import type { SQLiteTable } from '../table.ts'; +import type { SQLiteView } from '../view.ts'; -export class SQLiteCountBuilderAsync< - TSession extends SQLiteSession<'async' | 'sync', any, any, any>, +export class SQLiteCountBuilder< + TSession extends SQLiteSession, > extends SQL implements Promise, SQLWrapper { private sql: SQL; @@ -16,14 +17,14 @@ export class SQLiteCountBuilderAsync< private session: TSession; private static buildEmbeddedCount( - source: SQLiteTable | SQL | SQLWrapper, + source: SQLiteTable | SQLiteView | SQL | SQLWrapper, filters?: SQL, ): SQL { return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( - source: SQLiteTable | SQL | SQLWrapper, + source: SQLiteTable | SQLiteView | SQL | SQLWrapper, filters?: SQL, ): SQL { return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; @@ -31,17 +32,17 @@ export class SQLiteCountBuilderAsync< constructor( readonly params: { - source: SQLiteTable | SQL | SQLWrapper; + source: SQLiteTable | SQLiteView | SQL | SQLWrapper; filters?: SQL; dialect: SQLiteDialect; session: TSession; }, ) { - super(SQLiteCountBuilderAsync.buildEmbeddedCount(params.source, params.filters).queryChunks); + super(SQLiteCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); this.session = params.session; - this.sql = SQLiteCountBuilderAsync.buildCount( + this.sql = SQLiteCountBuilder.buildCount( params.source, params.filters, ); @@ -51,7 +52,7 @@ export class SQLiteCountBuilderAsync< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.values(this.sql)).then((it) => it![0]![0] as number).then( + return Promise.resolve(this.session.values(this.sql)).then((it) => it[0]![0] as number).then( onfulfilled, onrejected, ); diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.types.ts b/drizzle-orm/src/sqlite-core/query-builders/count.types.ts deleted file mode 100644 index d346c187ce..0000000000 --- a/drizzle-orm/src/sqlite-core/query-builders/count.types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { SQL, SQLWrapper } from '~/index'; -import type { SQLiteTable } from '../table'; -import type { SQLiteViewBase } from '../view-base'; - -export type SQLiteCountConfig = { - source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper; - filters?: SQL; -}; diff --git a/drizzle-orm/type-tests/mysql/count.ts b/drizzle-orm/type-tests/mysql/count.ts new file mode 100644 index 0000000000..d9b9ba9ff6 --- /dev/null +++ b/drizzle-orm/type-tests/mysql/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { int, mysqlTable, serial, text } from '~/mysql-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = mysqlTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; diff --git a/drizzle-orm/type-tests/pg/count.ts b/drizzle-orm/type-tests/pg/count.ts new file mode 100644 index 0000000000..9ed5eeaf91 --- /dev/null +++ b/drizzle-orm/type-tests/pg/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { integer, pgTable, serial, text } from '~/pg-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = pgTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: integer('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; diff --git a/drizzle-orm/type-tests/sqlite/count.ts b/drizzle-orm/type-tests/sqlite/count.ts new file mode 100644 index 0000000000..04350f000c --- /dev/null +++ b/drizzle-orm/type-tests/sqlite/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { integer, sqliteTable, text } from '~/sqlite-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = sqliteTable('names', { + id: integer('id').primaryKey(), + name: text('name'), + authorId: integer('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; From 672b4414e14f236d9ce01948170139e42dc053e8 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 14:28:04 +0300 Subject: [PATCH 111/152] Added missing runtime tests --- integration-tests/tests/mysql/mysql-common.ts | 209 ++++++++++++++++++ integration-tests/tests/pg/pg-common.ts | 209 ++++++++++++++++++ .../tests/sqlite/sqlite-common.ts | 209 ++++++++++++++++++ 3 files changed, 627 insertions(+) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 58f7a1e2cf..05c69cadae 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3577,6 +3577,215 @@ export function tests(driver?: string) { await db.execute(sql`drop view ${newYorkers1}`); }); + + test('$count separate', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(4); + }); + + test('$count embedded', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + }); + + test('$count separate reuse', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.$count(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual(4); + expect(count2).toStrictEqual(5); + expect(count3).toStrictEqual(6); + }); + + test('$count embedded reuse', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + expect(count2).toStrictEqual([ + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + ]); + expect(count3).toStrictEqual([ + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + ]); + }); + + test('$count separate with filters', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable, gt(countTestTable.id, 1)); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(3); + }); + + test('$count embedded with filters', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable, gt(countTestTable.id, 1)), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 3 }, + { count: 3 }, + { count: 3 }, + ]); + }); }); test('limit 0', async (ctx) => { diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index c48a533f96..3f3dd75cce 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4660,5 +4660,214 @@ export function tests() { jsonbNumberField: testNumber, }]); }); + + test('$count separate', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(4); + }); + + test('$count embedded', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + }); + + test('$count separate reuse', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.$count(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual(4); + expect(count2).toStrictEqual(5); + expect(count3).toStrictEqual(6); + }); + + test('$count embedded reuse', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + expect(count2).toStrictEqual([ + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + ]); + expect(count3).toStrictEqual([ + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + ]); + }); + + test('$count separate with filters', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable, gt(countTestTable.id, 1)); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(3); + }); + + test('$count embedded with filters', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable, gt(countTestTable.id, 1)), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 3 }, + { count: 3 }, + { count: 3 }, + ]); + }); }); } diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index be452bcf14..ed13f5b7b1 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2679,6 +2679,215 @@ export function tests() { expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); } }); + + test('$count separate', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(4); + }); + + test('$count embedded', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + }); + + test('$count separate reuse', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.$count(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.run(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual(4); + expect(count2).toStrictEqual(5); + expect(count3).toStrictEqual(6); + }); + + test('$count embedded reuse', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.run(sql`drop table ${countTestTable}`); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + expect(count2).toStrictEqual([ + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + ]); + expect(count3).toStrictEqual([ + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + ]); + }); + + test('$count separate with filters', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable, gt(countTestTable.id, 1)); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(3); + }); + + test('$count embedded with filters', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable, gt(countTestTable.id, 1)), + }).from(countTestTable); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 3 }, + { count: 3 }, + { count: 3 }, + ]); + }); }); test('table configs: unique third param', () => { From 951e5496bd3a53bd76c261e9d9af45ee5461e105 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 12 Aug 2024 12:40:27 +0300 Subject: [PATCH 112/152] LibSQL improvements Added: - handling alteting columns in libsql - new json statement for recreation table for sqlite and libsql - push updated for sqlite and libsql - tests --- .../src/cli/commands/libSqlPushUtils.ts | 327 +++++ drizzle-kit/src/cli/commands/migrate.ts | 94 +- drizzle-kit/src/cli/commands/push.ts | 123 +- .../src/cli/commands/sqlitePushUtils.ts | 300 ++-- drizzle-kit/src/cli/commands/utils.ts | 5 + drizzle-kit/src/cli/schema.ts | 12 +- drizzle-kit/src/cli/validations/cli.ts | 3 +- drizzle-kit/src/jsonStatements.ts | 200 ++- drizzle-kit/src/snapshotsDiffer.ts | 437 +++++- drizzle-kit/src/sqlgenerator.ts | 389 +++++- drizzle-kit/src/statementCombiner.ts | 387 ++++++ drizzle-kit/src/utils.ts | 13 + drizzle-kit/tests/libsql-statements.test.ts | 835 +++++++++++ drizzle-kit/tests/push/libsql.test.ts | 744 ++++++++++ drizzle-kit/tests/push/sqlite.test.ts | 1233 ++++++++++++----- drizzle-kit/tests/schemaDiffer.ts | 273 +++- .../libsql-statements-combiner.test.ts | 1209 ++++++++++++++++ .../sqilte-statements-combiner.test.ts | 778 +++++++++++ 18 files changed, 6762 insertions(+), 600 deletions(-) create mode 100644 drizzle-kit/src/cli/commands/libSqlPushUtils.ts create mode 100644 drizzle-kit/src/statementCombiner.ts create mode 100644 drizzle-kit/tests/libsql-statements.test.ts create mode 100644 drizzle-kit/tests/push/libsql.test.ts create mode 100644 drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts create mode 100644 drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts new file mode 100644 index 0000000000..537eee0a5a --- /dev/null +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -0,0 +1,327 @@ +import chalk from 'chalk'; + +import { JsonStatement } from 'src/jsonStatements'; +import { findAddedAndRemoved, SQLiteDB } from 'src/utils'; +import { SQLiteSchemaInternal, SQLiteSchemaSquashed, SQLiteSquasher } from '../../serializer/sqliteSchema'; +import { + CreateSqliteIndexConvertor, + fromJson, + LibSQLModifyColumn, + SQLiteCreateTableConvertor, + SQLiteDropTableConvertor, + SqliteRenameTableConvertor, +} from '../../sqlgenerator'; + +export const getOldTableName = ( + tableName: string, + meta: SQLiteSchemaInternal['_meta'], +) => { + for (const key of Object.keys(meta.tables)) { + const value = meta.tables[key]; + if (`"${tableName}"` === value) { + return key.substring(1, key.length - 1); + } + } + return tableName; +}; + +export const _moveDataStatements = ( + tableName: string, + json: SQLiteSchemaSquashed, + dataLoss: boolean = false, +) => { + const statements: string[] = []; + + statements.push( + new SqliteRenameTableConvertor().convert({ + type: 'rename_table', + tableNameFrom: tableName, + tableNameTo: `__old_push_${tableName}`, + fromSchema: '', + toSchema: '', + }), + ); + + const tableColumns = Object.values(json.tables[tableName].columns); + const referenceData = Object.values(json.tables[tableName].foreignKeys); + const compositePKs = Object.values( + json.tables[tableName].compositePrimaryKeys, + ).map((it) => SQLiteSquasher.unsquashPK(it)); + + statements.push( + new SQLiteCreateTableConvertor().convert({ + type: 'sqlite_create_table', + tableName: tableName, + columns: tableColumns, + referenceData: referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)), + compositePKs, + }), + ); + + if (!dataLoss) { + const columns = Object.keys(json.tables[tableName].columns).map( + (c) => `"${c}"`, + ); + + statements.push( + `INSERT INTO \`${tableName}\`(${ + columns.join( + ', ', + ) + }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, + ); + } + + statements.push( + new SQLiteDropTableConvertor().convert({ + type: 'drop_table', + tableName: `__old_push_${tableName}`, + schema: '', + }), + ); + + for (const idx of Object.values(json.tables[tableName].indexes)) { + statements.push( + new CreateSqliteIndexConvertor().convert({ + type: 'create_index', + tableName: tableName, + schema: '', + data: idx, + }), + ); + } + + return statements; +}; + +export const libSqlLogSuggestionsAndReturn = async ( + connection: SQLiteDB, + statements: JsonStatement[], + json1: SQLiteSchemaSquashed, + json2: SQLiteSchemaSquashed, + meta: SQLiteSchemaInternal['_meta'], +) => { + let shouldAskForApprove = false; + const statementsToExecute: string[] = []; + const infoToPrint: string[] = []; + + const tablesToRemove: string[] = []; + const columnsToRemove: string[] = []; + const tablesToTruncate: string[] = []; + + for (const statement of statements) { + if (statement.type === 'drop_table') { + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.tableName, + ) + } table with ${count} items`, + ); + tablesToRemove.push(statement.tableName); + shouldAskForApprove = true; + } + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if (statement.type === 'alter_table_drop_column') { + const tableName = statement.tableName; + + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${tableName} table with ${count} items`, + ); + columnsToRemove.push(`${tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if ( + statement.type === 'sqlite_alter_table_add_column' + && statement.column.notNull + && !statement.column.default + ) { + const newTableName = statement.tableName; + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${newTableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + statement.column.name, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(newTableName); + statementsToExecute.push(`delete from ${newTableName};`); + + shouldAskForApprove = true; + } + + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + const tableName = statement.tableName; + + if ( + statement.type === 'alter_table_alter_column_set_notnull' + && typeof statement.columnDefault === 'undefined' + ) { + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null constraint to ${ + chalk.underline( + statement.columnName, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(tableName); + statementsToExecute.push(`delete from \`${tableName}\``); + shouldAskForApprove = true; + } + } + + const modifyStatements = new LibSQLModifyColumn().convert(statement, json2); + + statementsToExecute.push( + ...(Array.isArray(modifyStatements) ? modifyStatements : [modifyStatements]), + ); + } else if (statement.type === 'recreate_table') { + const tableName = statement.tableName; + + const oldTableName = getOldTableName(tableName, meta); + + const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); + const currentColumnNames = Object.keys(json2.tables[tableName].columns); + const { removedColumns, addedColumns } = findAddedAndRemoved( + prevColumnNames, + currentColumnNames, + ); + + if (removedColumns.length) { + for (const removedColumn of removedColumns) { + const res = await connection.query<{ count: string }>( + `select count(\`${tableName}\`.\`${removedColumn}\`) as count from \`${tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + removedColumn, + ) + } column in ${tableName} table with ${count} items`, + ); + columnsToRemove.push(removedColumn); + shouldAskForApprove = true; + } + } + } + + if (addedColumns.length) { + for (const addedColumn of addedColumns) { + const [res] = await connection.query<{ count: string }>( + `select count(\`${tableName}\`.\`${addedColumn}\`) as count from \`${tableName}\``, + ); + + const columnConf = json2.tables[tableName].columns[addedColumn]; + + const count = Number(res.count); + if (count > 0 && columnConf.notNull && !columnConf.default) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + addedColumn, + ) + } column without default value, which contains ${count} items`, + ); + shouldAskForApprove = true; + tablesToTruncate.push(tableName); + } + } + } + + statementsToExecute.push(..._moveDataStatements(tableName, json2)); + + const tablesReferencingCurrent: string[] = []; + + for (const table of Object.values(json2.tables)) { + const tablesRefs = Object.values(json2.tables[table.name].foreignKeys) + .filter((t) => SQLiteSquasher.unsquashPushFK(t).tableTo === tableName) + .map((it) => SQLiteSquasher.unsquashPushFK(it).tableFrom); + + tablesReferencingCurrent.push(...tablesRefs); + } + + const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; + + for (const table of uniqueTableRefs) { + statementsToExecute.push(..._moveDataStatements(table, json2)); + } + } else if (statement.type === 'alter_table_alter_column_set_generated') { + const tableName = statement.tableName; + + const res = await connection.query<{ count: string }>( + `select count("${statement.columnName}") as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${tableName} table with ${count} items`, + ); + columnsToRemove.push(`${tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else { + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } + } + + return { + statementsToExecute: [...new Set(statementsToExecute)], + shouldAskForApprove, + infoToPrint, + columnsToRemove: [...new Set(columnsToRemove)], + tablesToTruncate: [...new Set(tablesToTruncate)], + tablesToRemove: [...new Set(tablesToRemove)], + }; +}; diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 0672fe734a..664e7da022 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,6 +13,7 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; +import { JsonStatement } from 'src/jsonStatements'; import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; @@ -20,6 +21,7 @@ import { MySqlSchema, mysqlSchema, squashMysqlScheme } from '../../serializer/my import { PgSchema, pgSchema, squashPgScheme } from '../../serializer/pgSchema'; import { SQLiteSchema, sqliteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { + applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySingleStoreSnapshotsDiff, @@ -36,7 +38,7 @@ import { } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; -import { Prefix } from '../validations/common'; +import { Driver, Prefix } from '../validations/common'; import { withStyle } from '../validations/outputs'; import { isRenamePromptItem, @@ -490,6 +492,7 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const driver = config.driver; try { assertV1OutFolder(outFolder); @@ -521,14 +524,34 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const squashedPrev = squashSqliteScheme(validatedPrev); const squashedCur = squashSqliteScheme(validatedCur); - const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - ); + let sqlStatements: string[]; + let _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; + + if (driver === 'turso') { + ({ sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + )); + } else { + ({ sqlStatements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + )); + } writeResult({ cur, @@ -549,6 +572,57 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { export const prepareSQLitePush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, + driver?: Driver, +) => { + const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); + + const validatedPrev = sqliteSchema.parse(prev); + const validatedCur = sqliteSchema.parse(cur); + + const squashedPrev = squashSqliteScheme(validatedPrev, 'push'); + const squashedCur = squashSqliteScheme(validatedCur, 'push'); + + let sqlStatements: string[]; + let statements: JsonStatement[]; + let _meta: { + schemas: {}; + tables: {}; + columns: {}; + } | undefined; + if (driver === 'turso') { + ({ sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + )); + } else { + ({ sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + )); + } + + return { + sqlStatements, + statements, + squashedPrev, + squashedCur, + meta: _meta, + }; +}; + +export const prepareLibSQLPush = async ( + schemaPath: string | string[], + snapshot: SQLiteSchema, ) => { const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); @@ -558,7 +632,7 @@ export const prepareSQLitePush = async ( const squashedPrev = squashSqliteScheme(validatedPrev, 'push'); const squashedCur = squashSqliteScheme(validatedCur, 'push'); - const { sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( + const { sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( squashedPrev, squashedCur, tablesResolver, diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index d54f8c6ebe..e8aaf2e2bf 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -7,6 +7,7 @@ import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; +import { libSqlLogSuggestionsAndReturn } from './libSqlPushUtils'; import { filterStatements as mySqlFilterStatements, logSuggestionsAndReturn as mySqlLogSuggestionsAndReturn, @@ -76,8 +77,6 @@ export const mysqlPush = async ( }); if (verbose) { - console.log(); - // console.log(chalk.gray('Verbose logs:')); console.log( withStyle.warning('You are about to execute current statements:'), ); @@ -439,8 +438,128 @@ export const sqlitePush = async ( } = await sqliteSuggestions( db, statements.statements, + statements.squashedPrev, statements.squashedCur, + statements.meta!, + ); + + if (verbose && statementsToExecute.length > 0) { + console.log(); + console.log( + withStyle.warning('You are about to execute current statements:'), + ); + console.log(); + console.log(statementsToExecute.map((s) => chalk.blue(s)).join('\n')); + console.log(); + } + + if (!force && strict) { + if (!shouldAskForApprove) { + const { status, data } = await render( + new Select(['No, abort', `Yes, I want to execute all statements`]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + } + + if (!force && shouldAskForApprove) { + console.log(withStyle.warning('Found data-loss statements:')); + console.log(infoToPrint.join('\n')); + console.log(); + console.log( + chalk.red.bold( + 'THIS ACTION WILL CAUSE DATA LOSS AND CANNOT BE REVERTED\n', + ), + ); + + console.log(chalk.white('Do you still want to push changes?')); + + const { status, data } = await render( + new Select([ + 'No, abort', + `Yes, I want to${ + tablesToRemove.length > 0 + ? ` remove ${tablesToRemove.length} ${tablesToRemove.length > 1 ? 'tables' : 'table'},` + : ' ' + }${ + columnsToRemove.length > 0 + ? ` remove ${columnsToRemove.length} ${columnsToRemove.length > 1 ? 'columns' : 'column'},` + : ' ' + }${ + tablesToTruncate.length > 0 + ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` + : '' + }` + .trimEnd() + .replace(/(^,)|(,$)/g, '') + .replace(/ +(?= )/g, ''), + ]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + + if (statementsToExecute.length === 0) { + render(`\n[${chalk.blue('i')}] No changes detected`); + } else { + if (!('driver' in credentials)) { + await db.query('begin'); + try { + for (const dStmnt of statementsToExecute) { + await db.query(dStmnt); + } + await db.query('commit'); + } catch (e) { + console.error(e); + await db.query('rollback'); + process.exit(1); + } + } else if (credentials.driver === 'turso') { + await db.batch!(statementsToExecute.map((it) => ({ query: it }))); + } + render(`[${chalk.green('✓')}] Changes applied`); + } + } +}; + +export const libSQLPush = async ( + schemaPath: string | string[], + verbose: boolean, + strict: boolean, + credentials: SqliteCredentials, + tablesFilter: string[], + force: boolean, +) => { + const { connectToSQLite } = await import('../connections'); + const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); + + const db = await connectToSQLite(credentials); + const { schema } = await sqlitePushIntrospect(db, tablesFilter); + + const { prepareLibSQLPush } = await import('./migrate'); + + const statements = await prepareLibSQLPush(schemaPath, schema); + + if (statements.sqlStatements.length === 0) { + render(`\n[${chalk.blue('i')}] No changes detected`); + } else { + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + } = await libSqlLogSuggestionsAndReturn( + db, + statements.statements, statements.squashedPrev, + statements.squashedCur, statements.meta!, ); diff --git a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts index 451f035a70..e04546157d 100644 --- a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts +++ b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts @@ -10,7 +10,7 @@ import { } from '../../sqlgenerator'; import type { JsonStatement } from '../../jsonStatements'; -import type { DB, SQLiteDB } from '../../utils'; +import { findAddedAndRemoved, type SQLiteDB } from '../../utils'; export const _moveDataStatements = ( tableName: string, @@ -51,8 +51,16 @@ export const _moveDataStatements = ( // move data if (!dataLoss) { + const columns = Object.keys(json.tables[tableName].columns).map( + (c) => `"${c}"`, + ); + statements.push( - `INSERT INTO "${tableName}" SELECT * FROM "__old_push_${tableName}";`, + `INSERT INTO \`${tableName}\`(${ + columns.join( + ', ', + ) + }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, ); } // drop table with name __old_${tablename} @@ -120,8 +128,6 @@ export const logSuggestionsAndReturn = async ( const schemasToRemove: string[] = []; const tablesToTruncate: string[] = []; - const tablesContext: Record = {}; - for (const statement of statements) { if (statement.type === 'drop_table') { const res = await connection.query<{ count: string }>( @@ -139,248 +145,144 @@ export const logSuggestionsAndReturn = async ( tablesToRemove.push(statement.tableName); shouldAskForApprove = true; } - const stmnt = fromJson([statement], 'sqlite')[0]; - statementsToExecute.push(stmnt); - } else if (statement.type === 'alter_table_drop_column') { - const newTableName = getOldTableName(statement.tableName, meta); - const columnIsPartOfPk = Object.values( - json1.tables[newTableName].compositePrimaryKeys, - ).find((c) => SQLiteSquasher.unsquashPK(c).includes(statement.columnName)); - - const columnIsPartOfIndex = Object.values( - json1.tables[newTableName].indexes, - ).find((c) => SQLiteSquasher.unsquashIdx(c).columns.includes(statement.columnName)); - - const columnIsPk = json1.tables[newTableName].columns[statement.columnName].primaryKey; - - const columnIsPartOfFk = Object.values( - json1.tables[newTableName].foreignKeys, - ).find((t) => - SQLiteSquasher.unsquashPushFK(t).columnsFrom.includes( - statement.columnName, - ) + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); + } else if (statement.type === 'alter_table_drop_column') { + const tableName = statement.tableName; + const columnName = statement.columnName; const res = await connection.query<{ count: string }>( - `select count(*) as count from \`${newTableName}\``, + `select count(\`${tableName}\`.\`${columnName}\`) as count from \`${tableName}\``, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to delete ${ chalk.underline( - statement.columnName, + columnName, ) - } column in ${newTableName} table with ${count} items`, + } column in ${tableName} table with ${count} items`, ); - columnsToRemove.push(`${newTableName}_${statement.columnName}`); + columnsToRemove.push(`${tableName}_${statement.columnName}`); shouldAskForApprove = true; } - if ( - columnIsPk - || columnIsPartOfPk - || columnIsPartOfIndex - || columnIsPartOfFk - ) { - tablesContext[newTableName] = [ - ..._moveDataStatements(statement.tableName, json2, true), - ]; - // check table that have fk to this table - - const tablesReferncingCurrent: string[] = []; - - for (const table of Object.values(json1.tables)) { - const tablesRefs = Object.values(json1.tables[table.name].foreignKeys) - .filter( - (t) => SQLiteSquasher.unsquashPushFK(t).tableTo === newTableName, + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if ( + statement.type === 'sqlite_alter_table_add_column' + && (statement.column.notNull && !statement.column.default) + ) { + const tableName = statement.tableName; + const columnName = statement.column.name; + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + columnName, ) - .map((t) => SQLiteSquasher.unsquashPushFK(t).tableFrom); - - tablesReferncingCurrent.push(...tablesRefs); - } - - const uniqueTableRefs = [...new Set(tablesReferncingCurrent)]; - - for (const table of uniqueTableRefs) { - if (typeof tablesContext[table] === 'undefined') { - tablesContext[table] = [..._moveDataStatements(table, json2)]; - } - } - } else { - if (typeof tablesContext[newTableName] === 'undefined') { - const stmnt = fromJson([statement], 'sqlite')[0]; - statementsToExecute.push(stmnt); - } - } - } else if (statement.type === 'sqlite_alter_table_add_column') { - const newTableName = getOldTableName(statement.tableName, meta); - if (statement.column.notNull && !statement.column.default) { - const res = await connection.query<{ count: string }>( - `select count(*) as count from \`${newTableName}\``, + } column without default value, which contains ${count} items`, ); - const count = Number(res[0].count); - if (count > 0) { - infoToPrint.push( - `· You're about to add not-null ${ - chalk.underline( - statement.column.name, - ) - } column without default value, which contains ${count} items`, - ); - tablesToTruncate.push(newTableName); - statementsToExecute.push(`delete from ${newTableName};`); + tablesToTruncate.push(tableName); + statementsToExecute.push(`delete from ${tableName};`); - shouldAskForApprove = true; - } + shouldAskForApprove = true; } - if (statement.column.primaryKey) { - tablesContext[newTableName] = [ - ..._moveDataStatements(statement.tableName, json2, true), - ]; - const tablesReferncingCurrent: string[] = []; - - for (const table of Object.values(json1.tables)) { - const tablesRefs = Object.values(json1.tables[table.name].foreignKeys) - .filter( - (t) => SQLiteSquasher.unsquashPushFK(t).tableTo === newTableName, - ) - .map((t) => SQLiteSquasher.unsquashPushFK(t).tableFrom); - tablesReferncingCurrent.push(...tablesRefs); - } - - const uniqueTableRefs = [...new Set(tablesReferncingCurrent)]; + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if (statement.type === 'recreate_table') { + const tableName = statement.tableName; + const oldTableName = getOldTableName(tableName, meta); + + const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); + const currentColumnNames = Object.keys(json2.tables[tableName].columns); + const { removedColumns, addedColumns } = findAddedAndRemoved( + prevColumnNames, + currentColumnNames, + ); - for (const table of uniqueTableRefs) { - if (typeof tablesContext[table] === 'undefined') { - tablesContext[table] = [..._moveDataStatements(table, json2)]; - } - } - } else { - if (typeof tablesContext[newTableName] === 'undefined') { - const stmnt = fromJson([statement], 'sqlite')[0]; - statementsToExecute.push(stmnt); - } - } - } else if ( - statement.type === 'alter_table_alter_column_set_type' - || statement.type === 'alter_table_alter_column_set_default' - || statement.type === 'alter_table_alter_column_drop_default' - || statement.type === 'alter_table_alter_column_set_notnull' - || statement.type === 'alter_table_alter_column_drop_notnull' - || statement.type === 'alter_table_alter_column_drop_autoincrement' - || statement.type === 'alter_table_alter_column_set_autoincrement' - || statement.type === 'alter_table_alter_column_drop_pk' - || statement.type === 'alter_table_alter_column_set_pk' - ) { - if ( - !( - statement.type === 'alter_table_alter_column_set_notnull' - && statement.columnPk - ) - ) { - const newTableName = getOldTableName(statement.tableName, meta); - if ( - statement.type === 'alter_table_alter_column_set_notnull' - && typeof statement.columnDefault === 'undefined' - ) { + if (removedColumns.length) { + for (const removedColumn of removedColumns) { const res = await connection.query<{ count: string }>( - `select count(*) as count from \`${newTableName}\``, + `select count(\`${tableName}\`.\`${removedColumn}\`) as count from \`${tableName}\``, ); + const count = Number(res[0].count); if (count > 0) { infoToPrint.push( - `· You're about to add not-null constraint to ${ + `· You're about to delete ${ chalk.underline( - statement.columnName, + removedColumn, ) - } column without default value, which contains ${count} items`, + } column in ${tableName} table with ${count} items`, ); - - tablesToTruncate.push(newTableName); + columnsToRemove.push(removedColumn); shouldAskForApprove = true; } - tablesContext[newTableName] = _moveDataStatements( - statement.tableName, - json1, - true, + } + } + + if (addedColumns.length) { + for (const addedColumn of addedColumns) { + const [res] = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, ); - } else { - if (typeof tablesContext[newTableName] === 'undefined') { - tablesContext[newTableName] = _moveDataStatements( - statement.tableName, - json1, + + const columnConf = json2.tables[tableName].columns[addedColumn]; + + const count = Number(res.count); + if (count > 0 && columnConf.notNull && !columnConf.default) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + addedColumn, + ) + } column without default value to table, which contains ${count} items`, ); + shouldAskForApprove = true; + tablesToTruncate.push(tableName); } } + } - const tablesReferncingCurrent: string[] = []; + statementsToExecute.push(..._moveDataStatements(tableName, json2)); - for (const table of Object.values(json1.tables)) { - const tablesRefs = Object.values(json1.tables[table.name].foreignKeys) - .filter( - (t) => SQLiteSquasher.unsquashPushFK(t).tableTo === newTableName, - ) - .map((t) => { - return getNewTableName( - SQLiteSquasher.unsquashPushFK(t).tableFrom, - meta, - ); - }); - - tablesReferncingCurrent.push(...tablesRefs); - } + const tablesReferencingCurrent: string[] = []; - const uniqueTableRefs = [...new Set(tablesReferncingCurrent)]; + for (const table of Object.values(json2.tables)) { + const tablesRefs = Object.values(json2.tables[table.name].foreignKeys) + .filter((t) => SQLiteSquasher.unsquashPushFK(t).tableTo === tableName) + .map((it) => SQLiteSquasher.unsquashPushFK(it).tableFrom); - for (const table of uniqueTableRefs) { - if (typeof tablesContext[table] === 'undefined') { - tablesContext[table] = [..._moveDataStatements(table, json1)]; - } - } + tablesReferencingCurrent.push(...tablesRefs); } - } else if ( - statement.type === 'create_reference' - || statement.type === 'delete_reference' - || statement.type === 'alter_reference' - ) { - const fk = SQLiteSquasher.unsquashPushFK(statement.data); - if (typeof tablesContext[statement.tableName] === 'undefined') { - tablesContext[statement.tableName] = _moveDataStatements( - statement.tableName, - json2, - ); - } - } else if ( - statement.type === 'create_composite_pk' - || statement.type === 'alter_composite_pk' - || statement.type === 'delete_composite_pk' - || statement.type === 'create_unique_constraint' - || statement.type === 'delete_unique_constraint' - ) { - const newTableName = getOldTableName(statement.tableName, meta); - if (typeof tablesContext[newTableName] === 'undefined') { - tablesContext[newTableName] = _moveDataStatements( - statement.tableName, - json2, - ); + const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; + + for (const table of uniqueTableRefs) { + statementsToExecute.push(..._moveDataStatements(table, json2)); } } else { - const stmnt = fromJson([statement], 'sqlite'); - if (typeof stmnt !== 'undefined') { - statementsToExecute.push(...stmnt); - } + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); } } - for (const context of Object.values(tablesContext)) { - statementsToExecute.push(...context); - } - return { statementsToExecute, shouldAskForApprove, diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 8f51d0c186..d8c704e7a9 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -127,6 +127,7 @@ export type GenerateConfig = { prefix: Prefix; custom: boolean; bundle: boolean; + driver?: Driver; }; export const prepareGenerateConfig = async ( @@ -173,6 +174,7 @@ export const prepareGenerateConfig = async ( schema: schema, out: out || 'drizzle', bundle: driver === 'expo', + driver, }; }; @@ -215,6 +217,7 @@ export const preparePushConfig = async ( | { dialect: 'sqlite'; credentials: SqliteCredentials; + driver?: Driver; } | { dialect: 'singlestore'; @@ -235,6 +238,7 @@ export const preparePushConfig = async ( : options, ); + raw.driver ||= options.driver; raw.verbose ||= options.verbose; // if provided in cli to debug raw.strict ||= options.strict; // if provided in cli only @@ -352,6 +356,7 @@ export const preparePushConfig = async ( credentials: parsed.data, tablesFilter, schemasFilter, + driver: config.driver, }; } diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 4da8af0ac1..bf825d3e34 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -294,7 +294,7 @@ export const push = command({ schemasFilter, force, ); - } else if (dialect === 'sqlite') { + } else if (dialect === 'sqlite' && !('driver' in credentials)) { const { sqlitePush } = await import('./commands/push'); await sqlitePush( schemaPath, @@ -304,6 +304,16 @@ export const push = command({ tablesFilter, force, ); + } else if (dialect === 'sqlite' && ('driver' in credentials && credentials.driver === 'turso')) { + const { libSQLPush } = await import('./commands/push'); + await libSQLPush( + schemaPath, + verbose, + strict, + credentials, + tablesFilter, + force, + ); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index c4bbbe530c..9f982b0582 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -1,6 +1,6 @@ import { boolean, intersection, literal, object, string, TypeOf, union } from 'zod'; import { dialect } from '../../schemaValidator'; -import { casing, prefix } from './common'; +import { casing, driver, prefix } from './common'; export const cliConfigGenerate = object({ dialect: dialect.optional(), @@ -25,6 +25,7 @@ export const pushParams = object({ extensionsFilters: literal('postgis').array().optional(), verbose: boolean().optional(), strict: boolean().optional(), + driver: driver, }).passthrough(); export type PushParams = TypeOf; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index c099a9a69e..dc9511e4b7 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -1,11 +1,14 @@ import chalk from 'chalk'; -import { table } from 'console'; +import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; -import { CommonSquashedSchema, Dialect } from './schemaValidator'; +import { CommonSquashedSchema } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; -import { SQLiteKitInternals, SQLiteSquasher } from './serializer/sqliteSchema'; +import { + SQLiteKitInternals, SQLiteSchemaInternal, + SQLiteSchemaSquashed, SQLiteSquasher +} from './serializer/sqliteSchema'; import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer'; export interface JsonSqliteCreateTableStatement { @@ -36,6 +39,23 @@ export interface JsonCreateTableStatement { internals?: MySqlKitInternals | SingleStoreKitInternals; } +export interface JsonRecreateTableStatement { + type: 'recreate_table'; + tableName: string; + columns: Column[]; + referenceData: { + name: string; + tableFrom: string; + columnsFrom: string[]; + tableTo: string; + columnsTo: string[]; + onUpdate?: string | undefined; + onDelete?: string | undefined; + }[]; + compositePKs: string[][]; + uniqueConstraints?: string[]; +} + export interface JsonDropTableStatement { type: 'drop_table'; tableName: string; @@ -174,6 +194,10 @@ export interface JsonReferenceStatement { data: string; schema: string; tableName: string; + isMulticolumn?: boolean; + columnNotNull?: boolean; + columnDefault?: string; + columnType?: string; // fromTable: string; // fromColumns: string[]; // toTable: string; @@ -520,6 +544,7 @@ export type JsonAlterColumnStatement = | JsonAlterColumnDropIdentityStatement; export type JsonStatement = + | JsonRecreateTableStatement | JsonAlterColumnStatement | JsonCreateTableStatement | JsonDropTableStatement @@ -1996,6 +2021,7 @@ export const prepareSqliteAlterColumns = ( columns: AlteredColumn[], // TODO: remove? json2: CommonSquashedSchema, + driver?: 'turso', ): JsonAlterColumnStatement[] => { let statements: JsonAlterColumnStatement[] = []; let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; @@ -2023,6 +2049,55 @@ export const prepareSqliteAlterColumns = ( `${tableName}_${columnName}` ]; + if (column.autoincrement?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'changed') { + const type = column.autoincrement.new + ? 'alter_table_alter_column_set_autoincrement' + : 'alter_table_alter_column_drop_autoincrement'; + + statements.push({ + type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + if (typeof column.name !== 'string') { statements.push({ type: 'alter_table_rename_column', @@ -2330,6 +2405,54 @@ export const prepareCreateReferencesJson = ( }; }); }; +export const prepareLibSQLCreateReferencesJson = ( + tableName: string, + schema: string, + foreignKeys: Record, + json2: SQLiteSchemaSquashed, + action?: 'push', +): JsonCreateReferenceStatement[] => { + return Object.values(foreignKeys).map((fkData) => { + const { columnsFrom, tableFrom, columnsTo } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(fkData) + : SQLiteSquasher.unsquashFK(fkData); + + // When trying to alter table in lib sql it is necessary to pass all config for column like "NOT NULL", "DEFAULT", etc. + // If it is multicolumn reference it is not possible to pass this data for all columns + // Pass multicolumn flag for sql statements to not generate migration + let isMulticolumn = false; + + if (columnsFrom.length > 1 || columnsTo.length > 1) { + isMulticolumn = true; + + return { + type: 'create_reference', + tableName, + data: fkData, + schema, + isMulticolumn, + }; + } + + const columnFrom = columnsFrom[0]; + + const { + notNull: columnNotNull, + default: columnDefault, + type: columnType, + } = json2.tables[tableFrom].columns[columnFrom]; + + return { + type: 'create_reference', + tableName, + data: fkData, + schema, + columnNotNull, + columnDefault, + columnType, + }; + }); +}; export const prepareDropReferencesJson = ( tableName: string, @@ -2345,6 +2468,77 @@ export const prepareDropReferencesJson = ( }; }); }; +export const prepareLibSQLDropReferencesJson = ( + tableName: string, + schema: string, + foreignKeys: Record, + json2: SQLiteSchemaSquashed, + meta: SQLiteSchemaInternal['_meta'], + action?: 'push', +): JsonDeleteReferenceStatement[] => { + const statements = Object.values(foreignKeys).map((fkData) => { + const { columnsFrom, tableFrom, columnsTo, name, tableTo, onDelete, onUpdate } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(fkData) + : SQLiteSquasher.unsquashFK(fkData); + + // If all columns from where were references were deleted -> skip this logic + // Drop colums will cover this scenario + const keys = Object.keys(json2.tables[tableName].columns); + const filtered = columnsFrom.filter((it) => keys.includes(it)); + const fullDrop = filtered.length === 0; + if (fullDrop) return; + + // When trying to alter table in lib sql it is necessary to pass all config for column like "NOT NULL", "DEFAULT", etc. + // If it is multicolumn reference it is not possible to pass this data for all columns + // Pass multicolumn flag for sql statements to not generate migration + let isMulticolumn = false; + + if (columnsFrom.length > 1 || columnsTo.length > 1) { + isMulticolumn = true; + + return { + type: 'delete_reference', + tableName, + data: fkData, + schema, + isMulticolumn, + }; + } + + const columnFrom = columnsFrom[0]; + const newTableName = getNewTableName(tableFrom, meta); + + const { + notNull: columnNotNull, + default: columnDefault, + type: columnType, + } = json2.tables[newTableName].columns[columnFrom]; + + const fkToSquash = { + columnsFrom, + columnsTo, + name, + tableFrom: newTableName, + tableTo, + onDelete, + onUpdate, + }; + const foreignKey = action === 'push' + ? SQLiteSquasher.squashPushFK(fkToSquash) + : SQLiteSquasher.squashFK(fkToSquash); + return { + type: 'delete_reference', + tableName, + data: foreignKey, + schema, + columnNotNull, + columnDefault, + columnType, + }; + }); + + return statements.filter((it) => it) as JsonDeleteReferenceStatement[]; +}; // alter should create 2 statements. It's important to make only 1 sql per statement(for breakpoints) export const prepareAlterReferencesJson = ( diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 5b6c782c2d..af3677abdc 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -5,13 +5,12 @@ import { enum as enumType, literal, never, - number, object, record, string, TypeOf, union, - ZodTypeAny, + ZodTypeAny } from 'zod'; import { applyJsonDiff, diffColumns, diffSchemasOrTables } from './jsonDiffer'; import { fromJson } from './sqlgenerator'; @@ -57,13 +56,15 @@ import { prepareDeleteCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeySingleStore, prepareDeleteCompositePrimaryKeySqlite, - prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, prepareDropEnumJson, prepareDropIndexesJson, prepareDropReferencesJson, + prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDropSequenceJson, prepareDropTableJson, + prepareLibSQLCreateReferencesJson, + prepareLibSQLDropReferencesJson, prepareMoveEnumJson, prepareMoveSequenceJson, prepareMySqlCreateTableJson, @@ -83,9 +84,10 @@ import { import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSchema, PgSchemaSquashed, PgSquasher, sequenceSchema, sequenceSquashed } from './serializer/pgSchema'; +import { PgSchema, PgSchemaSquashed, sequenceSquashed } from './serializer/pgSchema'; import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; +import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; const makeChanged = (schema: T) => { @@ -2469,7 +2471,8 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); - const sqlStatements = fromJson(jsonStatements, 'sqlite'); + const combinedJsonStatements = sqliteCombineStatements(jsonStatements, json2, action); + const sqlStatements = fromJson(combinedJsonStatements, 'sqlite'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { @@ -2485,7 +2488,429 @@ export const applySqliteSnapshotsDiff = async ( const _meta = prepareMigrationMeta([], rTables, rColumns); return { - statements: jsonStatements, + statements: combinedJsonStatements, + sqlStatements: uniqueSqlStatements, + _meta, + }; +}; + +export const applyLibSQLSnapshotsDiff = async ( + json1: SQLiteSchemaSquashed, + json2: SQLiteSchemaSquashed, + tablesResolver: ( + input: ResolverInput
, + ) => Promise>, + columnsResolver: ( + input: ColumnsResolverInput, + ) => Promise>, + prevFull: SQLiteSchema, + curFull: SQLiteSchema, + action?: 'push', +): Promise<{ + statements: JsonStatement[]; + sqlStatements: string[]; + _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; +}> => { + const tablesDiff = diffSchemasOrTables(json1.tables, json2.tables); + const { + created: createdTables, + deleted: deletedTables, + renamed: renamedTables, + } = await tablesResolver({ + created: tablesDiff.added, + deleted: tablesDiff.deleted, + }); + + const tablesPatchedSnap1 = copy(json1); + tablesPatchedSnap1.tables = mapEntries(tablesPatchedSnap1.tables, (_, it) => { + const { name } = nameChangeFor(it, renamedTables); + it.name = name; + return [name, it]; + }); + + const res = diffColumns(tablesPatchedSnap1.tables, json2.tables); + + const columnRenames = [] as { + table: string; + renames: { from: Column; to: Column }[]; + }[]; + + const columnCreates = [] as { + table: string; + columns: Column[]; + }[]; + + const columnDeletes = [] as { + table: string; + columns: Column[]; + }[]; + + for (let entry of Object.values(res)) { + const { renamed, created, deleted } = await columnsResolver({ + tableName: entry.name, + schema: entry.schema, + deleted: entry.columns.deleted, + created: entry.columns.added, + }); + + if (created.length > 0) { + columnCreates.push({ + table: entry.name, + columns: created, + }); + } + + if (deleted.length > 0) { + columnDeletes.push({ + table: entry.name, + columns: deleted, + }); + } + + if (renamed.length > 0) { + columnRenames.push({ + table: entry.name, + renames: renamed, + }); + } + } + + const columnRenamesDict = columnRenames.reduce( + (acc, it) => { + acc[it.table] = it.renames; + return acc; + }, + {} as Record< + string, + { + from: Named; + to: Named; + }[] + >, + ); + + const columnsPatchedSnap1 = copy(tablesPatchedSnap1); + columnsPatchedSnap1.tables = mapEntries( + columnsPatchedSnap1.tables, + (tableKey, tableValue) => { + const patchedColumns = mapKeys( + tableValue.columns, + (columnKey, column) => { + const rens = columnRenamesDict[tableValue.name] || []; + const newName = columnChangeFor(columnKey, rens); + column.name = newName; + return newName; + }, + ); + + tableValue.columns = patchedColumns; + return [tableKey, tableValue]; + }, + ); + + const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + + const typedResult = diffResultSchemeSQLite.parse(diffResult); + + // Map array of objects to map + const tablesMap: { + [key: string]: (typeof typedResult.alteredTablesWithColumns)[number]; + } = {}; + + typedResult.alteredTablesWithColumns.forEach((obj) => { + tablesMap[obj.name] = obj; + }); + + const jsonCreateTables = createdTables.map((it) => { + return prepareSQLiteCreateTable(it, action); + }); + + const jsonCreateIndexesForCreatedTables = createdTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.indexes, + curFull.internal, + ); + }) + .flat(); + + const jsonDropTables = deletedTables.map((it) => { + return prepareDropTableJson(it); + }); + + const jsonRenameTables = renamedTables.map((it) => { + return prepareRenameTableJson(it.from, it.to); + }); + + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames + .map((it) => prepareRenameColumns(it.table, '', it.renames)) + .flat(); + + const jsonDropColumnsStatemets: JsonDropColumnStatement[] = columnDeletes + .map((it) => _prepareDropColumns(it.table, '', it.columns)) + .flat(); + + const jsonAddColumnsStatemets: JsonSqliteAddColumnStatement[] = columnCreates + .map((it) => { + return _prepareSqliteAddColumns( + it.table, + it.columns, + tablesMap[it.table] && tablesMap[it.table].addedForeignKeys + ? Object.values(tablesMap[it.table].addedForeignKeys) + : [], + ); + }) + .flat(); + + const rColumns = jsonRenameColumnsStatements.map((it) => { + const tableName = it.tableName; + const schema = it.schema; + return { + from: { schema, table: tableName, column: it.oldColumnName }, + to: { schema, table: tableName, column: it.newColumnName }, + }; + }); + + const rTables = renamedTables.map((it) => { + return { from: it.from, to: it.to }; + }); + + const _meta = prepareMigrationMeta([], rTables, rColumns); + + const allAltered = typedResult.alteredTablesWithColumns; + + const jsonAddedCompositePKs: JsonCreateCompositePK[] = []; + const jsonDeletedCompositePKs: JsonDeleteCompositePK[] = []; + const jsonAlteredCompositePKs: JsonAlterCompositePK[] = []; + + const jsonAddedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + allAltered.forEach((it) => { + // This part is needed to make sure that same columns in a table are not triggered for change + // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name + // We double-check that pk with same set of columns are both in added and deleted diffs + let addedColumns: string[] = []; + for (const addedPkName of Object.keys(it.addedCompositePKs)) { + const addedPkColumns = it.addedCompositePKs[addedPkName]; + addedColumns = SQLiteSquasher.unsquashPK(addedPkColumns); + } + + let deletedColumns: string[] = []; + for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { + const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; + deletedColumns = SQLiteSquasher.unsquashPK(deletedPkColumns); + } + + // Don't need to sort, but need to add tests for it + // addedColumns.sort(); + // deletedColumns.sort(); + + const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + + let addedCompositePKs: JsonCreateCompositePK[] = []; + let deletedCompositePKs: JsonDeleteCompositePK[] = []; + let alteredCompositePKs: JsonAlterCompositePK[] = []; + if (doPerformDeleteAndCreate) { + addedCompositePKs = prepareAddCompositePrimaryKeySqlite( + it.name, + it.addedCompositePKs, + ); + deletedCompositePKs = prepareDeleteCompositePrimaryKeySqlite( + it.name, + it.deletedCompositePKs, + ); + } + alteredCompositePKs = prepareAlterCompositePrimaryKeySqlite( + it.name, + it.alteredCompositePKs, + ); + + // add logic for unique constraints + let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + jsonAddedCompositePKs.push(...addedCompositePKs); + jsonDeletedCompositePKs.push(...deletedCompositePKs); + jsonAlteredCompositePKs.push(...alteredCompositePKs); + + jsonAddedUniqueConstraints.push(...addedUniqueConstraints); + jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); + jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + }); + + const jsonTableAlternations = allAltered + .map((it) => { + return prepareSqliteAlterColumns(it.name, it.schema, it.altered, json2); + }) + .flat(); + + const jsonCreateIndexesForAllAlteredTables = allAltered + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.addedIndexes || {}, + curFull.internal, + ); + }) + .flat(); + + const jsonDropIndexesForAllAlteredTables = allAltered + .map((it) => { + return prepareDropIndexesJson( + it.name, + it.schema, + it.deletedIndexes || {}, + ); + }) + .flat(); + + allAltered.forEach((it) => { + const droppedIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__old; + return current; + }, + {} as Record, + ); + const createdIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__new; + return current; + }, + {} as Record, + ); + + jsonCreateIndexesForAllAlteredTables.push( + ...prepareCreateIndexesJson( + it.name, + it.schema, + createdIndexes || {}, + curFull.internal, + ), + ); + jsonDropIndexesForAllAlteredTables.push( + ...prepareDropIndexesJson(it.name, it.schema, droppedIndexes || {}), + ); + }); + + const jsonReferencesForAllAlteredTables: JsonReferenceStatement[] = allAltered + .map((it) => { + const forAdded = prepareLibSQLCreateReferencesJson( + it.name, + it.schema, + it.addedForeignKeys, + json2, + action, + ); + + const forAltered = prepareLibSQLDropReferencesJson( + it.name, + it.schema, + it.deletedForeignKeys, + json2, + _meta, + action, + ); + + const alteredFKs = prepareAlterReferencesJson(it.name, it.schema, it.alteredForeignKeys); + + return [...forAdded, ...forAltered, ...alteredFKs]; + }) + .flat(); + + const jsonCreatedReferencesForAlteredTables = jsonReferencesForAllAlteredTables.filter( + (t) => t.type === 'create_reference', + ); + const jsonDroppedReferencesForAlteredTables = jsonReferencesForAllAlteredTables.filter( + (t) => t.type === 'delete_reference', + ); + + const jsonStatements: JsonStatement[] = []; + jsonStatements.push(...jsonCreateTables); + + jsonStatements.push(...jsonDropTables); + jsonStatements.push(...jsonRenameTables); + jsonStatements.push(...jsonRenameColumnsStatements); + + jsonStatements.push(...jsonDroppedReferencesForAlteredTables); + + // Will need to drop indexes before changing any columns in table + // Then should go column alternations and then index creation + jsonStatements.push(...jsonDropIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDeletedCompositePKs); + jsonStatements.push(...jsonTableAlternations); + jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAddColumnsStatemets); + + jsonStatements.push(...jsonCreateIndexesForCreatedTables); + jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + + jsonStatements.push(...jsonCreatedReferencesForAlteredTables); + + jsonStatements.push(...jsonDropColumnsStatemets); + + jsonStatements.push(...jsonAlteredCompositePKs); + + jsonStatements.push(...jsonAlteredUniqueConstraints); + + const combinedJsonStatements = libSQLCombineStatements(jsonStatements, json2, action); + + const sqlStatements = fromJson( + combinedJsonStatements, + 'sqlite', + action, + 'turso', + json2, + ); + + const uniqueSqlStatements: string[] = []; + sqlStatements.forEach((ss) => { + if (!uniqueSqlStatements.includes(ss)) { + uniqueSqlStatements.push(ss); + } + }); + + return { + statements: combinedJsonStatements, sqlStatements: uniqueSqlStatements, _meta, }; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 07b24b6c9a..e3f5c2b209 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1,4 +1,5 @@ import { BREAKPOINT } from './cli/commands/migrate'; +import { Driver } from './cli/validations/common'; import { JsonAddColumnStatement, JsonAddValueToEnumStatement, @@ -42,6 +43,7 @@ import { JsonDropTableStatement, JsonMoveSequenceStatement, JsonPgCreateIndexStatement, + JsonRecreateTableStatement, JsonRenameColumnStatement, JsonRenameSchema, JsonRenameSequenceStatement, @@ -54,7 +56,7 @@ import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher } from './serializer/pgSchema'; import { SingleStoreSquasher } from './serializer/singlestoreSchema'; -import { SQLiteSquasher } from './serializer/sqliteSchema'; +import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; export const pgNativeTypes = new Set([ 'uuid', @@ -127,8 +129,16 @@ const isPgNativeType = (it: string) => { }; abstract class Convertor { - abstract can(statement: JsonStatement, dialect: Dialect): boolean; - abstract convert(statement: JsonStatement): string | string[]; + abstract can( + statement: JsonStatement, + dialect: Dialect, + driver?: Driver, + ): boolean; + abstract convert( + statement: JsonStatement, + json2?: SQLiteSchemaSquashed, + action?: 'push', + ): string | string[]; } class PgCreateTableConvertor extends Convertor { @@ -998,7 +1008,7 @@ class SQLiteAlterTableRenameColumnConvertor extends Convertor { convert(statement: JsonRenameColumnStatement) { const { tableName, oldColumnName, newColumnName } = statement; - return `ALTER TABLE \`${tableName}\` RENAME COLUMN \`${oldColumnName}\` TO \`${newColumnName}\`;`; + return `ALTER TABLE \`${tableName}\` RENAME COLUMN "${oldColumnName}" TO "${newColumnName}";`; } } @@ -1233,10 +1243,11 @@ class PgAlterTableAlterColumnSetTypeConvertor extends Convertor { } class SQLiteAlterTableAlterColumnSetTypeConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_set_type' && dialect === 'sqlite' + && !driver ); } @@ -1675,6 +1686,119 @@ class MySqlAlterTableDropPk extends Convertor { } } +type LibSQLModifyColumnStatement = + | JsonAlterColumnTypeStatement + | JsonAlterColumnDropNotNullStatement + | JsonAlterColumnSetNotNullStatement + | JsonAlterColumnSetDefaultStatement + | JsonAlterColumnDropDefaultStatement + | JsonAlterColumnSetGeneratedStatement + | JsonAlterColumnDropGeneratedStatement; + +export class LibSQLModifyColumn extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + (statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default') + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed) { + const { tableName, columnName } = statement; + + let columnType = ``; + let columnDefault: any = ''; + let columnNotNull = ''; + + switch (statement.type) { + case 'alter_table_alter_column_set_type': + columnType = ` ${statement.newDataType}`; + + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + + break; + case 'alter_table_alter_column_drop_notnull': + columnType = ` ${statement.newDataType}`; + + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + + columnNotNull = ''; + break; + case 'alter_table_alter_column_set_notnull': + columnType = ` ${statement.newDataType}`; + + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + + columnNotNull = ` NOT NULL`; + break; + case 'alter_table_alter_column_set_default': + columnType = ` ${statement.newDataType}`; + + columnDefault = ` DEFAULT ${statement.newDefaultValue}`; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + break; + case 'alter_table_alter_column_drop_default': + columnType = ` ${statement.newDataType}`; + + columnDefault = ''; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + break; + case 'alter_table_alter_column_drop_generated': + columnType = ` ${statement.newDataType}`; + + columnDefault = ''; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + break; + case 'alter_table_alter_column_set_generated': + return [ + new SQLiteAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: '', + }), + new SQLiteAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + type: 'sqlite_alter_table_add_column', + }), + ]; + } + + // Seems like getting value from simple json2 shanpshot makes dates be dates + columnDefault = columnDefault instanceof Date + ? columnDefault.toISOString() + : columnDefault; + + return `ALTER TABLE \`${tableName}\` ALTER COLUMN "${columnName}" TO "${columnName}"${columnType}${columnNotNull}${columnDefault};`; + } +} + type MySqlModifyColumnStatement = | JsonAlterColumnDropNotNullStatement | JsonAlterColumnSetNotNullStatement @@ -2281,7 +2405,6 @@ class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { }");`; } } - class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; @@ -2542,10 +2665,11 @@ class PgAlterTableAlterColumnSetNotNullConvertor extends Convertor { } class SqliteAlterTableAlterColumnSetNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_set_notnull' && dialect === 'sqlite' + && !driver ); } @@ -2562,10 +2686,11 @@ class SqliteAlterTableAlterColumnSetNotNullConvertor extends Convertor { } class SqliteAlterTableAlterColumnSetAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_set_autoincrement' && dialect === 'sqlite' + && !driver ); } @@ -2582,10 +2707,11 @@ class SqliteAlterTableAlterColumnSetAutoincrementConvertor extends Convertor { } class SqliteAlterTableAlterColumnDropAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_drop_autoincrement' && dialect === 'sqlite' + && !driver ); } @@ -2621,10 +2747,11 @@ class PgAlterTableAlterColumnDropNotNullConvertor extends Convertor { } class SqliteAlterTableAlterColumnDropNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_drop_notnull' && dialect === 'sqlite' + && !driver ); } @@ -2683,8 +2810,10 @@ class PgCreateForeignKeyConvertor extends Convertor { } class SqliteCreateForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_reference' && dialect === 'sqlite'; + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'create_reference' && dialect === 'sqlite' && !driver + ); } convert(statement: JsonCreateReferenceStatement): string { @@ -2698,6 +2827,50 @@ class SqliteCreateForeignKeyConvertor extends Convertor { } } +class LibSQLCreateForeignKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'create_reference' + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert( + statement: JsonCreateReferenceStatement, + json2?: SQLiteSchemaSquashed, + action?: 'push', + ): string { + const { columnsFrom, columnsTo, tableFrom, onDelete, onUpdate, tableTo } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; + + if (isMulticolumn) { + return ( + '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } + + const onDeleteStatement = onDelete ? ` ON DELETE ${onDelete}` : ''; + const onUpdateStatement = onUpdate ? ` ON UPDATE ${onUpdate}` : ''; + const columnsDefaultValue = columnDefault + ? ` DEFAULT ${columnDefault}` + : ''; + const columnNotNullValue = columnNotNull ? ` NOT NULL` : ''; + const columnTypeValue = columnType ? ` ${columnType}` : ''; + + const columnFrom = columnsFrom[0]; + const columnTo = columnsTo[0]; + + return `ALTER TABLE \`${tableFrom}\` ALTER COLUMN "${columnFrom}" TO "${columnFrom}"${columnTypeValue}${columnNotNullValue}${columnsDefaultValue} REFERENCES ${tableTo}(${columnTo})${onDeleteStatement}${onUpdateStatement};`; + } +} + class MySqlCreateForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_reference' && dialect === 'mysql'; @@ -2803,8 +2976,10 @@ class PgDeleteForeignKeyConvertor extends Convertor { } class SqliteDeleteForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_reference' && dialect === 'sqlite'; + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'delete_reference' && dialect === 'sqlite' && !driver + ); } convert(statement: JsonDeleteReferenceStatement): string { @@ -2818,6 +2993,48 @@ class SqliteDeleteForeignKeyConvertor extends Convertor { } } +class LibSQLDeleteForeignKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'delete_reference' + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert( + statement: JsonDeleteReferenceStatement, + json2?: SQLiteSchemaSquashed, + action?: 'push', + ): string { + const { columnsFrom, tableFrom } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + + const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; + + if (isMulticolumn) { + return ( + '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } + + const columnsDefaultValue = columnDefault + ? ` DEFAULT ${columnDefault}` + : ''; + const columnNotNullValue = columnNotNull ? ` NOT NULL` : ''; + const columnTypeValue = columnType ? ` ${columnType}` : ''; + + const columnFrom = columnsFrom[0]; + + return `ALTER TABLE \`${tableFrom}\` ALTER COLUMN "${columnFrom}" TO "${columnFrom}"${columnTypeValue}${columnNotNullValue}${columnsDefaultValue};`; + } +} + class MySqlDeleteForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_reference' && dialect === 'mysql'; @@ -3092,11 +3309,123 @@ class SingleStoreDropIndexConvertor extends Convertor { } } +class SQLiteRecreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'recreate_table' && dialect === 'sqlite' && !driver + ); + } + + convert(statement: JsonRecreateTableStatement): string | string[] { + const { tableName, columns, compositePKs, referenceData } = statement; + + const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + + const sqlStatements: string[] = []; + + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: tableName, + tableNameTo: `__old__generate_${tableName}`, + toSchema: '', + type: 'rename_table', + }), + ); + + // create new table + sqlStatements.push( + new SQLiteCreateTableConvertor().convert({ + type: 'sqlite_create_table', + tableName, + columns, + referenceData, + compositePKs, + }), + ); + + // migrate data + sqlStatements.push( + `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + ); + + // migrate data + sqlStatements.push( + new SQLiteDropTableConvertor().convert({ + type: 'drop_table', + tableName: `__old__generate_${tableName}`, + schema: '', + }), + ); + + return sqlStatements; + } +} + +class LibSQLRecreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'recreate_table' + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert(statement: JsonRecreateTableStatement): string[] { + const { tableName, columns, compositePKs, referenceData } = statement; + + const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + + const sqlStatements: string[] = []; + + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: tableName, + tableNameTo: `__old__generate_${tableName}`, + toSchema: '', + type: 'rename_table', + }), + ); + + // create new table + sqlStatements.push( + new SQLiteCreateTableConvertor().convert({ + type: 'sqlite_create_table', + tableName, + columns, + referenceData, + compositePKs, + }), + ); + + // migrate data + sqlStatements.push( + `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + ); + + // migrate data + sqlStatements.push( + new SQLiteDropTableConvertor().convert({ + type: 'drop_table', + tableName: `__old__generate_${tableName}`, + schema: '', + }), + ); + + return sqlStatements; + } +} + const convertors: Convertor[] = []; convertors.push(new PgCreateTableConvertor()); convertors.push(new MySqlCreateTableConvertor()); convertors.push(new SingleStoreCreateTableConvertor()); convertors.push(new SQLiteCreateTableConvertor()); +convertors.push(new SQLiteRecreateTableConvertor()); +convertors.push(new LibSQLRecreateTableConvertor()); convertors.push(new CreateTypeEnumConvertor()); @@ -3175,6 +3504,7 @@ convertors.push(new SqliteAlterTableAlterColumnAlterGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnSetExpressionConvertor()); convertors.push(new MySqlModifyColumn()); +convertors.push(new LibSQLModifyColumn()); // convertors.push(new MySqlAlterTableAlterColumnSetDefaultConvertor()); // convertors.push(new MySqlAlterTableAlterColumnDropDefaultConvertor()); @@ -3199,7 +3529,9 @@ convertors.push(new PgAlterTableRemoveFromSchemaConvertor()); convertors.push(new SQLiteAlterTableAlterColumnSetTypeConvertor()); convertors.push(new SqliteAlterForeignKeyConvertor()); convertors.push(new SqliteDeleteForeignKeyConvertor()); +convertors.push(new LibSQLDeleteForeignKeyConvertor()); convertors.push(new SqliteCreateForeignKeyConvertor()); +convertors.push(new LibSQLCreateForeignKeyConvertor()); convertors.push(new SQLiteAlterTableAddUniqueConstraintConvertor()); convertors.push(new SQLiteAlterTableDropUniqueConstraintConvertor()); @@ -3236,26 +3568,43 @@ convertors.push(new SingleStoreAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new SingleStoreAlterTableAddPk()); convertors.push(new SingleStoreAlterTableAlterCompositePrimaryKeyConvertor()); -export const fromJson = (statements: JsonStatement[], dialect: Dialect) => { +// overloads for turso driver +export function fromJson( + statements: JsonStatement[], + dialect: Exclude, +): string[]; +export function fromJson( + statements: JsonStatement[], + dialect: 'sqlite', + action?: 'push', + driver?: Driver, + json2?: SQLiteSchemaSquashed, +): string[]; + +export function fromJson( + statements: JsonStatement[], + dialect: Dialect, + action?: 'push', + driver?: Driver, + json2?: SQLiteSchemaSquashed, +) { const result = statements .flatMap((statement) => { const filtered = convertors.filter((it) => { - // console.log(statement, dialect) - return it.can(statement, dialect); + return it.can(statement, dialect, driver); }); const convertor = filtered.length === 1 ? filtered[0] : undefined; if (!convertor) { - // console.log("no convertor:", statement.type, dialect); return ''; } - return convertor.convert(statement); + return convertor.convert(statement, json2, action); }) .filter((it) => it !== ''); return result; -}; +} // blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/ // test case for enum altering diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts new file mode 100644 index 0000000000..21cc86b386 --- /dev/null +++ b/drizzle-kit/src/statementCombiner.ts @@ -0,0 +1,387 @@ +import { + JsonCreateIndexStatement, + JsonRecreateTableStatement, + JsonStatement, + prepareCreateIndexesJson, +} from './jsonStatements'; +import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; + +export const prepareLibSQLRecreateTable = ( + table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], + action?: 'push', +): (JsonRecreateTableStatement | JsonCreateIndexStatement)[] => { + const { name, columns, uniqueConstraints, indexes } = table; + + const composites: string[][] = Object.values(table.compositePrimaryKeys).map( + (it) => SQLiteSquasher.unsquashPK(it), + ); + + const references: string[] = Object.values(table.foreignKeys); + const fks = references.map((it) => + action === 'push' ? SQLiteSquasher.unsquashPushFK(it) : SQLiteSquasher.unsquashFK(it) + ); + + const statements: (JsonRecreateTableStatement | JsonCreateIndexStatement)[] = [ + { + type: 'recreate_table', + tableName: name, + columns: Object.values(columns), + compositePKs: composites, + referenceData: fks, + uniqueConstraints: Object.values(uniqueConstraints), + }, + ]; + + if (Object.keys(indexes).length) { + statements.push(...prepareCreateIndexesJson(name, '', indexes)); + } + return statements; +}; + +export const prepareSQLiteRecreateTable = ( + table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], + action?: 'push', +): JsonStatement[] => { + const { name, columns, uniqueConstraints, indexes } = table; + + const composites: string[][] = Object.values(table.compositePrimaryKeys).map( + (it) => SQLiteSquasher.unsquashPK(it), + ); + + const references: string[] = Object.values(table.foreignKeys); + const fks = references.map((it) => + action === 'push' ? SQLiteSquasher.unsquashPushFK(it) : SQLiteSquasher.unsquashFK(it) + ); + + const statements: JsonStatement[] = [ + { + type: 'recreate_table', + tableName: name, + columns: Object.values(columns), + compositePKs: composites, + referenceData: fks, + uniqueConstraints: Object.values(uniqueConstraints), + }, + ]; + + if (Object.keys(indexes).length) { + statements.push(...prepareCreateIndexesJson(name, '', indexes)); + } + return statements; +}; + +export const libSQLCombineStatements = ( + statements: JsonStatement[], + json2: SQLiteSchemaSquashed, + action?: 'push', +) => { + // const tablesContext: Record = {}; + const newStatements: Record = {}; + for (const statement of statements) { + if ( + statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_pk' + || statement.type === 'alter_table_alter_column_set_pk' + || statement.type === 'create_composite_pk' + || statement.type === 'alter_composite_pk' + || statement.type === 'delete_composite_pk' + ) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if ( + statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + ) { + const { tableName, columnName, columnPk } = statement; + + const columnIsPartOfUniqueIndex = Object.values( + json2.tables[tableName].indexes, + ).some((it) => { + const unsquashIndex = SQLiteSquasher.unsquashIdx(it); + + return ( + unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique + ); + }); + + const columnIsPartOfForeignKey = Object.values( + json2.tables[tableName].foreignKeys, + ).some((it) => { + const unsquashFk = action === 'push' ? SQLiteSquasher.unsquashPushFK(it) : SQLiteSquasher.unsquashFK(it); + + return ( + unsquashFk.columnsFrom.includes(columnName) + ); + }); + + const statementsForTable = newStatements[tableName]; + + if ( + !statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + ) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if ( + statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + ) { + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + } + continue; + } + if ( + statementsForTable && !(columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + ) { + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + continue; + } + + newStatements[tableName] = [statement]; + + continue; + } + + if (statement.type === 'create_reference' && statement.isMulticolumn) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if (statement.type === 'delete_reference') { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if (statement.type === 'sqlite_alter_table_add_column' && statement.column.primaryKey) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + const tableName = statement.type === 'rename_table' + ? statement.tableNameTo + : (statement as { tableName: string }).tableName; + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = [statement]; + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + } + + const combinedStatements = Object.values(newStatements).flat(); + const renamedTables = combinedStatements.filter((it) => it.type === 'rename_table'); + const renamedColumns = combinedStatements.filter((it) => it.type === 'alter_table_rename_column'); + + const rest = combinedStatements.filter((it) => it.type !== 'rename_table' && it.type !== 'alter_table_rename_column'); + + return [...renamedTables, ...renamedColumns, ...rest]; +}; + +export const sqliteCombineStatements = ( + statements: JsonStatement[], + json2: SQLiteSchemaSquashed, + action?: 'push', +) => { + // const tablesContext: Record = {}; + const newStatements: Record = {}; + for (const statement of statements) { + if ( + statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_pk' + || statement.type === 'alter_table_alter_column_set_pk' + || statement.type === 'create_reference' + || statement.type === 'delete_reference' + || statement.type === 'alter_reference' + || statement.type === 'create_composite_pk' + || statement.type === 'alter_composite_pk' + || statement.type === 'delete_composite_pk' + || statement.type === 'create_unique_constraint' + || statement.type === 'delete_unique_constraint' + ) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if (statement.type === 'sqlite_alter_table_add_column' && statement.column.primaryKey) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + const tableName = statement.type === 'rename_table' + ? statement.tableNameTo + : (statement as { tableName: string }).tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = [statement]; + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + } + + const combinedStatements = Object.values(newStatements).flat(); + + const renamedTables = combinedStatements.filter((it) => it.type === 'rename_table'); + const renamedColumns = combinedStatements.filter((it) => it.type === 'alter_table_rename_column'); + + const rest = combinedStatements.filter((it) => it.type !== 'rename_table' && it.type !== 'alter_table_rename_column'); + + return [...renamedTables, ...renamedColumns, ...rest]; +}; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 7b363a9d33..37d26f21ea 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -9,6 +9,7 @@ import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; import { backwardCompatibleMysqlSchema } from './serializer/mysqlSchema'; import { backwardCompatiblePgSchema } from './serializer/pgSchema'; +import { backwardCompatibleSingleStoreSchema } from './serializer/singlestoreSchema'; import { backwardCompatibleSqliteSchema } from './serializer/sqliteSchema'; import type { ProxyParams } from './serializer/studio'; @@ -117,6 +118,8 @@ const validatorForDialect = (dialect: Dialect) => { return { validator: backwardCompatibleSqliteSchema, version: 6 }; case 'mysql': return { validator: backwardCompatibleMysqlSchema, version: 5 }; + case 'singlestore': + return { validator: backwardCompatibleSingleStoreSchema, version: 1 }; } }; @@ -341,3 +344,13 @@ export const normalisePGliteUrl = ( export function isPgArrayType(sqlType: string) { return sqlType.match(/.*\[\d*\].*|.*\[\].*/g) !== null; } + +export function findAddedAndRemoved(columnNames1: string[], columnNames2: string[]) { + const set1 = new Set(columnNames1); + const set2 = new Set(columnNames2); + + const addedColumns = columnNames2.filter((it) => !set1.has(it)); + const removedColumns = columnNames1.filter((it) => !set2.has(it)); + + return { addedColumns, removedColumns }; +} diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts new file mode 100644 index 0000000000..adf354458e --- /dev/null +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -0,0 +1,835 @@ +import { foreignKey, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { JsonRecreateTableStatement } from 'src/jsonStatements'; +import { expect, test } from 'vitest'; +import { diffTestSchemasLibSQL } from './schemaDiffer'; + +test('drop autoincrement', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + }), + }; + + const { statements } = await diffTestSchemasLibSQL(schema1, schema2, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [{ + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); +}); + +test('set autoincrement', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }), + }; + + const { statements } = await diffTestSchemasLibSQL(schema1, schema2, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [{ + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); +}); + +test('set not null', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, + ); +}); + +test('drop not null', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); +}); + +test('set default. set not null. add column', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull().default('name'), + age: int('age').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(3); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_default', + tableName: 'users', + columnName: 'name', + newDefaultValue: "'name'", + schema: '', + newDataType: 'text', + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: "'name'", + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[2]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'users', + referenceData: undefined, + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL DEFAULT 'name';`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ADD \`age\` integer NOT NULL;`, + ); +}); + +test('drop default. drop not null', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull().default('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_drop_default', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); +}); + +test('set data type. set default', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: int('name').default(123), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_type', + tableName: 'users', + columnName: 'name', + newDataType: 'integer', + oldDataType: 'text', + schema: '', + columnDefault: 123, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_table_alter_column_set_default', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'integer', + newDefaultValue: 123, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" integer DEFAULT 123;`, + ); +}); + +test('add foriegn key', async (t) => { + const schema = { + table: sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => schema.table.id), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_reference', + tableName: 'users', + data: 'users_table_id_table_id_fk;users;table_id;table;id;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "table_id" TO "table_id" integer REFERENCES table(id) ON DELETE no action ON UPDATE no action;`, + ); +}); + +test('drop foriegn key', async (t) => { + const schema = { + table: sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => schema.table.id, { + onDelete: 'cascade', + }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'table_id', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`table_id\` integer +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('alter foriegn key', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }); + const tableRef2 = sqliteTable('table2', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => tableRef.id, { + onDelete: 'cascade', + }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => tableRef2.id), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'table_id', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'table_id', + ], + columnsTo: [ + 'id', + ], + name: 'users_table_id_table2_id_fk', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'users', + tableTo: 'table2', + }, + ], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + 'ALTER TABLE `users` RENAME TO `__old__generate_users`;', + ); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`table_id\` integer, +\tFOREIGN KEY (\`table_id\`) REFERENCES \`table2\`(\`id\`) ON UPDATE no action ON DELETE no action +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('add foriegn key for multiple columns', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + age: int('age'), + age1: int('age_1'), + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }), + tableRef, + }; + + const schema2 = { + tableRef, + users: sqliteTable( + 'users', + { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }, + (table) => ({ + foreignKey: foreignKey({ + columns: [table.column, table.column1], + foreignColumns: [tableRef.age, tableRef.age1], + }), + }), + ), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column_1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'column', + 'column_1', + ], + columnsTo: [ + 'age', + 'age_1', + ], + name: 'users_column_column_1_table_age_age_1_fk', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'users', + tableTo: 'table', + }, + ], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + } as JsonRecreateTableStatement); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`column\` integer, +\t\`column_1\` integer, +\tFOREIGN KEY (\`column\`,\`column_1\`) REFERENCES \`table\`(\`age\`,\`age_1\`) ON UPDATE no action ON DELETE no action +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('drop foriegn key for multiple columns', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + age: int('age'), + age1: int('age_1'), + }); + + const schema1 = { + users: sqliteTable( + 'users', + { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }, + (table) => ({ + foreignKey: foreignKey({ + columns: [table.column, table.column1], + foreignColumns: [tableRef.age, tableRef.age1], + }), + }), + ), + tableRef, + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }), + tableRef, + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column_1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`column\` integer, +\t\`column_1\` integer +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('drop foriegn key for multiple columns', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + age: int('age'), + age1: int('age_1'), + }); + + const schema1 = { + users: sqliteTable( + 'users', + { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }, + (table) => ({ + foreignKey: foreignKey({ + columns: [table.column, table.column1], + foreignColumns: [tableRef.age, tableRef.age1], + }), + }), + ), + tableRef, + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }), + tableRef, + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column_1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`column\` integer, +\t\`column_1\` integer +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts new file mode 100644 index 0000000000..205f31f0bd --- /dev/null +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -0,0 +1,744 @@ +import { createClient } from '@libsql/client'; +import chalk from 'chalk'; +import { + blob, + foreignKey, + getTableConfig, + int, + integer, + numeric, + real, + sqliteTable, + text, + uniqueIndex, +} from 'drizzle-orm/sqlite-core'; +import { diffTestSchemasPushLibSQL } from 'tests/schemaDiffer'; +import { expect, test } from 'vitest'; + +test('nothing changed in schema', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, + + customers: sqliteTable('customers', { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id') + .references(() => users.id) + .notNull(), + }), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema1, [], false); + expect(sqlStatements.length).toBe(0); + expect(statements.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); +}); + +test('added, dropped index', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, + customers: sqliteTable( + 'customers', + { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id').notNull(), + }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_address_unique').on(table.address), + }), + ), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const schema2 = { + users, + customers: sqliteTable( + 'customers', + { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id').notNull(), + }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_is_confirmed_unique').on( + table.isConfirmed, + ), + }), + ), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema2, [], false); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'drop_index', + tableName: 'customers', + data: 'customers_address_unique;address;true;', + schema: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_index', + tableName: 'customers', + data: 'customers_is_confirmed_unique;is_confirmed;true;', + schema: '', + internal: { indexes: {} }, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS \`customers_address_unique\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE UNIQUE INDEX \`customers_is_confirmed_unique\` ON \`customers\` (\`is_confirmed\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('added column not null and without default to table with data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("drizzle");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("turso");`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`delete from companies;`); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline( + 'age', + ) + } column without default value, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('companies'); +}); + +test('added column not null and without default to table without data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema2, [], false); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop autoincrement. drop column with data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, "drizzle");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, "turso");`, + ]; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ + { + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +);\n`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + + expect(columnsToRemove!.length).toBe(1); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to delete ${ + chalk.underline( + 'name', + ) + } column in companies table with 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('change autoincrement. table is part of foreign key', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const companies1 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + }); + const users1 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema1 = { + companies: companies1, + users: users1, + }; + + const companies2 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }); + const users2 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema2 = { + companies: companies2, + users: users2, + }; + + const { name: usersTableName } = getTableConfig(users1); + const { name: companiesTableName } = getTableConfig(companies1); + const seedStatements = [ + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("drizzle");`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("turso");`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("1");`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("2");`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ + { + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(9); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, + ); + expect(sqlStatements[5]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text, +\t\`company_id\` text, +\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action +); +`, + ); + expect(sqlStatements[6]).toBe( + `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); + expect(sqlStatements[8]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('create table with custom name references', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }); + + const schema1 = { + users, + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + (t) => ({ + fk: foreignKey({ + columns: [t.id], + foreignColumns: [users.id], + name: 'custom_name_fk', + }), + }), + ), + }; + + const schema2 = { + users, + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + (t) => ({ + fk: foreignKey({ + columns: [t.id], + foreignColumns: [users.id], + name: 'custom_name_fk', + }), + }), + ), + }; + + const { sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(sqlStatements!.length).toBe(0); +}); + +test('drop not null, add not null', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + userId: int('user_id'), + }, + ), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnName: 'name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_notnull', + }); + expect(statements![1]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'posts', + type: 'alter_table_alter_column_set_notnull', + }); + expect(sqlStatements!.length).toBe(2); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`); + expect(sqlStatements![1]).toBe(`ALTER TABLE \`posts\` ALTER COLUMN "name" TO "name" text NOT NULL;`); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop table with data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const schema2 = { + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const seedStatements = [ + `INSERT INTO \`users\` ("name") VALUES ("drizzle")`, + ]; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + schema: undefined, + tableName: 'users', + type: 'drop_table', + }); + + expect(sqlStatements!.length).toBe(1); + expect(sqlStatements![0]).toBe(`DROP TABLE \`users\`;`); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe(`· You're about to delete ${chalk.underline('users')} table with 1 items`); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(1); + expect(tablesToRemove![0]).toBe('users'); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index cf468d3ec0..d0c3cb05ee 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -1,384 +1,529 @@ import Database from 'better-sqlite3'; -import { SQL, sql } from 'drizzle-orm'; -import { blob, foreignKey, int, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import chalk from 'chalk'; +import { + blob, + foreignKey, + getTableConfig, + int, + integer, + numeric, + real, + sqliteTable, + text, + uniqueIndex, +} from 'drizzle-orm/sqlite-core'; import { diffTestSchemasPushSqlite } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; -import { DialectSuite, run } from './common'; - -const sqliteSuite: DialectSuite = { - addBasicIndexes: function(context?: any): Promise { - return {} as any; - }, - changeIndexFields: function(context?: any): Promise { - return {} as any; - }, - dropIndex: function(context?: any): Promise { - return {} as any; - }, - - async allTypes() { - const sqlite = new Database(':memory:'); - - const Users = sqliteTable('users', { - id: integer('id').primaryKey().notNull(), - name: text('name').notNull(), - email: text('email'), - textJson: text('text_json', { mode: 'json' }), - blobJon: blob('blob_json', { mode: 'json' }), - blobBigInt: blob('blob_bigint', { mode: 'bigint' }), - numeric: numeric('numeric'), - createdAt: integer('created_at', { mode: 'timestamp' }), - createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), - real: real('real'), - text: text('text', { length: 255 }), - role: text('role', { enum: ['admin', 'user'] }).default('user'), - isConfirmed: integer('is_confirmed', { - mode: 'boolean', - }), - }); - const schema1 = { - Users, +test('nothing changed in schema', async (t) => { + const client = new Database(':memory:'); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, - Customers: sqliteTable('customers', { + customers: sqliteTable('customers', { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id') + .references(() => users.id) + .notNull(), + }), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(client, schema1, schema1, [], false); + expect(sqlStatements.length).toBe(0); + expect(statements.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); +}); + +test('dropped, added unique index', async (t) => { + const client = new Database(':memory:'); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, + + customers: sqliteTable( + 'customers', + { id: integer('id').primaryKey(), - address: text('address').notNull(), + address: text('address').notNull().unique(), isConfirmed: integer('is_confirmed', { mode: 'boolean' }), registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) .notNull() .$defaultFn(() => new Date()), - userId: integer('user_id') - .references(() => Users.id) - .notNull(), + userId: integer('user_id').notNull(), + }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_address_unique').on(table.address), }), + ), - Posts: sqliteTable('posts', { - id: integer('id').primaryKey(), - content: text('content'), - authorId: integer('author_id'), - }), - }; - - const { statements } = await diffTestSchemasPushSqlite( - sqlite, - schema1, - schema1, - [], - false, - ); - expect(statements.length).toBe(0); - }, - indexesToBeNotTriggered: function(context?: any): Promise { - return {} as any; - }, - indexesTestCase1: function(context?: any): Promise { - return {} as any; - }, - async case1(): Promise { - const sqlite = new Database(':memory:'); - - const schema1 = { - users: sqliteTable('users', { - id: text('id').notNull().primaryKey(), - firstName: text('first_name').notNull(), - lastName: text('last_name').notNull(), - username: text('username').notNull().unique(), - email: text('email').notNull().unique(), - password: text('password').notNull(), - avatarUrl: text('avatar_url').notNull(), - postsCount: integer('posts_count').notNull().default(0), - followersCount: integer('followers_count').notNull().default(0), - followingsCount: integer('followings_count').notNull().default(0), - createdAt: integer('created_at').notNull(), - }), - }; - - const schema2 = { - users: sqliteTable('users', { - id: text('id').notNull().primaryKey(), - firstName: text('first_name').notNull(), - lastName: text('last_name').notNull(), - username: text('username').notNull().unique(), - email: text('email').notNull().unique(), - password: text('password').notNull(), - avatarUrl: text('avatar_url').notNull(), - followersCount: integer('followers_count').notNull().default(0), - followingsCount: integer('followings_count').notNull().default(0), - createdAt: integer('created_at').notNull(), - }), - }; - - const { statements } = await diffTestSchemasPushSqlite( - sqlite, - schema1, - schema2, - [], - false, - ); - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'alter_table_drop_column', - tableName: 'users', - columnName: 'posts_count', - schema: '', - }); - }, - addNotNull: function(context?: any): Promise { - return {} as any; - }, - addNotNullWithDataNoRollback: function(context?: any): Promise { - return {} as any; - }, - addBasicSequences: function(context?: any): Promise { - return {} as any; - }, - // --- - addGeneratedColumn: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'stored' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); - - expect(statements).toStrictEqual([]); - expect(sqlStatements).toStrictEqual([]); - }, - addGeneratedToColumn: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').notNull(), - generatedName1: text('gen_name1'), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name') - .notNull() - .generatedAlwaysAs((): SQL => sql`${to.users.name} || 'hello'`, { - mode: 'stored', - }), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); + const schema2 = { + users, - expect(statements).toStrictEqual([ + customers: sqliteTable( + 'customers', { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: '("name" || \'hello\')', - type: 'virtual', - }, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_generated', + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id').notNull(), }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS ("name" || \'hello\') VIRTUAL;', - ]); - - for (const st of sqlStatements) { - sqlite.exec(st); - } - }, - dropGeneratedConstraint: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'stored' }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_is_confirmed_unique').on( + table.isConfirmed, ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name'), - generatedName1: text('gen_name1'), }), - }; + ), - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; - expect(statements).toStrictEqual([ - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', - }, + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [], false); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'drop_index', + tableName: 'customers', + data: 'customers_address_unique;address;true;', + schema: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_index', + tableName: 'customers', + data: 'customers_is_confirmed_unique;is_confirmed;true;', + schema: '', + internal: { + indexes: {}, + }, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS \`customers_address_unique\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE UNIQUE INDEX \`customers_is_confirmed_unique\` ON \`customers\` (\`is_confirmed\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('added column not null and without default to table with data', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('turso');`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`delete from companies;`); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline( + 'age', + ) + } column without default value, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('companies'); +}); + +test('added column not null and without default to table without data', async (t) => { + const turso = new Database(':memory:'); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(turso, schema1, schema2, [], false); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop autoincrement. drop column with data', async (t) => { + const turso = new Database(':memory:'); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, 'drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, 'turso');`, + ]; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - 'ALTER TABLE `users` ADD `gen_name` text;', - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text;', - ]); - - for (const st of sqlStatements) { - sqlite.exec(st); - } - }, - alterGeneratedConstraint: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name}`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name}`, - { mode: 'virtual' }, - ), - }), - }; + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +);\n`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + + expect(columnsToRemove!.length).toBe(1); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to delete ${ + chalk.underline( + 'name', + ) + } column in companies table with 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); +test('change autoincrement. table is part of foreign key', async (t) => { + const client = new Database(':memory:'); - expect(statements).toStrictEqual([ + const companies1 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + }); + const users1 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema1 = { + companies: companies1, + users: users1, + }; + + const companies2 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }); + const users2 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema2 = { + companies: companies2, + users: users2, + }; + + const { name: usersTableName } = getTableConfig(users1); + const { name: companiesTableName } = getTableConfig(companies1); + const seedStatements = [ + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('turso');`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ('1');`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ('2');`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: '("name")', - type: 'virtual', - }, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_alter_generated', + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS ("name") VIRTUAL;', - ]); - - for (const st of sqlStatements) { - sqlite.exec(st); - } - }, - createTableWithGeneratedConstraint: function(context?: any): Promise { - return {} as any; - }, -}; - -run(sqliteSuite); + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(9); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, + ); + expect(sqlStatements[5]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text, +\t\`company_id\` text, +\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action +); +`, + ); + expect(sqlStatements[6]).toBe( + `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); + expect(sqlStatements[8]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); test('create table with custom name references', async (t) => { - const sqlite = new Database(':memory:'); + const client = new Database(':memory:'); const users = sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), @@ -424,7 +569,7 @@ test('create table with custom name references', async (t) => { }; const { sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, + client, schema1, schema2, [], @@ -432,3 +577,383 @@ test('create table with custom name references', async (t) => { expect(sqlStatements!.length).toBe(0); }); + +test('drop not null, add not null', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + userId: int('user_id'), + }, + ), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + expect(statements![1]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + generated: undefined, + name: 'user_id', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'posts', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(8); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`users\`("id", "name") SELECT ("id", "name") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); + + expect(sqlStatements![4]).toBe(`ALTER TABLE \`posts\` RENAME TO \`__old_push_posts\`;`); + expect(sqlStatements![5]).toBe(`CREATE TABLE \`posts\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text NOT NULL, +\t\`user_id\` integer +);\n`); + expect(sqlStatements![6]).toBe( + `INSERT INTO \`posts\`("id", "name", "user_id") SELECT ("id", "name", "user_id") FROM \`__old_push_posts\`;`, + ); + expect(sqlStatements![7]).toBe(`DROP TABLE \`__old_push_posts\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('rename table and change data type', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('old_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: text('age'), + }), + }; + + const schema2 = { + users: sqliteTable('new_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: integer('age'), + }), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.old_users->public.new_users'], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + fromSchema: undefined, + tableNameFrom: 'old_users', + tableNameTo: 'new_users', + toSchema: undefined, + type: 'rename_table', + }); + expect(statements![1]).toStrictEqual({ + columns: [ + { + autoincrement: true, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'new_users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(5); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); + expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); + expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements![3]).toBe( + `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + ); + expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('rename table and change data type', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('old_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: text('age'), + }), + }; + + const schema2 = { + users: sqliteTable('new_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: integer('age'), + }), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.old_users->public.new_users'], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + fromSchema: undefined, + tableNameFrom: 'old_users', + tableNameTo: 'new_users', + toSchema: undefined, + type: 'rename_table', + }); + expect(statements![1]).toStrictEqual({ + columns: [ + { + autoincrement: true, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'new_users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(5); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); + expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); + expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements![3]).toBe( + `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + ); + expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('rename column and change data type', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: integer('age'), + }), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.users.name->public.users.age'], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 58f6a8f642..07da0ed058 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,4 +1,5 @@ import { PGlite } from '@electric-sql/pglite'; +import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; @@ -8,6 +9,7 @@ import { SingleStoreTable } from 'drizzle-orm/singlestore-core'; import { SQLiteTable } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; +import { libSqlLogSuggestionsAndReturn } from 'src/cli/commands/libSqlPushUtils'; import { columnsResolver, enumsResolver, @@ -37,6 +39,7 @@ import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { + applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySingleStoreSnapshotsDiff, @@ -959,11 +962,18 @@ export const diffTestSchemasPushSqlite = async ( right: SqliteSchema, renamesArr: string[], cli: boolean = false, + seedStatements: string[] = [], ) => { const { sqlStatements } = await applySqliteDiffs(left, 'push'); + for (const st of sqlStatements) { client.exec(st); } + + for (const st of seedStatements) { + client.exec(st); + } + // do introspect into PgSchemaInternal const introspectedSchema = await fromSqliteDatabase( { @@ -977,9 +987,9 @@ export const diffTestSchemasPushSqlite = async ( undefined, ); - const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(leftTables); + const serialized2 = generateSqliteSnapshot(rightTables); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1016,7 +1026,15 @@ export const diffTestSchemasPushSqlite = async ( 'push', ); - const { statementsToExecute } = await logSuggestionsAndReturn( + const { + statementsToExecute, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await logSuggestionsAndReturn( { query: async (sql: string, params: any[] = []) => { return client.prepare(sql).bind(params).all() as T[]; @@ -1031,7 +1049,16 @@ export const diffTestSchemasPushSqlite = async ( _meta!, ); - return { sqlStatements: statementsToExecute, statements }; + return { + sqlStatements: statementsToExecute, + statements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + }; } else { const { sqlStatements, statements } = await applySqliteSnapshotsDiff( sn1, @@ -1046,6 +1073,136 @@ export const diffTestSchemasPushSqlite = async ( } }; +export async function diffTestSchemasPushLibSQL( + client: Client, + left: SqliteSchema, + right: SqliteSchema, + renamesArr: string[], + cli: boolean = false, + seedStatements: string[] = [], +) { + const { sqlStatements } = await applyLibSQLDiffs(left, 'push'); + + for (const st of sqlStatements) { + await client.execute(st); + } + + for (const st of seedStatements) { + await client.execute(st); + } + + const introspectedSchema = await fromSqliteDatabase( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batch: async ( + queries: { query: string; values?: any[] | undefined }[], + ) => { + await client.batch( + queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), + ); + }, + }, + undefined, + ); + + const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const serialized2 = generateSqliteSnapshot(leftTables); + + const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSqliteScheme(sch1, 'push'); + const sn2 = squashSqliteScheme(sch2, 'push'); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + sch1, + sch2, + 'push', + ); + + const { + statementsToExecute, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await libSqlLogSuggestionsAndReturn( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batch: async ( + queries: { query: string; values?: any[] | undefined }[], + ) => { + await client.batch( + queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), + ); + }, + }, + statements, + sn1, + sn2, + _meta!, + ); + + return { + sqlStatements: statementsToExecute, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + }; + } else { + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + sch1, + sch2, + 'push', + ); + return { sqlStatements, statements }; + } +} + export const applySqliteDiffs = async ( sn: SqliteSchema, action?: 'push' | undefined, @@ -1094,6 +1251,54 @@ export const applySqliteDiffs = async ( return { sqlStatements, statements }; }; +export const applyLibSQLDiffs = async ( + sn: SqliteSchema, + action?: 'push' | undefined, +) => { + const dryRun = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + tables: {}, + enums: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, + } as const; + + const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const serialized1 = generateSqliteSnapshot(tables); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + + const sch1 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sn1 = squashSqliteScheme(sch1, action); + + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + dryRun, + sn1, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + dryRun, + sch1, + action, + ); + + return { sqlStatements, statements }; +}; + export const diffTestSchemasSqlite = async ( left: SqliteSchema, right: SqliteSchema, @@ -1154,6 +1359,66 @@ export const diffTestSchemasSqlite = async ( return { sqlStatements, statements }; }; +export const diffTestSchemasLibSQL = async ( + left: SqliteSchema, + right: SqliteSchema, + renamesArr: string[], + cli: boolean = false, +) => { + const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const serialized1 = generateSqliteSnapshot(leftTables); + const serialized2 = generateSqliteSnapshot(rightTables); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSqliteScheme(sch1); + const sn2 = squashSqliteScheme(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + sch1, + sch2, + ); + return { sqlStatements, statements }; + } + + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + sch1, + sch2, + ); + return { sqlStatements, statements }; +}; + // --- Introspect to file helpers --- export const introspectPgToFile = async ( diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts new file mode 100644 index 0000000000..012ea1eac7 --- /dev/null +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -0,0 +1,1209 @@ +import { JsonStatement } from 'src/jsonStatements'; +import { SQLiteSchemaSquashed } from 'src/serializer/sqliteSchema'; +import { libSQLCombineStatements } from 'src/statementCombiner'; +import { expect, test } from 'vitest'; + +/** + * ! before: + * + * user: { + * id INT; + * first_name INT; + * iq INT; + * PRIMARY KEY (id, iq) + * INDEXES: { + * UNIQUE id; + * } + * } + * + * ! after: + * + * new_user: { + * id INT; + * first_name INT; + * iq INT; + * PRIMARY KEY (id, iq) + * INDEXES: {} + * } + * + * rename table and drop unique index + * expect to get "rename_table" statement and then "recreate_table" + */ +test(`rename table and drop index`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'rename_table', + fromSchema: '', + toSchema: '', + tableNameFrom: 'user', + tableNameTo: 'new_user', + }, + { + type: 'drop_index', + tableName: 'new_user', + data: 'user_first_name_unique;first_name;true;', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + first_name: { + name: 'first_name', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: { + user_first_name_unique: 'user_first_name_unique;first_name;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: { + user_id_iq_pk: 'id,iq', + }, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + new_user: { + name: 'new_user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + first_name: { + name: 'first_name', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: { + new_user_id_iq_pk: 'id,iq', + }, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'rename_table', + fromSchema: '', + toSchema: '', + tableNameFrom: 'user', + tableNameTo: 'new_user', + }, + { + type: 'drop_index', + tableName: 'new_user', + data: 'user_first_name_unique;first_name;true;', + schema: '', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * autoincrement1: { + * id INT PRIMARY KEY; + * } + * + * autoincrement2: { + * id INT PRIMARY KEY AUTOINCREMENT; + * } + * + * dropNotNull: { + * id INT NOT NULL; + * } + * + * ! after: + * + * autoincrement1: { + * id INT PRIMARY KEY AUTOINCREMENT; + * } + * + * autoincrement2: { + * id INT PRI { + const statements: JsonStatement[] = [ + { + type: 'alter_table_alter_column_set_autoincrement', + tableName: 'autoincrement1', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: true, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_autoincrement', + tableName: 'autoincrement2', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'dropNotNull', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + autoincrement1: { + name: 'autoincrement1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + autoincrement2: { + name: 'autoincrement2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: false, + autoincrement: true, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + dropNotNull: { + name: 'dropNotNull', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + autoincrement1: { + name: 'autoincrement1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + autoincrement2: { + name: 'autoincrement2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + dropNotNull: { + name: 'dropNotNull', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'autoincrement1', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'recreate_table', + tableName: 'autoincrement2', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'dropNotNull', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * pk1: { + * id INT; + * } + * + * pk2: { + * id INT PRIMARY KEY; + * } + * + * ref_table: { + * id INT; + * } + * + * create_reference: { + * id INT; + * } + * + * ! after: + * + * pk1: { + * id INT PRIMARY KEY; + * } + * + * pk2: { + * id INT; + * } + * + * ref_table: { + * id INT; + * } + * + * create_reference: { + * id INT -> ref_table INT; + * } + * + * drop primary key for pk2 + * set primary key for pk1 + * "create_reference" reference on "ref_table" + * + * expect to: + * - "recreate_table" statement for pk1 + * - "recreate_table" statement for pk2 + * - "create_reference" statement for create_reference + */ +test(`drop and set primary key. create reference`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_alter_column_set_pk', + tableName: 'pk1', + schema: '', + columnName: 'id', + }, + { + type: 'alter_table_alter_column_set_notnull', + tableName: 'pk1', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_pk', + tableName: 'pk2', + columnName: 'id', + schema: '', + }, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'pk2', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'create_reference', + tableName: 'create_reference', + data: 'create_reference_id_ref_table_id_fk;create_reference;id;ref_table;id;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'int', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + create_reference: { + name: 'create_reference', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk1: { + name: 'pk1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk2: { + name: 'pk2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + create_reference: { + name: 'create_reference', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + create_reference_id_ref_table_id_fk: + 'create_reference_id_ref_table_id_fk;create_reference;id;ref_table;id;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk1: { + name: 'pk1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk2: { + name: 'pk2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'pk1', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'recreate_table', + tableName: 'pk2', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'create_reference', + tableName: 'create_reference', + data: 'create_reference_id_ref_table_id_fk;create_reference;id;ref_table;id;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'int', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * fk1: { + * fk_id INT; + * fk_id1 INT; + * } + * + * fk2: { + * fk2_id INT; -> composite reference on ref_table id INT + * fk2_id1 INT; -> composite reference on ref_table id1 INT + * } + * + * ref_table: { + * id INT; + * id1 INT; + * } + * + * ! after: + * + * fk1: { + * fk_id INT; -> composite reference on ref_table id INT + * fk_id1 INT; -> composite reference on ref_table id1 INT + * } + * + * fk2: { + * fk2_id INT; + * fk2_id1 INT; + * } + * + * ref_table: { + * id INT; + * id1 INT; + * } + * + * set multi column reference for fk1 + * drop multi column reference for fk2 + * + * expect to: + * - "recreate_table" statement for fk1 + * - "recreate_table" statement for fk2 + */ +test(`set and drop multiple columns reference`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'delete_reference', + tableName: 'fk1', + data: 'fk1_fk_id_fk_id1_ref_table_id_id1_fk;fk1;fk_id,fk_id1;ref_table;id,id1;no action;no action', + schema: '', + isMulticolumn: true, + }, + { + type: 'create_reference', + tableName: 'fk2', + data: 'fk2_fk2_id_fk2_id1_ref_table_id_id1_fk;fk2;fk2_id,fk2_id1;ref_table;id,id1;no action;no action', + schema: '', + isMulticolumn: true, + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + fk1: { + name: 'fk1', + columns: { + fk_id: { + name: 'fk_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk_id1: { + name: 'fk_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + fk1_fk_id_fk_id1_ref_table_id_id1_fk: + 'fk1_fk_id_fk_id1_ref_table_id_id1_fk;fk1;fk_id,fk_id1;ref_table;id,id1;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + fk2: { + name: 'fk2', + columns: { + fk2_id: { + name: 'fk2_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk2_id1: { + name: 'fk2_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + id1: { + name: 'id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + fk1: { + name: 'fk1', + columns: { + fk_id: { + name: 'fk_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk_id1: { + name: 'fk_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + fk2: { + name: 'fk2', + columns: { + fk2_id: { + name: 'fk2_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk2_id1: { + name: 'fk2_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + fk2_fk2_id_fk2_id1_ref_table_id_id1_fk: + 'fk2_fk2_id_fk2_id1_ref_table_id_id1_fk;fk2;fk2_id,fk2_id1;ref_table;id,id1;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + id1: { + name: 'id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'fk1', + columns: [ + { + name: 'fk_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'fk_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'recreate_table', + tableName: 'fk2', + columns: [ + { + name: 'fk2_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'fk2_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [ + { + name: 'fk2_fk2_id_fk2_id1_ref_table_id_id1_fk', + tableFrom: 'fk2', + tableTo: 'ref_table', + columnsFrom: ['fk2_id', 'fk2_id1'], + columnsTo: ['id', 'id1'], + onDelete: 'no action', + onUpdate: 'no action', + }, + ], + uniqueConstraints: [], + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * pk: { + * pk TEXT PRIMARY KEY; + * } + * + * simple: { + * simple TEXT; + * } + * + * unique: { + * unique INT UNIQUE; + * } + * + * ! after: + * + * pk: { + * pk INT PRIMARY KEY; + * } + * + * simple: { + * simple INT; + * } + * + * unique: { + * unique TEXT UNIQUE; + * } + * + * set new type for primary key column + * set new type for unique column + * set new type for column without pk or unique + * + * expect to: + * - "recreate_table" statement for pk + * - "recreate_table" statement for unique + * - "alter_table_alter_column_set_type" statement for simple + * - "create_index" statement for unique + */ +test(`set new type for primary key, unique and normal column`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_alter_column_set_type', + tableName: 'pk', + columnName: 'pk', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_set_type', + tableName: 'simple', + columnName: 'simple', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_set_type', + tableName: 'unique', + columnName: 'unique', + newDataType: 'text', + oldDataType: 'int', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'text', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + simple: { + name: 'simple', + columns: { + simple: { + name: 'simple', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + simple: { + name: 'simple', + columns: { + simple: { + name: 'simple', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'pk', + columns: [ + { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'alter_table_alter_column_set_type', + tableName: 'simple', + columnName: 'simple', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }, + { + type: 'recreate_table', + tableName: 'unique', + columns: [ + { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + data: 'unique_unique_unique;unique;true;', + internal: undefined, + schema: '', + tableName: 'unique', + type: 'create_index', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); diff --git a/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts new file mode 100644 index 0000000000..517343d9b9 --- /dev/null +++ b/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts @@ -0,0 +1,778 @@ +import { JsonStatement } from 'src/jsonStatements'; +import { SQLiteSchemaSquashed } from 'src/serializer/sqliteSchema'; +import { sqliteCombineStatements } from 'src/statementCombiner'; +import { expect, test } from 'vitest'; + +test(`renamed column and altered this column type`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'user', + oldColumnName: 'lastName', + newColumnName: 'lastName123', + schema: '', + }, + { + type: 'alter_table_alter_column_set_type', + tableName: 'user', + columnName: 'lastName123', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + columnIsUnique: false, + } as unknown as JsonStatement, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName123', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'user', + columns: [ + { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + { + name: 'lastName123', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'test', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`renamed column and droped column "test"`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'user', + oldColumnName: 'lastName', + newColumnName: 'lastName123', + schema: '', + }, + { + type: 'alter_table_drop_column', + tableName: 'user', + columnName: 'test', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName123', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'user', + oldColumnName: 'lastName', + newColumnName: 'lastName123', + schema: '', + }, + { + type: 'alter_table_drop_column', + tableName: 'user', + columnName: 'test', + schema: '', + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`droped column that is part of composite pk`, async (t) => { + const statements: JsonStatement[] = [ + { type: 'delete_composite_pk', tableName: 'user', data: 'id,iq' }, + { + type: 'alter_table_alter_column_set_pk', + tableName: 'user', + schema: '', + columnName: 'id', + }, + { + type: 'alter_table_drop_column', + tableName: 'user', + columnName: 'iq', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + first_nam: { + name: 'first_nam', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: { + user_id_iq_pk: 'id,iq', + }, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: false, + autoincrement: false, + }, + first_nam: { + name: 'first_nam', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'recreate_table', + tableName: 'user', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: false, + autoincrement: false, + }, + { + name: 'first_nam', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`drop column "ref"."name", rename column "ref"."age". dropped primary key "user"."id". Set not null to "user"."iq"`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'ref', + oldColumnName: 'age', + newColumnName: 'age1', + schema: '', + }, + { + type: 'alter_table_alter_column_drop_pk', + tableName: 'user', + columnName: 'id', + schema: '', + }, + { + type: 'alter_table_alter_column_drop_autoincrement', + tableName: 'user', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'user', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_set_notnull', + tableName: 'user', + columnName: 'iq', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_drop_column', + tableName: 'ref', + columnName: 'text', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + user_iq: { + name: 'user_iq', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + name: { + name: 'name', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + age: { + name: 'age', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_user_iq_user_iq_fk: 'ref_user_iq_user_iq_fk;ref;user_iq;user;iq;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + first_name: { + name: 'first_name', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + user_iq: { + name: 'user_iq', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + age1: { + name: 'age1', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_user_iq_user_iq_fk: 'ref_user_iq_user_iq_fk;ref;user_iq;user;iq;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + first_name: { + name: 'first_name', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'ref', + oldColumnName: 'age', + newColumnName: 'age1', + schema: '', + }, + { + type: 'alter_table_drop_column', + tableName: 'ref', + columnName: 'text', + schema: '', + }, + { + type: 'recreate_table', + tableName: 'user', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + { + name: 'first_name', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + ]; + + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`create reference on exising column (table includes unique index). expect to recreate column and recreate index`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'create_reference', + tableName: 'unique', + data: 'unique_ref_pk_pk_pk_fk;unique;ref_pk;pk;pk;no action;no action', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ref_pk: { + name: 'ref_pk', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ref_pk: { + name: 'ref_pk', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: { + unique_ref_pk_pk_pk_fk: 'unique_ref_pk_pk_pk_fk;unique;ref_pk;pk;pk;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'recreate_table', + tableName: 'unique', + columns: [ + { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'ref_pk', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [ + { + name: 'unique_ref_pk_pk_pk_fk', + tableFrom: 'unique', + tableTo: 'pk', + columnsFrom: ['ref_pk'], + columnsTo: ['pk'], + onDelete: 'no action', + onUpdate: 'no action', + }, + ], + uniqueConstraints: [], + }, + { + data: 'unique_unique_unique;unique;true;', + internal: undefined, + schema: '', + tableName: 'unique', + type: 'create_index', + }, + ]; + + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); From 0b768d4cee58295e9a2a2f9e7d94b4a8de99f0da Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 12 Aug 2024 18:14:08 +0300 Subject: [PATCH 113/152] - updated tests - added handling create reference and create column for sqlite and libsql --- drizzle-kit/src/cli/validations/cli.ts | 2 +- drizzle-kit/src/jsonStatements.ts | 1 - drizzle-kit/src/sqlgenerator.ts | 34 +- drizzle-kit/src/statementCombiner.ts | 83 ++- drizzle-kit/tests/cli-generate.test.ts | 10 + drizzle-kit/tests/cli-push.test.ts | 2 + drizzle-kit/tests/libsql-statements.test.ts | 41 ++ drizzle-kit/tests/sqlite-columns.test.ts | 271 ++++++--- drizzle-kit/tests/sqlite-tables.test.ts | 14 +- .../libsql-statements-combiner.test.ts | 552 +++++++++++++++++- ....ts => sqlite-statements-combiner.test.ts} | 392 +++++++++++++ 11 files changed, 1265 insertions(+), 137 deletions(-) rename drizzle-kit/tests/statements-combiner/{sqilte-statements-combiner.test.ts => sqlite-statements-combiner.test.ts} (66%) diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 9f982b0582..9d580fbe4f 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -25,7 +25,7 @@ export const pushParams = object({ extensionsFilters: literal('postgis').array().optional(), verbose: boolean().optional(), strict: boolean().optional(), - driver: driver, + driver: driver.optional(), }).passthrough(); export type PushParams = TypeOf; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index dc9511e4b7..99f2ad6f04 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2021,7 +2021,6 @@ export const prepareSqliteAlterColumns = ( columns: AlteredColumn[], // TODO: remove? json2: CommonSquashedSchema, - driver?: 'turso', ): JsonAlterColumnStatement[] => { let statements: JsonAlterColumnStatement[] = []; let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index e3f5c2b209..cdb2595c45 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1691,9 +1691,7 @@ type LibSQLModifyColumnStatement = | JsonAlterColumnDropNotNullStatement | JsonAlterColumnSetNotNullStatement | JsonAlterColumnSetDefaultStatement - | JsonAlterColumnDropDefaultStatement - | JsonAlterColumnSetGeneratedStatement - | JsonAlterColumnDropGeneratedStatement; + | JsonAlterColumnDropDefaultStatement; export class LibSQLModifyColumn extends Convertor { can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { @@ -1758,36 +1756,6 @@ export class LibSQLModifyColumn extends Convertor { columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; break; - case 'alter_table_alter_column_drop_generated': - columnType = ` ${statement.newDataType}`; - - columnDefault = ''; - - columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; - break; - case 'alter_table_alter_column_set_generated': - return [ - new SQLiteAlterTableDropColumnConvertor().convert({ - type: 'alter_table_drop_column', - tableName: statement.tableName, - columnName: statement.columnName, - schema: '', - }), - new SQLiteAlterTableAddColumnConvertor().convert({ - tableName, - column: { - name: columnName, - type: statement.newDataType, - notNull: statement.columnNotNull, - default: statement.columnDefault, - onUpdate: statement.columnOnUpdate, - autoincrement: statement.columnAutoIncrement, - primaryKey: statement.columnPk, - generated: statement.columnGenerated, - }, - type: 'sqlite_alter_table_add_column', - }), - ]; } // Seems like getting value from simple json2 shanpshot makes dates be dates diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts index 21cc86b386..549457cf18 100644 --- a/drizzle-kit/src/statementCombiner.ts +++ b/drizzle-kit/src/statementCombiner.ts @@ -180,29 +180,54 @@ export const libSQLCombineStatements = ( continue; } - if (statement.type === 'create_reference' && statement.isMulticolumn) { + if (statement.type === 'create_reference') { const tableName = statement.tableName; + const data = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + const statementsForTable = newStatements[tableName]; if (!statementsForTable) { - newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + newStatements[tableName] = statement.isMulticolumn + ? prepareLibSQLRecreateTable(json2.tables[tableName], action) + : newStatements[tableName] = [statement]; + continue; } - if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { - const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + // if add column with reference -> skip create_reference statement + if ( + !statement.isMulticolumn + && statementsForTable.some((st) => + st.type === 'sqlite_alter_table_add_column' && st.column.name === data.columnsFrom[0] + ) + ) { + continue; + } - if (wasRename) { - newStatements[tableName].push(...preparedStatements); - } else { - newStatements[tableName] = preparedStatements; + if (statement.isMulticolumn) { + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; } continue; } + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + continue; } @@ -300,7 +325,6 @@ export const sqliteCombineStatements = ( || statement.type === 'alter_table_alter_column_set_autoincrement' || statement.type === 'alter_table_alter_column_drop_pk' || statement.type === 'alter_table_alter_column_set_pk' - || statement.type === 'create_reference' || statement.type === 'delete_reference' || statement.type === 'alter_reference' || statement.type === 'create_composite_pk' @@ -360,6 +384,45 @@ export const sqliteCombineStatements = ( continue; } + if (statement.type === 'create_reference') { + const tableName = statement.tableName; + + const data = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareSQLiteRecreateTable(json2.tables[tableName], action); + continue; + } + + // if add column with reference -> skip create_reference statement + if ( + data.columnsFrom.length === 1 + && statementsForTable.some((st) => + st.type === 'sqlite_alter_table_add_column' && st.column.name === data.columnsFrom[0] + ) + ) { + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + const tableName = statement.type === 'rename_table' ? statement.tableNameTo : (statement as { tableName: string }).tableName; diff --git a/drizzle-kit/tests/cli-generate.test.ts b/drizzle-kit/tests/cli-generate.test.ts index 3e5c0fc226..6eece02490 100644 --- a/drizzle-kit/tests/cli-generate.test.ts +++ b/drizzle-kit/tests/cli-generate.test.ts @@ -38,6 +38,7 @@ test('generate #1', async (t) => { schema: 'schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -57,11 +58,13 @@ test('generate #2', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, + driver: undefined, }); }); test('generate #3', async (t) => { const res = await brotest(generate, ''); + if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ dialect: 'postgresql', @@ -72,6 +75,7 @@ test('generate #3', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -89,6 +93,7 @@ test('generate #4', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -105,6 +110,7 @@ test('generate #5', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -121,6 +127,7 @@ test('generate #6', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -140,6 +147,7 @@ test('generate #7', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -157,6 +165,7 @@ test('generate #8', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: true, // expo driver + driver: 'expo', }); }); @@ -177,6 +186,7 @@ test('generate #9', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, + driver: undefined, }); }); diff --git a/drizzle-kit/tests/cli-push.test.ts b/drizzle-kit/tests/cli-push.test.ts index 1a4bde66d8..fb1ed3a113 100644 --- a/drizzle-kit/tests/cli-push.test.ts +++ b/drizzle-kit/tests/cli-push.test.ts @@ -46,6 +46,7 @@ test('push #2', async (t) => { tablesFilter: [], strict: false, verbose: false, + driver: 'turso', }); }); @@ -66,6 +67,7 @@ test('push #3', async (t) => { tablesFilter: [], strict: false, verbose: false, + driver: 'd1-http', }); }); diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index adf354458e..927411e443 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -833,3 +833,44 @@ test('drop foriegn key for multiple columns', async (t) => { `DROP TABLE \`__old__generate_users\`;`, ); }); + +test('alter column drop generated', async (t) => { + const from = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), + }), + }; + + const to = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + from, + to, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'table', + type: 'alter_table_alter_column_drop_generated', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); +}); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index 8a258072a9..e71b95e019 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -8,6 +8,7 @@ import { sqliteTable, text, } from 'drizzle-orm/sqlite-core'; +import { JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemasSqlite } from './schemaDiffer'; @@ -223,7 +224,7 @@ test('add columns #5', async (t) => { const { statements } = await diffTestSchemasSqlite(schema1, schema2, []); // TODO: Fix here - expect(statements.length).toBe(2); + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'sqlite_alter_table_add_column', tableName: 'users', @@ -332,12 +333,38 @@ test('add foreign key #1', async (t) => { const { statements } = await diffTestSchemasSqlite(schema1, schema2, []); expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'create_reference', - tableName: 'users', - schema: '', - data: 'users_report_to_users_id_fk;users;report_to;users;id;no action;no action', - }); + expect(statements[0]).toStrictEqual( + { + type: 'recreate_table', + columns: [{ + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, { + autoincrement: false, + generated: undefined, + name: 'report_to', + notNull: false, + primaryKey: false, + type: 'integer', + }], + compositePKs: [], + referenceData: [{ + columnsFrom: ['report_to'], + columnsTo: ['id'], + name: 'users_report_to_users_id_fk', + tableFrom: 'users', + tableTo: 'users', + onDelete: 'no action', + onUpdate: 'no action', + }], + tableName: 'users', + uniqueConstraints: [], + } as JsonRecreateTableStatement, + ); }); test('add foreign key #2', async (t) => { @@ -371,11 +398,35 @@ test('add foreign key #2', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'create_reference', + type: 'recreate_table', + columns: [{ + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, { + autoincrement: false, + generated: undefined, + name: 'report_to', + notNull: false, + primaryKey: false, + type: 'integer', + }], + compositePKs: [], + referenceData: [{ + columnsFrom: ['report_to'], + columnsTo: ['id'], + name: 'reportee_fk', + tableFrom: 'users', + tableTo: 'users', + onDelete: 'no action', + onUpdate: 'no action', + }], tableName: 'users', - schema: '', - data: 'reportee_fk;users;report_to;users;id;no action;no action', - }); + uniqueConstraints: [], + } as JsonRecreateTableStatement); }); test('alter column change name #1', async (t) => { @@ -513,9 +564,26 @@ test('alter table add composite pk', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'create_composite_pk', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'id1', + notNull: false, + primaryKey: false, + type: 'integer', + }, { + autoincrement: false, + generated: undefined, + name: 'id2', + notNull: false, + primaryKey: false, + type: 'integer', + }], + compositePKs: [['id1', 'id2']], + referenceData: [], tableName: 'table', - data: 'id1,id2', + uniqueConstraints: [], }); }); @@ -540,16 +608,19 @@ test('alter column drop not null', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_drop_notnull', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnDefault: undefined, - columnOnUpdate: undefined, - columnNotNull: false, - columnAutoIncrement: false, - columnPk: false, + uniqueConstraints: [], }); }); @@ -574,16 +645,19 @@ test('alter column add not null', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_set_notnull', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnDefault: undefined, - columnOnUpdate: undefined, - columnNotNull: true, - columnAutoIncrement: false, - columnPk: false, + uniqueConstraints: [], }); }); @@ -608,16 +682,20 @@ test('alter column add default', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_set_default', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + default: "'dan'", + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnNotNull: false, - columnOnUpdate: undefined, - columnAutoIncrement: false, - newDefaultValue: "'dan'", - columnPk: false, + uniqueConstraints: [], }); }); @@ -642,16 +720,19 @@ test('alter column drop default', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_drop_default', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnNotNull: false, - columnOnUpdate: undefined, - columnDefault: undefined, - columnAutoIncrement: false, - columnPk: false, + uniqueConstraints: [], }); }); @@ -674,31 +755,22 @@ test('alter column add default not null', async (t) => { [], ); - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnName: 'name', - columnNotNull: true, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - newDefaultValue: "'dan'", - schema: '', - tableName: 'table', - type: 'alter_table_alter_column_set_default', - }); - + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnName: 'name', - columnNotNull: true, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - newDefaultValue: "'dan'", - schema: '', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + default: "'dan'", + }], + compositePKs: [], + referenceData: [], tableName: 'table', - type: 'alter_table_alter_column_set_default', + uniqueConstraints: [], }); }); @@ -721,30 +793,61 @@ test('alter column drop default not null', async (t) => { [], ); - expect(statements.length).toBe(2); + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnDefault: undefined, - columnName: 'name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - type: 'alter_table_alter_column_drop_default', + uniqueConstraints: [], }); +}); +test('alter column drop generated', async (t) => { + const from = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), + }), + }; + + const to = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite( + from, + to, + [], + ); + + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ columnAutoIncrement: false, columnDefault: undefined, + columnGenerated: undefined, columnName: 'name', - columnNotNull: false, + columnNotNull: true, columnOnUpdate: undefined, columnPk: false, newDataType: 'text', schema: '', tableName: 'table', - type: 'alter_table_alter_column_drop_default', + type: 'alter_table_alter_column_drop_generated', }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); }); diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index d7781f150b..aa44908bac 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -162,6 +162,13 @@ test('add table #7', async () => { expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ + type: 'rename_table', + tableNameFrom: 'users1', + tableNameTo: 'users2', + fromSchema: undefined, + toSchema: undefined, + }); + expect(statements[1]).toStrictEqual({ type: 'sqlite_create_table', tableName: 'users', columns: [], @@ -169,13 +176,6 @@ test('add table #7', async () => { uniqueConstraints: [], referenceData: [], }); - expect(statements[1]).toStrictEqual({ - type: 'rename_table', - tableNameFrom: 'users1', - tableNameTo: 'users2', - fromSchema: undefined, - toSchema: undefined, - }); }); test('add table #8', async () => { diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts index 012ea1eac7..342e552323 100644 --- a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -1,5 +1,6 @@ -import { JsonStatement } from 'src/jsonStatements'; +import { JsonAddColumnStatement, JsonSqliteAddColumnStatement, JsonStatement } from 'src/jsonStatements'; import { SQLiteSchemaSquashed } from 'src/serializer/sqliteSchema'; +import { SQLiteAlterTableAddColumnConvertor } from 'src/sqlgenerator'; import { libSQLCombineStatements } from 'src/statementCombiner'; import { expect, test } from 'vitest'; @@ -1207,3 +1208,552 @@ test(`set new type for primary key, unique and normal column`, async (t) => { newJsonStatements, ); }); + +test(`add columns. set fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`add column and fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_test1_user_new_age_fk: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`add column and fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_test1_user_new_age_fk: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); diff --git a/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts similarity index 66% rename from drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts rename to drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts index 517343d9b9..2fcaf6436d 100644 --- a/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts @@ -776,3 +776,395 @@ test(`create reference on exising column (table includes unique index). expect t newJsonStatements, ); }); + +test(`add columns. set fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + columns: [ + { + autoincrement: false, + name: 'id1', + notNull: true, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'new_age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'test', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'test1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'new_age', + ], + columnsTo: [ + 'new_age', + ], + name: 'ref_new_age_user_new_age_fk', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'ref', + tableTo: 'user', + }, + ], + tableName: 'ref', + type: 'recreate_table', + uniqueConstraints: [], + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`add column and fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_test1_user_new_age_fk: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); From 7239e9f8e8bce026a3ae06afd94e134ae22d6a7c Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 15 Aug 2024 18:21:10 +0300 Subject: [PATCH 114/152] - handled foreign keys for recreate table - handled alter column with unique keys - made more tests - updated recreate sql statements order --- drizzle-kit/package.json | 2 +- .../src/cli/commands/libSqlPushUtils.ts | 74 ++- .../src/cli/commands/sqlitePushUtils.ts | 58 +- drizzle-kit/src/jsonStatements.ts | 2 +- drizzle-kit/src/sqlgenerator.ts | 351 +++-------- drizzle-kit/src/statementCombiner.ts | 24 +- drizzle-kit/tests/libsql-statements.test.ts | 335 +++++++---- drizzle-kit/tests/push/libsql.test.ts | 438 ++++++++++++-- drizzle-kit/tests/push/sqlite.test.ts | 554 ++++++++++++++---- drizzle-kit/tests/sqlite-columns.test.ts | 141 ++++- .../libsql-statements-combiner.test.ts | 28 +- 11 files changed, 1388 insertions(+), 619 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 552c14d0ec..8bfdebac47 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -38,7 +38,7 @@ "build": "rm -rf ./dist && tsx build.ts && cp package.json dist/ && attw --pack dist", "build:dev": "rm -rf ./dist && tsx build.dev.ts && tsc -p tsconfig.cli-types.json && chmod +x ./dist/index.cjs", "pack": "cp package.json README.md dist/ && (cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", - "tsc": "tsc -p tsconfig.build.json", + "tsc": "tsc -p tsconfig.cli-types.json", "publish": "npm publish package.tgz" }, "dependencies": { diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 537eee0a5a..3bc9e82257 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -32,54 +32,62 @@ export const _moveDataStatements = ( ) => { const statements: string[] = []; - statements.push( - new SqliteRenameTableConvertor().convert({ - type: 'rename_table', - tableNameFrom: tableName, - tableNameTo: `__old_push_${tableName}`, - fromSchema: '', - toSchema: '', - }), - ); + const newTableName = `__new_${tableName}`; + // create table statement from a new json2 with proper name const tableColumns = Object.values(json.tables[tableName].columns); const referenceData = Object.values(json.tables[tableName].foreignKeys); const compositePKs = Object.values( json.tables[tableName].compositePrimaryKeys, ).map((it) => SQLiteSquasher.unsquashPK(it)); + const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); + + // create new table statements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName: tableName, + tableName: newTableName, columns: tableColumns, - referenceData: referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)), + referenceData: fks, compositePKs, }), ); + // move data if (!dataLoss) { const columns = Object.keys(json.tables[tableName].columns).map( (c) => `"${c}"`, ); statements.push( - `INSERT INTO \`${tableName}\`(${ + `INSERT INTO \`${newTableName}\`(${ columns.join( ', ', ) - }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, + }) SELECT ${columns.join(', ')} FROM \`${tableName}\`;`, ); } statements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old_push_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + statements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + for (const idx of Object.values(json.tables[tableName].indexes)) { statements.push( new CreateSqliteIndexConvertor().convert({ @@ -90,7 +98,6 @@ export const _moveDataStatements = ( }), ); } - return statements; }; @@ -216,6 +223,8 @@ export const libSqlLogSuggestionsAndReturn = async ( } else if (statement.type === 'recreate_table') { const tableName = statement.tableName; + let dataLoss = false; + const oldTableName = getOldTableName(tableName, meta); const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); @@ -249,28 +258,31 @@ export const libSqlLogSuggestionsAndReturn = async ( if (addedColumns.length) { for (const addedColumn of addedColumns) { const [res] = await connection.query<{ count: string }>( - `select count(\`${tableName}\`.\`${addedColumn}\`) as count from \`${tableName}\``, + `select count(*) as count from \`${tableName}\``, ); const columnConf = json2.tables[tableName].columns[addedColumn]; const count = Number(res.count); if (count > 0 && columnConf.notNull && !columnConf.default) { + dataLoss = true; + infoToPrint.push( `· You're about to add not-null ${ chalk.underline( addedColumn, ) - } column without default value, which contains ${count} items`, + } column without default value to table, which contains ${count} items`, ); shouldAskForApprove = true; tablesToTruncate.push(tableName); + + statementsToExecute.push(`DELETE FROM \`${tableName}\`;`); } } } - statementsToExecute.push(..._moveDataStatements(tableName, json2)); - + // check if some tables referencing current for pragma const tablesReferencingCurrent: string[] = []; for (const table of Object.values(json2.tables)) { @@ -281,12 +293,26 @@ export const libSqlLogSuggestionsAndReturn = async ( tablesReferencingCurrent.push(...tablesRefs); } - const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; - - for (const table of uniqueTableRefs) { - statementsToExecute.push(..._moveDataStatements(table, json2)); + if (!tablesReferencingCurrent.length) { + statementsToExecute.push(..._moveDataStatements(tableName, json2, dataLoss)); + continue; } - } else if (statement.type === 'alter_table_alter_column_set_generated') { + + // ! for libsql it will break + const [{ foreign_keys: pragmaState }] = await connection.query<{ + foreign_keys: number; + }>(`PRAGMA foreign_keys;`); + + if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=OFF;`); + // recreate table + statementsToExecute.push( + ..._moveDataStatements(tableName, json2, dataLoss), + ); + if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=ON;`); + } else if ( + statement.type === 'alter_table_alter_column_set_generated' + || statement.type === 'alter_table_alter_column_drop_generated' + ) { const tableName = statement.tableName; const res = await connection.query<{ count: string }>( diff --git a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts index e04546157d..bcc2d19dbd 100644 --- a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts +++ b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts @@ -19,16 +19,7 @@ export const _moveDataStatements = ( ) => { const statements: string[] = []; - // rename table to __old_${tablename} - statements.push( - new SqliteRenameTableConvertor().convert({ - type: 'rename_table', - tableNameFrom: tableName, - tableNameTo: `__old_push_${tableName}`, - fromSchema: '', - toSchema: '', - }), - ); + const newTableName = `__new_${tableName}`; // create table statement from a new json2 with proper name const tableColumns = Object.values(json.tables[tableName].columns); @@ -39,10 +30,11 @@ export const _moveDataStatements = ( const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); + // create new table statements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName: tableName, + tableName: newTableName, columns: tableColumns, referenceData: fks, compositePKs, @@ -56,22 +48,33 @@ export const _moveDataStatements = ( ); statements.push( - `INSERT INTO \`${tableName}\`(${ + `INSERT INTO \`${newTableName}\`(${ columns.join( ', ', ) - }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, + }) SELECT ${columns.join(', ')} FROM \`${tableName}\`;`, ); } - // drop table with name __old_${tablename} + statements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old_push_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + statements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + for (const idx of Object.values(json.tables[tableName].indexes)) { statements.push( new CreateSqliteIndexConvertor().convert({ @@ -207,6 +210,8 @@ export const logSuggestionsAndReturn = async ( const tableName = statement.tableName; const oldTableName = getOldTableName(tableName, meta); + let dataLoss = false; + const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); const currentColumnNames = Object.keys(json2.tables[tableName].columns); const { removedColumns, addedColumns } = findAddedAndRemoved( @@ -245,6 +250,7 @@ export const logSuggestionsAndReturn = async ( const count = Number(res.count); if (count > 0 && columnConf.notNull && !columnConf.default) { + dataLoss = true; infoToPrint.push( `· You're about to add not-null ${ chalk.underline( @@ -254,12 +260,13 @@ export const logSuggestionsAndReturn = async ( ); shouldAskForApprove = true; tablesToTruncate.push(tableName); + + statementsToExecute.push(`DELETE FROM \`${tableName}\`;`); } } } - statementsToExecute.push(..._moveDataStatements(tableName, json2)); - + // check if some tables referencing current for pragma const tablesReferencingCurrent: string[] = []; for (const table of Object.values(json2.tables)) { @@ -270,10 +277,21 @@ export const logSuggestionsAndReturn = async ( tablesReferencingCurrent.push(...tablesRefs); } - const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; + if (!tablesReferencingCurrent.length) { + statementsToExecute.push(..._moveDataStatements(tableName, json2, dataLoss)); + continue; + } + + const [{ foreign_keys: pragmaState }] = await connection.query<{ + foreign_keys: number; + }>(`PRAGMA foreign_keys;`); - for (const table of uniqueTableRefs) { - statementsToExecute.push(..._moveDataStatements(table, json2)); + if (pragmaState) { + statementsToExecute.push(`PRAGMA foreign_keys=OFF;`); + } + statementsToExecute.push(..._moveDataStatements(tableName, json2, dataLoss)); + if (pragmaState) { + statementsToExecute.push(`PRAGMA foreign_keys=ON;`); } } else { const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 99f2ad6f04..c4c51d4b40 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2481,7 +2481,7 @@ export const prepareLibSQLDropReferencesJson = ( : SQLiteSquasher.unsquashFK(fkData); // If all columns from where were references were deleted -> skip this logic - // Drop colums will cover this scenario + // Drop columns will cover this scenario const keys = Object.keys(json2.tables[tableName].columns); const filtered = columnsFrom.filter((it) => keys.includes(it)); const fullDrop = filtered.length === 0; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index cdb2595c45..bcd47565ad 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1242,27 +1242,6 @@ class PgAlterTableAlterColumnSetTypeConvertor extends Convertor { } } -class SQLiteAlterTableAlterColumnSetTypeConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_set_type' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnTypeStatement) { - return ( - '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgAlterTableAlterColumnSetDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1282,26 +1261,6 @@ class PgAlterTableAlterColumnSetDefaultConvertor extends Convertor { } } -class SqliteAlterTableAlterColumnSetDefaultConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return ( - statement.type === 'alter_table_alter_column_set_default' - && dialect === 'sqlite' - ); - } - - convert(statement: JsonAlterColumnSetDefaultStatement) { - return ( - '/*\n SQLite does not support "Set default to column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgAlterTableAlterColumnDropDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1706,13 +1665,31 @@ export class LibSQLModifyColumn extends Convertor { ); } - convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed) { + convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed, action?: 'push') { const { tableName, columnName } = statement; let columnType = ``; let columnDefault: any = ''; let columnNotNull = ''; + const sqlStatements: string[] = []; + + // collect index info + const indexes: { + name: string; + tableName: string; + columns: string[]; + isUnique: boolean; + where?: string | undefined; + }[] = []; + for (const table of Object.values(json2.tables)) { + for (const index of Object.values(table.indexes)) { + const unsquashed = SQLiteSquasher.unsquashIdx(index); + sqlStatements.push(`DROP INDEX IF EXISTS "${unsquashed.name}";`); + indexes.push({ ...unsquashed, tableName: table.name }); + } + } + switch (statement.type) { case 'alter_table_alter_column_set_type': columnType = ` ${statement.newDataType}`; @@ -1763,7 +1740,22 @@ export class LibSQLModifyColumn extends Convertor { ? columnDefault.toISOString() : columnDefault; - return `ALTER TABLE \`${tableName}\` ALTER COLUMN "${columnName}" TO "${columnName}"${columnType}${columnNotNull}${columnDefault};`; + sqlStatements.push( + `ALTER TABLE \`${tableName}\` ALTER COLUMN "${columnName}" TO "${columnName}"${columnType}${columnNotNull}${columnDefault};`, + ); + + for (const index of indexes) { + const indexPart = index.isUnique ? 'UNIQUE INDEX' : 'INDEX'; + const whereStatement = index.where ? ` WHERE ${index.where}` : ''; + const uniqueString = index.columns.map((it) => `\`${it}\``).join(','); + const tableName = index.tableName; + + sqlStatements.push( + `CREATE ${indexPart} \`${index.name}\` ON \`${tableName}\` (${uniqueString})${whereStatement};`, + ); + } + + return sqlStatements; } } @@ -2632,69 +2624,6 @@ class PgAlterTableAlterColumnSetNotNullConvertor extends Convertor { } } -class SqliteAlterTableAlterColumnSetNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_set_notnull' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnSetNotNullStatement) { - return ( - '/*\n SQLite does not support "Set not null to column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - -class SqliteAlterTableAlterColumnSetAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_set_autoincrement' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnSetAutoincrementStatement) { - return ( - '/*\n SQLite does not support "Set autoincrement to a column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - -class SqliteAlterTableAlterColumnDropAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_drop_autoincrement' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnDropAutoincrementStatement) { - return ( - '/*\n SQLite does not support "Drop autoincrement from a column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgAlterTableAlterColumnDropNotNullConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2714,27 +2643,6 @@ class PgAlterTableAlterColumnDropNotNullConvertor extends Convertor { } } -class SqliteAlterTableAlterColumnDropNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_drop_notnull' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnDropNotNullStatement) { - return ( - '/*\n SQLite does not support "Drop not null from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - // FK class PgCreateForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { @@ -2777,24 +2685,6 @@ class PgCreateForeignKeyConvertor extends Convertor { } } -class SqliteCreateForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'create_reference' && dialect === 'sqlite' && !driver - ); - } - - convert(statement: JsonCreateReferenceStatement): string { - return ( - '/*\n SQLite does not support "Creating foreign key on existing column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class LibSQLCreateForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( @@ -2812,17 +2702,7 @@ class LibSQLCreateForeignKeyConvertor extends Convertor { const { columnsFrom, columnsTo, tableFrom, onDelete, onUpdate, tableTo } = action === 'push' ? SQLiteSquasher.unsquashPushFK(statement.data) : SQLiteSquasher.unsquashFK(statement.data); - const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; - - if (isMulticolumn) { - return ( - '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } + const { columnDefault, columnNotNull, columnType } = statement; const onDeleteStatement = onDelete ? ` ON DELETE ${onDelete}` : ''; const onUpdateStatement = onUpdate ? ` ON UPDATE ${onUpdate}` : ''; @@ -2910,22 +2790,6 @@ class PgAlterForeignKeyConvertor extends Convertor { } } -class SqliteAlterForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_reference' && dialect === 'sqlite'; - } - - convert(statement: JsonAlterReferenceStatement): string { - return ( - '/*\n SQLite does not support "Changing existing foreign key" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgDeleteForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_reference' && dialect === 'postgresql'; @@ -2943,66 +2807,6 @@ class PgDeleteForeignKeyConvertor extends Convertor { } } -class SqliteDeleteForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'delete_reference' && dialect === 'sqlite' && !driver - ); - } - - convert(statement: JsonDeleteReferenceStatement): string { - return ( - '/*\n SQLite does not support "Dropping foreign key" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - -class LibSQLDeleteForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'delete_reference' - && dialect === 'sqlite' - && driver === 'turso' - ); - } - - convert( - statement: JsonDeleteReferenceStatement, - json2?: SQLiteSchemaSquashed, - action?: 'push', - ): string { - const { columnsFrom, tableFrom } = action === 'push' - ? SQLiteSquasher.unsquashPushFK(statement.data) - : SQLiteSquasher.unsquashFK(statement.data); - - const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; - - if (isMulticolumn) { - return ( - '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } - - const columnsDefaultValue = columnDefault - ? ` DEFAULT ${columnDefault}` - : ''; - const columnNotNullValue = columnNotNull ? ` NOT NULL` : ''; - const columnTypeValue = columnType ? ` ${columnType}` : ''; - - const columnFrom = columnsFrom[0]; - - return `ALTER TABLE \`${tableFrom}\` ALTER COLUMN "${columnFrom}" TO "${columnFrom}"${columnTypeValue}${columnNotNullValue}${columnsDefaultValue};`; - } -} - class MySqlDeleteForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_reference' && dialect === 'mysql'; @@ -3288,25 +3092,17 @@ class SQLiteRecreateTableConvertor extends Convertor { const { tableName, columns, compositePKs, referenceData } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + const newTableName = `__new_${tableName}`; const sqlStatements: string[] = []; - // rename table - sqlStatements.push( - new SqliteRenameTableConvertor().convert({ - fromSchema: '', - tableNameFrom: tableName, - tableNameTo: `__old__generate_${tableName}`, - toSchema: '', - type: 'rename_table', - }), - ); + sqlStatements.push(`PRAGMA foreign_keys=OFF;`); // create new table sqlStatements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName, + tableName: newTableName, columns, referenceData, compositePKs, @@ -3315,18 +3111,31 @@ class SQLiteRecreateTableConvertor extends Convertor { // migrate data sqlStatements.push( - `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); // migrate data sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old__generate_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + + sqlStatements.push(`PRAGMA foreign_keys=ON;`); + return sqlStatements; } } @@ -3344,25 +3153,17 @@ class LibSQLRecreateTableConvertor extends Convertor { const { tableName, columns, compositePKs, referenceData } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + const newTableName = `__new_${tableName}`; const sqlStatements: string[] = []; - // rename table - sqlStatements.push( - new SqliteRenameTableConvertor().convert({ - fromSchema: '', - tableNameFrom: tableName, - tableNameTo: `__old__generate_${tableName}`, - toSchema: '', - type: 'rename_table', - }), - ); + sqlStatements.push(`PRAGMA foreign_keys=OFF;`); // create new table sqlStatements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName, + tableName: newTableName, columns, referenceData, compositePKs, @@ -3371,18 +3172,31 @@ class LibSQLRecreateTableConvertor extends Convertor { // migrate data sqlStatements.push( - `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); // migrate data sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old__generate_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + + sqlStatements.push(`PRAGMA foreign_keys=ON;`); + return sqlStatements; } } @@ -3493,33 +3307,12 @@ convertors.push(new PgAlterTableSetSchemaConvertor()); convertors.push(new PgAlterTableSetNewSchemaConvertor()); convertors.push(new PgAlterTableRemoveFromSchemaConvertor()); -// Unhandled sqlite queries, so they will appear last -convertors.push(new SQLiteAlterTableAlterColumnSetTypeConvertor()); -convertors.push(new SqliteAlterForeignKeyConvertor()); -convertors.push(new SqliteDeleteForeignKeyConvertor()); -convertors.push(new LibSQLDeleteForeignKeyConvertor()); -convertors.push(new SqliteCreateForeignKeyConvertor()); convertors.push(new LibSQLCreateForeignKeyConvertor()); -convertors.push(new SQLiteAlterTableAddUniqueConstraintConvertor()); -convertors.push(new SQLiteAlterTableDropUniqueConstraintConvertor()); - convertors.push(new PgAlterTableAlterColumnDropGenerated()); convertors.push(new PgAlterTableAlterColumnSetGenerated()); convertors.push(new PgAlterTableAlterColumnAlterGenerated()); -convertors.push(new SqliteAlterTableAlterColumnSetNotNullConvertor()); -convertors.push(new SqliteAlterTableAlterColumnDropNotNullConvertor()); -convertors.push(new SqliteAlterTableAlterColumnSetDefaultConvertor()); -convertors.push(new SqliteAlterTableAlterColumnDropDefaultConvertor()); - -convertors.push(new SqliteAlterTableAlterColumnSetAutoincrementConvertor()); -convertors.push(new SqliteAlterTableAlterColumnDropAutoincrementConvertor()); - -convertors.push(new SqliteAlterTableCreateCompositePrimaryKeyConvertor()); -convertors.push(new SqliteAlterTableDeleteCompositePrimaryKeyConvertor()); -convertors.push(new SqliteAlterTableAlterCompositePrimaryKeyConvertor()); - convertors.push(new PgAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new PgAlterTableDeleteCompositePrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterCompositePrimaryKeyConvertor()); diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts index 549457cf18..2f7b6ddbe2 100644 --- a/drizzle-kit/src/statementCombiner.ts +++ b/drizzle-kit/src/statementCombiner.ts @@ -122,15 +122,15 @@ export const libSQLCombineStatements = ( ) { const { tableName, columnName, columnPk } = statement; - const columnIsPartOfUniqueIndex = Object.values( - json2.tables[tableName].indexes, - ).some((it) => { - const unsquashIndex = SQLiteSquasher.unsquashIdx(it); + // const columnIsPartOfUniqueIndex = Object.values( + // json2.tables[tableName].indexes, + // ).some((it) => { + // const unsquashIndex = SQLiteSquasher.unsquashIdx(it); - return ( - unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique - ); - }); + // return ( + // unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique + // ); + // }); const columnIsPartOfForeignKey = Object.values( json2.tables[tableName].foreignKeys, @@ -145,14 +145,14 @@ export const libSQLCombineStatements = ( const statementsForTable = newStatements[tableName]; if ( - !statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + !statementsForTable && (columnIsPartOfForeignKey || columnPk) ) { newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); continue; } if ( - statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + statementsForTable && (columnIsPartOfForeignKey || columnPk) ) { if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); @@ -167,7 +167,7 @@ export const libSQLCombineStatements = ( continue; } if ( - statementsForTable && !(columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + statementsForTable && !(columnIsPartOfForeignKey || columnPk) ) { if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { newStatements[tableName].push(statement); @@ -192,7 +192,7 @@ export const libSQLCombineStatements = ( if (!statementsForTable) { newStatements[tableName] = statement.isMulticolumn ? prepareLibSQLRecreateTable(json2.tables[tableName], action) - : newStatements[tableName] = [statement]; + : [statement]; continue; } diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index 927411e443..e18e41950c 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -1,4 +1,5 @@ -import { foreignKey, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { sql } from 'drizzle-orm'; +import { foreignKey, index, int, integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; import { JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemasLibSQL } from './schemaDiffer'; @@ -429,20 +430,20 @@ test('drop foriegn key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, - ); - expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`table_id\` integer );\n`); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "table_id") SELECT "id", "table_id" FROM \`users\`;`, ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('alter foriegn key', async (t) => { @@ -500,12 +501,8 @@ test('alter foriegn key', async (t) => { compositePKs: [], referenceData: [ { - columnsFrom: [ - 'table_id', - ], - columnsTo: [ - 'id', - ], + columnsFrom: ['table_id'], + columnsTo: ['id'], name: 'users_table_id_table2_id_fk', onDelete: 'no action', onUpdate: 'no action', @@ -518,21 +515,23 @@ test('alter foriegn key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - 'ALTER TABLE `users` RENAME TO `__old__generate_users`;', - ); - expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`table_id\` integer, \tFOREIGN KEY (\`table_id\`) REFERENCES \`table2\`(\`id\`) ON UPDATE no action ON DELETE no action );\n`); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "table_id") SELECT "id", "table_id" FROM \`users\`;`, ); expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + 'DROP TABLE `users`;', + ); + expect(sqlStatements[4]).toBe( + 'ALTER TABLE `__new_users` RENAME TO `users`;', ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('add foriegn key for multiple columns', async (t) => { @@ -605,14 +604,8 @@ test('add foriegn key for multiple columns', async (t) => { compositePKs: [], referenceData: [ { - columnsFrom: [ - 'column', - 'column_1', - ], - columnsTo: [ - 'age', - 'age_1', - ], + columnsFrom: ['column', 'column_1'], + columnsTo: ['age', 'age_1'], name: 'users_column_column_1_table_age_age_1_fk', onDelete: 'no action', onUpdate: 'no action', @@ -625,25 +618,24 @@ test('add foriegn key for multiple columns', async (t) => { uniqueConstraints: [], } as JsonRecreateTableStatement); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`users\` ( + `CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`column\` integer, \t\`column_1\` integer, \tFOREIGN KEY (\`column\`,\`column_1\`) REFERENCES \`table\`(\`age\`,\`age_1\`) ON UPDATE no action ON DELETE no action -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`users\`;`, ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('drop foriegn key for multiple columns', async (t) => { @@ -720,59 +712,106 @@ test('drop foriegn key for multiple columns', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`users\` ( + `CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`column\` integer, \t\`column_1\` integer -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`users\`;`, ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); -test('drop foriegn key for multiple columns', async (t) => { - const tableRef = sqliteTable('table', { - id: int('id').primaryKey({ autoIncrement: true }), - age: int('age'), - age1: int('age_1'), +test('alter column drop generated', async (t) => { + const from = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), + }), + }; + + const to = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + from, + to, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'table', + type: 'alter_table_alter_column_drop_generated', }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`, + ); +}); + +test('recreate table with nested references', async (t) => { + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); const schema1 = { - users: sqliteTable( - 'users', - { - id: int('id').primaryKey({ autoIncrement: true }), - column: int('column'), - column1: int('column_1'), - }, - (table) => ({ - foreignKey: foreignKey({ - columns: [table.column, table.column1], - foreignColumns: [tableRef.age, tableRef.age1], - }), - }), - ), - tableRef, + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), }; + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); const schema2 = { - users: sqliteTable('users', { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { id: int('id').primaryKey({ autoIncrement: true }), - column: int('column'), - column1: int('column_1'), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), }), - tableRef, }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( schema1, schema2, @@ -783,7 +822,7 @@ test('drop foriegn key for multiple columns', async (t) => { expect(statements[0]).toStrictEqual({ columns: [ { - autoincrement: true, + autoincrement: false, generated: undefined, name: 'id', notNull: true, @@ -793,15 +832,15 @@ test('drop foriegn key for multiple columns', async (t) => { { autoincrement: false, generated: undefined, - name: 'column', + name: 'name', notNull: false, primaryKey: false, - type: 'integer', + type: 'text', }, { autoincrement: false, generated: undefined, - name: 'column_1', + name: 'age', notNull: false, primaryKey: false, type: 'integer', @@ -814,63 +853,131 @@ test('drop foriegn key for multiple columns', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('set not null with index', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(3); expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + `DROP INDEX IF EXISTS "users_name_index";`, ); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`column\` integer, -\t\`column_1\` integer -); -`, + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, - ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + `CREATE INDEX \`users_name_index\` ON \`users\` (\`name\`);`, ); }); -test('alter column drop generated', async (t) => { - const from = { - users: sqliteTable('table', { - id: int('id').primaryKey().notNull(), - name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), - }), +test('drop not null with two indexes', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), }; - const to = { - users: sqliteTable('table', { - id: int('id').primaryKey().notNull(), - name: text('name').notNull(), - }), + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), }; const { statements, sqlStatements } = await diffTestSchemasLibSQL( - from, - to, + schema1, + schema2, [], ); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', columnName: 'name', - columnNotNull: true, + schema: '', + newDataType: 'text', + columnDefault: undefined, columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'table', - type: 'alter_table_alter_column_drop_generated', }); - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); - expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); + expect(sqlStatements.length).toBe(5); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS "users_name_unique";`, + ); + expect(sqlStatements[1]).toBe( + `DROP INDEX IF EXISTS "users_age_index";`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); + expect(sqlStatements[3]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + expect(sqlStatements[4]).toBe( + `CREATE INDEX \`users_age_index\` ON \`users\` (\`age\`);`, + ); }); diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 205f31f0bd..3506cef329 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -1,9 +1,11 @@ import { createClient } from '@libsql/client'; import chalk from 'chalk'; +import { sql } from 'drizzle-orm'; import { blob, foreignKey, getTableConfig, + index, int, integer, numeric, @@ -390,15 +392,14 @@ test('drop autoincrement. drop column with data', async (t) => { expect(sqlStatements.length).toBe(4); expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, - ); - expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( + `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL );\n`, ); - expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + expect(sqlStatements[1]).toBe(`INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`); + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); expect(columnsToRemove!.length).toBe(1); @@ -426,7 +427,7 @@ test('change autoincrement. table is part of foreign key', async (t) => { const users1 = sqliteTable('users', { id: integer('id').primaryKey({ autoIncrement: true }), name: text('name').unique(), - companyId: text('company_id').references(() => companies1.id), + companyId: integer('company_id').references(() => companies1.id), }); const schema1 = { companies: companies1, @@ -439,7 +440,7 @@ test('change autoincrement. table is part of foreign key', async (t) => { const users2 = sqliteTable('users', { id: integer('id').primaryKey({ autoIncrement: true }), name: text('name').unique(), - companyId: text('company_id').references(() => companies1.id), + companyId: integer('company_id').references(() => companies2.id), }); const schema2 = { companies: companies2, @@ -451,8 +452,8 @@ test('change autoincrement. table is part of foreign key', async (t) => { const seedStatements = [ `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("drizzle");`, `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("turso");`, - `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("1");`, - `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("2");`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (1);`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (2);`, ]; const { @@ -491,39 +492,21 @@ test('change autoincrement. table is part of foreign key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(9); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( + `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, ); - expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`companies\`;`); expect(sqlStatements[4]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, - ); - expect(sqlStatements[5]).toBe( - `CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`name\` text, -\t\`company_id\` text, -\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action -); -`, - ); - expect(sqlStatements[6]).toBe( - `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, - ); - expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); - expect(sqlStatements[8]).toBe( - `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -742,3 +725,386 @@ test('drop table with data', async (t) => { expect(tablesToRemove![0]).toBe('users'); expect(tablesToTruncate!.length).toBe(0); }); + +test('recreate table with nested references', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); + const schema1 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); + const schema2 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema2, []); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + expect(sqlStatements[5]).toBe('PRAGMA foreign_keys=ON;'); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('recreate table with added column not null and without default', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + newColumn: text('new_column').notNull(), + }), + }; + + const seedStatements = [ + `INSERT INTO \`users\` ("name", "age") VALUES ('drizzle', 12)`, + `INSERT INTO \`users\` ("name", "age") VALUES ('turso', 12)`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'new_column', + notNull: true, + generated: undefined, + primaryKey: false, + type: 'text', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements[0]).toBe('DELETE FROM \`users\`;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\t\`new_column\` text NOT NULL +);\n`); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline('new_column') + } column without default value to table, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('users'); +}); + +test('set not null with index', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_notnull', + }); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS "users_name_index";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, + ); + expect(sqlStatements[2]).toBe( + `CREATE INDEX \`users_name_index\` ON \`users\` (\`name\`);`, + ); + expect(columnsToRemove!.length).toBe(0), expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop not null with two indexes', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(5); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS "users_name_unique";`, + ); + expect(sqlStatements[1]).toBe( + `DROP INDEX IF EXISTS "users_age_index";`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); + expect(sqlStatements[3]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + expect(sqlStatements[4]).toBe( + `CREATE INDEX \`users_age_index\` ON \`users\` (\`age\`);`, + ); + expect(columnsToRemove!.length).toBe(0), expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index d0c3cb05ee..e52559256c 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -382,15 +382,133 @@ test('drop autoincrement. drop column with data', async (t) => { expect(sqlStatements.length).toBe(4); expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + `CREATE TABLE \`__new_companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +);\n`, ); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( -\t\`id\` integer PRIMARY KEY NOT NULL + `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, + ); + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, + ); + + expect(columnsToRemove!.length).toBe(1); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to delete ${ + chalk.underline( + 'name', + ) + } column in companies table with 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop autoincrement. drop column with data with pragma off', async (t) => { + const client = new Database(':memory:'); + + client.exec('PRAGMA foreign_keys=OFF;'); + + const users = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + }); + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name'), + user_id: integer('user_id').references(() => users.id), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + user_id: integer('user_id').references(() => users.id), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, 'drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, 'turso');`, + ]; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ + { + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, + }, + { + name: 'user_id', + type: 'integer', + autoincrement: false, + notNull: false, + primaryKey: false, + generated: undefined, + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'user_id', + ], + columnsTo: [ + 'id', + ], + name: '', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'companies', + tableTo: 'users', + }, + ], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `CREATE TABLE \`__new_companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`user_id\` integer, +\tFOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE no action );\n`, ); - expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + expect(sqlStatements[1]).toBe( + `INSERT INTO \`__new_companies\`("id", "user_id") SELECT "id", "user_id" FROM \`companies\`;`, + ); + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); expect(columnsToRemove!.length).toBe(1); @@ -407,7 +525,7 @@ test('drop autoincrement. drop column with data', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('change autoincrement. table is part of foreign key', async (t) => { +test('change autoincrement. other table references current', async (t) => { const client = new Database(':memory:'); const companies1 = sqliteTable('companies', { @@ -481,39 +599,21 @@ test('change autoincrement. table is part of foreign key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(9); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( + `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, ); - expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`companies\`;`); expect(sqlStatements[4]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, - ); - expect(sqlStatements[5]).toBe( - `CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`name\` text, -\t\`company_id\` text, -\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action -); -`, - ); - expect(sqlStatements[6]).toBe( - `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, - ); - expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); - expect(sqlStatements[8]).toBe( - `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -586,14 +686,11 @@ test('drop not null, add not null', async (t) => { id: int('id').primaryKey({ autoIncrement: true }), name: text('name').notNull(), }), - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name'), - userId: int('user_id'), - }, - ), + posts: sqliteTable('posts', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }), }; const schema2 = { @@ -601,14 +698,11 @@ test('drop not null, add not null', async (t) => { id: int('id').primaryKey({ autoIncrement: true }), name: text('name'), }), - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name').notNull(), - userId: int('user_id'), - }, - ), + posts: sqliteTable('posts', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + userId: int('user_id'), + }), }; const { statements, @@ -618,12 +712,7 @@ test('drop not null, add not null', async (t) => { shouldAskForApprove, tablesToRemove, tablesToTruncate, - } = await diffTestSchemasPushSqlite( - client, - schema1, - schema2, - [], - ); + } = await diffTestSchemasPushSqlite(client, schema1, schema2, []); expect(statements!.length).toBe(2); expect(statements![0]).toStrictEqual({ @@ -685,27 +774,31 @@ test('drop not null, add not null', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements!.length).toBe(8); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); - expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( + expect(sqlStatements.length).toBe(8); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`name\` text );\n`); - expect(sqlStatements![2]).toBe( - `INSERT INTO \`users\`("id", "name") SELECT ("id", "name") FROM \`__old_push_users\`;`, + expect(sqlStatements[1]).toBe( + `INSERT INTO \`__new_users\`("id", "name") SELECT "id", "name" FROM \`users\`;`, + ); + expect(sqlStatements[2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); - expect(sqlStatements![4]).toBe(`ALTER TABLE \`posts\` RENAME TO \`__old_push_posts\`;`); - expect(sqlStatements![5]).toBe(`CREATE TABLE \`posts\` ( + expect(sqlStatements![4]).toBe(`CREATE TABLE \`__new_posts\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`name\` text NOT NULL, \t\`user_id\` integer );\n`); - expect(sqlStatements![6]).toBe( - `INSERT INTO \`posts\`("id", "name", "user_id") SELECT ("id", "name", "user_id") FROM \`__old_push_posts\`;`, + expect(sqlStatements![5]).toBe( + `INSERT INTO \`__new_posts\`("id", "name", "user_id") SELECT "id", "name", "user_id" FROM \`posts\`;`, + ); + expect(sqlStatements![6]).toBe(`DROP TABLE \`posts\`;`); + expect(sqlStatements![7]).toBe( + `ALTER TABLE \`__new_posts\` RENAME TO \`posts\`;`, ); - expect(sqlStatements![7]).toBe(`DROP TABLE \`__old_push_posts\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -738,12 +831,9 @@ test('rename table and change data type', async (t) => { shouldAskForApprove, tablesToRemove, tablesToTruncate, - } = await diffTestSchemasPushSqlite( - client, - schema1, - schema2, - ['public.old_users->public.new_users'], - ); + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [ + 'public.old_users->public.new_users', + ]); expect(statements!.length).toBe(2); expect(statements![0]).toStrictEqual({ @@ -780,16 +870,20 @@ test('rename table and change data type', async (t) => { }); expect(sqlStatements!.length).toBe(5); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); - expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); - expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( + expect(sqlStatements![0]).toBe( + `ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`, + ); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`age\` integer );\n`); - expect(sqlStatements![3]).toBe( - `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + expect(sqlStatements![2]).toBe( + `INSERT INTO \`__new_new_users\`("id", "age") SELECT "id", "age" FROM \`new_users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`new_users\`;`); + expect(sqlStatements![4]).toBe( + `ALTER TABLE \`__new_new_users\` RENAME TO \`new_users\`;`, ); - expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -798,18 +892,18 @@ test('rename table and change data type', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('rename table and change data type', async (t) => { +test('rename column and change data type', async (t) => { const client = new Database(':memory:'); const schema1 = { - users: sqliteTable('old_users', { + users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), - age: text('age'), + name: text('name'), }), }; const schema2 = { - users: sqliteTable('new_users', { + users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), age: integer('age'), }), @@ -822,22 +916,12 @@ test('rename table and change data type', async (t) => { shouldAskForApprove, tablesToRemove, tablesToTruncate, - } = await diffTestSchemasPushSqlite( - client, - schema1, - schema2, - ['public.old_users->public.new_users'], - ); + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [ + 'public.users.name->public.users.age', + ]); - expect(statements!.length).toBe(2); + expect(statements!.length).toBe(1); expect(statements![0]).toStrictEqual({ - fromSchema: undefined, - tableNameFrom: 'old_users', - tableNameTo: 'new_users', - toSchema: undefined, - type: 'rename_table', - }); - expect(statements![1]).toStrictEqual({ columns: [ { autoincrement: true, @@ -858,22 +942,23 @@ test('rename table and change data type', async (t) => { ], compositePKs: [], referenceData: [], - tableName: 'new_users', + tableName: 'users', type: 'recreate_table', uniqueConstraints: [], }); - expect(sqlStatements!.length).toBe(5); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); - expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); - expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`age\` integer );\n`); + expect(sqlStatements![1]).toBe( + `INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`, + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); expect(sqlStatements![3]).toBe( - `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -882,22 +967,247 @@ test('rename table and change data type', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('rename column and change data type', async (t) => { +test('recreate table with nested references', async (t) => { + const client = new Database(':memory:'); + + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); + const schema1 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); + const schema2 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [ + 'public.users.name->public.users.age', + ]); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + expect(sqlStatements[5]).toBe('PRAGMA foreign_keys=ON;'); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('recreate table with added column not null and without default with data', async (t) => { const client = new Database(':memory:'); const schema1 = { users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), name: text('name'), + age: integer('age'), }), }; const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + newColumn: text('new_column').notNull(), + }), + }; + + const seedStatements = [ + `INSERT INTO \`users\` ("name", "age") VALUES ('drizzle', 12)`, + `INSERT INTO \`users\` ("name", "age") VALUES ('turso', 12)`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'new_column', + notNull: true, + generated: undefined, + primaryKey: false, + type: 'text', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements[0]).toBe('DELETE FROM \`users\`;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\t\`new_column\` text NOT NULL +);\n`); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline('new_column') + } column without default value to table, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('users'); +}); + +test('recreate table with added column not null and without default with data', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), age: integer('age'), }), }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + newColumn: text('new_column').notNull(), + }), + }; + const { statements, sqlStatements, @@ -910,20 +1220,28 @@ test('rename column and change data type', async (t) => { client, schema1, schema2, - ['public.users.name->public.users.age'], + [], ); expect(statements!.length).toBe(1); expect(statements![0]).toStrictEqual({ columns: [ { - autoincrement: true, + autoincrement: false, name: 'id', notNull: true, generated: undefined, primaryKey: true, type: 'integer', }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, { autoincrement: false, name: 'age', @@ -932,6 +1250,14 @@ test('rename column and change data type', async (t) => { primaryKey: false, type: 'integer', }, + { + autoincrement: false, + name: 'new_column', + notNull: true, + generated: undefined, + primaryKey: false, + type: 'text', + }, ], compositePKs: [], referenceData: [], @@ -941,15 +1267,19 @@ test('rename column and change data type', async (t) => { }); expect(sqlStatements!.length).toBe(4); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); - expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`age\` integer + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\t\`new_column\` text NOT NULL );\n`); - expect(sqlStatements![2]).toBe( - `INSERT INTO \`users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_users\`;`, + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age", "new_column") SELECT "id", "name", "age", "new_column" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index e71b95e019..7329db7c99 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -8,7 +8,7 @@ import { sqliteTable, text, } from 'drizzle-orm/sqlite-core'; -import { JsonRecreateTableStatement } from 'src/jsonStatements'; +import { JsonCreateIndexStatement, JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemasSqlite } from './schemaDiffer'; @@ -774,6 +774,55 @@ test('alter column add default not null', async (t) => { }); }); +test('alter column add default not null with indexes', async (t) => { + const from = { + users: sqliteTable('table', { + name: text('name'), + }, (table) => ({ + someIndex: index('index_name').on(table.name), + })), + }; + + const to = { + users: sqliteTable('table', { + name: text('name').notNull().default('dan'), + }, (table) => ({ + someIndex: index('index_name').on(table.name), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite( + from, + to, + [], + ); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + default: "'dan'", + }], + compositePKs: [], + referenceData: [], + tableName: 'table', + uniqueConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + data: 'index_name;name;false;', + schema: '', + tableName: 'table', + type: 'create_index', + internal: undefined, + }); +}); + test('alter column drop default not null', async (t) => { const from = { users: sqliteTable('table', { @@ -851,3 +900,93 @@ test('alter column drop generated', async (t) => { expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); }); + +test('recreate table with nested references', async (t) => { + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); + const schema1 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references(() => subscriptions.id), + }), + }; + + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); + const schema2 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references(() => subscriptions.id), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts index 342e552323..47447decda 100644 --- a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -1181,27 +1181,17 @@ test(`set new type for primary key, unique and normal column`, async (t) => { columnPk: false, }, { - type: 'recreate_table', + type: 'alter_table_alter_column_set_type', tableName: 'unique', - columns: [ - { - name: 'unique', - type: 'text', - primaryKey: false, - notNull: false, - autoincrement: false, - }, - ], - compositePKs: [], - referenceData: [], - uniqueConstraints: [], - }, - { - data: 'unique_unique_unique;unique;true;', - internal: undefined, + columnName: 'unique', + newDataType: 'text', + oldDataType: 'int', schema: '', - tableName: 'unique', - type: 'create_index', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, }, ]; expect(libSQLCombineStatements(statements, json2)).toStrictEqual( From b0cf5550c6da62c1bb21921026eba4ffd2a8441d Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 15 Aug 2024 19:04:29 +0300 Subject: [PATCH 115/152] changed package json to prev state --- drizzle-kit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 8bfdebac47..552c14d0ec 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -38,7 +38,7 @@ "build": "rm -rf ./dist && tsx build.ts && cp package.json dist/ && attw --pack dist", "build:dev": "rm -rf ./dist && tsx build.dev.ts && tsc -p tsconfig.cli-types.json && chmod +x ./dist/index.cjs", "pack": "cp package.json README.md dist/ && (cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", - "tsc": "tsc -p tsconfig.cli-types.json", + "tsc": "tsc -p tsconfig.build.json", "publish": "npm publish package.tgz" }, "dependencies": { From 8d62f90148532c18de33c426d0a7e9d3504bb8ad Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 16 Aug 2024 12:17:23 +0300 Subject: [PATCH 116/152] updated tests --- drizzle-kit/tests/push/libsql.test.ts | 58 ------------------------ drizzle-kit/tests/push/sqlite.test.ts | 1 + drizzle-kit/tests/sqlite-columns.test.ts | 23 ++++++++++ 3 files changed, 24 insertions(+), 58 deletions(-) diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 3506cef329..482caa995f 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -515,64 +515,6 @@ test('change autoincrement. table is part of foreign key', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('create table with custom name references', async (t) => { - const turso = createClient({ - url: ':memory:', - }); - - const users = sqliteTable('users', { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name').notNull(), - }); - - const schema1 = { - users, - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name'), - userId: int('user_id'), - }, - (t) => ({ - fk: foreignKey({ - columns: [t.id], - foreignColumns: [users.id], - name: 'custom_name_fk', - }), - }), - ), - }; - - const schema2 = { - users, - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name'), - userId: int('user_id'), - }, - (t) => ({ - fk: foreignKey({ - columns: [t.id], - foreignColumns: [users.id], - name: 'custom_name_fk', - }), - }), - ), - }; - - const { sqlStatements } = await diffTestSchemasPushLibSQL( - turso, - schema1, - schema2, - [], - ); - - expect(sqlStatements!.length).toBe(0); -}); - test('drop not null, add not null', async (t) => { const turso = createClient({ url: ':memory:', diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index e52559256c..aea5cd379b 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -395,6 +395,7 @@ test('drop autoincrement. drop column with data', async (t) => { ); expect(columnsToRemove!.length).toBe(1); + expect(columnsToRemove![0]).toBe('name'); expect(infoToPrint!.length).toBe(1); expect(infoToPrint![0]).toBe( `· You're about to delete ${ diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index 7329db7c99..04dbb940c2 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -821,6 +821,18 @@ test('alter column add default not null with indexes', async (t) => { type: 'create_index', internal: undefined, }); + expect(sqlStatements.length).toBe(7); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_table\` ( +\t\`name\` text DEFAULT 'dan' NOT NULL +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_table\`("name") SELECT "name" FROM \`table\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`table\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_table\` RENAME TO \`table\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); + expect(sqlStatements[6]).toBe(`CREATE INDEX \`index_name\` ON \`table\` (\`name\`);`); }); test('alter column drop default not null', async (t) => { @@ -858,6 +870,17 @@ test('alter column drop default not null', async (t) => { tableName: 'table', uniqueConstraints: [], }); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_table\` ( +\t\`name\` text +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_table\`("name") SELECT "name" FROM \`table\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`table\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_table\` RENAME TO \`table\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('alter column drop generated', async (t) => { From ec4420ef109445e7b0f468647f280c40edb1fc11 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 16:05:10 +0300 Subject: [PATCH 117/152] - moved 'turso' driver to dialect - rewrote tests --- drizzle-kit/package.json | 2 +- drizzle-kit/schema.ts | 0 drizzle-kit/src/cli/commands/introspect.ts | 112 ++++++ .../src/cli/commands/libSqlPushUtils.ts | 10 +- drizzle-kit/src/cli/commands/migrate.ts | 132 +++--- drizzle-kit/src/cli/commands/push.ts | 25 +- drizzle-kit/src/cli/commands/utils.ts | 85 +++- drizzle-kit/src/cli/connections.ts | 162 ++++---- drizzle-kit/src/cli/schema.ts | 39 +- drizzle-kit/src/cli/validations/common.ts | 3 +- drizzle-kit/src/cli/validations/libsql.ts | 27 ++ drizzle-kit/src/cli/validations/sqlite.ts | 5 - drizzle-kit/src/index.ts | 3 +- drizzle-kit/src/schemaValidator.ts | 2 +- drizzle-kit/src/serializer/studio.ts | 29 +- drizzle-kit/src/snapshotsDiffer.ts | 3 +- drizzle-kit/src/sqlgenerator.ts | 55 ++- drizzle-kit/src/utils.ts | 8 + drizzle-kit/tests/cli-generate.test.ts | 9 - drizzle-kit/tests/cli-migrate.test.ts | 3 +- drizzle-kit/tests/cli-push.test.ts | 5 +- drizzle-kit/tests/cli/turso.config.ts | 3 +- drizzle-kit/tests/push/libsql.test.ts | 15 +- drizzle-orm/package.json | 2 +- pnpm-lock.yaml | 379 +++++++++++------- 25 files changed, 726 insertions(+), 392 deletions(-) delete mode 100644 drizzle-kit/schema.ts create mode 100644 drizzle-kit/src/cli/validations/libsql.ts diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 552c14d0ec..75c3d65dc4 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -54,7 +54,7 @@ "@electric-sql/pglite": "^0.1.5", "@hono/node-server": "^1.9.0", "@hono/zod-validator": "^0.2.1", - "@libsql/client": "^0.4.2", + "@libsql/client": "^0.10.0", "@neondatabase/serverless": "^0.9.1", "@originjs/vite-plugin-commonjs": "^1.0.3", "@planetscale/database": "^1.16.0", diff --git a/drizzle-kit/schema.ts b/drizzle-kit/schema.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 4e51d6b496..0940385af9 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -25,6 +25,7 @@ import { } from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; import type { Casing, Prefix } from '../validations/common'; +import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import type { PostgresCredentials } from '../validations/postgres'; import { SingleStoreCredentials } from '../validations/singlestore'; @@ -470,6 +471,117 @@ export const introspectSqlite = async ( process.exit(0); }; +export const introspectLibSQL = async ( + casing: Casing, + out: string, + breakpoints: boolean, + credentials: LibSQLCredentials, + tablesFilter: string[], + prefix: Prefix, +) => { + const { connectToLibSQL } = await import('../connections'); + const db = await connectToLibSQL(credentials); + + const matchers = tablesFilter.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new IntrospectProgress(); + const res = await renderWithTask( + progress, + fromSqliteDatabase(db, filter, (stage, count, status) => { + progress.update(stage, count, status); + }), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SQLiteSchema; + const ts = sqliteSchemaToTypeScript(schema, casing); + const relationsTs = relationsToTypeScript(schema, casing); + + // check orm and orm-pg api version + + const schemaFile = join(out, 'schema.ts'); + writeFileSync(schemaFile, ts.file); + const relationsFile = join(out, 'relations.ts'); + writeFileSync(relationsFile, relationsTs.file); + console.log(); + + const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + + if (snapshots.length === 0) { + const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( + squashSqliteScheme(drySQLite), + squashSqliteScheme(schema), + tablesResolver, + columnsResolver, + drySQLite, + schema, + ); + + writeResult({ + cur: schema, + sqlStatements, + journal, + _meta, + outFolder: out, + breakpoints, + type: 'introspect', + prefixMode: prefix, + }); + } else { + render( + `[${ + chalk.blue( + 'i', + ) + }] No SQL generated, you already have migrations in project`, + ); + } + + render( + `[${ + chalk.green( + '✓', + ) + }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + ); + render( + `[${ + chalk.green( + '✓', + ) + }] You relations file is ready ➜ ${ + chalk.bold.underline.blue( + relationsFile, + ) + } 🚀`, + ); + process.exit(0); +}; + const withCasing = (value: string, casing: Casing) => { if (casing === 'preserve') { return value; diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 3bc9e82257..98c95f0899 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -133,7 +133,7 @@ export const libSqlLogSuggestionsAndReturn = async ( tablesToRemove.push(statement.tableName); shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); @@ -156,7 +156,7 @@ export const libSqlLogSuggestionsAndReturn = async ( shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); @@ -185,7 +185,7 @@ export const libSqlLogSuggestionsAndReturn = async ( shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); @@ -330,12 +330,12 @@ export const libSqlLogSuggestionsAndReturn = async ( columnsToRemove.push(`${tableName}_${statement.columnName}`); shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); } else { - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 664e7da022..83f5b2dc8e 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -492,7 +492,6 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; - const driver = config.driver; try { assertV1OutFolder(outFolder); @@ -524,35 +523,74 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const squashedPrev = squashSqliteScheme(validatedPrev); const squashedCur = squashSqliteScheme(validatedCur); - let sqlStatements: string[]; - let _meta: - | { - schemas: {}; - tables: {}; - columns: {}; - } - | undefined; - - if (driver === 'turso') { - ({ sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - )); - } else { - ({ sqlStatements, _meta } = await applySqliteSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - )); + const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + writeResult({ + cur, + sqlStatements, + journal, + _meta, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + bundle: config.bundle, + prefixMode: config.prefix, + }); + } catch (e) { + console.error(e); + } +}; + +export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { + const outFolder = config.out; + const schemaPath = config.schema; + + try { + assertV1OutFolder(outFolder); + + const { snapshots, journal } = prepareMigrationFolder(outFolder, 'sqlite'); + const { prev, cur, custom } = await prepareSqliteMigrationSnapshot( + snapshots, + schemaPath, + ); + + const validatedPrev = sqliteSchema.parse(prev); + const validatedCur = sqliteSchema.parse(cur); + + if (config.custom) { + writeResult({ + cur: custom, + sqlStatements: [], + journal, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + bundle: config.bundle, + type: 'custom', + prefixMode: config.prefix, + }); + return; } + const squashedPrev = squashSqliteScheme(validatedPrev); + const squashedCur = squashSqliteScheme(validatedCur); + + const { sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + writeResult({ cur, sqlStatements, @@ -572,7 +610,6 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { export const prepareSQLitePush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, - driver?: Driver, ) => { const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); @@ -582,34 +619,15 @@ export const prepareSQLitePush = async ( const squashedPrev = squashSqliteScheme(validatedPrev, 'push'); const squashedCur = squashSqliteScheme(validatedCur, 'push'); - let sqlStatements: string[]; - let statements: JsonStatement[]; - let _meta: { - schemas: {}; - tables: {}; - columns: {}; - } | undefined; - if (driver === 'turso') { - ({ sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - 'push', - )); - } else { - ({ sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - 'push', - )); - } + const { sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); return { sqlStatements, diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index e8aaf2e2bf..1be844715c 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -2,6 +2,7 @@ import chalk from 'chalk'; import { render } from 'hanji'; import { fromJson } from '../../sqlgenerator'; import { Select } from '../selector-ui'; +import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; @@ -519,8 +520,6 @@ export const sqlitePush = async ( await db.query('rollback'); process.exit(1); } - } else if (credentials.driver === 'turso') { - await db.batch!(statementsToExecute.map((it) => ({ query: it }))); } render(`[${chalk.green('✓')}] Changes applied`); } @@ -531,14 +530,14 @@ export const libSQLPush = async ( schemaPath: string | string[], verbose: boolean, strict: boolean, - credentials: SqliteCredentials, + credentials: LibSQLCredentials, tablesFilter: string[], force: boolean, ) => { - const { connectToSQLite } = await import('../connections'); + const { connectToLibSQL } = await import('../connections'); const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); - const db = await connectToSQLite(credentials); + const db = await connectToLibSQL(credentials); const { schema } = await sqlitePushIntrospect(db, tablesFilter); const { prepareLibSQLPush } = await import('./migrate'); @@ -627,21 +626,7 @@ export const libSQLPush = async ( if (statementsToExecute.length === 0) { render(`\n[${chalk.blue('i')}] No changes detected`); } else { - if (!('driver' in credentials)) { - await db.query('begin'); - try { - for (const dStmnt of statementsToExecute) { - await db.query(dStmnt); - } - await db.query('commit'); - } catch (e) { - console.error(e); - await db.query('rollback'); - process.exit(1); - } - } else if (credentials.driver === 'turso') { - await db.batch!(statementsToExecute.map((it) => ({ query: it }))); - } + await db.batchWithPragma!(statementsToExecute); render(`[${chalk.green('✓')}] Changes applied`); } } diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index d8c704e7a9..2cfc7273bf 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -16,6 +16,8 @@ import { Prefix, wrapParam, } from '../validations/common'; +import { LibSQLCredentials, libSQLCredentials } from '../validations/libsql'; +import { printConfigConnectionIssues as printIssuesLibSql } from '../validations/libsql'; import { MysqlCredentials, mysqlCredentials, @@ -127,7 +129,6 @@ export type GenerateConfig = { prefix: Prefix; custom: boolean; bundle: boolean; - driver?: Driver; }; export const prepareGenerateConfig = async ( @@ -174,7 +175,6 @@ export const prepareGenerateConfig = async ( schema: schema, out: out || 'drizzle', bundle: driver === 'expo', - driver, }; }; @@ -217,7 +217,10 @@ export const preparePushConfig = async ( | { dialect: 'sqlite'; credentials: SqliteCredentials; - driver?: Driver; + } + | { + dialect: 'turso'; + credentials: LibSQLCredentials; } | { dialect: 'singlestore'; @@ -356,7 +359,24 @@ export const preparePushConfig = async ( credentials: parsed.data, tablesFilter, schemasFilter, - driver: config.driver, + }; + } + + if (config.dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSqlite(config, 'pull'); + process.exit(1); + } + return { + dialect: 'turso', + schemaPath: config.schema, + strict: config.strict ?? false, + verbose: config.verbose ?? false, + force: (options.force as boolean) ?? false, + credentials: parsed.data, + tablesFilter, + schemasFilter, }; } @@ -384,6 +404,10 @@ export const preparePullConfig = async ( dialect: 'singlestore'; credentials: SingleStoreCredentials; } + | { + dialect: 'turso'; + credentials: LibSQLCredentials; + } ) & { out: string; breakpoints: boolean; @@ -482,11 +506,11 @@ export const preparePullConfig = async ( dialect: 'singlestore', out: config.out, breakpoints: config.breakpoints, - casing: config.introspectCasing, + casing: config.casing, credentials: parsed.data, tablesFilter, schemasFilter, - prefix: config.database?.prefix || 'index', + prefix: config.migrations?.prefix || 'index', }; } @@ -508,6 +532,24 @@ export const preparePullConfig = async ( }; } + if (dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(config); + if (!parsed.success) { + printIssuesLibSql(config, 'pull'); + process.exit(1); + } + return { + dialect: 'sqlite', + out: config.out, + breakpoints: config.breakpoints, + casing: config.casing, + credentials: parsed.data, + tablesFilter, + schemasFilter, + prefix: config.migrations?.prefix || 'index', + }; + } + assertUnreachable(dialect); }; @@ -594,6 +636,22 @@ export const prepareStudioConfig = async (options: Record) => { }; } + if (dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesLibSql(flattened as Record, 'studio'); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + schema, + host, + port, + credentials, + }; + } + assertUnreachable(dialect); }; @@ -679,6 +737,21 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => { table, }; } + if (dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesLibSql(flattened as Record, 'migrate'); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + out, + credentials, + schema, + table, + }; + } assertUnreachable(dialect); }; diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 3357bf1467..440d3d5bf1 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -5,8 +5,17 @@ import fetch from 'node-fetch'; import ws from 'ws'; import { assertUnreachable } from '../global'; import type { ProxyParams } from '../serializer/studio'; -import { type DB, normalisePGliteUrl, normaliseSQLiteUrl, type Proxy, type SQLiteDB, type SqliteProxy } from '../utils'; +import { + type DB, + LibSQLDB, + normalisePGliteUrl, + normaliseSQLiteUrl, + type Proxy, + type SQLiteDB, + type SqliteProxy, +} from '../utils'; import { assertPackages, checkPackage } from './utils'; +import { LibSQLCredentials } from './validations/libsql'; import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; @@ -483,56 +492,7 @@ export const connectToSQLite = async ( > => { if ('driver' in credentials) { const { driver } = credentials; - if (driver === 'turso') { - assertPackages('@libsql/client'); - const { createClient } = await import('@libsql/client'); - const { drizzle } = await import('drizzle-orm/libsql'); - const { migrate } = await import('drizzle-orm/libsql/migrator'); - - const client = createClient({ - url: credentials.url, - authToken: credentials.authToken, - }); - - const drzl = drizzle(client); - const migrateFn = async (config: MigrationConfig) => { - return migrate(drzl, config); - }; - - const db: SQLiteDB = { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; - }, - run: async (query: string) => { - await client.execute(query); - }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, - }; - const proxy: SqliteProxy = { - proxy: async (params: ProxyParams) => { - const preparedParams = prepareSqliteParams(params.params); - const result = await client.execute({ - sql: params.sql, - args: preparedParams, - }); - - if (params.mode === 'array') { - return result.rows.map((row) => Object.values(row)); - } else { - return result.rows; - } - }, - }; - - return { ...db, ...proxy, migrate: migrateFn }; - } else if (driver === 'd1-http') { + if (driver === 'd1-http') { const { drizzle } = await import('drizzle-orm/sqlite-proxy'); const { migrate } = await import('drizzle-orm/sqlite-proxy/migrator'); @@ -626,48 +586,6 @@ export const connectToSQLite = async ( } } - if (await checkPackage('@libsql/client')) { - const { createClient } = await import('@libsql/client'); - const { drizzle } = await import('drizzle-orm/libsql'); - const { migrate } = await import('drizzle-orm/libsql/migrator'); - - const client = createClient({ - url: normaliseSQLiteUrl(credentials.url, 'libsql'), - }); - const drzl = drizzle(client); - const migrateFn = async (config: MigrationConfig) => { - return migrate(drzl, config); - }; - - const db: SQLiteDB = { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; - }, - run: async (query: string) => { - await client.execute(query); - }, - }; - - const proxy: SqliteProxy = { - proxy: async (params: ProxyParams) => { - const preparedParams = prepareSqliteParams(params.params); - const result = await client.execute({ - sql: params.sql, - args: preparedParams, - }); - - if (params.mode === 'array') { - return result.rows.map((row) => Object.values(row)); - } else { - return result.rows; - } - }, - }; - - return { ...db, ...proxy, migrate: migrateFn }; - } - if (await checkPackage('better-sqlite3')) { const { default: Database } = await import('better-sqlite3'); const { drizzle } = await import('drizzle-orm/better-sqlite3'); @@ -710,7 +628,63 @@ export const connectToSQLite = async ( return { ...db, ...proxy, migrate: migrateFn }; } console.log( - "Please install either 'better-sqlite3' or '@libsql/client' for Drizzle Kit to connect to SQLite databases", + "Please install 'better-sqlite3' for Drizzle Kit to connect to SQLite databases", + ); + process.exit(1); +}; + +export const connectToLibSQL = async (credentials: LibSQLCredentials): Promise< + & LibSQLDB + & SqliteProxy + & { migrate: (config: MigrationConfig) => Promise } +> => { + if (await checkPackage('@libsql/client')) { + const { createClient } = await import('@libsql/client'); + const { drizzle } = await import('drizzle-orm/libsql'); + const { migrate } = await import('drizzle-orm/libsql/migrator'); + + const client = createClient({ + url: normaliseSQLiteUrl(credentials.url, 'libsql'), + }); + const drzl = drizzle(client); + const migrateFn = async (config: MigrationConfig) => { + return migrate(drzl, config); + }; + + const db: LibSQLDB = { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batchWithPragma: async (queries: string[]) => { + await client.migrate(queries); + }, + }; + + const proxy: SqliteProxy = { + proxy: async (params: ProxyParams) => { + const preparedParams = prepareSqliteParams(params.params); + const result = await client.execute({ + sql: params.sql, + args: preparedParams, + }); + + if (params.mode === 'array') { + return result.rows.map((row) => Object.values(row)); + } else { + return result.rows; + } + }, + }; + + return { ...db, ...proxy, migrate: migrateFn }; + } + + console.log( + "Please install '@libsql/client' for Drizzle Kit to connect to LibSQL databases", ); process.exit(1); }; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index bf825d3e34..c7d5b88f3f 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -24,13 +24,13 @@ import { mkdirSync } from 'fs'; import { renderWithTask } from 'hanji'; import { dialects } from 'src/schemaValidator'; import { assertUnreachable } from '../global'; -import type { Setup } from '../serializer/studio'; +import { drizzleForLibSQL, type Setup } from '../serializer/studio'; import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') .enum(...dialects) - .desc(`Database dialect: 'postgresql', 'mysql' or 'sqlite'`); + .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite' or 'turso'`); const optionOut = string().desc("Output folder, 'drizzle' by default"); const optionConfig = string().desc('Path to drizzle config file'); const optionBreakpoints = boolean().desc( @@ -77,6 +77,7 @@ export const generate = command({ prepareAndMigratePg, prepareAndMigrateMysql, prepareAndMigrateSqlite, + prepareAndMigrateLibSQL, } = await import('./commands/migrate'); const dialect = opts.dialect; @@ -86,6 +87,8 @@ export const generate = command({ await prepareAndMigrateMysql(opts); } else if (dialect === 'sqlite') { await prepareAndMigrateSqlite(opts); + } else if (dialect === 'turso') { + await prepareAndMigrateLibSQL(opts); } else { assertUnreachable(dialect); } @@ -159,6 +162,17 @@ export const migrate = command({ migrationsSchema: schema, }), ); + } else if (dialect === 'turso') { + const { connectToLibSQL } = await import('./connections'); + const { migrate } = await connectToLibSQL(credentials); + await renderWithTask( + new MigrateProgress(), + migrate({ + migrationsFolder: opts.out, + migrationsTable: table, + migrationsSchema: schema, + }), + ); } else { assertUnreachable(dialect); } @@ -294,7 +308,7 @@ export const push = command({ schemasFilter, force, ); - } else if (dialect === 'sqlite' && !('driver' in credentials)) { + } else if (dialect === 'sqlite') { const { sqlitePush } = await import('./commands/push'); await sqlitePush( schemaPath, @@ -304,7 +318,7 @@ export const push = command({ tablesFilter, force, ); - } else if (dialect === 'sqlite' && ('driver' in credentials && credentials.driver === 'turso')) { + } else if (dialect === 'turso') { const { libSQLPush } = await import('./commands/push'); await libSQLPush( schemaPath, @@ -369,7 +383,7 @@ export const up = command({ upMysqlHandler(out); } - if (dialect === 'sqlite') { + if (dialect === 'sqlite' || dialect === 'turso') { upSqliteHandler(out); } }, @@ -493,6 +507,16 @@ export const pull = command({ tablesFilter, prefix, ); + } else if (dialect === 'turso') { + const { introspectLibSQL } = await import('./commands/introspect'); + await introspectLibSQL( + casing, + out, + breakpoints, + credentials, + tablesFilter, + prefix, + ); } else { assertUnreachable(dialect); } @@ -593,6 +617,11 @@ export const studio = command({ ? await prepareSQLiteSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; setup = await drizzleForSQLite(credentials, schema, relations, files); + } else if (dialect === 'turso') { + const { schema, relations, files } = schemaPath + ? await prepareSQLiteSchema(schemaPath) + : { schema: {}, relations: {}, files: [] }; + setup = await drizzleForLibSQL(credentials, schema, relations, files); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index a7307f4d69..3a2701e370 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -61,7 +61,6 @@ export const assertCollisions = < }; export const sqliteDriversLiterals = [ - literal('turso'), literal('d1-http'), literal('expo'), ] as const; @@ -156,7 +155,7 @@ export const configPushSchema = object({ }); export type CliConfig = TypeOf; -export const drivers = ['turso', 'd1-http', 'expo', 'aws-data-api', 'pglite'] as const; +export const drivers = ['d1-http', 'expo', 'aws-data-api', 'pglite'] as const; export type Driver = (typeof drivers)[number]; const _: Driver = '' as TypeOf; diff --git a/drizzle-kit/src/cli/validations/libsql.ts b/drizzle-kit/src/cli/validations/libsql.ts new file mode 100644 index 0000000000..a9b03c1687 --- /dev/null +++ b/drizzle-kit/src/cli/validations/libsql.ts @@ -0,0 +1,27 @@ +import { softAssertUnreachable } from 'src/global'; +import { object, string, TypeOf } from 'zod'; +import { error } from '../views'; +import { wrapParam } from './common'; + +export const libSQLCredentials = object({ + url: string().min(1), + authToken: string().min(1).optional(), +}); + +export type LibSQLCredentials = { + url: string; + authToken?: string; +}; + +const _: LibSQLCredentials = {} as TypeOf; + +export const printConfigConnectionIssues = ( + options: Record, + command: 'generate' | 'migrate' | 'push' | 'pull' | 'studio', +) => { + let text = `Please provide required params for 'turso' dialect:\n`; + console.log(error(text)); + console.log(wrapParam('url', options.url)); + console.log(wrapParam('authToken', options.authToken, true, 'secret')); + process.exit(1); +}; diff --git a/drizzle-kit/src/cli/validations/sqlite.ts b/drizzle-kit/src/cli/validations/sqlite.ts index b6ad062d54..54178fd4a9 100644 --- a/drizzle-kit/src/cli/validations/sqlite.ts +++ b/drizzle-kit/src/cli/validations/sqlite.ts @@ -25,11 +25,6 @@ export const sqliteCredentials = union([ ]); export type SqliteCredentials = - | { - driver: 'turso'; - url: string; - authToken: string; - } | { driver: 'd1-http'; accountId: string; diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 5da4cb7b40..dc0c6274c6 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -128,8 +128,7 @@ export type Config = } & ( | { - dialect: Verify; - driver: Verify; + dialect: Verify; dbCredentials: { url: string; authToken?: string; diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index 712252f379..e91b5ab113 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -4,7 +4,7 @@ import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; -export const dialects = ['postgresql', 'mysql', 'sqlite', 'singlestore'] as const; +export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso', 'singlestore'] as const; export const dialect = enumType(dialects); export type Dialect = (typeof dialects)[number]; diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index 5515e6f59f..12ea8207c0 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -25,6 +25,7 @@ import fs from 'fs'; import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { createServer } from 'node:https'; +import { LibSQLCredentials } from 'src/cli/validations/libsql'; import { assertUnreachable } from 'src/global'; import superjson from 'superjson'; import { z } from 'zod'; @@ -342,8 +343,6 @@ export const drizzleForSQLite = async ( const { driver } = credentials; if (driver === 'd1-http') { dbUrl = `d1-http://${credentials.accountId}/${credentials.databaseId}/${credentials.token}`; - } else if (driver === 'turso') { - dbUrl = `turso://${credentials.url}/${credentials.authToken}`; } else { assertUnreachable(driver); } @@ -364,6 +363,32 @@ export const drizzleForSQLite = async ( schemaFiles, }; }; +export const drizzleForLibSQL = async ( + credentials: LibSQLCredentials, + sqliteSchema: Record>, + relations: Record, + schemaFiles?: SchemaFile[], +): Promise => { + const { connectToLibSQL } = await import('../cli/connections'); + + const sqliteDB = await connectToLibSQL(credentials); + const customDefaults = getCustomDefaults(sqliteSchema); + + let dbUrl: string = `turso://${credentials.url}/${credentials.authToken}`; + + const dbHash = createHash('sha256').update(dbUrl).digest('hex'); + + return { + dbHash, + dialect: 'sqlite', + driver: undefined, + proxy: sqliteDB.proxy, + customDefaults, + schema: sqliteSchema, + relations, + schemaFiles, + }; +}; export const drizzleForSingleStore = async ( credentials: SingleStoreCredentials, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index af3677abdc..ec8a5c1b84 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -2896,9 +2896,8 @@ export const applyLibSQLSnapshotsDiff = async ( const sqlStatements = fromJson( combinedJsonStatements, - 'sqlite', - action, 'turso', + action, json2, ); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index bcd47565ad..227cdf032e 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -392,7 +392,7 @@ class SingleStoreCreateTableConvertor extends Convertor { export class SQLiteCreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'sqlite_create_table' && dialect === 'sqlite'; + return statement.type === 'sqlite_create_table' && (dialect === 'sqlite' || dialect === 'turso'); } convert(st: JsonSqliteCreateTableStatement) { @@ -898,7 +898,7 @@ class SingleStoreDropTableConvertor extends Convertor { export class SQLiteDropTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'drop_table' && dialect === 'sqlite'; + return statement.type === 'drop_table' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonDropTableStatement) { @@ -924,7 +924,7 @@ class PgRenameTableConvertor extends Convertor { export class SqliteRenameTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'rename_table' && dialect === 'sqlite'; + return statement.type === 'rename_table' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonRenameTableStatement) { @@ -1002,7 +1002,7 @@ class SingleStoreAlterTableRenameColumnConvertor extends Convertor { class SQLiteAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( - statement.type === 'alter_table_rename_column' && dialect === 'sqlite' + statement.type === 'alter_table_rename_column' && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1054,7 +1054,7 @@ class SingleStoreAlterTableDropColumnConvertor extends Convertor { class SQLiteAlterTableDropColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_table_drop_column' && dialect === 'sqlite'; + return statement.type === 'alter_table_drop_column' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonDropColumnStatement) { @@ -1195,7 +1195,7 @@ class SingleStoreAlterTableAddColumnConvertor extends Convertor { export class SQLiteAlterTableAddColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( - statement.type === 'sqlite_alter_table_add_column' && dialect === 'sqlite' + statement.type === 'sqlite_alter_table_add_column' && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1400,7 +1400,7 @@ class SqliteAlterTableAlterColumnDropGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'alter_table_alter_column_drop_generated' - && dialect === 'sqlite' + && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1449,7 +1449,7 @@ class SqliteAlterTableAlterColumnSetExpressionConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'alter_table_alter_column_set_generated' - && dialect === 'sqlite' + && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1498,7 +1498,7 @@ class SqliteAlterTableAlterColumnAlterGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'alter_table_alter_column_alter_generated' - && dialect === 'sqlite' + && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1653,19 +1653,18 @@ type LibSQLModifyColumnStatement = | JsonAlterColumnDropDefaultStatement; export class LibSQLModifyColumn extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( (statement.type === 'alter_table_alter_column_set_type' || statement.type === 'alter_table_alter_column_drop_notnull' || statement.type === 'alter_table_alter_column_set_notnull' || statement.type === 'alter_table_alter_column_set_default' || statement.type === 'alter_table_alter_column_drop_default') - && dialect === 'sqlite' - && driver === 'turso' + && dialect === 'turso' ); } - convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed, action?: 'push') { + convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed) { const { tableName, columnName } = statement; let columnType = ``; @@ -2686,11 +2685,10 @@ class PgCreateForeignKeyConvertor extends Convertor { } class LibSQLCreateForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'create_reference' - && dialect === 'sqlite' - && driver === 'turso' + && dialect === 'turso' ); } @@ -2928,7 +2926,7 @@ class CreateSingleStoreIndexConvertor extends Convertor { export class CreateSqliteIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_index' && dialect === 'sqlite'; + return statement.type === 'create_index' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonCreateIndexStatement): string { @@ -3050,7 +3048,7 @@ class PgAlterTableRemoveFromSchemaConvertor extends Convertor { export class SqliteDropIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'drop_index' && dialect === 'sqlite'; + return statement.type === 'drop_index' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonDropIndexStatement): string { @@ -3082,9 +3080,9 @@ class SingleStoreDropIndexConvertor extends Convertor { } class SQLiteRecreateTableConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( - statement.type === 'recreate_table' && dialect === 'sqlite' && !driver + statement.type === 'recreate_table' && dialect === 'sqlite' ); } @@ -3114,7 +3112,7 @@ class SQLiteRecreateTableConvertor extends Convertor { `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); - // migrate data + // drop table sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', @@ -3141,11 +3139,10 @@ class SQLiteRecreateTableConvertor extends Convertor { } class LibSQLRecreateTableConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'recreate_table' - && dialect === 'sqlite' - && driver === 'turso' + && dialect === 'turso' ); } @@ -3175,7 +3172,7 @@ class LibSQLRecreateTableConvertor extends Convertor { `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); - // migrate data + // drop table sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', @@ -3332,13 +3329,12 @@ convertors.push(new SingleStoreAlterTableAlterCompositePrimaryKeyConvertor()); // overloads for turso driver export function fromJson( statements: JsonStatement[], - dialect: Exclude, + dialect: Exclude, ): string[]; export function fromJson( statements: JsonStatement[], - dialect: 'sqlite', + dialect: 'sqlite' | 'turso', action?: 'push', - driver?: Driver, json2?: SQLiteSchemaSquashed, ): string[]; @@ -3346,13 +3342,12 @@ export function fromJson( statements: JsonStatement[], dialect: Dialect, action?: 'push', - driver?: Driver, json2?: SQLiteSchemaSquashed, ) { const result = statements .flatMap((statement) => { const filtered = convertors.filter((it) => { - return it.can(statement, dialect, driver); + return it.can(statement, dialect); }); const convertor = filtered.length === 1 ? filtered[0] : undefined; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 37d26f21ea..f5ff34c6ff 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -31,6 +31,12 @@ export type SQLiteDB = { ): Promise; }; +export type LibSQLDB = { + query: (sql: string, params?: any[]) => Promise; + run(query: string): Promise; + batchWithPragma?(queries: string[]): Promise; +}; + export const copy = (it: T): T => { return JSON.parse(JSON.stringify(it)); }; @@ -116,6 +122,8 @@ const validatorForDialect = (dialect: Dialect) => { return { validator: backwardCompatiblePgSchema, version: 7 }; case 'sqlite': return { validator: backwardCompatibleSqliteSchema, version: 6 }; + case 'turso': + return { validator: backwardCompatibleSqliteSchema, version: 6 }; case 'mysql': return { validator: backwardCompatibleMysqlSchema, version: 5 }; case 'singlestore': diff --git a/drizzle-kit/tests/cli-generate.test.ts b/drizzle-kit/tests/cli-generate.test.ts index 6eece02490..56a3a0d04b 100644 --- a/drizzle-kit/tests/cli-generate.test.ts +++ b/drizzle-kit/tests/cli-generate.test.ts @@ -38,7 +38,6 @@ test('generate #1', async (t) => { schema: 'schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -58,7 +57,6 @@ test('generate #2', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, - driver: undefined, }); }); @@ -75,7 +73,6 @@ test('generate #3', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -93,7 +90,6 @@ test('generate #4', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -110,7 +106,6 @@ test('generate #5', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -127,7 +122,6 @@ test('generate #6', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -147,7 +141,6 @@ test('generate #7', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -165,7 +158,6 @@ test('generate #8', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: true, // expo driver - driver: 'expo', }); }); @@ -186,7 +178,6 @@ test('generate #9', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, - driver: undefined, }); }); diff --git a/drizzle-kit/tests/cli-migrate.test.ts b/drizzle-kit/tests/cli-migrate.test.ts index a4ffec2f0c..1425691f0b 100644 --- a/drizzle-kit/tests/cli-migrate.test.ts +++ b/drizzle-kit/tests/cli-migrate.test.ts @@ -31,11 +31,10 @@ test('migrate #2', async (t) => { const res = await brotest(migrate, '--config=turso.config.ts'); if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ - dialect: 'sqlite', + dialect: 'turso', out: 'drizzle', credentials: { authToken: 'token', - driver: 'turso', url: 'turso.dev', }, schema: undefined, // drizzle migrations table schema diff --git a/drizzle-kit/tests/cli-push.test.ts b/drizzle-kit/tests/cli-push.test.ts index fb1ed3a113..f5b84fdce9 100644 --- a/drizzle-kit/tests/cli-push.test.ts +++ b/drizzle-kit/tests/cli-push.test.ts @@ -34,10 +34,9 @@ test('push #2', async (t) => { const res = await brotest(push, '--config=turso.config.ts'); if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ - dialect: 'sqlite', + dialect: 'turso', credentials: { authToken: 'token', - driver: 'turso', url: 'turso.dev', }, force: false, @@ -46,7 +45,6 @@ test('push #2', async (t) => { tablesFilter: [], strict: false, verbose: false, - driver: 'turso', }); }); @@ -67,7 +65,6 @@ test('push #3', async (t) => { tablesFilter: [], strict: false, verbose: false, - driver: 'd1-http', }); }); diff --git a/drizzle-kit/tests/cli/turso.config.ts b/drizzle-kit/tests/cli/turso.config.ts index 089e4d216c..85efe59343 100644 --- a/drizzle-kit/tests/cli/turso.config.ts +++ b/drizzle-kit/tests/cli/turso.config.ts @@ -2,8 +2,7 @@ import { defineConfig } from '../../src'; export default defineConfig({ schema: './schema.ts', - dialect: 'sqlite', - driver: 'turso', + dialect: 'turso', dbCredentials: { url: 'turso.dev', authToken: 'token', diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 482caa995f..5799b1fe3c 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -217,9 +217,10 @@ test('added column not null and without default to table with data', async (t) = }; const table = getTableConfig(schema1.companies); + const seedStatements = [ - `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("drizzle");`, - `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("turso");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('turso');`, ]; const { @@ -350,8 +351,8 @@ test('drop autoincrement. drop column with data', async (t) => { const table = getTableConfig(schema1.companies); const seedStatements = [ - `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, "drizzle");`, - `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, "turso");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, 'drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, 'turso');`, ]; const { @@ -450,8 +451,8 @@ test('change autoincrement. table is part of foreign key', async (t) => { const { name: usersTableName } = getTableConfig(users1); const { name: companiesTableName } = getTableConfig(companies1); const seedStatements = [ - `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("drizzle");`, - `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("turso");`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('turso');`, `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (1);`, `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (2);`, ]; @@ -631,7 +632,7 @@ test('drop table with data', async (t) => { }; const seedStatements = [ - `INSERT INTO \`users\` ("name") VALUES ("drizzle")`, + `INSERT INTO \`users\` ("name") VALUES ('drizzle')`, ]; const { statements, diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 888f7efcb8..7568c6e110 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -161,7 +161,7 @@ "@aws-sdk/client-rds-data": "^3.549.0", "@cloudflare/workers-types": "^4.20230904.0", "@electric-sql/pglite": "^0.1.1", - "@libsql/client": "^0.5.6", + "@libsql/client": "^0.10.0", "@neondatabase/serverless": "^0.9.0", "@op-engineering/op-sqlite": "^2.0.16", "@opentelemetry/api": "^1.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 209d2db3bc..4917e0d208 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -123,8 +123,8 @@ importers: specifier: ^0.2.1 version: 0.2.2(hono@4.5.0)(zod@3.23.7) '@libsql/client': - specifier: ^0.4.2 - version: 0.4.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + specifier: ^0.10.0 + version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: ^0.9.1 version: 0.9.3 @@ -306,14 +306,14 @@ importers: specifier: ^0.1.1 version: 0.1.5 '@libsql/client': - specifier: ^0.5.6 - version: 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + specifier: ^0.10.0 + version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: ^0.9.0 version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -361,7 +361,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -2977,10 +2977,12 @@ packages: '@humanwhocodes/config-array@0.11.11': resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} @@ -2993,9 +2995,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.1': resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} @@ -3081,31 +3085,31 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@libsql/client@0.4.3': - resolution: {integrity: sha512-AUYKnSPqAsFBVWBvmtrb4dG3pQlvTKT92eztAest9wQU2iJkabH8WzHLDb3dKFWKql7/kiCqvBQUVpozDwhekQ==} + '@libsql/client@0.10.0': + resolution: {integrity: sha512-2ERn08T4XOVx34yBtUPq0RDjAdd9TJ5qNH/izugr208ml2F94mk92qC64kXyDVQINodWJvp3kAdq6P4zTtCZ7g==} '@libsql/client@0.5.6': resolution: {integrity: sha512-UBjmDoxz75Z2sHdP+ETCROpeLA/77VMesiff8R4UWK1rnaWbh6/YoCLDILMJL3Rh0udQeKxjL8MjXthqohax+g==} - '@libsql/core@0.4.3': - resolution: {integrity: sha512-r28iYBtaLBW9RRgXPFh6cGCsVI/rwRlOzSOpAu/1PVTm6EJ3t233pUf97jETVHU0vjdr1d8VvV6fKAvJkokqCw==} + '@libsql/core@0.10.0': + resolution: {integrity: sha512-rqynAXGaiSpTsykOZdBtI1N4z4O+KZ6mt33K/aHeXAY0gSIfK/ctxuWa0Y1Bjo4FMz1idBTCXz4Ps5kITOvZZw==} '@libsql/core@0.5.6': resolution: {integrity: sha512-3vicUAydq6jPth410n4AsHHm1n2psTwvkSf94nfJlSXutGSZsl0updn2N/mJBgqUHkbuFoWZtlMifF0SwBj1xQ==} - '@libsql/darwin-arm64@0.2.0': - resolution: {integrity: sha512-+qyT2W/n5CFH1YZWv2mxW4Fsoo4dX9Z9M/nvbQqZ7H84J8hVegvVAsIGYzcK8xAeMEcpU5yGKB1Y9NoDY4hOSQ==} + '@libsql/darwin-arm64@0.3.18': + resolution: {integrity: sha512-Zt49dt+cwhPCkuoWgvjbQd4ckNfCJR5xzIAyhgHl3CBZqZaEuaXTOGKLNQT7bnFRPuQcdLt5PBT1cenKu2N6pA==} cpu: [arm64] os: [darwin] - '@libsql/darwin-arm64@0.3.18': - resolution: {integrity: sha512-Zt49dt+cwhPCkuoWgvjbQd4ckNfCJR5xzIAyhgHl3CBZqZaEuaXTOGKLNQT7bnFRPuQcdLt5PBT1cenKu2N6pA==} + '@libsql/darwin-arm64@0.3.19': + resolution: {integrity: sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ==} cpu: [arm64] os: [darwin] - '@libsql/darwin-x64@0.2.0': - resolution: {integrity: sha512-hwmO2mF1n8oDHKFrUju6Jv+n9iFtTf5JUK+xlnIE3Td0ZwGC/O1R/Z/btZTd9nD+vsvakC8SJT7/Q6YlWIkhEw==} - cpu: [x64] + '@libsql/darwin-arm64@0.4.1': + resolution: {integrity: sha512-XICT9/OyU8Aa9Iv1xZIHgvM09n/1OQUk3VC+s5uavzdiGHrDMkOWzN47JN7/FiMa/NWrcgoEiDMk3+e7mE53Ig==} + cpu: [arm64] os: [darwin] '@libsql/darwin-x64@0.3.18': @@ -3113,27 +3117,44 @@ packages: cpu: [x64] os: [darwin] + '@libsql/darwin-x64@0.3.19': + resolution: {integrity: sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw==} + cpu: [x64] + os: [darwin] + + '@libsql/darwin-x64@0.4.1': + resolution: {integrity: sha512-pSKxhRrhu4SsTD+IBRZXcs1SkwMdeAG1tv6Z/Ctp/sOEYrgkU8MDKLqkOr9NsmwpK4S0+JdwjkLMyhTkct/5TQ==} + cpu: [x64] + os: [darwin] + '@libsql/hrana-client@0.5.6': resolution: {integrity: sha512-mjQoAmejZ1atG+M3YR2ZW+rg6ceBByH/S/h17ZoYZkqbWrvohFhXyz2LFxj++ARMoY9m6w3RJJIRdJdmnEUlFg==} + '@libsql/hrana-client@0.6.2': + resolution: {integrity: sha512-MWxgD7mXLNf9FXXiM0bc90wCjZSpErWKr5mGza7ERy2FJNNMXd7JIOv+DepBA1FQTIfI8TFO4/QDYgaQC0goNw==} + '@libsql/isomorphic-fetch@0.1.12': resolution: {integrity: sha512-MRo4UcmjAGAa3ac56LoD5OE13m2p0lu0VEtZC2NZMcogM/jc5fU9YtMQ3qbPjFJ+u2BBjFZgMPkQaLS1dlMhpg==} + '@libsql/isomorphic-fetch@0.2.5': + resolution: {integrity: sha512-8s/B2TClEHms2yb+JGpsVRTPBfy1ih/Pq6h6gvyaNcYnMVJvgQRY7wAa8U2nD0dppbCuDU5evTNMEhrQ17ZKKg==} + engines: {node: '>=18.0.0'} + '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - '@libsql/linux-arm64-gnu@0.2.0': - resolution: {integrity: sha512-1w2lPXIYtnBaK5t/Ej5E8x7lPiE+jP3KATI/W4yei5Z/ONJh7jQW5PJ7sYU95vTME3hWEM1FXN6kvzcpFAte7w==} + '@libsql/linux-arm64-gnu@0.3.18': + resolution: {integrity: sha512-5m9xtDAhoyLSV54tho9uQ2ZIDeJWc0vU3Xpe/VK4+6bpURISs23qNhXiCrZnnq3oV0hFlBfcIgQUIATmb6jD2A==} cpu: [arm64] os: [linux] - '@libsql/linux-arm64-gnu@0.3.18': - resolution: {integrity: sha512-5m9xtDAhoyLSV54tho9uQ2ZIDeJWc0vU3Xpe/VK4+6bpURISs23qNhXiCrZnnq3oV0hFlBfcIgQUIATmb6jD2A==} + '@libsql/linux-arm64-gnu@0.3.19': + resolution: {integrity: sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg==} cpu: [arm64] os: [linux] - '@libsql/linux-arm64-musl@0.2.0': - resolution: {integrity: sha512-lkblBEJ7xuNiWNjP8DDq0rqoWccszfkUS7Efh5EjJ+GDWdCBVfh08mPofIZg0fZVLWQCY3j+VZCG1qZfATBizg==} + '@libsql/linux-arm64-gnu@0.4.1': + resolution: {integrity: sha512-9lpvb24tO2qZd9nq5dlq3ESA3hSKYWBIK7lJjfiCM6f7a70AUwBY9QoPJV9q4gILIyVnR1YBGrlm50nnb+dYgw==} cpu: [arm64] os: [linux] @@ -3142,9 +3163,14 @@ packages: cpu: [arm64] os: [linux] - '@libsql/linux-x64-gnu@0.2.0': - resolution: {integrity: sha512-+x/d289KeJydwOhhqSxKT+6MSQTCfLltzOpTzPccsvdt5fxg8CBi+gfvEJ4/XW23Sa+9bc7zodFP0i6MOlxX7w==} - cpu: [x64] + '@libsql/linux-arm64-musl@0.3.19': + resolution: {integrity: sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.4.1': + resolution: {integrity: sha512-lyxi+lFxE+NcBRDMQCxCtDg3c4WcKAbc9u63d5+B23Vm+UgphD9XY4seu+tGrBy1MU2tuNVix7r9S7ECpAaVrA==} + cpu: [arm64] os: [linux] '@libsql/linux-x64-gnu@0.3.18': @@ -3152,8 +3178,13 @@ packages: cpu: [x64] os: [linux] - '@libsql/linux-x64-musl@0.2.0': - resolution: {integrity: sha512-5Xn0c5A6vKf9D1ASpgk7mef//FuY7t5Lktj/eiU4n3ryxG+6WTpqstTittJUgepVjcleLPYxIhQAYeYwTYH1IQ==} + '@libsql/linux-x64-gnu@0.3.19': + resolution: {integrity: sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-gnu@0.4.1': + resolution: {integrity: sha512-psvuQ3UFBEmDFV8ZHG+WkUHIJiWv+elZ+zIPvOVedlIKdxG1O+8WthWUAhFHOGnbiyzc4sAZ4c3de1oCvyHxyQ==} cpu: [x64] os: [linux] @@ -3162,16 +3193,31 @@ packages: cpu: [x64] os: [linux] - '@libsql/win32-x64-msvc@0.2.0': - resolution: {integrity: sha512-rpK+trBIpRST15m3cMYg5aPaX7kvCIottxY7jZPINkKAaScvfbn9yulU/iZUM9YtuK96Y1ZmvwyVIK/Y5DzoMQ==} + '@libsql/linux-x64-musl@0.3.19': + resolution: {integrity: sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ==} cpu: [x64] - os: [win32] + os: [linux] + + '@libsql/linux-x64-musl@0.4.1': + resolution: {integrity: sha512-PDidJ3AhGDqosGg3OAZzGxMFIbnuOALya4BoezJKl667AFv3x7BBQ30H81Mngsq3Fh8RkJkXSdWfL91+Txb1iA==} + cpu: [x64] + os: [linux] '@libsql/win32-x64-msvc@0.3.18': resolution: {integrity: sha512-9EEIHz+e8tTbx9TMkb8ByZnzxc0pYFirK1nSbqC6cFEST95fiY0NCfQ/zAzJxe90KckbjifX6BbO69eWIi3TAg==} cpu: [x64] os: [win32] + '@libsql/win32-x64-msvc@0.3.19': + resolution: {integrity: sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg==} + cpu: [x64] + os: [win32] + + '@libsql/win32-x64-msvc@0.4.1': + resolution: {integrity: sha512-IdODVqV/PrdOnHA/004uWyorZQuRsB7U7bCRCE3vXgABj3eJLJGc6cv2C6ksEaEoVxJbD8k53H4VVAGrtYwXzQ==} + cpu: [x64] + os: [win32] + '@miniflare/core@2.14.2': resolution: {integrity: sha512-n/smm5ZTg7ilGM4fxO7Gxhbe573oc8Za06M3b2fO+lPWqF6NJcEKdCC+sJntVFbn3Cbbd2G1ChISmugPfmlCkQ==} engines: {node: '>=16.13'} @@ -4512,6 +4558,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -6278,6 +6325,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. generate-function@2.3.1: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} @@ -7095,13 +7143,19 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libsql@0.2.0: - resolution: {integrity: sha512-ELBRqhpJx5Dap0187zKQnntZyk4EjlDHSrjIVL8t+fQ5e8IxbQTeYgZgigMjB1EvrETdkm0Y0VxBGhzPQ+t0Jg==} - cpu: [x64, arm64] - os: [darwin, linux, win32] - libsql@0.3.18: resolution: {integrity: sha512-lvhKr7WV3NLWRbXkjn/MeKqXOAqWKU0PX9QYrvDh7fneukapj+iUQ4qgJASrQyxcCrEsClXCQiiK5W6OoYPAlA==} + cpu: [x64, arm64, wasm32] + os: [darwin, linux, win32] + + libsql@0.3.19: + resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + cpu: [x64, arm64, wasm32] + os: [darwin, linux, win32] + + libsql@0.4.1: + resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7788,6 +7842,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. npx-import@1.1.4: resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} @@ -8305,6 +8360,9 @@ packages: bluebird: optional: true + promise-limit@2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} @@ -8601,6 +8659,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.0: @@ -10210,8 +10269,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10297,11 +10356,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/client-sso-oidc@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10340,7 +10399,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10607,11 +10665,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10650,6 +10708,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -10804,7 +10863,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11011,7 +11070,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11212,7 +11271,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11221,7 +11280,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -12893,7 +12952,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12911,7 +12970,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13331,16 +13390,15 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@libsql/client@0.4.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: - '@libsql/core': 0.4.3 - '@libsql/hrana-client': 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@libsql/core': 0.10.0 + '@libsql/hrana-client': 0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) js-base64: 3.7.7 - optionalDependencies: - libsql: 0.2.0 + libsql: 0.4.1 + promise-limit: 2.7.0 transitivePeerDependencies: - bufferutil - - encoding - utf-8-validate '@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': @@ -13354,7 +13412,7 @@ snapshots: - encoding - utf-8-validate - '@libsql/core@0.4.3': + '@libsql/core@0.10.0': dependencies: js-base64: 3.7.7 @@ -13362,18 +13420,24 @@ snapshots: dependencies: js-base64: 3.7.7 - '@libsql/darwin-arm64@0.2.0': + '@libsql/darwin-arm64@0.3.18': optional: true - '@libsql/darwin-arm64@0.3.18': + '@libsql/darwin-arm64@0.3.19': optional: true - '@libsql/darwin-x64@0.2.0': + '@libsql/darwin-arm64@0.4.1': optional: true '@libsql/darwin-x64@0.3.18': optional: true + '@libsql/darwin-x64@0.3.19': + optional: true + + '@libsql/darwin-x64@0.4.1': + optional: true + '@libsql/hrana-client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@libsql/isomorphic-fetch': 0.1.12(encoding@0.1.13) @@ -13385,6 +13449,16 @@ snapshots: - encoding - utf-8-validate + '@libsql/hrana-client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)': + dependencies: + '@libsql/isomorphic-fetch': 0.2.5 + '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) + js-base64: 3.7.7 + node-fetch: 3.3.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@libsql/isomorphic-fetch@0.1.12(encoding@0.1.13)': dependencies: '@types/node-fetch': 2.6.11 @@ -13392,6 +13466,8 @@ snapshots: transitivePeerDependencies: - encoding + '@libsql/isomorphic-fetch@0.2.5': {} + '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@types/ws': 8.5.11 @@ -13400,36 +13476,51 @@ snapshots: - bufferutil - utf-8-validate - '@libsql/linux-arm64-gnu@0.2.0': + '@libsql/linux-arm64-gnu@0.3.18': optional: true - '@libsql/linux-arm64-gnu@0.3.18': + '@libsql/linux-arm64-gnu@0.3.19': optional: true - '@libsql/linux-arm64-musl@0.2.0': + '@libsql/linux-arm64-gnu@0.4.1': optional: true '@libsql/linux-arm64-musl@0.3.18': optional: true - '@libsql/linux-x64-gnu@0.2.0': + '@libsql/linux-arm64-musl@0.3.19': + optional: true + + '@libsql/linux-arm64-musl@0.4.1': optional: true '@libsql/linux-x64-gnu@0.3.18': optional: true - '@libsql/linux-x64-musl@0.2.0': + '@libsql/linux-x64-gnu@0.3.19': + optional: true + + '@libsql/linux-x64-gnu@0.4.1': optional: true '@libsql/linux-x64-musl@0.3.18': optional: true - '@libsql/win32-x64-msvc@0.2.0': + '@libsql/linux-x64-musl@0.3.19': + optional: true + + '@libsql/linux-x64-musl@0.4.1': optional: true '@libsql/win32-x64-msvc@0.3.18': optional: true + '@libsql/win32-x64-msvc@0.3.19': + optional: true + + '@libsql/win32-x64-msvc@0.4.1': + optional: true + '@miniflare/core@2.14.2': dependencies: '@iarna/toml': 2.2.5 @@ -13507,10 +13598,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -13647,7 +13738,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13657,7 +13748,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13684,14 +13775,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13780,16 +13871,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13804,7 +13895,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13818,7 +13909,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13841,12 +13932,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -15127,7 +15218,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -16316,11 +16407,11 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20240524.0 - '@libsql/client': 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.9.3 '@opentelemetry/api': 1.8.0 '@planetscale/database': 1.18.0 @@ -17157,35 +17248,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17199,24 +17290,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18357,24 +18448,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libsql@0.2.0: - dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - optionalDependencies: - '@libsql/darwin-arm64': 0.2.0 - '@libsql/darwin-x64': 0.2.0 - '@libsql/linux-arm64-gnu': 0.2.0 - '@libsql/linux-arm64-musl': 0.2.0 - '@libsql/linux-x64-gnu': 0.2.0 - '@libsql/linux-x64-musl': 0.2.0 - '@libsql/win32-x64-msvc': 0.2.0 - optional: true - libsql@0.3.18: dependencies: '@neon-rs/load': 0.0.4 detect-libc: 2.0.2 + libsql: 0.3.19 optionalDependencies: '@libsql/darwin-arm64': 0.3.18 '@libsql/darwin-x64': 0.3.18 @@ -18384,6 +18462,33 @@ snapshots: '@libsql/linux-x64-musl': 0.3.18 '@libsql/win32-x64-msvc': 0.3.18 + libsql@0.3.19: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.3.19 + '@libsql/darwin-x64': 0.3.19 + '@libsql/linux-arm64-gnu': 0.3.19 + '@libsql/linux-arm64-musl': 0.3.19 + '@libsql/linux-x64-gnu': 0.3.19 + '@libsql/linux-x64-musl': 0.3.19 + '@libsql/win32-x64-msvc': 0.3.19 + + libsql@0.4.1: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + libsql: 0.3.19 + optionalDependencies: + '@libsql/darwin-arm64': 0.4.1 + '@libsql/darwin-x64': 0.4.1 + '@libsql/linux-arm64-gnu': 0.4.1 + '@libsql/linux-arm64-musl': 0.4.1 + '@libsql/linux-x64-gnu': 0.4.1 + '@libsql/linux-x64-musl': 0.4.1 + '@libsql/win32-x64-msvc': 0.4.1 + lighthouse-logger@1.4.2: dependencies: debug: 2.6.9 @@ -18692,12 +18797,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18773,13 +18878,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18793,7 +18898,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18819,7 +18924,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18827,7 +18932,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18836,7 +18941,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19641,6 +19746,8 @@ snapshots: promise-inflight@1.0.1: optional: true + promise-limit@2.7.0: {} + promise-retry@2.0.1: dependencies: err-code: 2.0.3 @@ -19720,10 +19827,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19736,19 +19843,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19767,14 +19874,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21627,15 +21734,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 15c6b1a6399e741b6c50bebc2b4a1f27fe69f822 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 16:18:02 +0300 Subject: [PATCH 118/152] fixed dialects in introspect musql, psql, sqlite updated packages --- drizzle-kit/src/cli/commands/introspect.ts | 6 +- drizzle-orm/package.json | 2 +- integration-tests/package.json | 2 +- pnpm-lock.yaml | 334 +++++++++------------ 4 files changed, 143 insertions(+), 201 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 0940385af9..9b5a044f68 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -211,7 +211,7 @@ export const introspectMysql = async ( writeFileSync(relationsFile, relationsTs.file); console.log(); - const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + const { snapshots, journal } = prepareOutFolder(out, 'mysql'); if (snapshots.length === 0) { const { sqlStatements, _meta } = await applyMysqlSnapshotsDiff( @@ -418,7 +418,7 @@ export const introspectSqlite = async ( writeFileSync(relationsFile, relationsTs.file); console.log(); - const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + const { snapshots, journal } = prepareOutFolder(out, 'sqlite'); if (snapshots.length === 0) { const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( @@ -529,7 +529,7 @@ export const introspectLibSQL = async ( writeFileSync(relationsFile, relationsTs.file); console.log(); - const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + const { snapshots, journal } = prepareOutFolder(out, 'sqlite'); if (snapshots.length === 0) { const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 7568c6e110..11970a77ed 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -46,7 +46,7 @@ "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=3", "@electric-sql/pglite": ">=0.1.1", - "@libsql/client": "*", + "@libsql/client": ">=0.10.0", "@neondatabase/serverless": ">=0.1", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", diff --git a/integration-tests/package.json b/integration-tests/package.json index a4fcab0b23..78f36fe302 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -15,6 +15,7 @@ "license": "Apache-2.0", "private": true, "devDependencies": { + "@libsql/client": "^0.10.0", "@neondatabase/serverless": "0.9.0", "@originjs/vite-plugin-commonjs": "^1.0.3", "@paralleldrive/cuid2": "^2.2.2", @@ -41,7 +42,6 @@ "@aws-sdk/client-rds-data": "^3.549.0", "@aws-sdk/credential-providers": "^3.549.0", "@electric-sql/pglite": "^0.1.1", - "@libsql/client": "^0.5.6", "@miniflare/d1": "^2.14.2", "@miniflare/shared": "^2.14.2", "@planetscale/database": "^1.16.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4917e0d208..dfb3ae80d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -313,7 +313,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -361,7 +361,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -554,9 +554,6 @@ importers: '@electric-sql/pglite': specifier: ^0.1.1 version: 0.1.5 - '@libsql/client': - specifier: ^0.5.6 - version: 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@miniflare/d1': specifier: ^2.14.2 version: 2.14.2 @@ -648,6 +645,9 @@ importers: specifier: ^3.20.2 version: 3.23.7 devDependencies: + '@libsql/client': + specifier: ^0.10.0 + version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: 0.9.0 version: 0.9.0 @@ -3088,20 +3088,9 @@ packages: '@libsql/client@0.10.0': resolution: {integrity: sha512-2ERn08T4XOVx34yBtUPq0RDjAdd9TJ5qNH/izugr208ml2F94mk92qC64kXyDVQINodWJvp3kAdq6P4zTtCZ7g==} - '@libsql/client@0.5.6': - resolution: {integrity: sha512-UBjmDoxz75Z2sHdP+ETCROpeLA/77VMesiff8R4UWK1rnaWbh6/YoCLDILMJL3Rh0udQeKxjL8MjXthqohax+g==} - '@libsql/core@0.10.0': resolution: {integrity: sha512-rqynAXGaiSpTsykOZdBtI1N4z4O+KZ6mt33K/aHeXAY0gSIfK/ctxuWa0Y1Bjo4FMz1idBTCXz4Ps5kITOvZZw==} - '@libsql/core@0.5.6': - resolution: {integrity: sha512-3vicUAydq6jPth410n4AsHHm1n2psTwvkSf94nfJlSXutGSZsl0updn2N/mJBgqUHkbuFoWZtlMifF0SwBj1xQ==} - - '@libsql/darwin-arm64@0.3.18': - resolution: {integrity: sha512-Zt49dt+cwhPCkuoWgvjbQd4ckNfCJR5xzIAyhgHl3CBZqZaEuaXTOGKLNQT7bnFRPuQcdLt5PBT1cenKu2N6pA==} - cpu: [arm64] - os: [darwin] - '@libsql/darwin-arm64@0.3.19': resolution: {integrity: sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ==} cpu: [arm64] @@ -3112,11 +3101,6 @@ packages: cpu: [arm64] os: [darwin] - '@libsql/darwin-x64@0.3.18': - resolution: {integrity: sha512-faq6HUGDaNaueeqPei5cypHaD/hhazUyfHo094CXiEeRZq6ZKtNl5PHdlr8jE/Uw8USNpVVQaLdnvSgKcpRPHw==} - cpu: [x64] - os: [darwin] - '@libsql/darwin-x64@0.3.19': resolution: {integrity: sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw==} cpu: [x64] @@ -3127,15 +3111,9 @@ packages: cpu: [x64] os: [darwin] - '@libsql/hrana-client@0.5.6': - resolution: {integrity: sha512-mjQoAmejZ1atG+M3YR2ZW+rg6ceBByH/S/h17ZoYZkqbWrvohFhXyz2LFxj++ARMoY9m6w3RJJIRdJdmnEUlFg==} - '@libsql/hrana-client@0.6.2': resolution: {integrity: sha512-MWxgD7mXLNf9FXXiM0bc90wCjZSpErWKr5mGza7ERy2FJNNMXd7JIOv+DepBA1FQTIfI8TFO4/QDYgaQC0goNw==} - '@libsql/isomorphic-fetch@0.1.12': - resolution: {integrity: sha512-MRo4UcmjAGAa3ac56LoD5OE13m2p0lu0VEtZC2NZMcogM/jc5fU9YtMQ3qbPjFJ+u2BBjFZgMPkQaLS1dlMhpg==} - '@libsql/isomorphic-fetch@0.2.5': resolution: {integrity: sha512-8s/B2TClEHms2yb+JGpsVRTPBfy1ih/Pq6h6gvyaNcYnMVJvgQRY7wAa8U2nD0dppbCuDU5evTNMEhrQ17ZKKg==} engines: {node: '>=18.0.0'} @@ -3143,11 +3121,6 @@ packages: '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - '@libsql/linux-arm64-gnu@0.3.18': - resolution: {integrity: sha512-5m9xtDAhoyLSV54tho9uQ2ZIDeJWc0vU3Xpe/VK4+6bpURISs23qNhXiCrZnnq3oV0hFlBfcIgQUIATmb6jD2A==} - cpu: [arm64] - os: [linux] - '@libsql/linux-arm64-gnu@0.3.19': resolution: {integrity: sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg==} cpu: [arm64] @@ -3158,11 +3131,6 @@ packages: cpu: [arm64] os: [linux] - '@libsql/linux-arm64-musl@0.3.18': - resolution: {integrity: sha512-oYD5+oM2gPEalp+EoR5DVQBRtdGjLsocjsRbQs5O2m4WOBJKER7VUfDYZHsifLGZoBSc11Yo6s9IR9rjGWy20w==} - cpu: [arm64] - os: [linux] - '@libsql/linux-arm64-musl@0.3.19': resolution: {integrity: sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg==} cpu: [arm64] @@ -3173,11 +3141,6 @@ packages: cpu: [arm64] os: [linux] - '@libsql/linux-x64-gnu@0.3.18': - resolution: {integrity: sha512-QDSSP60nS8KIldGE7H3bpEflQHiL1erwED6huoVJdmDFxsyDJX2CYdWUWW8Za0ZUOvUbnEWAOyMhp6j1dBbZqw==} - cpu: [x64] - os: [linux] - '@libsql/linux-x64-gnu@0.3.19': resolution: {integrity: sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ==} cpu: [x64] @@ -3188,11 +3151,6 @@ packages: cpu: [x64] os: [linux] - '@libsql/linux-x64-musl@0.3.18': - resolution: {integrity: sha512-5SXwTlaLCUPzxYyq+P0c7Ko7tcEjpd1X6RZKe1DuRFmJPg6f7j2+LrPEhMSIbqKcrl5ACUUAyoKmGZqNYwz23w==} - cpu: [x64] - os: [linux] - '@libsql/linux-x64-musl@0.3.19': resolution: {integrity: sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ==} cpu: [x64] @@ -3203,11 +3161,6 @@ packages: cpu: [x64] os: [linux] - '@libsql/win32-x64-msvc@0.3.18': - resolution: {integrity: sha512-9EEIHz+e8tTbx9TMkb8ByZnzxc0pYFirK1nSbqC6cFEST95fiY0NCfQ/zAzJxe90KckbjifX6BbO69eWIi3TAg==} - cpu: [x64] - os: [win32] - '@libsql/win32-x64-msvc@0.3.19': resolution: {integrity: sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg==} cpu: [x64] @@ -4105,9 +4058,6 @@ packages: '@types/minimist@1.2.2': resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} - '@types/node-fetch@2.6.11': - resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} - '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} @@ -7143,11 +7093,6 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libsql@0.3.18: - resolution: {integrity: sha512-lvhKr7WV3NLWRbXkjn/MeKqXOAqWKU0PX9QYrvDh7fneukapj+iUQ4qgJASrQyxcCrEsClXCQiiK5W6OoYPAlA==} - cpu: [x64, arm64, wasm32] - os: [darwin, linux, win32] - libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} cpu: [x64, arm64, wasm32] @@ -10270,7 +10215,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.583.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10360,9 +10305,9 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10665,7 +10610,7 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/client-sts@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 @@ -10707,6 +10652,51 @@ snapshots: '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/core': 3.582.0 + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10863,7 +10853,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -10951,6 +10941,25 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0))': + dependencies: + '@aws-sdk/credential-provider-env': 3.577.0 + '@aws-sdk/credential-provider-http': 3.582.0 + '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-process': 3.577.0 + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) + '@aws-sdk/types': 3.577.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 @@ -11068,7 +11077,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0))': dependencies: '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 @@ -11076,6 +11085,14 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': + dependencies: + '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/types': 3.577.0 + '@smithy/property-provider': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.6.2 + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 @@ -12952,7 +12969,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12970,7 +12987,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13401,54 +13418,22 @@ snapshots: - bufferutil - utf-8-validate - '@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/core': 0.5.6 - '@libsql/hrana-client': 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - libsql: 0.3.18 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - '@libsql/core@0.10.0': dependencies: js-base64: 3.7.7 - '@libsql/core@0.5.6': - dependencies: - js-base64: 3.7.7 - - '@libsql/darwin-arm64@0.3.18': - optional: true - '@libsql/darwin-arm64@0.3.19': optional: true '@libsql/darwin-arm64@0.4.1': optional: true - '@libsql/darwin-x64@0.3.18': - optional: true - '@libsql/darwin-x64@0.3.19': optional: true '@libsql/darwin-x64@0.4.1': optional: true - '@libsql/hrana-client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/isomorphic-fetch': 0.1.12(encoding@0.1.13) - '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - node-fetch: 3.3.2 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - '@libsql/hrana-client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@libsql/isomorphic-fetch': 0.2.5 @@ -13459,62 +13444,40 @@ snapshots: - bufferutil - utf-8-validate - '@libsql/isomorphic-fetch@0.1.12(encoding@0.1.13)': - dependencies: - '@types/node-fetch': 2.6.11 - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - '@libsql/isomorphic-fetch@0.2.5': {} '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@types/ws': 8.5.11 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate - '@libsql/linux-arm64-gnu@0.3.18': - optional: true - '@libsql/linux-arm64-gnu@0.3.19': optional: true '@libsql/linux-arm64-gnu@0.4.1': optional: true - '@libsql/linux-arm64-musl@0.3.18': - optional: true - '@libsql/linux-arm64-musl@0.3.19': optional: true '@libsql/linux-arm64-musl@0.4.1': optional: true - '@libsql/linux-x64-gnu@0.3.18': - optional: true - '@libsql/linux-x64-gnu@0.3.19': optional: true '@libsql/linux-x64-gnu@0.4.1': optional: true - '@libsql/linux-x64-musl@0.3.18': - optional: true - '@libsql/linux-x64-musl@0.3.19': optional: true '@libsql/linux-x64-musl@0.4.1': optional: true - '@libsql/win32-x64-msvc@0.3.18': - optional: true - '@libsql/win32-x64-msvc@0.3.19': optional: true @@ -13598,10 +13561,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) '@opentelemetry/api@1.8.0': {} @@ -13738,7 +13701,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13748,7 +13711,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13775,14 +13738,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13871,16 +13834,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13895,7 +13858,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13909,7 +13872,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13932,12 +13895,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.1 @@ -14778,11 +14741,6 @@ snapshots: '@types/minimist@1.2.2': {} - '@types/node-fetch@2.6.11': - dependencies: - '@types/node': 20.12.12 - form-data: 4.0.0 - '@types/node-forge@1.3.11': dependencies: '@types/node': 20.12.12 @@ -17248,35 +17206,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) expo-modules-autolinking@1.11.1: dependencies: @@ -17290,24 +17248,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18448,20 +18406,6 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libsql@0.3.18: - dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - libsql: 0.3.19 - optionalDependencies: - '@libsql/darwin-arm64': 0.3.18 - '@libsql/darwin-x64': 0.3.18 - '@libsql/linux-arm64-gnu': 0.3.18 - '@libsql/linux-arm64-musl': 0.3.18 - '@libsql/linux-x64-gnu': 0.3.18 - '@libsql/linux-x64-musl': 0.3.18 - '@libsql/win32-x64-msvc': 0.3.18 - libsql@0.3.19: dependencies: '@neon-rs/load': 0.0.4 @@ -18797,12 +18741,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18878,13 +18822,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18898,7 +18842,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18924,7 +18868,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18932,7 +18876,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18941,7 +18885,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19827,10 +19771,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19843,19 +19787,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19874,14 +19818,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21734,17 +21678,15 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From deb7533a9926870a1b4e7506a1ea2cfa964c0666 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 17:28:57 +0300 Subject: [PATCH 119/152] updated tests and removed pragma from push in libsql --- .../src/cli/commands/libSqlPushUtils.ts | 7 ------ drizzle-kit/src/cli/connections.ts | 1 + .../src/serializer/sqliteSerializer.ts | 3 ++- drizzle-kit/tests/push/libsql.test.ts | 24 ++++++++----------- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 98c95f0899..01bb613346 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -298,17 +298,10 @@ export const libSqlLogSuggestionsAndReturn = async ( continue; } - // ! for libsql it will break - const [{ foreign_keys: pragmaState }] = await connection.query<{ - foreign_keys: number; - }>(`PRAGMA foreign_keys;`); - - if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=OFF;`); // recreate table statementsToExecute.push( ..._moveDataStatements(tableName, json2, dataLoss), ); - if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=ON;`); } else if ( statement.type === 'alter_table_alter_column_set_generated' || statement.type === 'alter_table_alter_column_drop_generated' diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 440d3d5bf1..e2923f9dfc 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -645,6 +645,7 @@ export const connectToLibSQL = async (credentials: LibSQLCredentials): Promise< const client = createClient({ url: normaliseSQLiteUrl(credentials.url, 'libsql'), + authToken: credentials.authToken, }); const drzl = drizzle(client); const migrateFn = async (config: MigrationConfig) => { diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index ce544235ba..81c633cb2b 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -363,7 +363,6 @@ export const fromDatabase = async ( ) => void, ): Promise => { const result: Record = {}; - const columns = await db.query<{ tableName: string; columnName: string; @@ -389,6 +388,8 @@ export const fromDatabase = async ( `, ); + console.log('HERE'); + const tablesWithSeq: string[] = []; const seq = await db.query<{ diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 5799b1fe3c..89ec008ca5 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -493,21 +493,19 @@ test('change autoincrement. table is part of foreign key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(6); - expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); - expect(sqlStatements[1]).toBe( + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL );\n`, ); - expect(sqlStatements[2]).toBe( + expect(sqlStatements[1]).toBe( `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, ); - expect(sqlStatements[3]).toBe(`DROP TABLE \`companies\`;`); - expect(sqlStatements[4]).toBe( + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); - expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -756,21 +754,19 @@ test('recreate table with nested references', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements!.length).toBe(6); - expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); - expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY NOT NULL, \t\`name\` text, \t\`age\` integer );\n`); - expect(sqlStatements![2]).toBe( + expect(sqlStatements![1]).toBe( `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, ); - expect(sqlStatements![3]).toBe(`DROP TABLE \`users\`;`); - expect(sqlStatements![4]).toBe( + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements[5]).toBe('PRAGMA foreign_keys=ON;'); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); From 380a4ce69687e1a829053eca1e21bd32ab88ea71 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 17:55:02 +0300 Subject: [PATCH 120/152] removed console.log --- drizzle-kit/src/serializer/sqliteSerializer.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 81c633cb2b..41edd78a9d 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -388,8 +388,6 @@ export const fromDatabase = async ( `, ); - console.log('HERE'); - const tablesWithSeq: string[] = []; const seq = await db.query<{ From 9b68f3d94afa54413d7b8fc4e2c557073c264873 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 3 Sep 2024 13:23:48 +0300 Subject: [PATCH 121/152] updated pull config update migrate function in drizzle-orm --- drizzle-kit/src/cli/commands/utils.ts | 2 +- drizzle-kit/src/cli/connections.ts | 46 +++++++++++++++ drizzle-kit/src/cli/utils.ts | 2 +- drizzle-kit/tests/libsql-statements.test.ts | 1 - drizzle-kit/tests/migrate/libsq-schema.ts | 6 ++ .../tests/migrate/libsql-migrate.test.ts | 58 +++++++++++++++++++ .../migrations/0000_little_blizzard.sql | 4 ++ .../migrations/0001_nebulous_storm.sql | 10 ++++ .../migrations/meta/0000_snapshot.json | 40 +++++++++++++ .../migrations/meta/0001_snapshot.json | 40 +++++++++++++ .../migrate/migrations/meta/_journal.json | 20 +++++++ drizzle-orm/src/libsql/migrator.ts | 2 +- drizzle-orm/src/libsql/session.ts | 15 +++++ drizzle-orm/src/version.ts | 2 +- 14 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 drizzle-kit/tests/migrate/libsq-schema.ts create mode 100644 drizzle-kit/tests/migrate/libsql-migrate.test.ts create mode 100644 drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql create mode 100644 drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql create mode 100644 drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json create mode 100644 drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json create mode 100644 drizzle-kit/tests/migrate/migrations/meta/_journal.json diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 2cfc7273bf..bbad4bdb17 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -539,7 +539,7 @@ export const preparePullConfig = async ( process.exit(1); } return { - dialect: 'sqlite', + dialect, out: config.out, breakpoints: config.breakpoints, casing: config.casing, diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index e2923f9dfc..26311dbd63 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -586,6 +586,51 @@ export const connectToSQLite = async ( } } + if (await checkPackage('@libsql/client')) { + const { createClient } = await import('@libsql/client'); + const { drizzle } = await import('drizzle-orm/libsql'); + const { migrate } = await import('drizzle-orm/libsql/migrator'); + + const client = createClient({ + url: credentials.url, + }); + const drzl = drizzle(client); + const migrateFn = async (config: MigrationConfig) => { + return migrate(drzl, config); + }; + + const db: LibSQLDB = { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batchWithPragma: async (queries: string[]) => { + await client.migrate(queries); + }, + }; + + const proxy: SqliteProxy = { + proxy: async (params: ProxyParams) => { + const preparedParams = prepareSqliteParams(params.params); + const result = await client.execute({ + sql: params.sql, + args: preparedParams, + }); + + if (params.mode === 'array') { + return result.rows.map((row) => Object.values(row)); + } else { + return result.rows; + } + }, + }; + + return { ...db, ...proxy, migrate: migrateFn }; + } + if (await checkPackage('better-sqlite3')) { const { default: Database } = await import('better-sqlite3'); const { drizzle } = await import('drizzle-orm/better-sqlite3'); @@ -627,6 +672,7 @@ export const connectToSQLite = async ( }; return { ...db, ...proxy, migrate: migrateFn }; } + console.log( "Please install 'better-sqlite3' for Drizzle Kit to connect to SQLite databases", ); diff --git a/drizzle-kit/src/cli/utils.ts b/drizzle-kit/src/cli/utils.ts index f7e7a2ae9c..0a5d7862e2 100644 --- a/drizzle-kit/src/cli/utils.ts +++ b/drizzle-kit/src/cli/utils.ts @@ -74,7 +74,7 @@ export const assertEitherPackage = async ( process.exit(1); }; -const requiredApiVersion = 7; +const requiredApiVersion = 8; export const assertOrmCoreVersion = async () => { try { const { compatibilityVersion } = await import('drizzle-orm/version'); diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index e18e41950c..8221e52e0d 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -1,4 +1,3 @@ -import { sql } from 'drizzle-orm'; import { foreignKey, index, int, integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; import { JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; diff --git a/drizzle-kit/tests/migrate/libsq-schema.ts b/drizzle-kit/tests/migrate/libsq-schema.ts new file mode 100644 index 0000000000..5cb344d518 --- /dev/null +++ b/drizzle-kit/tests/migrate/libsq-schema.ts @@ -0,0 +1,6 @@ +import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), +}); diff --git a/drizzle-kit/tests/migrate/libsql-migrate.test.ts b/drizzle-kit/tests/migrate/libsql-migrate.test.ts new file mode 100644 index 0000000000..b937b644fd --- /dev/null +++ b/drizzle-kit/tests/migrate/libsql-migrate.test.ts @@ -0,0 +1,58 @@ +import { createClient } from '@libsql/client'; +import { connectToLibSQL } from 'src/cli/connections'; +import { expect, test } from 'vitest'; + +test('validate migrate function', async () => { + const credentials = { + url: ':memory:', + }; + const { migrate, query } = await connectToLibSQL(credentials); + + await migrate({ migrationsFolder: 'tests/migrate/migrations' }); + + const res = await query(`PRAGMA table_info("users");`); + + expect(res).toStrictEqual([{ + cid: 0, + name: 'id', + type: 'INTEGER', + notnull: 0, + dflt_value: null, + pk: 0, + }, { + cid: 1, + name: 'name', + type: 'INTEGER', + notnull: 1, + dflt_value: null, + pk: 0, + }]); +}); + +// test('validate migrate function', async () => { +// const credentials = { +// url: '', +// authToken: '', +// }; +// const { migrate, query } = await connectToLibSQL(credentials); + +// await migrate({ migrationsFolder: 'tests/migrate/migrations' }); + +// const res = await query(`PRAGMA table_info("users");`); + +// expect(res).toStrictEqual([{ +// cid: 0, +// name: 'id', +// type: 'INTEGER', +// notnull: 0, +// dflt_value: null, +// pk: 0, +// }, { +// cid: 1, +// name: 'name', +// type: 'INTEGER', +// notnull: 1, +// dflt_value: null, +// pk: 0, +// }]); +// }); diff --git a/drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql b/drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql new file mode 100644 index 0000000000..9de0a139df --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql @@ -0,0 +1,4 @@ +CREATE TABLE `users` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL +); diff --git a/drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql b/drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql new file mode 100644 index 0000000000..4309a05c2f --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql @@ -0,0 +1,10 @@ +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_users` ( + `id` integer, + `name` integer NOT NULL +); +--> statement-breakpoint +INSERT INTO `__new_users`("id", "name") SELECT "id", "name" FROM `users`;--> statement-breakpoint +DROP TABLE `users`;--> statement-breakpoint +ALTER TABLE `__new_users` RENAME TO `users`;--> statement-breakpoint +PRAGMA foreign_keys=ON; \ No newline at end of file diff --git a/drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json b/drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json new file mode 100644 index 0000000000..599d02b915 --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json @@ -0,0 +1,40 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "2bd46776-9e41-4a6c-b617-5c600bb176f2", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json b/drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json new file mode 100644 index 0000000000..e3b26ba140 --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json @@ -0,0 +1,40 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "6c0ec455-42fd-47fd-a22c-4bb4551e1358", + "prevId": "2bd46776-9e41-4a6c-b617-5c600bb176f2", + "tables": { + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle-kit/tests/migrate/migrations/meta/_journal.json b/drizzle-kit/tests/migrate/migrations/meta/_journal.json new file mode 100644 index 0000000000..c836eb194b --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/meta/_journal.json @@ -0,0 +1,20 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1725358702427, + "tag": "0000_little_blizzard", + "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1725358713033, + "tag": "0001_nebulous_storm", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/drizzle-orm/src/libsql/migrator.ts b/drizzle-orm/src/libsql/migrator.ts index 58bcc9e05d..aa262bc2dc 100644 --- a/drizzle-orm/src/libsql/migrator.ts +++ b/drizzle-orm/src/libsql/migrator.ts @@ -47,5 +47,5 @@ export async function migrate>( } } - await db.session.batch(statementToBatch); + await db.session.migrate(statementToBatch); } diff --git a/drizzle-orm/src/libsql/session.ts b/drizzle-orm/src/libsql/session.ts index 29e4e268f0..6409777348 100644 --- a/drizzle-orm/src/libsql/session.ts +++ b/drizzle-orm/src/libsql/session.ts @@ -76,6 +76,21 @@ export class LibSQLSession< return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)); } + async migrate[] | readonly BatchItem<'sqlite'>[]>(queries: T) { + const preparedQueries: PreparedQuery[] = []; + const builtQueries: InStatement[] = []; + + for (const query of queries) { + const preparedQuery = query._prepare(); + const builtQuery = preparedQuery.getQuery(); + preparedQueries.push(preparedQuery); + builtQueries.push({ sql: builtQuery.sql, args: builtQuery.params as InArgs }); + } + + const batchResults = await this.client.migrate(builtQueries); + return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)); + } + override async transaction( transaction: (db: LibSQLTransaction) => T | Promise, _config?: SQLiteTransactionConfig, diff --git a/drizzle-orm/src/version.ts b/drizzle-orm/src/version.ts index 0c11937c83..d670a0575a 100644 --- a/drizzle-orm/src/version.ts +++ b/drizzle-orm/src/version.ts @@ -1,4 +1,4 @@ // @ts-ignore - imported using Rollup json plugin export { version as npmVersion } from '../package.json'; // In version 7, we changed the PostgreSQL indexes API -export const compatibilityVersion = 7; +export const compatibilityVersion = 8; From 779098355dccc1d82a0cca1e454269899e4b942c Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 3 Sep 2024 14:58:14 +0300 Subject: [PATCH 122/152] removed driver --- drizzle-kit/src/cli/commands/migrate.ts | 3 +-- drizzle-kit/src/cli/commands/utils.ts | 1 - drizzle-kit/src/cli/validations/cli.ts | 3 +-- drizzle-kit/src/sqlgenerator.ts | 2 -- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 83f5b2dc8e..de1d8bc453 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,7 +13,6 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; -import { JsonStatement } from 'src/jsonStatements'; import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; @@ -38,7 +37,7 @@ import { } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; -import { Driver, Prefix } from '../validations/common'; +import { Prefix } from '../validations/common'; import { withStyle } from '../validations/outputs'; import { isRenamePromptItem, diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index bbad4bdb17..5e5681b2c0 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -241,7 +241,6 @@ export const preparePushConfig = async ( : options, ); - raw.driver ||= options.driver; raw.verbose ||= options.verbose; // if provided in cli to debug raw.strict ||= options.strict; // if provided in cli only diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 9d580fbe4f..c4bbbe530c 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -1,6 +1,6 @@ import { boolean, intersection, literal, object, string, TypeOf, union } from 'zod'; import { dialect } from '../../schemaValidator'; -import { casing, driver, prefix } from './common'; +import { casing, prefix } from './common'; export const cliConfigGenerate = object({ dialect: dialect.optional(), @@ -25,7 +25,6 @@ export const pushParams = object({ extensionsFilters: literal('postgis').array().optional(), verbose: boolean().optional(), strict: boolean().optional(), - driver: driver.optional(), }).passthrough(); export type PushParams = TypeOf; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 227cdf032e..f1e783a503 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1,5 +1,4 @@ import { BREAKPOINT } from './cli/commands/migrate'; -import { Driver } from './cli/validations/common'; import { JsonAddColumnStatement, JsonAddValueToEnumStatement, @@ -132,7 +131,6 @@ abstract class Convertor { abstract can( statement: JsonStatement, dialect: Dialect, - driver?: Driver, ): boolean; abstract convert( statement: JsonStatement, From d954a4bd3cb3e84538f5dca7247658e21fe07fdd Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 4 Sep 2024 11:48:57 +0300 Subject: [PATCH 123/152] updated sqlite connection to libsql --- drizzle-kit/src/cli/connections.ts | 7 ++----- drizzle-kit/src/utils.ts | 3 --- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 26311dbd63..54945386e8 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -592,14 +592,14 @@ export const connectToSQLite = async ( const { migrate } = await import('drizzle-orm/libsql/migrator'); const client = createClient({ - url: credentials.url, + url: normaliseSQLiteUrl(credentials.url, 'libsql'), }); const drzl = drizzle(client); const migrateFn = async (config: MigrationConfig) => { return migrate(drzl, config); }; - const db: LibSQLDB = { + const db: SQLiteDB = { query: async (sql: string, params?: any[]) => { const res = await client.execute({ sql, args: params || [] }); return res.rows as T[]; @@ -607,9 +607,6 @@ export const connectToSQLite = async ( run: async (query: string) => { await client.execute(query); }, - batchWithPragma: async (queries: string[]) => { - await client.migrate(queries); - }, }; const proxy: SqliteProxy = { diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index f5ff34c6ff..71454550ea 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -26,9 +26,6 @@ export type DB = { export type SQLiteDB = { query: (sql: string, params?: any[]) => Promise; run(query: string): Promise; - batch?( - queries: { query: string; values?: any[] | undefined }[], - ): Promise; }; export type LibSQLDB = { From 482cdce9de02cf8a63f7ccec29fbcecece7f5f1c Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 2 Sep 2024 15:51:05 +0300 Subject: [PATCH 124/152] Added alternate config for better-sqlite3, bun:sqlite; Renamed bun-sqlite to bun:sqlite; Fixed schema inferrence issue (no schema would resrresult in `unknown`, expected: `Record`) --- drizzle-orm/src/monodriver.ts | 56 +++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index b2b82af3fd..db7ac1dddd 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -50,15 +50,21 @@ type BunSqliteDatabaseOptions = readwrite?: boolean; }; -type BunSqliteDatabaseConfig = { - filename?: string; - options?: BunSqliteDatabaseOptions; -}; +type BunSqliteDatabaseConfig = + | { + filename?: string; + options?: BunSqliteDatabaseOptions; + } + | string + | undefined; -type BetterSQLite3DatabaseConfig = { - filename?: string | Buffer; - options?: BetterSQLite3Options; -}; +type BetterSQLite3DatabaseConfig = + | { + filename?: string | Buffer; + options?: BetterSQLite3Options; + } + | string + | undefined; type MonodriverNeonHttpConfig = { connectionString: string; @@ -77,7 +83,7 @@ type ClientDrizzleInstanceMap> = { 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; - 'bun-sqlite': BunSQLiteDatabase; + 'bun:sqlite': BunSQLiteDatabase; 'better-sqlite3': BetterSQLite3Database; }; @@ -129,7 +135,7 @@ type InitializerParams< connection: D1Database; } & DrizzleConfig) | ({ - client: 'bun-sqlite'; + client: 'bun:sqlite'; connection: BunSqliteDatabaseConfig; } & DrizzleConfig) | ({ @@ -139,7 +145,9 @@ type InitializerParams< type DetermineClient< TParams extends InitializerParams, -> = ClientDrizzleInstanceMap[TParams['client']]; +> = ClientDrizzleInstanceMap< + TParams['schema'] extends Record ? TParams['schema'] : Record +>[TParams['client']]; const importError = (libName: string) => { throw new Error( @@ -172,17 +180,33 @@ export const drizzle = async < } case 'better-sqlite3': { const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); - const { filename, options } = connection as BetterSQLite3DatabaseConfig; const { drizzle } = await import('./better-sqlite3'); - const instance = new Client(filename, options); + + if (typeof connection === 'object') { + const { filename, options } = connection as Exclude; + + const instance = new Client(filename, options); + + return drizzle(instance, drizzleConfig) as any; + } + + const instance = new Client(connection); return drizzle(instance, drizzleConfig) as any; } - case 'bun-sqlite': { + case 'bun:sqlite': { const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); - const { filename, options } = connection as BunSqliteDatabaseConfig; const { drizzle } = await import('./bun-sqlite'); - const instance = new Client(filename, options); + + if (typeof connection === 'object') { + const { filename, options } = connection as Exclude; + + const instance = new Client(filename, options); + + return drizzle(instance, drizzleConfig) as any; + } + + const instance = new Client(connection); return drizzle(instance, drizzleConfig) as any; } From b40b752fae093f06b2c37e527237e5e3593c109f Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 2 Sep 2024 18:33:42 +0300 Subject: [PATCH 125/152] Added monomigrator --- drizzle-orm/src/index.ts | 1 + drizzle-orm/src/monomigrator.ts | 266 ++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 drizzle-orm/src/monomigrator.ts diff --git a/drizzle-orm/src/index.ts b/drizzle-orm/src/index.ts index 5cabdb0d84..469f5713e1 100644 --- a/drizzle-orm/src/index.ts +++ b/drizzle-orm/src/index.ts @@ -6,6 +6,7 @@ export * from './errors.ts'; export * from './expressions.ts'; export * from './logger.ts'; export * from './monodriver.ts'; +export * from './monomigrator.ts'; export * from './operations.ts'; export * from './query-promise.ts'; export * from './relations.ts'; diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts new file mode 100644 index 0000000000..b82a1ea0b1 --- /dev/null +++ b/drizzle-orm/src/monomigrator.ts @@ -0,0 +1,266 @@ +/* eslint-disable import/extensions */ +import type { AwsDataApiPgDatabase } from './aws-data-api/pg/index.ts'; +import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; +import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; +import type { DrizzleD1Database } from './d1/index.ts'; +import type { ExpoSQLiteDatabase } from './expo-sqlite/index.ts'; +import type { LibSQLDatabase } from './libsql/index.ts'; +import type { MigrationConfig } from './migrator.ts'; +import type { MySqlRemoteDatabase } from './mysql-proxy/index.ts'; +import type { ProxyMigrator as MySqlProxyMigrator } from './mysql-proxy/migrator.ts'; +import type { MySql2Database } from './mysql2/index.ts'; +import type { NeonHttpDatabase } from './neon-http/index.ts'; +import type { NeonDatabase } from './neon-serverless/index.ts'; +import type { NodePgDatabase } from './node-postgres/index.ts'; +import type { OPSQLiteDatabase } from './op-sqlite/index.ts'; +import type { PgRemoteDatabase } from './pg-proxy/index.ts'; +import type { ProxyMigrator as PgProxyMigrator } from './pg-proxy/migrator.ts'; +import type { PgliteDatabase } from './pglite/index.ts'; +import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; +import type { ProxyMigrator as SQLiteProxyMigrator } from './sqlite-proxy/migrator.ts'; +import type { VercelPgDatabase } from './vercel-postgres/index.ts'; +import type { XataHttpDatabase } from './xata-http/index.ts'; +import type { MigrationConfig as XataHttpMigrationConfig } from './xata-http/migrator.ts'; + +type OPSQLiteMigrationConfig = { + journal: { + entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; + }; + migrations: Record; +}; + +type ExpoSQLiteMigrationConfig = { + journal: { + entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; + }; + migrations: Record; +}; + +type DatabaseType = + | 'aws-data-api-pg' + | 'better-sqlite3' + | 'bun:sqlite' + | 'd1' + | 'expo-sqlite' + | 'libsql' + | 'mysql-proxy' + | 'mysql2' + | 'neon-http' + | 'neon-serverless' + | 'node-postgres' + | 'op-sqlite' + | 'pg-proxy' + | 'pglite' + | 'planetscale' + | 'postgres-js' + | 'sqlite-proxy' + | 'tidb-serverless' + | 'vercel-postgres' + | 'xata-http'; + +export async function migrate( + type: 'aws-data-api-pg', + db: AwsDataApiPgDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'better-sqlite3', + db: BetterSQLite3Database, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'bun:sqlite', + db: BunSQLiteDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate(type: 'd1', db: DrizzleD1Database, config: string | MigrationConfig): Promise; +export async function migrate( + type: 'expo-sqlite', + db: ExpoSQLiteDatabase, + config: ExpoSQLiteMigrationConfig, +): Promise; +export async function migrate(type: 'libsql', db: LibSQLDatabase, config: MigrationConfig): Promise; +export async function migrate( + type: 'mysql-proxy', + db: MySqlRemoteDatabase, + callback: MySqlProxyMigrator, + config: MigrationConfig, +): Promise; +export async function migrate(type: 'mysql2', db: MySql2Database, config: MigrationConfig): Promise; +export async function migrate( + type: 'neon-http', + db: NeonHttpDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'neon-serverless', + db: NeonDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'node-postgres', + db: NodePgDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'op-sqlite', + db: OPSQLiteDatabase, + config: OPSQLiteMigrationConfig, +): Promise; +export async function migrate( + type: 'pg-proxy', + db: PgRemoteDatabase, + callback: PgProxyMigrator, + config: string | MigrationConfig, +): Promise; +export async function migrate(type: 'pglite', db: PgliteDatabase, config: string | MigrationConfig): Promise; +export async function migrate( + type: 'planetscale', + db: PlanetScaleDatabase, + config: MigrationConfig, +): Promise; +export async function migrate( + type: 'postgres-js', + db: PlanetScaleDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'sqlite-proxy', + db: PgRemoteDatabase, + callback: SQLiteProxyMigrator, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'tidb-serverless', + db: PlanetScaleDatabase, + config: MigrationConfig, +): Promise; +export async function migrate( + type: 'vercel-postgres', + db: VercelPgDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'xata-http', + db: XataHttpDatabase, + config: string | XataHttpMigrationConfig, +): Promise; +export async function migrate( + type: DatabaseType, + db: any, + config: + | string + | MigrationConfig + | ExpoSQLiteMigrationConfig + | OPSQLiteMigrationConfig + | XataHttpMigrationConfig + | PgProxyMigrator + | MySqlProxyMigrator + | SQLiteProxyMigrator, + extraConfig?: string | MigrationConfig | undefined, +) { + const rest = [db, config, extraConfig]; + + switch (type) { + case 'aws-data-api-pg': { + const { migrate } = await import('./aws-data-api/pg/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'better-sqlite3': { + const { migrate } = await import('./better-sqlite3/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'bun:sqlite': { + const { migrate } = await import('./bun-sqlite/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'd1': { + const { migrate } = await import('./d1/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'expo-sqlite': { + const { migrate } = await import('./expo-sqlite/migrator'); + + return migrate(rest[0], rest[1] as ExpoSQLiteMigrationConfig); + } + case 'libsql': { + const { migrate } = await import('./libsql/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'mysql-proxy': { + const { migrate } = await import('./mysql-proxy/migrator'); + + return migrate(rest[0], rest[1] as MySqlProxyMigrator, rest[2] as MigrationConfig); + } + case 'mysql2': { + const { migrate } = await import('./mysql2/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'neon-http': { + const { migrate } = await import('./neon-http/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'neon-serverless': { + const { migrate } = await import('./neon-serverless/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'node-postgres': { + const { migrate } = await import('./node-postgres/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'op-sqlite': { + const { migrate } = await import('./op-sqlite/migrator'); + + return migrate(rest[0], rest[1] as OPSQLiteMigrationConfig); + } + case 'pg-proxy': { + const { migrate } = await import('./pg-proxy/migrator'); + + return migrate(rest[0], rest[1] as PgProxyMigrator, rest[2] as string | MigrationConfig); + } + case 'pglite': { + const { migrate } = await import('./pglite/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'planetscale': { + const { migrate } = await import('./planetscale-serverless/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'postgres-js': { + const { migrate } = await import('./postgres-js/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'sqlite-proxy': { + const { migrate } = await import('./sqlite-proxy/migrator'); + + return migrate(rest[0], rest[1] as SQLiteProxyMigrator, rest[2] as string | MigrationConfig); + } + case 'tidb-serverless': { + const { migrate } = await import('./tidb-serverless/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'vercel-postgres': { + const { migrate } = await import('./vercel-postgres/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'xata-http': { + const { migrate } = await import('./xata-http/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + } +} From ccac44066fe33bdd49670df20c5cc84cac210a7b Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 3 Sep 2024 12:47:31 +0300 Subject: [PATCH 126/152] Changed style of monodriver, monomigrator function args --- drizzle-orm/src/better-sqlite3/driver.ts | 11 +- drizzle-orm/src/bun-sqlite/driver.ts | 9 +- drizzle-orm/src/expo-sqlite/driver.ts | 11 +- drizzle-orm/src/monodriver.ts | 120 ++++++++++++---- drizzle-orm/src/monomigrator.ts | 132 ++++++------------ drizzle-orm/src/mysql-proxy/driver.ts | 9 +- drizzle-orm/src/neon-serverless/driver.ts | 8 +- drizzle-orm/src/op-sqlite/driver.ts | 9 +- drizzle-orm/src/pg-proxy/driver.ts | 9 +- drizzle-orm/src/pglite/driver.ts | 8 +- .../src/planetscale-serverless/driver.ts | 9 +- drizzle-orm/src/postgres-js/driver.ts | 9 +- drizzle-orm/src/tidb-serverless/driver.ts | 9 +- drizzle-orm/src/vercel-postgres/driver.ts | 8 +- 14 files changed, 213 insertions(+), 148 deletions(-) diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 728586e575..8d19cd8ab2 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -1,4 +1,5 @@ import type { Database, RunResult } from 'better-sqlite3'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -11,9 +12,11 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; -export type BetterSQLite3Database< - TSchema extends Record = Record, -> = BaseSQLiteDatabase<'sync', RunResult, TSchema>; +export class BetterSQLite3Database> + extends BaseSQLiteDatabase<'sync', RunResult, TSchema> +{ + static readonly [entityKind]: string = 'BetterSQLite3Database'; +} export function drizzle = Record>( client: Database, @@ -41,5 +44,5 @@ export function drizzle = Record; + return new BetterSQLite3Database('sync', dialect, session, schema) as BetterSQLite3Database; } diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 0d196ff03a..5771bd3711 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -1,6 +1,7 @@ /// import type { Database } from 'bun:sqlite'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -13,9 +14,11 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { SQLiteBunSession } from './session.ts'; -export type BunSQLiteDatabase< +export class BunSQLiteDatabase< TSchema extends Record = Record, -> = BaseSQLiteDatabase<'sync', void, TSchema>; +> extends BaseSQLiteDatabase<'sync', void, TSchema> { + static readonly [entityKind]: string = 'BunSQLiteDatabase'; +} export function drizzle = Record>( client: Database, @@ -43,5 +46,5 @@ export function drizzle = Record; + return new BunSQLiteDatabase('sync', dialect, session, schema) as BunSQLiteDatabase; } diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index ae8ce65777..51cb1a2042 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -1,4 +1,5 @@ import type { SQLiteDatabase, SQLiteRunResult } from 'expo-sqlite/next'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -11,9 +12,11 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { ExpoSQLiteSession } from './session.ts'; -export type ExpoSQLiteDatabase< - TSchema extends Record = Record, -> = BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema>; +export class ExpoSQLiteDatabase> + extends BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema> +{ + static readonly [entityKind]: string = 'ExpoSQLiteDatabase'; +} export function drizzle = Record>( client: SQLiteDatabase, @@ -41,5 +44,5 @@ export function drizzle = Record; + return new ExpoSQLiteDatabase('sync', dialect, session, schema) as ExpoSQLiteDatabase; } diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index db7ac1dddd..41bb202e89 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,5 +1,5 @@ /* eslint-disable import/extensions */ -import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { RDSDataClientConfig, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; import type { HTTPTransactionOptions as NeonHttpConfig, @@ -71,6 +71,21 @@ type MonodriverNeonHttpConfig = { options?: NeonHttpConfig; }; +type DatabaseVendor = + | 'node-postgres' + | 'postgres-js' + | 'neon-serverless' + | 'neon-http' + | 'vercel-postgres' + | 'aws-data-api-pg' + | 'planetscale' + | 'mysql2' + | 'tidb-serverless' + | 'libsql' + | 'd1' + | 'bun:sqlite' + | 'better-sqlite3'; + type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres-js': PostgresJsDatabase; @@ -91,63 +106,51 @@ type InitializerParams< TSchema extends Record = Record, > = | ({ - client: 'node-postgres'; connection: NodePGPoolConfig; } & DrizzleConfig) | ({ - client: 'postgres-js'; connection: PostgresJSOptions>; } & DrizzleConfig) | ({ - client: 'neon-serverless'; connection: NeonServerlessConfig; } & DrizzleConfig) | ({ - client: 'neon-http'; connection: MonodriverNeonHttpConfig; } & DrizzleConfig) | ({ - client: 'vercel-postgres'; connection: VercelPool; } & DrizzleConfig) | ({ - client: 'aws-data-api-pg'; connection: RDSConfig; } & DrizzleAwsDataApiPgConfig) | ({ - client: 'planetscale'; connection: PlanetscaleConfig; } & DrizzleConfig) | ({ - client: 'mysql2'; connection: Mysql2Config; } & MySql2DrizzleConfig) | ({ - client: 'tidb-serverless'; connection: TiDBServerlessConfig; } & DrizzleConfig) | ({ - client: 'libsql'; connection: LibsqlConfig; } & DrizzleConfig) | ({ - client: 'd1'; connection: D1Database; } & DrizzleConfig) | ({ - client: 'bun:sqlite'; - connection: BunSqliteDatabaseConfig; + connection?: BunSqliteDatabaseConfig; } & DrizzleConfig) | ({ - client: 'better-sqlite3'; - connection: BetterSQLite3DatabaseConfig; + connection?: BetterSQLite3DatabaseConfig; } & DrizzleConfig); type DetermineClient< - TParams extends InitializerParams, + TVendor extends DatabaseVendor, + TSchema extends Record, > = ClientDrizzleInstanceMap< - TParams['schema'] extends Record ? TParams['schema'] : Record ->[TParams['client']]; + TSchema +>[TVendor]; const importError = (libName: string) => { throw new Error( @@ -155,11 +158,75 @@ const importError = (libName: string) => { ); }; -export const drizzle = async < +const removeKey = , TKey extends keyof TRecord>( + obj: TRecord, + key: TKey, +): Omit => { + if (!(key in obj)) return obj; + + delete ( obj).key; + return obj; +}; + +export async function drizzle = Record>( + client: 'node-postgres', + params: { connection: NodePGPoolConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'postgres-js', + params: { connection: string | PostgresJSOptions> } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'neon-serverless', + params: { connection: NeonServerlessConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'neon-http', + params: { connection: MonodriverNeonHttpConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'vercel-postgres', + params: { connection: VercelPool } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'aws-data-api-pg', + params?: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, +): Promise>; +export async function drizzle = Record>( + client: 'planetscale', + params: { connection: PlanetscaleConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'mysql2', + params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'tidb-serverless', + params: { connection: TiDBServerlessConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'libsql', + params: { connection: LibsqlConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'd1', + params: { connection: D1Database } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'bun:sqlite', + params?: { connection?: BunSqliteDatabaseConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'better-sqlite3', + params?: { connection?: BetterSQLite3DatabaseConfig } & DrizzleConfig, +): Promise>; +export async function drizzle< + TVendor extends DatabaseVendor, TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): Promise> => { - const { client, connection, ...drizzleConfig } = params; +>(client: TVendor, params?: TParams): Promise> { + const connection = params?.connection; + const drizzleConfig = params ? removeKey(params, 'connection') : undefined; switch (client) { case 'node-postgres': { @@ -174,7 +241,7 @@ export const drizzle = async < importError('@aws-sdk/client-rds-data') ); const { drizzle } = await import('./aws-data-api/pg'); - const instance = new RDSDataClient(connection); + const instance = new RDSDataClient(connection as RDSDataClientConfig); return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } @@ -272,5 +339,10 @@ export const drizzle = async < return drizzle(sql, drizzleConfig) as any; } + default: { + throw new Error( + `Unsupported vendor for Drizzle ORM monodriver: '${client}'. Use dedicated drizzle initializer instead.`, + ); + } } -}; +} diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index b82a1ea0b1..eec37bbdf1 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -3,6 +3,7 @@ import type { AwsDataApiPgDatabase } from './aws-data-api/pg/index.ts'; import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; +import { entityKind } from './entity.ts'; import type { ExpoSQLiteDatabase } from './expo-sqlite/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; import type { MigrationConfig } from './migrator.ts'; @@ -36,117 +37,78 @@ type ExpoSQLiteMigrationConfig = { migrations: Record; }; -type DatabaseType = - | 'aws-data-api-pg' - | 'better-sqlite3' - | 'bun:sqlite' - | 'd1' - | 'expo-sqlite' - | 'libsql' - | 'mysql-proxy' - | 'mysql2' - | 'neon-http' - | 'neon-serverless' - | 'node-postgres' - | 'op-sqlite' - | 'pg-proxy' - | 'pglite' - | 'planetscale' - | 'postgres-js' - | 'sqlite-proxy' - | 'tidb-serverless' - | 'vercel-postgres' - | 'xata-http'; - export async function migrate( - type: 'aws-data-api-pg', db: AwsDataApiPgDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'better-sqlite3', db: BetterSQLite3Database, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'bun:sqlite', db: BunSQLiteDatabase, config: string | MigrationConfig, ): Promise; -export async function migrate(type: 'd1', db: DrizzleD1Database, config: string | MigrationConfig): Promise; +export async function migrate(db: DrizzleD1Database, config: string | MigrationConfig): Promise; export async function migrate( - type: 'expo-sqlite', db: ExpoSQLiteDatabase, config: ExpoSQLiteMigrationConfig, ): Promise; -export async function migrate(type: 'libsql', db: LibSQLDatabase, config: MigrationConfig): Promise; +export async function migrate(db: LibSQLDatabase, config: MigrationConfig): Promise; export async function migrate( - type: 'mysql-proxy', db: MySqlRemoteDatabase, callback: MySqlProxyMigrator, config: MigrationConfig, ): Promise; -export async function migrate(type: 'mysql2', db: MySql2Database, config: MigrationConfig): Promise; +export async function migrate(db: MySql2Database, config: MigrationConfig): Promise; export async function migrate( - type: 'neon-http', db: NeonHttpDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'neon-serverless', db: NeonDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'node-postgres', db: NodePgDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'op-sqlite', db: OPSQLiteDatabase, config: OPSQLiteMigrationConfig, ): Promise; export async function migrate( - type: 'pg-proxy', db: PgRemoteDatabase, callback: PgProxyMigrator, config: string | MigrationConfig, ): Promise; -export async function migrate(type: 'pglite', db: PgliteDatabase, config: string | MigrationConfig): Promise; +export async function migrate(db: PgliteDatabase, config: string | MigrationConfig): Promise; export async function migrate( - type: 'planetscale', db: PlanetScaleDatabase, config: MigrationConfig, ): Promise; export async function migrate( - type: 'postgres-js', db: PlanetScaleDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'sqlite-proxy', db: PgRemoteDatabase, callback: SQLiteProxyMigrator, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'tidb-serverless', db: PlanetScaleDatabase, config: MigrationConfig, ): Promise; export async function migrate( - type: 'vercel-postgres', db: VercelPgDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'xata-http', db: XataHttpDatabase, config: string | XataHttpMigrationConfig, ): Promise; export async function migrate( - type: DatabaseType, db: any, config: | string @@ -159,108 +121,106 @@ export async function migrate( | SQLiteProxyMigrator, extraConfig?: string | MigrationConfig | undefined, ) { - const rest = [db, config, extraConfig]; - - switch (type) { - case 'aws-data-api-pg': { + switch (db[entityKind]) { + case 'AwsDataApiPgDatabase': { const { migrate } = await import('./aws-data-api/pg/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'better-sqlite3': { + case 'BetterSQLite3Database': { const { migrate } = await import('./better-sqlite3/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'bun:sqlite': { + case 'BunSQLiteDatabase': { const { migrate } = await import('./bun-sqlite/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'd1': { + case 'D1Database': { const { migrate } = await import('./d1/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'expo-sqlite': { + case 'ExpoSQLiteDatabase': { const { migrate } = await import('./expo-sqlite/migrator'); - return migrate(rest[0], rest[1] as ExpoSQLiteMigrationConfig); + return migrate(db, config as ExpoSQLiteMigrationConfig); } - case 'libsql': { + case 'LibSQLDatabase': { const { migrate } = await import('./libsql/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'mysql-proxy': { + case 'MySqlRemoteDatabase': { const { migrate } = await import('./mysql-proxy/migrator'); - return migrate(rest[0], rest[1] as MySqlProxyMigrator, rest[2] as MigrationConfig); + return migrate(db, config as MySqlProxyMigrator, extraConfig as MigrationConfig); } - case 'mysql2': { + case 'MySql2Driver': { const { migrate } = await import('./mysql2/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'neon-http': { + case 'NeonHttpDatabase': { const { migrate } = await import('./neon-http/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'neon-serverless': { + case 'NeonServerlessDatabase': { const { migrate } = await import('./neon-serverless/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'node-postgres': { + case 'NodePgDriver': { const { migrate } = await import('./node-postgres/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'op-sqlite': { + case 'OPSQLiteDatabase': { const { migrate } = await import('./op-sqlite/migrator'); - return migrate(rest[0], rest[1] as OPSQLiteMigrationConfig); + return migrate(db, config as OPSQLiteMigrationConfig); } - case 'pg-proxy': { + case 'PgRemoteDatabase': { const { migrate } = await import('./pg-proxy/migrator'); - return migrate(rest[0], rest[1] as PgProxyMigrator, rest[2] as string | MigrationConfig); + return migrate(db, config as PgProxyMigrator, extraConfig as string | MigrationConfig); } - case 'pglite': { + case 'PgliteDatabase': { const { migrate } = await import('./pglite/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'planetscale': { + case 'PlanetScaleDatabase': { const { migrate } = await import('./planetscale-serverless/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'postgres-js': { + case 'PostgresJsDatabase': { const { migrate } = await import('./postgres-js/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'sqlite-proxy': { + case 'SqliteRemoteDatabase': { const { migrate } = await import('./sqlite-proxy/migrator'); - return migrate(rest[0], rest[1] as SQLiteProxyMigrator, rest[2] as string | MigrationConfig); + return migrate(db, config as SQLiteProxyMigrator, extraConfig as string | MigrationConfig); } - case 'tidb-serverless': { + case 'TiDBServerlessDatabase': { const { migrate } = await import('./tidb-serverless/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'vercel-postgres': { + case 'VercelPgDatabase': { const { migrate } = await import('./vercel-postgres/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'xata-http': { + case 'XataHttpDatabase': { const { migrate } = await import('./xata-http/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } } } diff --git a/drizzle-orm/src/mysql-proxy/driver.ts b/drizzle-orm/src/mysql-proxy/driver.ts index 574db42c15..dfbf69cc9f 100644 --- a/drizzle-orm/src/mysql-proxy/driver.ts +++ b/drizzle-orm/src/mysql-proxy/driver.ts @@ -1,3 +1,4 @@ +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; import { MySqlDialect } from '~/mysql-core/dialect.ts'; @@ -10,9 +11,11 @@ import { import type { DrizzleConfig } from '~/utils.ts'; import { type MySqlRemotePreparedQueryHKT, type MySqlRemoteQueryResultHKT, MySqlRemoteSession } from './session.ts'; -export type MySqlRemoteDatabase< +export class MySqlRemoteDatabase< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'MySqlRemoteDatabase'; +} export type RemoteCallback = ( sql: string, @@ -46,5 +49,5 @@ export function drizzle = Record; + return new MySqlRemoteDatabase(dialect, session, schema as any, 'default') as MySqlRemoteDatabase; } diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 8a15dd678e..7f42cfeb3d 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -43,9 +43,11 @@ export class NeonDriver { } } -export type NeonDatabase< +export class NeonDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'NeonServerlessDatabase'; +} export function drizzle = Record>( client: NeonClient, @@ -74,5 +76,5 @@ export function drizzle = Record; + return new NeonDatabase(dialect, session, schema as any) as NeonDatabase; } diff --git a/drizzle-orm/src/op-sqlite/driver.ts b/drizzle-orm/src/op-sqlite/driver.ts index 24c663abf9..94ee6e866a 100644 --- a/drizzle-orm/src/op-sqlite/driver.ts +++ b/drizzle-orm/src/op-sqlite/driver.ts @@ -1,4 +1,5 @@ import type { OPSQLiteConnection, QueryResult } from '@op-engineering/op-sqlite'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -11,9 +12,11 @@ import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { OPSQLiteSession } from './session.ts'; -export type OPSQLiteDatabase< +export class OPSQLiteDatabase< TSchema extends Record = Record, -> = BaseSQLiteDatabase<'async', QueryResult, TSchema>; +> extends BaseSQLiteDatabase<'async', QueryResult, TSchema> { + static readonly [entityKind]: string = 'OPSQLiteDatabase'; +} export function drizzle = Record>( client: OPSQLiteConnection, @@ -41,5 +44,5 @@ export function drizzle = Record; + return new OPSQLiteDatabase('async', dialect, session, schema) as OPSQLiteDatabase; } diff --git a/drizzle-orm/src/pg-proxy/driver.ts b/drizzle-orm/src/pg-proxy/driver.ts index cdffa15c13..d82e869620 100644 --- a/drizzle-orm/src/pg-proxy/driver.ts +++ b/drizzle-orm/src/pg-proxy/driver.ts @@ -1,3 +1,4 @@ +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; @@ -10,9 +11,11 @@ import { import type { DrizzleConfig } from '~/utils.ts'; import { type PgRemoteQueryResultHKT, PgRemoteSession } from './session.ts'; -export type PgRemoteDatabase< +export class PgRemoteDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'PgRemoteDatabase'; +} export type RemoteCallback = ( sql: string, @@ -48,5 +51,5 @@ export function drizzle = Record; + return new PgRemoteDatabase(dialect, session, schema as any) as PgRemoteDatabase; } diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index 7de2ce110d..a801005d8a 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -34,9 +34,11 @@ export class PgliteDriver { } } -export type PgliteDatabase< +export class PgliteDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'PgliteDatabase'; +} export function drizzle = Record>( client: PgliteClient, @@ -65,5 +67,5 @@ export function drizzle = Record; + return new PgliteDatabase(dialect, session, schema as any) as PgliteDatabase; } diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index b1d2d6e6f1..fd1327bbce 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -1,5 +1,6 @@ import type { Connection } from '@planetscale/database'; import { Client } from '@planetscale/database'; +import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; @@ -18,9 +19,11 @@ export interface PlanetscaleSDriverOptions { logger?: Logger; } -export type PlanetScaleDatabase< +export class PlanetScaleDatabase< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'PlanetScaleDatabase'; +} export function drizzle = Record>( client: Client | Connection, @@ -82,5 +85,5 @@ Starting from version 0.30.0, you will encounter an error if you attempt to use } const session = new PlanetscaleSession(client, dialect, undefined, schema, { logger }); - return new MySqlDatabase(dialect, session, schema, 'planetscale') as PlanetScaleDatabase; + return new PlanetScaleDatabase(dialect, session, schema as any, 'planetscale') as PlanetScaleDatabase; } diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 7f44344e86..6714cff8dc 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -1,4 +1,5 @@ import type { Sql } from 'postgres'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; @@ -12,9 +13,11 @@ import type { DrizzleConfig } from '~/utils.ts'; import type { PostgresJsQueryResultHKT } from './session.ts'; import { PostgresJsSession } from './session.ts'; -export type PostgresJsDatabase< +export class PostgresJsDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'PostgresJsDatabase'; +} export function drizzle = Record>( client: Sql, @@ -52,5 +55,5 @@ export function drizzle = Record; + return new PostgresJsDatabase(dialect, session, schema as any) as PostgresJsDatabase; } diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index bdd5324db8..b762bd889b 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -1,4 +1,5 @@ import type { Connection } from '@tidbcloud/serverless'; +import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; @@ -17,9 +18,11 @@ export interface TiDBServerlessSDriverOptions { logger?: Logger; } -export type TiDBServerlessDatabase< +export class TiDBServerlessDatabase< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'TiDBServerlessDatabase'; +} export function drizzle = Record>( client: Connection, @@ -47,5 +50,5 @@ export function drizzle = Record; + return new TiDBServerlessDatabase(dialect, session, schema as any, 'default') as TiDBServerlessDatabase; } diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 07e73c732c..bc990d0b34 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -42,9 +42,11 @@ export class VercelPgDriver { } } -export type VercelPgDatabase< +export class VercelPgDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'VercelPgDatabase'; +} export function drizzle = Record>( client: VercelPgClient, @@ -73,5 +75,5 @@ export function drizzle = Record; + return new VercelPgDatabase(dialect, session, schema as any) as VercelPgDatabase; } From 79b2dd953a09fff89280f7a7f0aef21f331aaeb7 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 3 Sep 2024 12:51:09 +0300 Subject: [PATCH 127/152] Fixed overload order for better autocomplete --- drizzle-orm/src/monodriver.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 41bb202e89..0eb2214ee0 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -168,6 +168,14 @@ const removeKey = , TKey extends keyof TReco return obj; }; +export async function drizzle = Record>( + client: 'aws-data-api-pg', + params: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, +): Promise>; +export async function drizzle = Record>( + client: 'mysql2', + params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, +): Promise>; export async function drizzle = Record>( client: 'node-postgres', params: { connection: NodePGPoolConfig } & DrizzleConfig, @@ -188,18 +196,10 @@ export async function drizzle = Record, ): Promise>; -export async function drizzle = Record>( - client: 'aws-data-api-pg', - params?: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, -): Promise>; export async function drizzle = Record>( client: 'planetscale', params: { connection: PlanetscaleConfig } & DrizzleConfig, ): Promise>; -export async function drizzle = Record>( - client: 'mysql2', - params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, -): Promise>; export async function drizzle = Record>( client: 'tidb-serverless', params: { connection: TiDBServerlessConfig } & DrizzleConfig, @@ -346,3 +346,9 @@ export async function drizzle< } } } + +const db = await drizzle('aws-data-api-pg', { + database: '', + resourceArn: '', + secretArn: '', +}); From 977fdd241d3dedf34c48f2c0262d6a9f6d470a6d Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 3 Sep 2024 12:51:30 +0300 Subject: [PATCH 128/152] Removed garbage --- drizzle-orm/src/monodriver.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 0eb2214ee0..05c676157a 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -346,9 +346,3 @@ export async function drizzle< } } } - -const db = await drizzle('aws-data-api-pg', { - database: '', - resourceArn: '', - secretArn: '', -}); From 3430e1c5a502191869e5925b37a9b48fcd7af60f Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 3 Sep 2024 15:37:53 +0300 Subject: [PATCH 129/152] Added missing postgres.js to monomigrator --- drizzle-orm/src/monomigrator.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index eec37bbdf1..1fc9dbc71c 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -18,6 +18,7 @@ import type { PgRemoteDatabase } from './pg-proxy/index.ts'; import type { ProxyMigrator as PgProxyMigrator } from './pg-proxy/migrator.ts'; import type { PgliteDatabase } from './pglite/index.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; +import type { PostgresJsDatabase } from './postgres-js/driver.ts'; import type { ProxyMigrator as SQLiteProxyMigrator } from './sqlite-proxy/migrator.ts'; import type { VercelPgDatabase } from './vercel-postgres/index.ts'; import type { XataHttpDatabase } from './xata-http/index.ts'; @@ -83,6 +84,7 @@ export async function migrate( config: string | MigrationConfig, ): Promise; export async function migrate(db: PgliteDatabase, config: string | MigrationConfig): Promise; +export async function migrate(db: PostgresJsDatabase, config: string | MigrationConfig): Promise; export async function migrate( db: PlanetScaleDatabase, config: MigrationConfig, From 56f7b1663470fa341f17b088d1f25b0a99c9c62f Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 3 Sep 2024 15:54:02 +0300 Subject: [PATCH 130/152] Fixed missing defaults in templates --- drizzle-orm/src/better-sqlite3/driver.ts | 2 +- drizzle-orm/src/expo-sqlite/driver.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 8d19cd8ab2..8fe7c00fbe 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -12,7 +12,7 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; -export class BetterSQLite3Database> +export class BetterSQLite3Database = Record> extends BaseSQLiteDatabase<'sync', RunResult, TSchema> { static readonly [entityKind]: string = 'BetterSQLite3Database'; diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index 51cb1a2042..fb858e482c 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -12,7 +12,7 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { ExpoSQLiteSession } from './session.ts'; -export class ExpoSQLiteDatabase> +export class ExpoSQLiteDatabase = Record> extends BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema> { static readonly [entityKind]: string = 'ExpoSQLiteDatabase'; From 091a8f4eeddc4707145ed731fa87ed271ffdeb78 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 13:00:44 +0300 Subject: [PATCH 131/152] Improved types, matched supported instances of monodriver and monomigrator, fixed pg withReplicas type's schema inferrence, fixed lack of [entityKind] on some instances, fixed migrators not accepting string as a config --- drizzle-orm/src/libsql/migrator.ts | 2 +- drizzle-orm/src/monodriver.ts | 134 ++++-------- drizzle-orm/src/monomigrator.ts | 190 +++--------------- drizzle-orm/src/mysql2/driver.ts | 8 +- drizzle-orm/src/mysql2/migrator.ts | 11 +- drizzle-orm/src/node-postgres/driver.ts | 8 +- drizzle-orm/src/pg-core/db.ts | 6 +- .../src/planetscale-serverless/migrator.ts | 11 +- 8 files changed, 110 insertions(+), 260 deletions(-) diff --git a/drizzle-orm/src/libsql/migrator.ts b/drizzle-orm/src/libsql/migrator.ts index aa262bc2dc..d362a2e4da 100644 --- a/drizzle-orm/src/libsql/migrator.ts +++ b/drizzle-orm/src/libsql/migrator.ts @@ -5,7 +5,7 @@ import type { LibSQLDatabase } from './driver.ts'; export async function migrate>( db: LibSQLDatabase, - config: MigrationConfig, + config: MigrationConfig | string, ) { const migrations = readMigrationFiles(config); const migrationsTable = config === undefined diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 05c676157a..d2b86848b1 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -71,7 +71,7 @@ type MonodriverNeonHttpConfig = { options?: NeonHttpConfig; }; -type DatabaseVendor = +type DatabaseClient = | 'node-postgres' | 'postgres-js' | 'neon-serverless' @@ -102,51 +102,50 @@ type ClientDrizzleInstanceMap> = { 'better-sqlite3': BetterSQLite3Database; }; -type InitializerParams< - TSchema extends Record = Record, -> = - | ({ +type InitializerParams = { + 'node-postgres': { connection: NodePGPoolConfig; - } & DrizzleConfig) - | ({ - connection: PostgresJSOptions>; - } & DrizzleConfig) - | ({ + }; + 'postgres-js': { + connection: string | PostgresJSOptions>; + }; + 'neon-serverless': { connection: NeonServerlessConfig; - } & DrizzleConfig) - | ({ + }; + 'neon-http': { connection: MonodriverNeonHttpConfig; - } & DrizzleConfig) - | ({ + }; + 'vercel-postgres': { connection: VercelPool; - } & DrizzleConfig) - | ({ - connection: RDSConfig; - } & DrizzleAwsDataApiPgConfig) - | ({ + }; + 'aws-data-api-pg': { + connection?: RDSConfig; + }; + planetscale: { connection: PlanetscaleConfig; - } & DrizzleConfig) - | ({ - connection: Mysql2Config; - } & MySql2DrizzleConfig) - | ({ + }; + mysql2: { + connection: Mysql2Config | string; + }; + 'tidb-serverless': { connection: TiDBServerlessConfig; - } & DrizzleConfig) - | ({ + }; + libsql: { connection: LibsqlConfig; - } & DrizzleConfig) - | ({ + }; + d1: { connection: D1Database; - } & DrizzleConfig) - | ({ + }; + 'bun:sqlite': { connection?: BunSqliteDatabaseConfig; - } & DrizzleConfig) - | ({ + }; + 'better-sqlite3': { connection?: BetterSQLite3DatabaseConfig; - } & DrizzleConfig); + }; +}; type DetermineClient< - TVendor extends DatabaseVendor, + TVendor extends DatabaseClient, TSchema extends Record, > = ClientDrizzleInstanceMap< TSchema @@ -167,64 +166,17 @@ const removeKey = , TKey extends keyof TReco delete ( obj).key; return obj; }; - -export async function drizzle = Record>( - client: 'aws-data-api-pg', - params: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, -): Promise>; -export async function drizzle = Record>( - client: 'mysql2', - params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'node-postgres', - params: { connection: NodePGPoolConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'postgres-js', - params: { connection: string | PostgresJSOptions> } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'neon-serverless', - params: { connection: NeonServerlessConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'neon-http', - params: { connection: MonodriverNeonHttpConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'vercel-postgres', - params: { connection: VercelPool } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'planetscale', - params: { connection: PlanetscaleConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'tidb-serverless', - params: { connection: TiDBServerlessConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'libsql', - params: { connection: LibsqlConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'd1', - params: { connection: D1Database } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'bun:sqlite', - params?: { connection?: BunSqliteDatabaseConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'better-sqlite3', - params?: { connection?: BetterSQLite3DatabaseConfig } & DrizzleConfig, -): Promise>; export async function drizzle< - TVendor extends DatabaseVendor, - TSchema extends Record, - TParams extends InitializerParams, ->(client: TVendor, params?: TParams): Promise> { + TClient extends DatabaseClient, + TSchema extends Record = Record, +>( + client: TClient, + params: + & InitializerParams[TClient] + & (TClient extends 'mysql2' ? MySql2DrizzleConfig + : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig + : DrizzleConfig), +): Promise> { const connection = params?.connection; const drizzleConfig = params ? removeKey(params, 'connection') : undefined; diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index 1fc9dbc71c..aa590c8d77 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -4,225 +4,101 @@ import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; import { entityKind } from './entity.ts'; -import type { ExpoSQLiteDatabase } from './expo-sqlite/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; import type { MigrationConfig } from './migrator.ts'; -import type { MySqlRemoteDatabase } from './mysql-proxy/index.ts'; -import type { ProxyMigrator as MySqlProxyMigrator } from './mysql-proxy/migrator.ts'; import type { MySql2Database } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/index.ts'; -import type { OPSQLiteDatabase } from './op-sqlite/index.ts'; -import type { PgRemoteDatabase } from './pg-proxy/index.ts'; -import type { ProxyMigrator as PgProxyMigrator } from './pg-proxy/migrator.ts'; -import type { PgliteDatabase } from './pglite/index.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; -import type { PostgresJsDatabase } from './postgres-js/driver.ts'; -import type { ProxyMigrator as SQLiteProxyMigrator } from './sqlite-proxy/migrator.ts'; +import type { PostgresJsDatabase } from './postgres-js/index.ts'; +import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; import type { VercelPgDatabase } from './vercel-postgres/index.ts'; -import type { XataHttpDatabase } from './xata-http/index.ts'; -import type { MigrationConfig as XataHttpMigrationConfig } from './xata-http/migrator.ts'; -type OPSQLiteMigrationConfig = { - journal: { - entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; - }; - migrations: Record; -}; - -type ExpoSQLiteMigrationConfig = { - journal: { - entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; - }; - migrations: Record; -}; - -export async function migrate( - db: AwsDataApiPgDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: BetterSQLite3Database, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: BunSQLiteDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate(db: DrizzleD1Database, config: string | MigrationConfig): Promise; -export async function migrate( - db: ExpoSQLiteDatabase, - config: ExpoSQLiteMigrationConfig, -): Promise; -export async function migrate(db: LibSQLDatabase, config: MigrationConfig): Promise; -export async function migrate( - db: MySqlRemoteDatabase, - callback: MySqlProxyMigrator, - config: MigrationConfig, -): Promise; -export async function migrate(db: MySql2Database, config: MigrationConfig): Promise; -export async function migrate( - db: NeonHttpDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: NeonDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: NodePgDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: OPSQLiteDatabase, - config: OPSQLiteMigrationConfig, -): Promise; -export async function migrate( - db: PgRemoteDatabase, - callback: PgProxyMigrator, - config: string | MigrationConfig, -): Promise; -export async function migrate(db: PgliteDatabase, config: string | MigrationConfig): Promise; -export async function migrate(db: PostgresJsDatabase, config: string | MigrationConfig): Promise; -export async function migrate( - db: PlanetScaleDatabase, - config: MigrationConfig, -): Promise; -export async function migrate( - db: PlanetScaleDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: PgRemoteDatabase, - callback: SQLiteProxyMigrator, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: PlanetScaleDatabase, - config: MigrationConfig, -): Promise; export async function migrate( - db: VercelPgDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: XataHttpDatabase, - config: string | XataHttpMigrationConfig, -): Promise; -export async function migrate( - db: any, + db: + | AwsDataApiPgDatabase + | BetterSQLite3Database + | BunSQLiteDatabase + | DrizzleD1Database + | LibSQLDatabase + | MySql2Database + | NeonHttpDatabase + | NeonDatabase + | NodePgDatabase + | PlanetScaleDatabase + | PostgresJsDatabase + | VercelPgDatabase + | TiDBServerlessDatabase, config: | string - | MigrationConfig - | ExpoSQLiteMigrationConfig - | OPSQLiteMigrationConfig - | XataHttpMigrationConfig - | PgProxyMigrator - | MySqlProxyMigrator - | SQLiteProxyMigrator, - extraConfig?: string | MigrationConfig | undefined, + | MigrationConfig, ) { - switch (db[entityKind]) { + switch (( db)[entityKind]) { case 'AwsDataApiPgDatabase': { const { migrate } = await import('./aws-data-api/pg/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as AwsDataApiPgDatabase, config as string | MigrationConfig); } case 'BetterSQLite3Database': { const { migrate } = await import('./better-sqlite3/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as BetterSQLite3Database, config as string | MigrationConfig); } case 'BunSQLiteDatabase': { const { migrate } = await import('./bun-sqlite/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as BunSQLiteDatabase, config as string | MigrationConfig); } case 'D1Database': { const { migrate } = await import('./d1/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'ExpoSQLiteDatabase': { - const { migrate } = await import('./expo-sqlite/migrator'); - - return migrate(db, config as ExpoSQLiteMigrationConfig); + return migrate(db as DrizzleD1Database, config as string | MigrationConfig); } case 'LibSQLDatabase': { const { migrate } = await import('./libsql/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as LibSQLDatabase, config as string | MigrationConfig); } - case 'MySqlRemoteDatabase': { - const { migrate } = await import('./mysql-proxy/migrator'); - - return migrate(db, config as MySqlProxyMigrator, extraConfig as MigrationConfig); - } - case 'MySql2Driver': { + case 'MySql2Database': { const { migrate } = await import('./mysql2/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as MySql2Database, config as string | MigrationConfig); } case 'NeonHttpDatabase': { const { migrate } = await import('./neon-http/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as NeonHttpDatabase, config as string | MigrationConfig); } case 'NeonServerlessDatabase': { const { migrate } = await import('./neon-serverless/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as NeonDatabase, config as string | MigrationConfig); } - case 'NodePgDriver': { + case 'NodePgDatabase': { const { migrate } = await import('./node-postgres/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'OPSQLiteDatabase': { - const { migrate } = await import('./op-sqlite/migrator'); - - return migrate(db, config as OPSQLiteMigrationConfig); - } - case 'PgRemoteDatabase': { - const { migrate } = await import('./pg-proxy/migrator'); - - return migrate(db, config as PgProxyMigrator, extraConfig as string | MigrationConfig); - } - case 'PgliteDatabase': { - const { migrate } = await import('./pglite/migrator'); - - return migrate(db, config as string | MigrationConfig); + return migrate(db as NodePgDatabase, config as string | MigrationConfig); } case 'PlanetScaleDatabase': { const { migrate } = await import('./planetscale-serverless/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as PlanetScaleDatabase, config as string | MigrationConfig); } case 'PostgresJsDatabase': { const { migrate } = await import('./postgres-js/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'SqliteRemoteDatabase': { - const { migrate } = await import('./sqlite-proxy/migrator'); - - return migrate(db, config as SQLiteProxyMigrator, extraConfig as string | MigrationConfig); + return migrate(db as PostgresJsDatabase, config as string | MigrationConfig); } case 'TiDBServerlessDatabase': { const { migrate } = await import('./tidb-serverless/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as TiDBServerlessDatabase, config as MigrationConfig); } case 'VercelPgDatabase': { const { migrate } = await import('./vercel-postgres/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'XataHttpDatabase': { - const { migrate } = await import('./xata-http/migrator'); - - return migrate(db, config as string | MigrationConfig); + return migrate(db as VercelPgDatabase, config as string | MigrationConfig); } } } diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 3b21bf11dd..a8fb65c3b9 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -40,9 +40,11 @@ export class MySql2Driver { export { MySqlDatabase } from '~/mysql-core/db.ts'; -export type MySql2Database< +export class MySql2Database< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'MySql2Database'; +} export type MySql2DrizzleConfig = Record> = & Omit, 'schema'> @@ -87,7 +89,7 @@ export function drizzle = Record; + return new MySql2Database(dialect, session, schema as any, mode) as MySql2Database; } interface CallbackClient { diff --git a/drizzle-orm/src/mysql2/migrator.ts b/drizzle-orm/src/mysql2/migrator.ts index 2f3c9c3dcf..ae56e01f13 100644 --- a/drizzle-orm/src/mysql2/migrator.ts +++ b/drizzle-orm/src/mysql2/migrator.ts @@ -4,8 +4,15 @@ import type { MySql2Database } from './driver.ts'; export async function migrate>( db: MySql2Database, - config: MigrationConfig, + config: MigrationConfig | string, ) { const migrations = readMigrationFiles(config); - await db.dialect.migrate(migrations, db.session, config); + + const preparedConfig = typeof config === 'string' + ? { + migrationsFolder: config, + } + : config; + + await db.dialect.migrate(migrations, db.session, preparedConfig); } diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 4c233f8915..15ac8fc067 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -45,9 +45,11 @@ export class NodePgDriver { } } -export type NodePgDatabase< +export class NodePgDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'NodePgDatabase'; +} export function drizzle = Record>( client: NodePgClient, @@ -76,5 +78,5 @@ export function drizzle = Record; + return new NodePgDatabase(dialect, session, schema as any) as NodePgDatabase; } diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 3c8da44f15..85dc797c91 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -631,7 +631,11 @@ export const withReplicas = < HKT extends PgQueryResultHKT, TFullSchema extends Record, TSchema extends TablesRelationalConfig, - Q extends PgDatabase, + Q extends PgDatabase< + HKT, + TFullSchema, + TSchema extends Record ? ExtractTablesWithRelations : TSchema + >, >( primary: Q, replicas: [Q, ...Q[]], diff --git a/drizzle-orm/src/planetscale-serverless/migrator.ts b/drizzle-orm/src/planetscale-serverless/migrator.ts index 5a668ae012..8b37136020 100644 --- a/drizzle-orm/src/planetscale-serverless/migrator.ts +++ b/drizzle-orm/src/planetscale-serverless/migrator.ts @@ -4,8 +4,15 @@ import type { PlanetScaleDatabase } from './driver.ts'; export async function migrate>( db: PlanetScaleDatabase, - config: MigrationConfig, + config: MigrationConfig | string, ) { const migrations = readMigrationFiles(config); - await db.dialect.migrate(migrations, db.session, config); + + const preparedConfig = typeof config === 'string' + ? { + migrationsFolder: config, + } + : config; + + await db.dialect.migrate(migrations, db.session, preparedConfig); } From 9af5fece91fc3ce5a3ed04427e3b6b99f67a1590 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 13:10:27 +0300 Subject: [PATCH 132/152] Fixed invalid [entityKind] call --- drizzle-orm/src/monomigrator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index aa590c8d77..bee18ad461 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -34,7 +34,7 @@ export async function migrate( | string | MigrationConfig, ) { - switch (( db)[entityKind]) { + switch (( db).constructor[entityKind]) { case 'AwsDataApiPgDatabase': { const { migrate } = await import('./aws-data-api/pg/migrator'); From ca04053a4a6ab8dee378fdd9e5543fe38d09bbba Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 13:31:23 +0300 Subject: [PATCH 133/152] Added `:memory:` autocomplete --- drizzle-orm/src/monodriver.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index d2b86848b1..d7955a585b 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -52,18 +52,23 @@ type BunSqliteDatabaseOptions = type BunSqliteDatabaseConfig = | { - filename?: string; + filename?: ':memory:' | (string & {}); options?: BunSqliteDatabaseOptions; } - | string + | ':memory:' + | (string & {}) | undefined; type BetterSQLite3DatabaseConfig = | { - filename?: string | Buffer; + filename?: + | ':memory:' + | (string & {}) + | Buffer; options?: BetterSQLite3Options; } - | string + | ':memory:' + | (string & {}) | undefined; type MonodriverNeonHttpConfig = { From 1e1d8aec69610147aaac25997d7612a7173bc165 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 14:11:25 +0300 Subject: [PATCH 134/152] Removed leftover code from overloads, added `assertUnreachable` --- drizzle-orm/src/monodriver.ts | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index d7955a585b..eb259e028e 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -162,15 +162,10 @@ const importError = (libName: string) => { ); }; -const removeKey = , TKey extends keyof TRecord>( - obj: TRecord, - key: TKey, -): Omit => { - if (!(key in obj)) return obj; - - delete ( obj).key; - return obj; -}; +function assertUnreachable(_: never | undefined): never { + throw new Error("Didn't expect to get here"); +} + export async function drizzle< TClient extends DatabaseClient, TSchema extends Record = Record, @@ -182,8 +177,7 @@ export async function drizzle< : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig : DrizzleConfig), ): Promise> { - const connection = params?.connection; - const drizzleConfig = params ? removeKey(params, 'connection') : undefined; + const { connection, ...drizzleConfig } = params; switch (client) { case 'node-postgres': { @@ -296,10 +290,7 @@ export async function drizzle< return drizzle(sql, drizzleConfig) as any; } - default: { - throw new Error( - `Unsupported vendor for Drizzle ORM monodriver: '${client}'. Use dedicated drizzle initializer instead.`, - ); - } } + + assertUnreachable(client); } From 1de8bf8b2ec7871dde6fb274e24b4035c5358a8b Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 15:39:49 +0300 Subject: [PATCH 135/152] Exposed db drivers from monodriver --- drizzle-orm/src/monodriver.ts | 144 ++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 32 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index eb259e028e..47e1881e13 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,19 +1,26 @@ /* eslint-disable import/extensions */ -import type { RDSDataClientConfig, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; -import type { Config as LibsqlConfig } from '@libsql/client'; +import type { RDSDataClient, RDSDataClientConfig, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { Client as LibsqlClient, Config as LibsqlConfig } from '@libsql/client'; import type { HTTPTransactionOptions as NeonHttpConfig, + NeonQueryFunction, + Pool as NeonServerlessPool, PoolConfig as NeonServerlessConfig, } from '@neondatabase/serverless'; -import type { Config as PlanetscaleConfig } from '@planetscale/database'; -import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; -import type { VercelPool } from '@vercel/postgres'; -import type { Options as BetterSQLite3Options } from 'better-sqlite3'; -import type { PoolOptions as Mysql2Config } from 'mysql2'; -import type { PoolConfig as NodePGPoolConfig } from 'pg'; -import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; +import type { Client as PlanetscaleClient, Config as PlanetscaleConfig } from '@planetscale/database'; +import type { Config as TiDBServerlessConfig, Connection as TiDBConnection } from '@tidbcloud/serverless'; +import type { QueryResult, QueryResultRow, VercelPool } from '@vercel/postgres'; +import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; +import type { Database as BunDatabase } from 'bun:sqlite'; +import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; +import type { Pool as NodePgPool, PoolConfig as NodePGPoolConfig } from 'pg'; +import type { + Options as PostgresJSOptions, + PostgresType as PostgresJSPostgresType, + Sql as PostgresJsClient, +} from 'postgres'; import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; -import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; +import type { BetterSQLite3Database as DrizzleBetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; @@ -76,6 +83,8 @@ type MonodriverNeonHttpConfig = { options?: NeonHttpConfig; }; +type VercelPrimitive = string | number | boolean | undefined | null; + type DatabaseClient = | 'node-postgres' | 'postgres-js' @@ -104,7 +113,28 @@ type ClientDrizzleInstanceMap> = { libsql: LibSQLDatabase; d1: DrizzleD1Database; 'bun:sqlite': BunSQLiteDatabase; - 'better-sqlite3': BetterSQLite3Database; + 'better-sqlite3': DrizzleBetterSQLite3Database; +}; + +type ClientInstanceMap = { + 'node-postgres': NodePgPool; + 'postgres-js': PostgresJsClient; + 'neon-serverless': NeonServerlessPool; + 'neon-http': NeonQueryFunction; + 'vercel-postgres': + & VercelPool + & (( + strings: TemplateStringsArray, + ...values: VercelPrimitive[] + ) => Promise>); + 'aws-data-api-pg': RDSDataClient; + planetscale: PlanetscaleClient; + mysql2: Mysql2Pool; + 'tidb-serverless': TiDBConnection; + libsql: LibsqlClient; + d1: D1Database; + 'bun:sqlite': BunDatabase; + 'better-sqlite3': BetterSQLite3Database; }; type InitializerParams = { @@ -150,11 +180,15 @@ type InitializerParams = { }; type DetermineClient< - TVendor extends DatabaseClient, + TClient extends DatabaseClient, TSchema extends Record, -> = ClientDrizzleInstanceMap< - TSchema ->[TVendor]; +> = + & ClientDrizzleInstanceMap< + TSchema + >[TClient] + & { + $client: ClientInstanceMap[TClient]; + }; const importError = (libName: string) => { throw new Error( @@ -185,7 +219,10 @@ export async function drizzle< const { drizzle } = await import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'aws-data-api-pg': { const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => @@ -194,7 +231,10 @@ export async function drizzle< const { drizzle } = await import('./aws-data-api/pg'); const instance = new RDSDataClient(connection as RDSDataClientConfig); - return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + const db = drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + db.$client = instance; + + return db; } case 'better-sqlite3': { const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); @@ -205,12 +245,18 @@ export async function drizzle< const instance = new Client(filename, options); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } const instance = new Client(connection); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'bun:sqlite': { const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); @@ -221,30 +267,46 @@ export async function drizzle< const instance = new Client(filename, options); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } const instance = new Client(connection); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'd1': { const { drizzle } = await import('./d1'); - return drizzle(connection as D1Database, drizzleConfig) as any; + + const db = drizzle(connection as D1Database, drizzleConfig) as any; + db.$client = connection; + + return db; } case 'libsql': { const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); const { drizzle } = await import('./libsql'); const instance = createClient(connection as LibsqlConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'mysql2': { - const { createConnection } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); - const instance = await createConnection(connection as Mysql2Config); + const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); + const instance = createPool(connection as Mysql2Config); const { drizzle } = await import('./mysql2'); - return drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; + const db = drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; + db.$client = instance; + + return db; } case 'neon-http': { const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); @@ -252,14 +314,20 @@ export async function drizzle< const { drizzle } = await import('./neon-http'); const instance = neon(connectionString, options); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'neon-serverless': { const { Pool } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'planetscale': { const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); @@ -268,27 +336,39 @@ export async function drizzle< connection as PlanetscaleConfig, ); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'postgres-js': { const { default: client } = await import('postgres').catch(() => importError('postgres')); const { drizzle } = await import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'tidb-serverless': { const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); const { drizzle } = await import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'vercel-postgres': { const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); const { drizzle } = await import('./vercel-postgres'); - return drizzle(sql, drizzleConfig) as any; + const db = drizzle(sql, drizzleConfig) as any; + db.$client = sql; + + return db; } } From 0f81774950ce1548c16ac0e9ddb2be3127ddbddb Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 16:50:20 +0300 Subject: [PATCH 136/152] Fixed test tables using already existing names --- integration-tests/tests/mysql/mysql-common.ts | 12 ++++++------ integration-tests/tests/pg/pg-common.ts | 12 ++++++------ integration-tests/tests/sqlite/sqlite-common.ts | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 05c69cadae..7a02a251d0 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3581,7 +3581,7 @@ export function tests(driver?: string) { test('$count separate', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3606,7 +3606,7 @@ export function tests(driver?: string) { test('$count embedded', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3638,7 +3638,7 @@ export function tests(driver?: string) { test('$count separate reuse', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3675,7 +3675,7 @@ export function tests(driver?: string) { test('$count embedded reuse', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3734,7 +3734,7 @@ export function tests(driver?: string) { test('$count separate with filters', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3759,7 +3759,7 @@ export function tests(driver?: string) { test('$count embedded with filters', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 3f3dd75cce..384c3dab38 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4664,7 +4664,7 @@ export function tests() { test('$count separate', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4689,7 +4689,7 @@ export function tests() { test('$count embedded', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4721,7 +4721,7 @@ export function tests() { test('$count separate reuse', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4758,7 +4758,7 @@ export function tests() { test('$count embedded reuse', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4817,7 +4817,7 @@ export function tests() { test('$count separate with filters', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4842,7 +4842,7 @@ export function tests() { test('$count embedded with filters', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index ed13f5b7b1..5711b5d1d7 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2683,7 +2683,7 @@ export function tests() { test('$count separate', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2708,7 +2708,7 @@ export function tests() { test('$count embedded', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2740,7 +2740,7 @@ export function tests() { test('$count separate reuse', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2777,7 +2777,7 @@ export function tests() { test('$count embedded reuse', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2836,7 +2836,7 @@ export function tests() { test('$count separate with filters', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2861,7 +2861,7 @@ export function tests() { test('$count embedded with filters', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); From f0275007cd028ed8870b08fa9016cc1a38e75671 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 17:52:29 +0300 Subject: [PATCH 137/152] Fixed faulty test cases; Fixed lack of count type conversion in mysql; added all method functionality to pg proxy driver; added websocket instance to monodriver neon serverless config --- drizzle-orm/src/monodriver.ts | 15 +++++++++++++-- .../src/mysql-core/query-builders/count.ts | 6 ++++-- drizzle-orm/src/pg-proxy/session.ts | 4 +++- integration-tests/tests/mysql/mysql-common.ts | 3 +-- integration-tests/tests/pg/pg-common.ts | 3 +-- integration-tests/tests/sqlite/sqlite-common.ts | 3 +-- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 47e1881e13..0706f271a7 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -209,9 +209,14 @@ export async function drizzle< & InitializerParams[TClient] & (TClient extends 'mysql2' ? MySql2DrizzleConfig : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig + : TClient extends 'neon-serverless' ? DrizzleConfig & { + ws?: any; + } : DrizzleConfig), ): Promise> { - const { connection, ...drizzleConfig } = params; + const { connection, ws, ...drizzleConfig } = params as typeof params & { + ws?: any; + }; switch (client) { case 'node-postgres': { @@ -320,10 +325,16 @@ export async function drizzle< return db; } case 'neon-serverless': { - const { Pool } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); + const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => + importError('@neondatabase/serverless') + ); const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); + if (ws) { + neonConfig.webSocketConstructor = ws; + } + const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 751ba61c72..b69d927771 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -27,7 +27,9 @@ export class MySqlCountBuilder< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; + return sql`select cast(count(*) as UNSIGNED) as count from ${source}${ + sql.raw(' where ').if(filters) + }${filters}`; } constructor( @@ -53,7 +55,7 @@ export class MySqlCountBuilder< onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { return Promise.resolve(this.session.all(this.sql)).then((it) => { - return (<[{ 'count(*)': number }]> it)[0]['count(*)']; + return (<[{ count: number }]> it)[0]['count']; }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-proxy/session.ts b/drizzle-orm/src/pg-proxy/session.ts index eb6a1b1a31..b5adad36c3 100644 --- a/drizzle-orm/src/pg-proxy/session.ts +++ b/drizzle-orm/src/pg-proxy/session.ts @@ -130,7 +130,9 @@ export class PreparedQuery extends PreparedQueryB }); } - async all() {} + async all() { + return this.execute(); + } /** @internal */ isResponseInArrayMode(): boolean { diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 7a02a251d0..7224b06f4d 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3706,8 +3706,6 @@ export function tests(driver?: string) { await db.execute(sql`drop table ${countTestTable}`); - await db.execute(sql`drop table ${countTestTable}`); - expect(count1).toStrictEqual([ { count: 4 }, { count: 4 }, @@ -3784,6 +3782,7 @@ export function tests(driver?: string) { { count: 3 }, { count: 3 }, { count: 3 }, + { count: 3 }, ]); }); }); diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 384c3dab38..b4afdcf64b 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4789,8 +4789,6 @@ export function tests() { await db.execute(sql`drop table ${countTestTable}`); - await db.execute(sql`drop table ${countTestTable}`); - expect(count1).toStrictEqual([ { count: 4 }, { count: 4 }, @@ -4867,6 +4865,7 @@ export function tests() { { count: 3 }, { count: 3 }, { count: 3 }, + { count: 3 }, ]); }); }); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 5711b5d1d7..e8ddb86e6e 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2808,8 +2808,6 @@ export function tests() { await db.run(sql`drop table ${countTestTable}`); - await db.run(sql`drop table ${countTestTable}`); - expect(count1).toStrictEqual([ { count: 4 }, { count: 4 }, @@ -2886,6 +2884,7 @@ export function tests() { { count: 3 }, { count: 3 }, { count: 3 }, + { count: 3 }, ]); }); }); From 890375583ec038870e2b6ff79dc6236b9e6dee76 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 18:06:26 +0300 Subject: [PATCH 138/152] Switched mysql count to execute --- drizzle-orm/src/mysql-core/query-builders/count.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index b69d927771..a54a9eaf8c 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -54,7 +54,7 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.all(this.sql)).then((it) => { + return Promise.resolve(this.session.execute(this.sql)).then((it) => { return (<[{ count: number }]> it)[0]['count']; }) .then( From a171311771930fe4cae5578dd7d93174652ef224 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 18:08:50 +0300 Subject: [PATCH 139/152] Added cast to embedded --- drizzle-orm/src/mysql-core/query-builders/count.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index a54a9eaf8c..01f9dfcd0a 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -20,7 +20,7 @@ export class MySqlCountBuilder< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + return sql`(select cast(count(*) as UNSIGNED) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( From 4f9c076e26a383c9e1c6a50eb01292a3007be2c8 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 12:55:11 +0300 Subject: [PATCH 140/152] Switched to `.execute` for mysql, pg; reverted pg proxy session changes; fixed misplaced mysql tests; removed unused args --- drizzle-orm/src/mysql-core/db.ts | 2 +- .../src/mysql-core/query-builders/count.ts | 4 +-- drizzle-orm/src/pg-core/db.ts | 2 +- .../src/pg-core/query-builders/count.ts | 6 ++-- drizzle-orm/src/pg-proxy/session.ts | 1 - drizzle-orm/src/sqlite-core/db.ts | 2 +- .../src/sqlite-core/query-builders/count.ts | 2 -- integration-tests/tests/mysql/mysql-common.ts | 36 +++++++++---------- 8 files changed, 24 insertions(+), 31 deletions(-) diff --git a/drizzle-orm/src/mysql-core/db.ts b/drizzle-orm/src/mysql-core/db.ts index 419359022c..8934c0edf8 100644 --- a/drizzle-orm/src/mysql-core/db.ts +++ b/drizzle-orm/src/mysql-core/db.ts @@ -140,7 +140,7 @@ export class MySqlDatabase< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new MySqlCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + return new MySqlCountBuilder({ source, filters, session: this.session }); } /** diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 01f9dfcd0a..1d5ac2a57a 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -1,7 +1,6 @@ import { entityKind, sql } from '~/index.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; import { SQL } from '~/sql/sql.ts'; -import type { MySqlDialect } from '../dialect.ts'; import type { MySqlSession } from '../session.ts'; import type { MySqlTable } from '../table.ts'; import type { MySqlViewBase } from '../view-base.ts'; @@ -36,7 +35,6 @@ export class MySqlCountBuilder< readonly params: { source: MySqlTable | MySqlViewBase | SQL | SQLWrapper; filters?: SQL; - dialect: MySqlDialect; session: TSession; }, ) { @@ -55,7 +53,7 @@ export class MySqlCountBuilder< onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { return Promise.resolve(this.session.execute(this.sql)).then((it) => { - return (<[{ count: number }]> it)[0]['count']; + return (<[[{ count: number }]]> it)[0][0]['count']; }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 85dc797c91..62b64fb8fd 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -141,7 +141,7 @@ export class PgDatabase< source: PgTable | PgViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new PgCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + return new PgCountBuilder({ source, filters, session: this.session }); } /** diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index 7ccd722a07..cfc4d583b9 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -1,7 +1,6 @@ import { entityKind, sql } from '~/index.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; import { SQL } from '~/sql/sql.ts'; -import type { PgDialect } from '../dialect.ts'; import type { PgSession } from '../session.ts'; import type { PgTable } from '../table.ts'; @@ -26,14 +25,13 @@ export class PgCountBuilder< source: PgTable | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters};`; + return sql`select count(*)::int as count from ${source}${sql.raw(' where ').if(filters)}${filters};`; } constructor( readonly params: { source: PgTable | SQL | SQLWrapper; filters?: SQL; - dialect: PgDialect; session: TSession; }, ) { @@ -51,7 +49,7 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.all(this.sql)).then((it) => { + return Promise.resolve(this.session.execute(this.sql)).then((it) => { return (<[{ count: number }]> it)[0]['count'] as number; }) .then( diff --git a/drizzle-orm/src/pg-proxy/session.ts b/drizzle-orm/src/pg-proxy/session.ts index b5adad36c3..1a30c0a3ce 100644 --- a/drizzle-orm/src/pg-proxy/session.ts +++ b/drizzle-orm/src/pg-proxy/session.ts @@ -131,7 +131,6 @@ export class PreparedQuery extends PreparedQueryB } async all() { - return this.execute(); } /** @internal */ diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 75b088f6de..7ae2736e08 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -140,7 +140,7 @@ export class BaseSQLiteDatabase< source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new SQLiteCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + return new SQLiteCountBuilder({ source, filters, session: this.session }); } /** diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index ed6cd9a1da..f6434ee81b 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -1,7 +1,6 @@ import { entityKind, sql } from '~/index.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; import { SQL } from '~/sql/sql.ts'; -import type { SQLiteDialect } from '../dialect.ts'; import type { SQLiteSession } from '../session.ts'; import type { SQLiteTable } from '../table.ts'; import type { SQLiteView } from '../view.ts'; @@ -34,7 +33,6 @@ export class SQLiteCountBuilder< readonly params: { source: SQLiteTable | SQLiteView | SQL | SQLWrapper; filters?: SQL; - dialect: SQLiteDialect; session: TSession; }, ) { diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 7224b06f4d..8a2fb768b9 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3785,29 +3785,29 @@ export function tests(driver?: string) { { count: 3 }, ]); }); - }); - test('limit 0', async (ctx) => { - const { db } = ctx.mysql; + test('limit 0', async (ctx) => { + const { db } = ctx.mysql; - await db.insert(usersTable).values({ name: 'John' }); - const users = await db - .select() - .from(usersTable) - .limit(0); + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(0); - expect(users).toEqual([]); - }); + expect(users).toEqual([]); + }); - test('limit -1', async (ctx) => { - const { db } = ctx.mysql; + test('limit -1', async (ctx) => { + const { db } = ctx.mysql; - await db.insert(usersTable).values({ name: 'John' }); - const users = await db - .select() - .from(usersTable) - .limit(-1); + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(-1); - expect(users.length).toBeGreaterThan(0); + expect(users.length).toBeGreaterThan(0); + }); }); } From 99795fa6683210aac55598962d05f292767cefd0 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 14:03:27 +0300 Subject: [PATCH 141/152] Moved type conversion drom db to ORM; improved types --- drizzle-orm/src/mysql-core/query-builders/count.ts | 12 ++++++------ drizzle-orm/src/pg-core/query-builders/count.ts | 10 ++++++---- drizzle-orm/src/sqlite-core/query-builders/count.ts | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 1d5ac2a57a..cf6188c2bc 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -19,16 +19,14 @@ export class MySqlCountBuilder< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`(select cast(count(*) as UNSIGNED) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select cast(count(*) as UNSIGNED) as count from ${source}${ - sql.raw(' where ').if(filters) - }${filters}`; + return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters}`; } constructor( @@ -40,6 +38,8 @@ export class MySqlCountBuilder< ) { super(MySqlCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + this.mapWith(Number); + this.session = params.session; this.sql = MySqlCountBuilder.buildCount( @@ -52,8 +52,8 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute(this.sql)).then((it) => { - return (<[[{ count: number }]]> it)[0][0]['count']; + return Promise.resolve(this.session.execute<[[{ count: string }]]>(this.sql)).then((it) => { + return Number(it[0][0]['count']); }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index cfc4d583b9..ca1f6b61d8 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -18,14 +18,14 @@ export class PgCountBuilder< source: PgTable | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`(select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters})`; + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( source: PgTable | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select count(*)::int as count from ${source}${sql.raw(' where ').if(filters)}${filters};`; + return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters};`; } constructor( @@ -37,6 +37,8 @@ export class PgCountBuilder< ) { super(PgCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + this.mapWith(Number); + this.session = params.session; this.sql = PgCountBuilder.buildCount( @@ -49,8 +51,8 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute(this.sql)).then((it) => { - return (<[{ count: number }]> it)[0]['count'] as number; + return Promise.resolve(this.session.execute<[{ count: string }]>(this.sql)).then((it) => { + return Number(it[0]['count']); }) .then( onfulfilled, diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index f6434ee81b..073562b8b8 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -50,7 +50,7 @@ export class SQLiteCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.values(this.sql)).then((it) => it[0]![0] as number).then( + return Promise.resolve(this.session.values<[[number]]>(this.sql)).then((it) => it[0][0]).then( onfulfilled, onrejected, ); From 0105349d09192e76c927de12775c3d854372c290 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 15:39:48 +0300 Subject: [PATCH 142/152] Moved pg, mysql counts to sessions to resolve return shape conflicts --- drizzle-orm/src/mysql-core/query-builders/count.ts | 4 ++-- drizzle-orm/src/mysql-core/session.ts | 8 ++++++++ drizzle-orm/src/neon-http/session.ts | 10 +++++++++- drizzle-orm/src/node-postgres/session.ts | 9 ++++++++- drizzle-orm/src/pg-core/query-builders/count.ts | 4 ++-- drizzle-orm/src/pg-core/session.ts | 8 ++++++++ drizzle-orm/src/pglite/session.ts | 9 ++++++++- drizzle-orm/src/tidb-serverless/session.ts | 8 ++++++++ 8 files changed, 53 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index cf6188c2bc..4e734135f6 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -52,8 +52,8 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute<[[{ count: string }]]>(this.sql)).then((it) => { - return Number(it[0][0]['count']); + return Promise.resolve(this.session.count(this.sql)).then((it) => { + return it; }) .then( onfulfilled, diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 6b62696398..021d4276d4 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -86,6 +86,14 @@ export abstract class MySqlSession< abstract all(query: SQL): Promise; + async count(sql: SQL): Promise { + const res = await this.execute<[[{ count: string }]]>(sql); + + return Number( + res[0][0]['count'], + ); + } + abstract transaction( transaction: (tx: MySqlTransaction) => Promise, config?: MySqlTransactionConfig, diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index 6d76851162..a36b7222bc 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -10,7 +10,7 @@ import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from import { PgPreparedQuery as PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import type { PreparedQuery } from '~/session.ts'; -import { fillPlaceholders, type Query } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL } from '~/sql/sql.ts'; import { mapResultRow } from '~/utils.ts'; export type NeonHttpClient = NeonQueryFunction; @@ -161,6 +161,14 @@ export class NeonHttpSession< return this.client(query, params, { arrayMode: false, fullResults: true }); } + override async count(sql: SQL): Promise { + const res = await this.execute<[{ count: string }]>(sql); + + return Number( + res[0]['count'], + ); + } + override async transaction( _transaction: (tx: NeonTransaction) => Promise, // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/drizzle-orm/src/node-postgres/session.ts b/drizzle-orm/src/node-postgres/session.ts index 91a21312a9..ef67793542 100644 --- a/drizzle-orm/src/node-postgres/session.ts +++ b/drizzle-orm/src/node-postgres/session.ts @@ -8,7 +8,7 @@ import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.type import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from '~/pg-core/session.ts'; import { PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; @@ -164,6 +164,13 @@ export class NodePgSession< } } } + + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + return Number( + res['rows'][0]['count'], + ); + } } export class NodePgTransaction< diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index ca1f6b61d8..6867b09501 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -51,8 +51,8 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute<[{ count: string }]>(this.sql)).then((it) => { - return Number(it[0]['count']); + return Promise.resolve(this.session.count(this.sql)).then((it) => { + return it; }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index 434ebc086d..ea820f2d82 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -86,6 +86,14 @@ export abstract class PgSession< ).all(); } + async count(sql: SQL): Promise { + const res = await this.execute<[{ count: string }]>(sql); + + return Number( + res[0]['count'], + ); + } + abstract transaction( transaction: (tx: PgTransaction) => Promise, config?: PgTransactionConfig, diff --git a/drizzle-orm/src/pglite/session.ts b/drizzle-orm/src/pglite/session.ts index c7a1dbb5d1..ebf7701a6b 100644 --- a/drizzle-orm/src/pglite/session.ts +++ b/drizzle-orm/src/pglite/session.ts @@ -7,7 +7,7 @@ import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.type import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from '~/pg-core/session.ts'; import { PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; import { types } from '@electric-sql/pglite'; @@ -140,6 +140,13 @@ export class PgliteSession< return transaction(tx); }) as Promise; } + + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + return Number( + res['rows'][0]['count'], + ); + } } export class PgliteTransaction< diff --git a/drizzle-orm/src/tidb-serverless/session.ts b/drizzle-orm/src/tidb-serverless/session.ts index 64a8d61d75..b01b9f948e 100644 --- a/drizzle-orm/src/tidb-serverless/session.ts +++ b/drizzle-orm/src/tidb-serverless/session.ts @@ -139,6 +139,14 @@ export class TiDBServerlessSession< return this.client.execute(querySql.sql, querySql.params) as Promise; } + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + + return Number( + res['rows'][0]['count'], + ); + } + override async transaction( transaction: (tx: TiDBServerlessTransaction) => Promise, ): Promise { From 865fc077cc2ee7ecfc6aa889e550d2cf1edd800e Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 16:26:58 +0300 Subject: [PATCH 143/152] Fixed neon-http, planetscale; removed leftover lines; switched sqlite to session-based count --- drizzle-orm/src/mysql-core/query-builders/count.ts | 4 +--- drizzle-orm/src/neon-http/session.ts | 4 ++-- drizzle-orm/src/pg-core/query-builders/count.ts | 4 +--- drizzle-orm/src/planetscale-serverless/session.ts | 8 ++++++++ drizzle-orm/src/sqlite-core/query-builders/count.ts | 2 +- drizzle-orm/src/sqlite-core/session.ts | 6 ++++++ 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 4e734135f6..645bb47535 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -52,9 +52,7 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.count(this.sql)).then((it) => { - return it; - }) + return Promise.resolve(this.session.count(this.sql)) .then( onfulfilled, onrejected, diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index a36b7222bc..4dd768d3e4 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -162,10 +162,10 @@ export class NeonHttpSession< } override async count(sql: SQL): Promise { - const res = await this.execute<[{ count: string }]>(sql); + const res = await this.execute<{ rows: [{ count: string }] }>(sql); return Number( - res[0]['count'], + res['rows'][0]['count'], ); } diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index 6867b09501..c93cbb18d0 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -51,9 +51,7 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.count(this.sql)).then((it) => { - return it; - }) + return Promise.resolve(this.session.count(this.sql)) .then( onfulfilled, onrejected, diff --git a/drizzle-orm/src/planetscale-serverless/session.ts b/drizzle-orm/src/planetscale-serverless/session.ts index f2275b7f23..987529d7cb 100644 --- a/drizzle-orm/src/planetscale-serverless/session.ts +++ b/drizzle-orm/src/planetscale-serverless/session.ts @@ -164,6 +164,14 @@ export class PlanetscaleSession< ) => eQuery.rows as T[]); } + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + + return Number( + res['rows'][0]['count'], + ); + } + override transaction( transaction: (tx: PlanetScaleTransaction) => Promise, ): Promise { diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 073562b8b8..1b19eed075 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -50,7 +50,7 @@ export class SQLiteCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.values<[[number]]>(this.sql)).then((it) => it[0][0]).then( + return Promise.resolve(this.session.count(this.sql)).then( onfulfilled, onrejected, ); diff --git a/drizzle-orm/src/sqlite-core/session.ts b/drizzle-orm/src/sqlite-core/session.ts index 4ac987b4a3..d291b6fdf4 100644 --- a/drizzle-orm/src/sqlite-core/session.ts +++ b/drizzle-orm/src/sqlite-core/session.ts @@ -187,6 +187,12 @@ export abstract class SQLiteSession< >; } + async count(sql: SQL) { + const result = await this.values(sql) as [[number]]; + + return result[0][0]; + } + /** @internal */ extractRawValuesValueFromBatchResult(_result: unknown): unknown { throw new Error('Not implemented'); From b60aa989454a55251c4929bc464112bbb7948822 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 5 Sep 2024 17:34:50 +0300 Subject: [PATCH 144/152] changed console.log outputs for connection to Sqlite returned removed console.log in mysql push --- drizzle-kit/src/cli/commands/push.ts | 1 + drizzle-kit/src/cli/connections.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 1be844715c..0cb3a8d286 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -78,6 +78,7 @@ export const mysqlPush = async ( }); if (verbose) { + console.log(); console.log( withStyle.warning('You are about to execute current statements:'), ); diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 54945386e8..fccc7def85 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -671,7 +671,7 @@ export const connectToSQLite = async ( } console.log( - "Please install 'better-sqlite3' for Drizzle Kit to connect to SQLite databases", + "Please install either 'better-sqlite3' or '@libsql/client' for Drizzle Kit to connect to SQLite databases", ); process.exit(1); }; From 388d422f478e3d4d918f423fa9d1e68d759de3f5 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 6 Sep 2024 16:02:15 +0300 Subject: [PATCH 145/152] Add draft for beta release --- changelogs/drizzle-kit/0.25.0.md | 0 changelogs/drizzle-orm/0.34.0.md | 141 +++++++++++++++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- integration-tests/tests/pg/awsdatapi.test.ts | 14 +- integration-tests/tests/pg/neon-http.test.ts | 14 +- integration-tests/tests/pg/pg-common.ts | 8 +- integration-tests/tests/pg/vercel-pg.test.ts | 14 +- 8 files changed, 168 insertions(+), 27 deletions(-) create mode 100644 changelogs/drizzle-kit/0.25.0.md create mode 100644 changelogs/drizzle-orm/0.34.0.md diff --git a/changelogs/drizzle-kit/0.25.0.md b/changelogs/drizzle-kit/0.25.0.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md new file mode 100644 index 0000000000..4ceb1a6302 --- /dev/null +++ b/changelogs/drizzle-orm/0.34.0.md @@ -0,0 +1,141 @@ +// Libsql and Sqlite migration updates + +SQLite generate statements updates. Starting from this release, we won't generate comments like this: + +```sql + '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' +``` + +We will generate a set of statements instead and you will decide if it's good to make data moving statements instead. Here is an example of generated sql file you'll get now: + +```sql +``` + +LibSQL generate statements updates. As long as libsql support more alter statements than SQLite we can generate more statements without recreating you schema and moving all the data, which can be potentially dangeourose for production envs + +LibSQL and Turso will now get a separate dialect in drizzle config file, means, that we will evolve Turso and LibSQL separately from SQLite and will try to support as much features Turso/LibSQL would have as possible + +Breaking change! All the users, who wants to get max from Turso and LibSQL DDL statements, shouls remove `driver: turso` from drizzle.config and add `dialect: turso` instead + +With updated LibSQL migrartion staretegy you would have a possibility to: + +- **Change Data Type**: You can set a new data type for existing columns. +- **Set and Drop Default Values**: You can add or remove default values for existing columns. +- **Set and Drop Not Null Constraint**: You can add or remov the `NOT NULL` constraint on existing columns. +- **Add References to Existing Columns**: You can add foreign key references to existing columns. + + +### Code Example: + +```sql +PRAGMA foreign_keys=OFF; + +CREATE TABLE `__new_table` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text NOT NULL +); + +INSERT INTO `__new_table`("id", "name") SELECT "id", "name" FROM `table`; + +DROP TABLE `table`; + +ALTER TABLE `__new_table` RENAME TO `table`; + +PRAGMA foreign_keys=ON; +``` + +### LIMITATIONS + +- Dropping or altering index will cause table recreation + +This is because LibSQL does not support dropping this type of index: + +```sql +CREATE TABLE `users` ( + `id` integer NOT NULL, + `name` integer, + `age` integer PRIMARY KEY NOT NULL + FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action +); +``` + +- If the table has indexes, altering columns will cause table recreation. + Drizzle-Kit will drop those indexes, modify the columns, and then recreate the indexes. +- Adding or dropping `composite foreign keys` is not supported and will cause table recreation. + +### NOTES: + +- You can create reference on any column type, but if you want to insert values than primary column should have unique index or primary key + +```sql +CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f); +CREATE UNIQUE INDEX i1 ON parent(c, d); +CREATE INDEX i2 ON parent(e); +CREATE UNIQUE INDEX i3 ON parent(f COLLATE nocase); + +CREATE TABLE child1(f, g REFERENCES parent(a)); -- Ok +CREATE TABLE child2(h, i REFERENCES parent(b)); -- Ok +CREATE TABLE child3(j, k, FOREIGN KEY(j, k) REFERENCES parent(c, d)); -- Ok +CREATE TABLE child4(l, m REFERENCES parent(e)); -- Error! +CREATE TABLE child5(n, o REFERENCES parent(f)); -- Error! +CREATE TABLE child6(p, q, FOREIGN KEY(p, q) REFERENCES parent(b, c)); -- Error! +CREATE TABLE child7(r REFERENCES parent(c)); -- Error! +``` + +> NOTE: The foreign key for table *child5* is an error because even though the parent key column has a unique index, the index uses a different collating sequence + +See more: https://www.sqlite.org/foreignkeys.html + +// monodriver + +before on example with node-postgres + +```ts +const client = new Pool({ url: '' }); +drizzle(client, { logger: true }); +``` + +will become + +```ts +await drizzle('', { client: '', logger: true }) +await drizzle('', { client: {}, logger: true }) +``` + +> Note that first example with client is still available and not deprecated. You ca use it, if you don't want to await drizzle object. New way of defining drizzle is done to make it easiser to import from 1 place and get an autocmplete with all the possible clients + +// db count feature + +to count entities in table you would need to do this +```ts +const res = await db.select({ count: sql`count(*)` }).from(users); +const count = res[0].count; +``` + +a new api will look like +```ts +// how many users are in the database +const count: number = await db.$count(users); + +// how many users with the name "Dan" are in the database +const count: number = await db.$count(users, eq(name, "Dan")); +``` + +This can also work as a subquery and inside relational queries +```ts +const users = await db.select({ + ...users, + postsCount: db.$count(posts, eq(posts.authorId, users.id)) +}); + +const users = await db.query.users.findMany({ + extras: { + postsCount: db.$count(posts, eq(posts.authorId, users.id)) + } +}) +``` diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 75c3d65dc4..66f19e6be9 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.24.2", + "version": "0.25.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 11970a77ed..333521a48e 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.33.0", + "version": "0.34.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { diff --git a/integration-tests/tests/pg/awsdatapi.test.ts b/integration-tests/tests/pg/awsdatapi.test.ts index 8ee39cf121..3bb884c0c3 100644 --- a/integration-tests/tests/pg/awsdatapi.test.ts +++ b/integration-tests/tests/pg/awsdatapi.test.ts @@ -799,19 +799,18 @@ test('migrator : default migration strategy', async () => { }); test('migrator : migrate with custom schema', async () => { - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); await migrate(db, { migrationsFolder: './drizzle2/pg', - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rows } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`, + sql`select * from custom_migrations."__drizzle_migrations";`, ); expect(rows).toBeTruthy(); expect(rows!.length).toBeGreaterThan(0); @@ -824,7 +823,7 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); await db.execute( - sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`, + sql`drop table custom_migrations."__drizzle_migrations"`, ); }); @@ -858,7 +857,6 @@ test('migrator : migrate with custom table', async () => { test('migrator : migrate with custom table and custom schema', async () => { const customTable = randomString(); - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); @@ -866,12 +864,12 @@ test('migrator : migrate with custom table and custom schema', async () => { await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable, - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rows } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${ + sql`select * from custom_migrations.${ sql.identifier( customTable, ) @@ -888,7 +886,7 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); await db.execute( - sql`drop table ${sql.identifier(customSchema)}.${ + sql`drop table custom_migrations.${ sql.identifier( customTable, ) diff --git a/integration-tests/tests/pg/neon-http.test.ts b/integration-tests/tests/pg/neon-http.test.ts index 1476e96289..319c84f403 100644 --- a/integration-tests/tests/pg/neon-http.test.ts +++ b/integration-tests/tests/pg/neon-http.test.ts @@ -68,15 +68,14 @@ test('migrator : default migration strategy', async () => { }); test('migrator : migrate with custom schema', async () => { - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); - await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: customSchema }); + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: 'custom_migrations' }); // test if the custom migrations table was created - const { rowCount } = await db.execute(sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`); + const { rowCount } = await db.execute(sql`select * from custom_migrations."__drizzle_migrations";`); expect(rowCount && rowCount > 0).toBeTruthy(); // test if the migrated table are working as expected @@ -86,7 +85,7 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`); + await db.execute(sql`drop table custom_migrations."__drizzle_migrations"`); }); test('migrator : migrate with custom table', async () => { @@ -113,7 +112,6 @@ test('migrator : migrate with custom table', async () => { test('migrator : migrate with custom table and custom schema', async () => { const customTable = randomString(); - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); @@ -121,12 +119,12 @@ test('migrator : migrate with custom table and custom schema', async () => { await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable, - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rowCount } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${sql.identifier(customTable)};`, + sql`select * from custom_migrations.${sql.identifier(customTable)};`, ); expect(rowCount && rowCount > 0).toBeTruthy(); @@ -137,7 +135,7 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}.${sql.identifier(customTable)}`); + await db.execute(sql`drop table custom_migrations.${sql.identifier(customTable)}`); }); test('all date and time columns without timezone first case mode string', async () => { diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index b4afdcf64b..8550f5ae4a 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -74,7 +74,7 @@ import { } from 'drizzle-orm/pg-core'; import getPort from 'get-port'; import { v4 as uuidV4 } from 'uuid'; -import { afterAll, beforeEach, describe, expect, test } from 'vitest'; +import { afterAll, afterEach, beforeEach, describe, expect, test } from 'vitest'; import { Expect } from '~/utils'; import type { schema } from './neon-http-batch.test'; // eslint-disable-next-line @typescript-eslint/no-import-type-side-effects @@ -246,6 +246,7 @@ export function tests() { await db.execute(sql`drop schema if exists public cascade`); await db.execute(sql`drop schema if exists ${mySchema} cascade`); await db.execute(sql`create schema public`); + await db.execute(sql`create schema if not exists custom_migrations`); await db.execute(sql`create schema ${mySchema}`); // public users await db.execute( @@ -377,6 +378,11 @@ export function tests() { ); }); + afterEach(async (ctx) => { + const { db } = ctx.pg; + await db.execute(sql`drop schema if exists custom_migrations cascade`); + }); + async function setupSetOperationTest(db: PgDatabase) { await db.execute(sql`drop table if exists users2`); await db.execute(sql`drop table if exists cities`); diff --git a/integration-tests/tests/pg/vercel-pg.test.ts b/integration-tests/tests/pg/vercel-pg.test.ts index 3f1248d9b5..ecf1d22ac3 100644 --- a/integration-tests/tests/pg/vercel-pg.test.ts +++ b/integration-tests/tests/pg/vercel-pg.test.ts @@ -77,15 +77,14 @@ test('migrator : default migration strategy', async () => { }); test('migrator : migrate with custom schema', async () => { - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); - await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: customSchema }); + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: 'custom_migrations' }); // test if the custom migrations table was created - const { rowCount } = await db.execute(sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`); + const { rowCount } = await db.execute(sql`select * from custom_migrations."__drizzle_migrations";`); expect(rowCount && rowCount > 0).toBeTruthy(); // test if the migrated table are working as expected @@ -95,7 +94,7 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`); + await db.execute(sql`drop table custom_migrations."__drizzle_migrations"`); }); test('migrator : migrate with custom table', async () => { @@ -122,7 +121,6 @@ test('migrator : migrate with custom table', async () => { test('migrator : migrate with custom table and custom schema', async () => { const customTable = randomString(); - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); @@ -130,12 +128,12 @@ test('migrator : migrate with custom table and custom schema', async () => { await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable, - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rowCount } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${sql.identifier(customTable)};`, + sql`select * from custom_migrations.${sql.identifier(customTable)};`, ); expect(rowCount && rowCount > 0).toBeTruthy(); @@ -146,7 +144,7 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}.${sql.identifier(customTable)}`); + await db.execute(sql`drop table custom_migrations.${sql.identifier(customTable)}`); }); test('all date and time columns without timezone first case mode string', async () => { From 6d413dff2d4b4caf82c8407cd691e7724d92f88c Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 9 Sep 2024 11:17:29 +0300 Subject: [PATCH 146/152] Add release notes for orm and kit --- changelogs/drizzle-kit/0.25.0.md | 95 ++++++++++++++++++++++++++++ changelogs/drizzle-orm/0.34.0.md | 103 +++++++++++++++++-------------- 2 files changed, 153 insertions(+), 45 deletions(-) diff --git a/changelogs/drizzle-kit/0.25.0.md b/changelogs/drizzle-kit/0.25.0.md index e69de29bb2..0c1c5ea6e9 100644 --- a/changelogs/drizzle-kit/0.25.0.md +++ b/changelogs/drizzle-kit/0.25.0.md @@ -0,0 +1,95 @@ +## Libsql and Sqlite migration updates + +### SQLite "generate" and "push" statements updates + +Starting from this release, we will no longer generate comments like this: + +```sql + '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' +``` + +We will generate a set of statements, and you can decide if it's appropriate to create data-moving statements instead. Here is an example of the SQL file you'll receive now: + +```sql +PRAGMA foreign_keys=OFF; +--> statement-breakpoint +CREATE TABLE `__new_worker` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `salary` text NOT NULL, + `job_id` integer, + FOREIGN KEY (`job_id`) REFERENCES `job`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +INSERT INTO `__new_worker`("id", "name", "salary", "job_id") SELECT "id", "name", "salary", "job_id" FROM `worker`; +--> statement-breakpoint +DROP TABLE `worker`; +--> statement-breakpoint +ALTER TABLE `__new_worker` RENAME TO `worker`; +--> statement-breakpoint +PRAGMA foreign_keys=ON; +``` + +### LibSQL "generate" and "push" statements updates + +Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. + +LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. + +> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead + +With the updated LibSQL migration strategy, you will have the ability to: + +- **Change Data Type**: Set a new data type for existing columns. +- **Set and Drop Default Values**: Add or remove default values for existing columns. +- **Set and Drop NOT NULL**: Add or remove the NOT NULL constraint on existing columns. +- **Add References to Existing Columns**: Add foreign key references to existing columns + +You can find more information in the [LibSQL documentation](https://github.com/tursodatabase/libsql/blob/main/libsql-sqlite3/doc/libsql_extensions.md#altering-columns) + +### LIMITATIONS + +- Dropping or altering an index will cause table recreation. + +This is because LibSQL does not support dropping this type of index. + +```sql +CREATE TABLE `users` ( + `id` integer NOT NULL, + `name` integer, + `age` integer PRIMARY KEY NOT NULL + FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action +); +``` + +- If the table has indexes, altering columns will cause table recreation. +- Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. +- Adding or dropping composite foreign keys is not supported and will cause table recreation + +### NOTES: + +- You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. + +```sql +CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f); +CREATE UNIQUE INDEX i1 ON parent(c, d); +CREATE INDEX i2 ON parent(e); +CREATE UNIQUE INDEX i3 ON parent(f COLLATE nocase); + +CREATE TABLE child1(f, g REFERENCES parent(a)); -- Ok +CREATE TABLE child2(h, i REFERENCES parent(b)); -- Ok +CREATE TABLE child3(j, k, FOREIGN KEY(j, k) REFERENCES parent(c, d)); -- Ok +CREATE TABLE child4(l, m REFERENCES parent(e)); -- Error! +CREATE TABLE child5(n, o REFERENCES parent(f)); -- Error! +CREATE TABLE child6(p, q, FOREIGN KEY(p, q) REFERENCES parent(b, c)); -- Error! +CREATE TABLE child7(r REFERENCES parent(c)); -- Error! +``` + +> **NOTE**: The foreign key for the table child5 is an error because, although the parent key column has a unique index, the index uses a different collating sequence. + +See more: https://www.sqlite.org/foreignkeys.html \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md index 4ceb1a6302..55eb0411f4 100644 --- a/changelogs/drizzle-orm/0.34.0.md +++ b/changelogs/drizzle-orm/0.34.0.md @@ -1,6 +1,8 @@ -// Libsql and Sqlite migration updates +## Libsql and Sqlite migration updates -SQLite generate statements updates. Starting from this release, we won't generate comments like this: +### SQLite "generate" and "push" statements updates + +Starting from this release, we will no longer generate comments like this: ```sql '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' @@ -11,66 +13,67 @@ SQLite generate statements updates. Starting from this release, we won't generat + '\n*/' ``` -We will generate a set of statements instead and you will decide if it's good to make data moving statements instead. Here is an example of generated sql file you'll get now: +We will generate a set of statements, and you can decide if it's appropriate to create data-moving statements instead. Here is an example of the SQL file you'll receive now: ```sql +PRAGMA foreign_keys=OFF; +--> statement-breakpoint +CREATE TABLE `__new_worker` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `salary` text NOT NULL, + `job_id` integer, + FOREIGN KEY (`job_id`) REFERENCES `job`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +INSERT INTO `__new_worker`("id", "name", "salary", "job_id") SELECT "id", "name", "salary", "job_id" FROM `worker`; +--> statement-breakpoint +DROP TABLE `worker`; +--> statement-breakpoint +ALTER TABLE `__new_worker` RENAME TO `worker`; +--> statement-breakpoint +PRAGMA foreign_keys=ON; ``` -LibSQL generate statements updates. As long as libsql support more alter statements than SQLite we can generate more statements without recreating you schema and moving all the data, which can be potentially dangeourose for production envs - -LibSQL and Turso will now get a separate dialect in drizzle config file, means, that we will evolve Turso and LibSQL separately from SQLite and will try to support as much features Turso/LibSQL would have as possible - -Breaking change! All the users, who wants to get max from Turso and LibSQL DDL statements, shouls remove `driver: turso` from drizzle.config and add `dialect: turso` instead - -With updated LibSQL migrartion staretegy you would have a possibility to: - -- **Change Data Type**: You can set a new data type for existing columns. -- **Set and Drop Default Values**: You can add or remove default values for existing columns. -- **Set and Drop Not Null Constraint**: You can add or remov the `NOT NULL` constraint on existing columns. -- **Add References to Existing Columns**: You can add foreign key references to existing columns. - +### LibSQL "generate" and "push" statements updates -### Code Example: +Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. -```sql -PRAGMA foreign_keys=OFF; - -CREATE TABLE `__new_table` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `name` text NOT NULL -); +LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. -INSERT INTO `__new_table`("id", "name") SELECT "id", "name" FROM `table`; +> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead -DROP TABLE `table`; +With the updated LibSQL migration strategy, you will have the ability to: -ALTER TABLE `__new_table` RENAME TO `table`; +- **Change Data Type**: Set a new data type for existing columns. +- **Set and Drop Default Values**: Add or remove default values for existing columns. +- **Set and Drop NOT NULL**: Add or remove the NOT NULL constraint on existing columns. +- **Add References to Existing Columns**: Add foreign key references to existing columns -PRAGMA foreign_keys=ON; -``` +You can find more information in the [LibSQL documentation](https://github.com/tursodatabase/libsql/blob/main/libsql-sqlite3/doc/libsql_extensions.md#altering-columns) ### LIMITATIONS -- Dropping or altering index will cause table recreation +- Dropping or altering an index will cause table recreation. -This is because LibSQL does not support dropping this type of index: +This is because LibSQL does not support dropping this type of index. ```sql CREATE TABLE `users` ( - `id` integer NOT NULL, - `name` integer, - `age` integer PRIMARY KEY NOT NULL - FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action + `id` integer NOT NULL, + `name` integer, + `age` integer PRIMARY KEY NOT NULL + FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action ); ``` - If the table has indexes, altering columns will cause table recreation. - Drizzle-Kit will drop those indexes, modify the columns, and then recreate the indexes. -- Adding or dropping `composite foreign keys` is not supported and will cause table recreation. +- Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. +- Adding or dropping composite foreign keys is not supported and will cause table recreation ### NOTES: -- You can create reference on any column type, but if you want to insert values than primary column should have unique index or primary key +- You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. ```sql CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f); @@ -87,17 +90,27 @@ CREATE TABLE child6(p, q, FOREIGN KEY(p, q) REFERENCES parent(b, c)); -- Error! CREATE TABLE child7(r REFERENCES parent(c)); -- Error! ``` -> NOTE: The foreign key for table *child5* is an error because even though the parent key column has a unique index, the index uses a different collating sequence +> **NOTE**: The foreign key for the table child5 is an error because, although the parent key column has a unique index, the index uses a different collating sequence. See more: https://www.sqlite.org/foreignkeys.html -// monodriver +## A new and easy way to start using drizzle before on example with node-postgres ```ts +// 1, current const client = new Pool({ url: '' }); drizzle(client, { logger: true }); + +// 2 +await drizzle('neon', { client: 'postgresql://...', logger: true }) + +// 3 +await drizzle('neon', { client: { url: 'postgresql://...' }, logger: true }) + +// 4 +await drizzle('neon', 'postgresql://...') ``` will become @@ -107,17 +120,17 @@ await drizzle('', { client: '', logger: true }) await drizzle('', { client: {}, logger: true }) ``` -> Note that first example with client is still available and not deprecated. You ca use it, if you don't want to await drizzle object. New way of defining drizzle is done to make it easiser to import from 1 place and get an autocmplete with all the possible clients +> Note that the first example with the client is still available and not deprecated. You can use it if you don't want to await the drizzle object. The new way of defining drizzle is designed to make it easier to import from one place and get autocomplete for all the available clients -// db count feature +## New "count" API -to count entities in table you would need to do this +Befor this release to count entities in a table, you would need to do this: ```ts const res = await db.select({ count: sql`count(*)` }).from(users); const count = res[0].count; ``` -a new api will look like +The new API will look like this: ```ts // how many users are in the database const count: number = await db.$count(users); @@ -126,7 +139,7 @@ const count: number = await db.$count(users); const count: number = await db.$count(users, eq(name, "Dan")); ``` -This can also work as a subquery and inside relational queries +This can also work as a subquery and within relational queries ```ts const users = await db.select({ ...users, From d5a0238754a47542e5b642173b57b7e851bcc1d8 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 11 Sep 2024 12:03:26 +0300 Subject: [PATCH 147/152] Update release notes --- changelogs/drizzle-kit/0.25.0.md | 61 ++++++++++++-- changelogs/drizzle-orm/0.34.0.md | 135 +++++++++++++++++++++++++++---- 2 files changed, 173 insertions(+), 23 deletions(-) diff --git a/changelogs/drizzle-kit/0.25.0.md b/changelogs/drizzle-kit/0.25.0.md index 0c1c5ea6e9..fc4b36c83f 100644 --- a/changelogs/drizzle-kit/0.25.0.md +++ b/changelogs/drizzle-kit/0.25.0.md @@ -1,4 +1,55 @@ -## Libsql and Sqlite migration updates +## Breaking changes and migrate guide for Turso users + +If you are using Turso and libsql, you will need to upgrade your `drizzle.config` and `@libsql/client` package. + +1. This version of drizzle-orm will only work with `@libsql/client@0.10.0` or higher if you are using the `migrate` function. For other use cases, you can continue using previous versions(But the suggestion is to upgrade) +To install the latest version, use the command: + +```bash +npm i @libsql/client@latest +``` + +2. Previously, we had a common `drizzle.config` for SQLite and Turso users, which allowed a shared strategy for both dialects. Starting with this release, we are introducing the turso dialect in drizzle-kit. We will evolve and improve Turso as a separate dialect with its own migration strategies. + +**Before** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "sqlite", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +**After** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "turso", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +If you are using only SQLite, you can use `dialect: "sqlite"` + +## LibSQL/Turso and Sqlite migration updates ### SQLite "generate" and "push" statements updates @@ -35,14 +86,12 @@ ALTER TABLE `__new_worker` RENAME TO `worker`; PRAGMA foreign_keys=ON; ``` -### LibSQL "generate" and "push" statements updates +### LibSQL/Turso "generate" and "push" statements updates Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. -> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead - With the updated LibSQL migration strategy, you will have the ability to: - **Change Data Type**: Set a new data type for existing columns. @@ -56,7 +105,7 @@ You can find more information in the [LibSQL documentation](https://github.com/t - Dropping or altering an index will cause table recreation. -This is because LibSQL does not support dropping this type of index. +This is because LibSQL/Turso does not support dropping this type of index. ```sql CREATE TABLE `users` ( @@ -71,7 +120,7 @@ CREATE TABLE `users` ( - Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. - Adding or dropping composite foreign keys is not supported and will cause table recreation -### NOTES: +### NOTES - You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md index 55eb0411f4..490422628d 100644 --- a/changelogs/drizzle-orm/0.34.0.md +++ b/changelogs/drizzle-orm/0.34.0.md @@ -1,4 +1,55 @@ -## Libsql and Sqlite migration updates +## Breaking changes and migrate guide for Turso users + +If you are using Turso and libsql, you will need to upgrade your `drizzle.config` and `@libsql/client` package. + +1. This version of drizzle-orm will only work with `@libsql/client@0.10.0` or higher if you are using the `migrate` function. For other use cases, you can continue using previous versions(But the suggestion is to upgrade) +To install the latest version, use the command: + +```bash +npm i @libsql/client@latest +``` + +2. Previously, we had a common `drizzle.config` for SQLite and Turso users, which allowed a shared strategy for both dialects. Starting with this release, we are introducing the turso dialect in drizzle-kit. We will evolve and improve Turso as a separate dialect with its own migration strategies. + +**Before** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "sqlite", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +**After** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "turso", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +If you are using only SQLite, you can use `dialect: "sqlite"` + +## LibSQL/Turso and Sqlite migration updates ### SQLite "generate" and "push" statements updates @@ -35,14 +86,12 @@ ALTER TABLE `__new_worker` RENAME TO `worker`; PRAGMA foreign_keys=ON; ``` -### LibSQL "generate" and "push" statements updates +### LibSQL/Turso "generate" and "push" statements updates Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. -> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead - With the updated LibSQL migration strategy, you will have the ability to: - **Change Data Type**: Set a new data type for existing columns. @@ -56,7 +105,7 @@ You can find more information in the [LibSQL documentation](https://github.com/t - Dropping or altering an index will cause table recreation. -This is because LibSQL does not support dropping this type of index. +This is because LibSQL/Turso does not support dropping this type of index. ```sql CREATE TABLE `users` ( @@ -71,7 +120,7 @@ CREATE TABLE `users` ( - Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. - Adding or dropping composite foreign keys is not supported and will cause table recreation -### NOTES: +### NOTES - You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. @@ -96,28 +145,77 @@ See more: https://www.sqlite.org/foreignkeys.html ## A new and easy way to start using drizzle -before on example with node-postgres +Current and the only way to do, is to define client yourself and pass it to drizzle ```ts -// 1, current const client = new Pool({ url: '' }); drizzle(client, { logger: true }); +``` + +But we want to introduce you to a new API, which is a simplified method in addition to the existing one. + +Most clients will have a few options to connect, starting with the easiest and most common one, and allowing you to control your client connection as needed. -// 2 -await drizzle('neon', { client: 'postgresql://...', logger: true }) +Let's use `node-postgres` as an example, but the same pattern can be applied to all other clients -// 3 -await drizzle('neon', { client: { url: 'postgresql://...' }, logger: true }) +```ts +// Finally, one import for all available clients and dialects! +import { drizzle } from 'drizzle-orm' + +// Choose a client and use a connection URL — nothing else is needed! +const db1 = await drizzle("node-postgres", process.env.POSTGRES_URL); + +// If you need to pass a logger, schema, or other configurations, you can use an object and specify the client-specific URL in the connection +const db2 = await drizzle("node-postgres", { + connection: process.env.POSTGRES_URL, + logger: true +}); + +// And finally, if you need to use full client/driver-specific types in connections, you can use a URL or host/port/etc. as an object inferred from the underlying client connection types +const db3 = await drizzle("node-postgres", { + connection: { + connectionString: process.env.POSTGRES_URL, + }, +}); -// 4 -await drizzle('neon', 'postgresql://...') +const db4 = await drizzle("node-postgres", { + connection: { + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + database: process.env.DB_NAME, + ssl: true, + }, +}); ``` -will become +A few clients will have a slightly different API due to their specific behavior. Let's take a look at them: + +For `aws-data-api-pg`, Drizzle will require `resourceArn`, `database`, and `secretArn`, along with any other AWS Data API client types for the connection, such as credentials, region, etc. ```ts -await drizzle('', { client: '', logger: true }) -await drizzle('', { client: {}, logger: true }) +drizzle("aws-data-api-pg", { + connection: { + resourceArn: "", + database: "", + secretArn: "", + }, +}); +``` + +For `d1`, the Cloudflare Worker types as described in the [documentation](https://developers.cloudflare.com/d1/get-started/) here will be required. + +```ts +drizzle("d1", { + connection: env.DB // Cloudflare Worker Types +}) +``` + +For `vercel-postgres`, nothing is needed since Vercel automatically retrieves the `POSTGRES_URL` from the `.env` file. You can check this [documentation](https://vercel.com/docs/storage/vercel-postgres/quickstart) for more info + +```ts +drizzle("vercel-postgres") ``` > Note that the first example with the client is still available and not deprecated. You can use it if you don't want to await the drizzle object. The new way of defining drizzle is designed to make it easier to import from one place and get autocomplete for all the available clients @@ -125,12 +223,14 @@ await drizzle('', { client: {}, logger: true }) ## New "count" API Befor this release to count entities in a table, you would need to do this: + ```ts const res = await db.select({ count: sql`count(*)` }).from(users); const count = res[0].count; ``` The new API will look like this: + ```ts // how many users are in the database const count: number = await db.$count(users); @@ -140,6 +240,7 @@ const count: number = await db.$count(users, eq(name, "Dan")); ``` This can also work as a subquery and within relational queries + ```ts const users = await db.select({ ...users, From c38333a6a9f97923c04f83557d52690f8256df25 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 8 Aug 2024 13:21:35 +0100 Subject: [PATCH 148/152] add singlestore dialect to drizzle-kit --- drizzle-kit/src/cli/commands/migrate.ts | 52 ++++++++++++ drizzle-kit/src/cli/commands/utils.ts | 7 ++ drizzle-kit/src/cli/connections.ts | 80 +++++++++++++++++++ drizzle-kit/src/introspect-singlestore.ts | 11 +-- drizzle-kit/src/jsonStatements.ts | 1 + drizzle-kit/src/migrationPreparator.ts | 1 + drizzle-kit/src/schemaValidator.ts | 1 + .../src/serializer/singlestoreSerializer.ts | 25 +++--- drizzle-kit/src/serializer/studio.ts | 10 +-- pnpm-lock.yaml | 25 +----- 10 files changed, 166 insertions(+), 47 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index de1d8bc453..6fd9120ae0 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -396,6 +396,58 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { } }; +// Not needed for now +function mySingleStoreSchemaSuggestions( + curSchema: TypeOf, + prevSchema: TypeOf, +) { + const suggestions: string[] = []; + const usedSuggestions: string[] = []; + const suggestionTypes = { + // TODO: Check if SingleStore has serial type + serial: withStyle.errorWarning( + `We deprecated the use of 'serial' for SingleStore starting from version 0.20.0. In SingleStore, 'serial' is simply an alias for 'bigint unsigned not null auto_increment unique,' which creates all constraints and indexes for you. This may make the process less explicit for both users and drizzle-kit push commands`, + ), + }; + + for (const table of Object.values(curSchema.tables)) { + for (const column of Object.values(table.columns)) { + if (column.type === 'serial') { + if (!usedSuggestions.includes('serial')) { + suggestions.push(suggestionTypes['serial']); + } + + const uniqueForSerial = Object.values( + prevSchema.tables[table.name].uniqueConstraints, + ).find((it) => it.columns[0] === column.name); + + suggestions.push( + `\n` + + withStyle.suggestion( + `We are suggesting to change ${ + chalk.blue( + column.name, + ) + } column in ${ + chalk.blueBright( + table.name, + ) + } table from serial to bigint unsigned\n\n${ + chalk.blueBright( + `bigint("${column.name}", { mode: "number", unsigned: true }).notNull().autoincrement().unique(${ + uniqueForSerial?.name ? `"${uniqueForSerial?.name}"` : '' + })`, + ) + }`, + ), + ); + } + } + } + + return suggestions; +} + // Intersect with prepareAnMigrate export const prepareSingleStorePush = async ( schemaPath: string | string[], diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 5e5681b2c0..f01ee5e0b5 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -29,6 +29,7 @@ import { postgresCredentials, printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; +import { printConfigConnectionIssues as printIssuesSingleStore, singlestoreCredentials, SingleStoreCredentials } from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSingleStore, SingleStoreCredentials, @@ -221,6 +222,9 @@ export const preparePushConfig = async ( | { dialect: 'turso'; credentials: LibSQLCredentials; + } | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; } | { dialect: 'singlestore'; @@ -406,6 +410,9 @@ export const preparePullConfig = async ( | { dialect: 'turso'; credentials: LibSQLCredentials; + } | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; } ) & { out: string; diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index fccc7def85..41bcebeb79 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -21,6 +21,7 @@ import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; import { SingleStoreCredentials } from './validations/singlestore'; import type { SqliteCredentials } from './validations/sqlite'; +import { SingleStoreCredentials } from './validations/singlestore'; export const preparePostgresDB = async ( credentials: PostgresCredentials, @@ -731,6 +732,85 @@ export const connectToLibSQL = async (credentials: LibSQLCredentials): Promise< "Please install '@libsql/client' for Drizzle Kit to connect to LibSQL databases", ); process.exit(1); +} + +const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { + if ('url' in credentials) { + const url = credentials.url; + + const connectionUrl = new URL(url); + const pathname = connectionUrl.pathname; + + const database = pathname.split('/')[pathname.split('/').length - 1]; + if (!database) { + console.error( + 'You should specify a database name in connection string (singlestore://USER:PASSWORD@HOST:PORT/DATABASE)', + ); + process.exit(1); + } + return { database, url }; + } else { + return { + database: credentials.database, + credentials, + }; + } +}; + +export const connectToSingleStore = async ( + it: SingleStoreCredentials, +): Promise<{ + db: DB; + proxy: Proxy; + database: string; + migrate: (config: MigrationConfig) => Promise; +}> => { + const result = parseSingleStoreCredentials(it); + + if (await checkPackage('singlestore')) { + const { createConnection } = await import('mysql2/promise'); + const { drizzle } = await import('drizzle-orm/singlestore'); + const { migrate } = await import('drizzle-orm/singlestore/migrator'); + + const connection = result.url + ? await createConnection(result.url) + : await createConnection(result.credentials!); // needed for some reason! + + const db = drizzle(connection); + const migrateFn = async (config: MigrationConfig) => { + return migrate(db, config); + }; + + await connection.connect(); + const query: DB['query'] = async ( + sql: string, + params?: any[], + ): Promise => { + const res = await connection.execute(sql, params); + return res[0] as any; + }; + + const proxy: Proxy = async (params: ProxyParams) => { + const result = await connection.query({ + sql: params.sql, + values: params.params, + rowsAsArray: params.mode === 'array', + }); + return result[0] as any[]; + }; + + return { + db: { query }, + proxy, + database: result.database, + migrate: migrateFn, + }; + } + + console.error( + "To connect to SingleStore database - please install 'mysql2' drivers", + ); + process.exit(1); }; const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 8aa6e3dd72..b9efc537a9 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -386,15 +386,16 @@ const column = ( ? `${casing(name)}: timestamp("${name}", ${params})` : `${casing(name)}: timestamp("${name}")`; - // TODO: check if SingleStore has defaultNow() or now() - defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + + // TODO: check if SingleStore has defaultNow() or now() + defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' ? '.defaultNow()' : defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; - - out += defaultValue; - + + out += defaultValue; + // TODO: check if SingleStore has onUpdateNow() let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; out += onUpdateNow; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index c4c51d4b40..cd31796570 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -3,6 +3,7 @@ import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; import { CommonSquashedSchema } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 4e5664290b..3d1ddbea39 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -5,6 +5,7 @@ import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; import { drySingleStore, SingleStoreSchema, singlestoreSchema } from './serializer/singlestoreSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; +import { drySingleStore, singlestoreSchema, SingleStoreSchema } from './serializer/singlestoreSchema'; export const prepareMySqlDbPushSnapshot = async ( prev: MySqlSchema, diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index e91b5ab113..4065e948f6 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -3,6 +3,7 @@ import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; +import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso', 'singlestore'] as const; export const dialect = enumType(dialects); diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index f275273f40..3f36f9c215 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -1,19 +1,18 @@ import chalk from 'chalk'; -import { getTableName, is } from 'drizzle-orm'; -import { SQL } from 'drizzle-orm'; +import { is, SQL } from 'drizzle-orm'; import { AnySingleStoreTable, + getTableConfig, type PrimaryKey as PrimaryKeyORM, SingleStoreDialect, uniqueKeyName, } from 'drizzle-orm/singlestore-core'; -import { getTableConfig } from 'drizzle-orm/singlestore-core'; import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; -import type { DB } from '../utils'; import { sqlToStr } from '.'; +import type { DB } from '../utils'; import { Column, Index, @@ -574,15 +573,15 @@ export const fromDatabase = async ( }; } } else { - if (typeof tableInResult.indexes[constraintName] !== 'undefined') { - tableInResult.indexes[constraintName]!.columns.push(columnName); - } else { - tableInResult.indexes[constraintName] = { - name: constraintName, - columns: [columnName], - isUnique: isUnique, - }; - } + if (typeof tableInResult.indexes[constraintName] !== 'undefined') { + tableInResult.indexes[constraintName]!.columns.push(columnName); + } else { + tableInResult.indexes[constraintName] = { + name: constraintName, + columns: [columnName], + isUnique: isUnique, + }; + } } } diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index 12ea8207c0..14f9a0d2e2 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -13,14 +13,14 @@ import { Relations, TablesRelationalConfig, } from 'drizzle-orm'; -import { AnyMySqlTable, getTableConfig as mysqlTableConfig, MySqlTable } from 'drizzle-orm/mysql-core'; -import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-orm/pg-core'; +import { AnyMySqlTable, MySqlTable, getTableConfig as mysqlTableConfig } from 'drizzle-orm/mysql-core'; +import { AnyPgTable, PgTable, getTableConfig as pgTableConfig } from 'drizzle-orm/pg-core'; import { AnySingleStoreTable, - getTableConfig as singlestoreTableConfig, SingleStoreTable, + getTableConfig as singlestoreTableConfig, } from 'drizzle-orm/singlestore-core'; -import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { AnySQLiteTable, SQLiteTable, getTableConfig as sqliteTableConfig } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; import { cors } from 'hono/cors'; @@ -29,12 +29,12 @@ import { LibSQLCredentials } from 'src/cli/validations/libsql'; import { assertUnreachable } from 'src/global'; import superjson from 'superjson'; import { z } from 'zod'; +import { prepareFilenames } from '.'; import { safeRegister } from '../cli/commands/utils'; import type { MysqlCredentials } from '../cli/validations/mysql'; import type { PostgresCredentials } from '../cli/validations/postgres'; import type { SingleStoreCredentials } from '../cli/validations/singlestore'; import type { SqliteCredentials } from '../cli/validations/sqlite'; -import { prepareFilenames } from '.'; type CustomDefault = { schema: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfb3ae80d3..4b41d44802 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7311,10 +7311,6 @@ packages: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} - lru-cache@9.1.2: - resolution: {integrity: sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==} - engines: {node: 14 || >=16.14} - lru-queue@0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} @@ -7628,10 +7624,6 @@ packages: resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} engines: {node: '>=0.8.0'} - mysql2@3.11.0: - resolution: {integrity: sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==} - engines: {node: '>= 8.0'} - mysql2@3.3.3: resolution: {integrity: sha512-MxDQJztArk4JFX1PKVjDhIXRzAmVJfuqZrVU+my6NeYBAA/XZRaDw5q7vga8TNvgyy3Lv3rivBFBBuJFbsdjaw==} engines: {node: '>= 8.0'} @@ -18600,8 +18592,6 @@ snapshots: lru-cache@8.0.5: {} - lru-cache@9.1.2: {} - lru-queue@0.1.0: dependencies: es5-ext: 0.10.62 @@ -19040,19 +19030,6 @@ snapshots: rimraf: 2.4.5 optional: true - mysql2@3.11.0: - dependencies: - aws-ssl-profiles: 1.1.1 - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.6.3 - long: 5.2.3 - lru-cache: 8.0.5 - named-placeholders: 1.1.3 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - optional: true - mysql2@3.3.3: dependencies: denque: 2.1.0 @@ -19465,7 +19442,7 @@ snapshots: path-scurry@1.10.1: dependencies: - lru-cache: 9.1.2 + lru-cache: 10.2.2 minipass: 5.0.0 path-scurry@1.11.1: From f86f5a164918e0733666edfdf8b6119d3a1c51fa Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 8 Aug 2024 13:51:05 +0100 Subject: [PATCH 149/152] create new singlestore-schemas.test.ts file --- drizzle-kit/src/cli/commands/utils.ts | 8 +-- drizzle-kit/src/cli/connections.ts | 80 --------------------------- drizzle-kit/src/jsonStatements.ts | 1 - drizzle-kit/tests/schemaDiffer.ts | 3 +- 4 files changed, 2 insertions(+), 90 deletions(-) diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index f01ee5e0b5..d80b736fe7 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -16,8 +16,7 @@ import { Prefix, wrapParam, } from '../validations/common'; -import { LibSQLCredentials, libSQLCredentials } from '../validations/libsql'; -import { printConfigConnectionIssues as printIssuesLibSql } from '../validations/libsql'; +import { LibSQLCredentials, libSQLCredentials, printConfigConnectionIssues as printIssuesLibSql } from '../validations/libsql'; import { MysqlCredentials, mysqlCredentials, @@ -30,11 +29,6 @@ import { printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; import { printConfigConnectionIssues as printIssuesSingleStore, singlestoreCredentials, SingleStoreCredentials } from '../validations/singlestore'; -import { - printConfigConnectionIssues as printIssuesSingleStore, - SingleStoreCredentials, - singlestoreCredentials, -} from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSqlite, SqliteCredentials, diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 41bcebeb79..f17351dfdc 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -21,7 +21,6 @@ import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; import { SingleStoreCredentials } from './validations/singlestore'; import type { SqliteCredentials } from './validations/sqlite'; -import { SingleStoreCredentials } from './validations/singlestore'; export const preparePostgresDB = async ( credentials: PostgresCredentials, @@ -812,82 +811,3 @@ export const connectToSingleStore = async ( ); process.exit(1); }; - -const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { - if ('url' in credentials) { - const url = credentials.url; - - const connectionUrl = new URL(url); - const pathname = connectionUrl.pathname; - - const database = pathname.split('/')[pathname.split('/').length - 1]; - if (!database) { - console.error( - 'You should specify a database name in connection string (singlestore://USER:PASSWORD@HOST:PORT/DATABASE)', - ); - process.exit(1); - } - return { database, url }; - } else { - return { - database: credentials.database, - credentials, - }; - } -}; - -export const connectToSingleStore = async ( - it: SingleStoreCredentials, -): Promise<{ - db: DB; - proxy: Proxy; - database: string; - migrate: (config: MigrationConfig) => Promise; -}> => { - const result = parseSingleStoreCredentials(it); - - if (await checkPackage('singlestore')) { - const { createConnection } = await import('mysql2/promise'); - const { drizzle } = await import('drizzle-orm/singlestore'); - const { migrate } = await import('drizzle-orm/singlestore/migrator'); - - const connection = result.url - ? await createConnection(result.url) - : await createConnection(result.credentials!); // needed for some reason! - - const db = drizzle(connection); - const migrateFn = async (config: MigrationConfig) => { - return migrate(db, config); - }; - - await connection.connect(); - const query: DB['query'] = async ( - sql: string, - params?: any[], - ): Promise => { - const res = await connection.execute(sql, params); - return res[0] as any; - }; - - const proxy: Proxy = async (params: ProxyParams) => { - const result = await connection.query({ - sql: params.sql, - values: params.params, - rowsAsArray: params.mode === 'array', - }); - return result[0] as any[]; - }; - - return { - db: { query }, - proxy, - database: result.database, - migrate: migrateFn, - }; - } - - console.error( - "To connect to SingleStore database - please install 'mysql2' drivers", - ); - process.exit(1); -}; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index cd31796570..c4c51d4b40 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -3,7 +3,6 @@ import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; import { CommonSquashedSchema } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; -import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 07da0ed058..da16dac879 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -4,8 +4,7 @@ import { Database } from 'better-sqlite3'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; -import { SingleStoreSchema } from 'drizzle-orm/singlestore-core'; -import { SingleStoreTable } from 'drizzle-orm/singlestore-core'; +import { SingleStoreSchema, SingleStoreTable } from 'drizzle-orm/singlestore-core'; import { SQLiteTable } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; From f32c8b872808bb875394448484ae3d656a0aa61f Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 13 Aug 2024 11:20:06 +0100 Subject: [PATCH 150/152] lint fix on drizzle-kit files --- drizzle-kit/src/cli/commands/utils.ts | 18 +- drizzle-kit/src/cli/connections.ts | 2 +- drizzle-kit/src/cli/schema.ts | 41 +++- drizzle-kit/src/introspect-singlestore.ts | 11 +- drizzle-kit/src/jsonStatements.ts | 6 +- drizzle-kit/src/migrationPreparator.ts | 1 - drizzle-kit/src/schemaValidator.ts | 1 - .../src/serializer/singlestoreSerializer.ts | 20 +- drizzle-kit/src/serializer/studio.ts | 10 +- drizzle-kit/src/snapshotsDiffer.ts | 4 +- drizzle-kit/tests/schemaDiffer.ts | 14 -- pnpm-lock.yaml | 221 ++++++------------ 12 files changed, 152 insertions(+), 197 deletions(-) diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index d80b736fe7..d206fd2353 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -16,7 +16,11 @@ import { Prefix, wrapParam, } from '../validations/common'; -import { LibSQLCredentials, libSQLCredentials, printConfigConnectionIssues as printIssuesLibSql } from '../validations/libsql'; +import { + LibSQLCredentials, + libSQLCredentials, + printConfigConnectionIssues as printIssuesLibSql, +} from '../validations/libsql'; import { MysqlCredentials, mysqlCredentials, @@ -28,7 +32,11 @@ import { postgresCredentials, printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; -import { printConfigConnectionIssues as printIssuesSingleStore, singlestoreCredentials, SingleStoreCredentials } from '../validations/singlestore'; +import { + printConfigConnectionIssues as printIssuesSingleStore, + SingleStoreCredentials, + singlestoreCredentials, +} from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSqlite, SqliteCredentials, @@ -216,7 +224,8 @@ export const preparePushConfig = async ( | { dialect: 'turso'; credentials: LibSQLCredentials; - } | { + } + | { dialect: 'singlestore'; credentials: SingleStoreCredentials; } @@ -404,7 +413,8 @@ export const preparePullConfig = async ( | { dialect: 'turso'; credentials: LibSQLCredentials; - } | { + } + | { dialect: 'singlestore'; credentials: SingleStoreCredentials; } diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index f17351dfdc..fccc7def85 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -731,7 +731,7 @@ export const connectToLibSQL = async (credentials: LibSQLCredentials): Promise< "Please install '@libsql/client' for Drizzle Kit to connect to LibSQL databases", ); process.exit(1); -} +}; const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { if ('url' in credentials) { diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index c7d5b88f3f..5316a9e90a 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -24,8 +24,9 @@ import { mkdirSync } from 'fs'; import { renderWithTask } from 'hanji'; import { dialects } from 'src/schemaValidator'; import { assertUnreachable } from '../global'; -import { drizzleForLibSQL, type Setup } from '../serializer/studio'; +import { drizzleForLibSQL, drizzleForSingleStore, prepareSingleStoreSchema, type Setup } from '../serializer/studio'; import { certs } from '../utils/certs'; +import { prepareAndMigrateSingleStore } from './commands/migrate'; import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') @@ -89,6 +90,8 @@ export const generate = command({ await prepareAndMigrateSqlite(opts); } else if (dialect === 'turso') { await prepareAndMigrateLibSQL(opts); + } else if (dialect === 'singlestore') { + await prepareAndMigrateSingleStore(opts); } else { assertUnreachable(dialect); } @@ -173,6 +176,17 @@ export const migrate = command({ migrationsSchema: schema, }), ); + } else if (dialect === 'singlestore') { + const { connectToSingleStore } = await import('./connections'); + const { migrate } = await connectToSingleStore(credentials); + await renderWithTask( + new MigrateProgress(), + migrate({ + migrationsFolder: out, + migrationsTable: table, + migrationsSchema: schema, + }), + ); } else { assertUnreachable(dialect); } @@ -328,6 +342,16 @@ export const push = command({ tablesFilter, force, ); + } else if (dialect === 'singlestore') { + const { singlestorePush } = await import('./commands/push'); + await singlestorePush( + schemaPath, + credentials, + tablesFilter, + strict, + verbose, + force, + ); } else { assertUnreachable(dialect); } @@ -517,6 +541,16 @@ export const pull = command({ tablesFilter, prefix, ); + } else if (dialect === 'singlestore') { + const { introspectSingleStore } = await import('./commands/introspect'); + await introspectSingleStore( + casing, + out, + breakpoints, + credentials, + tablesFilter, + prefix, + ); } else { assertUnreachable(dialect); } @@ -622,6 +656,11 @@ export const studio = command({ ? await prepareSQLiteSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; setup = await drizzleForLibSQL(credentials, schema, relations, files); + } else if (dialect === 'singlestore') { + const { schema, relations, files } = schemaPath + ? await prepareSingleStoreSchema(schemaPath) + : { schema: {}, relations: {}, files: [] }; + setup = await drizzleForSingleStore(credentials, schema, relations, files); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index b9efc537a9..8aa6e3dd72 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -386,16 +386,15 @@ const column = ( ? `${casing(name)}: timestamp("${name}", ${params})` : `${casing(name)}: timestamp("${name}")`; - - // TODO: check if SingleStore has defaultNow() or now() - defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + // TODO: check if SingleStore has defaultNow() or now() + defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' ? '.defaultNow()' : defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; - - out += defaultValue; - + + out += defaultValue; + // TODO: check if SingleStore has onUpdateNow() let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; out += onUpdateNow; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index c4c51d4b40..b27785d9aa 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -6,8 +6,10 @@ import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysq import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { - SQLiteKitInternals, SQLiteSchemaInternal, - SQLiteSchemaSquashed, SQLiteSquasher + SQLiteKitInternals, + SQLiteSchemaInternal, + SQLiteSchemaSquashed, + SQLiteSquasher, } from './serializer/sqliteSchema'; import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer'; diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 3d1ddbea39..4e5664290b 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -5,7 +5,6 @@ import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; import { drySingleStore, SingleStoreSchema, singlestoreSchema } from './serializer/singlestoreSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; -import { drySingleStore, singlestoreSchema, SingleStoreSchema } from './serializer/singlestoreSchema'; export const prepareMySqlDbPushSnapshot = async ( prev: MySqlSchema, diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index 4065e948f6..e91b5ab113 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -3,7 +3,6 @@ import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; -import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso', 'singlestore'] as const; export const dialect = enumType(dialects); diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 3f36f9c215..fc91becf2d 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -11,8 +11,8 @@ import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; -import { sqlToStr } from '.'; import type { DB } from '../utils'; +import { sqlToStr } from '.'; import { Column, Index, @@ -573,15 +573,15 @@ export const fromDatabase = async ( }; } } else { - if (typeof tableInResult.indexes[constraintName] !== 'undefined') { - tableInResult.indexes[constraintName]!.columns.push(columnName); - } else { - tableInResult.indexes[constraintName] = { - name: constraintName, - columns: [columnName], - isUnique: isUnique, - }; - } + if (typeof tableInResult.indexes[constraintName] !== 'undefined') { + tableInResult.indexes[constraintName]!.columns.push(columnName); + } else { + tableInResult.indexes[constraintName] = { + name: constraintName, + columns: [columnName], + isUnique: isUnique, + }; + } } } diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index 14f9a0d2e2..12ea8207c0 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -13,14 +13,14 @@ import { Relations, TablesRelationalConfig, } from 'drizzle-orm'; -import { AnyMySqlTable, MySqlTable, getTableConfig as mysqlTableConfig } from 'drizzle-orm/mysql-core'; -import { AnyPgTable, PgTable, getTableConfig as pgTableConfig } from 'drizzle-orm/pg-core'; +import { AnyMySqlTable, getTableConfig as mysqlTableConfig, MySqlTable } from 'drizzle-orm/mysql-core'; +import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-orm/pg-core'; import { AnySingleStoreTable, - SingleStoreTable, getTableConfig as singlestoreTableConfig, + SingleStoreTable, } from 'drizzle-orm/singlestore-core'; -import { AnySQLiteTable, SQLiteTable, getTableConfig as sqliteTableConfig } from 'drizzle-orm/sqlite-core'; +import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; import { cors } from 'hono/cors'; @@ -29,12 +29,12 @@ import { LibSQLCredentials } from 'src/cli/validations/libsql'; import { assertUnreachable } from 'src/global'; import superjson from 'superjson'; import { z } from 'zod'; -import { prepareFilenames } from '.'; import { safeRegister } from '../cli/commands/utils'; import type { MysqlCredentials } from '../cli/validations/mysql'; import type { PostgresCredentials } from '../cli/validations/postgres'; import type { SingleStoreCredentials } from '../cli/validations/singlestore'; import type { SqliteCredentials } from '../cli/validations/sqlite'; +import { prepareFilenames } from '.'; type CustomDefault = { schema: string; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index ec8a5c1b84..6f27a25056 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -10,7 +10,7 @@ import { string, TypeOf, union, - ZodTypeAny + ZodTypeAny, } from 'zod'; import { applyJsonDiff, diffColumns, diffSchemasOrTables } from './jsonDiffer'; import { fromJson } from './sqlgenerator'; @@ -56,11 +56,11 @@ import { prepareDeleteCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeySingleStore, prepareDeleteCompositePrimaryKeySqlite, + prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, prepareDropEnumJson, prepareDropIndexesJson, prepareDropReferencesJson, - prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDropSequenceJson, prepareDropTableJson, prepareLibSQLCreateReferencesJson, diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index da16dac879..3223ca5e72 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1099,13 +1099,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, undefined, ); @@ -1165,13 +1158,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, statements, sn1, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b41d44802..2870df804c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -313,7 +313,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -361,7 +361,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -4630,10 +4630,6 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - aws-ssl-profiles@1.1.1: - resolution: {integrity: sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==} - engines: {node: '>= 6.0.0'} - axios@1.6.8: resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} @@ -7095,12 +7091,10 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -10206,7 +10200,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) @@ -10293,13 +10287,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0': + '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10336,6 +10330,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10606,7 +10601,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10647,52 +10642,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 - '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.583.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.583.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/core@3.477.0': dependencies: '@smithy/core': 1.4.2 @@ -10933,25 +10882,6 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.577.0 - '@aws-sdk/credential-provider-http': 3.582.0 - '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 @@ -11069,14 +10999,6 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0))': - dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/client-sts': 3.583.0 @@ -11280,7 +11202,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11289,7 +11211,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -12961,7 +12883,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12979,7 +12901,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13553,10 +13475,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -13693,7 +13615,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13703,7 +13625,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13730,14 +13652,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13826,16 +13748,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13850,7 +13772,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13864,7 +13786,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13887,12 +13809,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -15469,9 +15391,6 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - aws-ssl-profiles@1.1.1: - optional: true - axios@1.6.8: dependencies: follow-redirects: 1.15.6 @@ -16357,7 +16276,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20240524.0 @@ -16371,9 +16290,9 @@ snapshots: '@vercel/postgres': 0.8.0 better-sqlite3: 9.6.0 bun-types: 1.0.3 - knex: 2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7) + knex: 2.5.1(better-sqlite3@9.6.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) kysely: 0.25.0 - mysql2: 3.11.0 + mysql2: 3.3.3 pg: 8.11.5 postgres: 3.4.4 sql.js: 1.10.3 @@ -17198,35 +17117,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17240,24 +17159,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18364,7 +18283,7 @@ snapshots: transitivePeerDependencies: - supports-color - knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 @@ -18382,7 +18301,7 @@ snapshots: tildify: 2.0.0 optionalDependencies: better-sqlite3: 9.6.0 - mysql2: 3.11.0 + mysql2: 3.3.3 pg: 8.11.5 sqlite3: 5.1.7 transitivePeerDependencies: @@ -18731,12 +18650,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18812,13 +18731,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18832,7 +18751,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18858,7 +18777,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18866,7 +18785,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18875,7 +18794,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19748,10 +19667,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19764,19 +19683,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19795,14 +19714,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21655,15 +21574,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 28876e6d53e0141f3bf6922c507d3021bbc51557 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Fri, 20 Sep 2024 14:12:50 +0100 Subject: [PATCH 151/152] adding missing driver declaration in drizzle-orm --- drizzle-kit/src/cli/commands/singlestoreUp.ts | 1 + drizzle-kit/src/cli/commands/utils.ts | 6 ++--- drizzle-kit/src/cli/schema.ts | 27 +++++++++++-------- drizzle-orm/src/monodriver.ts | 20 +++++++++++++- drizzle-orm/src/monomigrator.ts | 9 ++++++- 5 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 drizzle-kit/src/cli/commands/singlestoreUp.ts diff --git a/drizzle-kit/src/cli/commands/singlestoreUp.ts b/drizzle-kit/src/cli/commands/singlestoreUp.ts new file mode 100644 index 0000000000..dc5004ed09 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreUp.ts @@ -0,0 +1 @@ +export const upSinglestoreHandler = (out: string) => {}; diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index d206fd2353..25e80ed4d6 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -334,7 +334,7 @@ export const preparePushConfig = async ( if (config.dialect === 'singlestore') { const parsed = singlestoreCredentials.safeParse(config); if (!parsed.success) { - printIssuesPg(config); + printIssuesSingleStore(config); process.exit(1); } @@ -508,7 +508,7 @@ export const preparePullConfig = async ( if (dialect === 'singlestore') { const parsed = singlestoreCredentials.safeParse(config); if (!parsed.success) { - printIssuesPg(config); + printIssuesSingleStore(config); process.exit(1); } @@ -617,7 +617,7 @@ export const prepareStudioConfig = async (options: Record) => { if (dialect === 'singlestore') { const parsed = singlestoreCredentials.safeParse(flattened); if (!parsed.success) { - printIssuesPg(flattened as Record); + printIssuesSingleStore(flattened as Record); process.exit(1); } const credentials = parsed.data; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 5316a9e90a..6b7bcb5603 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -1,11 +1,20 @@ +import { boolean, command, number, string } from '@drizzle-team/brocli'; import chalk from 'chalk'; -import { checkHandler } from './commands/check'; -import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; +import 'dotenv/config'; +import { mkdirSync } from 'fs'; +import { renderWithTask } from 'hanji'; +import { dialects } from 'src/schemaValidator'; import '../@types/utils'; +import { assertUnreachable } from '../global'; +import { drizzleForLibSQL, drizzleForSingleStore, prepareSingleStoreSchema, type Setup } from '../serializer/studio'; import { assertV1OutFolder } from '../utils'; +import { certs } from '../utils/certs'; +import { checkHandler } from './commands/check'; import { dropMigration } from './commands/drop'; +import { prepareAndMigrateSingleStore } from './commands/migrate'; import { upMysqlHandler } from './commands/mysqlUp'; import { upPgHandler } from './commands/pgUp'; +import { upSinglestoreHandler } from './commands/singlestoreUp'; import { upSqliteHandler } from './commands/sqliteUp'; import { prepareCheckParams, @@ -16,17 +25,9 @@ import { preparePushConfig, prepareStudioConfig, } from './commands/utils'; +import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; import { assertCollisions, drivers, prefixes } from './validations/common'; import { withStyle } from './validations/outputs'; -import 'dotenv/config'; -import { boolean, command, number, string } from '@drizzle-team/brocli'; -import { mkdirSync } from 'fs'; -import { renderWithTask } from 'hanji'; -import { dialects } from 'src/schemaValidator'; -import { assertUnreachable } from '../global'; -import { drizzleForLibSQL, drizzleForSingleStore, prepareSingleStoreSchema, type Setup } from '../serializer/studio'; -import { certs } from '../utils/certs'; -import { prepareAndMigrateSingleStore } from './commands/migrate'; import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') @@ -407,6 +408,10 @@ export const up = command({ upMysqlHandler(out); } + if (dialect === 'singlestore') { + upSinglestoreHandler(out); + } + if (dialect === 'sqlite' || dialect === 'turso') { upSqliteHandler(out); } diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 0706f271a7..03fcdc58f2 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -30,6 +30,7 @@ import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/index.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; import type { PostgresJsDatabase } from './postgres-js/index.ts'; +import type { SingleStore2Database, SingleStore2DrizzleConfig } from './singlestore/driver.ts'; import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; import type { DrizzleConfig } from './utils.ts'; import type { VercelPgDatabase } from './vercel-postgres/index.ts'; @@ -98,7 +99,8 @@ type DatabaseClient = | 'libsql' | 'd1' | 'bun:sqlite' - | 'better-sqlite3'; + | 'better-sqlite3' + | 'singlestore'; type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; @@ -114,6 +116,7 @@ type ClientDrizzleInstanceMap> = { d1: DrizzleD1Database; 'bun:sqlite': BunSQLiteDatabase; 'better-sqlite3': DrizzleBetterSQLite3Database; + singlestore: SingleStore2Database; }; type ClientInstanceMap = { @@ -135,6 +138,7 @@ type ClientInstanceMap = { d1: D1Database; 'bun:sqlite': BunDatabase; 'better-sqlite3': BetterSQLite3Database; + singlestore: SingleStore2Database; }; type InitializerParams = { @@ -177,6 +181,10 @@ type InitializerParams = { 'better-sqlite3': { connection?: BetterSQLite3DatabaseConfig; }; + singlestore: { + // This Mysql2Config is from the node package 'mysql2' and not the one from Drizzle + connection: Mysql2Config; + }; }; type DetermineClient< @@ -379,6 +387,16 @@ export async function drizzle< const db = drizzle(sql, drizzleConfig) as any; db.$client = sql; + return db; + } + case 'singlestore': { + const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); + const instance = createPool(connection as Mysql2Config); + const { drizzle } = await import('./mysql2'); + + const db = drizzle(instance, drizzleConfig as SingleStore2DrizzleConfig) as any; + db.$client = instance; + return db; } } diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index bee18ad461..d8681ebf95 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -12,6 +12,7 @@ import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/index.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; import type { PostgresJsDatabase } from './postgres-js/index.ts'; +import type { SingleStore2Database } from './singlestore/driver.ts'; import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; import type { VercelPgDatabase } from './vercel-postgres/index.ts'; @@ -29,7 +30,8 @@ export async function migrate( | PlanetScaleDatabase | PostgresJsDatabase | VercelPgDatabase - | TiDBServerlessDatabase, + | TiDBServerlessDatabase + | SingleStore2Database, config: | string | MigrationConfig, @@ -100,5 +102,10 @@ export async function migrate( return migrate(db as VercelPgDatabase, config as string | MigrationConfig); } + case 'SingleStore2Database': { + const { migrate } = await import('./singlestore/migrator'); + + return migrate(db as SingleStore2Database, config as MigrationConfig); + } } } From 83ba948cc82d921ceea051b950f28cd744eae2e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:20:35 +0000 Subject: [PATCH 152/152] Bump serve-static and express in /examples/pg-proxy Bumps [serve-static](https://github.com/expressjs/serve-static) to 1.16.2 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together. Updates `serve-static` from 1.15.0 to 1.16.2 - [Release notes](https://github.com/expressjs/serve-static/releases) - [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md) - [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2) Updates `express` from 4.18.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.18.2...4.21.0) --- updated-dependencies: - dependency-name: serve-static dependency-type: indirect - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- examples/pg-proxy/package-lock.json | 272 +++++++++++++++++++--------- examples/pg-proxy/package.json | 2 +- 2 files changed, 189 insertions(+), 85 deletions(-) diff --git a/examples/pg-proxy/package-lock.json b/examples/pg-proxy/package-lock.json index 0dcfbee7b6..4f0fa429f6 100644 --- a/examples/pg-proxy/package-lock.json +++ b/examples/pg-proxy/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "axios": "^1.5.1", - "express": "^4.18.2", + "express": "^4.21.0", "express-rate-limit": "^7.0.2", "pg": "^8.11.3" }, @@ -601,20 +601,20 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", + "qs": "6.13.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -655,12 +655,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -746,9 +752,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -776,6 +782,22 @@ "ms": "2.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -854,13 +876,32 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es5-ext": { "version": "0.10.62", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", @@ -1005,36 +1046,36 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1072,12 +1113,12 @@ "dev": true }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1157,19 +1198,26 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1218,6 +1266,17 @@ "node": ">=10" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hanji": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/hanji/-/hanji-0.0.5.tgz", @@ -1228,21 +1287,21 @@ "sisteransi": "^1.0.5" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { - "function-bind": "^1.1.1" + "es-define-property": "^1.0.0" }, - "engines": { - "node": ">= 0.4.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { "node": ">= 0.4" }, @@ -1261,6 +1320,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/heap": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", @@ -1379,9 +1449,12 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/methods": { "version": "1.1.2", @@ -1456,9 +1529,12 @@ "dev": true }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1503,9 +1579,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "node_modules/pg": { "version": "8.11.3", @@ -1658,11 +1734,11 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1680,9 +1756,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -1727,9 +1803,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -1749,38 +1825,66 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" diff --git a/examples/pg-proxy/package.json b/examples/pg-proxy/package.json index 1440f40475..7804fd9c1f 100644 --- a/examples/pg-proxy/package.json +++ b/examples/pg-proxy/package.json @@ -13,7 +13,7 @@ "license": "ISC", "dependencies": { "axios": "^1.5.1", - "express": "^4.18.2", + "express": "^4.21.0", "express-rate-limit": "^7.0.2", "pg": "^8.11.3" },