@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.
Files changed (200) hide show
  1. package/.turbo/turbo-build.log +137 -13
  2. package/.turbo/turbo-test.log +36 -0
  3. package/CHANGELOG.md +7 -0
  4. package/dist/adapters/adapters.d.ts +18 -0
  5. package/dist/adapters/adapters.d.ts.map +1 -0
  6. package/dist/adapters/drizzle/drizzle-adapter.d.ts +21 -0
  7. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -0
  8. package/dist/adapters/drizzle/drizzle-adapter.js +62 -0
  9. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -0
  10. package/dist/adapters/drizzle/drizzle-query.d.ts +17 -0
  11. package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -0
  12. package/dist/adapters/drizzle/drizzle-query.js +139 -0
  13. package/dist/adapters/drizzle/drizzle-query.js.map +1 -0
  14. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +9 -0
  15. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -0
  16. package/dist/adapters/drizzle/drizzle-uow-compiler.js +300 -0
  17. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -0
  18. package/dist/adapters/drizzle/drizzle-uow-decoder.js +82 -0
  19. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -0
  20. package/dist/adapters/drizzle/drizzle-uow-executor.js +125 -0
  21. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -0
  22. package/dist/adapters/drizzle/generate.js +273 -0
  23. package/dist/adapters/drizzle/generate.js.map +1 -0
  24. package/dist/adapters/drizzle/join-column-utils.js +28 -0
  25. package/dist/adapters/drizzle/join-column-utils.js.map +1 -0
  26. package/dist/adapters/drizzle/shared.js +11 -0
  27. package/dist/adapters/drizzle/shared.js.map +1 -0
  28. package/dist/adapters/kysely/kysely-adapter.d.ts +23 -0
  29. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -0
  30. package/dist/adapters/kysely/kysely-adapter.js +119 -0
  31. package/dist/adapters/kysely/kysely-adapter.js.map +1 -0
  32. package/dist/adapters/kysely/kysely-query-builder.js +306 -0
  33. package/dist/adapters/kysely/kysely-query-builder.js.map +1 -0
  34. package/dist/adapters/kysely/kysely-query-compiler.js +67 -0
  35. package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -0
  36. package/dist/adapters/kysely/kysely-query.js +158 -0
  37. package/dist/adapters/kysely/kysely-query.js.map +1 -0
  38. package/dist/adapters/kysely/kysely-uow-compiler.js +139 -0
  39. package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -0
  40. package/dist/adapters/kysely/kysely-uow-executor.js +89 -0
  41. package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -0
  42. package/dist/adapters/kysely/migration/execute.js +176 -0
  43. package/dist/adapters/kysely/migration/execute.js.map +1 -0
  44. package/dist/fragment.d.ts +54 -0
  45. package/dist/fragment.d.ts.map +1 -0
  46. package/dist/fragment.js +92 -0
  47. package/dist/fragment.js.map +1 -0
  48. package/dist/id.d.ts +2 -0
  49. package/dist/migration-engine/auto-from-schema.js +116 -0
  50. package/dist/migration-engine/auto-from-schema.js.map +1 -0
  51. package/dist/migration-engine/create.d.ts +41 -0
  52. package/dist/migration-engine/create.d.ts.map +1 -0
  53. package/dist/migration-engine/create.js +58 -0
  54. package/dist/migration-engine/create.js.map +1 -0
  55. package/dist/migration-engine/shared.d.ts +90 -0
  56. package/dist/migration-engine/shared.d.ts.map +1 -0
  57. package/dist/migration-engine/shared.js +8 -0
  58. package/dist/migration-engine/shared.js.map +1 -0
  59. package/dist/mod.d.ts +55 -2
  60. package/dist/mod.d.ts.map +1 -1
  61. package/dist/mod.js +111 -2
  62. package/dist/mod.js.map +1 -1
  63. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js +108 -0
  64. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js.map +1 -0
  65. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js +55 -0
  66. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js.map +1 -0
  67. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js +18 -0
  68. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js.map +1 -0
  69. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js +183 -0
  70. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js.map +1 -0
  71. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js +58 -0
  72. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js.map +1 -0
  73. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js +68 -0
  74. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js.map +1 -0
  75. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js +56 -0
  76. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js.map +1 -0
  77. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js +65 -0
  78. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js.map +1 -0
  79. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js +81 -0
  80. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js.map +1 -0
  81. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js +13 -0
  82. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js.map +1 -0
  83. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js +10 -0
  84. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js.map +1 -0
  85. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js +372 -0
  86. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js.map +1 -0
  87. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js +23 -0
  88. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js.map +1 -0
  89. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js +62 -0
  90. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js.map +1 -0
  91. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js +6 -0
  92. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js.map +1 -0
  93. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js +8 -0
  94. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js.map +1 -0
  95. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js +8 -0
  96. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js.map +1 -0
  97. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js +6 -0
  98. package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js.map +1 -0
  99. package/dist/query/condition-builder.d.ts +41 -0
  100. package/dist/query/condition-builder.d.ts.map +1 -0
  101. package/dist/query/condition-builder.js +93 -0
  102. package/dist/query/condition-builder.js.map +1 -0
  103. package/dist/query/cursor.d.ts +88 -0
  104. package/dist/query/cursor.d.ts.map +1 -0
  105. package/dist/query/cursor.js +103 -0
  106. package/dist/query/cursor.js.map +1 -0
  107. package/dist/query/orm/orm.d.ts +18 -0
  108. package/dist/query/orm/orm.d.ts.map +1 -0
  109. package/dist/query/orm/orm.js +48 -0
  110. package/dist/query/orm/orm.js.map +1 -0
  111. package/dist/query/query.d.ts +79 -0
  112. package/dist/query/query.d.ts.map +1 -0
  113. package/dist/query/query.js +1 -0
  114. package/dist/query/result-transform.js +155 -0
  115. package/dist/query/result-transform.js.map +1 -0
  116. package/dist/query/unit-of-work.d.ts +435 -0
  117. package/dist/query/unit-of-work.d.ts.map +1 -0
  118. package/dist/query/unit-of-work.js +549 -0
  119. package/dist/query/unit-of-work.js.map +1 -0
  120. package/dist/schema/create.d.ts +273 -116
  121. package/dist/schema/create.d.ts.map +1 -1
  122. package/dist/schema/create.js +410 -222
  123. package/dist/schema/create.js.map +1 -1
  124. package/dist/schema/serialize.js +101 -0
  125. package/dist/schema/serialize.js.map +1 -0
  126. package/dist/schema-generator/schema-generator.d.ts +15 -0
  127. package/dist/schema-generator/schema-generator.d.ts.map +1 -0
  128. package/dist/shared/providers.d.ts +6 -0
  129. package/dist/shared/providers.d.ts.map +1 -0
  130. package/dist/util/import-generator.js +26 -0
  131. package/dist/util/import-generator.js.map +1 -0
  132. package/dist/util/parse.js +15 -0
  133. package/dist/util/parse.js.map +1 -0
  134. package/dist/util/types.d.ts +8 -0
  135. package/dist/util/types.d.ts.map +1 -0
  136. package/package.json +63 -2
  137. package/src/adapters/adapters.ts +22 -0
  138. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +433 -0
  139. package/src/adapters/drizzle/drizzle-adapter.test.ts +122 -0
  140. package/src/adapters/drizzle/drizzle-adapter.ts +118 -0
  141. package/src/adapters/drizzle/drizzle-query.ts +234 -0
  142. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +1084 -0
  143. package/src/adapters/drizzle/drizzle-uow-compiler.ts +546 -0
  144. package/src/adapters/drizzle/drizzle-uow-decoder.ts +165 -0
  145. package/src/adapters/drizzle/drizzle-uow-executor.ts +213 -0
  146. package/src/adapters/drizzle/generate.test.ts +643 -0
  147. package/src/adapters/drizzle/generate.ts +481 -0
  148. package/src/adapters/drizzle/join-column-utils.test.ts +79 -0
  149. package/src/adapters/drizzle/join-column-utils.ts +39 -0
  150. package/src/adapters/drizzle/migrate-drizzle.test.ts +226 -0
  151. package/src/adapters/drizzle/shared.ts +22 -0
  152. package/src/adapters/drizzle/test-utils.ts +56 -0
  153. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +789 -0
  154. package/src/adapters/kysely/kysely-adapter.ts +196 -0
  155. package/src/adapters/kysely/kysely-query-builder.test.ts +1344 -0
  156. package/src/adapters/kysely/kysely-query-builder.ts +611 -0
  157. package/src/adapters/kysely/kysely-query-compiler.ts +124 -0
  158. package/src/adapters/kysely/kysely-query.ts +254 -0
  159. package/src/adapters/kysely/kysely-uow-compiler.test.ts +916 -0
  160. package/src/adapters/kysely/kysely-uow-compiler.ts +271 -0
  161. package/src/adapters/kysely/kysely-uow-executor.ts +149 -0
  162. package/src/adapters/kysely/kysely-uow-joins.test.ts +811 -0
  163. package/src/adapters/kysely/migration/execute-mysql.test.ts +1173 -0
  164. package/src/adapters/kysely/migration/execute-postgres.test.ts +2657 -0
  165. package/src/adapters/kysely/migration/execute.ts +382 -0
  166. package/src/adapters/kysely/migration/kysely-migrator.test.ts +197 -0
  167. package/src/fragment.test.ts +287 -0
  168. package/src/fragment.ts +198 -0
  169. package/src/migration-engine/auto-from-schema.test.ts +118 -58
  170. package/src/migration-engine/auto-from-schema.ts +103 -32
  171. package/src/migration-engine/create.test.ts +34 -46
  172. package/src/migration-engine/create.ts +41 -26
  173. package/src/migration-engine/shared.ts +26 -6
  174. package/src/mod.ts +197 -1
  175. package/src/query/condition-builder.test.ts +379 -0
  176. package/src/query/condition-builder.ts +294 -0
  177. package/src/query/cursor.test.ts +296 -0
  178. package/src/query/cursor.ts +147 -0
  179. package/src/query/orm/orm.ts +92 -0
  180. package/src/query/query-type.test.ts +429 -0
  181. package/src/query/query.ts +200 -0
  182. package/src/query/result-transform.test.ts +795 -0
  183. package/src/query/result-transform.ts +247 -0
  184. package/src/query/unit-of-work-types.test.ts +192 -0
  185. package/src/query/unit-of-work.test.ts +947 -0
  186. package/src/query/unit-of-work.ts +1199 -0
  187. package/src/schema/create.test.ts +653 -110
  188. package/src/schema/create.ts +708 -337
  189. package/src/schema/serialize.test.ts +559 -0
  190. package/src/schema/serialize.ts +359 -0
  191. package/src/schema-generator/schema-generator.ts +12 -0
  192. package/src/shared/config.ts +0 -8
  193. package/src/util/import-generator.ts +28 -0
  194. package/src/util/parse.ts +16 -0
  195. package/src/util/types.ts +4 -0
  196. package/tsconfig.json +1 -1
  197. package/tsdown.config.ts +11 -1
  198. package/vitest.config.ts +3 -0
  199. /package/dist/{cuid.js → id.js} +0 -0
  200. /package/src/{cuid.ts → id.ts} +0 -0
@@ -23,20 +23,17 @@ describe("createMigrator", () => {
23
23
 
24
24
  const options: MigrationEngineOptions = {
25
25
  schema: testSchema,
26
- userConfig: {
27
- provider: "postgresql",
28
- },
29
26
  executor: async (operations) => {
30
27
  executedOperations.push(operations);
31
28
  },
32
29
  settings: {
33
30
  getVersion: async () => version,
34
- updateSettingsInMigration: async (newVersion) => {
35
- version = newVersion;
31
+ updateSettingsInMigration: async (_fromVersion, toVersion) => {
32
+ version = toVersion;
36
33
  return [
37
34
  {
38
35
  type: "custom",
39
- sql: `UPDATE _settings SET version = ${newVersion}`,
36
+ sql: `UPDATE _settings SET version = ${toVersion}`,
40
37
  },
41
38
  ];
42
39
  },
@@ -52,7 +49,7 @@ describe("createMigrator", () => {
52
49
  it("should migrate from version 0 to latest schema version", async () => {
53
50
  const { migrator, getVersion } = createTestMigrator(0);
54
51
 
55
- const result = await migrator.migrate();
52
+ const result = await migrator.prepareMigration();
56
53
 
57
54
  expect(result.operations.length).toBeGreaterThan(0);
58
55
  expect(getVersion()).toBe(testSchema.version);
@@ -61,7 +58,7 @@ describe("createMigrator", () => {
61
58
  it("should migrate from intermediate version to latest", async () => {
62
59
  const { migrator, getVersion } = createTestMigrator(1);
63
60
 
64
- const result = await migrator.migrate();
61
+ const result = await migrator.prepareMigration();
65
62
 
66
63
  expect(result.operations.length).toBeGreaterThan(0);
67
64
  expect(getVersion()).toBe(testSchema.version);
@@ -70,7 +67,7 @@ describe("createMigrator", () => {
70
67
  it("should return empty operations when already at latest version", async () => {
71
68
  const { migrator, getVersion } = createTestMigrator(testSchema.version);
72
69
 
73
- const result = await migrator.migrate();
70
+ const result = await migrator.prepareMigration();
74
71
 
75
72
  expect(result.operations).toEqual([]);
76
73
  expect(getVersion()).toBe(testSchema.version);
@@ -79,7 +76,7 @@ describe("createMigrator", () => {
79
76
  it("should generate correct operations when jumping multiple versions", async () => {
80
77
  const { migrator } = createTestMigrator(0);
81
78
 
82
- const result = await migrator.migrate();
79
+ const result = await migrator.prepareMigration();
83
80
 
84
81
  // Should create all 3 tables plus settings update
85
82
  const createTableOps = result.operations.filter((op) => op.type === "create-table");
@@ -91,7 +88,7 @@ describe("createMigrator", () => {
91
88
  it("should migrate forward from version 0 to version 2", async () => {
92
89
  const { migrator, getVersion } = createTestMigrator(0);
93
90
 
94
- const result = await migrator.migrateTo(2);
91
+ const result = await migrator.prepareMigrationTo(2);
95
92
 
96
93
  expect(result.operations.length).toBeGreaterThan(0);
97
94
  expect(getVersion()).toBe(2);
@@ -100,7 +97,7 @@ describe("createMigrator", () => {
100
97
  it("should migrate forward by jumping multiple versions", async () => {
101
98
  const { migrator, getVersion } = createTestMigrator(0);
102
99
 
103
- const result = await migrator.migrateTo(testSchema.version);
100
+ const result = await migrator.prepareMigrationTo(testSchema.version);
104
101
 
105
102
  expect(getVersion()).toBe(testSchema.version);
106
103
  const createTableOps = result.operations.filter((op) => op.type === "create-table");
@@ -110,20 +107,20 @@ describe("createMigrator", () => {
110
107
  it("should migrate forward one version at a time", async () => {
111
108
  const { migrator, getVersion } = createTestMigrator(0);
112
109
 
113
- await migrator.migrateTo(1);
110
+ await migrator.prepareMigrationTo(1);
114
111
  expect(getVersion()).toBe(1);
115
112
 
116
- await migrator.migrateTo(2);
113
+ await migrator.prepareMigrationTo(2);
117
114
  expect(getVersion()).toBe(2);
118
115
 
119
- await migrator.migrateTo(3);
116
+ await migrator.prepareMigrationTo(3);
120
117
  expect(getVersion()).toBe(3);
121
118
  });
122
119
 
123
120
  it("should return empty operations when already at target version", async () => {
124
121
  const { migrator, getVersion } = createTestMigrator(2);
125
122
 
126
- const result = await migrator.migrateTo(2);
123
+ const result = await migrator.prepareMigrationTo(2);
127
124
 
128
125
  expect(result.operations).toEqual([]);
129
126
  expect(getVersion()).toBe(2);
@@ -132,7 +129,7 @@ describe("createMigrator", () => {
132
129
  it("should throw error when trying to migrate backwards", async () => {
133
130
  const { migrator } = createTestMigrator(3);
134
131
 
135
- await expect(migrator.migrateTo(1)).rejects.toThrow(
132
+ await expect(migrator.prepareMigrationTo(1)).rejects.toThrow(
136
133
  "Cannot migrate backwards: current version is 3, target is 1. Only forward migrations are supported.",
137
134
  );
138
135
  });
@@ -140,7 +137,7 @@ describe("createMigrator", () => {
140
137
  it("should throw error when migrating to negative version", async () => {
141
138
  const { migrator } = createTestMigrator(0);
142
139
 
143
- await expect(migrator.migrateTo(-1)).rejects.toThrow(
140
+ await expect(migrator.prepareMigrationTo(-1)).rejects.toThrow(
144
141
  "Cannot migrate to negative version: -1",
145
142
  );
146
143
  });
@@ -148,7 +145,7 @@ describe("createMigrator", () => {
148
145
  it("should throw error when migrating beyond schema version", async () => {
149
146
  const { migrator } = createTestMigrator(0);
150
147
 
151
- await expect(migrator.migrateTo(999)).rejects.toThrow(
148
+ await expect(migrator.prepareMigrationTo(999)).rejects.toThrow(
152
149
  `Cannot migrate to version 999: schema only has version ${testSchema.version}`,
153
150
  );
154
151
  });
@@ -166,7 +163,7 @@ describe("createMigrator", () => {
166
163
  it("should return updated version after migration", async () => {
167
164
  const { migrator } = createTestMigrator(0);
168
165
 
169
- await migrator.migrateTo(2);
166
+ await migrator.prepareMigrationTo(2);
170
167
  const version = await migrator.getVersion();
171
168
 
172
169
  expect(version).toBe(2);
@@ -177,7 +174,7 @@ describe("createMigrator", () => {
177
174
  it("should execute migration operations", async () => {
178
175
  const { migrator, executedOperations } = createTestMigrator(0);
179
176
 
180
- const result = await migrator.migrateTo(1);
177
+ const result = await migrator.prepareMigrationTo(1);
181
178
  await result.execute();
182
179
 
183
180
  expect(executedOperations).toHaveLength(1);
@@ -187,7 +184,7 @@ describe("createMigrator", () => {
187
184
  it("should not execute operations until execute() is called", async () => {
188
185
  const { migrator, executedOperations } = createTestMigrator(0);
189
186
 
190
- await migrator.migrateTo(1);
187
+ await migrator.prepareMigrationTo(1);
191
188
 
192
189
  expect(executedOperations).toHaveLength(0);
193
190
  });
@@ -210,16 +207,13 @@ describe("createMigrator", () => {
210
207
 
211
208
  const options: MigrationEngineOptions = {
212
209
  schema: testSchema,
213
- userConfig: {
214
- provider: "postgresql",
215
- },
216
210
  executor: async (operations) => {
217
211
  executedOperations.push(operations);
218
212
  },
219
213
  settings: {
220
214
  getVersion: async () => version,
221
- updateSettingsInMigration: async (newVersion) => {
222
- version = newVersion;
215
+ updateSettingsInMigration: async (_fromVersion, toVersion) => {
216
+ version = toVersion;
223
217
  return [];
224
218
  },
225
219
  },
@@ -231,7 +225,7 @@ describe("createMigrator", () => {
231
225
  };
232
226
 
233
227
  const migrator = createMigrator(options);
234
- const result = await migrator.migrateTo(1);
228
+ const result = await migrator.prepareMigrationTo(1);
235
229
 
236
230
  expect(afterAutoSpy).toHaveBeenCalledOnce();
237
231
  expect(result.operations.some((op) => op.type === "custom")).toBe(true);
@@ -253,16 +247,13 @@ describe("createMigrator", () => {
253
247
 
254
248
  const options: MigrationEngineOptions = {
255
249
  schema: testSchema,
256
- userConfig: {
257
- provider: "postgresql",
258
- },
259
250
  executor: async (operations) => {
260
251
  executedOperations.push(operations);
261
252
  },
262
253
  settings: {
263
254
  getVersion: async () => version,
264
- updateSettingsInMigration: async (newVersion) => {
265
- version = newVersion;
255
+ updateSettingsInMigration: async (_fromVersion, toVersion) => {
256
+ version = toVersion;
266
257
  return [];
267
258
  },
268
259
  },
@@ -274,7 +265,7 @@ describe("createMigrator", () => {
274
265
  };
275
266
 
276
267
  const migrator = createMigrator(options);
277
- const result = await migrator.migrateTo(1);
268
+ const result = await migrator.prepareMigrationTo(1);
278
269
 
279
270
  expect(afterAllSpy).toHaveBeenCalledOnce();
280
271
  expect(result.operations.some((op) => op.type === "custom")).toBe(true);
@@ -285,7 +276,7 @@ describe("createMigrator", () => {
285
276
  it("should update settings by default", async () => {
286
277
  const { migrator } = createTestMigrator(0);
287
278
 
288
- const result = await migrator.migrateTo(1);
279
+ const result = await migrator.prepareMigrationTo(1);
289
280
 
290
281
  const settingsOp = result.operations.find((op) => op.type === "custom");
291
282
  expect(settingsOp).toBeDefined();
@@ -294,7 +285,7 @@ describe("createMigrator", () => {
294
285
  it("should skip settings update when updateSettings is false", async () => {
295
286
  const { migrator } = createTestMigrator(0);
296
287
 
297
- const result = await migrator.migrateTo(1, { updateSettings: false });
288
+ const result = await migrator.prepareMigrationTo(1, { updateSettings: false });
298
289
 
299
290
  // When updateSettings is false, we shouldn't have the settings update operation
300
291
  // Check that we only have create-table operations
@@ -313,31 +304,28 @@ describe("createMigrator", () => {
313
304
  .addTable("posts", (t) => {
314
305
  return t.addColumn("id", idColumn()).addColumn("authorId", referenceColumn());
315
306
  })
316
- .addReference("posts", "author", {
317
- columns: ["authorId"],
318
- targetTable: "users",
319
- targetColumns: ["id"],
307
+ .addReference("author", {
308
+ type: "one",
309
+ from: { table: "posts", column: "authorId" },
310
+ to: { table: "users", column: "id" },
320
311
  });
321
312
  });
322
313
 
323
314
  let version = 0;
324
315
  const options: MigrationEngineOptions = {
325
316
  schema: fkSchema,
326
- userConfig: {
327
- provider: "postgresql",
328
- },
329
317
  executor: async () => {},
330
318
  settings: {
331
319
  getVersion: async () => version,
332
- updateSettingsInMigration: async (newVersion) => {
333
- version = newVersion;
320
+ updateSettingsInMigration: async (_fromVersion, toVersion) => {
321
+ version = toVersion;
334
322
  return [];
335
323
  },
336
324
  },
337
325
  };
338
326
 
339
327
  const migrator = createMigrator(options);
340
- const result = await migrator.migrate();
328
+ const result = await migrator.prepareMigration();
341
329
 
342
330
  const createTableOps = result.operations.filter((op) => op.type === "create-table");
343
331
  const fkOps = result.operations.filter((op) => op.type === "add-foreign-key");
@@ -1,5 +1,4 @@
1
1
  import { type MigrationOperation } from "./shared";
2
- import type { Provider } from "../shared/providers";
3
2
  import type { AnySchema } from "../schema/create";
4
3
  import { generateMigrationFromSchema as defaultGenerateMigrationFromSchema } from "./auto-from-schema";
5
4
 
@@ -19,7 +18,7 @@ export interface MigrateOptions {
19
18
  updateSettings?: boolean;
20
19
  }
21
20
 
22
- export interface MigrationResult {
21
+ export interface PreparedMigration {
23
22
  operations: MigrationOperation[];
24
23
  getSQL?: () => string;
25
24
  execute: () => Promise<void>;
@@ -34,12 +33,22 @@ export interface Migrator {
34
33
  /**
35
34
  * Migrate to the latest schema version
36
35
  */
37
- migrate: (options?: MigrateOptions) => Promise<MigrationResult>;
36
+ prepareMigration: (options?: MigrateOptions) => Promise<PreparedMigration>;
38
37
 
39
38
  /**
40
39
  * Migrate to a specific version (only forward migrations allowed)
40
+ * @param toVersion - Target version to migrate to
41
+ * @param options - Migration options including optional fromVersion
41
42
  */
42
- migrateTo: (version: number, options?: MigrateOptions) => Promise<MigrationResult>;
43
+ prepareMigrationTo: (
44
+ toVersion: number,
45
+ options?: MigrateOptions & { fromVersion?: number },
46
+ ) => Promise<PreparedMigration>;
47
+
48
+ /**
49
+ * Get default file name for migration SQL
50
+ */
51
+ getDefaultFileName?: (namespace: string, fromVersion: number, toVersion: number) => string;
43
52
  }
44
53
 
45
54
  export interface MigrationEngineOptions {
@@ -48,10 +57,6 @@ export interface MigrationEngineOptions {
48
57
  */
49
58
  schema: AnySchema;
50
59
 
51
- userConfig: {
52
- provider: Provider;
53
- };
54
-
55
60
  executor: (operations: MigrationOperation[]) => Promise<void>;
56
61
 
57
62
  generateMigrationFromSchema?: typeof defaultGenerateMigrationFromSchema;
@@ -62,7 +67,10 @@ export interface MigrationEngineOptions {
62
67
  */
63
68
  getVersion: () => Promise<number>;
64
69
 
65
- updateSettingsInMigration: (version: number) => Awaitable<MigrationOperation[]>;
70
+ updateSettingsInMigration: (
71
+ fromVersion: number,
72
+ toVersion: number,
73
+ ) => Awaitable<MigrationOperation[]>;
66
74
  };
67
75
 
68
76
  sql?: {
@@ -103,7 +111,6 @@ export function createMigrator({
103
111
  settings,
104
112
  generateMigrationFromSchema = defaultGenerateMigrationFromSchema,
105
113
  schema: targetSchema,
106
- userConfig,
107
114
  executor,
108
115
  sql: sqlConfig,
109
116
  transformers = [],
@@ -112,17 +119,23 @@ export function createMigrator({
112
119
  getVersion() {
113
120
  return settings.getVersion();
114
121
  },
115
- async migrate(options = {}) {
116
- return this.migrateTo(targetSchema.version, options);
122
+ async prepareMigration(options = {}) {
123
+ return this.prepareMigrationTo(targetSchema.version, options);
117
124
  },
118
- async migrateTo(toVersion, options = {}) {
119
- const { updateSettings: updateVersion = true } = options;
120
- const fromVersion = await settings.getVersion();
125
+ async prepareMigrationTo(toVersion, options = {}) {
126
+ const { updateSettings: updateVersion = true, fromVersion: providedFromVersion } = options;
127
+
128
+ // Use provided fromVersion if available, otherwise query the database
129
+ const fromVersion = providedFromVersion ?? (await settings.getVersion());
121
130
 
122
131
  if (toVersion < 0) {
123
132
  throw new Error(`Cannot migrate to negative version: ${toVersion}`);
124
133
  }
125
134
 
135
+ if (fromVersion < 0) {
136
+ throw new Error(`Cannot migrate from negative version: ${fromVersion}`);
137
+ }
138
+
126
139
  if (toVersion < fromVersion) {
127
140
  throw new Error(
128
141
  `Cannot migrate backwards: current version is ${fromVersion}, target is ${toVersion}. Only forward migrations are supported.`,
@@ -135,6 +148,12 @@ export function createMigrator({
135
148
  );
136
149
  }
137
150
 
151
+ if (fromVersion > targetSchema.version) {
152
+ throw new Error(
153
+ `Cannot migrate from version ${fromVersion}: schema only has version ${targetSchema.version}`,
154
+ );
155
+ }
156
+
138
157
  if (toVersion === fromVersion) {
139
158
  // Already at target version, return empty migration
140
159
  return {
@@ -146,12 +165,7 @@ export function createMigrator({
146
165
 
147
166
  const context: MigrationContext = {
148
167
  async auto() {
149
- let generated = generateMigrationFromSchema(
150
- targetSchema,
151
- fromVersion,
152
- toVersion,
153
- userConfig,
154
- );
168
+ let generated = generateMigrationFromSchema(targetSchema, fromVersion, toVersion);
155
169
 
156
170
  for (const transformer of transformers) {
157
171
  if (!transformer.afterAuto) {
@@ -170,11 +184,12 @@ export function createMigrator({
170
184
  },
171
185
  };
172
186
 
173
- let operations = await context.auto();
174
-
175
- if (updateVersion) {
176
- operations.push(...(await settings.updateSettingsInMigration(toVersion)));
177
- }
187
+ let operations = updateVersion
188
+ ? [
189
+ ...(await settings.updateSettingsInMigration(fromVersion, toVersion)),
190
+ ...(await context.auto()),
191
+ ]
192
+ : await context.auto();
178
193
 
179
194
  for (const transformer of transformers) {
180
195
  if (!transformer.afterAll) {
@@ -1,5 +1,3 @@
1
- import type { AnyColumn, AnyTable } from "../schema/create";
2
-
3
1
  export interface ForeignKeyInfo {
4
2
  name: string;
5
3
  columns: string[];
@@ -7,6 +5,27 @@ export interface ForeignKeyInfo {
7
5
  referencedColumns: string[];
8
6
  }
9
7
 
8
+ export interface ColumnInfo {
9
+ name: string;
10
+ type:
11
+ | "string"
12
+ | "integer"
13
+ | "bigint"
14
+ | "decimal"
15
+ | "bool"
16
+ | "date"
17
+ | "timestamp"
18
+ | "json"
19
+ | "binary"
20
+ | `varchar(${number})`;
21
+ isNullable: boolean;
22
+ role: "external-id" | "internal-id" | "version" | "reference" | "regular";
23
+ default?: {
24
+ value?: unknown;
25
+ runtime?: "now" | "auto";
26
+ };
27
+ }
28
+
10
29
  export type MigrationOperation =
11
30
  | TableOperation
12
31
  | {
@@ -42,14 +61,15 @@ export type CustomOperation = {
42
61
  export type TableOperation =
43
62
  | {
44
63
  type: "create-table";
45
- value: AnyTable;
64
+ name: string;
65
+ columns: ColumnInfo[];
46
66
  }
47
67
  | {
48
68
  type: "drop-table";
49
69
  name: string;
50
70
  }
51
71
  | {
52
- type: "update-table";
72
+ type: "alter-table";
53
73
  name: string;
54
74
  value: ColumnOperation[];
55
75
  }
@@ -74,7 +94,7 @@ export type ColumnOperation =
74
94
  * Note: unique constraints are not created, please use dedicated operations like `add-index` instead
75
95
  */
76
96
  type: "create-column";
77
- value: AnyColumn;
97
+ value: ColumnInfo;
78
98
  }
79
99
  | {
80
100
  /**
@@ -90,7 +110,7 @@ export type ColumnOperation =
90
110
  *
91
111
  * Note: unique constraints are not updated, please use dedicated operations like `add-index` instead
92
112
  */
93
- value: AnyColumn;
113
+ value: ColumnInfo;
94
114
 
95
115
  updateNullable: boolean;
96
116
  updateDefault: boolean;
package/src/mod.ts CHANGED
@@ -1 +1,197 @@
1
- export const hello = "world";
1
+ import type { DatabaseAdapter } from "./adapters/adapters";
2
+ import type { AnySchema } from "./schema/create";
3
+ import type { AbstractQuery } from "./query/query";
4
+
5
+ export type { DatabaseAdapter };
6
+
7
+ export const fragnoDatabaseFakeSymbol = "$fragno-database" as const;
8
+ export const fragnoDatabaseLibraryVersion = "0.1" as const;
9
+
10
+ export interface CreateFragnoDatabaseDefinitionOptions<T extends AnySchema> {
11
+ namespace: string;
12
+ schema: T;
13
+ }
14
+
15
+ export function isFragnoDatabase(value: unknown): value is FragnoDatabase<AnySchema> {
16
+ if (value instanceof FragnoDatabase) {
17
+ return true;
18
+ }
19
+
20
+ if (typeof value !== "object" || value === null) {
21
+ return false;
22
+ }
23
+
24
+ return (
25
+ fragnoDatabaseFakeSymbol in value &&
26
+ value[fragnoDatabaseFakeSymbol] === fragnoDatabaseFakeSymbol
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Definition of a Fragno database schema and namespace.
32
+ * Created by library authors using defineFragnoDatabase().
33
+ * Apps instantiate it by calling .create(adapter).
34
+ */
35
+ export class FragnoDatabaseDefinition<const T extends AnySchema> {
36
+ #namespace: string;
37
+ #schema: T;
38
+
39
+ constructor(options: CreateFragnoDatabaseDefinitionOptions<T>) {
40
+ this.#namespace = options.namespace;
41
+ this.#schema = options.schema;
42
+ }
43
+
44
+ get namespace() {
45
+ return this.#namespace;
46
+ }
47
+
48
+ get schema() {
49
+ return this.#schema;
50
+ }
51
+
52
+ /**
53
+ * Creates a FragnoDatabase instance by binding an adapter to this definition.
54
+ */
55
+ create(adapter: DatabaseAdapter): FragnoDatabase<T> {
56
+ return new FragnoDatabase({
57
+ namespace: this.#namespace,
58
+ schema: this.#schema,
59
+ adapter,
60
+ });
61
+ }
62
+ }
63
+
64
+ /**
65
+ * A Fragno database instance with a bound adapter.
66
+ * Created from a FragnoDatabaseDefinition by calling .create(adapter).
67
+ */
68
+ export class FragnoDatabase<const T extends AnySchema> {
69
+ #namespace: string;
70
+ #schema: T;
71
+ #adapter: DatabaseAdapter;
72
+
73
+ constructor(options: { namespace: string; schema: T; adapter: DatabaseAdapter }) {
74
+ this.#namespace = options.namespace;
75
+ this.#schema = options.schema;
76
+ this.#adapter = options.adapter;
77
+ }
78
+
79
+ get [fragnoDatabaseFakeSymbol](): typeof fragnoDatabaseFakeSymbol {
80
+ return fragnoDatabaseFakeSymbol;
81
+ }
82
+
83
+ async createClient(): Promise<AbstractQuery<T>> {
84
+ const dbVersion = await this.#adapter.getSchemaVersion(this.#namespace);
85
+ if (dbVersion !== this.#schema.version.toString()) {
86
+ throw new Error(
87
+ `Database is not at expected version. Did you forget to run migrations?` +
88
+ ` Current version: ${dbVersion}, Expected version: ${this.#schema.version}`,
89
+ );
90
+ }
91
+
92
+ return this.#adapter.createQueryEngine(this.#schema, this.#namespace);
93
+ }
94
+
95
+ async runMigrations(): Promise<boolean> {
96
+ if (!this.#adapter.createMigrationEngine) {
97
+ throw new Error("Migration engine not supported for this adapter.");
98
+ }
99
+
100
+ const migrator = this.#adapter.createMigrationEngine(this.#schema, this.#namespace);
101
+ const preparedMigration = await migrator.prepareMigration();
102
+ await preparedMigration.execute();
103
+
104
+ return preparedMigration.operations.length > 0;
105
+ }
106
+
107
+ get namespace() {
108
+ return this.#namespace;
109
+ }
110
+
111
+ get schema() {
112
+ return this.#schema;
113
+ }
114
+
115
+ get adapter() {
116
+ return this.#adapter;
117
+ }
118
+
119
+ async generateSchema(options?: {
120
+ path?: string;
121
+ toVersion?: number;
122
+ fromVersion?: number;
123
+ }): Promise<{ schema: string; path: string }> {
124
+ const adapter = this.#adapter;
125
+
126
+ if (adapter.createSchemaGenerator) {
127
+ if (options?.toVersion !== undefined || options?.fromVersion !== undefined) {
128
+ console.warn("⚠️ toVersion and fromVersion are not supported for schema generation.");
129
+ }
130
+
131
+ const generator = adapter.createSchemaGenerator(this.#schema, this.#namespace);
132
+ const defaultPath = options?.path ?? "schema.ts";
133
+ return generator.generateSchema({
134
+ path: defaultPath,
135
+ toVersion: options?.toVersion,
136
+ fromVersion: options?.fromVersion,
137
+ });
138
+ }
139
+
140
+ if (adapter.createMigrationEngine) {
141
+ const migrator = adapter.createMigrationEngine(this.#schema, this.#namespace);
142
+ const targetVersion = options?.toVersion ?? this.#schema.version;
143
+ const sourceVersion = options?.fromVersion;
144
+
145
+ // Get current version for file naming if not provided
146
+ const currentVersion = sourceVersion ?? (await migrator.getVersion());
147
+
148
+ // Determine the default path using the migrator's getDefaultFileName if available
149
+ const defaultPath =
150
+ options?.path ??
151
+ (migrator.getDefaultFileName
152
+ ? migrator.getDefaultFileName(this.#namespace, currentVersion, targetVersion)
153
+ : "schema.sql");
154
+
155
+ // Generate migration from source to target version
156
+ const preparedMigration = await migrator.prepareMigrationTo(targetVersion, {
157
+ updateSettings: true,
158
+ fromVersion: sourceVersion,
159
+ });
160
+
161
+ if (!preparedMigration.getSQL) {
162
+ throw new Error(
163
+ "Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().",
164
+ );
165
+ }
166
+
167
+ const sql = preparedMigration.getSQL();
168
+
169
+ // If no migrations needed, return informative message
170
+ if (!sql.trim()) {
171
+ throw new Error("No migrations needed. Database is already at the target version.");
172
+ }
173
+
174
+ return {
175
+ schema: sql,
176
+ path: defaultPath,
177
+ };
178
+ }
179
+
180
+ throw new Error(
181
+ "Adapter does not support schema generation. Ensure your adapter implements either createSchemaGenerator or createMigrationEngine.",
182
+ );
183
+ }
184
+ }
185
+
186
+ export function defineFragnoDatabase<const TSchema extends AnySchema>(
187
+ options: CreateFragnoDatabaseDefinitionOptions<TSchema>,
188
+ ): FragnoDatabaseDefinition<TSchema> {
189
+ return new FragnoDatabaseDefinition(options);
190
+ }
191
+
192
+ export {
193
+ defineFragmentWithDatabase,
194
+ DatabaseFragmentBuilder,
195
+ type FragnoPublicConfigWithDatabase,
196
+ type DatabaseFragmentContext,
197
+ } from "./fragment";