@bakery-framework/orm 1.2.2 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/adapters/base.ts +7 -8
- package/src/orm/index.ts +2 -3
- package/src/orm/query.ts +10 -0
- package/src/schema-registry.ts +4 -7
- package/src/sync/builder.ts +10 -15
- package/src/sync/engine.ts +8 -16
- package/src/sync/load.ts +6 -5
- package/src/sync/types.ts +7 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bakery-framework/orm",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.1",
|
|
4
4
|
"description": "Bakery database layer: adapters, query builder, schema sync and backup.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bakery",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
"bun": ">=1.3.14"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@bakery-framework/core": "^1.
|
|
57
|
+
"@bakery-framework/core": "^1.2.3"
|
|
58
58
|
}
|
|
59
59
|
}
|
package/src/adapters/base.ts
CHANGED
|
@@ -768,14 +768,6 @@ export abstract class SQLAdapter {
|
|
|
768
768
|
})
|
|
769
769
|
}
|
|
770
770
|
|
|
771
|
-
/**
|
|
772
|
-
* A `CHECK (col IN (…))` clause restricting a column to a set of values.
|
|
773
|
-
*
|
|
774
|
-
* Takes the column name because a CHECK has to name it, which is why
|
|
775
|
-
* `colDef` grew an optional `column` argument. Values bind nowhere — this is
|
|
776
|
-
* DDL — so they are quoted the same way `formatDefault` quotes a string
|
|
777
|
-
* default, by doubling the single quote.
|
|
778
|
-
*/
|
|
779
771
|
/**
|
|
780
772
|
* The declared width of a **sized** text column, or `undefined`.
|
|
781
773
|
*
|
|
@@ -804,6 +796,13 @@ export abstract class SQLAdapter {
|
|
|
804
796
|
return Number.isInteger(n) && n > 0 ? n : undefined
|
|
805
797
|
}
|
|
806
798
|
|
|
799
|
+
/**
|
|
800
|
+
* A `CHECK (col IN (…))` clause restricting a column to a set of values.
|
|
801
|
+
*
|
|
802
|
+
* Takes the column name because a CHECK has to name it. Values bind nowhere —
|
|
803
|
+
* this is DDL — so they are quoted the same way `formatDefault` quotes a
|
|
804
|
+
* string default, by doubling the single quote.
|
|
805
|
+
*/
|
|
807
806
|
protected enumClause(column: string, values: string[]): string {
|
|
808
807
|
const list = values
|
|
809
808
|
.map(v => `'${String(v).replaceAll("'", "''")}'`)
|
package/src/orm/index.ts
CHANGED
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
* `TypeError: undefined is not an object (evaluating 'Mutation.Insert')`.
|
|
13
13
|
*
|
|
14
14
|
* Biome's `organizeImports` sorts these alphabetically and puts `./mutation`
|
|
15
|
-
* first.
|
|
16
|
-
*
|
|
17
|
-
* suppression.
|
|
15
|
+
* first. The compiler cannot see the breakage, because the types are fine
|
|
16
|
+
* either way. Hence the suppression.
|
|
18
17
|
*/
|
|
19
18
|
// biome-ignore-all assist/source/organizeImports: cycle — see above
|
|
20
19
|
import { DB } from './query'
|
package/src/orm/query.ts
CHANGED
|
@@ -1072,6 +1072,16 @@ export namespace DB {
|
|
|
1072
1072
|
if (op === 'IS NULL' || op === 'IS NOT NULL') {
|
|
1073
1073
|
return `${left} ${op}`
|
|
1074
1074
|
}
|
|
1075
|
+
// A bound NULL can never satisfy `=` or `<>` — three-valued logic makes
|
|
1076
|
+
// both comparisons UNKNOWN for every row, so `where(col, null)` silently
|
|
1077
|
+
// matched nothing while cheerfully reporting success. The caller who
|
|
1078
|
+
// passes an explicit null means the SQL spelling of it. Only literal
|
|
1079
|
+
// values: a column reference on the right is a different comparison and
|
|
1080
|
+
// is left alone.
|
|
1081
|
+
if (rightArg === null && !isRightColumn) {
|
|
1082
|
+
if (op === '=') return `${left} IS NULL`
|
|
1083
|
+
if (op === '!=' || op === '<>') return `${left} IS NOT NULL`
|
|
1084
|
+
}
|
|
1075
1085
|
if (op === 'BETWEEN' && Array.isArray(rightArg)) {
|
|
1076
1086
|
const min = evalOperands(rightArg[0], params, false)
|
|
1077
1087
|
const max = evalOperands(rightArg[1], params, false)
|
package/src/schema-registry.ts
CHANGED
|
@@ -36,18 +36,15 @@ import type { MapOf } from '@bakery-framework/core/types'
|
|
|
36
36
|
|
|
37
37
|
// Augmented by the app; empty until then.
|
|
38
38
|
//
|
|
39
|
-
// **It has to be an `interface`, and the empty body is the point.** Biome's
|
|
40
39
|
// **`interface`, not `type`, and the empty body is the point.** A type alias
|
|
41
40
|
// cannot be declaration-merged, so rewriting this to `type X = {}` turns every
|
|
42
41
|
// app's `declare module '@bakery-framework/orm/schema-registry'` into
|
|
43
42
|
// `TS2300: Duplicate identifier` and the whole schema registry stops working.
|
|
44
43
|
//
|
|
45
|
-
// Biome's `noBannedTypes`
|
|
46
|
-
// fix
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
// offers the same fix, so the suppression stays. The compiler is the real
|
|
50
|
-
// guard: change this line and `apps/starter` fails to typecheck.
|
|
44
|
+
// Biome's `noBannedTypes` proposes exactly that rewrite and calls it a safe
|
|
45
|
+
// fix. That rule is off repo-wide now, but `noEmptyInterface` reaches the same
|
|
46
|
+
// construct and offers the same fix, so the suppression stays. The compiler is
|
|
47
|
+
// the real guard: change this line and `apps/starter` fails to typecheck.
|
|
51
48
|
// biome-ignore lint/suspicious/noEmptyInterface: must stay mergeable — above
|
|
52
49
|
export interface SchemaRegistry {}
|
|
53
50
|
|
package/src/sync/builder.ts
CHANGED
|
@@ -503,21 +503,6 @@ ${body}`
|
|
|
503
503
|
return `${result} } as const;\n`
|
|
504
504
|
}
|
|
505
505
|
|
|
506
|
-
/**
|
|
507
|
-
* The `orm/` folder layout's `schema.ts`: `table()` values and nothing else.
|
|
508
|
-
*
|
|
509
|
-
* The generator only ever emitted the `DBInfo` namespace, and for a folder
|
|
510
|
-
* project the write target is `orm/schema.ts` — which `orm/index.ts`
|
|
511
|
-
* re-exports. So a regeneration replaced every `table()` with a namespace
|
|
512
|
-
* *and* added a second `declare module '@bakery-framework/orm/schema-registry'` block
|
|
513
|
-
* colliding with the one in `index.ts`. It fired on `--choose=db` and, less
|
|
514
|
-
* visibly, after any sync involving `old()` wrappers.
|
|
515
|
-
*
|
|
516
|
-
* Tables only, deliberately: `index.ts` owns the re-exports and the schema
|
|
517
|
-
* registration, `indexes.ts` owns the index and unique declarations, and
|
|
518
|
-
* neither is the generator's to rewrite. That separation is the reason the
|
|
519
|
-
* folder layout exists (see `load.ts`).
|
|
520
|
-
*/
|
|
521
506
|
/**
|
|
522
507
|
* The constraints key a `_references.table` names, or `undefined`.
|
|
523
508
|
*
|
|
@@ -604,6 +589,16 @@ ${body}`
|
|
|
604
589
|
: `Field.Foreign(${target})`
|
|
605
590
|
}
|
|
606
591
|
|
|
592
|
+
/**
|
|
593
|
+
* The `orm/` folder layout's `schema.ts`: `table()` values and nothing else.
|
|
594
|
+
*
|
|
595
|
+
* Tables only, deliberately: `index.ts` owns the re-exports and the schema
|
|
596
|
+
* registration, `indexes.ts` owns the index and unique declarations, and
|
|
597
|
+
* neither is the generator's to rewrite. Emitting the single-file `DBInfo`
|
|
598
|
+
* namespace here instead would clobber both and leave two colliding
|
|
599
|
+
* `declare module '@bakery-framework/orm/schema-registry'` blocks. That
|
|
600
|
+
* separation is the reason the folder layout exists (see `load.ts`).
|
|
601
|
+
*/
|
|
607
602
|
private static buildTableModule(
|
|
608
603
|
constraints: Record<string, any>,
|
|
609
604
|
adapter: SQLAdapter,
|
package/src/sync/engine.ts
CHANGED
|
@@ -95,22 +95,14 @@ export const MESSAGES = messageLogger(logger, syncMsgs)
|
|
|
95
95
|
/**
|
|
96
96
|
* Whether a destructive sync in this process needs an explicit `--force-sync`.
|
|
97
97
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* `
|
|
101
|
-
*
|
|
102
|
-
* `
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* decision here. `import.meta.env.PROD` means only "`--dev` is absent", and
|
|
107
|
-
* `db:sync` is a separate CLI invocation that never passes `--dev` — so for
|
|
108
|
-
* this caller the flag is a constant `true`, carrying no information about the
|
|
109
|
-
* environment at all. Activating it would not have made the guard smarter; it
|
|
110
|
-
* would have made the `isProd` branch unconditional and left `handleSafetyChecks`'s
|
|
111
|
-
* interactive `Proceed with sync?` unreachable for the one workflow it exists
|
|
112
|
-
* for. That is dead code traded for different dead code, plus a silent UX
|
|
113
|
-
* change to the documented way of applying a schema.
|
|
98
|
+
* **`NODE_ENV` is the only term, deliberately — do not add a `PROD` check back.**
|
|
99
|
+
* There used to be a `process.env.PROD === 'true'` half that could never be
|
|
100
|
+
* true, since `core/init.ts` installs `PROD` as a getter returning a *boolean*.
|
|
101
|
+
* Repairing it rather than deleting it would have been worse: `PROD` means only
|
|
102
|
+
* "`--dev` is absent", and `db:sync` is a separate CLI invocation that never
|
|
103
|
+
* passes `--dev`, so for this caller it is a constant `true`. That would make
|
|
104
|
+
* the `isProd` branch unconditional and leave `handleSafetyChecks`'s interactive
|
|
105
|
+
* `Proceed with sync?` unreachable for the one workflow it exists for.
|
|
114
106
|
*
|
|
115
107
|
* `NODE_ENV` is the only term that actually says "deployment", which is what
|
|
116
108
|
* the guard is protecting against. Set it, and a destructive plan requires
|
package/src/sync/load.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import { Case, fs } from '@bakery-framework/core/utils'
|
|
2
|
-
import { Try } from '@bakery-framework/core/utils/common'
|
|
3
|
-
import { collectConstraints } from '../define'
|
|
4
|
-
import type * as SyncTypes from './types'
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* Where a project's data model lives, and how it is read.
|
|
8
3
|
*
|
|
@@ -33,6 +28,12 @@ import type * as SyncTypes from './types'
|
|
|
33
28
|
* a fresh one at the typo'd path while the real model sits untouched
|
|
34
29
|
* somewhere else.
|
|
35
30
|
*/
|
|
31
|
+
|
|
32
|
+
import { Case, fs } from '@bakery-framework/core/utils'
|
|
33
|
+
import { Try } from '@bakery-framework/core/utils/common'
|
|
34
|
+
import { collectConstraints } from '../define'
|
|
35
|
+
import type * as SyncTypes from './types'
|
|
36
|
+
|
|
36
37
|
/**
|
|
37
38
|
* Which shape the generator must write back.
|
|
38
39
|
*
|
package/src/sync/types.ts
CHANGED
|
@@ -60,14 +60,6 @@ export interface IndexConstraint {
|
|
|
60
60
|
refCols?: string[]
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
/**
|
|
64
|
-
* A foreign key as the database reports it.
|
|
65
|
-
*
|
|
66
|
-
* Identity is the tuple, not the name: SQLite's `PRAGMA foreign_key_list`
|
|
67
|
-
* does not return a constraint name at all, so keying on one would make every
|
|
68
|
-
* SQLite foreign key look new on every sync — the perpetual-rebuild failure
|
|
69
|
-
* this project keeps hitting.
|
|
70
|
-
*/
|
|
71
63
|
/**
|
|
72
64
|
* Referential actions, normalised to the SQL spelling.
|
|
73
65
|
*
|
|
@@ -83,6 +75,13 @@ export type ForeignKeyAction =
|
|
|
83
75
|
| 'SET NULL'
|
|
84
76
|
| 'SET DEFAULT'
|
|
85
77
|
|
|
78
|
+
/**
|
|
79
|
+
* A foreign key as the database reports it.
|
|
80
|
+
*
|
|
81
|
+
* Identity is the tuple, not the name: SQLite's `PRAGMA foreign_key_list` does
|
|
82
|
+
* not return a constraint name at all, so keying on one would make every SQLite
|
|
83
|
+
* foreign key look new on every sync.
|
|
84
|
+
*/
|
|
86
85
|
export interface ForeignKeyInfo {
|
|
87
86
|
table: string
|
|
88
87
|
cols: string[]
|