@fragno-dev/db 0.1.1 → 0.1.2

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 (108) hide show
  1. package/.turbo/turbo-build.log +61 -53
  2. package/CHANGELOG.md +12 -0
  3. package/dist/adapters/adapters.d.ts +11 -1
  4. package/dist/adapters/adapters.d.ts.map +1 -1
  5. package/dist/adapters/drizzle/drizzle-adapter.d.ts +9 -2
  6. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.js +21 -39
  8. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  9. package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -1
  10. package/dist/adapters/drizzle/drizzle-query.js +3 -2
  11. package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
  12. package/dist/adapters/drizzle/drizzle-uow-compiler.js +8 -6
  13. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
  14. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
  15. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
  16. package/dist/adapters/drizzle/generate.js +107 -34
  17. package/dist/adapters/drizzle/generate.js.map +1 -1
  18. package/dist/adapters/drizzle/shared.js +14 -1
  19. package/dist/adapters/drizzle/shared.js.map +1 -1
  20. package/dist/adapters/kysely/kysely-adapter.d.ts +2 -1
  21. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  22. package/dist/adapters/kysely/kysely-adapter.js +25 -30
  23. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  24. package/dist/adapters/kysely/kysely-query-builder.js +48 -44
  25. package/dist/adapters/kysely/kysely-query-builder.js.map +1 -1
  26. package/dist/adapters/kysely/kysely-query-compiler.js +2 -2
  27. package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
  28. package/dist/adapters/kysely/kysely-query.js +3 -2
  29. package/dist/adapters/kysely/kysely-query.js.map +1 -1
  30. package/dist/adapters/kysely/kysely-shared.js +18 -0
  31. package/dist/adapters/kysely/kysely-shared.js.map +1 -0
  32. package/dist/adapters/kysely/kysely-uow-compiler.js +4 -3
  33. package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
  34. package/dist/adapters/kysely/migration/execute.js +15 -12
  35. package/dist/adapters/kysely/migration/execute.js.map +1 -1
  36. package/dist/migration-engine/auto-from-schema.js +2 -8
  37. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  38. package/dist/migration-engine/create.d.ts +1 -5
  39. package/dist/migration-engine/create.js +1 -1
  40. package/dist/migration-engine/create.js.map +1 -1
  41. package/dist/migration-engine/generation-engine.d.ts +51 -0
  42. package/dist/migration-engine/generation-engine.d.ts.map +1 -0
  43. package/dist/migration-engine/generation-engine.js +165 -0
  44. package/dist/migration-engine/generation-engine.js.map +1 -0
  45. package/dist/migration-engine/shared.d.ts +5 -2
  46. package/dist/migration-engine/shared.d.ts.map +1 -1
  47. package/dist/migration-engine/shared.js.map +1 -1
  48. package/dist/mod.d.ts +0 -8
  49. package/dist/mod.d.ts.map +1 -1
  50. package/dist/mod.js +0 -32
  51. package/dist/mod.js.map +1 -1
  52. package/dist/query/condition-builder.js.map +1 -1
  53. package/dist/query/result-transform.js +2 -1
  54. package/dist/query/result-transform.js.map +1 -1
  55. package/dist/schema/create.d.ts +74 -16
  56. package/dist/schema/create.d.ts.map +1 -1
  57. package/dist/schema/create.js +76 -11
  58. package/dist/schema/create.js.map +1 -1
  59. package/dist/schema/serialize.js.map +1 -1
  60. package/dist/shared/settings-schema.js +36 -0
  61. package/dist/shared/settings-schema.js.map +1 -0
  62. package/dist/util/import-generator.js.map +1 -1
  63. package/dist/util/parse.js.map +1 -1
  64. package/package.json +8 -2
  65. package/src/adapters/adapters.ts +10 -3
  66. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +11 -7
  67. package/src/adapters/drizzle/drizzle-adapter.test.ts +77 -29
  68. package/src/adapters/drizzle/drizzle-adapter.ts +31 -78
  69. package/src/adapters/drizzle/drizzle-query.ts +4 -7
  70. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +9 -3
  71. package/src/adapters/drizzle/drizzle-uow-compiler.ts +12 -6
  72. package/src/adapters/drizzle/drizzle-uow-decoder.ts +1 -1
  73. package/src/adapters/drizzle/drizzle-uow-executor.ts +1 -1
  74. package/src/adapters/drizzle/generate.test.ts +573 -150
  75. package/src/adapters/drizzle/generate.ts +187 -36
  76. package/src/adapters/drizzle/migrate-drizzle.test.ts +30 -6
  77. package/src/adapters/drizzle/shared.ts +31 -1
  78. package/src/adapters/drizzle/test-utils.ts +3 -1
  79. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +25 -27
  80. package/src/adapters/kysely/kysely-adapter.ts +35 -58
  81. package/src/adapters/kysely/kysely-query-builder.ts +75 -44
  82. package/src/adapters/kysely/kysely-query-compiler.ts +3 -1
  83. package/src/adapters/kysely/kysely-query.ts +8 -2
  84. package/src/adapters/kysely/kysely-shared.ts +23 -0
  85. package/src/adapters/kysely/kysely-uow-compiler.ts +5 -2
  86. package/src/adapters/kysely/migration/execute-mysql.test.ts +2 -2
  87. package/src/adapters/kysely/migration/execute-postgres.test.ts +19 -19
  88. package/src/adapters/kysely/migration/execute.ts +48 -17
  89. package/src/adapters/kysely/migration/kysely-migrator.test.ts +19 -37
  90. package/src/fragment.test.ts +1 -0
  91. package/src/migration-engine/auto-from-schema.ts +14 -18
  92. package/src/migration-engine/create.ts +1 -6
  93. package/src/migration-engine/generation-engine.test.ts +597 -0
  94. package/src/migration-engine/generation-engine.ts +356 -0
  95. package/src/migration-engine/shared.ts +1 -4
  96. package/src/mod.ts +0 -66
  97. package/src/query/condition-builder.ts +24 -8
  98. package/src/query/result-transform.ts +7 -1
  99. package/src/schema/create.test.ts +4 -1
  100. package/src/schema/create.ts +132 -24
  101. package/src/schema/serialize.ts +21 -7
  102. package/src/shared/settings-schema.ts +61 -0
  103. package/src/util/deep-equal.ts +21 -7
  104. package/src/util/import-generator.ts +3 -1
  105. package/src/util/parse.ts +3 -1
  106. package/tsdown.config.ts +1 -0
  107. package/.turbo/turbo-test.log +0 -37
  108. package/.turbo/turbo-types$colon$check.log +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","names":[],"sources":["../../../src/adapters/drizzle/shared.ts"],"sourcesContent":["import * as Drizzle from \"drizzle-orm\";\nimport type * as MySQL from \"drizzle-orm/mysql-core\";\n\nexport type TableType = MySQL.MySqlTableWithColumns<MySQL.TableConfig>;\nexport type ColumnType = MySQL.AnyMySqlColumn;\nexport type DBType = MySQL.MySqlDatabase<\n MySQL.MySqlQueryResultHKT,\n MySQL.PreparedQueryHKTBase,\n Record<string, unknown>,\n Drizzle.TablesRelationalConfig\n>;\n\nexport function parseDrizzle(drizzle: unknown) {\n const db = drizzle as DBType;\n const drizzleTables = db._.fullSchema as Record<string, TableType>;\n if (!drizzleTables || Object.keys(drizzleTables).length === 0)\n throw new Error(\n \"Drizzle adapter requires query mode, make sure to configure it following their guide: https://orm.drizzle.team/docs/rqb.\",\n );\n\n return [db, drizzleTables] as const;\n}\n"],"mappings":";AAYA,SAAgB,aAAa,SAAkB;CAC7C,MAAM,KAAK;CACX,MAAM,gBAAgB,GAAG,EAAE;AAC3B,KAAI,CAAC,iBAAiB,OAAO,KAAK,cAAc,CAAC,WAAW,EAC1D,OAAM,IAAI,MACR,2HACD;AAEH,QAAO,CAAC,IAAI,cAAc"}
1
+ {"version":3,"file":"shared.js","names":[],"sources":["../../../src/adapters/drizzle/shared.ts"],"sourcesContent":["import * as Drizzle from \"drizzle-orm\";\nimport type * as MySQL from \"drizzle-orm/mysql-core\";\n\nexport type TableType = MySQL.MySqlTableWithColumns<MySQL.TableConfig>;\nexport type ColumnType = MySQL.AnyMySqlColumn;\nexport type DBType = MySQL.MySqlDatabase<\n MySQL.MySqlQueryResultHKT,\n MySQL.PreparedQueryHKTBase,\n Record<string, unknown>,\n Drizzle.TablesRelationalConfig\n>;\n\nexport function parseDrizzle(drizzle: unknown) {\n const db = drizzle as DBType;\n const drizzleTables = db._.fullSchema as Record<string, TableType>;\n if (!drizzleTables || Object.keys(drizzleTables).length === 0) {\n throw new Error(\n \"Drizzle adapter requires query mode, make sure to configure it following their guide: https://orm.drizzle.team/docs/rqb.\",\n );\n }\n\n return [db, drizzleTables] as const;\n}\n\n/**\n * Maps logical table names (used by fragment authors) to physical table names (with namespace suffix)\n */\nexport interface TableNameMapper {\n toPhysical(logicalName: string): string;\n toLogical(physicalName: string): string;\n}\n\n/**\n * Creates a table name mapper for a given namespace.\n * Physical names have format: {logicalName}_{namespace}\n */\nexport function createTableNameMapper(namespace: string): TableNameMapper {\n return {\n toPhysical: (logicalName: string) => `${logicalName}_${namespace}`,\n toLogical: (physicalName: string) => {\n if (physicalName.endsWith(`_${namespace}`)) {\n return physicalName.slice(0, -(namespace.length + 1));\n }\n return physicalName;\n },\n };\n}\n\nexport interface DrizzleResult {\n rows: Record<string, unknown>[];\n affectedRows: number;\n}\n"],"mappings":";AAYA,SAAgB,aAAa,SAAkB;CAC7C,MAAM,KAAK;CACX,MAAM,gBAAgB,GAAG,EAAE;AAC3B,KAAI,CAAC,iBAAiB,OAAO,KAAK,cAAc,CAAC,WAAW,EAC1D,OAAM,IAAI,MACR,2HACD;AAGH,QAAO,CAAC,IAAI,cAAc;;;;;;AAe5B,SAAgB,sBAAsB,WAAoC;AACxE,QAAO;EACL,aAAa,gBAAwB,GAAG,YAAY,GAAG;EACvD,YAAY,iBAAyB;AACnC,OAAI,aAAa,SAAS,IAAI,YAAY,CACxC,QAAO,aAAa,MAAM,GAAG,EAAE,UAAU,SAAS,GAAG;AAEvD,UAAO;;EAEV"}
@@ -14,7 +14,8 @@ interface KyselyConfig {
14
14
  declare class KyselyAdapter implements DatabaseAdapter {
15
15
  #private;
16
16
  constructor(config: KyselyConfig);
17
- createQueryEngine<T extends AnySchema>(schema: T, _namespace: string): AbstractQuery<T>;
17
+ createQueryEngine<T extends AnySchema>(schema: T, namespace: string): AbstractQuery<T>;
18
+ isConnectionHealthy(): Promise<boolean>;
18
19
  createMigrationEngine(schema: AnySchema, namespace: string): Migrator;
19
20
  getSchemaVersion(namespace: string): Promise<string | undefined>;
20
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-adapter.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAcK,SAAA,GAAY;UAEA,YAAA;EAFZ,EAAA,EAGC,SAHQ;EAEG,QAAA,EAEL,WAFiB;AAK7B;AAGsB,cAHT,aAAA,YAAyB,eAGhB,CAAA;EAIQ,CAAA,OAAA;EAAmB,WAAA,CAAA,MAAA,EAJ3B,YAI2B;EAAsC,iBAAA,CAAA,UAAzD,SAAyD,CAAA,CAAA,MAAA,EAAtC,CAAsC,EAAA,UAAA,EAAA,MAAA,CAAA,EAAd,aAAc,CAAA,CAAA,CAAA;EAAd,qBAAA,CAAA,MAAA,EAIzC,SAJyC,EAAA,SAAA,EAAA,MAAA,CAAA,EAIV,QAJU;EAIzC,gBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAkGI,OAlGJ,CAAA,MAAA,GAAA,SAAA,CAAA"}
1
+ {"version":3,"file":"kysely-adapter.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAcK,SAAA,GAAY;UAEA,YAAA;EAFZ,EAAA,EAGC,SAHQ;EAEG,QAAA,EAEL,WAFiB;AAK7B;AAGsB,cAHT,aAAA,YAAyB,eAGhB,CAAA;EAIQ,CAAA,OAAA;EAAmB,WAAA,CAAA,MAAA,EAJ3B,YAI2B;EAAqC,iBAAA,CAAA,UAAxD,SAAwD,CAAA,CAAA,MAAA,EAArC,CAAqC,EAAA,SAAA,EAAA,MAAA,CAAA,EAAd,aAAc,CAAA,CAAA,CAAA;EAAd,mBAAA,CAAA,CAAA,EAMzC,OANyC,CAAA,OAAA,CAAA;EAMzC,qBAAA,CAAA,MAAA,EAWC,SAXD,EAAA,SAAA,EAAA,MAAA,CAAA,EAWgC,QAXhC;EAWC,gBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EA+EI,OA/EJ,CAAA,MAAA,GAAA,SAAA,CAAA"}
@@ -1,21 +1,31 @@
1
- import { schemaToDBType } from "../../schema/serialize.js";
1
+ import { SETTINGS_TABLE_NAME } from "../../shared/settings-schema.js";
2
2
  import { createMigrator } from "../../migration-engine/create.js";
3
3
  import { execute } from "./migration/execute.js";
4
4
  import { fromKysely } from "./kysely-query.js";
5
+ import { createTableNameMapper } from "./kysely-shared.js";
5
6
  import { sql } from "kysely";
7
+ import { createHash } from "node:crypto";
6
8
 
7
9
  //#region src/adapters/kysely/kysely-adapter.ts
8
- const SETTINGS_TABLE_NAME = "fragno_db_settings";
9
10
  var KyselyAdapter = class {
10
11
  #kyselyConfig;
11
12
  constructor(config) {
12
13
  this.#kyselyConfig = config;
13
14
  }
14
- createQueryEngine(schema, _namespace) {
15
- return fromKysely(schema, this.#kyselyConfig);
15
+ createQueryEngine(schema, namespace) {
16
+ const mapper = namespace ? createTableNameMapper(namespace) : void 0;
17
+ return fromKysely(schema, this.#kyselyConfig, mapper);
18
+ }
19
+ async isConnectionHealthy() {
20
+ try {
21
+ return (await this.#kyselyConfig.db.executeQuery(sql`SELECT 1 as healthy`.compile(this.#kyselyConfig.db))).rows[0]["healthy"] === 1;
22
+ } catch {
23
+ return false;
24
+ }
16
25
  }
17
26
  createMigrationEngine(schema, namespace) {
18
- const manager = createSettingsManager(this.#kyselyConfig.db, this.#kyselyConfig.provider, SETTINGS_TABLE_NAME, namespace);
27
+ const manager = createSettingsManager(this.#kyselyConfig.db, namespace);
28
+ const mapper = namespace ? createTableNameMapper(namespace) : void 0;
19
29
  const onCustomNode = (node, db) => {
20
30
  const statement = sql.raw(node["sql"]);
21
31
  return {
@@ -41,9 +51,9 @@ var KyselyAdapter = class {
41
51
  type: "custom",
42
52
  sql: "PRAGMA defer_foreign_keys = ON"
43
53
  });
44
- return operations.flatMap((op) => execute(op, this.#kyselyConfig, (node) => onCustomNode(node, db)));
54
+ return operations.flatMap((op) => execute(op, this.#kyselyConfig, (node) => onCustomNode(node, db), mapper));
45
55
  };
46
- const migrator = createMigrator({
56
+ return createMigrator({
47
57
  schema,
48
58
  executor: async (operations) => {
49
59
  await this.#kyselyConfig.db.transaction().execute(async (tx) => {
@@ -64,52 +74,37 @@ var KyselyAdapter = class {
64
74
  return v ? parseInt(v) : 0;
65
75
  },
66
76
  updateSettingsInMigration: async (fromVersion, toVersion) => {
67
- if (fromVersion === 0) return [{
68
- type: "custom",
69
- sql: manager.initTable()
70
- }, {
71
- type: "custom",
72
- sql: manager.insert(`schema_version`, toVersion.toString())
73
- }];
74
77
  return [{
75
78
  type: "custom",
76
- sql: manager.update(`schema_version`, toVersion.toString())
79
+ sql: fromVersion === 0 ? manager.insert(`schema_version`, toVersion.toString()) : manager.update(`schema_version`, toVersion.toString())
77
80
  }];
78
81
  }
79
82
  }
80
83
  });
81
- migrator.getDefaultFileName = (namespace$1, fromVersion, toVersion) => {
82
- return `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, "")}_${namespace$1.replace(/[^a-z0-9-]/gi, "_")}_migration_${fromVersion}_to_${toVersion}.sql`;
83
- };
84
- return migrator;
85
84
  }
86
85
  getSchemaVersion(namespace) {
87
- return createSettingsManager(this.#kyselyConfig.db, this.#kyselyConfig.provider, SETTINGS_TABLE_NAME, namespace).get(`schema_version`);
86
+ return createSettingsManager(this.#kyselyConfig.db, namespace).get(`schema_version`);
88
87
  }
89
88
  };
90
- function createSettingsManager(db, provider, settingsTableName, namespace) {
91
- function initTable() {
92
- return db.schema.createTable(settingsTableName).addColumn("key", provider === "sqlite" ? "text" : "varchar(255)", (col) => col.primaryKey()).addColumn("value", sql.raw(schemaToDBType({ type: "string" }, provider)), (col) => col.notNull());
93
- }
89
+ function createSettingsManager(db, namespace) {
90
+ const tableName = SETTINGS_TABLE_NAME;
94
91
  return {
95
92
  async get(key) {
96
93
  try {
97
- return (await db.selectFrom(settingsTableName).where("key", "=", sql.lit(`${namespace}.${key}`)).select(["value"]).executeTakeFirstOrThrow()).value;
94
+ return (await db.selectFrom(tableName).where("key", "=", sql.lit(`${namespace}.${key}`)).select(["value"]).executeTakeFirstOrThrow()).value;
98
95
  } catch {
99
96
  return;
100
97
  }
101
98
  },
102
- initTable() {
103
- return initTable().compile().sql;
104
- },
105
99
  insert(key, value) {
106
- return db.insertInto(settingsTableName).values({
100
+ return db.insertInto(tableName).values({
101
+ id: sql.lit(createHash("md5").update(`${namespace}.${key}`).digest("base64url").replace(/=/g, "")),
107
102
  key: sql.lit(`${namespace}.${key}`),
108
103
  value: sql.lit(value)
109
104
  }).compile().sql;
110
105
  },
111
106
  update(key, value) {
112
- return db.updateTable(settingsTableName).set({ value: sql.lit(value) }).where("key", "=", sql.lit(`${namespace}.${key}`)).compile().sql;
107
+ return db.updateTable(tableName).set({ value: sql.lit(value) }).where("key", "=", sql.lit(`${namespace}.${key}`)).compile().sql;
113
108
  }
114
109
  };
115
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-adapter.js","names":["#kyselyConfig","namespace"],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport type { DatabaseAdapter } from \"../adapters\";\nimport { schemaToDBType } from \"../../schema/serialize\";\nimport { createMigrator, type Migrator } from \"../../migration-engine/create\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { CustomOperation, MigrationOperation } from \"../../migration-engine/shared\";\nimport { execute } from \"./migration/execute\";\nimport type { AbstractQuery } from \"../../query/query\";\nimport { fromKysely } from \"./kysely-query\";\n\nconst SETTINGS_TABLE_NAME = \"fragno_db_settings\" as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\nexport interface KyselyConfig {\n db: KyselyAny;\n provider: SQLProvider;\n}\n\nexport class KyselyAdapter implements DatabaseAdapter {\n #kyselyConfig: KyselyConfig;\n\n constructor(config: KyselyConfig) {\n this.#kyselyConfig = config;\n }\n\n createQueryEngine<T extends AnySchema>(schema: T, _namespace: string): AbstractQuery<T> {\n return fromKysely(schema, this.#kyselyConfig);\n }\n\n createMigrationEngine(schema: AnySchema, namespace: string): Migrator {\n const manager = createSettingsManager(\n this.#kyselyConfig.db,\n this.#kyselyConfig.provider,\n SETTINGS_TABLE_NAME,\n namespace,\n );\n\n const onCustomNode = (node: CustomOperation, db: KyselyAny) => {\n const statement = sql.raw(node[\"sql\"] as string);\n\n return {\n compile() {\n return statement.compile(db);\n },\n execute() {\n return statement.execute(db);\n },\n };\n };\n\n const preprocess = (operations: MigrationOperation[], db: KyselyAny) => {\n if (this.#kyselyConfig.provider === \"mysql\") {\n operations.unshift({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 0\" });\n operations.push({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 1\" });\n } else if (this.#kyselyConfig.provider === \"sqlite\") {\n operations.unshift({\n type: \"custom\",\n sql: \"PRAGMA defer_foreign_keys = ON\",\n });\n }\n\n return operations.flatMap((op) =>\n execute(op, this.#kyselyConfig, (node) => onCustomNode(node, db)),\n );\n };\n\n const migrator = createMigrator({\n schema,\n executor: async (operations) => {\n await this.#kyselyConfig.db.transaction().execute(async (tx) => {\n for (const node of preprocess(operations, tx)) {\n try {\n await node.execute();\n } catch (e) {\n console.error(\"failed at\", node.compile(), e);\n throw e;\n }\n }\n });\n },\n sql: {\n toSql: (operations) => {\n const compiled = preprocess(operations, this.#kyselyConfig.db).map(\n (m) => `${m.compile().sql};`,\n );\n\n return compiled.join(\"\\n\\n\");\n },\n },\n\n settings: {\n getVersion: async () => {\n const v = await manager.get(`schema_version`);\n return v ? parseInt(v) : 0;\n },\n updateSettingsInMigration: async (fromVersion, toVersion) => {\n // Only create the settings table if we're migrating from version 0\n if (fromVersion === 0) {\n return [\n { type: \"custom\", sql: manager.initTable() },\n {\n type: \"custom\",\n sql: manager.insert(`schema_version`, toVersion.toString()),\n },\n ];\n }\n\n return [\n {\n type: \"custom\",\n sql: manager.update(`schema_version`, toVersion.toString()),\n },\n ];\n },\n },\n });\n\n // Add getDefaultFileName implementation\n migrator.getDefaultFileName = (namespace: string, fromVersion: number, toVersion: number) => {\n const date = new Date().toISOString().split(\"T\")[0].replace(/-/g, \"\");\n const safeName = namespace.replace(/[^a-z0-9-]/gi, \"_\");\n return `${date}_${safeName}_migration_${fromVersion}_to_${toVersion}.sql`;\n };\n\n return migrator;\n }\n\n getSchemaVersion(namespace: string) {\n const manager = createSettingsManager(\n this.#kyselyConfig.db,\n this.#kyselyConfig.provider,\n SETTINGS_TABLE_NAME,\n namespace,\n );\n\n return manager.get(`schema_version`);\n }\n}\n\nfunction createSettingsManager(\n db: KyselyAny,\n provider: SQLProvider,\n settingsTableName: string,\n namespace: string,\n) {\n function initTable() {\n return db.schema\n .createTable(settingsTableName)\n .addColumn(\"key\", provider === \"sqlite\" ? \"text\" : \"varchar(255)\", (col) => col.primaryKey())\n .addColumn(\"value\", sql.raw(schemaToDBType({ type: \"string\" }, provider)), (col) =>\n col.notNull(),\n );\n }\n\n return {\n async get(key: string): Promise<string | undefined> {\n try {\n const result = await db\n .selectFrom(settingsTableName)\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .select([\"value\"])\n .executeTakeFirstOrThrow();\n return result.value as string;\n } catch {\n return;\n }\n },\n\n initTable() {\n return initTable().compile().sql;\n },\n\n insert(key: string, value: string) {\n return db\n .insertInto(settingsTableName)\n .values({\n key: sql.lit(`${namespace}.${key}`),\n value: sql.lit(value),\n })\n .compile().sql;\n },\n\n update(key: string, value: string) {\n return db\n .updateTable(settingsTableName)\n .set({\n value: sql.lit(value),\n })\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .compile().sql;\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"kysely-adapter.js","names":["#kyselyConfig"],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport type { DatabaseAdapter } from \"../adapters\";\nimport { createMigrator, type Migrator } from \"../../migration-engine/create\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { CustomOperation, MigrationOperation } from \"../../migration-engine/shared\";\nimport { execute } from \"./migration/execute\";\nimport type { AbstractQuery } from \"../../query/query\";\nimport { fromKysely } from \"./kysely-query\";\nimport { createTableNameMapper } from \"./kysely-shared\";\nimport { createHash } from \"node:crypto\";\nimport { SETTINGS_TABLE_NAME } from \"../../shared/settings-schema\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\nexport interface KyselyConfig {\n db: KyselyAny;\n provider: SQLProvider;\n}\n\nexport class KyselyAdapter implements DatabaseAdapter {\n #kyselyConfig: KyselyConfig;\n\n constructor(config: KyselyConfig) {\n this.#kyselyConfig = config;\n }\n\n createQueryEngine<T extends AnySchema>(schema: T, namespace: string): AbstractQuery<T> {\n // Only create mapper if namespace is non-empty\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n return fromKysely(schema, this.#kyselyConfig, mapper);\n }\n\n async isConnectionHealthy(): Promise<boolean> {\n try {\n const result = await this.#kyselyConfig.db.executeQuery(\n sql`SELECT 1 as healthy`.compile(this.#kyselyConfig.db),\n );\n return (result.rows[0] as Record<string, unknown>)[\"healthy\"] === 1;\n } catch {\n return false;\n }\n }\n\n createMigrationEngine(schema: AnySchema, namespace: string): Migrator {\n const manager = createSettingsManager(this.#kyselyConfig.db, namespace);\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n\n const onCustomNode = (node: CustomOperation, db: KyselyAny) => {\n const statement = sql.raw(node[\"sql\"] as string);\n\n return {\n compile() {\n return statement.compile(db);\n },\n execute() {\n return statement.execute(db);\n },\n };\n };\n\n const preprocess = (operations: MigrationOperation[], db: KyselyAny) => {\n if (this.#kyselyConfig.provider === \"mysql\") {\n operations.unshift({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 0\" });\n operations.push({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 1\" });\n } else if (this.#kyselyConfig.provider === \"sqlite\") {\n operations.unshift({\n type: \"custom\",\n sql: \"PRAGMA defer_foreign_keys = ON\",\n });\n }\n\n return operations.flatMap((op) =>\n execute(op, this.#kyselyConfig, (node) => onCustomNode(node, db), mapper),\n );\n };\n\n const migrator = createMigrator({\n schema,\n executor: async (operations) => {\n await this.#kyselyConfig.db.transaction().execute(async (tx) => {\n for (const node of preprocess(operations, tx)) {\n try {\n await node.execute();\n } catch (e) {\n console.error(\"failed at\", node.compile(), e);\n throw e;\n }\n }\n });\n },\n sql: {\n toSql: (operations) => {\n const compiled = preprocess(operations, this.#kyselyConfig.db).map(\n (m) => `${m.compile().sql};`,\n );\n\n return compiled.join(\"\\n\\n\");\n },\n },\n\n settings: {\n getVersion: async () => {\n const v = await manager.get(`schema_version`);\n return v ? parseInt(v) : 0;\n },\n updateSettingsInMigration: async (fromVersion, toVersion) => {\n return [\n {\n type: \"custom\",\n sql:\n fromVersion === 0\n ? manager.insert(`schema_version`, toVersion.toString())\n : manager.update(`schema_version`, toVersion.toString()),\n },\n ];\n },\n },\n });\n\n return migrator;\n }\n\n getSchemaVersion(namespace: string) {\n const manager = createSettingsManager(this.#kyselyConfig.db, namespace);\n\n return manager.get(`schema_version`);\n }\n}\n\nfunction createSettingsManager(db: KyselyAny, namespace: string) {\n // Settings table is never namespaced, but keys include namespace prefix\n const tableName = SETTINGS_TABLE_NAME;\n\n return {\n async get(key: string): Promise<string | undefined> {\n try {\n const result = await db\n .selectFrom(tableName)\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .select([\"value\"])\n .executeTakeFirstOrThrow();\n return result.value as string;\n } catch {\n return;\n }\n },\n\n insert(key: string, value: string) {\n return db\n .insertInto(tableName)\n .values({\n id: sql.lit(\n createHash(\"md5\").update(`${namespace}.${key}`).digest(\"base64url\").replace(/=/g, \"\"),\n ),\n key: sql.lit(`${namespace}.${key}`),\n value: sql.lit(value),\n })\n .compile().sql;\n },\n\n update(key: string, value: string) {\n return db\n .updateTable(tableName)\n .set({\n value: sql.lit(value),\n })\n .where(\"key\", \"=\", sql.lit(`${namespace}.${key}`))\n .compile().sql;\n },\n };\n}\n"],"mappings":"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"}
@@ -8,6 +8,7 @@ import { sql } from "kysely";
8
8
  * Returns the fully qualified SQL name for a column (table.column).
9
9
  *
10
10
  * @param column - The column to get the full name for
11
+ * @param mapper - Optional table name mapper for namespace prefixing
11
12
  * @returns The fully qualified SQL name in the format "tableName.columnName"
12
13
  * @internal
13
14
  *
@@ -17,8 +18,8 @@ import { sql } from "kysely";
17
18
  * // Returns: "users.email"
18
19
  * ```
19
20
  */
20
- function fullSQLName(column) {
21
- return `${column.tableName}.${column.name}`;
21
+ function fullSQLName(column, mapper) {
22
+ return `${mapper ? mapper.toPhysical(column.tableName) : column.tableName}.${column.name}`;
22
23
  }
23
24
  /**
24
25
  * Builds a WHERE clause expression from a Condition tree.
@@ -44,7 +45,7 @@ function fullSQLName(column) {
44
45
  * const whereClause = buildWhere(condition, eb, 'postgresql');
45
46
  * ```
46
47
  */
47
- function buildWhere(condition, eb, provider) {
48
+ function buildWhere(condition, eb, provider, mapper) {
48
49
  if (condition.type === "compare") {
49
50
  const left = condition.a;
50
51
  const op = condition.operator;
@@ -55,37 +56,37 @@ function buildWhere(condition, eb, provider) {
55
56
  switch (op) {
56
57
  case "contains":
57
58
  v = "like";
58
- rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))}, '%')` : `%${val}%`;
59
+ rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')` : `%${val}%`;
59
60
  break;
60
61
  case "not contains":
61
62
  v = "not like";
62
- rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))}, '%')` : `%${val}%`;
63
+ rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')` : `%${val}%`;
63
64
  break;
64
65
  case "starts with":
65
66
  v = "like";
66
- rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val))}, '%')` : `${val}%`;
67
+ rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;
67
68
  break;
68
69
  case "not starts with":
69
70
  v = "not like";
70
- rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val))}, '%')` : `${val}%`;
71
+ rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;
71
72
  break;
72
73
  case "ends with":
73
74
  v = "like";
74
- rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))})` : `%${val}`;
75
+ rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;
75
76
  break;
76
77
  case "not ends with":
77
78
  v = "not like";
78
- rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))})` : `%${val}`;
79
+ rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;
79
80
  break;
80
81
  default:
81
82
  v = op;
82
- rhs = val instanceof Column ? eb.ref(fullSQLName(val)) : val;
83
+ rhs = val instanceof Column ? eb.ref(fullSQLName(val, mapper)) : val;
83
84
  }
84
- return eb(fullSQLName(left), v, rhs);
85
+ return eb(fullSQLName(left, mapper), v, rhs);
85
86
  }
86
- if (condition.type === "and") return eb.and(condition.items.map((v) => buildWhere(v, eb, provider)));
87
- if (condition.type === "not") return eb.not(buildWhere(condition.item, eb, provider));
88
- return eb.or(condition.items.map((v) => buildWhere(v, eb, provider)));
87
+ if (condition.type === "and") return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));
88
+ if (condition.type === "not") return eb.not(buildWhere(condition.item, eb, provider, mapper));
89
+ return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));
89
90
  }
90
91
  /**
91
92
  * Maps a select clause to SQL column names with optional aliases.
@@ -177,15 +178,17 @@ function extendSelect(original) {
177
178
  *
178
179
  * @param values - The encoded values that may contain ReferenceSubquery objects
179
180
  * @param kysely - The Kysely database instance for building subqueries
181
+ * @param mapper - Optional table name mapper for namespace prefixing
180
182
  * @returns Processed values with subqueries in place of ReferenceSubquery markers
181
183
  * @internal
182
184
  */
183
- function processReferenceSubqueries(values, kysely) {
185
+ function processReferenceSubqueries(values, kysely, mapper) {
184
186
  const processed = {};
187
+ const getTableName = (table) => mapper ? mapper.toPhysical(table.name) : table.name;
185
188
  for (const [key, value] of Object.entries(values)) if (value instanceof ReferenceSubquery) {
186
189
  const refTable = value.referencedTable;
187
190
  const externalId = value.externalIdValue;
188
- processed[key] = kysely.selectFrom(refTable.name).select(refTable.getInternalIdColumn().name).where(refTable.getIdColumn().name, "=", externalId).limit(1);
191
+ processed[key] = kysely.selectFrom(getTableName(refTable)).select(refTable.getInternalIdColumn().name).where(refTable.getIdColumn().name, "=", externalId).limit(1);
189
192
  } else processed[key] = value;
190
193
  return processed;
191
194
  }
@@ -207,27 +210,28 @@ function processReferenceSubqueries(values, kysely) {
207
210
  * const result = await kysely.executeQuery(query);
208
211
  * ```
209
212
  */
210
- function createKyselyQueryBuilder(kysely, provider) {
213
+ function createKyselyQueryBuilder(kysely, provider, mapper) {
214
+ const getTableName = (table) => mapper ? mapper.toPhysical(table.name) : table.name;
211
215
  return {
212
216
  count(table, { where }) {
213
- let query = kysely.selectFrom(table.name).select(kysely.fn.countAll().as("count"));
214
- if (where) query = query.where((b) => buildWhere(where, b, provider));
217
+ let query = kysely.selectFrom(getTableName(table)).select(kysely.fn.countAll().as("count"));
218
+ if (where) query = query.where((b) => buildWhere(where, b, provider, mapper));
215
219
  return query.compile();
216
220
  },
217
221
  create(table, values) {
218
- const processedValues = processReferenceSubqueries(encodeValues(values, table, true, provider), kysely);
219
- const insert = kysely.insertInto(table.name).values(processedValues);
222
+ const processedValues = processReferenceSubqueries(encodeValues(values, table, true, provider), kysely, mapper);
223
+ const insert = kysely.insertInto(getTableName(table)).values(processedValues);
220
224
  if (provider === "mssql") return insert.output(mapSelect(true, table, { tableName: "inserted" })).compile();
221
- if (provider === "postgresql" || provider === "sqlite") return insert.returning(mapSelect(true, table)).compile();
225
+ if (provider === "postgresql" || provider === "sqlite") return insert.returning(mapSelect(true, table, { tableName: getTableName(table) })).compile();
222
226
  return insert.compile();
223
227
  },
224
228
  findMany(table, v) {
225
- let query = kysely.selectFrom(table.name);
229
+ let query = kysely.selectFrom(getTableName(table));
226
230
  const where = v.where;
227
- if (where) query = query.where((eb) => buildWhere(where, eb, provider));
231
+ if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper));
228
232
  if (v.offset !== void 0) query = query.offset(v.offset);
229
233
  if (v.limit !== void 0) query = provider === "mssql" ? query.top(v.limit) : query.limit(v.limit);
230
- if (v.orderBy) for (const [col, mode] of v.orderBy) query = query.orderBy(fullSQLName(col), mode);
234
+ if (v.orderBy) for (const [col, mode] of v.orderBy) query = query.orderBy(fullSQLName(col, mapper), mode);
231
235
  const selectBuilder = extendSelect(v.select);
232
236
  const mappedSelect = [];
233
237
  const processJoins = (joins, parentTable, parentTableName, parentPath = "") => {
@@ -241,62 +245,62 @@ function createKyselyQueryBuilder(kysely, provider) {
241
245
  relation: fullPath,
242
246
  tableName: joinName
243
247
  }));
244
- query = query.leftJoin(`${targetTable.name} as ${joinName}`, (b) => b.on((eb) => {
248
+ query = query.leftJoin(`${getTableName(targetTable)} as ${joinName}`, (b) => b.on((eb) => {
245
249
  const conditions = [];
246
250
  for (const [left, right] of relation.on) {
247
251
  const actualRight = targetTable.columns[right]?.role === "external-id" ? "_internalId" : right;
248
252
  conditions.push(eb(`${parentTableName}.${parentTable.columns[left].name}`, "=", eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`)));
249
253
  }
250
- if (joinOptions.where) conditions.push(buildWhere(joinOptions.where, eb, provider));
254
+ if (joinOptions.where) conditions.push(buildWhere(joinOptions.where, eb, provider, mapper));
251
255
  return eb.and(conditions);
252
256
  }));
253
257
  processJoins(joinOptions.join, targetTable, joinName, fullPath);
254
258
  }
255
259
  };
256
- processJoins(v.join, table, table.name);
260
+ processJoins(v.join, table, getTableName(table));
257
261
  const compiledSelect = selectBuilder.compile();
258
- mappedSelect.push(...mapSelect(compiledSelect.result, table));
262
+ mappedSelect.push(...mapSelect(compiledSelect.result, table, { tableName: getTableName(table) }));
259
263
  return query.select(mappedSelect).compile();
260
264
  },
261
265
  updateMany(table, v) {
262
- const processed = processReferenceSubqueries(encodeValues(v.set, table, false, provider), kysely);
266
+ const processed = processReferenceSubqueries(encodeValues(v.set, table, false, provider), kysely, mapper);
263
267
  const versionCol = table.getVersionColumn();
264
268
  processed[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`);
265
- let query = kysely.updateTable(table.name).set(processed);
269
+ let query = kysely.updateTable(getTableName(table)).set(processed);
266
270
  const { where } = v;
267
- if (where) query = query.where((eb) => buildWhere(where, eb, provider));
271
+ if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper));
268
272
  return query.compile();
269
273
  },
270
274
  upsertCheck(table, where) {
271
275
  const idColumn = table.getIdColumn();
272
- let query = kysely.selectFrom(table.name).select([`${idColumn.name} as id`]);
273
- if (where) query = query.where((b) => buildWhere(where, b, provider));
276
+ let query = kysely.selectFrom(getTableName(table)).select([`${idColumn.name} as id`]);
277
+ if (where) query = query.where((b) => buildWhere(where, b, provider, mapper));
274
278
  return query.limit(1).compile();
275
279
  },
276
280
  upsertUpdate(table, update, where, top) {
277
- const processed = processReferenceSubqueries(encodeValues(update, table, false, provider), kysely);
278
- let query = kysely.updateTable(table.name).set(processed);
281
+ const processed = processReferenceSubqueries(encodeValues(update, table, false, provider), kysely, mapper);
282
+ let query = kysely.updateTable(getTableName(table)).set(processed);
279
283
  if (top) query = query.top(1);
280
- if (where) query = query.where((b) => buildWhere(where, b, provider));
284
+ if (where) query = query.where((b) => buildWhere(where, b, provider, mapper));
281
285
  return query.compile();
282
286
  },
283
287
  upsertUpdateById(table, update, id) {
284
288
  const idColumn = table.getIdColumn();
285
- const processed = processReferenceSubqueries(encodeValues(update, table, false, provider), kysely);
286
- return kysely.updateTable(table.name).set(processed).where(idColumn.name, "=", id).compile();
289
+ const processed = processReferenceSubqueries(encodeValues(update, table, false, provider), kysely, mapper);
290
+ return kysely.updateTable(getTableName(table)).set(processed).where(idColumn.name, "=", id).compile();
287
291
  },
288
292
  createMany(table, values) {
289
- const processedValues = values.map((v) => encodeValues(v, table, true, provider)).map((v) => processReferenceSubqueries(v, kysely));
290
- return kysely.insertInto(table.name).values(processedValues).compile();
293
+ const processedValues = values.map((v) => encodeValues(v, table, true, provider)).map((v) => processReferenceSubqueries(v, kysely, mapper));
294
+ return kysely.insertInto(getTableName(table)).values(processedValues).compile();
291
295
  },
292
296
  deleteMany(table, { where }) {
293
- let query = kysely.deleteFrom(table.name);
294
- if (where) query = query.where((eb) => buildWhere(where, eb, provider));
297
+ let query = kysely.deleteFrom(getTableName(table));
298
+ if (where) query = query.where((eb) => buildWhere(where, eb, provider, mapper));
295
299
  return query.compile();
296
300
  },
297
301
  findById(table, idValue) {
298
302
  const idColumn = table.getIdColumn();
299
- return kysely.selectFrom(table.name).select(mapSelect(true, table)).where(idColumn.name, "=", idValue).limit(1).compile();
303
+ return kysely.selectFrom(getTableName(table)).select(mapSelect(true, table, { tableName: getTableName(table) })).where(idColumn.name, "=", idValue).limit(1).compile();
300
304
  }
301
305
  };
302
306
  }
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-query-builder.js","names":["v: BinaryOperator","rhs: unknown","out: string[]","extendedKeys: string[]","processed: Record<string, unknown>","mappedSelect: string[]"],"sources":["../../../src/adapters/kysely/kysely-query-builder.ts"],"sourcesContent":["import {\n type BinaryOperator,\n type CompiledQuery,\n type ExpressionBuilder,\n type ExpressionWrapper,\n type Kysely,\n sql,\n} from \"kysely\";\nimport type { AnySelectClause, FindManyOptions } from \"../../query/query\";\nimport type { SqlBool } from \"kysely\";\nimport { type AnyColumn, type AnyTable, Column } from \"../../schema/create\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport type { Condition } from \"../../query/condition-builder\";\nimport { serialize } from \"../../schema/serialize\";\nimport type { CompiledJoin, SimplifyFindOptions } from \"../../query/orm/orm\";\nimport { decodeResult, encodeValues, ReferenceSubquery } from \"../../query/result-transform\";\n\n/**\n * Returns the fully qualified SQL name for a column (table.column).\n *\n * @param column - The column to get the full name for\n * @returns The fully qualified SQL name in the format \"tableName.columnName\"\n * @internal\n *\n * @example\n * ```ts\n * fullSQLName(userTable.columns.email)\n * // Returns: \"users.email\"\n * ```\n */\nexport function fullSQLName(column: AnyColumn) {\n return `${column.tableName}.${column.name}`;\n}\n\n/**\n * Builds a WHERE clause expression from a Condition tree.\n *\n * Recursively processes condition objects to build Kysely WHERE expressions.\n * Handles comparison operators, logical AND/OR/NOT, and special string operators\n * like \"contains\", \"starts with\", and \"ends with\".\n *\n * @param condition - The condition tree to build the WHERE clause from\n * @param eb - Kysely expression builder for constructing SQL expressions\n * @param provider - The SQL provider (affects SQL generation)\n * @returns A Kysely expression wrapper representing the WHERE clause\n * @internal\n *\n * @example\n * ```ts\n * const condition = {\n * type: \"compare\",\n * a: userTable.columns.name,\n * operator: \"contains\",\n * b: \"john\"\n * };\n * const whereClause = buildWhere(condition, eb, 'postgresql');\n * ```\n */\nexport function buildWhere(\n condition: Condition,\n eb: ExpressionBuilder<any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): ExpressionWrapper<any, any, SqlBool> {\n if (condition.type === \"compare\") {\n const left = condition.a;\n const op = condition.operator;\n let val = condition.b;\n\n if (!(val instanceof Column)) {\n val = serialize(val, left, provider);\n }\n\n let v: BinaryOperator;\n let rhs: unknown;\n\n switch (op) {\n case \"contains\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))}, '%')` : `%${val}%`;\n break;\n case \"not contains\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))}, '%')` : `%${val}%`;\n break;\n case \"starts with\":\n v = \"like\";\n rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val))}, '%')` : `${val}%`;\n break;\n case \"not starts with\":\n v = \"not like\";\n rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val))}, '%')` : `${val}%`;\n break;\n case \"ends with\":\n v = \"like\";\n rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))})` : `%${val}`;\n break;\n case \"not ends with\":\n v = \"not like\";\n rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val))})` : `%${val}`;\n break;\n default:\n v = op;\n rhs = val instanceof Column ? eb.ref(fullSQLName(val)) : val;\n }\n\n return eb(fullSQLName(left), v, rhs);\n }\n\n // Nested conditions\n if (condition.type === \"and\") {\n return eb.and(condition.items.map((v) => buildWhere(v, eb, provider)));\n }\n\n if (condition.type === \"not\") {\n return eb.not(buildWhere(condition.item, eb, provider));\n }\n\n return eb.or(condition.items.map((v) => buildWhere(v, eb, provider)));\n}\n\n/**\n * Maps a select clause to SQL column names with optional aliases.\n *\n * Converts application-level select clauses (either array of keys or \"select all\")\n * into SQL-compatible column selections with proper aliasing for relations.\n *\n * @param select - The select clause (array of keys or true for all columns)\n * @param table - The table schema containing column definitions\n * @param options - Optional configuration\n * @param options.relation - Relation name to prefix in aliases (for joined data)\n * @param options.tableName - Override the table name in the SQL (defaults to table.name)\n * @returns Array of SQL select strings in the format \"tableName.columnName as alias\"\n * @internal\n *\n * @example\n * ```ts\n * mapSelect(['id', 'name'], userTable)\n * // Returns: ['users.id as id', 'users.name as name']\n *\n * mapSelect(['title'], postTable, { relation: 'posts' })\n * // Returns: ['posts.title as posts:title']\n * ```\n */\nexport function mapSelect(\n select: AnySelectClause,\n table: AnyTable,\n options: {\n relation?: string;\n tableName?: string;\n } = {},\n): string[] {\n const { relation, tableName = table.name } = options;\n const out: string[] = [];\n const keys = Array.isArray(select) ? select : Object.keys(table.columns);\n\n for (const key of keys) {\n const col = table.columns[key];\n\n // Skip hidden columns when explicitly selecting\n if (Array.isArray(select) && col.isHidden) {\n continue;\n }\n\n // Add the column to the select list\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n\n // Always include hidden columns (for FragnoId construction with internal ID and version)\n for (const key in table.columns) {\n const col = table.columns[key];\n if (col.isHidden && !keys.includes(key)) {\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n }\n\n return out;\n}\n\n/**\n * Result type from compiling a select clause with extensions.\n * @internal\n */\nexport interface CompiledSelect {\n /**\n * The final select clause to use in the query\n */\n result: AnySelectClause;\n\n /**\n * Keys that were added to the select clause (not originally requested)\n */\n extendedKeys: string[];\n\n /**\n * Removes the extended keys from a record (mutates the record).\n * Used to clean up keys that were only needed for join operations.\n *\n * @param record - The record to remove extended keys from\n * @returns The same record with extended keys removed\n */\n removeExtendedKeys: (record: Record<string, unknown>) => Record<string, unknown>;\n}\n\n/**\n * Builder for extending a select clause with additional keys.\n * @internal\n */\nexport interface SelectBuilder {\n /**\n * Adds a key to the select clause if not already present.\n * Tracks which keys were added for later removal.\n *\n * @param key - The key to add to the select clause\n */\n extend: (key: string) => void;\n\n /**\n * Compiles the select clause into its final form.\n *\n * @returns The compiled select information\n */\n compile: () => CompiledSelect;\n}\n\n/**\n * Creates a builder that can extend a select clause with additional keys.\n *\n * This is useful when you need to temporarily include columns for join operations\n * or other internal processing, but don't want them in the final result.\n *\n * @param original - The original select clause from the user\n * @returns A select builder with extend() and compile() methods\n * @internal\n *\n * @example\n * ```ts\n * const builder = extendSelect(['name', 'email']);\n * builder.extend('id'); // Add id for join operation\n * const { result, removeExtendedKeys } = builder.compile();\n * // result: ['name', 'email', 'id']\n *\n * const record = { name: 'John', email: 'j@ex.com', id: 123 };\n * removeExtendedKeys(record);\n * // record: { name: 'John', email: 'j@ex.com' }\n * ```\n */\nexport function extendSelect(original: AnySelectClause): SelectBuilder {\n const select = Array.isArray(original) ? new Set(original) : true;\n const extendedKeys: string[] = [];\n\n return {\n extend(key) {\n if (select === true || select.has(key)) {\n return;\n }\n\n select.add(key);\n extendedKeys.push(key);\n },\n compile() {\n return {\n result: select instanceof Set ? Array.from(select) : true,\n extendedKeys,\n removeExtendedKeys(record) {\n for (const key of extendedKeys) {\n delete record[key];\n }\n return record;\n },\n };\n },\n };\n}\n\n/**\n * Executes a SELECT query to find multiple records.\n *\n * Builds and executes a Kysely query with the provided options including\n * filtering (where), ordering (orderBy), pagination (limit/offset), and\n * column selection (select).\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @param table - The table to query from\n * @param v - Query options including where, select, orderBy, limit, and offset\n * @param runSubQueryJoin - Function to execute subquery joins on the results\n * @returns Array of decoded records matching the query criteria\n * @internal\n *\n * @example\n * ```ts\n * const records = await findMany(kysely, 'postgresql', userTable, {\n * where: someCondition,\n * orderBy: [['name', 'asc']],\n * limit: 10\n * });\n * ```\n */\nexport async function findMany(\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n table: AnyTable,\n v: SimplifyFindOptions<FindManyOptions>,\n runSubQueryJoin: (records: Record<string, unknown>[], join: CompiledJoin) => Promise<void>,\n) {\n let query = kysely.selectFrom(table.name);\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n const subqueryJoins: CompiledJoin[] = [];\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(...mapSelect(compiledSelect.result, table));\n\n const records = (await query.select(mappedSelect).execute()).map((v) =>\n decodeResult(v, table, provider),\n );\n\n await Promise.all(subqueryJoins.map((join) => runSubQueryJoin(records, join)));\n for (const record of records) {\n compiledSelect.removeExtendedKeys(record);\n }\n\n return records;\n}\n\n/**\n * Processes encoded values and replaces ReferenceSubquery markers with actual SQL subqueries.\n *\n * @param values - The encoded values that may contain ReferenceSubquery objects\n * @param kysely - The Kysely database instance for building subqueries\n * @returns Processed values with subqueries in place of ReferenceSubquery markers\n * @internal\n */\nfunction processReferenceSubqueries(\n values: Record<string, unknown>,\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n): Record<string, unknown> {\n const processed: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(values)) {\n if (value instanceof ReferenceSubquery) {\n const refTable = value.referencedTable;\n const externalId = value.externalIdValue;\n\n // Build a subquery: SELECT _internal_id FROM referenced_table WHERE id = external_id LIMIT 1\n processed[key] = kysely\n .selectFrom(refTable.name)\n .select(refTable.getInternalIdColumn().name)\n .where(refTable.getIdColumn().name, \"=\", externalId)\n .limit(1);\n } else {\n processed[key] = value;\n }\n }\n\n return processed;\n}\n\n/**\n * Creates a query compiler that builds and compiles Kysely queries without executing them.\n *\n * Each method takes table and query parameters and returns a CompiledQuery that can be\n * executed later using kysely.executeQuery().\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @returns An object with methods for compiling various database operations\n * @internal\n *\n * @example\n * ```ts\n * const builder = createKyselyQueryBuilder(kysely, 'postgresql');\n * const query = builder.count(userTable, { where: someCondition });\n * const result = await kysely.executeQuery(query);\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function createKyselyQueryBuilder(kysely: Kysely<any>, provider: SQLProvider) {\n return {\n count(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.selectFrom(table.name).select(kysely.fn.countAll().as(\"count\"));\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider));\n }\n return query.compile();\n },\n\n create(table: AnyTable, values: Record<string, unknown>): CompiledQuery {\n const encodedValues = encodeValues(values, table, true, provider);\n const processedValues = processReferenceSubqueries(encodedValues, kysely);\n const insert = kysely.insertInto(table.name).values(processedValues);\n\n if (provider === \"mssql\") {\n return (\n insert\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .output(mapSelect(true, table, { tableName: \"inserted\" }) as any[])\n .compile()\n );\n }\n\n if (provider === \"postgresql\" || provider === \"sqlite\") {\n return insert.returning(mapSelect(true, table)).compile();\n }\n\n // For MySQL/other providers, return the insert query\n return insert.compile();\n },\n\n findMany<T extends AnyTable>(\n table: T,\n v: SimplifyFindOptions<FindManyOptions<T>>,\n ): CompiledQuery {\n let query = kysely.selectFrom(table.name);\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n\n // Process joins recursively to support nested joins\n const processJoins = (\n joins: CompiledJoin[] | undefined,\n parentTable: AnyTable,\n parentTableName: string,\n parentPath: string = \"\",\n ) => {\n for (const join of joins ?? []) {\n const { options: joinOptions, relation } = join;\n\n if (joinOptions === false) {\n continue;\n }\n\n const targetTable = relation.table;\n // Build the full path for this join (e.g., \"author:inviter\")\n const fullPath = parentPath ? `${parentPath}:${relation.name}` : relation.name;\n // SQL table alias uses underscores (e.g., \"author_inviter\")\n const joinName = fullPath.replace(/:/g, \"_\");\n\n // update select\n mappedSelect.push(\n ...mapSelect(joinOptions.select, targetTable, {\n relation: fullPath, // Use full path with colons for column aliases\n tableName: joinName, // Use underscore version for table name\n }),\n );\n\n query = query.leftJoin(`${targetTable.name} as ${joinName}`, (b) =>\n b.on((eb) => {\n const conditions = [];\n for (const [left, right] of relation.on) {\n // Foreign keys always use internal IDs\n // If the relation references an external ID column (any name), translate to \"_internalId\"\n const rightCol = targetTable.columns[right];\n const actualRight = rightCol?.role === \"external-id\" ? \"_internalId\" : right;\n\n conditions.push(\n eb(\n `${parentTableName}.${parentTable.columns[left].name}`,\n \"=\",\n eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`),\n ),\n );\n }\n\n if (joinOptions.where) {\n conditions.push(buildWhere(joinOptions.where, eb, provider));\n }\n\n return eb.and(conditions);\n }),\n );\n\n // Recursively process nested joins with the full path\n processJoins(joinOptions.join, targetTable, joinName, fullPath);\n }\n };\n\n processJoins(v.join, table, table.name);\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(...mapSelect(compiledSelect.result, table));\n\n return query.select(mappedSelect).compile();\n },\n\n updateMany(\n table: AnyTable,\n v: {\n where?: Condition;\n set: Record<string, unknown>;\n },\n ): CompiledQuery {\n const encoded = encodeValues(v.set, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely);\n\n // Automatically increment _version for optimistic concurrency control\n const versionCol = table.getVersionColumn();\n // Safe cast: we're building a SQL expression for incrementing the version\n processed[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`) as unknown;\n\n let query = kysely.updateTable(table.name).set(processed);\n const { where } = v;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider));\n }\n return query.compile();\n },\n\n upsertCheck(table: AnyTable, where: Condition | undefined): CompiledQuery {\n const idColumn = table.getIdColumn();\n let query = kysely.selectFrom(table.name).select([`${idColumn.name} as id`]);\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider));\n }\n return query.limit(1).compile();\n },\n\n upsertUpdate(\n table: AnyTable,\n update: Record<string, unknown>,\n where: Condition | undefined,\n top?: boolean,\n ): CompiledQuery {\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely);\n let query = kysely.updateTable(table.name).set(processed);\n if (top) {\n query = query.top(1);\n }\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider));\n }\n return query.compile();\n },\n\n upsertUpdateById(table: AnyTable, update: Record<string, unknown>, id: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely);\n return kysely.updateTable(table.name).set(processed).where(idColumn.name, \"=\", id).compile();\n },\n\n createMany(table: AnyTable, values: Record<string, unknown>[]): CompiledQuery {\n const encodedValues = values.map((v) => encodeValues(v, table, true, provider));\n const processedValues = encodedValues.map((v) => processReferenceSubqueries(v, kysely));\n return kysely.insertInto(table.name).values(processedValues).compile();\n },\n\n deleteMany(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.deleteFrom(table.name);\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider));\n }\n return query.compile();\n },\n\n findById(table: AnyTable, idValue: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n return kysely\n .selectFrom(table.name)\n .select(mapSelect(true, table))\n .where(idColumn.name, \"=\", idValue)\n .limit(1)\n .compile();\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"kysely-query-builder.js","names":["v: BinaryOperator","rhs: unknown","out: string[]","extendedKeys: string[]","processed: Record<string, unknown>","mappedSelect: string[]"],"sources":["../../../src/adapters/kysely/kysely-query-builder.ts"],"sourcesContent":["import {\n type BinaryOperator,\n type CompiledQuery,\n type ExpressionBuilder,\n type ExpressionWrapper,\n type Kysely,\n sql,\n} from \"kysely\";\nimport type { AnySelectClause, FindManyOptions } from \"../../query/query\";\nimport type { SqlBool } from \"kysely\";\nimport { type AnyColumn, type AnyTable, Column } from \"../../schema/create\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport type { Condition } from \"../../query/condition-builder\";\nimport { serialize } from \"../../schema/serialize\";\nimport type { CompiledJoin, SimplifyFindOptions } from \"../../query/orm/orm\";\nimport { decodeResult, encodeValues, ReferenceSubquery } from \"../../query/result-transform\";\nimport type { TableNameMapper } from \"./kysely-shared\";\n\n/**\n * Returns the fully qualified SQL name for a column (table.column).\n *\n * @param column - The column to get the full name for\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns The fully qualified SQL name in the format \"tableName.columnName\"\n * @internal\n *\n * @example\n * ```ts\n * fullSQLName(userTable.columns.email)\n * // Returns: \"users.email\"\n * ```\n */\nexport function fullSQLName(column: AnyColumn, mapper?: TableNameMapper) {\n const tableName = mapper ? mapper.toPhysical(column.tableName) : column.tableName;\n return `${tableName}.${column.name}`;\n}\n\n/**\n * Builds a WHERE clause expression from a Condition tree.\n *\n * Recursively processes condition objects to build Kysely WHERE expressions.\n * Handles comparison operators, logical AND/OR/NOT, and special string operators\n * like \"contains\", \"starts with\", and \"ends with\".\n *\n * @param condition - The condition tree to build the WHERE clause from\n * @param eb - Kysely expression builder for constructing SQL expressions\n * @param provider - The SQL provider (affects SQL generation)\n * @returns A Kysely expression wrapper representing the WHERE clause\n * @internal\n *\n * @example\n * ```ts\n * const condition = {\n * type: \"compare\",\n * a: userTable.columns.name,\n * operator: \"contains\",\n * b: \"john\"\n * };\n * const whereClause = buildWhere(condition, eb, 'postgresql');\n * ```\n */\nexport function buildWhere(\n condition: Condition,\n eb: ExpressionBuilder<any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n mapper?: TableNameMapper,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): ExpressionWrapper<any, any, SqlBool> {\n if (condition.type === \"compare\") {\n const left = condition.a;\n const op = condition.operator;\n let val = condition.b;\n\n if (!(val instanceof Column)) {\n val = serialize(val, left, provider);\n }\n\n let v: BinaryOperator;\n let rhs: unknown;\n\n switch (op) {\n case \"contains\":\n v = \"like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"not contains\":\n v = \"not like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"starts with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"not starts with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"ends with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n case \"not ends with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n default:\n v = op;\n rhs = val instanceof Column ? eb.ref(fullSQLName(val, mapper)) : val;\n }\n\n return eb(fullSQLName(left, mapper), v, rhs);\n }\n\n // Nested conditions\n if (condition.type === \"and\") {\n return eb.and(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));\n }\n\n if (condition.type === \"not\") {\n return eb.not(buildWhere(condition.item, eb, provider, mapper));\n }\n\n return eb.or(condition.items.map((v) => buildWhere(v, eb, provider, mapper)));\n}\n\n/**\n * Maps a select clause to SQL column names with optional aliases.\n *\n * Converts application-level select clauses (either array of keys or \"select all\")\n * into SQL-compatible column selections with proper aliasing for relations.\n *\n * @param select - The select clause (array of keys or true for all columns)\n * @param table - The table schema containing column definitions\n * @param options - Optional configuration\n * @param options.relation - Relation name to prefix in aliases (for joined data)\n * @param options.tableName - Override the table name in the SQL (defaults to table.name)\n * @returns Array of SQL select strings in the format \"tableName.columnName as alias\"\n * @internal\n *\n * @example\n * ```ts\n * mapSelect(['id', 'name'], userTable)\n * // Returns: ['users.id as id', 'users.name as name']\n *\n * mapSelect(['title'], postTable, { relation: 'posts' })\n * // Returns: ['posts.title as posts:title']\n * ```\n */\nexport function mapSelect(\n select: AnySelectClause,\n table: AnyTable,\n options: {\n relation?: string;\n tableName?: string;\n } = {},\n): string[] {\n const { relation, tableName = table.name } = options;\n const out: string[] = [];\n const keys = Array.isArray(select) ? select : Object.keys(table.columns);\n\n for (const key of keys) {\n const col = table.columns[key];\n\n // Skip hidden columns when explicitly selecting\n if (Array.isArray(select) && col.isHidden) {\n continue;\n }\n\n // Add the column to the select list\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n\n // Always include hidden columns (for FragnoId construction with internal ID and version)\n for (const key in table.columns) {\n const col = table.columns[key];\n if (col.isHidden && !keys.includes(key)) {\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n }\n\n return out;\n}\n\n/**\n * Result type from compiling a select clause with extensions.\n * @internal\n */\nexport interface CompiledSelect {\n /**\n * The final select clause to use in the query\n */\n result: AnySelectClause;\n\n /**\n * Keys that were added to the select clause (not originally requested)\n */\n extendedKeys: string[];\n\n /**\n * Removes the extended keys from a record (mutates the record).\n * Used to clean up keys that were only needed for join operations.\n *\n * @param record - The record to remove extended keys from\n * @returns The same record with extended keys removed\n */\n removeExtendedKeys: (record: Record<string, unknown>) => Record<string, unknown>;\n}\n\n/**\n * Builder for extending a select clause with additional keys.\n * @internal\n */\nexport interface SelectBuilder {\n /**\n * Adds a key to the select clause if not already present.\n * Tracks which keys were added for later removal.\n *\n * @param key - The key to add to the select clause\n */\n extend: (key: string) => void;\n\n /**\n * Compiles the select clause into its final form.\n *\n * @returns The compiled select information\n */\n compile: () => CompiledSelect;\n}\n\n/**\n * Creates a builder that can extend a select clause with additional keys.\n *\n * This is useful when you need to temporarily include columns for join operations\n * or other internal processing, but don't want them in the final result.\n *\n * @param original - The original select clause from the user\n * @returns A select builder with extend() and compile() methods\n * @internal\n *\n * @example\n * ```ts\n * const builder = extendSelect(['name', 'email']);\n * builder.extend('id'); // Add id for join operation\n * const { result, removeExtendedKeys } = builder.compile();\n * // result: ['name', 'email', 'id']\n *\n * const record = { name: 'John', email: 'j@ex.com', id: 123 };\n * removeExtendedKeys(record);\n * // record: { name: 'John', email: 'j@ex.com' }\n * ```\n */\nexport function extendSelect(original: AnySelectClause): SelectBuilder {\n const select = Array.isArray(original) ? new Set(original) : true;\n const extendedKeys: string[] = [];\n\n return {\n extend(key) {\n if (select === true || select.has(key)) {\n return;\n }\n\n select.add(key);\n extendedKeys.push(key);\n },\n compile() {\n return {\n result: select instanceof Set ? Array.from(select) : true,\n extendedKeys,\n removeExtendedKeys(record) {\n for (const key of extendedKeys) {\n delete record[key];\n }\n return record;\n },\n };\n },\n };\n}\n\n/**\n * Executes a SELECT query to find multiple records.\n *\n * Builds and executes a Kysely query with the provided options including\n * filtering (where), ordering (orderBy), pagination (limit/offset), and\n * column selection (select).\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @param table - The table to query from\n * @param v - Query options including where, select, orderBy, limit, and offset\n * @param runSubQueryJoin - Function to execute subquery joins on the results\n * @returns Array of decoded records matching the query criteria\n * @internal\n *\n * @example\n * ```ts\n * const records = await findMany(kysely, 'postgresql', userTable, {\n * where: someCondition,\n * orderBy: [['name', 'asc']],\n * limit: 10\n * });\n * ```\n */\nexport async function findMany(\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n table: AnyTable,\n v: SimplifyFindOptions<FindManyOptions>,\n runSubQueryJoin: (records: Record<string, unknown>[], join: CompiledJoin) => Promise<void>,\n) {\n let query = kysely.selectFrom(table.name);\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n const subqueryJoins: CompiledJoin[] = [];\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(...mapSelect(compiledSelect.result, table));\n\n const records = (await query.select(mappedSelect).execute()).map((v) =>\n decodeResult(v, table, provider),\n );\n\n await Promise.all(subqueryJoins.map((join) => runSubQueryJoin(records, join)));\n for (const record of records) {\n compiledSelect.removeExtendedKeys(record);\n }\n\n return records;\n}\n\n/**\n * Processes encoded values and replaces ReferenceSubquery markers with actual SQL subqueries.\n *\n * @param values - The encoded values that may contain ReferenceSubquery objects\n * @param kysely - The Kysely database instance for building subqueries\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns Processed values with subqueries in place of ReferenceSubquery markers\n * @internal\n */\nfunction processReferenceSubqueries(\n values: Record<string, unknown>,\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n mapper?: TableNameMapper,\n): Record<string, unknown> {\n const processed: Record<string, unknown> = {};\n const getTableName = (table: AnyTable) => (mapper ? mapper.toPhysical(table.name) : table.name);\n\n for (const [key, value] of Object.entries(values)) {\n if (value instanceof ReferenceSubquery) {\n const refTable = value.referencedTable;\n const externalId = value.externalIdValue;\n\n // Build a subquery: SELECT _internal_id FROM referenced_table WHERE id = external_id LIMIT 1\n processed[key] = kysely\n .selectFrom(getTableName(refTable))\n .select(refTable.getInternalIdColumn().name)\n .where(refTable.getIdColumn().name, \"=\", externalId)\n .limit(1);\n } else {\n processed[key] = value;\n }\n }\n\n return processed;\n}\n\n/**\n * Creates a query compiler that builds and compiles Kysely queries without executing them.\n *\n * Each method takes table and query parameters and returns a CompiledQuery that can be\n * executed later using kysely.executeQuery().\n *\n * @param kysely - The Kysely database instance\n * @param provider - The SQL provider (affects SQL generation)\n * @returns An object with methods for compiling various database operations\n * @internal\n *\n * @example\n * ```ts\n * const builder = createKyselyQueryBuilder(kysely, 'postgresql');\n * const query = builder.count(userTable, { where: someCondition });\n * const result = await kysely.executeQuery(query);\n * ```\n */\nexport function createKyselyQueryBuilder(\n kysely: Kysely<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n provider: SQLProvider,\n mapper?: TableNameMapper,\n) {\n // Helper to get the physical table name (with namespace suffix if mapper is provided)\n const getTableName = (table: AnyTable) => (mapper ? mapper.toPhysical(table.name) : table.name);\n\n return {\n count(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.selectFrom(getTableName(table)).select(kysely.fn.countAll().as(\"count\"));\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper));\n }\n return query.compile();\n },\n\n create(table: AnyTable, values: Record<string, unknown>): CompiledQuery {\n const encodedValues = encodeValues(values, table, true, provider);\n const processedValues = processReferenceSubqueries(encodedValues, kysely, mapper);\n const insert = kysely.insertInto(getTableName(table)).values(processedValues);\n\n if (provider === \"mssql\") {\n return (\n insert\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .output(mapSelect(true, table, { tableName: \"inserted\" }) as any[])\n .compile()\n );\n }\n\n if (provider === \"postgresql\" || provider === \"sqlite\") {\n return insert\n .returning(mapSelect(true, table, { tableName: getTableName(table) }))\n .compile();\n }\n\n // For MySQL/other providers, return the insert query\n return insert.compile();\n },\n\n findMany<T extends AnyTable>(\n table: T,\n v: SimplifyFindOptions<FindManyOptions<T>>,\n ): CompiledQuery {\n let query = kysely.selectFrom(getTableName(table));\n\n const where = v.where;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper));\n }\n\n if (v.offset !== undefined) {\n query = query.offset(v.offset);\n }\n\n if (v.limit !== undefined) {\n query = provider === \"mssql\" ? query.top(v.limit) : query.limit(v.limit);\n }\n\n if (v.orderBy) {\n for (const [col, mode] of v.orderBy) {\n query = query.orderBy(fullSQLName(col, mapper), mode);\n }\n }\n\n const selectBuilder = extendSelect(v.select);\n const mappedSelect: string[] = [];\n\n // Process joins recursively to support nested joins\n const processJoins = (\n joins: CompiledJoin[] | undefined,\n parentTable: AnyTable,\n parentTableName: string,\n parentPath: string = \"\",\n ) => {\n for (const join of joins ?? []) {\n const { options: joinOptions, relation } = join;\n\n if (joinOptions === false) {\n continue;\n }\n\n const targetTable = relation.table;\n // Build the full path for this join (e.g., \"author:inviter\")\n const fullPath = parentPath ? `${parentPath}:${relation.name}` : relation.name;\n // SQL table alias uses underscores (e.g., \"author_inviter\")\n const joinName = fullPath.replace(/:/g, \"_\");\n\n // update select\n mappedSelect.push(\n ...mapSelect(joinOptions.select, targetTable, {\n relation: fullPath, // Use full path with colons for column aliases\n tableName: joinName, // Use underscore version for table name\n }),\n );\n\n query = query.leftJoin(`${getTableName(targetTable)} as ${joinName}`, (b) =>\n b.on((eb) => {\n const conditions = [];\n for (const [left, right] of relation.on) {\n // Foreign keys always use internal IDs\n // If the relation references an external ID column (any name), translate to \"_internalId\"\n const rightCol = targetTable.columns[right];\n const actualRight = rightCol?.role === \"external-id\" ? \"_internalId\" : right;\n\n conditions.push(\n eb(\n `${parentTableName}.${parentTable.columns[left].name}`,\n \"=\",\n eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`),\n ),\n );\n }\n\n if (joinOptions.where) {\n conditions.push(buildWhere(joinOptions.where, eb, provider, mapper));\n }\n\n return eb.and(conditions);\n }),\n );\n\n // Recursively process nested joins with the full path\n processJoins(joinOptions.join, targetTable, joinName, fullPath);\n }\n };\n\n processJoins(v.join, table, getTableName(table));\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(\n ...mapSelect(compiledSelect.result, table, { tableName: getTableName(table) }),\n );\n\n return query.select(mappedSelect).compile();\n },\n\n updateMany(\n table: AnyTable,\n v: {\n where?: Condition;\n set: Record<string, unknown>;\n },\n ): CompiledQuery {\n const encoded = encodeValues(v.set, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n\n // Automatically increment _version for optimistic concurrency control\n const versionCol = table.getVersionColumn();\n // Safe cast: we're building a SQL expression for incrementing the version\n processed[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`) as unknown;\n\n let query = kysely.updateTable(getTableName(table)).set(processed);\n const { where } = v;\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper));\n }\n return query.compile();\n },\n\n upsertCheck(table: AnyTable, where: Condition | undefined): CompiledQuery {\n const idColumn = table.getIdColumn();\n let query = kysely.selectFrom(getTableName(table)).select([`${idColumn.name} as id`]);\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper));\n }\n return query.limit(1).compile();\n },\n\n upsertUpdate(\n table: AnyTable,\n update: Record<string, unknown>,\n where: Condition | undefined,\n top?: boolean,\n ): CompiledQuery {\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n let query = kysely.updateTable(getTableName(table)).set(processed);\n if (top) {\n query = query.top(1);\n }\n if (where) {\n query = query.where((b) => buildWhere(where, b, provider, mapper));\n }\n return query.compile();\n },\n\n upsertUpdateById(table: AnyTable, update: Record<string, unknown>, id: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n const encoded = encodeValues(update, table, false, provider);\n const processed = processReferenceSubqueries(encoded, kysely, mapper);\n return kysely\n .updateTable(getTableName(table))\n .set(processed)\n .where(idColumn.name, \"=\", id)\n .compile();\n },\n\n createMany(table: AnyTable, values: Record<string, unknown>[]): CompiledQuery {\n const encodedValues = values.map((v) => encodeValues(v, table, true, provider));\n const processedValues = encodedValues.map((v) =>\n processReferenceSubqueries(v, kysely, mapper),\n );\n return kysely.insertInto(getTableName(table)).values(processedValues).compile();\n },\n\n deleteMany(table: AnyTable, { where }: { where?: Condition }): CompiledQuery {\n let query = kysely.deleteFrom(getTableName(table));\n if (where) {\n query = query.where((eb) => buildWhere(where, eb, provider, mapper));\n }\n return query.compile();\n },\n\n findById(table: AnyTable, idValue: unknown): CompiledQuery {\n const idColumn = table.getIdColumn();\n return kysely\n .selectFrom(getTableName(table))\n .select(mapSelect(true, table, { tableName: getTableName(table) }))\n .where(idColumn.name, \"=\", idValue)\n .limit(1)\n .compile();\n },\n };\n}\n"],"mappings":"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"}
@@ -3,9 +3,9 @@ import { buildFindOptions } from "../../query/orm/orm.js";
3
3
  import { createKyselyQueryBuilder } from "./kysely-query-builder.js";
4
4
 
5
5
  //#region src/adapters/kysely/kysely-query-compiler.ts
6
- function createKyselyQueryCompiler(schema, config) {
6
+ function createKyselyQueryCompiler(schema, config, mapper) {
7
7
  const { db: kysely, provider } = config;
8
- const queryBuilder = createKyselyQueryBuilder(kysely, provider);
8
+ const queryBuilder = createKyselyQueryBuilder(kysely, provider, mapper);
9
9
  function toTable(name) {
10
10
  const table = schema.tables[name];
11
11
  if (!table) throw new Error(`Invalid table name ${name}.`);
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-query-compiler.js","names":[],"sources":["../../../src/adapters/kysely/kysely-query-compiler.ts"],"sourcesContent":["import type { CompiledQuery } from \"kysely\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport { buildCondition } from \"../../query/condition-builder\";\nimport { buildFindOptions } from \"../../query/orm/orm\";\nimport type { KyselyConfig } from \"./kysely-adapter\";\nimport { createKyselyQueryBuilder } from \"./kysely-query-builder\";\nimport type { ConditionBuilder, Condition } from \"../../query/condition-builder\";\n\n/**\n * Internal query compiler interface for Kysely\n * Used by the UOW compiler to generate compiled queries\n */\nexport interface KyselyQueryCompiler {\n count: (\n name: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: { where?: (eb: ConditionBuilder<any>) => any },\n ) => CompiledQuery | null;\n findFirst: (name: string, options: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n findMany: (name: string, options?: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n create: (name: string, values: any) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n createMany: (name: string, values: any[]) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n updateMany: (name: string, options: { set: any; where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n deleteMany: (name: string, options: { where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nexport function createKyselyQueryCompiler<T extends AnySchema>(\n schema: T,\n config: KyselyConfig,\n): KyselyQueryCompiler {\n const { db: kysely, provider } = config;\n const queryBuilder = createKyselyQueryBuilder(kysely, provider);\n\n function toTable(name: unknown): AnyTable {\n const table = schema.tables[name as string];\n if (!table) {\n throw new Error(`Invalid table name ${name}.`);\n }\n return table;\n }\n\n return {\n count(name, { where } = {}) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n return queryBuilder.count(table, { where: conditions });\n },\n\n findFirst(name, options) {\n const table = toTable(name);\n // Safe cast: FindFirstOptions is structurally compatible with FindManyOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, {\n ...compiledOptions,\n limit: 1,\n });\n },\n\n findMany(name, options = {}) {\n const table = toTable(name);\n // Safe cast: FindManyOptions from compiler matches FindManyOptions from buildFindOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, compiledOptions);\n },\n\n create(name, values) {\n const table = toTable(name);\n return queryBuilder.create(table, values);\n },\n\n createMany(name, values) {\n const table = toTable(name);\n return queryBuilder.createMany(table, values);\n },\n\n updateMany(name, { set, where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.updateMany(table, {\n set,\n where: conditions as Condition | undefined,\n });\n },\n\n deleteMany(name, { where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.deleteMany(table, { where: conditions as Condition | undefined });\n },\n };\n}\n"],"mappings":";;;;;AA0BA,SAAgB,0BACd,QACA,QACqB;CACrB,MAAM,EAAE,IAAI,QAAQ,aAAa;CACjC,MAAM,eAAe,yBAAyB,QAAQ,SAAS;CAE/D,SAAS,QAAQ,MAAyB;EACxC,MAAM,QAAQ,OAAO,OAAO;AAC5B,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,sBAAsB,KAAK,GAAG;AAEhD,SAAO;;AAGT,QAAO;EACL,MAAM,MAAM,EAAE,UAAU,EAAE,EAAE;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAGT,UAAO,aAAa,MAAM,OAAO,EAAE,OAAO,YAAY,CAAC;;EAGzD,UAAU,MAAM,SAAS;GACvB,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO;IAClC,GAAG;IACH,OAAO;IACR,CAAC;;EAGJ,SAAS,MAAM,UAAU,EAAE,EAAE;GAC3B,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO,gBAAgB;;EAGtD,OAAO,MAAM,QAAQ;GACnB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,OAAO,OAAO,OAAO;;EAG3C,WAAW,MAAM,QAAQ;GACvB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,WAAW,OAAO,OAAO;;EAG/C,WAAW,MAAM,EAAE,KAAK,SAAS;GAC/B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO;IACpC;IACA,OAAO;IACR,CAAC;;EAGJ,WAAW,MAAM,EAAE,SAAS;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO,EAAE,OAAO,YAAqC,CAAC;;EAExF"}
1
+ {"version":3,"file":"kysely-query-compiler.js","names":[],"sources":["../../../src/adapters/kysely/kysely-query-compiler.ts"],"sourcesContent":["import type { CompiledQuery } from \"kysely\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport { buildCondition } from \"../../query/condition-builder\";\nimport { buildFindOptions } from \"../../query/orm/orm\";\nimport type { KyselyConfig } from \"./kysely-adapter\";\nimport { createKyselyQueryBuilder } from \"./kysely-query-builder\";\nimport type { ConditionBuilder, Condition } from \"../../query/condition-builder\";\nimport type { TableNameMapper } from \"./kysely-shared\";\n\n/**\n * Internal query compiler interface for Kysely\n * Used by the UOW compiler to generate compiled queries\n */\nexport interface KyselyQueryCompiler {\n count: (\n name: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: { where?: (eb: ConditionBuilder<any>) => any },\n ) => CompiledQuery | null;\n findFirst: (name: string, options: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n findMany: (name: string, options?: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n create: (name: string, values: any) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n createMany: (name: string, values: any[]) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any\n updateMany: (name: string, options: { set: any; where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n deleteMany: (name: string, options: { where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nexport function createKyselyQueryCompiler<T extends AnySchema>(\n schema: T,\n config: KyselyConfig,\n mapper?: TableNameMapper,\n): KyselyQueryCompiler {\n const { db: kysely, provider } = config;\n const queryBuilder = createKyselyQueryBuilder(kysely, provider, mapper);\n\n function toTable(name: unknown): AnyTable {\n const table = schema.tables[name as string];\n if (!table) {\n throw new Error(`Invalid table name ${name}.`);\n }\n return table;\n }\n\n return {\n count(name, { where } = {}) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n return queryBuilder.count(table, { where: conditions });\n },\n\n findFirst(name, options) {\n const table = toTable(name);\n // Safe cast: FindFirstOptions is structurally compatible with FindManyOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, {\n ...compiledOptions,\n limit: 1,\n });\n },\n\n findMany(name, options = {}) {\n const table = toTable(name);\n // Safe cast: FindManyOptions from compiler matches FindManyOptions from buildFindOptions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledOptions = buildFindOptions(table, options as any);\n if (compiledOptions === false) {\n return null;\n }\n\n return queryBuilder.findMany(table, compiledOptions);\n },\n\n create(name, values) {\n const table = toTable(name);\n return queryBuilder.create(table, values);\n },\n\n createMany(name, values) {\n const table = toTable(name);\n return queryBuilder.createMany(table, values);\n },\n\n updateMany(name, { set, where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.updateMany(table, {\n set,\n where: conditions as Condition | undefined,\n });\n },\n\n deleteMany(name, { where }) {\n const table = toTable(name);\n let conditions = where ? buildCondition(table.columns, where) : undefined;\n if (conditions === true) {\n conditions = undefined;\n }\n if (conditions === false) {\n return null;\n }\n\n // Safe: conditions is Condition | undefined after filtering out true/false\n return queryBuilder.deleteMany(table, { where: conditions as Condition | undefined });\n },\n };\n}\n"],"mappings":";;;;;AA2BA,SAAgB,0BACd,QACA,QACA,QACqB;CACrB,MAAM,EAAE,IAAI,QAAQ,aAAa;CACjC,MAAM,eAAe,yBAAyB,QAAQ,UAAU,OAAO;CAEvE,SAAS,QAAQ,MAAyB;EACxC,MAAM,QAAQ,OAAO,OAAO;AAC5B,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,sBAAsB,KAAK,GAAG;AAEhD,SAAO;;AAGT,QAAO;EACL,MAAM,MAAM,EAAE,UAAU,EAAE,EAAE;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAGT,UAAO,aAAa,MAAM,OAAO,EAAE,OAAO,YAAY,CAAC;;EAGzD,UAAU,MAAM,SAAS;GACvB,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO;IAClC,GAAG;IACH,OAAO;IACR,CAAC;;EAGJ,SAAS,MAAM,UAAU,EAAE,EAAE;GAC3B,MAAM,QAAQ,QAAQ,KAAK;GAG3B,MAAM,kBAAkB,iBAAiB,OAAO,QAAe;AAC/D,OAAI,oBAAoB,MACtB,QAAO;AAGT,UAAO,aAAa,SAAS,OAAO,gBAAgB;;EAGtD,OAAO,MAAM,QAAQ;GACnB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,OAAO,OAAO,OAAO;;EAG3C,WAAW,MAAM,QAAQ;GACvB,MAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAO,aAAa,WAAW,OAAO,OAAO;;EAG/C,WAAW,MAAM,EAAE,KAAK,SAAS;GAC/B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO;IACpC;IACA,OAAO;IACR,CAAC;;EAGJ,WAAW,MAAM,EAAE,SAAS;GAC1B,MAAM,QAAQ,QAAQ,KAAK;GAC3B,IAAI,aAAa,QAAQ,eAAe,MAAM,SAAS,MAAM,GAAG;AAChE,OAAI,eAAe,KACjB,cAAa;AAEf,OAAI,eAAe,MACjB,QAAO;AAIT,UAAO,aAAa,WAAW,OAAO,EAAE,OAAO,YAAqC,CAAC;;EAExF"}
@@ -13,6 +13,7 @@ import { executeKyselyMutationPhase, executeKyselyRetrievalPhase } from "./kysel
13
13
  *
14
14
  * @param schema - The database schema definition
15
15
  * @param config - Kysely configuration containing the database instance and provider
16
+ * @param mapper - Optional table name mapper for namespace prefixing
16
17
  * @returns An AbstractQuery instance for performing database operations
17
18
  *
18
19
  * @example
@@ -28,9 +29,9 @@ import { executeKyselyMutationPhase, executeKyselyRetrievalPhase } from "./kysel
28
29
  * });
29
30
  * ```
30
31
  */
31
- function fromKysely(schema, config) {
32
+ function fromKysely(schema, config, mapper) {
32
33
  const { db: kysely, provider } = config;
33
- const uowCompiler = createKyselyUOWCompiler(schema, config);
34
+ const uowCompiler = createKyselyUOWCompiler(schema, config, mapper);
34
35
  function createUOW(name) {
35
36
  const executor = {
36
37
  executeRetrievalPhase: (retrievalBatch) => executeKyselyRetrievalPhase(kysely, retrievalBatch),