@thomasfosterau/effect-drizzle-ext 0.0.0 → 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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +508 -2
  3. package/dist/columns.d.ts +113 -0
  4. package/dist/columns.d.ts.map +1 -0
  5. package/dist/columns.js +146 -0
  6. package/dist/columns.js.map +1 -0
  7. package/dist/constraints.d.ts +117 -0
  8. package/dist/constraints.d.ts.map +1 -0
  9. package/dist/constraints.js +93 -0
  10. package/dist/constraints.js.map +1 -0
  11. package/dist/database.d.ts +189 -0
  12. package/dist/database.d.ts.map +1 -0
  13. package/dist/database.js +51 -0
  14. package/dist/database.js.map +1 -0
  15. package/dist/derive.d.ts +97 -0
  16. package/dist/derive.d.ts.map +1 -0
  17. package/dist/derive.js +142 -0
  18. package/dist/derive.js.map +1 -0
  19. package/dist/errors.d.ts +157 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +287 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/index-CFhgcF4N.d.ts +418 -0
  24. package/dist/index-CFhgcF4N.d.ts.map +1 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.js +1 -0
  27. package/dist/jsonapi/derive.d.ts +28 -0
  28. package/dist/jsonapi/derive.d.ts.map +1 -0
  29. package/dist/jsonapi/derive.js +28 -0
  30. package/dist/jsonapi/derive.js.map +1 -0
  31. package/dist/jsonapi/index.d.ts +189 -0
  32. package/dist/jsonapi/index.d.ts.map +1 -0
  33. package/dist/jsonapi/index.js +164 -0
  34. package/dist/jsonapi/index.js.map +1 -0
  35. package/dist/query.d.ts +111 -0
  36. package/dist/query.d.ts.map +1 -0
  37. package/dist/query.js +142 -0
  38. package/dist/query.js.map +1 -0
  39. package/dist/references.d.ts +38 -0
  40. package/dist/references.d.ts.map +1 -0
  41. package/dist/references.js +60 -0
  42. package/dist/references.js.map +1 -0
  43. package/dist/sort.d.ts +129 -0
  44. package/dist/sort.d.ts.map +1 -0
  45. package/dist/sort.js +225 -0
  46. package/dist/sort.js.map +1 -0
  47. package/dist/src-CBeuhy5b.js +478 -0
  48. package/dist/src-CBeuhy5b.js.map +1 -0
  49. package/dist/update.d.ts +61 -0
  50. package/dist/update.d.ts.map +1 -0
  51. package/dist/update.js +64 -0
  52. package/dist/update.js.map +1 -0
  53. package/dist/versioned-chain.d.ts +524 -0
  54. package/dist/versioned-chain.d.ts.map +1 -0
  55. package/dist/versioned-chain.js +298 -0
  56. package/dist/versioned-chain.js.map +1 -0
  57. package/package.json +102 -4
  58. package/src/columns.ts +186 -0
  59. package/src/constraints.ts +225 -0
  60. package/src/database.ts +273 -0
  61. package/src/derivation-error.ts +27 -0
  62. package/src/derive.ts +320 -0
  63. package/src/errors.ts +466 -0
  64. package/src/index.ts +653 -0
  65. package/src/jsonapi/derive.ts +74 -0
  66. package/src/jsonapi/index.ts +355 -0
  67. package/src/query.ts +183 -0
  68. package/src/references.ts +103 -0
  69. package/src/sort.ts +368 -0
  70. package/src/tree.ts +367 -0
  71. package/src/update.ts +88 -0
  72. package/src/versioned-chain.ts +1027 -0
@@ -0,0 +1,418 @@
1
+ import * as Option from "effect/Option";
2
+ import * as Schema from "effect/Schema";
3
+ declare const DerivationError_base: Schema.Class<DerivationError, Schema.TaggedStruct<"DerivationError", {
4
+ readonly message: Schema.String;
5
+ }>, import("effect/Cause").YieldableError>;
6
+ /**
7
+ * A construction-time derivation failure: a table or a tree could not be built
8
+ * from its declarations (no builder registered for a column kind, a
9
+ * `references` annotation with no resolver, numeric bounds on a column the
10
+ * table has no column for, an unresolvable FK target, a tree level whose
11
+ * parent is missing or forms a cycle).
12
+ *
13
+ * **Thrown, never failed.** Derivation runs at module load, before an Effect
14
+ * runtime exists, so the only way to stop a misdeclared table or tree from
15
+ * reaching production is to make its `import` fail. It is a tagged error all
16
+ * the same, so a consumer that does catch one (a registry loader, a codegen
17
+ * script) can match it structurally.
18
+ */
19
+ declare class DerivationError extends DerivationError_base {}
20
+ /**
21
+ * How a level stores its columns. `"plain"` (the default): one version table
22
+ * carrying every level column. `"fact-scoped"`: an `(id, version)` spine plus
23
+ * one fact table per level column, where a fact's absence at a version is its
24
+ * `NULL` (website's 6NF `manifestation_version` pilot).
25
+ */
26
+ type LevelKind = "plain" | "fact-scoped";
27
+ /**
28
+ * One level's declaration, generic in the names its `parent` may take and in
29
+ * the leaf payload. Optional members are `?: T | undefined` so a caller can
30
+ * forward its own optional.
31
+ */
32
+ interface LevelSpec<Parent extends string = string, Leaf = unknown> {
33
+ /** The parent level. Absent: a child of the root (a branch root). */
34
+ readonly parent?: Parent | undefined;
35
+ /** How the level stores its columns; `"plain"` when absent. */
36
+ readonly kind?: LevelKind | undefined;
37
+ /**
38
+ * Level columns: `dbColumn`-annotated fields on this level's version table,
39
+ * contributed to every descendant's view. Every field must carry a
40
+ * `dbColumn` annotation.
41
+ */
42
+ readonly columns?: Schema.Struct.Fields | undefined;
43
+ /** The leaf payload. Present: a concrete leaf; absent: a marker level. */
44
+ readonly leaf?: Leaf | undefined;
45
+ }
46
+ /**
47
+ * The constraint a tree declaration `S` is checked against: every entry is a
48
+ * {@link LevelSpec} whose `parent` names **another** level of `S`, plus the
49
+ * consumer's extension record `Ext` (pulpit's `owned` / `pageable` flags, say),
50
+ * whose names the library never learns. A parent naming no level, or the level
51
+ * itself, is a type error at the declaration.
52
+ */
53
+ type CheckedTreeSpec<S, Leaf, Ext> = { readonly [K in keyof S]: LevelSpec<Exclude<keyof S & string, K>, Leaf> & Ext; };
54
+ /** Every level name a tree declaration `S` declares (a `Tree` reads its own). */
55
+ type LevelName<S> = keyof S & string;
56
+ /** The names of the leaf levels of declaration `S`: the discriminator values. */
57
+ type LeafName<S> = { readonly [K in keyof S]: S[K] extends {
58
+ readonly leaf?: infer L;
59
+ } ? [Exclude<L, undefined>] extends [never] ? never : K : never; }[keyof S] & string;
60
+ /** The names of the marker (non-leaf) levels of declaration `S`. */
61
+ type MarkerName<S> = Exclude<LevelName<S>, LeafName<S>>;
62
+ /** Everything derived about one level of a tree. */
63
+ interface TreeLevel<S> {
64
+ /** The level's name (a leaf's discriminator value). */
65
+ readonly name: LevelName<S>;
66
+ /** The declaration entry, extension flags included. */
67
+ readonly entry: S[LevelName<S>];
68
+ /** The parent level; `Option.none()` for a branch root. */
69
+ readonly parent: Option.Option<LevelName<S>>;
70
+ /** The level kind, `"plain"` when the entry names none. */
71
+ readonly kind: LevelKind;
72
+ /** Whether the level is a concrete leaf. */
73
+ readonly isLeaf: boolean;
74
+ /** Every ancestor, root-most first, the level itself excluded. */
75
+ readonly ancestors: ReadonlyArray<LevelName<S>>;
76
+ /** The direct children, in declaration order. */
77
+ readonly children: ReadonlyArray<LevelName<S>>;
78
+ /** Every descendant, in declaration order, the level itself excluded. */
79
+ readonly descendants: ReadonlyArray<LevelName<S>>;
80
+ /**
81
+ * The leaves of the level's subtree in declaration order, the level itself
82
+ * included when it is a leaf: the value set of its discriminator CHECK.
83
+ */
84
+ readonly subtreeLeaves: ReadonlyArray<LeafName<S>>;
85
+ /** The branch root the level belongs to (itself for a branch root). */
86
+ readonly branch: LevelName<S>;
87
+ /** The level columns' db-column metadata, keyed by field, in order. */
88
+ readonly levelColumns: Readonly<Record<string, DbColumn>>;
89
+ /** A leaf's own domain columns, keyed by field, in order; empty for a marker. */
90
+ readonly leafColumns: Readonly<Record<string, DbColumn>>;
91
+ }
92
+ /**
93
+ * The type-level column metadata of one level: its level columns' and its
94
+ * leaf's `DbColumn` maps, recovered from the declaration's phantoms. What a
95
+ * table derivation reads to type the tables it builds.
96
+ */
97
+ interface LevelColumnsMeta {
98
+ readonly level: object;
99
+ readonly leaf: object;
100
+ }
101
+ /** The default column metadata of a declaration `S`: untyped maps per level. */
102
+ type AnyTreeColumnsMeta<S> = { readonly [K in keyof S]: LevelColumnsMeta; };
103
+ declare const TreeColumnsTypeId: unique symbol;
104
+ /**
105
+ * A checked tree: the declaration plus every level's derived facts. `M` is a
106
+ * type-only phantom (never present at runtime) carrying each level's typed
107
+ * column metadata, so the table derivation types every table it builds.
108
+ */
109
+ interface Tree<S, M = AnyTreeColumnsMeta<S>> {
110
+ /** Type-only: each level's typed column metadata. */
111
+ readonly [TreeColumnsTypeId]?: M;
112
+ /** The declaration exactly as written, for type-level consumers. */
113
+ readonly spec: S;
114
+ /** Every level name, in declaration order. */
115
+ readonly names: ReadonlyArray<LevelName<S>>;
116
+ /** Every level, in declaration order. */
117
+ readonly levels: ReadonlyArray<TreeLevel<S>>;
118
+ /** The leaf names, in declaration order. */
119
+ readonly leaves: ReadonlyArray<LeafName<S>>;
120
+ /** The branch roots (children of the root), in declaration order. */
121
+ readonly branchRoots: ReadonlyArray<LevelName<S>>;
122
+ /** Look a level up by name. */
123
+ readonly level: (name: LevelName<S>) => TreeLevel<S>;
124
+ }
125
+ /**
126
+ * A referential action for a derived foreign-key column — the Drizzle
127
+ * `onDelete` / `onUpdate` vocabulary, restated as plain data so the annotation
128
+ * layer stays Drizzle-free.
129
+ */
130
+ type ReferentialAction = "cascade" | "restrict" | "no action" | "set null" | "set default";
131
+ /**
132
+ * Reference / foreign-key metadata a column annotation may carry: the target
133
+ * relation + column the derived column foreign-keys to, plus its referential
134
+ * actions. Expressed as **names** (not Drizzle column thunks) so it survives in
135
+ * the Drizzle-free annotation layer; the derivation resolves the names to real
136
+ * columns via its own `resolveReference` hook (see the {@link ./derive.ts}
137
+ * entry).
138
+ *
139
+ * This is the metadata that lets an FK-backed attribute be derived rather than
140
+ * hand-authored as a table-only `references()` column and re-stated in the
141
+ * consuming application's operation value map.
142
+ */
143
+ interface DbColumnReference {
144
+ /** The referenced relation (table) name. */
145
+ readonly table: string;
146
+ /** The referenced column name. */
147
+ readonly column: string;
148
+ /** Referential action on delete of the referenced row. */
149
+ readonly onDelete?: ReferentialAction | undefined;
150
+ /** Referential action on update of the referenced row. */
151
+ readonly onUpdate?: ReferentialAction | undefined;
152
+ }
153
+ /**
154
+ * Column metadata a model attribute declares about the column it backs. Generic
155
+ * over the column-kind union `Kind` (open `string` by default) — a consumer pins
156
+ * it to its own kinds via {@link dbColumnFor}.
157
+ */
158
+ interface DbColumn<Kind extends string = string> {
159
+ /** The snake_case column name (e.g. `published_at`). */
160
+ readonly column: string;
161
+ /** The column kind (selects the Drizzle builder in the derivation). */
162
+ readonly pg: Kind;
163
+ /** Whether the column is `NOT NULL`. */
164
+ readonly notNull: boolean;
165
+ /** Optional SQL `DEFAULT`. */
166
+ readonly default?: boolean | number | string | undefined;
167
+ /** Optional foreign-key metadata (see {@link DbColumnReference}). */
168
+ readonly references?: DbColumnReference | undefined;
169
+ /**
170
+ * Optional explicit name for the CHECK constraint the column's numeric
171
+ * bounds derive — a migration-compat escape hatch for keeping a historical
172
+ * constraint name where the canonical `${table}_${column}_${suffix}` would
173
+ * rename it. Omit for new columns.
174
+ */
175
+ readonly checkName?: string | undefined;
176
+ }
177
+ /**
178
+ * The annotation key under which {@link dbColumn} stores its metadata.
179
+ * {@link dbColumn} writes it; {@link readDbColumn} and {@link fieldColumns}
180
+ * read it. Namespaced to the package so a consumer's own annotations never
181
+ * collide.
182
+ */
183
+ declare const DB_COLUMN_KEY = "effect-drizzle-ext/dbColumn";
184
+ declare const DbColumnTypeId: unique symbol;
185
+ /**
186
+ * A schema carrying db-column metadata `M` in a type-level phantom (the
187
+ * annotation value itself is erased from the type, so the phantom is what keeps
188
+ * the derived column map precise). The phantom property is **required for type
189
+ * matching** — a non-annotated schema must yield `never`, not `unknown`, so the
190
+ * column derivation can tell columns from plain / computed fields — but it is
191
+ * never present at runtime (the runtime reads the real annotation instead).
192
+ */
193
+ type Annotated<S extends Schema.Top, M extends DbColumn> = S & {
194
+ readonly [DbColumnTypeId]: M;
195
+ };
196
+ /** Recovers the db-column metadata phantom from a schema, or `never`. */
197
+ type DbColumnOf<S> = S extends {
198
+ readonly [DbColumnTypeId]: infer M extends DbColumn;
199
+ } ? M : never;
200
+ /**
201
+ * Annotate a base schema with the database column it backs. Attaches a genuine
202
+ * Effect annotation (the runtime reads it via {@link readDbColumn}) and carries
203
+ * the metadata literally in the type (so the column derivation stays precisely
204
+ * typed). Wrap the result in a model helper as usual — the helper's projection
205
+ * carries the annotation through to the table factory.
206
+ *
207
+ * Accepts any `pg` string; pin the kind union with {@link dbColumnFor} to catch
208
+ * unknown-kind typos at the annotation site.
209
+ */
210
+ declare const dbColumn: <S extends Schema.Top, const M extends DbColumn>(schema: S, meta: M) => Annotated<S, M>;
211
+ /**
212
+ * A {@link dbColumn} constrained to a specific column-kind union `Kind`. A
213
+ * consumer pins its own kinds once — `const dbColumn = dbColumnFor<PgKind>()` —
214
+ * so an annotation naming a kind the derivation can't build is a type error at
215
+ * the annotation site rather than a runtime surprise.
216
+ */
217
+ declare const dbColumnFor: <Kind extends string>() => <S extends Schema.Top, const M extends DbColumn<Kind>>(schema: S, meta: M) => Annotated<S, M>;
218
+ /**
219
+ * Read the db-column annotation off a schema at runtime. `Option.none()` when
220
+ * the schema declares none.
221
+ *
222
+ * Reads the schema's **own** annotations only: `Schema.resolveAnnotations` on a
223
+ * `Schema.optional(...)` / `Schema.NullOr(...)` wrapper does not see the inner
224
+ * schema's annotation. Use {@link fieldColumns} for a struct's fields, which
225
+ * peels those wrappers structurally.
226
+ */
227
+ declare const readDbColumn: (schema: Schema.Constraint) => Option.Option<DbColumn>;
228
+ /**
229
+ * The base table metadata {@link dbTable} attaches: the SQL leaf name the
230
+ * annotated target backs (a versioned consumer's version table is
231
+ * `${name}_version`).
232
+ *
233
+ * `TableMeta` is the floor, not the whole vocabulary: {@link dbTable} accepts
234
+ * any `TableMeta`, so a **flat** consumer — one whose tables anchor at no
235
+ * hierarchy at all — annotates with `{ name }` and nothing else, instead of
236
+ * re-implementing `dbTable` locally just to drop a field it has no use for.
237
+ * A level-dispatching consumer pins {@link DbTable} via {@link dbTableFor}.
238
+ */
239
+ interface TableMeta {
240
+ /** The snake_case leaf table name (e.g. `podcast_series`). */
241
+ readonly name: string;
242
+ }
243
+ /**
244
+ * Table metadata that additionally names the hierarchy level the leaf anchors
245
+ * at (selecting the parent table pair in a level-dispatching consumer). Generic
246
+ * over the level union `Level` (open `string` by default) — a consumer pins it
247
+ * to its own levels via {@link dbTableFor}, so a leaf naming an unknown level is
248
+ * a type error at the annotation site.
249
+ */
250
+ interface DbTable<Level extends string = string> extends TableMeta {
251
+ /** The hierarchy level the leaf anchors at (selects the parent table pair). */
252
+ readonly level: Level;
253
+ }
254
+ declare const DbTableTypeId: unique symbol;
255
+ /**
256
+ * A target object carrying db-table metadata `M` in a type-level phantom — the
257
+ * table-level counterpart of {@link Annotated}. The phantom keeps a consumer's
258
+ * level dispatch precise (a `"work"`-anchored leaf cannot be passed to a
259
+ * `"manifestation"` table factory); the runtime reads the real attached
260
+ * metadata via {@link readDbTable}.
261
+ */
262
+ type TableAnnotated<T extends object, M extends TableMeta> = T & {
263
+ readonly [DbTableTypeId]: M;
264
+ };
265
+ /** Recovers the db-table metadata phantom from a target, or `never`. */
266
+ type DbTableOf<T> = T extends {
267
+ readonly [DbTableTypeId]: infer M extends TableMeta;
268
+ } ? M : never;
269
+ /**
270
+ * Annotate any object with the database table it backs. Attaches the metadata
271
+ * as a non-enumerable symbol property (see {@link DB_TABLE_KEY} for why not
272
+ * `annotate`) and carries it literally in the type, so a level-bound table
273
+ * factory can constrain its input to leaves anchored at its level. Returns the
274
+ * **same** object.
275
+ *
276
+ * Accepts any {@link TableMeta}; pin a level union with {@link dbTableFor}.
277
+ */
278
+ declare const dbTable: <T extends object, const M extends TableMeta>(target: T, meta: M) => TableAnnotated<T, M>;
279
+ /**
280
+ * A {@link dbTable} constrained to a specific level union `Level`, requiring the
281
+ * full {@link DbTable} metadata. A consumer pins its own levels once — `const
282
+ * dbTable = dbTableFor<LeafLevel>()` — so an annotation naming a level the
283
+ * derivation has no parent binding for is a type error at the annotation site
284
+ * rather than a runtime surprise.
285
+ */
286
+ declare const dbTableFor: <Level extends string>() => <T extends object, const M extends DbTable<Level>>(target: T, meta: M) => TableAnnotated<T, M>;
287
+ /**
288
+ * Read the db-table metadata off a target at runtime. `Option.none()` when the
289
+ * target carries none.
290
+ *
291
+ * Typed to the {@link TableMeta} floor: a consumer that annotated with a
292
+ * {@link DbTable} recovers its `level` through the {@link DbTableOf} phantom,
293
+ * which is where the level is statically known.
294
+ */
295
+ declare const readDbTable: <T extends object>(target: T) => Option.Option<TableMeta>;
296
+ /**
297
+ * Numeric bounds recovered from a schema's checks — the JSON-Schema bound
298
+ * vocabulary. The source of a derived SQL `CHECK` constraint: one declaration
299
+ * (the model's `Schema.isGreaterThanOrEqualTo(0)` / `isBetween` check) drives
300
+ * wire validation **and** the column's database constraint.
301
+ */
302
+ interface NumericBounds {
303
+ readonly minimum?: number | undefined;
304
+ readonly maximum?: number | undefined;
305
+ readonly exclusiveMinimum?: number | undefined;
306
+ readonly exclusiveMaximum?: number | undefined;
307
+ }
308
+ /** The bounds of one column-backed attribute, paired with its column metadata. */
309
+ interface ColumnBounds extends NumericBounds {
310
+ readonly column: DbColumn;
311
+ }
312
+ /**
313
+ * Recover the {@link NumericBounds} a single attribute schema declares, or
314
+ * `Option.none()` when it declares none. Reads the schema's own checks plus the
315
+ * checks of each union member — the `Schema.NullOr(Schema.Finite.check(...))`
316
+ * shape a nullable numeric attribute takes. Deliberately shallow: bounds
317
+ * buried deeper than one union level are a modelling smell, not a supported
318
+ * shape.
319
+ *
320
+ * Exported because the `./jsonapi` entry's resource-level bounds reader is the
321
+ * same walk over a different field source.
322
+ */
323
+ declare const numericBounds: (schema: Schema.Constraint) => Option.Option<NumericBounds>;
324
+ /**
325
+ * Peels the `Schema.optional(...)` / `Schema.optionalKey(...)` /
326
+ * `Schema.NullOr(...)` / `Schema.UndefinedOr(...)` wrappers a model attribute
327
+ * applies, to reach a {@link dbColumn}-annotated base schema's phantom, or
328
+ * `never`. A required attribute carries the annotation on its base schema
329
+ * directly (no peel); an optional / nullable projection wraps it.
330
+ *
331
+ * The wrapper set mirrors what {@link fieldColumns} peels at runtime — note
332
+ * that `Schema.optional(S)` *is* `optionalKey(UndefinedOr(S))`, so the two pairs
333
+ * are one chain, not four independent cases.
334
+ */
335
+ type UnwrapColumn<S> = [DbColumnOf<S>] extends [never] ? [S] extends [Schema.optional<infer Inner>] ? UnwrapColumn<Inner> : [S] extends [Schema.optionalKey<infer Inner>] ? UnwrapColumn<Inner> : [S] extends [Schema.NullOr<infer Inner>] ? UnwrapColumn<Inner> : [S] extends [Schema.UndefinedOr<infer Inner>] ? UnwrapColumn<Inner> : never : DbColumnOf<S>;
336
+ /**
337
+ * The db-column metadata map a `Schema.Struct`'s fields project to, keyed by the
338
+ * fields that declare a {@link dbColumn} (others drop out of the map entirely).
339
+ * The type-level counterpart of {@link fieldColumns}.
340
+ */
341
+ type FieldColumnsMetaOf<F extends Schema.Struct.Fields> = { readonly [K in keyof F as [UnwrapColumn<F[K]>] extends [never] ? never : K]: UnwrapColumn<F[K]>; };
342
+ /**
343
+ * Project a `Schema.Struct`'s fields to the per-field {@link DbColumn} metadata
344
+ * the derivation consumes, dropping fields that declare no column. Peels the
345
+ * `optional` / `NullOr` wrappers a field may apply. The type-level counterpart
346
+ * is {@link FieldColumnsMetaOf}.
347
+ */
348
+ declare const fieldColumns: (fields: Schema.Struct.Fields) => Record<string, DbColumn>;
349
+ /**
350
+ * Project a `Schema.Struct`'s per-field numeric bounds into plain data a
351
+ * `CHECK`-constraint derivation consumes: for each {@link dbColumn}-annotated
352
+ * field whose schema carries numeric-bound checks, the bounds paired with the
353
+ * column metadata. Fields without a column, or without bounds, drop. The
354
+ * Drizzle-emitting counterpart is the `./derive` entry's
355
+ * `deriveFieldCheckConstraints`.
356
+ */
357
+ declare const fieldColumnBounds: (fields: Schema.Struct.Fields) => Record<string, ColumnBounds>;
358
+ /** The fields an entry's member `K` (`columns` or `leaf`) declares; `{}` when absent. */
359
+ type EntryFields<E, K extends "columns" | "leaf"> = E extends { readonly [P in K]?: infer F; } ? Exclude<F, undefined> extends Schema.Struct.Fields ? Exclude<F, undefined> : Record<never, never> : Record<never, never>;
360
+ /**
361
+ * The typed column metadata of a {@link defineTree} declaration `S`: per level,
362
+ * the `DbColumn` maps its level columns and its leaf fields carry. The phantom
363
+ * a `Tree` built by `defineTree` holds for the table derivation.
364
+ */
365
+ type FieldsTreeMeta<S> = { readonly [K in keyof S]: {
366
+ readonly level: FieldColumnsMetaOf<EntryFields<S[K], "columns">>;
367
+ readonly leaf: FieldColumnsMetaOf<EntryFields<S[K], "leaf">>;
368
+ }; };
369
+ /**
370
+ * A {@link defineTree} whose every entry also carries the consumer's
371
+ * extension record `Ext` (pulpit's `owned` / `pageable` flags, say); the
372
+ * library reads none of its members and hands each entry back on
373
+ * `tree.level(name).entry`. Pin it once — `const defineTree =
374
+ * defineTreeFor<RegistryFlags>()` — so an entry missing a flag is a type
375
+ * error. Throws {@link DerivationError} at module load as `defineTree` does.
376
+ */
377
+ declare const defineTreeFor: <Ext extends object>() => <const S extends CheckedTreeSpec<S, Schema.Struct.Fields, Ext>>(spec: S) => Tree<S, FieldsTreeMeta<S>>;
378
+ /**
379
+ * Declare an ontology's level tree once, Drizzle-free, so a models package can
380
+ * state it and the database layer derive every table, constraint and view from
381
+ * it. Each entry is a level: a **marker** (no `leaf`) or a **leaf**, whose
382
+ * `leaf` is the struct fields of its domain columns (`dbColumn`-annotated) and
383
+ * whose name is its discriminator value. An entry names its `parent` (absent:
384
+ * a branch root under the tree's root), and may carry level `columns`
385
+ * contributed to every descendant's view and a level `kind`.
386
+ *
387
+ * Returns the checked {@link Tree}: per level, its ancestors, children,
388
+ * descendants, subtree leaves (the discriminator CHECK value set) and branch,
389
+ * all in declaration order. A parent naming no level of the tree, or the level
390
+ * itself, is a type error. Throws {@link DerivationError} at module load for
391
+ * every structural fault the types can't catch: a missing parent or a cycle, a
392
+ * leaf with children, a marker with no leaf below it, an unannotated level
393
+ * column, a reserved column name (`id`, `version`, `action`, `type`), or two
394
+ * columns on one root-to-leaf path sharing a field key or a column name.
395
+ *
396
+ * @example
397
+ * ```ts
398
+ * import { dbColumn, defineTree } from "@thomasfosterau/effect-drizzle-ext";
399
+ * import * as Schema from "effect/Schema";
400
+ *
401
+ * const tree = defineTree({
402
+ * work: {
403
+ * columns: { title: dbColumn(Schema.String, { column: "title", pg: "text", notNull: true }) },
404
+ * },
405
+ * book: {
406
+ * parent: "work",
407
+ * leaf: { pages: dbColumn(Schema.Finite, { column: "pages", pg: "integer", notNull: false }) },
408
+ * },
409
+ * film: { parent: "work", leaf: {} },
410
+ * });
411
+ *
412
+ * console.log(tree.level("work").subtreeLeaves); // ["book", "film"]
413
+ * console.log(tree.level("book").ancestors); // ["work"]
414
+ * ```
415
+ */
416
+ declare const defineTree: <const S extends CheckedTreeSpec<S, Schema.Struct.Fields, Record<never, never>>>(spec: S) => Tree<S, FieldsTreeMeta<S>>;
417
+ export { LevelColumnsMeta as A, fieldColumns as C, AnyTreeColumnsMeta as D, readDbTable as E, Tree as F, TreeLevel as I, DerivationError as L, LevelName as M, LevelSpec as N, CheckedTreeSpec as O, MarkerName as P, fieldColumnBounds as S, readDbColumn as T, dbColumnFor as _, DbColumnOf as a, defineTree as b, DbTableOf as c, NumericBounds as d, ReferentialAction as f, dbColumn as g, UnwrapColumn as h, DbColumn as i, LevelKind as j, LeafName as k, FieldColumnsMetaOf as l, TableMeta as m, ColumnBounds as n, DbColumnReference as o, TableAnnotated as p, DB_COLUMN_KEY as r, DbTable as s, Annotated as t, FieldsTreeMeta as u, dbTable as v, numericBounds as w, defineTreeFor as x, dbTableFor as y };
418
+ //# sourceMappingURL=index-CFhgcF4N.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CFhgcF4N.d.ts","names":[],"sources":["../src/derivation-error.ts","../src/tree.ts","../src/index.ts"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { A as LevelColumnsMeta, C as fieldColumns, D as AnyTreeColumnsMeta, E as readDbTable, F as Tree, I as TreeLevel, L as DerivationError, M as LevelName, N as LevelSpec, O as CheckedTreeSpec, P as MarkerName, S as fieldColumnBounds, T as readDbColumn, _ as dbColumnFor, a as DbColumnOf, b as defineTree, c as DbTableOf, d as NumericBounds, f as ReferentialAction, g as dbColumn, h as UnwrapColumn, i as DbColumn, j as LevelKind, k as LeafName, l as FieldColumnsMetaOf, m as TableMeta, n as ColumnBounds, o as DbColumnReference, p as TableAnnotated, r as DB_COLUMN_KEY, s as DbTable, t as Annotated, u as FieldsTreeMeta, v as dbTable, w as numericBounds, x as defineTreeFor, y as dbTableFor } from "./index-CFhgcF4N.js";
2
+ export { Annotated, type AnyTreeColumnsMeta, type CheckedTreeSpec, ColumnBounds, DB_COLUMN_KEY, DbColumn, DbColumnOf, DbColumnReference, DbTable, DbTableOf, DerivationError, FieldColumnsMetaOf, FieldsTreeMeta, type LeafName, type LevelColumnsMeta, type LevelKind, type LevelName, type LevelSpec, type MarkerName, NumericBounds, ReferentialAction, TableAnnotated, TableMeta, type Tree, type TreeLevel, UnwrapColumn, dbColumn, dbColumnFor, dbTable, dbTableFor, defineTree, defineTreeFor, fieldColumnBounds, fieldColumns, numericBounds, readDbColumn, readDbTable };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { t as DB_COLUMN_KEY, h as DerivationError, n as dbColumn, r as dbColumnFor, i as dbTable, a as dbTableFor, o as defineTree, s as defineTreeFor, c as fieldColumnBounds, l as fieldColumns, u as numericBounds, d as readDbColumn, f as readDbTable } from "./src-CBeuhy5b.js";
@@ -0,0 +1,28 @@
1
+ import { ColumnBuilders, DeriveOptions, DerivedColumns } from "../derive.js";
2
+ import { AnyResource, ResourceColumnsMetaOf } from "./index.js";
3
+ import { ExtraConfigColumn, PgTableExtraConfigValue } from "drizzle-orm/pg-core";
4
+ /**
5
+ * The Drizzle column builders a `Resource.make` definition's annotated
6
+ * attributes produce against registry `B`, keyed and typed per attribute.
7
+ */
8
+ export type DerivedResourceColumns<R extends AnyResource, B extends ColumnBuilders> = DerivedColumns<ResourceColumnsMetaOf<R>, B>;
9
+ /**
10
+ * Build a `deriveResourceColumns` bound to a specific builder registry. The
11
+ * returned function interprets a `Resource.make` definition's per-attribute
12
+ * `dbColumn` annotations into the Drizzle column builders a table factory's
13
+ * `columns` expects.
14
+ */
15
+ export declare const makeDeriveResourceColumns: <B extends ColumnBuilders>(builders: B, options?: DeriveOptions) => (<R extends AnyResource>(resource: R) => DerivedResourceColumns<R, B>);
16
+ /**
17
+ * Derive the SQL `CHECK` constraints a resource definition's numeric-bound
18
+ * checks imply, named `${tableName}_${column}_${suffix}` unless the annotation
19
+ * pins a `checkName`, and guarded with `col IS NULL OR …` for a nullable
20
+ * column. Returns a callback shaped for a table factory's `extraConstraints`
21
+ * seam; a bounded attribute whose column is absent from the table throws
22
+ * {@link DerivationError}.
23
+ *
24
+ * The projection is deferred to the returned callback, so this composes inside
25
+ * a `pgTable(...)` call whose columns are still being assembled.
26
+ */
27
+ export declare const deriveCheckConstraints: (resource: AnyResource, tableName: string) => (table: Record<string, ExtraConfigColumn>) => PgTableExtraConfigValue[];
28
+ //# sourceMappingURL=derive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive.d.ts","names":[],"sources":["../../src/jsonapi/derive.ts"],"mappings":";;;;;;;YAqCY,uBACV,UAAU,aACV,UAAU,kBACR,eAAe,sBAAsB,IAAI;;;;;;;qBAQhC,4BAA6B,UAAU,gBAAc,UACtD,GAAC,UACF,oBACN,UAAU,aAAa,UAAU,MAAM,uBAAuB,GAAG;;;;;;;;;;;;qBAmBzD,yBAAsB,UACtB,aAAW,uBAAmB,OACjC,eAAe,uBAAqB"}
@@ -0,0 +1,28 @@
1
+ import { deriveCheckConstraintsFrom, makeDeriveColumns } from "../derive.js";
2
+ import { resourceColumnBounds, resourceColumns } from "./index.js";
3
+ // src/jsonapi/derive.ts
4
+ /**
5
+ * Build a `deriveResourceColumns` bound to a specific builder registry. The
6
+ * returned function interprets a `Resource.make` definition's per-attribute
7
+ * `dbColumn` annotations into the Drizzle column builders a table factory's
8
+ * `columns` expects.
9
+ */
10
+ const makeDeriveResourceColumns = (builders, options = {}) => {
11
+ const derive = makeDeriveColumns(builders, options);
12
+ return (resource) => derive.fromMeta(resourceColumns(resource));
13
+ };
14
+ /**
15
+ * Derive the SQL `CHECK` constraints a resource definition's numeric-bound
16
+ * checks imply, named `${tableName}_${column}_${suffix}` unless the annotation
17
+ * pins a `checkName`, and guarded with `col IS NULL OR …` for a nullable
18
+ * column. Returns a callback shaped for a table factory's `extraConstraints`
19
+ * seam; a bounded attribute whose column is absent from the table throws
20
+ * {@link DerivationError}.
21
+ *
22
+ * The projection is deferred to the returned callback, so this composes inside
23
+ * a `pgTable(...)` call whose columns are still being assembled.
24
+ */
25
+ const deriveCheckConstraints = (resource, tableName) => (table) => deriveCheckConstraintsFrom(resourceColumnBounds(resource), tableName)(table);
26
+ export { deriveCheckConstraints, makeDeriveResourceColumns };
27
+
28
+ //# sourceMappingURL=derive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive.js","names":[],"sources":["../../src/jsonapi/derive.ts"],"mappings":";;;;;;;;;AAgDA,MAAa,6BACX,UACA,UAAyB,CAAC,MACiD;CAC3E,MAAM,SAAS,kBAAkB,UAAU,OAAO;CAClD,QAA+B,aAG7B,OAAO,SAAS,gBAAgB,QAAQ,CAAC;AAC7C;;;;;;;;;;;;AAaA,MAAa,0BACV,UAAuB,eACvB,UACC,2BAA2B,qBAAqB,QAAQ,GAAG,SAAS,CAAC,CAAC,KAAK"}