@fougere/adapter-sql 0.6.0-alpha.0 → 0.8.0-alpha.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 (78) hide show
  1. package/README.md +2 -2
  2. package/dist/adapter.schema.json +16 -0
  3. package/dist/check.d.ts +2 -27
  4. package/dist/check.d.ts.map +1 -1
  5. package/dist/check.js +2 -27
  6. package/dist/check.js.map +1 -1
  7. package/dist/crud.d.ts +21 -81
  8. package/dist/crud.d.ts.map +1 -1
  9. package/dist/crud.js +58 -102
  10. package/dist/crud.js.map +1 -1
  11. package/dist/ddl.d.ts +8 -53
  12. package/dist/ddl.d.ts.map +1 -1
  13. package/dist/ddl.js +16 -55
  14. package/dist/ddl.js.map +1 -1
  15. package/dist/dialect.d.ts +7 -50
  16. package/dist/dialect.d.ts.map +1 -1
  17. package/dist/dialect.js +2 -5
  18. package/dist/dialect.js.map +1 -1
  19. package/dist/diff.d.ts +6 -44
  20. package/dist/diff.d.ts.map +1 -1
  21. package/dist/diff.js +20 -50
  22. package/dist/diff.js.map +1 -1
  23. package/dist/drift.d.ts +29 -0
  24. package/dist/drift.d.ts.map +1 -0
  25. package/dist/drift.js +53 -0
  26. package/dist/drift.js.map +1 -0
  27. package/dist/fields.d.ts +10 -9
  28. package/dist/fields.d.ts.map +1 -1
  29. package/dist/fields.js +8 -1
  30. package/dist/fields.js.map +1 -1
  31. package/dist/index.d.ts +6 -2
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +3 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/order.d.ts +23 -0
  36. package/dist/order.d.ts.map +1 -0
  37. package/dist/order.js +40 -0
  38. package/dist/order.js.map +1 -0
  39. package/dist/query.d.ts +2 -17
  40. package/dist/query.d.ts.map +1 -1
  41. package/dist/query.js +1 -11
  42. package/dist/query.js.map +1 -1
  43. package/dist/setup.d.ts +8 -36
  44. package/dist/setup.d.ts.map +1 -1
  45. package/dist/setup.js +11 -21
  46. package/dist/setup.js.map +1 -1
  47. package/dist/sqlite.d.ts.map +1 -1
  48. package/dist/sqlite.js +12 -20
  49. package/dist/sqlite.js.map +1 -1
  50. package/dist/step.d.ts +4 -33
  51. package/dist/step.d.ts.map +1 -1
  52. package/dist/step.js +11 -46
  53. package/dist/step.js.map +1 -1
  54. package/dist/table.d.ts +15 -77
  55. package/dist/table.d.ts.map +1 -1
  56. package/dist/table.js +34 -146
  57. package/dist/table.js.map +1 -1
  58. package/dist/values.d.ts +1 -17
  59. package/dist/values.d.ts.map +1 -1
  60. package/dist/values.js +2 -7
  61. package/dist/values.js.map +1 -1
  62. package/package.json +4 -4
  63. package/src/adapter.schema.json +16 -0
  64. package/src/check.ts +2 -27
  65. package/src/crud.ts +66 -105
  66. package/src/ddl.ts +14 -55
  67. package/src/dialect.ts +7 -50
  68. package/src/diff.ts +18 -50
  69. package/src/drift.ts +75 -0
  70. package/src/fields.ts +17 -8
  71. package/src/index.ts +5 -3
  72. package/src/order.ts +63 -0
  73. package/src/query.ts +2 -17
  74. package/src/setup.ts +19 -49
  75. package/src/sqlite.ts +13 -20
  76. package/src/step.ts +12 -54
  77. package/src/table.ts +42 -185
  78. package/src/values.ts +3 -24
package/dist/diff.js CHANGED
@@ -1,21 +1,10 @@
1
- /**
2
- * Diff — what the database is missing, compared to what the entities describe.
3
- *
4
- * Two states, one comparison, one realisation. The desired state comes from the
5
- * entities; the actual one from Kysely's introspection, which is already
6
- * engine-agnostic. The comparison itself is pure — no IO, no SQL.
7
- *
8
- * ADDITIVE ONLY, and that incapacity is the guarantee: a missing table is
9
- * created, a missing column is added, and **nothing else ever happens**. Drops,
10
- * renames and type changes are human intentions — a rename is not even
11
- * detectable from a diff (it reads as a drop plus an add). Those belong in a
12
- * written migration, never in an automatic pass.
13
- */
1
+ /** Diff — what the database is missing, compared to what the entities describe. */
14
2
  import { sql } from 'kysely';
15
3
  import { addForeignKeyConstraintSQL, compiler, createTableSQL, indexSQL } from './ddl.js';
16
4
  import { checkFor } from './check.js';
17
5
  import { columnTypeFor, resolveDialect } from './dialect.js';
18
- import { isKeyed, orderTables, toTables, toTableName, } from './table.js';
6
+ import { isKeyed, toTables, toTableName, } from './table.js';
7
+ import { orderTables } from './order.js';
19
8
  /** Read the live schema. Only names are needed — an additive pass never inspects types. */
20
9
  export async function actualState(db) {
21
10
  const state = new Map();
@@ -48,26 +37,21 @@ export function delta(desired, actual) {
48
37
  // cannot see whether an index exists. `CREATE INDEX IF NOT EXISTS` is idempotent, so
49
38
  // proposing it every time is cheaper and more honest than introspecting to guess —
50
39
  // the alternative would be an index that a `unique()` added later never gets.
40
+ //
41
+ // `unique` comes here too, and for that very reason: written as a column constraint it
42
+ // only ever reached a table being created, so the rule was declared and never realized on
43
+ // a database that had already lived. A unique index is the one form that can arrive late.
51
44
  for (const table of desired) {
52
45
  for (const column of table.columns) {
53
- if (column.index)
46
+ if (column.index || (column.unique && !column.primary))
54
47
  changes.push({ kind: 'createIndex', table, column });
55
48
  }
56
49
  }
57
50
  return changes;
58
51
  }
59
52
  /**
60
- * Order the changes `delta` found, dialect-aware — `delta` itself stays pure and
61
- * unordered, this is the one place that adds engine knowledge to the plan.
62
- *
63
- * SQLite resolves FK targets lazily and accepts any order, with no `ALTER TABLE
64
- * ADD CONSTRAINT` to defer to — changes pass through unchanged. Every other
65
- * engine needs a `createTable`'s FK targets to already exist: `orderTables`
66
- * sorts the NEW tables among themselves and reports the edges a cycle forces to
67
- * defer as `addConstraint` changes. An `addColumn` always lands last — its
68
- * table already exists (that's why it's `addColumn` and not `createTable`), but
69
- * its FK target might be one of THIS batch's new tables, so it waits until
70
- * every `createTable`/`addConstraint` above it has run.
53
+ * Order the changes `delta` found, dialect-aware — `delta` itself stays pure and unordered, this
54
+ * is the one place that adds engine knowledge to the plan.
71
55
  */
72
56
  export function orderChanges(changes, dialectName) {
73
57
  if (dialectName === 'sqlite')
@@ -90,14 +74,7 @@ export function orderChanges(changes, dialectName) {
90
74
  // Indexes last: the column they stand on may be one this very batch added.
91
75
  return [...createChanges, ...constraintChanges, ...addColumns, ...indexes];
92
76
  }
93
- /**
94
- * Render one change.
95
- *
96
- * A column added to a populated table cannot be `NOT NULL` without a default —
97
- * every engine refuses it. So an added column keeps its `NOT NULL` only when a
98
- * default answers the existing rows; otherwise it lands nullable, and tightening
99
- * it is a written migration.
100
- */
77
+ /** Render one change. */
101
78
  export function changeSQL(change, dialectName) {
102
79
  const dialect = resolveDialect(dialectName);
103
80
  if (change.kind === 'createTable') {
@@ -119,11 +96,14 @@ export function changeSQL(change, dialectName) {
119
96
  .schema.alterTable(table.name)
120
97
  .addColumn(column.name, sql.raw(type), (col) => {
121
98
  let built = col;
122
- if (column.default !== undefined) {
99
+ if (column.default !== undefined)
123
100
  built = built.defaultTo(column.default);
124
- if (!column.nullable)
125
- built = built.notNull();
126
- }
101
+ // Stated whether a default fills it or not: the same declaration gave NOT NULL on a
102
+ // fresh table and nothing on a migrated one, so two databases of one entity promised
103
+ // different things. Without a default the engine refuses on a table holding rows —
104
+ // which is the refusal `planStep` already names, arriving here instead of never.
105
+ if (!column.nullable)
106
+ built = built.notNull();
127
107
  if (column.references) {
128
108
  built = built.references(`${column.references.table}.${column.references.column}`);
129
109
  if (column.references.onDelete)
@@ -145,18 +125,8 @@ export async function planMigration(app, db, options) {
145
125
  const changes = orderChanges(delta(desiredTables(app, options), await actualState(db)), dialect);
146
126
  return { changes, statements: changes.map((change) => changeSQL(change, dialect)) };
147
127
  }
148
- /**
149
- * Bring the database up to what the entities describe — additively.
150
- *
151
- * Returns what it did, so a caller can log or refuse. Replaces the old
152
- * create-if-not-exists pass: it also catches a field added to an existing entity,
153
- * which used to be silently ignored.
154
- */
155
- /**
156
- * Bring the schema up to date. Takes the setup itself — `migrate(app, setup)` — so the
157
- * common case never has to reach into `setup.db`, the one handle that meets no judge.
158
- * A bare Kysely instance is still accepted, for a caller who holds only that.
159
- */
128
+ /** Bring the database up to what the entities describe — additively. */
129
+ /** Bring the schema up to date. */
160
130
  export async function migrate(app, target, options) {
161
131
  const db = target.db ?? target;
162
132
  const { changes, statements } = await planMigration(app, db, options);
package/dist/diff.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,OAAO,EAAE,GAAG,EAAe,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,0BAA0B,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAwB,MAAM,UAAU,CAAC;AAChH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAoB,MAAM,cAAc,CAAC;AAC/E,OAAO,EACL,OAAO,EACP,QAAQ,EACR,WAAW,GAIZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAKzC,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAe;IAC/C,MAAM,KAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC;QACvD,IAAI,KAAK,CAAC,MAAM;YAAE,SAAS;QAC3B,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,aAAa,CAAC,GAAY,EAAE,OAAyB;IACnE,OAAO,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,IAAI,WAAW,CAAC,CAAC;AAC1D,CAAC;AAQD,kFAAkF;AAClF,MAAM,UAAU,KAAK,CAAC,OAAmB,EAAE,MAAmB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7C,SAAS;QACX,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IACD,qFAAqF;IACrF,qFAAqF;IACrF,mFAAmF;IACnF,8EAA8E;IAC9E,EAAE;IACF,uFAAuF;IACvF,0FAA0F;IAC1F,0FAA0F;IAC1F,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/G,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAiB,EAAE,WAAwB;IACtE,IAAI,WAAW,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAE7C,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAiD,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;IAC/G,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;IAEhE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAuB,CAAC;IACzD,KAAK,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QACrE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvB,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,aAAa,GAAa,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACpD,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IAC9G,CAAC,CAAC,CAAC;IACH,MAAM,iBAAiB,GAAa,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAEpH,2EAA2E;IAC3E,OAAO,CAAC,GAAG,aAAa,EAAE,GAAG,iBAAiB,EAAE,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,CAAC;AAC7E,CAAC;AAED,yBAAyB;AACzB,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,WAAwB;IAChE,MAAM,OAAO,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QAClC,sEAAsE;QACtE,MAAM,IAAI,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,OAAO,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACpC,OAAO,0BAA0B,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QAClC,gFAAgF;QAChF,mBAAmB;QACnB,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IACjC,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IACpE,OAAO,QAAQ,CAAC,WAAW,CAAC;SACzB,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;SAC7B,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;QACpD,IAAI,KAAK,GAAG,GAAG,CAAC;QAChB,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1E,oFAAoF;QACpF,qFAAqF;QACrF,mFAAmF;QACnF,iFAAiF;QACjF,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;QAC9C,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;YACnF,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ;gBAAE,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACrF,CAAC;QACD,+EAA+E;QAC/E,+EAA+E;QAC/E,wEAAwE;QACxE,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;SACD,OAAO,EAAE,CAAC,GAAG,CAAC;AACnB,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAY,EACZ,EAAe,EACf,OAAyB;IAEzB,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,QAAQ,CAAC;IAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACjG,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;AACtF,CAAC;AAED,wEAAwE;AACxE,mCAAmC;AACnC,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAY,EACZ,MAAyC,EACzC,OAAyB;IAEzB,MAAM,EAAE,GAAI,MAA+B,CAAC,EAAE,IAAK,MAAsB,CAAC;IAC1E,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACtE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,29 @@
1
+ /** What a table PROMISES and what it now holds, when the two stopped agreeing. */
2
+ import type { Kysely } from 'kysely';
3
+ import type { TableDef } from './table.js';
4
+ /** One column whose declaration moved and whose table did not follow. */
5
+ export interface Drift {
6
+ table: string;
7
+ column: string;
8
+ /** What the entity says now. */
9
+ declared: string;
10
+ /** What the table still enforces. */
11
+ held: string;
12
+ /** What it costs, said where the reader is — a boot, not a migration plan. */
13
+ reason: string;
14
+ }
15
+ /**
16
+ * A migration is ADDITIVE by design: it creates what is missing and never touches a
17
+ * column that exists. That is a promise worth keeping — nothing is dropped behind your
18
+ * back — but it leaves a second fact unsaid, and unsaid is where it hurt: relax a
19
+ * `required` field and the table keeps its NOT NULL, so the write fails on a row, in
20
+ * production, long after the boot that could have named it.
21
+ *
22
+ * What is read here is what `actualState` already receives and throws away. `SchemaState`
23
+ * stays a set of names on purpose: `done()` reads it to decide whether a frozen step was
24
+ * already applied, and a wider one would make a replayed migration answer wrong.
25
+ */
26
+ export declare function drift(db: Kysely<any>, desired: TableDef[]): Promise<Drift[]>;
27
+ /** The one line a boot has room for, and the detail under it. */
28
+ export declare const driftReport: (found: Drift[]) => string;
29
+ //# sourceMappingURL=drift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.d.ts","sourceRoot":"","sources":["../src/drift.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,yEAAyE;AACzE,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAuClF;AAED,iEAAiE;AACjE,eAAO,MAAM,WAAW,UAAW,KAAK,EAAE,KAAG,MAI9B,CAAC"}
package/dist/drift.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * A migration is ADDITIVE by design: it creates what is missing and never touches a
3
+ * column that exists. That is a promise worth keeping — nothing is dropped behind your
4
+ * back — but it leaves a second fact unsaid, and unsaid is where it hurt: relax a
5
+ * `required` field and the table keeps its NOT NULL, so the write fails on a row, in
6
+ * production, long after the boot that could have named it.
7
+ *
8
+ * What is read here is what `actualState` already receives and throws away. `SchemaState`
9
+ * stays a set of names on purpose: `done()` reads it to decide whether a frozen step was
10
+ * already applied, and a wider one would make a replayed migration answer wrong.
11
+ */
12
+ export async function drift(db, desired) {
13
+ const held = new Map((await db.introspection.getTables())
14
+ .filter((table) => !table.isView)
15
+ .map((table) => [table.name, table.columns]));
16
+ const found = [];
17
+ for (const table of desired) {
18
+ const columns = held.get(table.name);
19
+ if (!columns)
20
+ continue;
21
+ for (const column of table.columns) {
22
+ const live = columns.find((one) => one.name === column.name);
23
+ // A column the table does not have yet is the additive pass's business, not this one.
24
+ if (!live)
25
+ continue;
26
+ if (column.nullable && !live.isNullable) {
27
+ found.push({
28
+ table: table.name,
29
+ column: column.name,
30
+ declared: 'optional',
31
+ held: 'NOT NULL',
32
+ reason: 'a write with no value for it fails at the row, not at boot',
33
+ });
34
+ }
35
+ if (!column.nullable && live.isNullable && !column.primary) {
36
+ found.push({
37
+ table: table.name,
38
+ column: column.name,
39
+ declared: 'required',
40
+ held: 'nullable',
41
+ reason: 'the door refuses what the table would still accept',
42
+ });
43
+ }
44
+ }
45
+ }
46
+ return found;
47
+ }
48
+ /** The one line a boot has room for, and the detail under it. */
49
+ export const driftReport = (found) => `${found.length} column(s) declare one thing and the table holds another:\n`
50
+ + found
51
+ .map((one) => ` ${one.table}.${one.column} — declared ${one.declared}, table keeps ${one.held}: ${one.reason}`)
52
+ .join('\n');
53
+ //# sourceMappingURL=drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../src/drift.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,EAAe,EAAE,OAAmB;IAC9D,MAAM,IAAI,GAAG,IAAI,GAAG,CAClB,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC;SACjC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;SAChC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAC/C,CAAC;IAEF,MAAM,KAAK,GAAY,EAAE,CAAC;IAC1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;YAC7D,sFAAsF;YACtF,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,IAAI,MAAM,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,KAAK,CAAC,IAAI,CAAC;oBACT,KAAK,EAAE,KAAK,CAAC,IAAI;oBACjB,MAAM,EAAE,MAAM,CAAC,IAAI;oBACnB,QAAQ,EAAE,UAAU;oBACpB,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,4DAA4D;iBACrE,CAAC,CAAC;YACL,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC3D,KAAK,CAAC,IAAI,CAAC;oBACT,KAAK,EAAE,KAAK,CAAC,IAAI;oBACjB,MAAM,EAAE,MAAM,CAAC,IAAI;oBACnB,QAAQ,EAAE,UAAU;oBACpB,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,oDAAoD;iBAC7D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAc,EAAU,EAAE,CACpD,GAAG,KAAK,CAAC,MAAM,6DAA6D;MAC1E,KAAK;SACJ,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,eAAe,GAAG,CAAC,QAAQ,iBAAiB,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC;SAC/G,IAAI,CAAC,IAAI,CAAC,CAAC"}
package/dist/fields.d.ts CHANGED
@@ -1,22 +1,23 @@
1
1
  /**
2
- * What an entity may state for THIS adapter, declared from OUTSIDE `@fougere/schema` —
3
- * which names no engine and no column type, and must not learn one to let this exist.
4
- *
5
- * It replaces what the shape would have given, and only for the engine it names: an
6
- * engine absent here keeps the shape's answer, so the entity still boots on every
7
- * dialect. What an engine must HONOR is not stated here — it is a decision, and it
8
- * belongs in `fougere.config.ts` beside `remotes:`, `sources:` and `ports:`.
2
+ * What an entity may state for THIS adapter, declared from OUTSIDE `@fougere/schema` — which names
3
+ * no engine and no column type, and must not learn one to let this exist.
9
4
  */
10
- import type { DialectName } from './dialect.js';
5
+ import { AdapterFieldValidator } from '@fougere/schema';
6
+ import ENTRY_FORMAT from './adapter.schema.json';
7
+ /** The engines the format names — the one list, read off the file that states it. */
8
+ type Engine = keyof typeof ENTRY_FORMAT.properties.columnType.properties;
11
9
  /** What sql holds, addressed by field — the shape every augmentation of the registry takes. */
12
10
  export type SqlFields<K extends string> = Readonly<Partial<Record<K, SqlField>>>;
13
11
  export interface SqlField {
14
12
  /** The column type to emit, per engine. An engine absent here keeps the shape's own. */
15
- readonly columnType?: Readonly<Partial<Record<DialectName, string>>>;
13
+ readonly columnType?: Readonly<Partial<Record<Engine, string>>>;
16
14
  }
15
+ /** Judges what an entity states under `adapters.sql`, against the format this adapter ships. */
16
+ export declare const sqlEntries: AdapterFieldValidator;
17
17
  declare module '@fougere/schema' {
18
18
  interface FougereEntityAdapters<K extends string> {
19
19
  sql?: SqlFields<K>;
20
20
  }
21
21
  }
22
+ export {};
22
23
  //# sourceMappingURL=fields.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,+FAA+F;AAC/F,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEjF,MAAM,WAAW,QAAQ;IACvB,wFAAwF;IACxF,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CACtE;AAED,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,qBAAqB,CAAC,CAAC,SAAS,MAAM;QAC9C,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;KACpB;CACF"}
1
+ {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,qBAAqB,EAAc,MAAM,iBAAiB,CAAC;AACpE,OAAO,YAAY,MAAM,uBAAuB,CAAuB;AAGvE,qFAAqF;AACrF,KAAK,MAAM,GAAG,MAAM,OAAO,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC;AAEzE,+FAA+F;AAC/F,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEjF,MAAM,WAAW,QAAQ;IACvB,wFAAwF;IACxF,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CACjE;AAED,gGAAgG;AAChG,eAAO,MAAM,UAAU,uBAAkD,CAAC;AAQ1E,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,qBAAqB,CAAC,CAAC,SAAS,MAAM;QAC9C,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;KACpB;CACF"}
package/dist/fields.js CHANGED
@@ -1,2 +1,9 @@
1
- export {};
1
+ /**
2
+ * What an entity may state for THIS adapter, declared from OUTSIDE `@fougere/schema` — which names
3
+ * no engine and no column type, and must not learn one to let this exist.
4
+ */
5
+ import { AdapterFieldValidator } from '@fougere/schema';
6
+ import ENTRY_FORMAT from './adapter.schema.json' with { type: 'json' };
7
+ /** Judges what an entity states under `adapters.sql`, against the format this adapter ships. */
8
+ export const sqlEntries = AdapterFieldValidator.of(ENTRY_FORMAT);
2
9
  //# sourceMappingURL=fields.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fields.js","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"fields.js","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,qBAAqB,EAAc,MAAM,iBAAiB,CAAC;AACpE,OAAO,YAAY,MAAM,uBAAuB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAcvE,gGAAgG;AAChG,MAAM,CAAC,MAAM,UAAU,GAAG,qBAAqB,CAAC,EAAE,CAAC,YAAqB,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export { createTableSQL, createIndexSQL, indexSQL, addForeignKeyConstraintSQL, generateSQL, autoMigrate, compiler } from './ddl.js';
2
2
  export { onQuery, logQueries, type QueryEvent, type QuerySink } from './query.js';
3
+ export type { FkEdge, TableOrder } from './order.js';
3
4
  export type { GenerateOptions, SqlSink } from './ddl.js';
4
- export { toTable, toTables, toTableName, toSnakeCase, isKeyed, orderTables } from './table.js';
5
- export type { TableDef, ColumnDef, ColumnShape, ColumnReference, RelationResolve, FkEdge, TableOrder, EntityEntry, FrondLike, AppLike, } from './table.js';
5
+ export { toTable, toTables, toTableName, toSnakeCase, isKeyed } from './table.js';
6
+ export { orderTables } from './order.js';
7
+ export type { TableDef, ColumnDef, ColumnShape, ColumnReference, RelationResolve, EntityEntry, FrondLike, AppLike, } from './table.js';
6
8
  export { columnTypeFor, dialects, resolveDialect, sqliteDialect, pgDialect, mysqlDialect, mssqlDialect, } from './dialect.js';
7
9
  export type { Dialect, DialectName } from './dialect.js';
8
10
  export type { SqlField, SqlFields } from './fields.js';
@@ -12,6 +14,8 @@ export { codecFor, codecsOf } from './values.js';
12
14
  export type { ValueCodec } from './values.js';
13
15
  export { setupKysely, sqlSink } from './setup.js';
14
16
  export type { Setup, SqlSource, SetupOptions } from './setup.js';
17
+ export { drift, driftReport } from './drift.js';
18
+ export type { Drift } from './drift.js';
15
19
  export { actualState, desiredTables, delta, orderChanges, changeSQL, planMigration, migrate } from './diff.js';
16
20
  export type { SchemaState, Change } from './diff.js';
17
21
  export { planStep, collapseChain, stepSQL, applyStep } from './step.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,0BAA0B,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpI,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAClF,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC/F,YAAY,EACV,QAAQ,EACR,SAAS,EACT,WAAW,EACX,eAAe,EACf,eAAe,EACf,MAAM,EACN,UAAU,EACV,WAAW,EACX,SAAS,EACT,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,QAAQ,EACR,cAAc,EACd,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC7D,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC/G,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACxE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,0BAA0B,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpI,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAClF,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EACV,QAAQ,EACR,SAAS,EACT,WAAW,EACX,eAAe,EACf,eAAe,EACf,WAAW,EACX,SAAS,EACT,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,QAAQ,EACR,cAAc,EACd,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC7D,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC/G,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACxE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createTableSQL, createIndexSQL, indexSQL, addForeignKeyConstraintSQL, generateSQL, autoMigrate, compiler } from './ddl.js';
2
2
  export { onQuery, logQueries } from './query.js';
3
- export { toTable, toTables, toTableName, toSnakeCase, isKeyed, orderTables } from './table.js';
3
+ export { toTable, toTables, toTableName, toSnakeCase, isKeyed } from './table.js';
4
+ export { orderTables } from './order.js';
4
5
  export { columnTypeFor, dialects, resolveDialect, sqliteDialect, pgDialect, mysqlDialect, mssqlDialect, } from './dialect.js';
5
6
  export { SqlStorage, createStorageFactory } from './crud.js';
6
7
  export { codecFor, codecsOf } from './values.js';
@@ -8,6 +9,7 @@ export { codecFor, codecsOf } from './values.js';
8
9
  // builtin, and an index that re-exported them made the whole adapter unreachable from a
9
10
  // runtime that has neither. It lives at `@fougere/adapter-sql/sqlite`.
10
11
  export { setupKysely, sqlSink } from './setup.js';
12
+ export { drift, driftReport } from './drift.js';
11
13
  export { actualState, desiredTables, delta, orderChanges, changeSQL, planMigration, migrate } from './diff.js';
12
14
  // The non-additive half — realised only from a step a human wrote down.
13
15
  export { planStep, collapseChain, stepSQL, applyStep } from './step.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,0BAA0B,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpI,OAAO,EAAE,OAAO,EAAE,UAAU,EAAmC,MAAM,YAAY,CAAC;AAElF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAa/F,OAAO,EACL,aAAa,EACb,QAAQ,EACR,cAAc,EACd,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEjD,0FAA0F;AAC1F,wFAAwF;AACxF,uEAAuE;AACvE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/G,wEAAwE;AACxE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,0BAA0B,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpI,OAAO,EAAE,OAAO,EAAE,UAAU,EAAmC,MAAM,YAAY,CAAC;AAGlF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAWzC,OAAO,EACL,aAAa,EACb,QAAQ,EACR,cAAc,EACd,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEjD,0FAA0F;AAC1F,wFAAwF;AACxF,uEAAuE;AACvE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/G,wEAAwE;AACxE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * In what order a batch of tables is created — the one question that reads a `TableDef` and
3
+ * knows nothing above it: no entity, no axis, no schema.
4
+ */
5
+ import type { ColumnDef, TableDef } from './table.js';
6
+ export interface FkEdge {
7
+ table: TableDef;
8
+ column: ColumnDef;
9
+ }
10
+ export interface TableOrder {
11
+ /** Tables in dependency order — a `ref()` target always precedes its referrer. */
12
+ ordered: TableDef[];
13
+ /** FK columns whose target could not be ordered first — a cycle. Constrain after creation. */
14
+ deferred: FkEdge[];
15
+ }
16
+ /**
17
+ * Order a table set so a `ref()`'s target always exists before the table that points at it —
18
+ * required by every engine except SQLite, which resolves FK targets lazily and accepts any order
19
+ * (and has no `ALTER TABLE ADD CONSTRAINT` to close a cycle with — a caller on that dialect skips
20
+ * this function entirely).
21
+ */
22
+ export declare function orderTables(tables: TableDef[]): TableOrder;
23
+ //# sourceMappingURL=order.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order.d.ts","sourceRoot":"","sources":["../src/order.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,kFAAkF;IAClF,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,8FAA8F;IAC9F,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,CAsC1D"}
package/dist/order.js ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Order a table set so a `ref()`'s target always exists before the table that points at it —
3
+ * required by every engine except SQLite, which resolves FK targets lazily and accepts any order
4
+ * (and has no `ALTER TABLE ADD CONSTRAINT` to close a cycle with — a caller on that dialect skips
5
+ * this function entirely).
6
+ */
7
+ export function orderTables(tables) {
8
+ const byName = new Map(tables.map((table) => [table.name, table]));
9
+ const needs = new Map(tables.map((table) => [
10
+ table.name,
11
+ new Set(table.columns
12
+ .filter((c) => c.references && c.references.table !== table.name && byName.has(c.references.table))
13
+ .map((c) => c.references.table)),
14
+ ]));
15
+ const ordered = [];
16
+ const deferred = [];
17
+ const done = new Set();
18
+ while (needs.size > 0) {
19
+ const ready = [...needs.keys()].find((name) => [...needs.get(name)].every((dep) => done.has(dep)));
20
+ if (ready) {
21
+ ordered.push(byName.get(ready));
22
+ done.add(ready);
23
+ needs.delete(ready);
24
+ continue;
25
+ }
26
+ // Every table left waits on another table left — a cycle. Break it by
27
+ // deferring one edge: every column of the first remaining table that points
28
+ // at its first unmet dependency.
29
+ const [name, deps] = [...needs.entries()][0];
30
+ const dep = [...deps].find((d) => !done.has(d));
31
+ const table = byName.get(name);
32
+ for (const column of table.columns) {
33
+ if (column.references?.table === dep)
34
+ deferred.push({ table, column });
35
+ }
36
+ deps.delete(dep);
37
+ }
38
+ return { ordered, deferred };
39
+ }
40
+ //# sourceMappingURL=order.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order.js","sourceRoot":"","sources":["../src/order.ts"],"names":[],"mappings":"AAkBA;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI;QACV,IAAI,GAAG,CACL,KAAK,CAAC,OAAO;aACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;aAClG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAW,CAAC,KAAK,CAAC,CACnC;KACF,CAAC,CACH,CAAC;IAEF,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,OAAO,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACpG,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,CAAC;YACjC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QACD,sEAAsE;QACtE,4EAA4E;QAC5E,iCAAiC;QACjC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QAChC,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,UAAU,EAAE,KAAK,KAAK,GAAG;gBAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC"}
package/dist/query.d.ts CHANGED
@@ -4,12 +4,7 @@ export interface QueryEvent {
4
4
  /** Which storage ran it — a process may open several (`sources:`). */
5
5
  storage: string;
6
6
  sql: string;
7
- /**
8
- * How MANY parameters, never their values.
9
- *
10
- * They are user data nobody chose to expose — the rule the call log states for a body.
11
- * The count is what a reader needs anyway: it is how you see an `IN (?, ?, ?)` grow.
12
- */
7
+ /** How MANY parameters, never their values. */
13
8
  parameters: number;
14
9
  /** Rounded to three decimals: a sub-microsecond statement reports 17 digits otherwise. */
15
10
  ms: number;
@@ -17,17 +12,7 @@ export interface QueryEvent {
17
12
  at: number;
18
13
  }
19
14
  export type QuerySink = (event: QueryEvent) => void;
20
- /**
21
- * Be told about every statement this process runs, and get the unsubscription back.
22
- *
23
- * A subscription and not an option, for one reason that decides it: Kysely takes its `log`
24
- * at CONSTRUCTION, and the storage is built during the boot — before any extension's
25
- * `up(app)` runs. So the only way to subscribe afterwards is for the log to be installed
26
- * from the start and route to whoever is listening.
27
- *
28
- * The same shape core states for `onLog` and observability for `onSpan`. Costs nothing when
29
- * nobody listens: `logQueries` returns on an empty list before touching the event.
30
- */
15
+ /** Be told about every statement this process runs, and get the unsubscription back. */
31
16
  export declare function onQuery(sink: QuerySink): () => void;
32
17
  /** The `log` every Kysely is built with. Named by storage, since a sink sees them all. */
33
18
  export declare function logQueries(storage: string): (event: LogEvent) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEvC,wDAAwD;AACxD,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAIpD;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,IAAI,CAOnD;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAkBrE"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEvC,wDAAwD;AACxD,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAIpD,wFAAwF;AACxF,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,IAAI,CAOnD;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAkBrE"}
package/dist/query.js CHANGED
@@ -1,15 +1,5 @@
1
1
  const sinks = [];
2
- /**
3
- * Be told about every statement this process runs, and get the unsubscription back.
4
- *
5
- * A subscription and not an option, for one reason that decides it: Kysely takes its `log`
6
- * at CONSTRUCTION, and the storage is built during the boot — before any extension's
7
- * `up(app)` runs. So the only way to subscribe afterwards is for the log to be installed
8
- * from the start and route to whoever is listening.
9
- *
10
- * The same shape core states for `onLog` and observability for `onSpan`. Costs nothing when
11
- * nobody listens: `logQueries` returns on an empty list before touching the event.
12
- */
2
+ /** Be told about every statement this process runs, and get the unsubscription back. */
13
3
  export function onQuery(sink) {
14
4
  sinks.push(sink);
15
5
  return () => {
package/dist/query.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAsBA,MAAM,KAAK,GAAgB,EAAE,CAAC;AAE9B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CAAC,IAAe;IACrC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjB,OAAO,GAAG,EAAE;QACV,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE/B,MAAM,IAAI,GAAe;YACvB,OAAO;YACP,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG;YACpB,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM;YACzC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC,GAAG,IAAI;YACvD,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,OAAO;YAC/B,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;SACf,CAAC;QACF,qFAAqF;QACrF,gFAAgF;QAChF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAiBA,MAAM,KAAK,GAAgB,EAAE,CAAC;AAE9B,wFAAwF;AACxF,MAAM,UAAU,OAAO,CAAC,IAAe;IACrC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjB,OAAO,GAAG,EAAE;QACV,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE/B,MAAM,IAAI,GAAe;YACvB,OAAO;YACP,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG;YACpB,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM;YACzC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC,GAAG,IAAI;YACvD,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,OAAO;YAC/B,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;SACf,CAAC;QACF,qFAAqF;QACrF,gFAAgF;QAChF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
package/dist/setup.d.ts CHANGED
@@ -1,12 +1,4 @@
1
- /**
2
- * Storage setup — the shape every engine answers, and no driver at all.
3
- *
4
- * Fougere has no business choosing a driver (`pg`, `mysql2`, `tedious`, `better-sqlite3`,
5
- * a D1 binding), so the caller builds the Kysely dialect and hands it over — no dynamic
6
- * import, no optional dependency. This file therefore reaches for nothing: it is what a
7
- * runtime with no filesystem imports. The one driver this package does own lives behind
8
- * `@fougere/adapter-sql/sqlite`.
9
- */
1
+ /** Storage setup — the shape every engine answers, and no driver at all. */
10
2
  import { Kysely, type Dialect as KyselyDialect } from 'kysely';
11
3
  import type { Source } from '@fougere/core';
12
4
  import { createStorageFactory, type StorageFactoryOptions } from './crud.js';
@@ -15,47 +7,27 @@ import type { SqlSink } from './ddl.js';
15
7
  export interface SetupOptions {
16
8
  /** Override naming for specific entities (e.g. better-auth wants singular table names). */
17
9
  storageFactoryOptions?: StorageFactoryOptions;
18
- /**
19
- * What to call this storage when a query is reported.
20
- *
21
- * A process may open several (`sources:`), and a module-level sink sees them all — without
22
- * a name, two statements from two databases read as one stream. Defaults to what
23
- * distinguishes them anyway: the engine here, the file path for SQLite.
24
- */
10
+ /** What to call this storage when a query is reported. */
25
11
  name?: string;
26
12
  }
27
- /**
28
- * A `Source` realized by SQL — and the three members that are SQL's, not the routing's.
29
- *
30
- * `dialect`, `db` and `sink` are to a source what `Kysely` is to `SqlStorage.client`: what
31
- * this adapter is MADE OF, reached by narrowing. Nothing that routes entities across
32
- * sources reads them.
33
- */
13
+ /** A `Source` realized by SQL — and the three members that are SQL's, not the routing's. */
34
14
  export interface SqlSource extends Source {
35
15
  dialect: DialectName;
36
16
  storageFactory: ReturnType<typeof createStorageFactory>;
37
17
  /** Runs raw statements — what `autoMigrate` writes through. */
38
18
  sink: SqlSink;
39
19
  /**
40
- * The Kysely instance, for what precedes any entity: `migrate(app, setup)` writes the
41
- * schema through it, and a script may need it before a container exists.
42
- *
43
- * It is not the way to reach data from inside an app — that is the injected `Storage`,
44
- * whose `client` gives the same handle while keeping the scope of its entity.
20
+ * The Kysely instance, for what precedes any entity: `migrate(app, setup)` writes the schema
21
+ * through it, and a script may need it before a container exists.
45
22
  */
46
23
  db: Kysely<any>;
47
- /**
48
- * Run `fn` inside one transaction of this engine, with a storage factory bound to it.
49
- *
50
- * The transaction belongs to the engine, so obtaining one is a gesture on the engine and
51
- * nowhere else. Nothing new is handed back: `Transaction<DB> extends Kysely<DB>` and
52
- * `SqlStorage` takes a `Kysely<any>`, so the SAME storage is rebuilt over the substituted
53
- * connection — which is why a frame needs no support in this package.
54
- */
24
+ /** Run `fn` inside one transaction of this engine, with a storage factory bound to it. */
55
25
  transacted<R>(fn: (storageFactory: ReturnType<typeof createStorageFactory>) => Promise<R>): Promise<R>;
56
26
  }
57
27
  /** The name this shape answered to before it was one realization among several. */
58
28
  export type Setup = SqlSource;
29
+ /** What every SQL engine keeps at the rows, whatever the dialect: the index IS the constraint. */
30
+ export declare const sqlEnforces: readonly ['unique'];
59
31
  /** A sink that runs statements through Kysely — works on every engine. */
60
32
  export declare function sqlSink(db: Kysely<any>): SqlSink;
61
33
  /** Wrap any Kysely dialect — Postgres, MySQL, SQL Server. */
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,EAAO,KAAK,OAAO,IAAI,aAAa,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAI7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAU,SAAQ,MAAM;IACvC,OAAO,EAAE,WAAW,CAAC;IACrB,cAAc,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;IACxD,+DAA+D;IAC/D,IAAI,EAAE,OAAO,CAAC;IACd;;;;;;OAMG;IACH,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAChB;;;;;;;OAOG;IACH,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,cAAc,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxG;AAED,mFAAmF;AACnF,MAAM,MAAM,KAAK,GAAG,SAAS,CAAC;AAkB9B,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAEhD;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CACzB,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,WAAW,EACpB,IAAI,GAAE,YAAiB,GACtB,SAAS,CAYX"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,MAAM,EAAO,KAAK,OAAO,IAAI,aAAa,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAK7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,4FAA4F;AAC5F,MAAM,WAAW,SAAU,SAAQ,MAAM;IACvC,OAAO,EAAE,WAAW,CAAC;IACrB,cAAc,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;IACxD,+DAA+D;IAC/D,IAAI,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAChB,0FAA0F;IAC1F,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,cAAc,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxG;AAED,mFAAmF;AACnF,MAAM,MAAM,KAAK,GAAG,SAAS,CAAC;AAE9B,kGAAkG;AAClG,eAAO,MAAM,WAAW,YAAI,QAAQ,CAAU,CAAC;AAa/C,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAEhD;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CACzB,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,WAAW,EACpB,IAAI,GAAE,YAAiB,GACtB,SAAS,CAaX"}
package/dist/setup.js CHANGED
@@ -1,30 +1,19 @@
1
- /**
2
- * Storage setup — the shape every engine answers, and no driver at all.
3
- *
4
- * Fougere has no business choosing a driver (`pg`, `mysql2`, `tedious`, `better-sqlite3`,
5
- * a D1 binding), so the caller builds the Kysely dialect and hands it over — no dynamic
6
- * import, no optional dependency. This file therefore reaches for nothing: it is what a
7
- * runtime with no filesystem imports. The one driver this package does own lives behind
8
- * `@fougere/adapter-sql/sqlite`.
9
- */
1
+ /** Storage setup — the shape every engine answers, and no driver at all. */
10
2
  import { Kysely, sql } from 'kysely';
11
3
  import { createStorageFactory } from './crud.js';
12
4
  import { logQueries } from './query.js';
13
- import { migrate } from './diff.js';
5
+ import { desiredTables, migrate } from './diff.js';
6
+ import { drift, driftReport } from './drift.js';
14
7
  import { toTableName } from './table.js';
15
- /**
16
- * The migration of what lives in ONE sql source, carrying its own dialect.
17
- *
18
- * It was the router's gesture, which had to know how SQL migrates — and did not pass the
19
- * dialect, so every source was migrated as sqlite, the documented Postgres case included.
20
- * A source knows its own engine, so the gesture is its own.
21
- */
8
+ /** What every SQL engine keeps at the rows, whatever the dialect: the index IS the constraint. */
9
+ export const sqlEnforces = ['unique'];
10
+ /** The migration of what lives in ONE sql source, carrying its own dialect. */
22
11
  function migrating(db, dialect, opts) {
23
12
  return async (view) => {
24
- await migrate(view, db, {
25
- dialect,
26
- tableName: opts.storageFactoryOptions?.tableName ?? toTableName,
27
- });
13
+ const options = { dialect, tableName: opts.storageFactoryOptions?.tableName ?? toTableName };
14
+ await migrate(view, db, options);
15
+ const found = await drift(db, desiredTables(view, options));
16
+ return found.length ? driftReport(found) : undefined;
28
17
  };
29
18
  }
30
19
  /** A sink that runs statements through Kysely — works on every engine. */
@@ -42,6 +31,7 @@ export function setupKysely(kyselyDialect, dialect, opts = {}) {
42
31
  migrate: migrating(db, dialect, opts),
43
32
  close: () => db.destroy(),
44
33
  name: opts.name ?? dialect,
34
+ enforces: sqlEnforces,
45
35
  transacted: (fn) => db.transaction().execute((trx) => fn(createStorageFactory(trx, opts.storageFactoryOptions, dialect))),
46
36
  };
47
37
  }