@zmdb/schema 1.0.0-beta.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/LICENSE +674 -0
- package/README.md +30 -0
- package/dist/custom-types/index.d.ts +41 -0
- package/dist/custom-types/index.d.ts.map +1 -0
- package/dist/custom-types/index.js +32 -0
- package/dist/custom-types/index.js.map +1 -0
- package/dist/derive/index.d.ts +122 -0
- package/dist/derive/index.d.ts.map +1 -0
- package/dist/derive/index.js +13 -0
- package/dist/derive/index.js.map +1 -0
- package/dist/derive/query.d.ts +62 -0
- package/dist/derive/query.d.ts.map +1 -0
- package/dist/derive/query.js +18 -0
- package/dist/derive/query.js.map +1 -0
- package/dist/dto/index.d.ts +224 -0
- package/dist/dto/index.d.ts.map +1 -0
- package/dist/dto/index.js +118 -0
- package/dist/dto/index.js.map +1 -0
- package/dist/entity-modeling/index.d.ts +12 -0
- package/dist/entity-modeling/index.d.ts.map +1 -0
- package/dist/entity-modeling/index.js +28 -0
- package/dist/entity-modeling/index.js.map +1 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/index.d.ts +374 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +735 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/validation-shape.d.ts +46 -0
- package/dist/ir/validation-shape.d.ts.map +1 -0
- package/dist/ir/validation-shape.js +130 -0
- package/dist/ir/validation-shape.js.map +1 -0
- package/dist/ir/vocabulary.d.ts +54 -0
- package/dist/ir/vocabulary.d.ts.map +1 -0
- package/dist/ir/vocabulary.js +51 -0
- package/dist/ir/vocabulary.js.map +1 -0
- package/dist/naming/index.d.ts +26 -0
- package/dist/naming/index.d.ts.map +1 -0
- package/dist/naming/index.js +147 -0
- package/dist/naming/index.js.map +1 -0
- package/dist/openapi/index.d.ts +57 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +98 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/relations/index.d.ts +23 -0
- package/dist/relations/index.d.ts.map +1 -0
- package/dist/relations/index.js +98 -0
- package/dist/relations/index.js.map +1 -0
- package/dist/tags/index.d.ts +261 -0
- package/dist/tags/index.d.ts.map +1 -0
- package/dist/tags/index.js +64 -0
- package/dist/tags/index.js.map +1 -0
- package/package.json +82 -0
- package/src/custom-types/index.ts +59 -0
- package/src/derive/index.ts +224 -0
- package/src/derive/query.ts +128 -0
- package/src/dto/index.ts +395 -0
- package/src/entity-modeling/index.ts +33 -0
- package/src/index.ts +263 -0
- package/src/ir/index.ts +1085 -0
- package/src/ir/validation-shape.ts +145 -0
- package/src/ir/vocabulary.ts +56 -0
- package/src/naming/index.ts +159 -0
- package/src/openapi/index.ts +133 -0
- package/src/relations/index.ts +134 -0
- package/src/tags/index.ts +284 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {} from '../index.js';
|
|
2
|
+
import { jsonSchemaFromIR } from '../ir/index.js';
|
|
3
|
+
// JSON Schema / OpenAPI generation — implementation.
|
|
4
|
+
// #64 toJsonSchema scalar/enum/nullable (+ tag mapping and variant/aggregation
|
|
5
|
+
// logic that the shared golden suite exercises). Build-time, no reflection.
|
|
6
|
+
//
|
|
7
|
+
// The scalar/variant walk used to live here as `scalarSchema` — one of the four
|
|
8
|
+
// independent walkers over column metadata catalogued in `PLAN-type-first.md` §1.
|
|
9
|
+
// It now delegates to `../ir`, so naming a variant and naming a derived type cannot
|
|
10
|
+
// produce different documents: both are read off the same `SchemaIR`, and the emitter is
|
|
11
|
+
// a pure function of it (REQ-TF-7). What is left in this file is the OpenAPI framing —
|
|
12
|
+
// components, list/search envelopes, naming — which is genuinely its own concern.
|
|
13
|
+
import { singularPascalCase } from '../naming/index.js';
|
|
14
|
+
export function toJsonSchema(schema, variant = 'entity') {
|
|
15
|
+
if (!schema) {
|
|
16
|
+
throw new Error('toJsonSchema<T>() was not replaced at build time. It is compiled away by @zmdb/compiler ' +
|
|
17
|
+
'(the unplugin, Metro adapter, or project compiler), which did not run over this file — a type argument cannot ' +
|
|
18
|
+
'be read at runtime, so there is nothing to fall back to.');
|
|
19
|
+
}
|
|
20
|
+
return jsonSchemaFromIR(schema.ir, variant);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The `components.schemas` key for a table, and the target of every `$ref` that points at
|
|
24
|
+
* it: singularized, then PascalCase. `user_addresses` → `UserAddress`.
|
|
25
|
+
*
|
|
26
|
+
* Exported because it is the only way to write a `$ref` by hand that resolves against a
|
|
27
|
+
* document this module produced, and because it is the whole subject of
|
|
28
|
+
* `singularization.spec.ts` — which used to reach it by declaring twenty schemas whose only
|
|
29
|
+
* distinguishing feature was the table name.
|
|
30
|
+
*/
|
|
31
|
+
export function componentName(table) {
|
|
32
|
+
return singularPascalCase(table);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The entity schema with a `$ref` per relation: a to-one refs the target component, a to-many
|
|
36
|
+
* is an array of them.
|
|
37
|
+
*
|
|
38
|
+
* Relations reach the `entity` (response) variant only. A create or update body is columns,
|
|
39
|
+
* and a `$ref` to a whole entity in one would say the client may post a nested graph, which
|
|
40
|
+
* no write path here accepts.
|
|
41
|
+
*
|
|
42
|
+
* There used to be a second parameter — a `Record<string, RelationLike>` naming each relation
|
|
43
|
+
* and its target table — because a schema value carried no relations for this to read. It
|
|
44
|
+
* carries them now, on `schema.ir`, so a document generated from a set of schemas can no
|
|
45
|
+
* longer disagree with the tables about which relations exist. The kinds are the IR's
|
|
46
|
+
* (`oneToMany`, not `one-to-many`).
|
|
47
|
+
*/
|
|
48
|
+
export function toJsonSchemaWithRelations(schema, variant = 'entity') {
|
|
49
|
+
const base = toJsonSchema(schema, variant);
|
|
50
|
+
if (variant !== 'entity')
|
|
51
|
+
return base; // input bodies exclude relations
|
|
52
|
+
const properties = { ...base.properties };
|
|
53
|
+
for (const rel of schema.ir.relations) {
|
|
54
|
+
const ref = { $ref: `#/components/schemas/${componentName(rel.target)}` };
|
|
55
|
+
const toMany = rel.relation === 'oneToMany' || rel.relation === 'manyToMany';
|
|
56
|
+
properties[rel.name] = toMany ? { type: 'array', items: ref } : ref;
|
|
57
|
+
}
|
|
58
|
+
return { type: 'object', properties, required: base.required };
|
|
59
|
+
}
|
|
60
|
+
export function toOpenApiComponents(schemas) {
|
|
61
|
+
const out = {};
|
|
62
|
+
for (const s of [...schemas].toSorted((a, b) => a.ir.table.localeCompare(b.ir.table))) {
|
|
63
|
+
out[componentName(s.ir.table)] = toJsonSchema(s, 'entity');
|
|
64
|
+
}
|
|
65
|
+
return { schemas: out };
|
|
66
|
+
}
|
|
67
|
+
export function toListSchema(schema) {
|
|
68
|
+
const entity = toJsonSchema(schema, 'entity');
|
|
69
|
+
return {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
items: { type: 'array', items: entity },
|
|
73
|
+
total: { type: 'integer' },
|
|
74
|
+
hasMore: { type: 'boolean' },
|
|
75
|
+
cursor: { type: 'string' },
|
|
76
|
+
},
|
|
77
|
+
required: ['hasMore', 'items'],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function toSearchSchema(schema) {
|
|
81
|
+
const entity = toJsonSchema(schema, 'entity');
|
|
82
|
+
const hit = {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: { ...entity.properties, _score: { type: 'number' } },
|
|
85
|
+
required: entity.required,
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
type: 'object',
|
|
89
|
+
properties: {
|
|
90
|
+
items: { type: 'array', items: hit },
|
|
91
|
+
total: { type: 'integer' },
|
|
92
|
+
hasMore: { type: 'boolean' },
|
|
93
|
+
cursor: { type: 'string' },
|
|
94
|
+
},
|
|
95
|
+
required: ['hasMore', 'items'],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/openapi/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type SchemaIR } from '../ir/index.js';
|
|
2
|
+
export interface ResolvedRelation {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
/** Where the related rows live. */
|
|
5
|
+
readonly targetTable: string;
|
|
6
|
+
/** Ordered columns on the declaring table whose values the join matches. */
|
|
7
|
+
readonly parentKey: readonly string[];
|
|
8
|
+
/** Ordered columns on the target table, positionally paired with `parentKey`. */
|
|
9
|
+
readonly targetKey: readonly string[];
|
|
10
|
+
/** `true` for `oneToMany`: the relation attaches an array, empty where nothing matched. */
|
|
11
|
+
readonly toMany: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve one relation of a table by name.
|
|
15
|
+
*
|
|
16
|
+
* Throws for a name the type does not declare — naming the ones it does, because a
|
|
17
|
+
* misspelled `populate` is the common case — and for `manyToMany`, whose `via` is a join
|
|
18
|
+
* table rather than a column: two hops cannot be expressed as one `IN`, and guessing the
|
|
19
|
+
* join table's two foreign keys from the table names either side is how a wrong query gets
|
|
20
|
+
* built quietly.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveRelation(ir: SchemaIR, name: string): ResolvedRelation;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAqC5E"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {} from '../ir/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve one relation of a table by name.
|
|
4
|
+
*
|
|
5
|
+
* Throws for a name the type does not declare — naming the ones it does, because a
|
|
6
|
+
* misspelled `populate` is the common case — and for `manyToMany`, whose `via` is a join
|
|
7
|
+
* table rather than a column: two hops cannot be expressed as one `IN`, and guessing the
|
|
8
|
+
* join table's two foreign keys from the table names either side is how a wrong query gets
|
|
9
|
+
* built quietly.
|
|
10
|
+
*/
|
|
11
|
+
export function resolveRelation(ir, name) {
|
|
12
|
+
const declared = ir.relations;
|
|
13
|
+
const rel = declared.find(candidate => candidate.name === name);
|
|
14
|
+
if (!rel) {
|
|
15
|
+
const known = declared.map(candidate => candidate.name);
|
|
16
|
+
throw new Error(`unknown relation "${name}" on ${ir.table}: ` +
|
|
17
|
+
(known.length > 0 ? `the type declares ${known.join(', ')}` : 'the type declares none'));
|
|
18
|
+
}
|
|
19
|
+
if (rel.relation === 'manyToMany') {
|
|
20
|
+
throw new Error(`relation "${name}" on ${ir.table} is many-to-many through "${rel.via}", which populate ` +
|
|
21
|
+
'does not resolve — join the two tables explicitly');
|
|
22
|
+
}
|
|
23
|
+
if (rel.relation === 'oneToMany') {
|
|
24
|
+
// The inverse side: the foreign key is a column of the *target*, holding this row's key.
|
|
25
|
+
return inverseRelation(ir, name, rel, true);
|
|
26
|
+
}
|
|
27
|
+
const via = relationColumns(ir, name, rel.via);
|
|
28
|
+
if (rel.relation === 'oneToOne' && !via.every(column => ir.columns.some(candidate => candidate.name === column))) {
|
|
29
|
+
// A one-to-one pair is symmetric, so `OneToOne<'profiles', 'userId'>` does not say which
|
|
30
|
+
// of the two tables holds the key — and the answer is "the one with the column". Declared
|
|
31
|
+
// on `users`, which has no `userId`, it is the inverse side, joined from the primary key
|
|
32
|
+
// exactly as a to-many is; it just cannot match twice.
|
|
33
|
+
return inverseRelation(ir, name, rel, false);
|
|
34
|
+
}
|
|
35
|
+
// The owning side: this row holds the foreign key, and the column it points at is written
|
|
36
|
+
// down on that column, as `References<'users.id'>`.
|
|
37
|
+
return {
|
|
38
|
+
name,
|
|
39
|
+
targetTable: rel.target,
|
|
40
|
+
parentKey: via,
|
|
41
|
+
targetKey: via.map(column => referencedColumn(ir, name, rel.target, column, via.length > 1)),
|
|
42
|
+
toMany: false,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function relationColumns(ir, relation, via) {
|
|
46
|
+
const columns = via.split(',').map(column => column.trim());
|
|
47
|
+
if (columns.some(column => column.length === 0)) {
|
|
48
|
+
throw new Error(`${ir.table}.${relation}: relation via "${via}" contains an empty column name`);
|
|
49
|
+
}
|
|
50
|
+
return columns;
|
|
51
|
+
}
|
|
52
|
+
/** The column a foreign key points at, per its `References<'table.column'>`; `id` without one. */
|
|
53
|
+
function referencedColumn(ir, relation, target, fk, requireReference) {
|
|
54
|
+
const reference = ir.columns.find(col => col.name === fk)?.references;
|
|
55
|
+
const separator = reference?.lastIndexOf('.') ?? -1;
|
|
56
|
+
if (reference !== undefined && separator > 0 && separator < reference.length - 1) {
|
|
57
|
+
return reference.slice(separator + 1);
|
|
58
|
+
}
|
|
59
|
+
if (requireReference) {
|
|
60
|
+
throw new Error(`${ir.table}.${relation}: composite relation via column "${fk}" must carry ` +
|
|
61
|
+
`References<'${target}.column'>; every via column must name its target`);
|
|
62
|
+
}
|
|
63
|
+
return 'id';
|
|
64
|
+
}
|
|
65
|
+
function primaryKeyOf(ir) {
|
|
66
|
+
if (ir.primaryKey.length === 0) {
|
|
67
|
+
throw new Error(`schema ${ir.table} has no primary key, so its relations have nothing to join from`);
|
|
68
|
+
}
|
|
69
|
+
return ir.primaryKey;
|
|
70
|
+
}
|
|
71
|
+
function relationTag(relation) {
|
|
72
|
+
switch (relation) {
|
|
73
|
+
case 'manyToOne':
|
|
74
|
+
return 'ManyToOne';
|
|
75
|
+
case 'oneToMany':
|
|
76
|
+
return 'OneToMany';
|
|
77
|
+
case 'oneToOne':
|
|
78
|
+
return 'OneToOne';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function inverseRelation(ir, name, rel, toMany) {
|
|
82
|
+
if (rel.relation !== 'oneToMany' && rel.relation !== 'oneToOne') {
|
|
83
|
+
throw new Error(`${ir.table}.${name}: ${rel.relation} is not an inverse relation`);
|
|
84
|
+
}
|
|
85
|
+
const parentKey = primaryKeyOf(ir);
|
|
86
|
+
const targetKey = relationColumns(ir, name, rel.via);
|
|
87
|
+
if (parentKey.length !== targetKey.length) {
|
|
88
|
+
const tag = relationTag(rel.relation);
|
|
89
|
+
const missing = Math.max(0, parentKey.length - targetKey.length);
|
|
90
|
+
const suggestedVia = [...parentKey.slice(0, missing), ...targetKey].join(',');
|
|
91
|
+
const targetLabel = targetKey.length === 1 ? 'column' : 'columns';
|
|
92
|
+
throw new Error(`${ir.table}.${name}: ${tag}<'${rel.target}', '${rel.via}'> supplies ${String(targetKey.length)} target ` +
|
|
93
|
+
`${targetLabel} for a ${String(parentKey.length)}-column parent key (${parentKey.join(', ')}); ` +
|
|
94
|
+
`name every column, in key order — ${tag}<'${rel.target}', '${suggestedVia}'>`);
|
|
95
|
+
}
|
|
96
|
+
return { name, targetTable: rel.target, parentKey, targetKey, toMany };
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/relations/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { type SqlType } from '../index.js';
|
|
2
|
+
import { type ProtoScalar, type ReferentialAction, type RelationKind } from '../ir/index.js';
|
|
3
|
+
declare const zmdbTable: unique symbol;
|
|
4
|
+
declare const zmdbPhysical: unique symbol;
|
|
5
|
+
declare const zmdbFts: unique symbol;
|
|
6
|
+
declare const zmdbShardKey: unique symbol;
|
|
7
|
+
declare const zmdbSortKey: unique symbol;
|
|
8
|
+
declare const zmdbRowstore: unique symbol;
|
|
9
|
+
declare const zmdbSoftDelete: unique symbol;
|
|
10
|
+
declare const zmdbSqlType: unique symbol;
|
|
11
|
+
declare const zmdbPrimaryKey: unique symbol;
|
|
12
|
+
declare const zmdbSerial: unique symbol;
|
|
13
|
+
declare const zmdbUnique: unique symbol;
|
|
14
|
+
declare const zmdbDefault: unique symbol;
|
|
15
|
+
declare const zmdbSensitive: unique symbol;
|
|
16
|
+
declare const zmdbReferences: unique symbol;
|
|
17
|
+
declare const zmdbOnDelete: unique symbol;
|
|
18
|
+
declare const zmdbOnUpdate: unique symbol;
|
|
19
|
+
declare const zmdbForeignKey: unique symbol;
|
|
20
|
+
declare const zmdbLength: unique symbol;
|
|
21
|
+
declare const zmdbNumeric: unique symbol;
|
|
22
|
+
declare const zmdbCodec: unique symbol;
|
|
23
|
+
declare const zmdbWire: unique symbol;
|
|
24
|
+
declare const zmdbRelation: unique symbol;
|
|
25
|
+
declare const zmdbMin: unique symbol;
|
|
26
|
+
declare const zmdbMax: unique symbol;
|
|
27
|
+
declare const zmdbMinLength: unique symbol;
|
|
28
|
+
declare const zmdbMaxLength: unique symbol;
|
|
29
|
+
declare const zmdbPattern: unique symbol;
|
|
30
|
+
declare const zmdbRule: unique symbol;
|
|
31
|
+
declare const zmdbProtoField: unique symbol;
|
|
32
|
+
declare const zmdbProtoScalar: unique symbol;
|
|
33
|
+
/** The table an entity maps to. `interface User extends Table<'users'>`. */
|
|
34
|
+
export type Table<Name extends string> = {
|
|
35
|
+
readonly [zmdbTable]?: Name;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The physical SQL identifier when it must override the configured naming strategy.
|
|
39
|
+
*
|
|
40
|
+
* In interface position it names the table; in a property intersection it names the
|
|
41
|
+
* column. The reflector decides which from the position, so one zero-runtime tag covers
|
|
42
|
+
* both without changing the declaration's TypeScript-facing name.
|
|
43
|
+
*/
|
|
44
|
+
export type Physical<Name extends string> = {
|
|
45
|
+
readonly [zmdbPhysical]?: Name;
|
|
46
|
+
};
|
|
47
|
+
/** The full-text-search table backing this entity (`CoreSchema.ftsTable`). */
|
|
48
|
+
export type Fts<Name extends string | true> = {
|
|
49
|
+
readonly [zmdbFts]?: Name;
|
|
50
|
+
};
|
|
51
|
+
/** SingleStore distribution columns, in declared order. */
|
|
52
|
+
export type ShardKey<Columns extends readonly string[]> = {
|
|
53
|
+
readonly [zmdbShardKey]?: Columns;
|
|
54
|
+
};
|
|
55
|
+
/** SingleStore columnstore sort columns, in declared order. */
|
|
56
|
+
export type SortKey<Columns extends readonly string[]> = {
|
|
57
|
+
readonly [zmdbSortKey]?: Columns;
|
|
58
|
+
};
|
|
59
|
+
/** Select SingleStore's row-oriented table storage instead of its columnstore default. */
|
|
60
|
+
export type Rowstore = {
|
|
61
|
+
readonly [zmdbRowstore]?: true;
|
|
62
|
+
};
|
|
63
|
+
/** The nullable timestamp column managed by repository soft delete. */
|
|
64
|
+
export type SoftDelete<Column extends string> = {
|
|
65
|
+
readonly [zmdbSoftDelete]?: Column;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* The SQL column types a declaration may name: every `SqlType` except `serial`.
|
|
69
|
+
*
|
|
70
|
+
* `serial` is not a column type. Postgres documents it as notational convenience for
|
|
71
|
+
* an `integer` with a sequence default, and that is how it is spelled here —
|
|
72
|
+
* `number & Sql<'integer'> & Serial` — which makes `Serial` the single place the fact
|
|
73
|
+
* lives, the way `| null` is the single place nullability lives (REQ-TF-2).
|
|
74
|
+
*
|
|
75
|
+
* Saying it twice was not merely redundant, it was wrong, and the way it was wrong is
|
|
76
|
+
* worth recording because nothing about the tags predicts it. Tag payloads are
|
|
77
|
+
* invariant, so the old `Sql<'serial'>` spelling was not assignable to `Sql<'integer'>` and
|
|
78
|
+
* a value read out of a serial primary key could not be written into an `integer` foreign key.
|
|
79
|
+
* `orders.create({ userId: user.id })` — the most ordinary line in a relational model —
|
|
80
|
+
* did not compile. With `serial` off the vocabulary the tags on `id` are
|
|
81
|
+
* `Sql<'integer'> & Serial & PrimaryKey`, which drops to `Sql<'integer'>` on the way in,
|
|
82
|
+
* and it does.
|
|
83
|
+
*
|
|
84
|
+
* The residue is honest and much smaller: two columns whose SQL types genuinely differ
|
|
85
|
+
* still do not interchange, so assigning a `Sql<'varchar'>` value into a `Sql<'text'>`
|
|
86
|
+
* column needs a conversion at the boundary. That is a rarer thing to write than a
|
|
87
|
+
* foreign key, and unlike the serial case the two columns really are different types.
|
|
88
|
+
*/
|
|
89
|
+
export type ColumnSqlType = Exclude<SqlType, 'serial'>;
|
|
90
|
+
/** The abstract SQL column type. Dialects render the spelling — see `../ir`. */
|
|
91
|
+
export type Sql<T extends ColumnSqlType> = {
|
|
92
|
+
readonly [zmdbSqlType]?: T;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* A column type supplied by a database extension.
|
|
96
|
+
*
|
|
97
|
+
* The installable extension and the SQL type are separate because PostGIS installs
|
|
98
|
+
* `postgis` and provides `geometry`. Arguments are type parameters rather than a SQL
|
|
99
|
+
* fragment, so reflection can validate and render each one without parsing SQL. This is
|
|
100
|
+
* the one structural marker in the vocabulary: the frozen IR contract names
|
|
101
|
+
* `__zmdbExt` directly, so it needs neither a `declare const` nor a runtime symbol.
|
|
102
|
+
*/
|
|
103
|
+
export type Ext<E extends string, N extends string, A extends readonly (string | number)[] = []> = {
|
|
104
|
+
readonly __zmdbExt?: [E, N, A];
|
|
105
|
+
};
|
|
106
|
+
export type PrimaryKey = {
|
|
107
|
+
readonly [zmdbPrimaryKey]?: true;
|
|
108
|
+
};
|
|
109
|
+
/** Database-generated. Omitted from `CreateDTO` entirely, not made optional. */
|
|
110
|
+
export type Serial = {
|
|
111
|
+
readonly [zmdbSerial]?: true;
|
|
112
|
+
};
|
|
113
|
+
export type Unique = {
|
|
114
|
+
readonly [zmdbUnique]?: true;
|
|
115
|
+
};
|
|
116
|
+
/** Has a database default, so it is *optional* on insert rather than absent. */
|
|
117
|
+
export type HasDefault = {
|
|
118
|
+
readonly [zmdbDefault]?: true;
|
|
119
|
+
};
|
|
120
|
+
/** Never serialised. `ReadDTO<T>` cannot name it, so a leak is a type error. */
|
|
121
|
+
export type Sensitive = {
|
|
122
|
+
readonly [zmdbSensitive]?: true;
|
|
123
|
+
};
|
|
124
|
+
export type References<Target extends string> = {
|
|
125
|
+
readonly [zmdbReferences]?: Target;
|
|
126
|
+
};
|
|
127
|
+
export { type ReferentialAction } from '../ir/index.js';
|
|
128
|
+
export type OnDelete<Action extends ReferentialAction> = {
|
|
129
|
+
readonly [zmdbOnDelete]?: Action;
|
|
130
|
+
};
|
|
131
|
+
export type OnUpdate<Action extends ReferentialAction> = {
|
|
132
|
+
readonly [zmdbOnUpdate]?: Action;
|
|
133
|
+
};
|
|
134
|
+
export type ForeignKey<LocalColumns extends string, TargetTable extends string, TargetColumns extends string> = {
|
|
135
|
+
readonly [zmdbForeignKey]?: {
|
|
136
|
+
readonly columns: LocalColumns;
|
|
137
|
+
readonly targetTable: TargetTable;
|
|
138
|
+
readonly targetColumns: TargetColumns;
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
/** `varchar(N)`. Also emits `maxLength: N` into JSON Schema. */
|
|
142
|
+
export type Length<N extends number> = {
|
|
143
|
+
readonly [zmdbLength]?: N;
|
|
144
|
+
};
|
|
145
|
+
/** `numeric(P, S)` precision and scale. */
|
|
146
|
+
export type Numeric<P extends number, S extends number> = {
|
|
147
|
+
readonly [zmdbNumeric]?: readonly [P, S];
|
|
148
|
+
};
|
|
149
|
+
/** Names a `CustomType` codec that converts between the wire, app and db types. */
|
|
150
|
+
export type Codec<Name extends string> = {
|
|
151
|
+
readonly [zmdbCodec]?: Name;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* What this column looks like over the wire, when that is not what it looks like in
|
|
155
|
+
* the app.
|
|
156
|
+
*
|
|
157
|
+
* The only tag whose payload is a *type* rather than a literal, and it has to be: a
|
|
158
|
+
* codec's wire type is arbitrary — cents as a decimal string, a UUID as a string, a
|
|
159
|
+
* point as `[number, number]` — so there is nothing to name it with but the type
|
|
160
|
+
* itself. `Wire<T>` reads it; a column without it is its own wire type, which is
|
|
161
|
+
* right for everything JSON can carry natively.
|
|
162
|
+
*
|
|
163
|
+
* amount: Money & Sql<'integer'> & Codec<'Money'> & WireAs<string>;
|
|
164
|
+
*
|
|
165
|
+
* `Sql<'timestamp'>` and `Sql<'bigint'>` do not need it. Their wire form follows from
|
|
166
|
+
* the SQL type and is built into `Wire<T>`, so writing it out would be a second place
|
|
167
|
+
* for the same fact to be wrong.
|
|
168
|
+
*/
|
|
169
|
+
export type WireAs<W> = {
|
|
170
|
+
readonly [zmdbWire]?: W;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* The four cardinalities. Listed once so `AnyRelation` cannot fall behind the tags — and
|
|
174
|
+
* listed in `../ir`, where the same four exist as data for the reflection to check against.
|
|
175
|
+
* Re-exported here because this is where a reader looking at the tags expects to find it.
|
|
176
|
+
*/
|
|
177
|
+
export { type RelationKind } from '../ir/index.js';
|
|
178
|
+
/**
|
|
179
|
+
* Matches a property carrying any relation tag, whatever its cardinality.
|
|
180
|
+
*
|
|
181
|
+
* `derive`'s `RelationKeys<T>` needs this because a relation is **not** a column:
|
|
182
|
+
* `Entity<T>` has to exclude `author` and `comments` or a join target would show up
|
|
183
|
+
* as something to `INSERT`. Written as `{ kind: RelationKind }` rather than
|
|
184
|
+
* `unknown` on purpose — an optional slot typed `unknown` is satisfied by a tag
|
|
185
|
+
* payload of any shape, including a future non-relation tag that happens to reuse
|
|
186
|
+
* the symbol, and matching on `kind` keeps the four cardinalities the whole set.
|
|
187
|
+
*
|
|
188
|
+
* Cardinality itself is deliberately *not* read back out of the tag. The declared
|
|
189
|
+
* type already says it: `author?: User & ManyToOne<…>` is to-one and
|
|
190
|
+
* `comments?: Comment[] & OneToMany<…>` is to-many, natively.
|
|
191
|
+
*/
|
|
192
|
+
export type AnyRelation = {
|
|
193
|
+
readonly [zmdbRelation]?: {
|
|
194
|
+
readonly kind: RelationKind;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
export type ManyToOne<Target extends string, Fk extends string> = {
|
|
198
|
+
readonly [zmdbRelation]?: {
|
|
199
|
+
readonly kind: 'manyToOne';
|
|
200
|
+
readonly target: Target;
|
|
201
|
+
readonly fk: Fk;
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
export type OneToMany<Target extends string, Fk extends string> = {
|
|
205
|
+
readonly [zmdbRelation]?: {
|
|
206
|
+
readonly kind: 'oneToMany';
|
|
207
|
+
readonly target: Target;
|
|
208
|
+
readonly fk: Fk;
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
export type OneToOne<Target extends string, Fk extends string> = {
|
|
212
|
+
readonly [zmdbRelation]?: {
|
|
213
|
+
readonly kind: 'oneToOne';
|
|
214
|
+
readonly target: Target;
|
|
215
|
+
readonly fk: Fk;
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
export type ManyToMany<Target extends string, Through extends string> = {
|
|
219
|
+
readonly [zmdbRelation]?: {
|
|
220
|
+
readonly kind: 'manyToMany';
|
|
221
|
+
readonly target: Target;
|
|
222
|
+
readonly through: Through;
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
export type Min<N extends number> = {
|
|
226
|
+
readonly [zmdbMin]?: N;
|
|
227
|
+
};
|
|
228
|
+
export type Max<N extends number> = {
|
|
229
|
+
readonly [zmdbMax]?: N;
|
|
230
|
+
};
|
|
231
|
+
export type MinLength<N extends number> = {
|
|
232
|
+
readonly [zmdbMinLength]?: N;
|
|
233
|
+
};
|
|
234
|
+
export type MaxLength<N extends number> = {
|
|
235
|
+
readonly [zmdbMaxLength]?: N;
|
|
236
|
+
};
|
|
237
|
+
export type Pattern<S extends string> = {
|
|
238
|
+
readonly [zmdbPattern]?: S;
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* The named escape hatch. `ValidationRule.kind` is an open `string`, so a
|
|
242
|
+
* consumer can register a check the vocabulary does not model. The reflection
|
|
243
|
+
* records the name and emits a call to the registered predicate — it does not
|
|
244
|
+
* invent a check, and an unregistered name is a build error (plan D4).
|
|
245
|
+
*/
|
|
246
|
+
export type Rule<Name extends string> = {
|
|
247
|
+
readonly [zmdbRule]?: Name;
|
|
248
|
+
};
|
|
249
|
+
/** Protobuf field number. Required on every property of a protobuf message. */
|
|
250
|
+
export type ProtoField<N extends number> = {
|
|
251
|
+
readonly [zmdbProtoField]?: N;
|
|
252
|
+
};
|
|
253
|
+
/** Protobuf scalar spelling where TypeScript does not determine width or signedness. */
|
|
254
|
+
export type Proto<K extends ProtoScalar> = {
|
|
255
|
+
readonly [zmdbProtoScalar]?: K;
|
|
256
|
+
};
|
|
257
|
+
/** `Nullable<string>` is exactly `string | null`. No tag involved. */
|
|
258
|
+
export type Nullable<T> = T | null;
|
|
259
|
+
/** Non-null is the default; this exists for symmetry at the declaration site. */
|
|
260
|
+
export type NonNull<T> = Exclude<T, null | undefined>;
|
|
261
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tags/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @zmdb/schema/tags — the type-first declaration vocabulary.
|
|
2
|
+
//
|
|
3
|
+
// A domain type is declared as a plain interface plus these tags; everything else,
|
|
4
|
+
// the DTOs, the validators, the JSON Schema, the SQL — is derived from it.
|
|
5
|
+
//
|
|
6
|
+
// interface User extends Table<'users'> {
|
|
7
|
+
// id: number & Sql<'integer'> & Serial & PrimaryKey;
|
|
8
|
+
// email: string & Sql<'varchar'> & Length<255> & Unique;
|
|
9
|
+
// nickname: (string & MinLength<3>) | null;
|
|
10
|
+
// }
|
|
11
|
+
//
|
|
12
|
+
// Every established tag is an OPTIONAL unique-symbol slot, and all three parts carry
|
|
13
|
+
// weight:
|
|
14
|
+
//
|
|
15
|
+
// - `unique symbol` is un-forgeable and cannot collide with a real data
|
|
16
|
+
// property of the same name. A consumer cannot accidentally (or deliberately)
|
|
17
|
+
// synthesise `Serial` by typing a property.
|
|
18
|
+
// - `?` means no runtime value is ever required, so the tag erases completely.
|
|
19
|
+
// Zero bytes reach the output — asserted by `erasure.spec.ts`, which compiles
|
|
20
|
+
// a tagged declaration and its untagged twin and compares the emitted bytes.
|
|
21
|
+
// - an all-optional (weak) object type is not assignable from an unrelated
|
|
22
|
+
// type, which is what lets `T[K] extends Serial ? K : never` give an exact
|
|
23
|
+
// answer rather than a false positive.
|
|
24
|
+
//
|
|
25
|
+
// A tag only has to NAME a constraint, never prove it. There are no conditional
|
|
26
|
+
// types, no recursion and no template-literal arithmetic in this file, which is
|
|
27
|
+
// what makes "zero type-level computation" true by construction instead of by
|
|
28
|
+
// discipline.
|
|
29
|
+
//
|
|
30
|
+
// There is deliberately NO tag for nullability, optionality, enums, arrays,
|
|
31
|
+
// readonly-ness or nested JSON shape: TypeScript already expresses those as
|
|
32
|
+
// `| null`, `?`, a literal union, `T[]`, `readonly` and a nested interface, and
|
|
33
|
+
// the reflection reads them off the type directly.
|
|
34
|
+
//
|
|
35
|
+
// A note on duplicate installs (plan D5).
|
|
36
|
+
//
|
|
37
|
+
// `unique symbol` identity is nominal, so two *copies* of this module produce two
|
|
38
|
+
// non-matching tags even though their source text is identical. A key filter then
|
|
39
|
+
// collapses to `never`, and `never` is assignable to anything, so `CreateDTO`
|
|
40
|
+
// silently stops omitting a serial column and starts requiring it. Reflection is
|
|
41
|
+
// name-based and therefore immune, which would make the emitted validator disagree
|
|
42
|
+
// with the derived type — that asymmetry is the real hazard, not the duplicate
|
|
43
|
+
// itself.
|
|
44
|
+
//
|
|
45
|
+
// Nothing in this file can guard against it: a runtime check here would give the
|
|
46
|
+
// tags a runtime cost, which is the one thing they must not have. The guard belongs
|
|
47
|
+
// in the reflection, which can see the escaped symbol ids (`__@zmdbSerial@1` vs
|
|
48
|
+
// `__@zmdbSerial@12`) that the type system distinguishes, and refuses the build
|
|
49
|
+
// when one tag name resolves to two declarations. Until that lands,
|
|
50
|
+
// `duplicate-install.type-test.ts` pins the failure mode exactly — using `Equal`
|
|
51
|
+
// throughout, never assignability, for the reason given there.
|
|
52
|
+
import {} from '../index.js';
|
|
53
|
+
import {} from '../ir/index.js';
|
|
54
|
+
export {} from '../ir/index.js';
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Relation tags — cardinality plus the column that carries the join.
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
/**
|
|
59
|
+
* The four cardinalities. Listed once so `AnyRelation` cannot fall behind the tags — and
|
|
60
|
+
* listed in `../ir`, where the same four exist as data for the reflection to check against.
|
|
61
|
+
* Re-exported here because this is where a reader looking at the tags expects to find it.
|
|
62
|
+
*/
|
|
63
|
+
export {} from '../ir/index.js';
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tags/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,mFAAmF;AACnF,2EAA2E;AAC3E,EAAE;AACF,4CAA4C;AAC5C,yDAAyD;AACzD,6DAA6D;AAC7D,gDAAgD;AAChD,MAAM;AACN,EAAE;AACF,qFAAqF;AACrF,UAAU;AACV,EAAE;AACF,0EAA0E;AAC1E,kFAAkF;AAClF,gDAAgD;AAChD,iFAAiF;AACjF,kFAAkF;AAClF,iFAAiF;AACjF,6EAA6E;AAC7E,+EAA+E;AAC/E,2CAA2C;AAC3C,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,8EAA8E;AAC9E,cAAc;AACd,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,gFAAgF;AAChF,mDAAmD;AACnD,EAAE;AACF,0CAA0C;AAC1C,EAAE;AACF,kFAAkF;AAClF,kFAAkF;AAClF,8EAA8E;AAC9E,iFAAiF;AACjF,mFAAmF;AACnF,+EAA+E;AAC/E,UAAU;AACV,EAAE;AACF,iFAAiF;AACjF,oFAAoF;AACpF,gFAAgF;AAChF,gFAAgF;AAChF,oEAAoE;AACpE,iFAAiF;AACjF,+DAA+D;AAE/D,OAAO,EAAgB,MAAM,aAAa,CAAC;AAC3C,OAAO,EAA+D,MAAM,gBAAgB,CAAC;AAuH7F,OAAO,EAA0B,MAAM,gBAAgB,CAAC;AAmCxD,8EAA8E;AAC9E,qEAAqE;AACrE,8EAA8E;AAE9E;;;;GAIG;AACH,OAAO,EAAqB,MAAM,gBAAgB,CAAC"}
|