@fragno-dev/db 0.0.1 → 0.1.0
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 +137 -13
- package/.turbo/turbo-test.log +36 -0
- package/CHANGELOG.md +7 -0
- package/dist/adapters/adapters.d.ts +18 -0
- package/dist/adapters/adapters.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +21 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.js +62 -0
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts +17 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.js +139 -0
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +9 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +300 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +82 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js +125 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -0
- package/dist/adapters/drizzle/generate.js +273 -0
- package/dist/adapters/drizzle/generate.js.map +1 -0
- package/dist/adapters/drizzle/join-column-utils.js +28 -0
- package/dist/adapters/drizzle/join-column-utils.js.map +1 -0
- package/dist/adapters/drizzle/shared.js +11 -0
- package/dist/adapters/drizzle/shared.js.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +23 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.js +119 -0
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-builder.js +306 -0
- package/dist/adapters/kysely/kysely-query-builder.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-compiler.js +67 -0
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-query.js +158 -0
- package/dist/adapters/kysely/kysely-query.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +139 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-executor.js +89 -0
- package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -0
- package/dist/adapters/kysely/migration/execute.js +176 -0
- package/dist/adapters/kysely/migration/execute.js.map +1 -0
- package/dist/fragment.d.ts +54 -0
- package/dist/fragment.d.ts.map +1 -0
- package/dist/fragment.js +92 -0
- package/dist/fragment.js.map +1 -0
- package/dist/id.d.ts +2 -0
- package/dist/migration-engine/auto-from-schema.js +116 -0
- package/dist/migration-engine/auto-from-schema.js.map +1 -0
- package/dist/migration-engine/create.d.ts +41 -0
- package/dist/migration-engine/create.d.ts.map +1 -0
- package/dist/migration-engine/create.js +58 -0
- package/dist/migration-engine/create.js.map +1 -0
- package/dist/migration-engine/shared.d.ts +90 -0
- package/dist/migration-engine/shared.d.ts.map +1 -0
- package/dist/migration-engine/shared.js +8 -0
- package/dist/migration-engine/shared.js.map +1 -0
- package/dist/mod.d.ts +55 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +111 -2
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js +108 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js +55 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js +18 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js +183 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js +58 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js +68 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js +56 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js +65 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js +81 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js +13 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js +10 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js +372 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js +23 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js +62 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js.map +1 -0
- package/dist/query/condition-builder.d.ts +41 -0
- package/dist/query/condition-builder.d.ts.map +1 -0
- package/dist/query/condition-builder.js +93 -0
- package/dist/query/condition-builder.js.map +1 -0
- package/dist/query/cursor.d.ts +88 -0
- package/dist/query/cursor.d.ts.map +1 -0
- package/dist/query/cursor.js +103 -0
- package/dist/query/cursor.js.map +1 -0
- package/dist/query/orm/orm.d.ts +18 -0
- package/dist/query/orm/orm.d.ts.map +1 -0
- package/dist/query/orm/orm.js +48 -0
- package/dist/query/orm/orm.js.map +1 -0
- package/dist/query/query.d.ts +79 -0
- package/dist/query/query.d.ts.map +1 -0
- package/dist/query/query.js +1 -0
- package/dist/query/result-transform.js +155 -0
- package/dist/query/result-transform.js.map +1 -0
- package/dist/query/unit-of-work.d.ts +435 -0
- package/dist/query/unit-of-work.d.ts.map +1 -0
- package/dist/query/unit-of-work.js +549 -0
- package/dist/query/unit-of-work.js.map +1 -0
- package/dist/schema/create.d.ts +273 -116
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +410 -222
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/serialize.js +101 -0
- package/dist/schema/serialize.js.map +1 -0
- package/dist/schema-generator/schema-generator.d.ts +15 -0
- package/dist/schema-generator/schema-generator.d.ts.map +1 -0
- package/dist/shared/providers.d.ts +6 -0
- package/dist/shared/providers.d.ts.map +1 -0
- package/dist/util/import-generator.js +26 -0
- package/dist/util/import-generator.js.map +1 -0
- package/dist/util/parse.js +15 -0
- package/dist/util/parse.js.map +1 -0
- package/dist/util/types.d.ts +8 -0
- package/dist/util/types.d.ts.map +1 -0
- package/package.json +63 -2
- package/src/adapters/adapters.ts +22 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +433 -0
- package/src/adapters/drizzle/drizzle-adapter.test.ts +122 -0
- package/src/adapters/drizzle/drizzle-adapter.ts +118 -0
- package/src/adapters/drizzle/drizzle-query.ts +234 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +1084 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +546 -0
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +165 -0
- package/src/adapters/drizzle/drizzle-uow-executor.ts +213 -0
- package/src/adapters/drizzle/generate.test.ts +643 -0
- package/src/adapters/drizzle/generate.ts +481 -0
- package/src/adapters/drizzle/join-column-utils.test.ts +79 -0
- package/src/adapters/drizzle/join-column-utils.ts +39 -0
- package/src/adapters/drizzle/migrate-drizzle.test.ts +226 -0
- package/src/adapters/drizzle/shared.ts +22 -0
- package/src/adapters/drizzle/test-utils.ts +56 -0
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +789 -0
- package/src/adapters/kysely/kysely-adapter.ts +196 -0
- package/src/adapters/kysely/kysely-query-builder.test.ts +1344 -0
- package/src/adapters/kysely/kysely-query-builder.ts +611 -0
- package/src/adapters/kysely/kysely-query-compiler.ts +124 -0
- package/src/adapters/kysely/kysely-query.ts +254 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +916 -0
- package/src/adapters/kysely/kysely-uow-compiler.ts +271 -0
- package/src/adapters/kysely/kysely-uow-executor.ts +149 -0
- package/src/adapters/kysely/kysely-uow-joins.test.ts +811 -0
- package/src/adapters/kysely/migration/execute-mysql.test.ts +1173 -0
- package/src/adapters/kysely/migration/execute-postgres.test.ts +2657 -0
- package/src/adapters/kysely/migration/execute.ts +382 -0
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +197 -0
- package/src/fragment.test.ts +287 -0
- package/src/fragment.ts +198 -0
- package/src/migration-engine/auto-from-schema.test.ts +118 -58
- package/src/migration-engine/auto-from-schema.ts +103 -32
- package/src/migration-engine/create.test.ts +34 -46
- package/src/migration-engine/create.ts +41 -26
- package/src/migration-engine/shared.ts +26 -6
- package/src/mod.ts +197 -1
- package/src/query/condition-builder.test.ts +379 -0
- package/src/query/condition-builder.ts +294 -0
- package/src/query/cursor.test.ts +296 -0
- package/src/query/cursor.ts +147 -0
- package/src/query/orm/orm.ts +92 -0
- package/src/query/query-type.test.ts +429 -0
- package/src/query/query.ts +200 -0
- package/src/query/result-transform.test.ts +795 -0
- package/src/query/result-transform.ts +247 -0
- package/src/query/unit-of-work-types.test.ts +192 -0
- package/src/query/unit-of-work.test.ts +947 -0
- package/src/query/unit-of-work.ts +1199 -0
- package/src/schema/create.test.ts +653 -110
- package/src/schema/create.ts +708 -337
- package/src/schema/serialize.test.ts +559 -0
- package/src/schema/serialize.ts +359 -0
- package/src/schema-generator/schema-generator.ts +12 -0
- package/src/shared/config.ts +0 -8
- package/src/util/import-generator.ts +28 -0
- package/src/util/parse.ts +16 -0
- package/src/util/types.ts +4 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +11 -1
- package/vitest.config.ts +3 -0
- /package/dist/{cuid.js → id.js} +0 -0
- /package/src/{cuid.ts → id.ts} +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { CompiledQuery } from "kysely";
|
|
2
|
+
import type { AnySchema, AnyTable } from "../../schema/create";
|
|
3
|
+
import { buildCondition } from "../../query/condition-builder";
|
|
4
|
+
import { buildFindOptions } from "../../query/orm/orm";
|
|
5
|
+
import type { KyselyConfig } from "./kysely-adapter";
|
|
6
|
+
import { createKyselyQueryBuilder } from "./kysely-query-builder";
|
|
7
|
+
import type { ConditionBuilder, Condition } from "../../query/condition-builder";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal query compiler interface for Kysely
|
|
11
|
+
* Used by the UOW compiler to generate compiled queries
|
|
12
|
+
*/
|
|
13
|
+
export interface KyselyQueryCompiler {
|
|
14
|
+
count: (
|
|
15
|
+
name: string,
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
options?: { where?: (eb: ConditionBuilder<any>) => any },
|
|
18
|
+
) => CompiledQuery | null;
|
|
19
|
+
findFirst: (name: string, options: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
20
|
+
findMany: (name: string, options?: any) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
21
|
+
create: (name: string, values: any) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
22
|
+
createMany: (name: string, values: any[]) => CompiledQuery; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
23
|
+
updateMany: (name: string, options: { set: any; where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
24
|
+
deleteMany: (name: string, options: { where?: any }) => CompiledQuery | null; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createKyselyQueryCompiler<T extends AnySchema>(
|
|
28
|
+
schema: T,
|
|
29
|
+
config: KyselyConfig,
|
|
30
|
+
): KyselyQueryCompiler {
|
|
31
|
+
const { db: kysely, provider } = config;
|
|
32
|
+
const queryBuilder = createKyselyQueryBuilder(kysely, provider);
|
|
33
|
+
|
|
34
|
+
function toTable(name: unknown): AnyTable {
|
|
35
|
+
const table = schema.tables[name as string];
|
|
36
|
+
if (!table) {
|
|
37
|
+
throw new Error(`Invalid table name ${name}.`);
|
|
38
|
+
}
|
|
39
|
+
return table;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
count(name, { where } = {}) {
|
|
44
|
+
const table = toTable(name);
|
|
45
|
+
let conditions = where ? buildCondition(table.columns, where) : undefined;
|
|
46
|
+
if (conditions === true) {
|
|
47
|
+
conditions = undefined;
|
|
48
|
+
}
|
|
49
|
+
if (conditions === false) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return queryBuilder.count(table, { where: conditions });
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
findFirst(name, options) {
|
|
57
|
+
const table = toTable(name);
|
|
58
|
+
// Safe cast: FindFirstOptions is structurally compatible with FindManyOptions
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
const compiledOptions = buildFindOptions(table, options as any);
|
|
61
|
+
if (compiledOptions === false) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return queryBuilder.findMany(table, {
|
|
66
|
+
...compiledOptions,
|
|
67
|
+
limit: 1,
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
findMany(name, options = {}) {
|
|
72
|
+
const table = toTable(name);
|
|
73
|
+
// Safe cast: FindManyOptions from compiler matches FindManyOptions from buildFindOptions
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
+
const compiledOptions = buildFindOptions(table, options as any);
|
|
76
|
+
if (compiledOptions === false) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return queryBuilder.findMany(table, compiledOptions);
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
create(name, values) {
|
|
84
|
+
const table = toTable(name);
|
|
85
|
+
return queryBuilder.create(table, values);
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
createMany(name, values) {
|
|
89
|
+
const table = toTable(name);
|
|
90
|
+
return queryBuilder.createMany(table, values);
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
updateMany(name, { set, where }) {
|
|
94
|
+
const table = toTable(name);
|
|
95
|
+
let conditions = where ? buildCondition(table.columns, where) : undefined;
|
|
96
|
+
if (conditions === true) {
|
|
97
|
+
conditions = undefined;
|
|
98
|
+
}
|
|
99
|
+
if (conditions === false) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Safe: conditions is Condition | undefined after filtering out true/false
|
|
104
|
+
return queryBuilder.updateMany(table, {
|
|
105
|
+
set,
|
|
106
|
+
where: conditions as Condition | undefined,
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
deleteMany(name, { where }) {
|
|
111
|
+
const table = toTable(name);
|
|
112
|
+
let conditions = where ? buildCondition(table.columns, where) : undefined;
|
|
113
|
+
if (conditions === true) {
|
|
114
|
+
conditions = undefined;
|
|
115
|
+
}
|
|
116
|
+
if (conditions === false) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Safe: conditions is Condition | undefined after filtering out true/false
|
|
121
|
+
return queryBuilder.deleteMany(table, { where: conditions as Condition | undefined });
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import type { AbstractQuery } from "../../query/query";
|
|
2
|
+
import type { AnySchema } from "../../schema/create";
|
|
3
|
+
import type { KyselyConfig } from "./kysely-adapter";
|
|
4
|
+
import type { CompiledMutation, UOWDecoder, UOWExecutor } from "../../query/unit-of-work";
|
|
5
|
+
import { decodeResult } from "../../query/result-transform";
|
|
6
|
+
import { createKyselyUOWCompiler } from "./kysely-uow-compiler";
|
|
7
|
+
import { executeKyselyRetrievalPhase, executeKyselyMutationPhase } from "./kysely-uow-executor";
|
|
8
|
+
import { UnitOfWork } from "../../query/unit-of-work";
|
|
9
|
+
import type { CompiledQuery } from "kysely";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a Kysely-based query engine for the given schema.
|
|
13
|
+
*
|
|
14
|
+
* This is the main entry point for creating a database query interface using Kysely.
|
|
15
|
+
* It uses a compiler-based architecture where queries are compiled to SQL and then executed,
|
|
16
|
+
* enabling features like SQL snapshot testing.
|
|
17
|
+
*
|
|
18
|
+
* @param schema - The database schema definition
|
|
19
|
+
* @param config - Kysely configuration containing the database instance and provider
|
|
20
|
+
* @returns An AbstractQuery instance for performing database operations
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const queryEngine = fromKysely(mySchema, {
|
|
25
|
+
* db: kysely,
|
|
26
|
+
* provider: 'postgresql'
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* const users = await queryEngine.findMany('users', {
|
|
30
|
+
* where: (b) => b('age', '>', 18),
|
|
31
|
+
* orderBy: [['name', 'asc']]
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function fromKysely<T extends AnySchema>(schema: T, config: KyselyConfig): AbstractQuery<T> {
|
|
36
|
+
const { db: kysely, provider } = config;
|
|
37
|
+
const uowCompiler = createKyselyUOWCompiler(schema, config);
|
|
38
|
+
|
|
39
|
+
function createUOW(name?: string): UnitOfWork<T, []> {
|
|
40
|
+
const executor: UOWExecutor<CompiledQuery, unknown> = {
|
|
41
|
+
executeRetrievalPhase: (retrievalBatch: CompiledQuery[]) =>
|
|
42
|
+
executeKyselyRetrievalPhase(kysely, retrievalBatch),
|
|
43
|
+
executeMutationPhase: (mutationBatch: CompiledMutation<CompiledQuery>[]) =>
|
|
44
|
+
executeKyselyMutationPhase(kysely, mutationBatch),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Create a decoder function to transform raw results into application format
|
|
48
|
+
const decoder: UOWDecoder<T> = (rawResults, ops) => {
|
|
49
|
+
if (rawResults.length !== ops.length) {
|
|
50
|
+
throw new Error("rawResults and ops must have the same length");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return rawResults.map((rows, index) => {
|
|
54
|
+
const op = ops[index];
|
|
55
|
+
if (!op) {
|
|
56
|
+
throw new Error("op must be defined");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Handle count operations differently - return the count number directly
|
|
60
|
+
if (op.type === "count") {
|
|
61
|
+
const rowArray = rows as Record<string, unknown>[];
|
|
62
|
+
const firstRow = rowArray[0];
|
|
63
|
+
if (!firstRow) {
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
const count = Number(firstRow["count"]);
|
|
67
|
+
if (Number.isNaN(count)) {
|
|
68
|
+
throw new Error(`Unexpected result for count, received: ${count}`);
|
|
69
|
+
}
|
|
70
|
+
return count;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Each result is an array of rows - decode each row
|
|
74
|
+
const rowArray = rows as Record<string, unknown>[];
|
|
75
|
+
return rowArray.map((row) => decodeResult(row, op.table, provider));
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return new UnitOfWork(schema, uowCompiler, executor, decoder, name);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
async find(tableName, builderFn) {
|
|
84
|
+
const uow = createUOW();
|
|
85
|
+
uow.find(tableName, builderFn);
|
|
86
|
+
// executeRetrieve returns an array of results (one per find operation)
|
|
87
|
+
// Since we only have one find, unwrap the first result
|
|
88
|
+
const [result]: unknown[][] = await uow.executeRetrieve();
|
|
89
|
+
return result ?? [];
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
async findFirst(tableName, builderFn) {
|
|
93
|
+
const uow = createUOW();
|
|
94
|
+
if (builderFn) {
|
|
95
|
+
uow.find(tableName, (b) => builderFn(b as never).pageSize(1));
|
|
96
|
+
} else {
|
|
97
|
+
uow.find(tableName, (b) => b.whereIndex("primary").pageSize(1));
|
|
98
|
+
}
|
|
99
|
+
// executeRetrieve runs an array of `find` operation results, which each return an array of rows
|
|
100
|
+
const [result]: unknown[][] = await uow.executeRetrieve();
|
|
101
|
+
return result?.[0] ?? null;
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
async create(tableName, values) {
|
|
105
|
+
const uow = createUOW();
|
|
106
|
+
uow.create(tableName, values);
|
|
107
|
+
const { success } = await uow.executeMutations();
|
|
108
|
+
if (!success) {
|
|
109
|
+
// This should not happen because we don't `.check()` this call.
|
|
110
|
+
// TODO: Verify what happens when there are unique constraints
|
|
111
|
+
throw new Error("Failed to create record");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const [createdId] = uow.getCreatedIds();
|
|
115
|
+
if (!createdId) {
|
|
116
|
+
throw new Error("Failed to get created ID");
|
|
117
|
+
}
|
|
118
|
+
return createdId;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
async createMany(tableName, valuesArray) {
|
|
122
|
+
const uow = createUOW();
|
|
123
|
+
for (const values of valuesArray) {
|
|
124
|
+
uow.create(tableName, values);
|
|
125
|
+
}
|
|
126
|
+
const { success } = await uow.executeMutations();
|
|
127
|
+
if (!success) {
|
|
128
|
+
throw new Error("Failed to create records");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return uow.getCreatedIds();
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
async update(tableName, id, builderFn) {
|
|
135
|
+
const uow = createUOW();
|
|
136
|
+
uow.update(tableName, id, builderFn);
|
|
137
|
+
const { success } = await uow.executeMutations();
|
|
138
|
+
if (!success) {
|
|
139
|
+
throw new Error("Failed to update record (version conflict or record not found)");
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
async updateMany(tableName, builderFn) {
|
|
144
|
+
// Create a special builder that captures both where and set operations
|
|
145
|
+
let whereConfig: { indexName?: string; condition?: unknown } = {};
|
|
146
|
+
let setValues: unknown;
|
|
147
|
+
|
|
148
|
+
const specialBuilder = {
|
|
149
|
+
whereIndex(indexName: string, condition?: unknown) {
|
|
150
|
+
whereConfig = { indexName, condition };
|
|
151
|
+
return this;
|
|
152
|
+
},
|
|
153
|
+
set(values: unknown) {
|
|
154
|
+
setValues = values;
|
|
155
|
+
return this;
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
builderFn(specialBuilder);
|
|
160
|
+
|
|
161
|
+
if (!whereConfig.indexName) {
|
|
162
|
+
throw new Error("whereIndex() must be called in updateMany");
|
|
163
|
+
}
|
|
164
|
+
if (!setValues) {
|
|
165
|
+
throw new Error("set() must be called in updateMany");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// First, find all matching records
|
|
169
|
+
const findUow = createUOW();
|
|
170
|
+
findUow.find(tableName, (b) => {
|
|
171
|
+
if (whereConfig.condition) {
|
|
172
|
+
return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);
|
|
173
|
+
}
|
|
174
|
+
return b.whereIndex(whereConfig.indexName as never);
|
|
175
|
+
});
|
|
176
|
+
const findResults: unknown[][] = await findUow.executeRetrieve();
|
|
177
|
+
const records = findResults[0];
|
|
178
|
+
|
|
179
|
+
if (!records || records.length === 0) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Now update all found records
|
|
184
|
+
const updateUow = createUOW();
|
|
185
|
+
for (const record of records as never as Array<{ id: unknown }>) {
|
|
186
|
+
updateUow.update(tableName as string, record.id as string, (b) =>
|
|
187
|
+
b.set(setValues as never),
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const { success } = await updateUow.executeMutations();
|
|
191
|
+
if (!success) {
|
|
192
|
+
throw new Error("Failed to update records (version conflict)");
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
async delete(tableName, id, builderFn) {
|
|
197
|
+
const uow = createUOW();
|
|
198
|
+
uow.delete(tableName, id, builderFn as never);
|
|
199
|
+
const { success } = await uow.executeMutations();
|
|
200
|
+
if (!success) {
|
|
201
|
+
throw new Error("Failed to delete record (version conflict or record not found)");
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
async deleteMany(tableName, builderFn) {
|
|
206
|
+
// Create a special builder that captures where configuration
|
|
207
|
+
let whereConfig: { indexName?: string; condition?: unknown } = {};
|
|
208
|
+
|
|
209
|
+
const specialBuilder = {
|
|
210
|
+
whereIndex(indexName: string, condition?: unknown) {
|
|
211
|
+
whereConfig = { indexName, condition };
|
|
212
|
+
return this;
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Safe: Call builderFn to capture the configuration
|
|
217
|
+
builderFn(specialBuilder as never);
|
|
218
|
+
|
|
219
|
+
if (!whereConfig.indexName) {
|
|
220
|
+
throw new Error("whereIndex() must be called in deleteMany");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// First, find all matching records
|
|
224
|
+
const findUow = createUOW();
|
|
225
|
+
findUow.find(tableName as string, (b) => {
|
|
226
|
+
if (whereConfig.condition) {
|
|
227
|
+
return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);
|
|
228
|
+
}
|
|
229
|
+
return b.whereIndex(whereConfig.indexName as never);
|
|
230
|
+
});
|
|
231
|
+
const findResults2 = await findUow.executeRetrieve();
|
|
232
|
+
const records = (findResults2 as unknown as [unknown])[0];
|
|
233
|
+
|
|
234
|
+
// @ts-expect-error - Type narrowing doesn't work through unknown cast
|
|
235
|
+
if (!records || records.length === 0) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Now delete all found records
|
|
240
|
+
const deleteUow = createUOW();
|
|
241
|
+
for (const record of records as never as Array<{ id: unknown }>) {
|
|
242
|
+
deleteUow.delete(tableName as string, record.id as string);
|
|
243
|
+
}
|
|
244
|
+
const { success } = await deleteUow.executeMutations();
|
|
245
|
+
if (!success) {
|
|
246
|
+
throw new Error("Failed to delete records (version conflict)");
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
createUnitOfWork(name) {
|
|
251
|
+
return createUOW(name);
|
|
252
|
+
},
|
|
253
|
+
} as AbstractQuery<T>;
|
|
254
|
+
}
|