@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.
- package/.turbo/turbo-build.log +61 -53
- package/CHANGELOG.md +12 -0
- package/dist/adapters/adapters.d.ts +11 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +9 -2
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +21 -39
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +3 -2
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +8 -6
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
- package/dist/adapters/drizzle/generate.js +107 -34
- package/dist/adapters/drizzle/generate.js.map +1 -1
- package/dist/adapters/drizzle/shared.js +14 -1
- package/dist/adapters/drizzle/shared.js.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts +2 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +25 -30
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/kysely/kysely-query-builder.js +48 -44
- package/dist/adapters/kysely/kysely-query-builder.js.map +1 -1
- package/dist/adapters/kysely/kysely-query-compiler.js +2 -2
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-query.js +3 -2
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.js +18 -0
- package/dist/adapters/kysely/kysely-shared.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +4 -3
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
- package/dist/adapters/kysely/migration/execute.js +15 -12
- package/dist/adapters/kysely/migration/execute.js.map +1 -1
- package/dist/migration-engine/auto-from-schema.js +2 -8
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/create.d.ts +1 -5
- package/dist/migration-engine/create.js +1 -1
- package/dist/migration-engine/create.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts +51 -0
- package/dist/migration-engine/generation-engine.d.ts.map +1 -0
- package/dist/migration-engine/generation-engine.js +165 -0
- package/dist/migration-engine/generation-engine.js.map +1 -0
- package/dist/migration-engine/shared.d.ts +5 -2
- package/dist/migration-engine/shared.d.ts.map +1 -1
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +0 -8
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +0 -32
- package/dist/mod.js.map +1 -1
- package/dist/query/condition-builder.js.map +1 -1
- package/dist/query/result-transform.js +2 -1
- package/dist/query/result-transform.js.map +1 -1
- package/dist/schema/create.d.ts +74 -16
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +76 -11
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/serialize.js.map +1 -1
- package/dist/shared/settings-schema.js +36 -0
- package/dist/shared/settings-schema.js.map +1 -0
- package/dist/util/import-generator.js.map +1 -1
- package/dist/util/parse.js.map +1 -1
- package/package.json +8 -2
- package/src/adapters/adapters.ts +10 -3
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +11 -7
- package/src/adapters/drizzle/drizzle-adapter.test.ts +77 -29
- package/src/adapters/drizzle/drizzle-adapter.ts +31 -78
- package/src/adapters/drizzle/drizzle-query.ts +4 -7
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +9 -3
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +12 -6
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +1 -1
- package/src/adapters/drizzle/drizzle-uow-executor.ts +1 -1
- package/src/adapters/drizzle/generate.test.ts +573 -150
- package/src/adapters/drizzle/generate.ts +187 -36
- package/src/adapters/drizzle/migrate-drizzle.test.ts +30 -6
- package/src/adapters/drizzle/shared.ts +31 -1
- package/src/adapters/drizzle/test-utils.ts +3 -1
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +25 -27
- package/src/adapters/kysely/kysely-adapter.ts +35 -58
- package/src/adapters/kysely/kysely-query-builder.ts +75 -44
- package/src/adapters/kysely/kysely-query-compiler.ts +3 -1
- package/src/adapters/kysely/kysely-query.ts +8 -2
- package/src/adapters/kysely/kysely-shared.ts +23 -0
- package/src/adapters/kysely/kysely-uow-compiler.ts +5 -2
- package/src/adapters/kysely/migration/execute-mysql.test.ts +2 -2
- package/src/adapters/kysely/migration/execute-postgres.test.ts +19 -19
- package/src/adapters/kysely/migration/execute.ts +48 -17
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +19 -37
- package/src/fragment.test.ts +1 -0
- package/src/migration-engine/auto-from-schema.ts +14 -18
- package/src/migration-engine/create.ts +1 -6
- package/src/migration-engine/generation-engine.test.ts +597 -0
- package/src/migration-engine/generation-engine.ts +356 -0
- package/src/migration-engine/shared.ts +1 -4
- package/src/mod.ts +0 -66
- package/src/query/condition-builder.ts +24 -8
- package/src/query/result-transform.ts +7 -1
- package/src/schema/create.test.ts +4 -1
- package/src/schema/create.ts +132 -24
- package/src/schema/serialize.ts +21 -7
- package/src/shared/settings-schema.ts +61 -0
- package/src/util/deep-equal.ts +21 -7
- package/src/util/import-generator.ts +3 -1
- package/src/util/parse.ts +3 -1
- package/tsdown.config.ts +1 -0
- package/.turbo/turbo-test.log +0 -37
- 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;
|
|
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,
|
|
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;
|
|
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 {
|
|
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,
|
|
15
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
86
|
+
return createSettingsManager(this.#kyselyConfig.db, namespace).get(`schema_version`);
|
|
88
87
|
}
|
|
89
88
|
};
|
|
90
|
-
function createSettingsManager(db,
|
|
91
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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"
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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":";;;;;
|
|
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),
|