drizzle-orm 1.0.0-beta.21 → 1.0.0-beta.22-1b8fcb2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/aws-data-api/common/index.d.cts +1 -1
  2. package/aws-data-api/common/index.d.ts +1 -1
  3. package/cache/core/cache-effect.d.cts +1 -1
  4. package/cache/core/cache-effect.d.ts +1 -1
  5. package/cache/upstash/cache.d.cts +1 -1
  6. package/cache/upstash/cache.d.ts +1 -1
  7. package/effect-postgres/migrator.d.cts +1 -1
  8. package/effect-postgres/migrator.d.ts +1 -1
  9. package/mssql-core/columns/real.cjs +3 -0
  10. package/mssql-core/columns/real.cjs.map +1 -1
  11. package/mssql-core/columns/real.d.cts +1 -0
  12. package/mssql-core/columns/real.d.ts +1 -0
  13. package/mssql-core/columns/real.js +3 -0
  14. package/mssql-core/columns/real.js.map +1 -1
  15. package/package.cjs +1 -1
  16. package/package.js +1 -1
  17. package/package.json +13 -1
  18. package/pg-core/effect/session.d.cts +1 -1
  19. package/pg-core/effect/session.d.ts +1 -1
  20. package/sqlite-proxy/migrator.cjs +2 -40
  21. package/sqlite-proxy/migrator.cjs.map +1 -1
  22. package/sqlite-proxy/migrator.internal.cjs +61 -0
  23. package/sqlite-proxy/migrator.internal.cjs.map +1 -0
  24. package/sqlite-proxy/migrator.internal.d.cts +26 -0
  25. package/sqlite-proxy/migrator.internal.d.ts +26 -0
  26. package/sqlite-proxy/migrator.internal.js +59 -0
  27. package/sqlite-proxy/migrator.internal.js.map +1 -0
  28. package/sqlite-proxy/migrator.js +2 -39
  29. package/sqlite-proxy/migrator.js.map +1 -1
  30. package/up-migrations/sqlite.cjs +16 -13
  31. package/up-migrations/sqlite.cjs.map +1 -1
  32. package/up-migrations/sqlite.d.cts +1 -1
  33. package/up-migrations/sqlite.d.ts +1 -1
  34. package/up-migrations/sqlite.js +16 -13
  35. package/up-migrations/sqlite.js.map +1 -1
@@ -4,7 +4,7 @@ import { Field, TypeHint } from "@aws-sdk/client-rds-data";
4
4
 
5
5
  //#region src/aws-data-api/common/index.d.ts
6
6
  declare const typeHint: { [K in TypeHint]: K };
7
- declare function getValueFromDataApi(field: Field): string | number | boolean | string[] | number[] | Uint8Array<ArrayBufferLike> | boolean[] | _aws_sdk_client_rds_data0.ArrayValue[] | null;
7
+ declare function getValueFromDataApi(field: Field): string | number | boolean | string[] | Uint8Array<ArrayBufferLike> | number[] | boolean[] | _aws_sdk_client_rds_data0.ArrayValue[] | null;
8
8
  declare function typingsToAwsTypeHint(typings?: QueryTypingsValue): TypeHint | undefined;
9
9
  declare function toValueParam(value: any, typings?: QueryTypingsValue): {
10
10
  value: Field;
@@ -4,7 +4,7 @@ import { Field, TypeHint } from "@aws-sdk/client-rds-data";
4
4
 
5
5
  //#region src/aws-data-api/common/index.d.ts
6
6
  declare const typeHint: { [K in TypeHint]: K };
7
- declare function getValueFromDataApi(field: Field): string | number | boolean | string[] | number[] | Uint8Array<ArrayBufferLike> | boolean[] | _aws_sdk_client_rds_data0.ArrayValue[] | null;
7
+ declare function getValueFromDataApi(field: Field): string | number | boolean | string[] | Uint8Array<ArrayBufferLike> | number[] | boolean[] | _aws_sdk_client_rds_data0.ArrayValue[] | null;
8
8
  declare function typingsToAwsTypeHint(typings?: QueryTypingsValue): TypeHint | undefined;
9
9
  declare function toValueParam(value: any, typings?: QueryTypingsValue): {
10
10
  value: Field;
@@ -8,7 +8,7 @@ import * as Schema$1 from "effect/Schema";
8
8
  //#region src/cache/core/cache-effect.d.ts
9
9
  declare const EffectCache_base: Effect.Service.Class<EffectCache, "drizzle-orm/EffectCache", {
10
10
  readonly sync: () => {
11
- strategy: () => "all" | "explicit";
11
+ strategy: () => "explicit" | "all";
12
12
  get: (key: string, tables: string[], isTag: boolean, isAutoInvalidate?: boolean | undefined) => Effect.Effect<any[] | undefined, EffectCacheError, never>;
13
13
  put: (hashedQuery: string, response: any, tables: string[], isTag: boolean, config?: CacheConfig | undefined) => Effect.Effect<void, EffectCacheError, never>;
14
14
  onMutate: (params: MutationOption) => Effect.Effect<void, EffectCacheError, never>;
@@ -8,7 +8,7 @@ import * as Schema$1 from "effect/Schema";
8
8
  //#region src/cache/core/cache-effect.d.ts
9
9
  declare const EffectCache_base: Effect.Service.Class<EffectCache, "drizzle-orm/EffectCache", {
10
10
  readonly sync: () => {
11
- strategy: () => "all" | "explicit";
11
+ strategy: () => "explicit" | "all";
12
12
  get: (key: string, tables: string[], isTag: boolean, isAutoInvalidate?: boolean | undefined) => Effect.Effect<any[] | undefined, EffectCacheError, never>;
13
13
  put: (hashedQuery: string, response: any, tables: string[], isTag: boolean, config?: CacheConfig | undefined) => Effect.Effect<void, EffectCacheError, never>;
14
14
  onMutate: (params: MutationOption) => Effect.Effect<void, EffectCacheError, never>;
@@ -44,7 +44,7 @@ declare class UpstashCache extends Cache {
44
44
  private luaScripts;
45
45
  private internalConfig;
46
46
  constructor(redis: Redis, config?: CacheConfig, useGlobally?: boolean | undefined);
47
- strategy(): "all" | "explicit";
47
+ strategy(): "explicit" | "all";
48
48
  private toInternalConfig;
49
49
  get(key: string, tables: string[], isTag?: boolean, isAutoInvalidate?: boolean): Promise<any[] | undefined>;
50
50
  put(key: string, response: any, tables: string[], isTag?: boolean, config?: CacheConfig): Promise<void>;
@@ -44,7 +44,7 @@ declare class UpstashCache extends Cache {
44
44
  private luaScripts;
45
45
  private internalConfig;
46
46
  constructor(redis: Redis, config?: CacheConfig, useGlobally?: boolean | undefined);
47
- strategy(): "all" | "explicit";
47
+ strategy(): "explicit" | "all";
48
48
  private toInternalConfig;
49
49
  get(key: string, tables: string[], isTag?: boolean, isAutoInvalidate?: boolean): Promise<any[] | undefined>;
50
50
  put(key: string, response: any, tables: string[], isTag?: boolean, config?: CacheConfig): Promise<void>;
@@ -6,7 +6,7 @@ import * as effect_Effect0 from "effect/Effect";
6
6
  import * as _effect_sql_SqlError0 from "@effect/sql/SqlError";
7
7
 
8
8
  //#region src/effect-postgres/migrator.d.ts
9
- declare function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(db: EffectPgDatabase<TSchema, TRelations>, config: MigrationConfig): effect_Effect0.Effect<undefined, MigratorInitError | EffectDrizzleQueryError | _effect_sql_SqlError0.SqlError, never>;
9
+ declare function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(db: EffectPgDatabase<TSchema, TRelations>, config: MigrationConfig): effect_Effect0.Effect<undefined, EffectDrizzleQueryError | _effect_sql_SqlError0.SqlError | MigratorInitError, never>;
10
10
  //#endregion
11
11
  export { migrate };
12
12
  //# sourceMappingURL=migrator.d.cts.map
@@ -6,7 +6,7 @@ import { AnyRelations } from "../relations.js";
6
6
  import * as _effect_sql_SqlError0 from "@effect/sql/SqlError";
7
7
 
8
8
  //#region src/effect-postgres/migrator.d.ts
9
- declare function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(db: EffectPgDatabase<TSchema, TRelations>, config: MigrationConfig): effect_Effect0.Effect<undefined, MigratorInitError | EffectDrizzleQueryError | _effect_sql_SqlError0.SqlError, never>;
9
+ declare function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(db: EffectPgDatabase<TSchema, TRelations>, config: MigrationConfig): effect_Effect0.Effect<undefined, EffectDrizzleQueryError | _effect_sql_SqlError0.SqlError | MigratorInitError, never>;
10
10
  //#endregion
11
11
  export { migrate };
12
12
  //# sourceMappingURL=migrator.d.ts.map
@@ -19,6 +19,9 @@ var MsSqlReal = class extends require_mssql_core_columns_common.MsSqlColumnWithI
19
19
  getSQLType() {
20
20
  return "real";
21
21
  }
22
+ mapFromDriverValue(value) {
23
+ return parseFloat(value.toPrecision(7));
24
+ }
22
25
  };
23
26
  function real(name) {
24
27
  return new MsSqlRealBuilder(name ?? "");
@@ -1 +1 @@
1
- {"version":3,"file":"real.cjs","names":["MsSqlColumnBuilderWithIdentity","entityKind","MsSqlColumnWithIdentity"],"sources":["../../../src/mssql-core/columns/real.ts"],"sourcesContent":["import type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { AnyMsSqlTable } from '~/mssql-core/table.ts';\nimport { MsSqlColumnBuilderWithIdentity, MsSqlColumnWithIdentity } from './common.ts';\n\nexport class MsSqlRealBuilder extends MsSqlColumnBuilderWithIdentity<{\n\tdataType: 'number float';\n\tdata: number;\n\tdriverParam: number;\n}> {\n\tstatic override readonly [entityKind]: string = 'MsSqlRealBuilder';\n\n\tconstructor(name: string) {\n\t\tsuper(name, 'number float', 'MsSqlReal');\n\t}\n\n\t/** @internal */\n\toverride build<TTableName extends string>(\n\t\ttable: AnyMsSqlTable<{ name: TTableName }>,\n\t) {\n\t\treturn new MsSqlReal(table, this.config);\n\t}\n}\n\nexport class MsSqlReal<T extends ColumnBaseConfig<'number float'>> extends MsSqlColumnWithIdentity<T> {\n\tstatic override readonly [entityKind]: string = 'MsSqlReal';\n\n\tgetSQLType(): string {\n\t\treturn 'real';\n\t}\n}\n\nexport function real(name?: string) {\n\treturn new MsSqlRealBuilder(name ?? '');\n}\n"],"mappings":";;;;;;AAKA,IAAa,mBAAb,cAAsCA,iEAInC;CACF,QAA0BC,0BAAsB;CAEhD,YAAY,MAAc;AACzB,QAAM,MAAM,gBAAgB,YAAY;;;CAIzC,AAAS,MACR,OACC;AACD,SAAO,IAAI,UAAU,OAAO,KAAK,OAAO;;;AAI1C,IAAa,YAAb,cAA2EC,0DAA2B;CACrG,QAA0BD,0BAAsB;CAEhD,aAAqB;AACpB,SAAO;;;AAIT,SAAgB,KAAK,MAAe;AACnC,QAAO,IAAI,iBAAiB,QAAQ,GAAG"}
1
+ {"version":3,"file":"real.cjs","names":["MsSqlColumnBuilderWithIdentity","entityKind","MsSqlColumnWithIdentity"],"sources":["../../../src/mssql-core/columns/real.ts"],"sourcesContent":["import type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { AnyMsSqlTable } from '~/mssql-core/table.ts';\nimport { MsSqlColumnBuilderWithIdentity, MsSqlColumnWithIdentity } from './common.ts';\n\nexport class MsSqlRealBuilder extends MsSqlColumnBuilderWithIdentity<{\n\tdataType: 'number float';\n\tdata: number;\n\tdriverParam: number;\n}> {\n\tstatic override readonly [entityKind]: string = 'MsSqlRealBuilder';\n\n\tconstructor(name: string) {\n\t\tsuper(name, 'number float', 'MsSqlReal');\n\t}\n\n\t/** @internal */\n\toverride build<TTableName extends string>(\n\t\ttable: AnyMsSqlTable<{ name: TTableName }>,\n\t) {\n\t\treturn new MsSqlReal(table, this.config);\n\t}\n}\n\nexport class MsSqlReal<T extends ColumnBaseConfig<'number float'>> extends MsSqlColumnWithIdentity<T> {\n\tstatic override readonly [entityKind]: string = 'MsSqlReal';\n\n\tgetSQLType(): string {\n\t\treturn 'real';\n\t}\n\n\toverride mapFromDriverValue(value: number): number {\n\t\treturn parseFloat(value.toPrecision(7));\n\t}\n}\n\nexport function real(name?: string) {\n\treturn new MsSqlRealBuilder(name ?? '');\n}\n"],"mappings":";;;;;;AAKA,IAAa,mBAAb,cAAsCA,iEAInC;CACF,QAA0BC,0BAAsB;CAEhD,YAAY,MAAc;AACzB,QAAM,MAAM,gBAAgB,YAAY;;;CAIzC,AAAS,MACR,OACC;AACD,SAAO,IAAI,UAAU,OAAO,KAAK,OAAO;;;AAI1C,IAAa,YAAb,cAA2EC,0DAA2B;CACrG,QAA0BD,0BAAsB;CAEhD,aAAqB;AACpB,SAAO;;CAGR,AAAS,mBAAmB,OAAuB;AAClD,SAAO,WAAW,MAAM,YAAY,EAAE,CAAC;;;AAIzC,SAAgB,KAAK,MAAe;AACnC,QAAO,IAAI,iBAAiB,QAAQ,GAAG"}
@@ -14,6 +14,7 @@ declare class MsSqlRealBuilder extends MsSqlColumnBuilderWithIdentity<{
14
14
  declare class MsSqlReal<T extends ColumnBaseConfig<'number float'>> extends MsSqlColumnWithIdentity<T> {
15
15
  static readonly [entityKind]: string;
16
16
  getSQLType(): string;
17
+ mapFromDriverValue(value: number): number;
17
18
  }
18
19
  declare function real(name?: string): MsSqlRealBuilder;
19
20
  //#endregion
@@ -14,6 +14,7 @@ declare class MsSqlRealBuilder extends MsSqlColumnBuilderWithIdentity<{
14
14
  declare class MsSqlReal<T extends ColumnBaseConfig<'number float'>> extends MsSqlColumnWithIdentity<T> {
15
15
  static readonly [entityKind]: string;
16
16
  getSQLType(): string;
17
+ mapFromDriverValue(value: number): number;
17
18
  }
18
19
  declare function real(name?: string): MsSqlRealBuilder;
19
20
  //#endregion
@@ -17,6 +17,9 @@ var MsSqlReal = class extends MsSqlColumnWithIdentity {
17
17
  getSQLType() {
18
18
  return "real";
19
19
  }
20
+ mapFromDriverValue(value) {
21
+ return parseFloat(value.toPrecision(7));
22
+ }
20
23
  };
21
24
  function real(name) {
22
25
  return new MsSqlRealBuilder(name ?? "");
@@ -1 +1 @@
1
- {"version":3,"file":"real.js","names":[],"sources":["../../../src/mssql-core/columns/real.ts"],"sourcesContent":["import type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { AnyMsSqlTable } from '~/mssql-core/table.ts';\nimport { MsSqlColumnBuilderWithIdentity, MsSqlColumnWithIdentity } from './common.ts';\n\nexport class MsSqlRealBuilder extends MsSqlColumnBuilderWithIdentity<{\n\tdataType: 'number float';\n\tdata: number;\n\tdriverParam: number;\n}> {\n\tstatic override readonly [entityKind]: string = 'MsSqlRealBuilder';\n\n\tconstructor(name: string) {\n\t\tsuper(name, 'number float', 'MsSqlReal');\n\t}\n\n\t/** @internal */\n\toverride build<TTableName extends string>(\n\t\ttable: AnyMsSqlTable<{ name: TTableName }>,\n\t) {\n\t\treturn new MsSqlReal(table, this.config);\n\t}\n}\n\nexport class MsSqlReal<T extends ColumnBaseConfig<'number float'>> extends MsSqlColumnWithIdentity<T> {\n\tstatic override readonly [entityKind]: string = 'MsSqlReal';\n\n\tgetSQLType(): string {\n\t\treturn 'real';\n\t}\n}\n\nexport function real(name?: string) {\n\treturn new MsSqlRealBuilder(name ?? '');\n}\n"],"mappings":";;;;AAKA,IAAa,mBAAb,cAAsC,+BAInC;CACF,QAA0B,cAAsB;CAEhD,YAAY,MAAc;AACzB,QAAM,MAAM,gBAAgB,YAAY;;;CAIzC,AAAS,MACR,OACC;AACD,SAAO,IAAI,UAAU,OAAO,KAAK,OAAO;;;AAI1C,IAAa,YAAb,cAA2E,wBAA2B;CACrG,QAA0B,cAAsB;CAEhD,aAAqB;AACpB,SAAO;;;AAIT,SAAgB,KAAK,MAAe;AACnC,QAAO,IAAI,iBAAiB,QAAQ,GAAG"}
1
+ {"version":3,"file":"real.js","names":[],"sources":["../../../src/mssql-core/columns/real.ts"],"sourcesContent":["import type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { AnyMsSqlTable } from '~/mssql-core/table.ts';\nimport { MsSqlColumnBuilderWithIdentity, MsSqlColumnWithIdentity } from './common.ts';\n\nexport class MsSqlRealBuilder extends MsSqlColumnBuilderWithIdentity<{\n\tdataType: 'number float';\n\tdata: number;\n\tdriverParam: number;\n}> {\n\tstatic override readonly [entityKind]: string = 'MsSqlRealBuilder';\n\n\tconstructor(name: string) {\n\t\tsuper(name, 'number float', 'MsSqlReal');\n\t}\n\n\t/** @internal */\n\toverride build<TTableName extends string>(\n\t\ttable: AnyMsSqlTable<{ name: TTableName }>,\n\t) {\n\t\treturn new MsSqlReal(table, this.config);\n\t}\n}\n\nexport class MsSqlReal<T extends ColumnBaseConfig<'number float'>> extends MsSqlColumnWithIdentity<T> {\n\tstatic override readonly [entityKind]: string = 'MsSqlReal';\n\n\tgetSQLType(): string {\n\t\treturn 'real';\n\t}\n\n\toverride mapFromDriverValue(value: number): number {\n\t\treturn parseFloat(value.toPrecision(7));\n\t}\n}\n\nexport function real(name?: string) {\n\treturn new MsSqlRealBuilder(name ?? '');\n}\n"],"mappings":";;;;AAKA,IAAa,mBAAb,cAAsC,+BAInC;CACF,QAA0B,cAAsB;CAEhD,YAAY,MAAc;AACzB,QAAM,MAAM,gBAAgB,YAAY;;;CAIzC,AAAS,MACR,OACC;AACD,SAAO,IAAI,UAAU,OAAO,KAAK,OAAO;;;AAI1C,IAAa,YAAb,cAA2E,wBAA2B;CACrG,QAA0B,cAAsB;CAEhD,aAAqB;AACpB,SAAO;;CAGR,AAAS,mBAAmB,OAAuB;AAClD,SAAO,WAAW,MAAM,YAAY,EAAE,CAAC;;;AAIzC,SAAgB,KAAK,MAAe;AACnC,QAAO,IAAI,iBAAiB,QAAQ,GAAG"}
package/package.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  //#region package.json
3
- var version = "1.0.0-beta.21";
3
+ var version = "1.0.0-beta.22";
4
4
 
5
5
  //#endregion
6
6
  Object.defineProperty(exports, 'version', {
package/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "1.0.0-beta.21";
2
+ var version = "1.0.0-beta.22";
3
3
 
4
4
  //#endregion
5
5
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drizzle-orm",
3
- "version": "1.0.0-beta.21",
3
+ "version": "1.0.0-beta.22-1b8fcb2",
4
4
  "description": "Drizzle ORM package for SQL databases",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1438,6 +1438,18 @@
1438
1438
  "types": "./sqlite-proxy/index.d.ts",
1439
1439
  "default": "./sqlite-proxy/index.js"
1440
1440
  },
1441
+ "./sqlite-proxy/migrator.internal": {
1442
+ "import": {
1443
+ "types": "./sqlite-proxy/migrator.internal.d.ts",
1444
+ "default": "./sqlite-proxy/migrator.internal.js"
1445
+ },
1446
+ "require": {
1447
+ "types": "./sqlite-proxy/migrator.internal.d.cts",
1448
+ "default": "./sqlite-proxy/migrator.internal.cjs"
1449
+ },
1450
+ "types": "./sqlite-proxy/migrator.internal.d.ts",
1451
+ "default": "./sqlite-proxy/migrator.internal.js"
1452
+ },
1441
1453
  "./sqlite-proxy/migrator": {
1442
1454
  "import": {
1443
1455
  "types": "./sqlite-proxy/migrator.d.ts",
@@ -56,7 +56,7 @@ declare abstract class PgEffectTransaction<TEffectHKT extends QueryEffectHKTBase
56
56
  rollback(): EffectTransactionRollbackError;
57
57
  setTransaction(config: PgTransactionConfig): QueryEffectKind<TEffectHKT, void>;
58
58
  }
59
- declare const migrate: <TEffectHKT extends QueryEffectHKTBase>(migrations: MigrationMeta[], session: PgEffectSession<TEffectHKT, PgQueryResultHKT, Record<string, never>, EmptyRelations, V1.ExtractTablesWithRelations<Record<string, never>>>, config: string | MigrationConfig) => Effect.Effect<undefined, MigratorInitError | TEffectHKT["error"] | SqlError, TEffectHKT["context"]>;
59
+ declare const migrate: <TEffectHKT extends QueryEffectHKTBase>(migrations: MigrationMeta[], session: PgEffectSession<TEffectHKT, PgQueryResultHKT, Record<string, never>, EmptyRelations, V1.ExtractTablesWithRelations<Record<string, never>>>, config: string | MigrationConfig) => Effect.Effect<undefined, SqlError | MigratorInitError | TEffectHKT["error"], TEffectHKT["context"]>;
60
60
  //#endregion
61
61
  export { PgEffectPreparedQuery, PgEffectSession, PgEffectTransaction, migrate };
62
62
  //# sourceMappingURL=session.d.cts.map
@@ -56,7 +56,7 @@ declare abstract class PgEffectTransaction<TEffectHKT extends QueryEffectHKTBase
56
56
  rollback(): EffectTransactionRollbackError;
57
57
  setTransaction(config: PgTransactionConfig): QueryEffectKind<TEffectHKT, void>;
58
58
  }
59
- declare const migrate: <TEffectHKT extends QueryEffectHKTBase>(migrations: MigrationMeta[], session: PgEffectSession<TEffectHKT, PgQueryResultHKT, Record<string, never>, EmptyRelations, V1.ExtractTablesWithRelations<Record<string, never>>>, config: string | MigrationConfig) => Effect.Effect<undefined, MigratorInitError | TEffectHKT["error"] | SqlError, TEffectHKT["context"]>;
59
+ declare const migrate: <TEffectHKT extends QueryEffectHKTBase>(migrations: MigrationMeta[], session: PgEffectSession<TEffectHKT, PgQueryResultHKT, Record<string, never>, EmptyRelations, V1.ExtractTablesWithRelations<Record<string, never>>>, config: string | MigrationConfig) => Effect.Effect<undefined, SqlError | MigratorInitError | TEffectHKT["error"], TEffectHKT["context"]>;
60
60
  //#endregion
61
61
  export { PgEffectPreparedQuery, PgEffectSession, PgEffectTransaction, migrate };
62
62
  //# sourceMappingURL=session.d.ts.map
@@ -1,47 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
- let __sql_sql_ts = require("../sql/sql.cjs");
4
- let __migrator_ts = require("../migrator.cjs");
5
- let __migrator_utils_ts = require("../migrator.utils.cjs");
6
- let __up_migrations_sqlite_ts = require("../up-migrations/sqlite.cjs");
2
+ const require_sqlite_proxy_migrator_internal = require('./migrator.internal.cjs');
7
3
 
8
4
  //#region src/sqlite-proxy/migrator.ts
9
5
  async function migrate(db, callback, config) {
10
- const migrations = (0, __migrator_ts.readMigrationFiles)(config);
11
- const migrationsTable = typeof config === "string" ? "__drizzle_migrations" : config.migrationsTable ?? "__drizzle_migrations";
12
- const { newDb } = await (0, __up_migrations_sqlite_ts.upgradeAsyncIfNeeded)(migrationsTable, db.session, migrations);
13
- if (newDb) {
14
- const migrationTableCreate = __sql_sql_ts.sql`
15
- CREATE TABLE IF NOT EXISTS ${__sql_sql_ts.sql.identifier(migrationsTable)} (
16
- id INTEGER PRIMARY KEY,
17
- hash text NOT NULL,
18
- created_at numeric,
19
- name text,
20
- applied_at TEXT
21
- );`;
22
- await db.run(migrationTableCreate);
23
- }
24
- const dbMigrations = (await db.values(__sql_sql_ts.sql`SELECT id, hash, created_at, name FROM ${__sql_sql_ts.sql.identifier(migrationsTable)}`)).map(([id, hash, created_at, name]) => ({
25
- id,
26
- hash,
27
- created_at,
28
- name
29
- }));
30
- if (typeof config === "object" && config.init) {
31
- if (dbMigrations.length) return { exitCode: "databaseMigrations" };
32
- if (migrations.length > 1) return { exitCode: "localMigrations" };
33
- const [migration] = migrations;
34
- if (!migration) return;
35
- await callback([db.dialect.sqlToQuery(__sql_sql_ts.sql`insert into ${__sql_sql_ts.sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql]);
36
- return;
37
- }
38
- const migrationsToRun = (0, __migrator_utils_ts.getMigrationsToRun)({
39
- localMigrations: migrations,
40
- dbMigrations
41
- });
42
- const queriesToRun = [];
43
- for (const migration of migrationsToRun) queriesToRun.push(...migration.sql, db.dialect.sqlToQuery(__sql_sql_ts.sql`insert into ${__sql_sql_ts.sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql);
44
- await callback(queriesToRun);
6
+ return require_sqlite_proxy_migrator_internal.migrateInternal(db, callback, config, "transaction");
45
7
  }
46
8
 
47
9
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"migrator.cjs","names":["sql"],"sources":["../../src/sqlite-proxy/migrator.ts"],"sourcesContent":["import type { MigrationConfig } from '~/migrator.ts';\nimport { readMigrationFiles } from '~/migrator.ts';\nimport { getMigrationsToRun } from '~/migrator.utils.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { sql } from '~/sql/sql.ts';\nimport { upgradeAsyncIfNeeded } from '~/up-migrations/sqlite.ts';\nimport type { SqliteRemoteDatabase } from './driver.ts';\n\nexport type ProxyMigrator = (migrationQueries: string[]) => Promise<void>;\n\nexport async function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(\n\tdb: SqliteRemoteDatabase<TSchema, TRelations>,\n\tcallback: ProxyMigrator,\n\tconfig: MigrationConfig,\n) {\n\tconst migrations = readMigrationFiles(config);\n\n\tconst migrationsTable = typeof config === 'string'\n\t\t? '__drizzle_migrations'\n\t\t: config.migrationsTable ?? '__drizzle_migrations';\n\n\t// Detect DB version and upgrade table schema if needed\n\tconst { newDb } = await upgradeAsyncIfNeeded(migrationsTable, db.session, migrations);\n\n\tif (newDb) {\n\t\tconst migrationTableCreate = sql`\n\t\tCREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} (\n\t\t\tid INTEGER PRIMARY KEY,\n\t\t\thash text NOT NULL,\n\t\t\tcreated_at numeric,\n\t\t\tname text,\n\t\t\tapplied_at TEXT\n\t\t);`;\n\n\t\tawait db.run(migrationTableCreate);\n\t}\n\n\tconst dbMigrations = (await db.values<[number, string, string, string | null]>(\n\t\tsql`SELECT id, hash, created_at, name FROM ${sql.identifier(migrationsTable)}`,\n\t)).map(([id, hash, created_at, name]) => ({ id, hash, created_at, name }));\n\n\tif (typeof config === 'object' && config.init) {\n\t\tif (dbMigrations.length) {\n\t\t\treturn { exitCode: 'databaseMigrations' as const };\n\t\t}\n\n\t\tif (migrations.length > 1) {\n\t\t\treturn { exitCode: 'localMigrations' as const };\n\t\t}\n\n\t\tconst [migration] = migrations;\n\n\t\tif (!migration) return;\n\n\t\tawait callback(\n\t\t\t[\n\t\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\t\tsql`insert into ${\n\t\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t\t})`\n\t\t\t\t\t\t.inlineParams(),\n\t\t\t\t).sql,\n\t\t\t],\n\t\t);\n\n\t\treturn;\n\t}\n\n\tconst migrationsToRun = getMigrationsToRun({ localMigrations: migrations, dbMigrations });\n\tconst queriesToRun: string[] = [];\n\tfor (const migration of migrationsToRun) {\n\t\tqueriesToRun.push(\n\t\t\t...migration.sql,\n\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\tsql`insert into ${\n\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t})`\n\t\t\t\t\t.inlineParams(),\n\t\t\t).sql,\n\t\t);\n\t}\n\n\tawait callback(queriesToRun);\n\n\treturn;\n}\n"],"mappings":";;;;;;;;AAUA,eAAsB,QACrB,IACA,UACA,QACC;CACD,MAAM,mDAAgC,OAAO;CAE7C,MAAM,kBAAkB,OAAO,WAAW,WACvC,yBACA,OAAO,mBAAmB;CAG7B,MAAM,EAAE,UAAU,0DAA2B,iBAAiB,GAAG,SAAS,WAAW;AAErF,KAAI,OAAO;EACV,MAAM,uBAAuB,gBAAG;+BACHA,iBAAI,WAAW,gBAAgB,CAAC;;;;;;;AAQ7D,QAAM,GAAG,IAAI,qBAAqB;;CAGnC,MAAM,gBAAgB,MAAM,GAAG,OAC9B,gBAAG,0CAA0CA,iBAAI,WAAW,gBAAgB,GAC5E,EAAE,KAAK,CAAC,IAAI,MAAM,YAAY,WAAW;EAAE;EAAI;EAAM;EAAY;EAAM,EAAE;AAE1E,KAAI,OAAO,WAAW,YAAY,OAAO,MAAM;AAC9C,MAAI,aAAa,OAChB,QAAO,EAAE,UAAU,sBAA+B;AAGnD,MAAI,WAAW,SAAS,EACvB,QAAO,EAAE,UAAU,mBAA4B;EAGhD,MAAM,CAAC,aAAa;AAEpB,MAAI,CAAC,UAAW;AAEhB,QAAM,SACL,CACC,GAAG,QAAQ,WACV,gBAAG,eACFA,iBAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF,CACD;AAED;;CAGD,MAAM,8DAAqC;EAAE,iBAAiB;EAAY;EAAc,CAAC;CACzF,MAAM,eAAyB,EAAE;AACjC,MAAK,MAAM,aAAa,gBACvB,cAAa,KACZ,GAAG,UAAU,KACb,GAAG,QAAQ,WACV,gBAAG,eACFA,iBAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF;AAGF,OAAM,SAAS,aAAa"}
1
+ {"version":3,"file":"migrator.cjs","names":["migrateInternal"],"sources":["../../src/sqlite-proxy/migrator.ts"],"sourcesContent":["import type { MigrationConfig } from '~/migrator.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport type { SqliteRemoteDatabase } from './driver.ts';\nimport { migrateInternal } from './migrator.internal.ts';\n\nexport type ProxyMigrator = (migrationQueries: string[]) => Promise<void>;\n\nexport async function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(\n\tdb: SqliteRemoteDatabase<TSchema, TRelations>,\n\tcallback: ProxyMigrator,\n\tconfig: MigrationConfig,\n) {\n\treturn migrateInternal(db, callback, config, 'transaction');\n}\n"],"mappings":";;;;AAOA,eAAsB,QACrB,IACA,UACA,QACC;AACD,QAAOA,uDAAgB,IAAI,UAAU,QAAQ,cAAc"}
@@ -0,0 +1,61 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
+ let __sql_sql_ts = require("../sql/sql.cjs");
4
+ let __migrator_ts = require("../migrator.cjs");
5
+ let __migrator_utils_ts = require("../migrator.utils.cjs");
6
+ let __up_migrations_sqlite_ts = require("../up-migrations/sqlite.cjs");
7
+
8
+ //#region src/sqlite-proxy/migrator.internal.ts
9
+ /**
10
+ * - `migrate` - Public API for end users. Uses 'transaction' mode by default
11
+ * - `migrateInternal` - Internal API used by drizzle-kit. Accepts a `mode` parameter
12
+ *
13
+ * Why `mode` parameter exists:
14
+ * - 'transaction':
15
+ * Used by normal sqlite proxy driver
16
+ *
17
+ * - 'run':
18
+ * Executes statements individually without transaction. Required for Drizzle Kit D1 migrate, which uses sqlite proxy to run statements
19
+ * @see "drizzle-kit/src/cli/connections.ts"
20
+ */
21
+ async function migrateInternal(db, callback, config, mode) {
22
+ const migrations = (0, __migrator_ts.readMigrationFiles)(config);
23
+ const migrationsTable = typeof config === "string" ? "__drizzle_migrations" : config.migrationsTable ?? "__drizzle_migrations";
24
+ const { newDb } = await (0, __up_migrations_sqlite_ts.upgradeAsyncIfNeeded)(migrationsTable, db.session, migrations, mode);
25
+ if (newDb) {
26
+ const migrationTableCreate = __sql_sql_ts.sql`
27
+ CREATE TABLE IF NOT EXISTS ${__sql_sql_ts.sql.identifier(migrationsTable)} (
28
+ id INTEGER PRIMARY KEY,
29
+ hash text NOT NULL,
30
+ created_at numeric,
31
+ name text,
32
+ applied_at TEXT
33
+ );`;
34
+ await db.run(migrationTableCreate);
35
+ }
36
+ const dbMigrations = (await db.values(__sql_sql_ts.sql`SELECT id, hash, created_at, name FROM ${__sql_sql_ts.sql.identifier(migrationsTable)}`)).map(([id, hash, created_at, name]) => ({
37
+ id,
38
+ hash,
39
+ created_at,
40
+ name
41
+ }));
42
+ if (typeof config === "object" && config.init) {
43
+ if (dbMigrations.length) return { exitCode: "databaseMigrations" };
44
+ if (migrations.length > 1) return { exitCode: "localMigrations" };
45
+ const [migration] = migrations;
46
+ if (!migration) return;
47
+ await callback([db.dialect.sqlToQuery(__sql_sql_ts.sql`insert into ${__sql_sql_ts.sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql]);
48
+ return;
49
+ }
50
+ const migrationsToRun = (0, __migrator_utils_ts.getMigrationsToRun)({
51
+ localMigrations: migrations,
52
+ dbMigrations
53
+ });
54
+ const queriesToRun = [];
55
+ for (const migration of migrationsToRun) queriesToRun.push(...migration.sql, db.dialect.sqlToQuery(__sql_sql_ts.sql`insert into ${__sql_sql_ts.sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql);
56
+ await callback(queriesToRun);
57
+ }
58
+
59
+ //#endregion
60
+ exports.migrateInternal = migrateInternal;
61
+ //# sourceMappingURL=migrator.internal.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrator.internal.cjs","names":["sql"],"sources":["../../src/sqlite-proxy/migrator.internal.ts"],"sourcesContent":["import type { MigrationConfig } from '~/migrator.ts';\nimport { readMigrationFiles } from '~/migrator.ts';\nimport { getMigrationsToRun } from '~/migrator.utils.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { sql } from '~/sql/sql.ts';\nimport { upgradeAsyncIfNeeded } from '~/up-migrations/sqlite.ts';\nimport type { SqliteRemoteDatabase } from './driver.ts';\nimport type { ProxyMigrator } from './migrator.ts';\n\n/**\n * - `migrate` - Public API for end users. Uses 'transaction' mode by default\n * - `migrateInternal` - Internal API used by drizzle-kit. Accepts a `mode` parameter\n *\n * Why `mode` parameter exists:\n * - 'transaction':\n * Used by normal sqlite proxy driver\n *\n * - 'run':\n * Executes statements individually without transaction. Required for Drizzle Kit D1 migrate, which uses sqlite proxy to run statements\n * @see \"drizzle-kit/src/cli/connections.ts\"\n */\nexport async function migrateInternal<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(\n\tdb: SqliteRemoteDatabase<TSchema, TRelations>,\n\tcallback: ProxyMigrator,\n\tconfig: MigrationConfig,\n\tmode: 'transaction' | 'run',\n) {\n\tconst migrations = readMigrationFiles(config);\n\n\tconst migrationsTable = typeof config === 'string'\n\t\t? '__drizzle_migrations'\n\t\t: config.migrationsTable ?? '__drizzle_migrations';\n\n\t// Detect DB version and upgrade table schema if needed\n\tconst { newDb } = await upgradeAsyncIfNeeded(migrationsTable, db.session, migrations, mode);\n\n\tif (newDb) {\n\t\tconst migrationTableCreate = sql`\n\t\tCREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} (\n\t\t\tid INTEGER PRIMARY KEY,\n\t\t\thash text NOT NULL,\n\t\t\tcreated_at numeric,\n\t\t\tname text,\n\t\t\tapplied_at TEXT\n\t\t);`;\n\n\t\tawait db.run(migrationTableCreate);\n\t}\n\n\tconst dbMigrations = (await db.values<[number, string, string, string | null]>(\n\t\tsql`SELECT id, hash, created_at, name FROM ${sql.identifier(migrationsTable)}`,\n\t)).map(([id, hash, created_at, name]) => ({ id, hash, created_at, name }));\n\n\tif (typeof config === 'object' && config.init) {\n\t\tif (dbMigrations.length) {\n\t\t\treturn { exitCode: 'databaseMigrations' as const };\n\t\t}\n\n\t\tif (migrations.length > 1) {\n\t\t\treturn { exitCode: 'localMigrations' as const };\n\t\t}\n\n\t\tconst [migration] = migrations;\n\n\t\tif (!migration) return;\n\n\t\tawait callback(\n\t\t\t[\n\t\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\t\tsql`insert into ${\n\t\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t\t})`\n\t\t\t\t\t\t.inlineParams(),\n\t\t\t\t).sql,\n\t\t\t],\n\t\t);\n\n\t\treturn;\n\t}\n\n\tconst migrationsToRun = getMigrationsToRun({ localMigrations: migrations, dbMigrations });\n\tconst queriesToRun: string[] = [];\n\tfor (const migration of migrationsToRun) {\n\t\tqueriesToRun.push(\n\t\t\t...migration.sql,\n\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\tsql`insert into ${\n\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t})`\n\t\t\t\t\t.inlineParams(),\n\t\t\t).sql,\n\t\t);\n\t}\n\n\tawait callback(queriesToRun);\n\n\treturn;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBA,eAAsB,gBACrB,IACA,UACA,QACA,MACC;CACD,MAAM,mDAAgC,OAAO;CAE7C,MAAM,kBAAkB,OAAO,WAAW,WACvC,yBACA,OAAO,mBAAmB;CAG7B,MAAM,EAAE,UAAU,0DAA2B,iBAAiB,GAAG,SAAS,YAAY,KAAK;AAE3F,KAAI,OAAO;EACV,MAAM,uBAAuB,gBAAG;+BACHA,iBAAI,WAAW,gBAAgB,CAAC;;;;;;;AAQ7D,QAAM,GAAG,IAAI,qBAAqB;;CAGnC,MAAM,gBAAgB,MAAM,GAAG,OAC9B,gBAAG,0CAA0CA,iBAAI,WAAW,gBAAgB,GAC5E,EAAE,KAAK,CAAC,IAAI,MAAM,YAAY,WAAW;EAAE;EAAI;EAAM;EAAY;EAAM,EAAE;AAE1E,KAAI,OAAO,WAAW,YAAY,OAAO,MAAM;AAC9C,MAAI,aAAa,OAChB,QAAO,EAAE,UAAU,sBAA+B;AAGnD,MAAI,WAAW,SAAS,EACvB,QAAO,EAAE,UAAU,mBAA4B;EAGhD,MAAM,CAAC,aAAa;AAEpB,MAAI,CAAC,UAAW;AAEhB,QAAM,SACL,CACC,GAAG,QAAQ,WACV,gBAAG,eACFA,iBAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF,CACD;AAED;;CAGD,MAAM,8DAAqC;EAAE,iBAAiB;EAAY;EAAc,CAAC;CACzF,MAAM,eAAyB,EAAE;AACjC,MAAK,MAAM,aAAa,gBACvB,cAAa,KACZ,GAAG,UAAU,KACb,GAAG,QAAQ,WACV,gBAAG,eACFA,iBAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF;AAGF,OAAM,SAAS,aAAa"}
@@ -0,0 +1,26 @@
1
+ import { SqliteRemoteDatabase } from "./driver.cjs";
2
+ import { ProxyMigrator } from "./migrator.cjs";
3
+ import { MigrationConfig } from "../migrator.cjs";
4
+ import { AnyRelations } from "../relations.cjs";
5
+
6
+ //#region src/sqlite-proxy/migrator.internal.d.ts
7
+ /**
8
+ * - `migrate` - Public API for end users. Uses 'transaction' mode by default
9
+ * - `migrateInternal` - Internal API used by drizzle-kit. Accepts a `mode` parameter
10
+ *
11
+ * Why `mode` parameter exists:
12
+ * - 'transaction':
13
+ * Used by normal sqlite proxy driver
14
+ *
15
+ * - 'run':
16
+ * Executes statements individually without transaction. Required for Drizzle Kit D1 migrate, which uses sqlite proxy to run statements
17
+ * @see "drizzle-kit/src/cli/connections.ts"
18
+ */
19
+ declare function migrateInternal<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(db: SqliteRemoteDatabase<TSchema, TRelations>, callback: ProxyMigrator, config: MigrationConfig, mode: 'transaction' | 'run'): Promise<{
20
+ exitCode: "databaseMigrations";
21
+ } | {
22
+ exitCode: "localMigrations";
23
+ } | undefined>;
24
+ //#endregion
25
+ export { migrateInternal };
26
+ //# sourceMappingURL=migrator.internal.d.cts.map
@@ -0,0 +1,26 @@
1
+ import { SqliteRemoteDatabase } from "./driver.js";
2
+ import { ProxyMigrator } from "./migrator.js";
3
+ import { MigrationConfig } from "../migrator.js";
4
+ import { AnyRelations } from "../relations.js";
5
+
6
+ //#region src/sqlite-proxy/migrator.internal.d.ts
7
+ /**
8
+ * - `migrate` - Public API for end users. Uses 'transaction' mode by default
9
+ * - `migrateInternal` - Internal API used by drizzle-kit. Accepts a `mode` parameter
10
+ *
11
+ * Why `mode` parameter exists:
12
+ * - 'transaction':
13
+ * Used by normal sqlite proxy driver
14
+ *
15
+ * - 'run':
16
+ * Executes statements individually without transaction. Required for Drizzle Kit D1 migrate, which uses sqlite proxy to run statements
17
+ * @see "drizzle-kit/src/cli/connections.ts"
18
+ */
19
+ declare function migrateInternal<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(db: SqliteRemoteDatabase<TSchema, TRelations>, callback: ProxyMigrator, config: MigrationConfig, mode: 'transaction' | 'run'): Promise<{
20
+ exitCode: "databaseMigrations";
21
+ } | {
22
+ exitCode: "localMigrations";
23
+ } | undefined>;
24
+ //#endregion
25
+ export { migrateInternal };
26
+ //# sourceMappingURL=migrator.internal.d.ts.map
@@ -0,0 +1,59 @@
1
+ import { sql } from "../sql/sql.js";
2
+ import { readMigrationFiles } from "../migrator.js";
3
+ import { getMigrationsToRun } from "../migrator.utils.js";
4
+ import { upgradeAsyncIfNeeded } from "../up-migrations/sqlite.js";
5
+
6
+ //#region src/sqlite-proxy/migrator.internal.ts
7
+ /**
8
+ * - `migrate` - Public API for end users. Uses 'transaction' mode by default
9
+ * - `migrateInternal` - Internal API used by drizzle-kit. Accepts a `mode` parameter
10
+ *
11
+ * Why `mode` parameter exists:
12
+ * - 'transaction':
13
+ * Used by normal sqlite proxy driver
14
+ *
15
+ * - 'run':
16
+ * Executes statements individually without transaction. Required for Drizzle Kit D1 migrate, which uses sqlite proxy to run statements
17
+ * @see "drizzle-kit/src/cli/connections.ts"
18
+ */
19
+ async function migrateInternal(db, callback, config, mode) {
20
+ const migrations = readMigrationFiles(config);
21
+ const migrationsTable = typeof config === "string" ? "__drizzle_migrations" : config.migrationsTable ?? "__drizzle_migrations";
22
+ const { newDb } = await upgradeAsyncIfNeeded(migrationsTable, db.session, migrations, mode);
23
+ if (newDb) {
24
+ const migrationTableCreate = sql`
25
+ CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} (
26
+ id INTEGER PRIMARY KEY,
27
+ hash text NOT NULL,
28
+ created_at numeric,
29
+ name text,
30
+ applied_at TEXT
31
+ );`;
32
+ await db.run(migrationTableCreate);
33
+ }
34
+ const dbMigrations = (await db.values(sql`SELECT id, hash, created_at, name FROM ${sql.identifier(migrationsTable)}`)).map(([id, hash, created_at, name]) => ({
35
+ id,
36
+ hash,
37
+ created_at,
38
+ name
39
+ }));
40
+ if (typeof config === "object" && config.init) {
41
+ if (dbMigrations.length) return { exitCode: "databaseMigrations" };
42
+ if (migrations.length > 1) return { exitCode: "localMigrations" };
43
+ const [migration] = migrations;
44
+ if (!migration) return;
45
+ await callback([db.dialect.sqlToQuery(sql`insert into ${sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql]);
46
+ return;
47
+ }
48
+ const migrationsToRun = getMigrationsToRun({
49
+ localMigrations: migrations,
50
+ dbMigrations
51
+ });
52
+ const queriesToRun = [];
53
+ for (const migration of migrationsToRun) queriesToRun.push(...migration.sql, db.dialect.sqlToQuery(sql`insert into ${sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql);
54
+ await callback(queriesToRun);
55
+ }
56
+
57
+ //#endregion
58
+ export { migrateInternal };
59
+ //# sourceMappingURL=migrator.internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrator.internal.js","names":[],"sources":["../../src/sqlite-proxy/migrator.internal.ts"],"sourcesContent":["import type { MigrationConfig } from '~/migrator.ts';\nimport { readMigrationFiles } from '~/migrator.ts';\nimport { getMigrationsToRun } from '~/migrator.utils.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { sql } from '~/sql/sql.ts';\nimport { upgradeAsyncIfNeeded } from '~/up-migrations/sqlite.ts';\nimport type { SqliteRemoteDatabase } from './driver.ts';\nimport type { ProxyMigrator } from './migrator.ts';\n\n/**\n * - `migrate` - Public API for end users. Uses 'transaction' mode by default\n * - `migrateInternal` - Internal API used by drizzle-kit. Accepts a `mode` parameter\n *\n * Why `mode` parameter exists:\n * - 'transaction':\n * Used by normal sqlite proxy driver\n *\n * - 'run':\n * Executes statements individually without transaction. Required for Drizzle Kit D1 migrate, which uses sqlite proxy to run statements\n * @see \"drizzle-kit/src/cli/connections.ts\"\n */\nexport async function migrateInternal<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(\n\tdb: SqliteRemoteDatabase<TSchema, TRelations>,\n\tcallback: ProxyMigrator,\n\tconfig: MigrationConfig,\n\tmode: 'transaction' | 'run',\n) {\n\tconst migrations = readMigrationFiles(config);\n\n\tconst migrationsTable = typeof config === 'string'\n\t\t? '__drizzle_migrations'\n\t\t: config.migrationsTable ?? '__drizzle_migrations';\n\n\t// Detect DB version and upgrade table schema if needed\n\tconst { newDb } = await upgradeAsyncIfNeeded(migrationsTable, db.session, migrations, mode);\n\n\tif (newDb) {\n\t\tconst migrationTableCreate = sql`\n\t\tCREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} (\n\t\t\tid INTEGER PRIMARY KEY,\n\t\t\thash text NOT NULL,\n\t\t\tcreated_at numeric,\n\t\t\tname text,\n\t\t\tapplied_at TEXT\n\t\t);`;\n\n\t\tawait db.run(migrationTableCreate);\n\t}\n\n\tconst dbMigrations = (await db.values<[number, string, string, string | null]>(\n\t\tsql`SELECT id, hash, created_at, name FROM ${sql.identifier(migrationsTable)}`,\n\t)).map(([id, hash, created_at, name]) => ({ id, hash, created_at, name }));\n\n\tif (typeof config === 'object' && config.init) {\n\t\tif (dbMigrations.length) {\n\t\t\treturn { exitCode: 'databaseMigrations' as const };\n\t\t}\n\n\t\tif (migrations.length > 1) {\n\t\t\treturn { exitCode: 'localMigrations' as const };\n\t\t}\n\n\t\tconst [migration] = migrations;\n\n\t\tif (!migration) return;\n\n\t\tawait callback(\n\t\t\t[\n\t\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\t\tsql`insert into ${\n\t\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t\t})`\n\t\t\t\t\t\t.inlineParams(),\n\t\t\t\t).sql,\n\t\t\t],\n\t\t);\n\n\t\treturn;\n\t}\n\n\tconst migrationsToRun = getMigrationsToRun({ localMigrations: migrations, dbMigrations });\n\tconst queriesToRun: string[] = [];\n\tfor (const migration of migrationsToRun) {\n\t\tqueriesToRun.push(\n\t\t\t...migration.sql,\n\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\tsql`insert into ${\n\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t})`\n\t\t\t\t\t.inlineParams(),\n\t\t\t).sql,\n\t\t);\n\t}\n\n\tawait callback(queriesToRun);\n\n\treturn;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,eAAsB,gBACrB,IACA,UACA,QACA,MACC;CACD,MAAM,aAAa,mBAAmB,OAAO;CAE7C,MAAM,kBAAkB,OAAO,WAAW,WACvC,yBACA,OAAO,mBAAmB;CAG7B,MAAM,EAAE,UAAU,MAAM,qBAAqB,iBAAiB,GAAG,SAAS,YAAY,KAAK;AAE3F,KAAI,OAAO;EACV,MAAM,uBAAuB,GAAG;+BACH,IAAI,WAAW,gBAAgB,CAAC;;;;;;;AAQ7D,QAAM,GAAG,IAAI,qBAAqB;;CAGnC,MAAM,gBAAgB,MAAM,GAAG,OAC9B,GAAG,0CAA0C,IAAI,WAAW,gBAAgB,GAC5E,EAAE,KAAK,CAAC,IAAI,MAAM,YAAY,WAAW;EAAE;EAAI;EAAM;EAAY;EAAM,EAAE;AAE1E,KAAI,OAAO,WAAW,YAAY,OAAO,MAAM;AAC9C,MAAI,aAAa,OAChB,QAAO,EAAE,UAAU,sBAA+B;AAGnD,MAAI,WAAW,SAAS,EACvB,QAAO,EAAE,UAAU,mBAA4B;EAGhD,MAAM,CAAC,aAAa;AAEpB,MAAI,CAAC,UAAW;AAEhB,QAAM,SACL,CACC,GAAG,QAAQ,WACV,GAAG,eACF,IAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF,CACD;AAED;;CAGD,MAAM,kBAAkB,mBAAmB;EAAE,iBAAiB;EAAY;EAAc,CAAC;CACzF,MAAM,eAAyB,EAAE;AACjC,MAAK,MAAM,aAAa,gBACvB,cAAa,KACZ,GAAG,UAAU,KACb,GAAG,QAAQ,WACV,GAAG,eACF,IAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF;AAGF,OAAM,SAAS,aAAa"}
@@ -1,45 +1,8 @@
1
- import { sql } from "../sql/sql.js";
2
- import { readMigrationFiles } from "../migrator.js";
3
- import { getMigrationsToRun } from "../migrator.utils.js";
4
- import { upgradeAsyncIfNeeded } from "../up-migrations/sqlite.js";
1
+ import { migrateInternal } from "./migrator.internal.js";
5
2
 
6
3
  //#region src/sqlite-proxy/migrator.ts
7
4
  async function migrate(db, callback, config) {
8
- const migrations = readMigrationFiles(config);
9
- const migrationsTable = typeof config === "string" ? "__drizzle_migrations" : config.migrationsTable ?? "__drizzle_migrations";
10
- const { newDb } = await upgradeAsyncIfNeeded(migrationsTable, db.session, migrations);
11
- if (newDb) {
12
- const migrationTableCreate = sql`
13
- CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} (
14
- id INTEGER PRIMARY KEY,
15
- hash text NOT NULL,
16
- created_at numeric,
17
- name text,
18
- applied_at TEXT
19
- );`;
20
- await db.run(migrationTableCreate);
21
- }
22
- const dbMigrations = (await db.values(sql`SELECT id, hash, created_at, name FROM ${sql.identifier(migrationsTable)}`)).map(([id, hash, created_at, name]) => ({
23
- id,
24
- hash,
25
- created_at,
26
- name
27
- }));
28
- if (typeof config === "object" && config.init) {
29
- if (dbMigrations.length) return { exitCode: "databaseMigrations" };
30
- if (migrations.length > 1) return { exitCode: "localMigrations" };
31
- const [migration] = migrations;
32
- if (!migration) return;
33
- await callback([db.dialect.sqlToQuery(sql`insert into ${sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql]);
34
- return;
35
- }
36
- const migrationsToRun = getMigrationsToRun({
37
- localMigrations: migrations,
38
- dbMigrations
39
- });
40
- const queriesToRun = [];
41
- for (const migration of migrationsToRun) queriesToRun.push(...migration.sql, db.dialect.sqlToQuery(sql`insert into ${sql.identifier(migrationsTable)} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${(/* @__PURE__ */ new Date()).toISOString()})`.inlineParams()).sql);
42
- await callback(queriesToRun);
5
+ return migrateInternal(db, callback, config, "transaction");
43
6
  }
44
7
 
45
8
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"migrator.js","names":[],"sources":["../../src/sqlite-proxy/migrator.ts"],"sourcesContent":["import type { MigrationConfig } from '~/migrator.ts';\nimport { readMigrationFiles } from '~/migrator.ts';\nimport { getMigrationsToRun } from '~/migrator.utils.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { sql } from '~/sql/sql.ts';\nimport { upgradeAsyncIfNeeded } from '~/up-migrations/sqlite.ts';\nimport type { SqliteRemoteDatabase } from './driver.ts';\n\nexport type ProxyMigrator = (migrationQueries: string[]) => Promise<void>;\n\nexport async function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(\n\tdb: SqliteRemoteDatabase<TSchema, TRelations>,\n\tcallback: ProxyMigrator,\n\tconfig: MigrationConfig,\n) {\n\tconst migrations = readMigrationFiles(config);\n\n\tconst migrationsTable = typeof config === 'string'\n\t\t? '__drizzle_migrations'\n\t\t: config.migrationsTable ?? '__drizzle_migrations';\n\n\t// Detect DB version and upgrade table schema if needed\n\tconst { newDb } = await upgradeAsyncIfNeeded(migrationsTable, db.session, migrations);\n\n\tif (newDb) {\n\t\tconst migrationTableCreate = sql`\n\t\tCREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} (\n\t\t\tid INTEGER PRIMARY KEY,\n\t\t\thash text NOT NULL,\n\t\t\tcreated_at numeric,\n\t\t\tname text,\n\t\t\tapplied_at TEXT\n\t\t);`;\n\n\t\tawait db.run(migrationTableCreate);\n\t}\n\n\tconst dbMigrations = (await db.values<[number, string, string, string | null]>(\n\t\tsql`SELECT id, hash, created_at, name FROM ${sql.identifier(migrationsTable)}`,\n\t)).map(([id, hash, created_at, name]) => ({ id, hash, created_at, name }));\n\n\tif (typeof config === 'object' && config.init) {\n\t\tif (dbMigrations.length) {\n\t\t\treturn { exitCode: 'databaseMigrations' as const };\n\t\t}\n\n\t\tif (migrations.length > 1) {\n\t\t\treturn { exitCode: 'localMigrations' as const };\n\t\t}\n\n\t\tconst [migration] = migrations;\n\n\t\tif (!migration) return;\n\n\t\tawait callback(\n\t\t\t[\n\t\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\t\tsql`insert into ${\n\t\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t\t})`\n\t\t\t\t\t\t.inlineParams(),\n\t\t\t\t).sql,\n\t\t\t],\n\t\t);\n\n\t\treturn;\n\t}\n\n\tconst migrationsToRun = getMigrationsToRun({ localMigrations: migrations, dbMigrations });\n\tconst queriesToRun: string[] = [];\n\tfor (const migration of migrationsToRun) {\n\t\tqueriesToRun.push(\n\t\t\t...migration.sql,\n\t\t\tdb.dialect.sqlToQuery(\n\t\t\t\tsql`insert into ${\n\t\t\t\t\tsql.identifier(migrationsTable)\n\t\t\t\t} (\"hash\", \"created_at\", \"name\", \"applied_at\") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${\n\t\t\t\t\tnew Date().toISOString()\n\t\t\t\t})`\n\t\t\t\t\t.inlineParams(),\n\t\t\t).sql,\n\t\t);\n\t}\n\n\tawait callback(queriesToRun);\n\n\treturn;\n}\n"],"mappings":";;;;;;AAUA,eAAsB,QACrB,IACA,UACA,QACC;CACD,MAAM,aAAa,mBAAmB,OAAO;CAE7C,MAAM,kBAAkB,OAAO,WAAW,WACvC,yBACA,OAAO,mBAAmB;CAG7B,MAAM,EAAE,UAAU,MAAM,qBAAqB,iBAAiB,GAAG,SAAS,WAAW;AAErF,KAAI,OAAO;EACV,MAAM,uBAAuB,GAAG;+BACH,IAAI,WAAW,gBAAgB,CAAC;;;;;;;AAQ7D,QAAM,GAAG,IAAI,qBAAqB;;CAGnC,MAAM,gBAAgB,MAAM,GAAG,OAC9B,GAAG,0CAA0C,IAAI,WAAW,gBAAgB,GAC5E,EAAE,KAAK,CAAC,IAAI,MAAM,YAAY,WAAW;EAAE;EAAI;EAAM;EAAY;EAAM,EAAE;AAE1E,KAAI,OAAO,WAAW,YAAY,OAAO,MAAM;AAC9C,MAAI,aAAa,OAChB,QAAO,EAAE,UAAU,sBAA+B;AAGnD,MAAI,WAAW,SAAS,EACvB,QAAO,EAAE,UAAU,mBAA4B;EAGhD,MAAM,CAAC,aAAa;AAEpB,MAAI,CAAC,UAAW;AAEhB,QAAM,SACL,CACC,GAAG,QAAQ,WACV,GAAG,eACF,IAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF,CACD;AAED;;CAGD,MAAM,kBAAkB,mBAAmB;EAAE,iBAAiB;EAAY;EAAc,CAAC;CACzF,MAAM,eAAyB,EAAE;AACjC,MAAK,MAAM,aAAa,gBACvB,cAAa,KACZ,GAAG,UAAU,KACb,GAAG,QAAQ,WACV,GAAG,eACF,IAAI,WAAW,gBAAgB,CAC/B,uDAAuD,UAAU,KAAK,IAAI,UAAU,aAAa,IAAI,UAAU,KAAK,qBACpH,IAAI,MAAM,EAAC,aAAa,CACxB,GACC,cAAc,CAChB,CAAC,IACF;AAGF,OAAM,SAAS,aAAa"}
1
+ {"version":3,"file":"migrator.js","names":[],"sources":["../../src/sqlite-proxy/migrator.ts"],"sourcesContent":["import type { MigrationConfig } from '~/migrator.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport type { SqliteRemoteDatabase } from './driver.ts';\nimport { migrateInternal } from './migrator.internal.ts';\n\nexport type ProxyMigrator = (migrationQueries: string[]) => Promise<void>;\n\nexport async function migrate<TSchema extends Record<string, unknown>, TRelations extends AnyRelations>(\n\tdb: SqliteRemoteDatabase<TSchema, TRelations>,\n\tcallback: ProxyMigrator,\n\tconfig: MigrationConfig,\n) {\n\treturn migrateInternal(db, callback, config, 'transaction');\n}\n"],"mappings":";;;AAOA,eAAsB,QACrB,IACA,UACA,QACC;AACD,QAAO,gBAAgB,IAAI,UAAU,QAAQ,cAAc"}
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
+ let __utils_ts = require("../utils.cjs");
3
4
  let __sql_sql_ts = require("../sql/sql.cjs");
4
5
 
5
6
  //#region src/up-migrations/sqlite.ts
@@ -100,20 +101,20 @@ const upgradeSyncFunctions = { 0: (migrationsTable, session, localMigrations) =>
100
101
  * Version 0: Original schema (id, hash, created_at)
101
102
  * Version 1: Extended schema (id, hash, created_at, name, applied_at)
102
103
  */
103
- async function upgradeAsyncIfNeeded(migrationsTable, session, localMigrations) {
104
+ async function upgradeAsyncIfNeeded(migrationsTable, session, localMigrations, mode = "transaction") {
104
105
  if ((await allAsync(session, __sql_sql_ts.sql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`, (row) => ({ "1": row[0] }))).length === 0) return { newDb: true };
105
106
  const version = getVersion((await allAsync(session, __sql_sql_ts.sql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`, (row) => ({ column_name: row[0] }))).map((r) => r.column_name));
106
107
  for (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {
107
108
  const upgradeFn = upgradeAsyncFunctions[v];
108
109
  if (!upgradeFn) throw new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);
109
- await upgradeFn(migrationsTable, session, localMigrations);
110
+ await upgradeFn(migrationsTable, session, localMigrations, mode);
110
111
  }
111
112
  return {
112
113
  prevVersion: version,
113
114
  currentVersion: CURRENT_MIGRATION_TABLE_VERSION
114
115
  };
115
116
  }
116
- const upgradeAsyncFunctions = { 0: async (migrationsTable, session, localMigrations) => {
117
+ const upgradeAsyncFunctions = { 0: async (migrationsTable, session, localMigrations, mode) => {
117
118
  const table = __sql_sql_ts.sql`${__sql_sql_ts.sql.identifier(migrationsTable)}`;
118
119
  const dbRows = await allAsync(session, __sql_sql_ts.sql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`, (row) => ({
119
120
  id: row[0],
@@ -156,17 +157,19 @@ const upgradeAsyncFunctions = { 0: async (migrationsTable, session, localMigrati
156
157
  else unmatched.push(dbRow);
157
158
  }
158
159
  if (unmatched.length > 0) throw Error(`While upgrading your database migrations table we found ${unmatched.length} (${unmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(", ")}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`);
159
- await session.transaction(async (tx) => {
160
- await tx.run(__sql_sql_ts.sql`ALTER TABLE ${table} ADD COLUMN ${__sql_sql_ts.sql.identifier("name")} text`);
161
- await tx.run(__sql_sql_ts.sql`ALTER TABLE ${table} ADD COLUMN ${__sql_sql_ts.sql.identifier("applied_at")} TEXT`);
162
- for (const backfillEntry of toApply) {
163
- const updateQuery = __sql_sql_ts.sql`UPDATE ${table} SET ${__sql_sql_ts.sql.identifier("name")} = ${backfillEntry.name}, ${__sql_sql_ts.sql.identifier("applied_at")} = NULL WHERE`;
164
- if (backfillEntry.id) updateQuery.append(__sql_sql_ts.sql` ${__sql_sql_ts.sql.identifier("id")} = ${backfillEntry.id}`);
165
- else if (backfillEntry.matchedBy === "millis") updateQuery.append(__sql_sql_ts.sql` ${__sql_sql_ts.sql.identifier("created_at")} = ${backfillEntry.created_at}`);
166
- else updateQuery.append(__sql_sql_ts.sql` ${__sql_sql_ts.sql.identifier("hash")} = ${backfillEntry.hash}`);
167
- await tx.run(updateQuery);
168
- }
160
+ const statements = [__sql_sql_ts.sql`ALTER TABLE ${table} ADD COLUMN ${__sql_sql_ts.sql.identifier("name")} text`, __sql_sql_ts.sql`ALTER TABLE ${table} ADD COLUMN ${__sql_sql_ts.sql.identifier("applied_at")} TEXT`];
161
+ for (const backfillEntry of toApply) {
162
+ const updateQuery = __sql_sql_ts.sql`UPDATE ${table} SET ${__sql_sql_ts.sql.identifier("name")} = ${backfillEntry.name}, ${__sql_sql_ts.sql.identifier("applied_at")} = NULL WHERE`;
163
+ if (backfillEntry.id) updateQuery.append(__sql_sql_ts.sql` ${__sql_sql_ts.sql.identifier("id")} = ${backfillEntry.id}`);
164
+ else if (backfillEntry.matchedBy === "millis") updateQuery.append(__sql_sql_ts.sql` ${__sql_sql_ts.sql.identifier("created_at")} = ${backfillEntry.created_at}`);
165
+ else updateQuery.append(__sql_sql_ts.sql` ${__sql_sql_ts.sql.identifier("hash")} = ${backfillEntry.hash}`);
166
+ statements.push(updateQuery);
167
+ }
168
+ if (mode === "transaction") await session.transaction(async (tx) => {
169
+ for (const statement of statements) await tx.run(statement);
169
170
  });
171
+ else if (mode === "run") for (const statement of statements) await session.run(statement);
172
+ else (0, __utils_ts.assertUnreachable)(mode);
170
173
  } };
171
174
 
172
175
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.cjs","names":["sql"],"sources":["../../src/up-migrations/sqlite.ts"],"sourcesContent":["import type { TablesRelationalConfig } from '~/_relations.ts';\nimport type { SQLiteD1Session } from '~/d1/session.ts';\nimport type { LibSQLSession } from '~/libsql/session.ts';\nimport type { MigrationMeta } from '~/migrator.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { type SQL, sql } from '~/sql/sql.ts';\nimport type { SQLiteCloudSession } from '~/sqlite-cloud/session.ts';\nimport type { SQLiteSession } from '~/sqlite-core/session.ts';\nimport type { SQLiteRemoteSession } from '~/sqlite-proxy/session.ts';\n\nconst CURRENT_MIGRATION_TABLE_VERSION = 1;\n\ninterface UpgradeResult {\n\tnewDb?: boolean;\n\tprevVersion?: number;\n\tcurrentVersion?: number;\n}\n\nfunction getVersion(columns: string[]) {\n\tif (columns.includes('name')) return 1;\n\treturn 0;\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nfunction allSync<T>(\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): T[] {\n\tconst result = session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nasync function allAsync<T>(\n\tsession: SQLiteSession<\n\t\t'async',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): Promise<T[]> {\n\tconst result = await session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport function upgradeSyncIfNeeded(\n\tmigrationsTable: string,\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tlocalMigrations: MigrationMeta[],\n): UpgradeResult {\n\t// Check if the table exists at all\n\t// sqlite-proxy returns [ [1] ]\n\t// sqlite returns [{ '1': 1 }]\n\tconst tableExists = allSync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\tconst rows = allSync<{ column_name: string }>(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeSyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tupgradeFn(migrationsTable, session, localMigrations);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeSyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'sync',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t) => void\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: (migrationsTable, session, localMigrations) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = allSync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tsession.transaction((tx) => {\n\t\t\ttx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`);\n\t\t\ttx.run(\n\t\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t\t);\n\n\t\t\tfor (const backfillEntry of toApply) {\n\t\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\t\tsql.identifier('applied_at')\n\t\t\t\t} = NULL WHERE`;\n\n\t\t\t\t// id\n\t\t\t\t// created_at\n\t\t\t\t// hash\n\t\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\t\ttx.run(updateQuery);\n\t\t\t}\n\t\t});\n\t},\n};\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport async function upgradeAsyncIfNeeded(\n\tmigrationsTable: string,\n\tsession:\n\t\t| SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>\n\t\t| SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>,\n\tlocalMigrations: MigrationMeta[],\n): Promise<UpgradeResult> {\n\t// Check if the table exists at all\n\tconst tableExists = await allAsync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\t// sqlite-proxy returns [ [string] ]\n\t// sqlite returns [{ column_name: string }]\n\tconst rows = await allAsync(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeAsyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tawait upgradeFn(migrationsTable, session, localMigrations);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeAsyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t) => Promise<void>\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: async (migrationsTable, session, localMigrations) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = await allAsync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tawait session.transaction(async (tx) => {\n\t\t\tawait tx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`);\n\t\t\tawait tx.run(\n\t\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t\t);\n\n\t\t\tfor (const backfillEntry of toApply) {\n\t\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\t\tsql.identifier('applied_at')\n\t\t\t\t} = NULL WHERE`;\n\n\t\t\t\t// id\n\t\t\t\t// created_at\n\t\t\t\t// hash\n\t\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\t\tawait tx.run(updateQuery);\n\t\t\t}\n\t\t});\n\t},\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"sqlite.cjs","names":["sql"],"sources":["../../src/up-migrations/sqlite.ts"],"sourcesContent":["import type { TablesRelationalConfig } from '~/_relations.ts';\nimport type { SQLiteD1Session } from '~/d1/session.ts';\nimport type { LibSQLSession } from '~/libsql/session.ts';\nimport type { MigrationMeta } from '~/migrator.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { type SQL, sql } from '~/sql/sql.ts';\nimport type { SQLiteCloudSession } from '~/sqlite-cloud/session.ts';\nimport type { SQLiteSession } from '~/sqlite-core/session.ts';\nimport type { SQLiteRemoteSession } from '~/sqlite-proxy/session.ts';\nimport { assertUnreachable } from '~/utils.ts';\n\nconst CURRENT_MIGRATION_TABLE_VERSION = 1;\n\ninterface UpgradeResult {\n\tnewDb?: boolean;\n\tprevVersion?: number;\n\tcurrentVersion?: number;\n}\n\nfunction getVersion(columns: string[]) {\n\tif (columns.includes('name')) return 1;\n\treturn 0;\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nfunction allSync<T>(\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): T[] {\n\tconst result = session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nasync function allAsync<T>(\n\tsession: SQLiteSession<\n\t\t'async',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): Promise<T[]> {\n\tconst result = await session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport function upgradeSyncIfNeeded(\n\tmigrationsTable: string,\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tlocalMigrations: MigrationMeta[],\n): UpgradeResult {\n\t// Check if the table exists at all\n\t// sqlite-proxy returns [ [1] ]\n\t// sqlite returns [{ '1': 1 }]\n\tconst tableExists = allSync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\tconst rows = allSync<{ column_name: string }>(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeSyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tupgradeFn(migrationsTable, session, localMigrations);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeSyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'sync',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t) => void\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: (migrationsTable, session, localMigrations) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = allSync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tsession.transaction((tx) => {\n\t\t\ttx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`);\n\t\t\ttx.run(\n\t\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t\t);\n\n\t\t\tfor (const backfillEntry of toApply) {\n\t\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\t\tsql.identifier('applied_at')\n\t\t\t\t} = NULL WHERE`;\n\n\t\t\t\t// id\n\t\t\t\t// created_at\n\t\t\t\t// hash\n\t\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\t\ttx.run(updateQuery);\n\t\t\t}\n\t\t});\n\t},\n};\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport async function upgradeAsyncIfNeeded(\n\tmigrationsTable: string,\n\tsession:\n\t\t| SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>\n\t\t| SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>,\n\tlocalMigrations: MigrationMeta[],\n\tmode: 'transaction' | 'run' = 'transaction',\n): Promise<UpgradeResult> {\n\t// Check if the table exists at all\n\tconst tableExists = await allAsync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\t// sqlite-proxy returns [ [string] ]\n\t// sqlite returns [{ column_name: string }]\n\tconst rows = await allAsync(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeAsyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tawait upgradeFn(migrationsTable, session, localMigrations, mode);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeAsyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t\tmode: 'transaction' | 'run',\n\t) => Promise<void>\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: async (migrationsTable, session, localMigrations, mode) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = await allAsync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tconst statements: SQL[] = [\n\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`,\n\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t];\n\t\tfor (const backfillEntry of toApply) {\n\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\tsql.identifier('applied_at')\n\t\t\t} = NULL WHERE`;\n\n\t\t\t// id\n\t\t\t// created_at\n\t\t\t// hash\n\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\tstatements.push(updateQuery);\n\t\t}\n\n\t\tif (mode === 'transaction') {\n\t\t\t// for normal sqlite proxy migrate() call from code\n\t\t\tawait session.transaction(async (tx) => {\n\t\t\t\tfor (const statement of statements) {\n\t\t\t\t\tawait tx.run(statement);\n\t\t\t\t}\n\t\t\t});\n\t\t} else if (mode === 'run') {\n\t\t\t// for drizzle-kit migrate call for d1 driver\n\t\t\t// see drizzle-kit/src/cli/connections.ts for sqlite d1\n\t\t\tfor (const statement of statements) {\n\t\t\t\tawait session.run(statement);\n\t\t\t}\n\t\t} else assertUnreachable(mode);\n\t},\n};\n"],"mappings":"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"}
@@ -26,7 +26,7 @@ declare function upgradeSyncIfNeeded(migrationsTable: string, session: SQLiteSes
26
26
  * Version 0: Original schema (id, hash, created_at)
27
27
  * Version 1: Extended schema (id, hash, created_at, name, applied_at)
28
28
  */
29
- declare function upgradeAsyncIfNeeded(migrationsTable: string, session: SQLiteSession<'async', unknown, Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>, localMigrations: MigrationMeta[]): Promise<UpgradeResult>;
29
+ declare function upgradeAsyncIfNeeded(migrationsTable: string, session: SQLiteSession<'async', unknown, Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>, localMigrations: MigrationMeta[], mode?: 'transaction' | 'run'): Promise<UpgradeResult>;
30
30
  //#endregion
31
31
  export { upgradeAsyncIfNeeded, upgradeSyncIfNeeded };
32
32
  //# sourceMappingURL=sqlite.d.cts.map
@@ -26,7 +26,7 @@ declare function upgradeSyncIfNeeded(migrationsTable: string, session: SQLiteSes
26
26
  * Version 0: Original schema (id, hash, created_at)
27
27
  * Version 1: Extended schema (id, hash, created_at, name, applied_at)
28
28
  */
29
- declare function upgradeAsyncIfNeeded(migrationsTable: string, session: SQLiteSession<'async', unknown, Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>, localMigrations: MigrationMeta[]): Promise<UpgradeResult>;
29
+ declare function upgradeAsyncIfNeeded(migrationsTable: string, session: SQLiteSession<'async', unknown, Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig> | SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>, localMigrations: MigrationMeta[], mode?: 'transaction' | 'run'): Promise<UpgradeResult>;
30
30
  //#endregion
31
31
  export { upgradeAsyncIfNeeded, upgradeSyncIfNeeded };
32
32
  //# sourceMappingURL=sqlite.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { assertUnreachable } from "../utils.js";
1
2
  import { sql } from "../sql/sql.js";
2
3
 
3
4
  //#region src/up-migrations/sqlite.ts
@@ -98,20 +99,20 @@ const upgradeSyncFunctions = { 0: (migrationsTable, session, localMigrations) =>
98
99
  * Version 0: Original schema (id, hash, created_at)
99
100
  * Version 1: Extended schema (id, hash, created_at, name, applied_at)
100
101
  */
101
- async function upgradeAsyncIfNeeded(migrationsTable, session, localMigrations) {
102
+ async function upgradeAsyncIfNeeded(migrationsTable, session, localMigrations, mode = "transaction") {
102
103
  if ((await allAsync(session, sql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`, (row) => ({ "1": row[0] }))).length === 0) return { newDb: true };
103
104
  const version = getVersion((await allAsync(session, sql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`, (row) => ({ column_name: row[0] }))).map((r) => r.column_name));
104
105
  for (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {
105
106
  const upgradeFn = upgradeAsyncFunctions[v];
106
107
  if (!upgradeFn) throw new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);
107
- await upgradeFn(migrationsTable, session, localMigrations);
108
+ await upgradeFn(migrationsTable, session, localMigrations, mode);
108
109
  }
109
110
  return {
110
111
  prevVersion: version,
111
112
  currentVersion: CURRENT_MIGRATION_TABLE_VERSION
112
113
  };
113
114
  }
114
- const upgradeAsyncFunctions = { 0: async (migrationsTable, session, localMigrations) => {
115
+ const upgradeAsyncFunctions = { 0: async (migrationsTable, session, localMigrations, mode) => {
115
116
  const table = sql`${sql.identifier(migrationsTable)}`;
116
117
  const dbRows = await allAsync(session, sql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`, (row) => ({
117
118
  id: row[0],
@@ -154,17 +155,19 @@ const upgradeAsyncFunctions = { 0: async (migrationsTable, session, localMigrati
154
155
  else unmatched.push(dbRow);
155
156
  }
156
157
  if (unmatched.length > 0) throw Error(`While upgrading your database migrations table we found ${unmatched.length} (${unmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(", ")}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`);
157
- await session.transaction(async (tx) => {
158
- await tx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier("name")} text`);
159
- await tx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier("applied_at")} TEXT`);
160
- for (const backfillEntry of toApply) {
161
- const updateQuery = sql`UPDATE ${table} SET ${sql.identifier("name")} = ${backfillEntry.name}, ${sql.identifier("applied_at")} = NULL WHERE`;
162
- if (backfillEntry.id) updateQuery.append(sql` ${sql.identifier("id")} = ${backfillEntry.id}`);
163
- else if (backfillEntry.matchedBy === "millis") updateQuery.append(sql` ${sql.identifier("created_at")} = ${backfillEntry.created_at}`);
164
- else updateQuery.append(sql` ${sql.identifier("hash")} = ${backfillEntry.hash}`);
165
- await tx.run(updateQuery);
166
- }
158
+ const statements = [sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier("name")} text`, sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier("applied_at")} TEXT`];
159
+ for (const backfillEntry of toApply) {
160
+ const updateQuery = sql`UPDATE ${table} SET ${sql.identifier("name")} = ${backfillEntry.name}, ${sql.identifier("applied_at")} = NULL WHERE`;
161
+ if (backfillEntry.id) updateQuery.append(sql` ${sql.identifier("id")} = ${backfillEntry.id}`);
162
+ else if (backfillEntry.matchedBy === "millis") updateQuery.append(sql` ${sql.identifier("created_at")} = ${backfillEntry.created_at}`);
163
+ else updateQuery.append(sql` ${sql.identifier("hash")} = ${backfillEntry.hash}`);
164
+ statements.push(updateQuery);
165
+ }
166
+ if (mode === "transaction") await session.transaction(async (tx) => {
167
+ for (const statement of statements) await tx.run(statement);
167
168
  });
169
+ else if (mode === "run") for (const statement of statements) await session.run(statement);
170
+ else assertUnreachable(mode);
168
171
  } };
169
172
 
170
173
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.js","names":[],"sources":["../../src/up-migrations/sqlite.ts"],"sourcesContent":["import type { TablesRelationalConfig } from '~/_relations.ts';\nimport type { SQLiteD1Session } from '~/d1/session.ts';\nimport type { LibSQLSession } from '~/libsql/session.ts';\nimport type { MigrationMeta } from '~/migrator.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { type SQL, sql } from '~/sql/sql.ts';\nimport type { SQLiteCloudSession } from '~/sqlite-cloud/session.ts';\nimport type { SQLiteSession } from '~/sqlite-core/session.ts';\nimport type { SQLiteRemoteSession } from '~/sqlite-proxy/session.ts';\n\nconst CURRENT_MIGRATION_TABLE_VERSION = 1;\n\ninterface UpgradeResult {\n\tnewDb?: boolean;\n\tprevVersion?: number;\n\tcurrentVersion?: number;\n}\n\nfunction getVersion(columns: string[]) {\n\tif (columns.includes('name')) return 1;\n\treturn 0;\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nfunction allSync<T>(\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): T[] {\n\tconst result = session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nasync function allAsync<T>(\n\tsession: SQLiteSession<\n\t\t'async',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): Promise<T[]> {\n\tconst result = await session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport function upgradeSyncIfNeeded(\n\tmigrationsTable: string,\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tlocalMigrations: MigrationMeta[],\n): UpgradeResult {\n\t// Check if the table exists at all\n\t// sqlite-proxy returns [ [1] ]\n\t// sqlite returns [{ '1': 1 }]\n\tconst tableExists = allSync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\tconst rows = allSync<{ column_name: string }>(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeSyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tupgradeFn(migrationsTable, session, localMigrations);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeSyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'sync',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t) => void\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: (migrationsTable, session, localMigrations) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = allSync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tsession.transaction((tx) => {\n\t\t\ttx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`);\n\t\t\ttx.run(\n\t\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t\t);\n\n\t\t\tfor (const backfillEntry of toApply) {\n\t\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\t\tsql.identifier('applied_at')\n\t\t\t\t} = NULL WHERE`;\n\n\t\t\t\t// id\n\t\t\t\t// created_at\n\t\t\t\t// hash\n\t\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\t\ttx.run(updateQuery);\n\t\t\t}\n\t\t});\n\t},\n};\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport async function upgradeAsyncIfNeeded(\n\tmigrationsTable: string,\n\tsession:\n\t\t| SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>\n\t\t| SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>,\n\tlocalMigrations: MigrationMeta[],\n): Promise<UpgradeResult> {\n\t// Check if the table exists at all\n\tconst tableExists = await allAsync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\t// sqlite-proxy returns [ [string] ]\n\t// sqlite returns [{ column_name: string }]\n\tconst rows = await allAsync(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeAsyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tawait upgradeFn(migrationsTable, session, localMigrations);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeAsyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t) => Promise<void>\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: async (migrationsTable, session, localMigrations) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = await allAsync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tawait session.transaction(async (tx) => {\n\t\t\tawait tx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`);\n\t\t\tawait tx.run(\n\t\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t\t);\n\n\t\t\tfor (const backfillEntry of toApply) {\n\t\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\t\tsql.identifier('applied_at')\n\t\t\t\t} = NULL WHERE`;\n\n\t\t\t\t// id\n\t\t\t\t// created_at\n\t\t\t\t// hash\n\t\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\t\tawait tx.run(updateQuery);\n\t\t\t}\n\t\t});\n\t},\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"sqlite.js","names":[],"sources":["../../src/up-migrations/sqlite.ts"],"sourcesContent":["import type { TablesRelationalConfig } from '~/_relations.ts';\nimport type { SQLiteD1Session } from '~/d1/session.ts';\nimport type { LibSQLSession } from '~/libsql/session.ts';\nimport type { MigrationMeta } from '~/migrator.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport { type SQL, sql } from '~/sql/sql.ts';\nimport type { SQLiteCloudSession } from '~/sqlite-cloud/session.ts';\nimport type { SQLiteSession } from '~/sqlite-core/session.ts';\nimport type { SQLiteRemoteSession } from '~/sqlite-proxy/session.ts';\nimport { assertUnreachable } from '~/utils.ts';\n\nconst CURRENT_MIGRATION_TABLE_VERSION = 1;\n\ninterface UpgradeResult {\n\tnewDb?: boolean;\n\tprevVersion?: number;\n\tcurrentVersion?: number;\n}\n\nfunction getVersion(columns: string[]) {\n\tif (columns.includes('name')) return 1;\n\treturn 0;\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nfunction allSync<T>(\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): T[] {\n\tconst result = session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n// sqlite-proxy returns [ [string] ]\n// sqlite returns [{ column_name: string }]\nasync function allAsync<T>(\n\tsession: SQLiteSession<\n\t\t'async',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tsqlQuery: SQL,\n\tresultMapper: (row: any[]) => T = () => [] as T,\n): Promise<T[]> {\n\tconst result = await session.all(sqlQuery) as any[] | any[][];\n\n\tif (result.length === 0) return [];\n\n\tif (Array.isArray(result[0])) {\n\t\treturn (result as any[][]).map((row) => resultMapper(row));\n\t}\n\n\treturn result as T[];\n}\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport function upgradeSyncIfNeeded(\n\tmigrationsTable: string,\n\tsession: SQLiteSession<\n\t\t'sync',\n\t\tunknown,\n\t\tRecord<string, unknown>,\n\t\tAnyRelations,\n\t\tTablesRelationalConfig\n\t>,\n\tlocalMigrations: MigrationMeta[],\n): UpgradeResult {\n\t// Check if the table exists at all\n\t// sqlite-proxy returns [ [1] ]\n\t// sqlite returns [{ '1': 1 }]\n\tconst tableExists = allSync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\tconst rows = allSync<{ column_name: string }>(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeSyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tupgradeFn(migrationsTable, session, localMigrations);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeSyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'sync',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t) => void\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: (migrationsTable, session, localMigrations) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = allSync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tsession.transaction((tx) => {\n\t\t\ttx.run(sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`);\n\t\t\ttx.run(\n\t\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t\t);\n\n\t\t\tfor (const backfillEntry of toApply) {\n\t\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\t\tsql.identifier('applied_at')\n\t\t\t\t} = NULL WHERE`;\n\n\t\t\t\t// id\n\t\t\t\t// created_at\n\t\t\t\t// hash\n\t\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\t\ttx.run(updateQuery);\n\t\t\t}\n\t\t});\n\t},\n};\n\n/**\n * Detects the current version of the migrations table schema and upgrades it if needed.\n *\n * Version 0: Original schema (id, hash, created_at)\n * Version 1: Extended schema (id, hash, created_at, name, applied_at)\n */\nexport async function upgradeAsyncIfNeeded(\n\tmigrationsTable: string,\n\tsession:\n\t\t| SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>\n\t\t| SQLiteRemoteSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteD1Session<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| LibSQLSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>\n\t\t| SQLiteCloudSession<Record<string, unknown>, AnyRelations, TablesRelationalConfig>,\n\tlocalMigrations: MigrationMeta[],\n\tmode: 'transaction' | 'run' = 'transaction',\n): Promise<UpgradeResult> {\n\t// Check if the table exists at all\n\tconst tableExists = await allAsync(\n\t\tsession,\n\t\tsql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`,\n\t\t(row) => ({ '1': row[0] }),\n\t);\n\n\tif (tableExists.length === 0) {\n\t\treturn { newDb: true };\n\t}\n\n\t// Table exists, check table shape\n\t// sqlite-proxy returns [ [string] ]\n\t// sqlite returns [{ column_name: string }]\n\tconst rows = await allAsync(\n\t\tsession,\n\t\tsql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`,\n\t\t(row) => ({ column_name: row[0] }),\n\t);\n\n\tconst version = getVersion(rows.map((r) => r.column_name));\n\n\tfor (let v = version; v < CURRENT_MIGRATION_TABLE_VERSION; v++) {\n\t\tconst upgradeFn = upgradeAsyncFunctions[v];\n\t\tif (!upgradeFn) {\n\t\t\tthrow new Error(`No upgrade path from migration table version ${v} to ${v + 1}`);\n\t\t}\n\t\tawait upgradeFn(migrationsTable, session, localMigrations, mode);\n\t}\n\n\treturn { prevVersion: version, currentVersion: CURRENT_MIGRATION_TABLE_VERSION };\n}\n\nconst upgradeAsyncFunctions: Record<\n\tnumber,\n\t(\n\t\tmigrationsTable: string,\n\t\tsession: SQLiteSession<\n\t\t\t'async',\n\t\t\tunknown,\n\t\t\tRecord<string, unknown>,\n\t\t\tAnyRelations,\n\t\t\tTablesRelationalConfig\n\t\t>,\n\t\tlocalMigrations: MigrationMeta[],\n\t\tmode: 'transaction' | 'run',\n\t) => Promise<void>\n> = {\n\t/**\n\t * Upgrade from version 0 to version 1:\n\t * 1. Read all existing DB migrations\n\t * 2. Sort localMigrations ASC by millis and if the same - sort by name\n\t * 3. Match each DB row to a local migration\n\t * If multiple migrations share the same second, use hash matching as a tiebreaker\n\t * Not implemented for now -> If hash matching fails, fall back to serial id ordering\n\t * 5. Create extra column and backfill names for matched migrations\n\t */\n\t0: async (migrationsTable, session, localMigrations, mode) => {\n\t\tconst table = sql`${sql.identifier(migrationsTable)}`;\n\n\t\t// 1. Read all existing DB migrations\n\t\t// Sort them by ids asc (order how they were applied)\n\t\t// this can be null from legacy implementation where id was serial\n\t\tconst dbRows = await allAsync<{ id: number | null; hash: string; created_at: number }>(\n\t\t\tsession,\n\t\t\tsql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`,\n\t\t\t(row) => ({\n\t\t\t\tid: row[0],\n\t\t\t\thash: row[1],\n\t\t\t\tcreated_at: row[2],\n\t\t\t}),\n\t\t);\n\n\t\t// 2. Sort ASC by millis and if the same - sort by name\n\t\tlocalMigrations.sort((a, b) =>\n\t\t\ta.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? '').localeCompare(b.name ?? '')\n\t\t);\n\n\t\tconst byMillis = new Map<number, MigrationMeta[]>();\n\t\tconst byHash = new Map<string, MigrationMeta>();\n\t\tfor (const lm of localMigrations) {\n\t\t\tif (!byMillis.has(lm.folderMillis)) {\n\t\t\t\tbyMillis.set(lm.folderMillis, []);\n\t\t\t}\n\t\t\tbyMillis.get(lm.folderMillis)!.push(lm);\n\t\t\tbyHash.set(lm.hash, lm);\n\t\t}\n\n\t\t// \t3. Match each DB row to a local migration\n\t\t// \tPriority: millis -> hash\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\tconst toApply: {\n\t\t\tid: number | null;\n\t\t\tname: string;\n\t\t\thash: string;\n\t\t\tcreated_at: string;\n\t\t\tmatchedBy: 'id' | 'hash' | 'millis';\n\t\t}[] = [];\n\n\t\t// id can be null from legacy implementation where id was serial\n\t\t// hash can only be '' for bun-sqlite journal entries\n\t\tlet unmatched: { id: number | null; hash: string; created_at: number }[] = [];\n\n\t\tfor (const dbRow of dbRows) {\n\t\t\tconst stringified = String(dbRow.created_at);\n\t\t\tconst millis = Number(stringified.substring(0, stringified.length - 3) + '000');\n\t\t\tconst candidates = byMillis.get(millis);\n\n\t\t\tlet matched: MigrationMeta | undefined;\n\t\t\tlet matchedBy: 'hash' | 'millis' | null = null;\n\t\t\tif (candidates && candidates.length === 1) {\n\t\t\t\tmatched = candidates[0];\n\t\t\t\tmatchedBy = 'millis';\n\t\t\t} else if (candidates && candidates.length > 1) {\n\t\t\t\tmatched = candidates.find((c) => c.hash && dbRow.hash && c.hash === dbRow.hash); // for bun-sqlite cases (journal had empty hash)\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t} else {\n\t\t\t\tmatched = byHash.get(dbRow.hash);\n\t\t\t\tif (matched) matchedBy = 'hash';\n\t\t\t}\n\n\t\t\tif (matched) {\n\t\t\t\ttoApply.push({\n\t\t\t\t\tid: dbRow.id,\n\t\t\t\t\tname: matched.name,\n\t\t\t\t\thash: dbRow.hash,\n\t\t\t\t\tcreated_at: stringified,\n\t\t\t\t\tmatchedBy: dbRow.id ? 'id' : matchedBy!,\n\t\t\t\t});\n\t\t\t} else unmatched.push(dbRow);\n\t\t}\n\n\t\t// 4. Check for unmatched\n\t\t// Our assumption on this migration flow is that all DB entries should be matched to a local migration\n\t\t// (if same seconds - fallback to hash, if hash fails - corner case)\n\t\t// If there are unmatched entries, it means that the local environment is missing migrations that have been applied to the DB,\n\t\t// which can lead to inconsistencies and potential issues when running future migrations\n\t\tif (unmatched.length > 0) {\n\t\t\tthrow Error(\n\t\t\t\t`While upgrading your database migrations table we found ${unmatched.length} (${\n\t\t\t\t\tunmatched.map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`).join(', ')\n\t\t\t\t}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`,\n\t\t\t);\n\t\t}\n\n\t\t// 5. Create extra column and backfill names for matched migrations\n\t\tconst statements: SQL[] = [\n\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('name')} text`,\n\t\t\tsql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier('applied_at')} TEXT`,\n\t\t];\n\t\tfor (const backfillEntry of toApply) {\n\t\t\tconst updateQuery = sql`UPDATE ${table} SET ${sql.identifier('name')} = ${backfillEntry.name}, ${\n\t\t\t\tsql.identifier('applied_at')\n\t\t\t} = NULL WHERE`;\n\n\t\t\t// id\n\t\t\t// created_at\n\t\t\t// hash\n\t\t\tif (backfillEntry.id) updateQuery.append(sql` ${sql.identifier('id')} = ${backfillEntry.id}`);\n\t\t\telse if (backfillEntry.matchedBy === 'millis') {\n\t\t\t\tupdateQuery.append(sql` ${sql.identifier('created_at')} = ${backfillEntry.created_at}`);\n\t\t\t} else updateQuery.append(sql` ${sql.identifier('hash')} = ${backfillEntry.hash}`);\n\n\t\t\tstatements.push(updateQuery);\n\t\t}\n\n\t\tif (mode === 'transaction') {\n\t\t\t// for normal sqlite proxy migrate() call from code\n\t\t\tawait session.transaction(async (tx) => {\n\t\t\t\tfor (const statement of statements) {\n\t\t\t\t\tawait tx.run(statement);\n\t\t\t\t}\n\t\t\t});\n\t\t} else if (mode === 'run') {\n\t\t\t// for drizzle-kit migrate call for d1 driver\n\t\t\t// see drizzle-kit/src/cli/connections.ts for sqlite d1\n\t\t\tfor (const statement of statements) {\n\t\t\t\tawait session.run(statement);\n\t\t\t}\n\t\t} else assertUnreachable(mode);\n\t},\n};\n"],"mappings":"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"}