@fragno-dev/db 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.turbo/turbo-build.log +30 -28
  2. package/CHANGELOG.md +13 -0
  3. package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -1
  4. package/dist/adapters/drizzle/drizzle-query.js +38 -34
  5. package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
  6. package/dist/adapters/kysely/kysely-adapter.d.ts +3 -2
  7. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  8. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  9. package/dist/adapters/kysely/kysely-query.d.ts +22 -0
  10. package/dist/adapters/kysely/kysely-query.d.ts.map +1 -0
  11. package/dist/adapters/kysely/kysely-query.js +72 -50
  12. package/dist/adapters/kysely/kysely-query.js.map +1 -1
  13. package/dist/adapters/kysely/kysely-uow-executor.js +2 -2
  14. package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -1
  15. package/dist/migration-engine/generation-engine.d.ts +1 -1
  16. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  17. package/dist/migration-engine/generation-engine.js.map +1 -1
  18. package/dist/mod.d.ts +5 -5
  19. package/dist/mod.d.ts.map +1 -1
  20. package/dist/mod.js.map +1 -1
  21. package/dist/query/query.d.ts +24 -8
  22. package/dist/query/query.d.ts.map +1 -1
  23. package/dist/query/result-transform.js +17 -5
  24. package/dist/query/result-transform.js.map +1 -1
  25. package/dist/query/unit-of-work.d.ts +5 -4
  26. package/dist/query/unit-of-work.d.ts.map +1 -1
  27. package/dist/query/unit-of-work.js +2 -3
  28. package/dist/query/unit-of-work.js.map +1 -1
  29. package/dist/schema/serialize.js +2 -0
  30. package/dist/schema/serialize.js.map +1 -1
  31. package/package.json +2 -2
  32. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +170 -50
  33. package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +89 -35
  34. package/src/adapters/drizzle/drizzle-query.test.ts +54 -4
  35. package/src/adapters/drizzle/drizzle-query.ts +65 -60
  36. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +63 -3
  37. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +88 -0
  38. package/src/adapters/kysely/kysely-adapter.ts +6 -3
  39. package/src/adapters/kysely/kysely-query.test.ts +498 -0
  40. package/src/adapters/kysely/kysely-query.ts +137 -82
  41. package/src/adapters/kysely/kysely-uow-compiler.test.ts +66 -0
  42. package/src/adapters/kysely/kysely-uow-executor.ts +5 -9
  43. package/src/migration-engine/generation-engine.ts +2 -1
  44. package/src/mod.ts +6 -6
  45. package/src/query/query-type.test.ts +34 -14
  46. package/src/query/query.ts +77 -36
  47. package/src/query/result-transform.test.ts +5 -5
  48. package/src/query/result-transform.ts +29 -11
  49. package/src/query/unit-of-work.ts +8 -11
  50. package/src/schema/serialize.test.ts +223 -0
  51. package/src/schema/serialize.ts +16 -0
@@ -1,5 +1,5 @@
1
1
 
2
- > @fragno-dev/db@0.1.11 build /home/runner/work/fragno/fragno/packages/fragno-db
2
+ > @fragno-dev/db@0.1.12 build /home/runner/work/fragno/fragno/packages/fragno-db
3
3
  > tsdown
4
4
 
5
5
  ℹ tsdown v0.15.12 powered by rolldown v1.0.0-beta.45
@@ -8,7 +8,7 @@
8
8
  ℹ tsconfig: tsconfig.json
9
9
  ℹ Build start
10
10
  ℹ dist/schema/create.js 19.85 kB │ gzip: 5.20 kB
11
- ℹ dist/query/unit-of-work.js 16.39 kB │ gzip: 3.81 kB
11
+ ℹ dist/query/unit-of-work.js 16.49 kB │ gzip: 3.87 kB
12
12
  ℹ dist/adapters/drizzle/generate.js 14.82 kB │ gzip: 3.64 kB
13
13
  ℹ dist/migration-engine/generation-engine.js  8.40 kB │ gzip: 2.26 kB
14
14
  ℹ dist/adapters/kysely/kysely-adapter.js  5.27 kB │ gzip: 1.64 kB
@@ -20,25 +20,25 @@
20
20
  ℹ dist/id.js  0.07 kB │ gzip: 0.07 kB
21
21
  ℹ dist/query/query.js  0.01 kB │ gzip: 0.03 kB
22
22
  ℹ dist/schema/create.js.map 48.81 kB │ gzip: 11.78 kB
23
- ℹ dist/query/unit-of-work.js.map 45.94 kB │ gzip: 10.16 kB
23
+ ℹ dist/query/unit-of-work.js.map 46.06 kB │ gzip: 10.25 kB
24
24
  ℹ dist/adapters/drizzle/generate.js.map 34.28 kB │ gzip: 8.39 kB
25
25
  ℹ dist/adapters/drizzle/drizzle-uow-compiler.js.map 31.70 kB │ gzip: 7.84 kB
26
26
  ℹ dist/adapters/kysely/kysely-query-builder.js.map 30.22 kB │ gzip: 7.85 kB
27
- ℹ dist/migration-engine/generation-engine.js.map 16.35 kB │ gzip: 4.35 kB
27
+ ℹ dist/migration-engine/generation-engine.js.map 16.40 kB │ gzip: 4.39 kB
28
+ ℹ dist/adapters/kysely/kysely-query.js.map 15.71 kB │ gzip: 4.41 kB
28
29
  ℹ dist/adapters/drizzle/drizzle-uow-compiler.js 14.29 kB │ gzip: 3.65 kB
29
- ℹ dist/adapters/drizzle/drizzle-query.js.map 14.26 kB │ gzip: 3.64 kB
30
+ ℹ dist/adapters/drizzle/drizzle-query.js.map 14.14 kB │ gzip: 3.85 kB
30
31
  ℹ dist/adapters/kysely/kysely-uow-compiler.js.map 13.93 kB │ gzip: 4.01 kB
31
32
  ℹ dist/adapters/kysely/kysely-query-builder.js 13.63 kB │ gzip: 3.77 kB
32
- ℹ dist/adapters/kysely/kysely-query.js.map 13.57 kB │ gzip: 3.66 kB
33
+ ℹ dist/schema/serialize.js.map 12.70 kB │ gzip: 2.80 kB
33
34
  ℹ dist/adapters/drizzle/drizzle-uow-executor.js.map 12.65 kB │ gzip: 3.76 kB
34
- ℹ dist/schema/serialize.js.map 12.12 kB │ gzip: 2.75 kB
35
35
  ℹ dist/schema/create.d.ts.map 11.85 kB │ gzip: 4.65 kB
36
36
  ℹ dist/adapters/kysely/migration/execute-sqlite.js.map 11.80 kB │ gzip: 3.28 kB
37
- ℹ dist/adapters/kysely/kysely-adapter.js.map 11.59 kB │ gzip: 3.52 kB
37
+ ℹ dist/adapters/kysely/kysely-adapter.js.map 11.66 kB │ gzip: 3.55 kB
38
+ ℹ dist/query/result-transform.js.map 11.61 kB │ gzip: 3.42 kB
38
39
  ℹ dist/adapters/kysely/migration/execute-mssql.js.map 11.48 kB │ gzip: 2.94 kB
39
- ℹ dist/query/result-transform.js.map 10.51 kB │ gzip: 3.26 kB
40
40
  ℹ dist/adapters/kysely/migration/execute-postgres.js.map 10.44 kB │ gzip: 2.64 kB
41
- ℹ dist/query/unit-of-work.d.ts.map  9.82 kB │ gzip: 3.79 kB
41
+ ℹ dist/query/unit-of-work.d.ts.map  9.84 kB │ gzip: 3.81 kB
42
42
  ℹ dist/adapters/kysely/migration/execute-base.js.map  9.77 kB │ gzip: 3.27 kB
43
43
  ℹ dist/adapters/kysely/migration/execute-mysql.js.map  9.30 kB │ gzip: 2.37 kB
44
44
  ℹ dist/query/condition-builder.js.map  9.18 kB │ gzip: 2.42 kB
@@ -46,27 +46,27 @@
46
46
  ℹ dist/fragment.js.map  8.01 kB │ gzip: 2.12 kB
47
47
  ℹ dist/adapters/drizzle/drizzle-uow-decoder.js.map  7.73 kB │ gzip: 2.82 kB
48
48
  ℹ dist/migration-engine/create.js.map  7.32 kB │ gzip: 2.14 kB
49
- ℹ dist/adapters/kysely/kysely-uow-executor.js.map  7.10 kB │ gzip: 2.53 kB
50
- ℹ dist/adapters/drizzle/drizzle-query.js  6.61 kB │ gzip: 1.74 kB
51
- ℹ dist/query/query.d.ts.map  6.51 kB │ gzip: 2.43 kB
49
+ ℹ dist/query/query.d.ts.map  7.31 kB │ gzip: 2.73 kB
50
+ ℹ dist/adapters/kysely/kysely-query.js  7.10 kB │ gzip: 2.10 kB
51
+ ℹ dist/adapters/kysely/kysely-uow-executor.js.map  6.98 kB │ gzip: 2.48 kB
52
+ ℹ dist/adapters/drizzle/drizzle-query.js  6.63 kB │ gzip: 1.87 kB
52
53
  ℹ dist/adapters/kysely/kysely-query-compiler.js.map  6.50 kB │ gzip: 1.62 kB
53
- ℹ dist/adapters/kysely/kysely-query.js  6.30 kB │ gzip: 1.75 kB
54
54
  ℹ dist/adapters/drizzle/drizzle-uow-executor.js  6.18 kB │ gzip: 1.90 kB
55
55
  ℹ dist/adapters/kysely/kysely-uow-compiler.js  6.02 kB │ gzip: 1.85 kB
56
- ℹ dist/query/result-transform.js  5.52 kB │ gzip: 1.87 kB
56
+ ℹ dist/query/result-transform.js  6.01 kB │ gzip: 1.92 kB
57
57
  ℹ dist/adapters/kysely/migration/execute-mssql.js  5.51 kB │ gzip: 1.52 kB
58
58
  ℹ dist/adapters/kysely/migration/execute-sqlite.js  5.48 kB │ gzip: 1.63 kB
59
+ ℹ dist/mod.js.map  5.15 kB │ gzip: 1.72 kB
59
60
  ℹ dist/query/cursor.js.map  5.13 kB │ gzip: 1.81 kB
60
- ℹ dist/mod.js.map  5.04 kB │ gzip: 1.69 kB
61
61
  ℹ dist/adapters/kysely/migration/execute-postgres.js  4.91 kB │ gzip: 1.39 kB
62
62
  ℹ dist/adapters/drizzle/drizzle-adapter.js.map  4.61 kB │ gzip: 1.71 kB
63
63
  ℹ dist/adapters/kysely/migration/execute-mysql.js  4.34 kB │ gzip: 1.20 kB
64
64
  ℹ dist/migration-engine/auto-from-schema.js  4.33 kB │ gzip: 1.21 kB
65
65
  ℹ dist/adapters/kysely/migration/execute-base.js  4.31 kB │ gzip: 1.69 kB
66
+ ℹ dist/schema/serialize.js  4.04 kB │ gzip: 1.07 kB
66
67
  ℹ dist/migration-engine/shared.js.map  3.89 kB │ gzip: 1.25 kB
67
68
  ℹ dist/adapters/drizzle/drizzle-uow-decoder.js  3.78 kB │ gzip: 1.46 kB
68
- ℹ dist/schema/serialize.js  3.74 kB │ gzip: 1.06 kB
69
- ℹ dist/adapters/kysely/kysely-uow-executor.js  3.54 kB │ gzip: 1.25 kB
69
+ ℹ dist/adapters/kysely/kysely-uow-executor.js  3.56 kB │ gzip: 1.26 kB
70
70
  ℹ dist/query/orm/orm.js.map  3.49 kB │ gzip: 1.38 kB
71
71
  ℹ dist/shared/settings-schema.js.map  3.19 kB │ gzip: 1.24 kB
72
72
  ℹ dist/adapters/kysely/migration/execute-factory.js.map  2.68 kB │ gzip: 1.10 kB
@@ -87,16 +87,16 @@
87
87
  ℹ dist/query/orm/orm.js  1.33 kB │ gzip: 0.60 kB
88
88
  ℹ dist/util/import-generator.js.map  1.30 kB │ gzip: 0.62 kB
89
89
  ℹ dist/adapters/drizzle/shared.js  1.27 kB │ gzip: 0.66 kB
90
+ ℹ dist/mod.d.ts.map  1.17 kB │ gzip: 0.57 kB
90
91
  ℹ dist/adapters/kysely/kysely-connection-pool.js  1.15 kB │ gzip: 0.52 kB
91
92
  ℹ dist/adapters/drizzle/join-column-utils.js  1.14 kB │ gzip: 0.55 kB
92
93
  ℹ dist/adapters/drizzle/drizzle-connection-pool.js  1.11 kB │ gzip: 0.53 kB
93
94
  ℹ dist/adapters/kysely/kysely-shared.js.map  1.07 kB │ gzip: 0.53 kB
94
95
  ℹ dist/adapters/drizzle/drizzle-adapter.d.ts.map  0.92 kB │ gzip: 0.42 kB
95
- ℹ dist/mod.d.ts.map  0.92 kB │ gzip: 0.49 kB
96
96
  ℹ dist/util/parse.js.map  0.83 kB │ gzip: 0.48 kB
97
- ℹ dist/adapters/kysely/kysely-adapter.d.ts.map  0.79 kB │ gzip: 0.41 kB
97
+ ℹ dist/adapters/kysely/kysely-adapter.d.ts.map  0.82 kB │ gzip: 0.42 kB
98
98
  ℹ dist/adapters/adapters.d.ts.map  0.73 kB │ gzip: 0.36 kB
99
- ℹ dist/migration-engine/generation-engine.d.ts.map  0.68 kB │ gzip: 0.35 kB
99
+ ℹ dist/migration-engine/generation-engine.d.ts.map  0.69 kB │ gzip: 0.36 kB
100
100
  ℹ dist/util/import-generator.js  0.65 kB │ gzip: 0.36 kB
101
101
  ℹ dist/adapters/kysely/kysely-shared.js  0.54 kB │ gzip: 0.31 kB
102
102
  ℹ dist/migration-engine/shared.d.ts.map  0.51 kB │ gzip: 0.30 kB
@@ -110,28 +110,30 @@
110
110
  ℹ dist/migration-engine/shared.js  0.21 kB │ gzip: 0.17 kB
111
111
  ℹ dist/adapters/drizzle/drizzle-query.d.ts.map  0.18 kB │ gzip: 0.14 kB
112
112
  ℹ dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map  0.18 kB │ gzip: 0.14 kB
113
+ ℹ dist/adapters/kysely/kysely-query.d.ts.map  0.17 kB │ gzip: 0.14 kB
113
114
  ℹ dist/shared/providers.d.ts.map  0.15 kB │ gzip: 0.13 kB
114
115
  ℹ dist/schema/create.d.ts 19.46 kB │ gzip: 4.72 kB
115
- ℹ dist/query/unit-of-work.d.ts 17.56 kB │ gzip: 4.28 kB
116
- ℹ dist/query/query.d.ts  6.17 kB │ gzip: 1.57 kB
116
+ ℹ dist/query/unit-of-work.d.ts 17.68 kB │ gzip: 4.33 kB
117
+ ℹ dist/query/query.d.ts  6.96 kB │ gzip: 1.75 kB
117
118
  ℹ dist/query/cursor.d.ts  2.57 kB │ gzip: 0.93 kB
118
119
  ℹ dist/fragment.d.ts  2.39 kB │ gzip: 0.75 kB
119
- ℹ dist/mod.d.ts  2.22 kB │ gzip: 0.73 kB
120
- ℹ dist/migration-engine/generation-engine.d.ts  1.99 kB │ gzip: 0.72 kB
120
+ ℹ dist/mod.d.ts  2.32 kB │ gzip: 0.76 kB
121
+ ℹ dist/migration-engine/generation-engine.d.ts  2.00 kB │ gzip: 0.72 kB
121
122
  ℹ dist/adapters/adapters.d.ts  1.48 kB │ gzip: 0.60 kB
122
123
  ℹ dist/adapters/drizzle/drizzle-adapter.d.ts  1.35 kB │ gzip: 0.56 kB
123
- ℹ dist/adapters/kysely/kysely-adapter.d.ts  1.19 kB │ gzip: 0.52 kB
124
+ ℹ dist/adapters/kysely/kysely-adapter.d.ts  1.28 kB │ gzip: 0.54 kB
124
125
  ℹ dist/adapters/drizzle/generate.d.ts  0.82 kB │ gzip: 0.42 kB
125
126
  ℹ dist/id.d.ts  0.07 kB │ gzip: 0.07 kB
126
127
  ℹ dist/migration-engine/shared.d.ts  2.76 kB │ gzip: 0.99 kB
127
128
  ℹ dist/query/condition-builder.d.ts  2.00 kB │ gzip: 0.68 kB
128
129
  ℹ dist/migration-engine/create.d.ts  1.10 kB │ gzip: 0.51 kB
129
130
  ℹ dist/adapters/drizzle/drizzle-query.d.ts  0.71 kB │ gzip: 0.41 kB
131
+ ℹ dist/adapters/kysely/kysely-query.d.ts  0.65 kB │ gzip: 0.39 kB
130
132
  ℹ dist/query/orm/orm.d.ts  0.61 kB │ gzip: 0.34 kB
131
133
  ℹ dist/schema-generator/schema-generator.d.ts  0.37 kB │ gzip: 0.20 kB
132
134
  ℹ dist/shared/providers.d.ts  0.26 kB │ gzip: 0.19 kB
133
135
  ℹ dist/util/types.d.ts  0.26 kB │ gzip: 0.21 kB
134
136
  ℹ dist/adapters/drizzle/drizzle-uow-compiler.d.ts  0.25 kB │ gzip: 0.18 kB
135
137
  ℹ dist/adapters/drizzle/shared.d.ts  0.02 kB │ gzip: 0.04 kB
136
- ℹ 126 files, total: 745.03 kB
137
- ✔ Build complete in 20040ms
138
+ ℹ 128 files, total: 753.71 kB
139
+ ✔ Build complete in 9805ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @fragno-dev/db
2
2
 
3
+ ## 0.1.12
4
+
5
+ ### Patch Changes
6
+
7
+ - 2900bfa: fix: improve typing on query results
8
+ - 059a249: Properly construct return type for `find` and `findFirst` with `select()`. The return
9
+ type now correctly infers only the selected columns from the builder function, providing better
10
+ type safety when using `.select()` to specify a subset of columns.
11
+ - f3f7bc2: feat: allow creating and referencing an object in a single unit of work
12
+ - fdb5aaf: Fix timestamp deserialization for PostgreSQL, MySQL, and CockroachDB. Previously,
13
+ timestamp and date columns were returned as strings instead of JavaScript Date objects. Now they
14
+ are properly converted to Date objects with full timezone support.
15
+
3
16
  ## 0.1.11
4
17
 
5
18
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"drizzle-query.d.ts","names":[],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAaiB,gBAAA;;;;;oBAKG"}
1
+ {"version":3,"file":"drizzle-query.d.ts","names":[],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAciB,gBAAA;;;;;oBAKG"}
@@ -6,6 +6,30 @@ import { createDrizzleUOWDecoder } from "./drizzle-uow-decoder.js";
6
6
 
7
7
  //#region src/adapters/drizzle/drizzle-query.ts
8
8
  /**
9
+ * Special builder for updateMany operations that captures configuration
10
+ */
11
+ var UpdateManySpecialBuilder = class {
12
+ #indexName;
13
+ #condition;
14
+ #setValues;
15
+ whereIndex(indexName, condition) {
16
+ this.#indexName = indexName;
17
+ this.#condition = condition;
18
+ return this;
19
+ }
20
+ set(values) {
21
+ this.#setValues = values;
22
+ return this;
23
+ }
24
+ getConfig() {
25
+ return {
26
+ indexName: this.#indexName,
27
+ condition: this.#condition,
28
+ setValues: this.#setValues
29
+ };
30
+ }
31
+ };
32
+ /**
9
33
  * Creates a Drizzle-based query engine for the given schema.
10
34
  *
11
35
  * This is the main entry point for creating a database query interface using Drizzle.
@@ -74,7 +98,10 @@ function fromDrizzle(schema, pool, provider, mapper, uowConfig) {
74
98
  },
75
99
  async findFirst(tableName, builderFn) {
76
100
  const uow = createUOW({ config: uowConfig });
77
- if (builderFn) uow.find(tableName, (b) => builderFn(b).pageSize(1));
101
+ if (builderFn) uow.find(tableName, (b) => {
102
+ builderFn(b);
103
+ return b.pageSize(1);
104
+ });
78
105
  else uow.find(tableName, (b) => b.whereIndex("primary").pageSize(1));
79
106
  const [result] = await uow.executeRetrieve();
80
107
  return result?.[0] ?? null;
@@ -102,29 +129,18 @@ function fromDrizzle(schema, pool, provider, mapper, uowConfig) {
102
129
  if (!success) throw new Error("Failed to update record (version conflict or record not found)");
103
130
  },
104
131
  async updateMany(tableName, builderFn) {
105
- let whereConfig = {};
106
- let setValues;
107
- builderFn({
108
- whereIndex(indexName, condition) {
109
- whereConfig = {
110
- indexName,
111
- condition
112
- };
113
- return this;
114
- },
115
- set(values) {
116
- setValues = values;
117
- return this;
118
- }
119
- });
120
- if (!whereConfig.indexName) throw new Error("whereIndex() must be called in updateMany");
132
+ if (!schema.tables[tableName]) throw new Error(`Table ${tableName} not found in schema`);
133
+ const specialBuilder = new UpdateManySpecialBuilder();
134
+ builderFn(specialBuilder);
135
+ const { indexName, condition, setValues } = specialBuilder.getConfig();
136
+ if (!indexName) throw new Error("whereIndex() must be called in updateMany");
121
137
  if (!setValues) throw new Error("set() must be called in updateMany");
122
138
  const findUow = createUOW({ config: uowConfig });
123
139
  findUow.find(tableName, (b) => {
124
- if (whereConfig.condition) return b.whereIndex(whereConfig.indexName, whereConfig.condition);
125
- return b.whereIndex(whereConfig.indexName);
140
+ if (condition) return b.whereIndex(indexName, condition);
141
+ return b.whereIndex(indexName);
126
142
  });
127
- const records = (await findUow.executeRetrieve())[0];
143
+ const [records] = await findUow.executeRetrieve();
128
144
  if (!records || records.length === 0) return;
129
145
  const updateUow = createUOW({ config: uowConfig });
130
146
  for (const record of records) updateUow.update(tableName, record.id, (b) => b.set(setValues));
@@ -138,21 +154,9 @@ function fromDrizzle(schema, pool, provider, mapper, uowConfig) {
138
154
  if (!success) throw new Error("Failed to delete record (version conflict or record not found)");
139
155
  },
140
156
  async deleteMany(tableName, builderFn) {
141
- let whereConfig = {};
142
- builderFn({ whereIndex(indexName, condition) {
143
- whereConfig = {
144
- indexName,
145
- condition
146
- };
147
- return this;
148
- } });
149
- if (!whereConfig.indexName) throw new Error("whereIndex() must be called in deleteMany");
150
157
  const findUow = createUOW({ config: uowConfig });
151
- findUow.find(tableName, (b) => {
152
- if (whereConfig.condition) return b.whereIndex(whereConfig.indexName, whereConfig.condition);
153
- return b.whereIndex(whereConfig.indexName);
154
- });
155
- const records = (await findUow.executeRetrieve())[0];
158
+ findUow.find(tableName, builderFn);
159
+ const [records] = await findUow.executeRetrieve();
156
160
  if (!records || records.length === 0) return;
157
161
  const deleteUow = createUOW({ config: uowConfig });
158
162
  for (const record of records) deleteUow.delete(tableName, record.id);
@@ -1 +1 @@
1
- {"version":3,"file":"drizzle-query.js","names":["executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult>","whereConfig: { indexName?: string; condition?: unknown }","setValues: unknown"],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema } from \"../../schema/create\";\nimport type { CompiledMutation, UOWExecutor } from \"../../query/unit-of-work\";\nimport { createDrizzleUOWCompiler, type DrizzleCompiledQuery } from \"./drizzle-uow-compiler\";\nimport { executeDrizzleRetrievalPhase, executeDrizzleMutationPhase } from \"./drizzle-uow-executor\";\nimport { UnitOfWork } from \"../../query/unit-of-work\";\nimport { parseDrizzle, type DrizzleResult, type TableNameMapper, type DBType } from \"./shared\";\nimport { createDrizzleUOWDecoder } from \"./drizzle-uow-decoder\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\n\n/**\n * Configuration options for creating a Drizzle Unit of Work\n */\nexport interface DrizzleUOWConfig {\n /**\n * Optional callback to receive compiled SQL queries for logging/debugging\n * This callback is invoked for each query as it's compiled\n */\n onQuery?: (query: DrizzleCompiledQuery) => void;\n /**\n * If true, the query will not be executed and the query will be returned. Not respected for UOWs\n * since those have to be manually executed.\n */\n dryRun?: boolean;\n}\n\n/**\n * Creates a Drizzle-based query engine for the given schema.\n *\n * This is the main entry point for creating a database query interface using Drizzle.\n * It uses a compiler-based architecture where queries are compiled to SQL and then executed,\n * enabling features like SQL snapshot testing.\n *\n * @param schema - The database schema definition\n * @param pool - Connection pool for acquiring database connections\n * @param provider - SQL provider (sqlite, mysql, postgresql)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const pool = createSimpleConnectionPool(drizzle);\n * const queryEngine = fromDrizzle(mySchema, pool, 'postgresql');\n *\n * const uow = queryEngine.createUnitOfWork('myOperation');\n * ```\n */\nexport function fromDrizzle<T extends AnySchema>(\n schema: T,\n pool: ConnectionPool<DBType>,\n provider: \"sqlite\" | \"mysql\" | \"postgresql\",\n mapper?: TableNameMapper,\n uowConfig?: DrizzleUOWConfig,\n): AbstractQuery<T, DrizzleUOWConfig> {\n function createUOW(opts: { name?: string; config?: DrizzleUOWConfig }) {\n const uowCompiler = createDrizzleUOWCompiler(schema, pool, provider, mapper);\n\n const executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult> = {\n async executeRetrievalPhase(retrievalBatch: DrizzleCompiledQuery[]) {\n // In dryRun mode, skip execution and return empty results\n if (opts.config?.dryRun) {\n return retrievalBatch.map(() => ({\n rows: [],\n affectedRows: 0,\n }));\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleRetrievalPhase(db, retrievalBatch, provider);\n } finally {\n await conn.release();\n }\n },\n async executeMutationPhase(mutationBatch: CompiledMutation<DrizzleCompiledQuery>[]) {\n // In dryRun mode, skip execution and return success with mock internal IDs\n if (opts.config?.dryRun) {\n return {\n success: true,\n createdInternalIds: mutationBatch.map(() => null),\n };\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleMutationPhase(db, mutationBatch, provider);\n } finally {\n await conn.release();\n }\n },\n };\n\n const decoder = createDrizzleUOWDecoder(schema, provider);\n\n const { onQuery, ...restUowConfig } = opts.config ?? {};\n\n return new UnitOfWork(schema, uowCompiler, executor, decoder, opts.name, {\n ...restUowConfig,\n onQuery: (query) => {\n // Handle both CompiledQuery and CompiledMutation structures\n // Retrieval operations return DrizzleCompiledQuery directly: { sql, params }\n // Mutation operations return CompiledMutation: { query: DrizzleCompiledQuery, expectedAffectedRows }\n const actualQuery =\n query && typeof query === \"object\" && \"query\" in query\n ? (query as CompiledMutation<DrizzleCompiledQuery>).query\n : (query as DrizzleCompiledQuery);\n\n opts.config?.onQuery?.(actualQuery);\n },\n });\n }\n\n return {\n async find(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig }).find(tableName, builderFn);\n const [result] = await uow.executeRetrieve();\n return result;\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => builderFn(b as never).pageSize(1));\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW({ config: uowConfig });\n uow.create(tableName as string, values as never);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create record\");\n }\n\n const createdIds = uow.getCreatedIds();\n const createdId = createdIds[0];\n if (!createdId) {\n throw new Error(\"Failed to get created ID\");\n }\n return createdId;\n },\n\n async createMany(tableName, valuesArray) {\n const uow = createUOW({ config: uowConfig });\n for (const values of valuesArray) {\n uow.create(tableName as string, values as never);\n }\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create records\");\n }\n\n return uow.getCreatedIds();\n },\n\n async update(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.update(tableName as string, id, builderFn as never);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n // FIXME: This is not correct\n\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n let setValues: unknown;\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n set(values: unknown) {\n setValues = values;\n return this;\n },\n };\n\n builderFn(specialBuilder);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults = await findUow.executeRetrieve();\n const records = (findResults as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as never as Array<{ id: unknown }>) {\n updateUow.update(tableName as string, record.id as string, (b) =>\n b.set(setValues as never),\n );\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.delete(tableName as string, id, builderFn as never);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n let whereConfig: { indexName?: string; condition?: unknown } = {};\n\n const specialBuilder = {\n whereIndex(indexName: string, condition?: unknown) {\n whereConfig = { indexName, condition };\n return this;\n },\n };\n\n builderFn(specialBuilder as never);\n\n if (!whereConfig.indexName) {\n throw new Error(\"whereIndex() must be called in deleteMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName as string, (b) => {\n if (whereConfig.condition) {\n return b.whereIndex(whereConfig.indexName as never, whereConfig.condition as never);\n }\n return b.whereIndex(whereConfig.indexName as never);\n });\n const findResults2 = await findUow.executeRetrieve();\n const records = (findResults2 as unknown as [unknown])[0];\n\n // @ts-expect-error - Type narrowing doesn't work through unknown cast\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as never as Array<{ id: unknown }>) {\n deleteUow.delete(tableName as string, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name, nestedUowConfig) {\n return createUOW({\n name,\n config: {\n ...uowConfig,\n ...nestedUowConfig,\n },\n });\n },\n } as AbstractQuery<T, DrizzleUOWConfig>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"drizzle-query.js","names":["#indexName","#condition","#setValues","executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult>"],"sources":["../../../src/adapters/drizzle/drizzle-query.ts"],"sourcesContent":["import type { AbstractQuery } from \"../../query/query\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport type { CompiledMutation, UOWExecutor, ValidIndexName } from \"../../query/unit-of-work\";\nimport { createDrizzleUOWCompiler, type DrizzleCompiledQuery } from \"./drizzle-uow-compiler\";\nimport { executeDrizzleRetrievalPhase, executeDrizzleMutationPhase } from \"./drizzle-uow-executor\";\nimport { UnitOfWork } from \"../../query/unit-of-work\";\nimport { parseDrizzle, type DrizzleResult, type TableNameMapper, type DBType } from \"./shared\";\nimport { createDrizzleUOWDecoder } from \"./drizzle-uow-decoder\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport type { TableToUpdateValues } from \"../../query/query\";\n\n/**\n * Configuration options for creating a Drizzle Unit of Work\n */\nexport interface DrizzleUOWConfig {\n /**\n * Optional callback to receive compiled SQL queries for logging/debugging\n * This callback is invoked for each query as it's compiled\n */\n onQuery?: (query: DrizzleCompiledQuery) => void;\n /**\n * If true, the query will not be executed and the query will be returned. Not respected for UOWs\n * since those have to be manually executed.\n */\n dryRun?: boolean;\n}\n\n/**\n * Special builder for updateMany operations that captures configuration\n */\nclass UpdateManySpecialBuilder<TTable extends AnyTable> {\n #indexName?: string;\n #condition?: unknown;\n #setValues?: TableToUpdateValues<TTable>;\n\n whereIndex<TIndexName extends ValidIndexName<TTable>>(\n indexName: TIndexName,\n condition?: unknown,\n ): this {\n this.#indexName = indexName as string;\n this.#condition = condition;\n return this;\n }\n\n set(values: TableToUpdateValues<TTable>): this {\n this.#setValues = values;\n return this;\n }\n\n getConfig() {\n return {\n indexName: this.#indexName,\n condition: this.#condition,\n setValues: this.#setValues,\n };\n }\n}\n\n/**\n * Creates a Drizzle-based query engine for the given schema.\n *\n * This is the main entry point for creating a database query interface using Drizzle.\n * It uses a compiler-based architecture where queries are compiled to SQL and then executed,\n * enabling features like SQL snapshot testing.\n *\n * @param schema - The database schema definition\n * @param pool - Connection pool for acquiring database connections\n * @param provider - SQL provider (sqlite, mysql, postgresql)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns An AbstractQuery instance for performing database operations\n *\n * @example\n * ```ts\n * const pool = createSimpleConnectionPool(drizzle);\n * const queryEngine = fromDrizzle(mySchema, pool, 'postgresql');\n *\n * const uow = queryEngine.createUnitOfWork('myOperation');\n * ```\n */\nexport function fromDrizzle<T extends AnySchema>(\n schema: T,\n pool: ConnectionPool<DBType>,\n provider: \"sqlite\" | \"mysql\" | \"postgresql\",\n mapper?: TableNameMapper,\n uowConfig?: DrizzleUOWConfig,\n): AbstractQuery<T, DrizzleUOWConfig> {\n function createUOW(opts: { name?: string; config?: DrizzleUOWConfig }) {\n const uowCompiler = createDrizzleUOWCompiler(schema, pool, provider, mapper);\n\n const executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult> = {\n async executeRetrievalPhase(retrievalBatch: DrizzleCompiledQuery[]) {\n // In dryRun mode, skip execution and return empty results\n if (opts.config?.dryRun) {\n return retrievalBatch.map(() => ({\n rows: [],\n affectedRows: 0,\n }));\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleRetrievalPhase(db, retrievalBatch, provider);\n } finally {\n await conn.release();\n }\n },\n async executeMutationPhase(mutationBatch: CompiledMutation<DrizzleCompiledQuery>[]) {\n // In dryRun mode, skip execution and return success with mock internal IDs\n if (opts.config?.dryRun) {\n return {\n success: true,\n createdInternalIds: mutationBatch.map(() => null),\n };\n }\n\n const conn = await pool.connect();\n try {\n const db = parseDrizzle(conn.db)[0];\n return await executeDrizzleMutationPhase(db, mutationBatch, provider);\n } finally {\n await conn.release();\n }\n },\n };\n\n const decoder = createDrizzleUOWDecoder(schema, provider);\n\n const { onQuery, ...restUowConfig } = opts.config ?? {};\n\n return new UnitOfWork(schema, uowCompiler, executor, decoder, opts.name, {\n ...restUowConfig,\n onQuery: (query) => {\n // Handle both CompiledQuery and CompiledMutation structures\n // Retrieval operations return DrizzleCompiledQuery directly: { sql, params }\n // Mutation operations return CompiledMutation: { query: DrizzleCompiledQuery, expectedAffectedRows }\n const actualQuery =\n query && typeof query === \"object\" && \"query\" in query\n ? (query as CompiledMutation<DrizzleCompiledQuery>).query\n : (query as DrizzleCompiledQuery);\n\n opts.config?.onQuery?.(actualQuery);\n },\n });\n }\n\n return {\n async find(tableName, builderFn) {\n // Safe: builderFn returns a FindBuilder (or void), which matches UnitOfWork signature\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const uow = createUOW({ config: uowConfig }).find(tableName, builderFn as any);\n const [result] = await uow.executeRetrieve();\n return result;\n },\n\n async findFirst(tableName, builderFn) {\n const uow = createUOW({ config: uowConfig });\n if (builderFn) {\n uow.find(tableName, (b) => {\n builderFn(b);\n return b.pageSize(1);\n });\n } else {\n uow.find(tableName, (b) => b.whereIndex(\"primary\").pageSize(1));\n }\n // executeRetrieve runs an array of `find` operation results, which each return an array of rows\n const [result]: unknown[][] = await uow.executeRetrieve();\n return result?.[0] ?? null;\n },\n\n async create(tableName, values) {\n const uow = createUOW({ config: uowConfig });\n uow.create(tableName, values);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create record\");\n }\n\n const createdIds = uow.getCreatedIds();\n const createdId = createdIds[0];\n if (!createdId) {\n throw new Error(\"Failed to get created ID\");\n }\n return createdId;\n },\n\n async createMany(tableName, valuesArray) {\n const uow = createUOW({ config: uowConfig });\n for (const values of valuesArray) {\n uow.create(tableName, values);\n }\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to create records\");\n }\n\n return uow.getCreatedIds();\n },\n\n async update(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.update(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update record (version conflict or record not found)\");\n }\n },\n\n async updateMany(tableName, builderFn) {\n const table = schema.tables[tableName];\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n const specialBuilder = new UpdateManySpecialBuilder<typeof table>();\n builderFn(specialBuilder);\n\n const { indexName, condition, setValues } = specialBuilder.getConfig();\n\n if (!indexName) {\n throw new Error(\"whereIndex() must be called in updateMany\");\n }\n if (!setValues) {\n throw new Error(\"set() must be called in updateMany\");\n }\n\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, (b) => {\n if (condition) {\n // Safe: condition is captured from whereIndex call with proper typing\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return b.whereIndex(indexName as ValidIndexName<typeof table>, condition as any);\n }\n return b.whereIndex(indexName as ValidIndexName<typeof table>);\n });\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const updateUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n updateUow.update(tableName, record.id as string, (b) => b.set(setValues));\n }\n const { success } = await updateUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to update records (version conflict)\");\n }\n },\n\n async delete(tableName, id, builderFn) {\n const uow = createUOW({ config: uowConfig });\n uow.delete(tableName, id, builderFn);\n const { success } = await uow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete record (version conflict or record not found)\");\n }\n },\n\n async deleteMany(tableName, builderFn) {\n const findUow = createUOW({ config: uowConfig });\n findUow.find(tableName, builderFn);\n const [records]: unknown[][] = await findUow.executeRetrieve();\n\n if (!records || records.length === 0) {\n return;\n }\n\n const deleteUow = createUOW({ config: uowConfig });\n for (const record of records as Array<{ id: unknown }>) {\n deleteUow.delete(tableName, record.id as string);\n }\n const { success } = await deleteUow.executeMutations();\n if (!success) {\n throw new Error(\"Failed to delete records (version conflict)\");\n }\n },\n\n createUnitOfWork(name, nestedUowConfig) {\n return createUOW({\n name,\n config: {\n ...uowConfig,\n ...nestedUowConfig,\n },\n });\n },\n } as AbstractQuery<T, DrizzleUOWConfig>;\n}\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { Migrator } from "../../migration-engine/create.js";
3
3
  import { AbstractQuery } from "../../query/query.js";
4
4
  import { DatabaseAdapter, fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "../adapters.js";
5
5
  import { SQLProvider } from "../../shared/providers.js";
6
+ import { KyselyUOWConfig } from "./kysely-query.js";
6
7
  import { Kysely } from "kysely";
7
8
 
8
9
  //#region src/adapters/kysely/kysely-adapter.d.ts
@@ -11,13 +12,13 @@ interface KyselyConfig {
11
12
  db: KyselyAny | (() => KyselyAny | Promise<KyselyAny>);
12
13
  provider: SQLProvider;
13
14
  }
14
- declare class KyselyAdapter implements DatabaseAdapter {
15
+ declare class KyselyAdapter implements DatabaseAdapter<KyselyUOWConfig> {
15
16
  #private;
16
17
  constructor(config: KyselyConfig);
17
18
  get [fragnoDatabaseAdapterNameFakeSymbol](): string;
18
19
  get [fragnoDatabaseAdapterVersionFakeSymbol](): number;
19
20
  close(): Promise<void>;
20
- createQueryEngine<T extends AnySchema>(schema: T, namespace: string): AbstractQuery<T>;
21
+ createQueryEngine<T extends AnySchema>(schema: T, namespace: string): AbstractQuery<T, KyselyUOWConfig>;
21
22
  isConnectionHealthy(): Promise<boolean>;
22
23
  createMigrationEngine(schema: AnySchema, namespace: string): Migrator;
23
24
  getSchemaVersion(namespace: string): Promise<string | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-adapter.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAoBK,SAAA,GAAY;UAEA,YAAA;EAFZ,EAAA,EAGC,SAHQ,GAAA,CAAA,GAAA,GAGW,SAHF,GAGc,OAHd,CAGsB,SAHtB,CAAA,CAAA;EAEN,QAAA,EAEL,WAFiB;;AACJ,cAIZ,aAAA,YAAyB,eAJb,CAAA;EAAoB,CAAA,OAAA;EAAR,WAAA,CAAA,MAAA,EAQf,YARe;EACzB,KAYL,mCAAA,GAZK,EAAA,MAAA;EAAW,KAgBhB,sCAAA,GAhBgB,EAAA,MAAA;EAGV,KAAA,CAAA,CAAA,EAiBI,OAjBU,CAAA,IAAA,CAAA;EAIL,iBAAA,CAAA,UAiBQ,SAjBR,CAAA,CAAA,MAAA,EAiB2B,CAjB3B,EAAA,SAAA,EAAA,MAAA,CAAA,EAiBkD,aAjBlD,CAiBgE,CAjBhE,CAAA;EAKf,mBAAA,CAAA,CAAA,EAkBwB,OAlBxB,CAAA,OAAA,CAAA;EAIA,qBAAA,CAAA,MAAA,EA0ByB,SA1BzB,EAAA,SAAA,EAAA,MAAA,CAAA,EA0BwD,QA1BxD;EAIU,gBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAgJ4B,OAhJ5B,CAAA,MAAA,GAAA,SAAA,CAAA"}
1
+ {"version":3,"file":"kysely-adapter.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;;;;KAoBK,SAAA,GAAY;UAEA,YAAA;EAFZ,EAAA,EAGC,SAHQ,GAAA,CAAA,GAAA,GAGW,SAHF,GAGc,OAHd,CAGsB,SAHtB,CAAA,CAAA;EAEN,QAAA,EAEL,WAFiB;;AACJ,cAIZ,aAAA,YAAyB,eAJb,CAI6B,eAJ7B,CAAA,CAAA;EAAoB,CAAA,OAAA;EAAR,WAAA,CAAA,MAAA,EAQf,YARe;EACzB,KAYL,mCAAA,GAZK,EAAA,MAAA;EAAW,KAgBhB,sCAAA,GAhBgB,EAAA,MAAA;EAGV,KAAA,CAAA,CAAA,EAiBI,OAjBU,CAAA,IAAA,CAAA;EAA2B,iBAAA,CAAA,UAqBxB,SArBwB,CAAA,CAAA,MAAA,EAsB1C,CAtB0C,EAAA,SAAA,EAAA,MAAA,CAAA,EAwBjD,aAxBiD,CAwBnC,CAxBmC,EAwBhC,eAxBgC,CAAA;EAIhC,mBAAA,CAAA,CAAA,EA0BS,OA1BT,CAAA,OAAA,CAAA;EAKf,qBAAA,CAAA,MAAA,EAiCyB,SAjCzB,EAAA,SAAA,EAAA,MAAA,CAAA,EAiCwD,QAjCxD;EAIA,gBAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAuJsC,OAvJtC,CAAA,MAAA,GAAA,SAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-adapter.js","names":["#connectionPool","#provider","db","config: KyselyConfig","parts: string[]"],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n type DatabaseAdapter,\n} 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, preprocessOperations } 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\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport { createKyselyConnectionPool } from \"./kysely-connection-pool\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\nexport interface KyselyConfig {\n db: KyselyAny | (() => KyselyAny | Promise<KyselyAny>);\n provider: SQLProvider;\n}\n\nexport class KyselyAdapter implements DatabaseAdapter {\n #connectionPool: ConnectionPool<KyselyAny>;\n #provider: SQLProvider;\n\n constructor(config: KyselyConfig) {\n this.#connectionPool = createKyselyConnectionPool(config.db);\n this.#provider = config.provider;\n }\n\n get [fragnoDatabaseAdapterNameFakeSymbol](): string {\n return \"kysely\";\n }\n\n get [fragnoDatabaseAdapterVersionFakeSymbol](): number {\n return 0;\n }\n\n async close(): Promise<void> {\n await this.#connectionPool.close();\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.#connectionPool, this.#provider, mapper);\n }\n\n async isConnectionHealthy(): Promise<boolean> {\n const conn = await this.#connectionPool.connect();\n try {\n const result = await conn.db.executeQuery(sql`SELECT 1 as healthy`.compile(conn.db));\n return (result.rows[0] as Record<string, unknown>)[\"healthy\"] === 1;\n } catch {\n return false;\n } finally {\n await conn.release();\n }\n }\n\n createMigrationEngine(schema: AnySchema, namespace: string): Migrator {\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n\n const preprocessMigrationOperations = (operations: MigrationOperation[], db: KyselyAny) => {\n // Preprocess operations using the provided db instance\n const config: KyselyConfig = {\n db,\n provider: this.#provider,\n };\n let preprocessed = preprocessOperations(operations, config);\n\n if (this.#provider === \"mysql\") {\n preprocessed.unshift({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 0\" });\n preprocessed.push({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 1\" });\n }\n\n return preprocessed;\n };\n\n // Convert operations to executable nodes bound to specific db instance\n const toExecutableNodes = (operations: MigrationOperation[], db: KyselyAny) => {\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 config: KyselyConfig = { db, provider: this.#provider };\n return operations.flatMap((op) =>\n execute(op, config, (node) => onCustomNode(node, db), mapper),\n );\n };\n\n const migrator = createMigrator({\n schema,\n executor: async (operations) => {\n const conn = await this.#connectionPool.connect();\n try {\n // For SQLite, execute PRAGMA defer_foreign_keys BEFORE transaction\n if (this.#provider === \"sqlite\") {\n await sql.raw(\"PRAGMA defer_foreign_keys = ON\").execute(conn.db);\n }\n\n await conn.db.transaction().execute(async (tx) => {\n // Use the transaction instance for both preprocessing and execution\n const preprocessed = preprocessMigrationOperations(operations, tx);\n const nodes = toExecutableNodes(preprocessed, tx);\n for (const node of nodes) {\n try {\n await node.execute();\n } catch (e) {\n console.error(\"failed at\", node.compile(), e);\n throw e;\n }\n }\n });\n } finally {\n await conn.release();\n }\n },\n sql: {\n toSql: (operations) => {\n const parts: string[] = [];\n\n // Add SQLite PRAGMA at the beginning\n if (this.#provider === \"sqlite\") {\n parts.push(\"PRAGMA defer_foreign_keys = ON;\");\n }\n\n // Use getDatabaseSync for SQL generation (doesn't execute, just builds SQL strings)\n const db = this.#connectionPool.getDatabaseSync();\n const preprocessed = preprocessMigrationOperations(operations, db);\n const nodes = toExecutableNodes(preprocessed, db);\n const compiled = nodes.map((node) => `${node.compile().sql};`);\n\n parts.push(...compiled);\n\n return parts.join(\"\\n\\n\");\n },\n },\n\n settings: {\n getVersion: async () => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n const v = await manager.get(`schema_version`);\n return v ? parseInt(v) : 0;\n } finally {\n await conn.release();\n }\n },\n updateSettingsInMigration: async (fromVersion, toVersion) => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\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 } finally {\n await conn.release();\n }\n },\n },\n });\n\n return migrator;\n }\n\n async getSchemaVersion(namespace: string): Promise<string | undefined> {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n return await manager.get(`schema_version`);\n } finally {\n await conn.release();\n }\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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"}
1
+ {"version":3,"file":"kysely-adapter.js","names":["#connectionPool","#provider","db","config: KyselyConfig","parts: string[]"],"sources":["../../../src/adapters/kysely/kysely-adapter.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport type { SQLProvider } from \"../../shared/providers\";\nimport {\n fragnoDatabaseAdapterNameFakeSymbol,\n fragnoDatabaseAdapterVersionFakeSymbol,\n type DatabaseAdapter,\n} 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, preprocessOperations } from \"./migration/execute\";\nimport type { AbstractQuery } from \"../../query/query\";\nimport { fromKysely, type KyselyUOWConfig } from \"./kysely-query\";\nimport { createTableNameMapper } from \"./kysely-shared\";\nimport { createHash } from \"node:crypto\";\nimport { SETTINGS_TABLE_NAME } from \"../../shared/settings-schema\";\nimport type { ConnectionPool } from \"../../shared/connection-pool\";\nimport { createKyselyConnectionPool } from \"./kysely-connection-pool\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype KyselyAny = Kysely<any>;\n\nexport interface KyselyConfig {\n db: KyselyAny | (() => KyselyAny | Promise<KyselyAny>);\n provider: SQLProvider;\n}\n\nexport class KyselyAdapter implements DatabaseAdapter<KyselyUOWConfig> {\n #connectionPool: ConnectionPool<KyselyAny>;\n #provider: SQLProvider;\n\n constructor(config: KyselyConfig) {\n this.#connectionPool = createKyselyConnectionPool(config.db);\n this.#provider = config.provider;\n }\n\n get [fragnoDatabaseAdapterNameFakeSymbol](): string {\n return \"kysely\";\n }\n\n get [fragnoDatabaseAdapterVersionFakeSymbol](): number {\n return 0;\n }\n\n async close(): Promise<void> {\n await this.#connectionPool.close();\n }\n\n createQueryEngine<T extends AnySchema>(\n schema: T,\n namespace: string,\n ): AbstractQuery<T, KyselyUOWConfig> {\n // Only create mapper if namespace is non-empty\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n return fromKysely(schema, this.#connectionPool, this.#provider, mapper);\n }\n\n async isConnectionHealthy(): Promise<boolean> {\n const conn = await this.#connectionPool.connect();\n try {\n const result = await conn.db.executeQuery(sql`SELECT 1 as healthy`.compile(conn.db));\n return (result.rows[0] as Record<string, unknown>)[\"healthy\"] === 1;\n } catch {\n return false;\n } finally {\n await conn.release();\n }\n }\n\n createMigrationEngine(schema: AnySchema, namespace: string): Migrator {\n const mapper = namespace ? createTableNameMapper(namespace) : undefined;\n\n const preprocessMigrationOperations = (operations: MigrationOperation[], db: KyselyAny) => {\n // Preprocess operations using the provided db instance\n const config: KyselyConfig = {\n db,\n provider: this.#provider,\n };\n let preprocessed = preprocessOperations(operations, config);\n\n if (this.#provider === \"mysql\") {\n preprocessed.unshift({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 0\" });\n preprocessed.push({ type: \"custom\", sql: \"SET FOREIGN_KEY_CHECKS = 1\" });\n }\n\n return preprocessed;\n };\n\n // Convert operations to executable nodes bound to specific db instance\n const toExecutableNodes = (operations: MigrationOperation[], db: KyselyAny) => {\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 config: KyselyConfig = { db, provider: this.#provider };\n return operations.flatMap((op) =>\n execute(op, config, (node) => onCustomNode(node, db), mapper),\n );\n };\n\n const migrator = createMigrator({\n schema,\n executor: async (operations) => {\n const conn = await this.#connectionPool.connect();\n try {\n // For SQLite, execute PRAGMA defer_foreign_keys BEFORE transaction\n if (this.#provider === \"sqlite\") {\n await sql.raw(\"PRAGMA defer_foreign_keys = ON\").execute(conn.db);\n }\n\n await conn.db.transaction().execute(async (tx) => {\n // Use the transaction instance for both preprocessing and execution\n const preprocessed = preprocessMigrationOperations(operations, tx);\n const nodes = toExecutableNodes(preprocessed, tx);\n for (const node of nodes) {\n try {\n await node.execute();\n } catch (e) {\n console.error(\"failed at\", node.compile(), e);\n throw e;\n }\n }\n });\n } finally {\n await conn.release();\n }\n },\n sql: {\n toSql: (operations) => {\n const parts: string[] = [];\n\n // Add SQLite PRAGMA at the beginning\n if (this.#provider === \"sqlite\") {\n parts.push(\"PRAGMA defer_foreign_keys = ON;\");\n }\n\n // Use getDatabaseSync for SQL generation (doesn't execute, just builds SQL strings)\n const db = this.#connectionPool.getDatabaseSync();\n const preprocessed = preprocessMigrationOperations(operations, db);\n const nodes = toExecutableNodes(preprocessed, db);\n const compiled = nodes.map((node) => `${node.compile().sql};`);\n\n parts.push(...compiled);\n\n return parts.join(\"\\n\\n\");\n },\n },\n\n settings: {\n getVersion: async () => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n const v = await manager.get(`schema_version`);\n return v ? parseInt(v) : 0;\n } finally {\n await conn.release();\n }\n },\n updateSettingsInMigration: async (fromVersion, toVersion) => {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\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 } finally {\n await conn.release();\n }\n },\n },\n });\n\n return migrator;\n }\n\n async getSchemaVersion(namespace: string): Promise<string | undefined> {\n const conn = await this.#connectionPool.connect();\n try {\n const manager = createSettingsManager(conn.db, namespace);\n return await manager.get(`schema_version`);\n } finally {\n await conn.release();\n }\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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"}
@@ -0,0 +1,22 @@
1
+ import { CompiledQuery, Kysely } from "kysely";
2
+
3
+ //#region src/adapters/kysely/kysely-query.d.ts
4
+
5
+ /**
6
+ * Configuration options for creating a Kysely Unit of Work
7
+ */
8
+ interface KyselyUOWConfig {
9
+ /**
10
+ * Optional callback to receive compiled SQL queries for logging/debugging
11
+ * This callback is invoked for each query as it's compiled
12
+ */
13
+ onQuery?: (query: CompiledQuery) => void;
14
+ /**
15
+ * If true, the query will not be executed and the query will be returned. Not respected for UOWs
16
+ * since those have to be manually executed.
17
+ */
18
+ dryRun?: boolean;
19
+ }
20
+ //#endregion
21
+ export { KyselyUOWConfig };
22
+ //# sourceMappingURL=kysely-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kysely-query.d.ts","names":[],"sources":["../../../src/adapters/kysely/kysely-query.ts"],"sourcesContent":[],"mappings":";;;;;;;UAuBiB,eAAA;;;;;oBAKG"}