@danceroutine/tango-schema 0.1.0 → 1.0.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.
- package/LICENSE +21 -0
- package/README.md +122 -0
- package/dist/domain/DeleteReferentialAction.d.ts +1 -2
- package/dist/domain/Model.d.ts +17 -1
- package/dist/domain/ModelMetadata.d.ts +7 -0
- package/dist/domain/ModelWriteHooks.d.ts +82 -0
- package/dist/domain/UpdateReferentialAction.d.ts +1 -2
- package/dist/domain/index.d.ts +2 -1
- package/dist/domain-Cufz6y1q.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/model/ModelAugmentorRegistry.d.ts +11 -0
- package/dist/model/ModelDefinition.d.ts +12 -1
- package/dist/model/RelationBuilder.d.ts +6 -0
- package/dist/model/constraints/Constraints.d.ts +19 -0
- package/dist/model/constraints/Indexes.d.ts +4 -0
- package/dist/model/constraints/index.d.ts +6 -0
- package/dist/model/decorators/Decorators.d.ts +35 -0
- package/dist/model/decorators/index.d.ts +6 -0
- package/dist/model/decorators/types.d.ts +29 -0
- package/dist/model/index.d.ts +8 -0
- package/dist/model/index.js +2 -2
- package/dist/model/inferFields.d.ts +8 -1
- package/dist/model/internal/FieldMetadataStore.d.ts +3 -0
- package/dist/model/meta/Meta.d.ts +22 -0
- package/dist/model/meta/index.d.ts +5 -0
- package/dist/model/registry/ModelRegistry.d.ts +68 -0
- package/dist/model-DI8lQH1W.js +585 -0
- package/dist/model-DI8lQH1W.js.map +1 -0
- package/package.json +52 -50
- package/dist/domain/DeleteReferentialAction.js +0 -1
- package/dist/domain/Model.js +0 -1
- package/dist/domain/UpdateReferentialAction.js +0 -1
- package/dist/domain/internal/InternalFieldType.js +0 -10
- package/dist/domain/internal/InternalReferentialAction.d.ts +0 -6
- package/dist/domain/internal/InternalReferentialAction.js +0 -6
- package/dist/domain/internal/InternalRelationType.js +0 -5
- package/dist/domain/internal/ZodGuards.d.ts +0 -13
- package/dist/domain/internal/ZodGuards.js +0 -39
- package/dist/domain/internal/zod/hasConstructorName.js +0 -5
- package/dist/domain/internal/zod/index.js +0 -13
- package/dist/domain/internal/zod/isDate.js +0 -3
- package/dist/domain/internal/zod/isZodArray.js +0 -5
- package/dist/domain/internal/zod/isZodBoolean.js +0 -5
- package/dist/domain/internal/zod/isZodDate.js +0 -5
- package/dist/domain/internal/zod/isZodDefault.js +0 -5
- package/dist/domain/internal/zod/isZodNullable.js +0 -5
- package/dist/domain/internal/zod/isZodNumber.js +0 -5
- package/dist/domain/internal/zod/isZodObject.js +0 -5
- package/dist/domain/internal/zod/isZodOptional.js +0 -5
- package/dist/domain/internal/zod/isZodString.js +0 -5
- package/dist/model/Model.js +0 -22
- package/dist/model/ModelDefinition.js +0 -1
- package/dist/model/inferFields.js +0 -64
- package/dist/model-DE1qDItF.js +0 -174
- package/dist/model-DE1qDItF.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Pedro Del Moral Lopez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# @danceroutine/tango-schema
|
|
2
|
+
|
|
3
|
+
`@danceroutine/tango-schema` defines Tango models, structural metadata, and model-owned write lifecycle hooks.
|
|
4
|
+
|
|
5
|
+
A Tango model is the shared contract that the ORM, migrations, resources, OpenAPI generation, and code generation read from. The schema package keeps those layers aligned by giving them one model definition to build on.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @danceroutine/tango-schema zod
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
import { Model, t } from '@danceroutine/tango-schema';
|
|
18
|
+
|
|
19
|
+
const PostSchema = z.object({
|
|
20
|
+
id: t.primaryKey(z.number().int()),
|
|
21
|
+
title: z.string(),
|
|
22
|
+
slug: z.string(),
|
|
23
|
+
content: z.string(),
|
|
24
|
+
createdAt: z.string(),
|
|
25
|
+
updatedAt: z.string(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const PostModel = Model({
|
|
29
|
+
namespace: 'blog',
|
|
30
|
+
name: 'Post',
|
|
31
|
+
schema: PostSchema,
|
|
32
|
+
hooks: {
|
|
33
|
+
async beforeCreate({ data }) {
|
|
34
|
+
const now = new Date().toISOString();
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
...data,
|
|
38
|
+
createdAt: now,
|
|
39
|
+
updatedAt: now,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
async beforeUpdate({ patch }) {
|
|
43
|
+
return {
|
|
44
|
+
...patch,
|
|
45
|
+
updatedAt: new Date().toISOString(),
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`PostModel` becomes the source of truth for:
|
|
53
|
+
|
|
54
|
+
- field metadata and primary-key identity
|
|
55
|
+
- relation and index metadata
|
|
56
|
+
- migration generation
|
|
57
|
+
- `Model.objects` manager attachment in the ORM
|
|
58
|
+
- model-owned write lifecycle hooks
|
|
59
|
+
|
|
60
|
+
## Model lifecycle hooks
|
|
61
|
+
|
|
62
|
+
Model hooks live on the model definition through `hooks`. They run inside `Model.objects`, which means the same persistence rules apply across serializers, viewsets, scripts, and direct manager usage.
|
|
63
|
+
|
|
64
|
+
Use model hooks for persistence rules such as:
|
|
65
|
+
|
|
66
|
+
- timestamp stamping
|
|
67
|
+
- slug generation that should apply for every write path
|
|
68
|
+
- default persisted values
|
|
69
|
+
- normalization that belongs to the record itself
|
|
70
|
+
|
|
71
|
+
The write hook surface includes:
|
|
72
|
+
|
|
73
|
+
- `beforeCreate` and `afterCreate`
|
|
74
|
+
- `beforeUpdate` and `afterUpdate`
|
|
75
|
+
- `beforeDelete` and `afterDelete`
|
|
76
|
+
- `beforeBulkCreate` and `afterBulkCreate`
|
|
77
|
+
|
|
78
|
+
`before*` hooks may return normalized data to persist. `after*` hooks are for observation and side effects after the write succeeds.
|
|
79
|
+
|
|
80
|
+
## How the schema package fits with serializers
|
|
81
|
+
|
|
82
|
+
Serializers stay Zod-backed and continue to own request validation, update validation, and output representation.
|
|
83
|
+
|
|
84
|
+
Model hooks serve a different role. They hold persistence rules that should run for every caller of `Model.objects`, even when the write does not come from a resource.
|
|
85
|
+
|
|
86
|
+
That split keeps the model responsible for record lifecycle behavior while the serializer stays focused on the HTTP-facing contract.
|
|
87
|
+
|
|
88
|
+
## Public API
|
|
89
|
+
|
|
90
|
+
The root export includes:
|
|
91
|
+
|
|
92
|
+
- `Model`
|
|
93
|
+
- `RelationBuilder`
|
|
94
|
+
- `ModelRegistry`
|
|
95
|
+
- metadata helpers such as `t`, `m`, `c`, and `i`
|
|
96
|
+
- model and relation domain types
|
|
97
|
+
- model write hook types such as `ModelWriteHooks`
|
|
98
|
+
|
|
99
|
+
The root import is the normal entrypoint for application code. The `domain` and `model` subpaths are available when you want narrower imports.
|
|
100
|
+
|
|
101
|
+
## Documentation
|
|
102
|
+
|
|
103
|
+
- Official documentation: <https://tangowebframework.dev>
|
|
104
|
+
- Models and schema topic: <https://tangowebframework.dev/topics/models-and-schema>
|
|
105
|
+
- Model lifecycle hooks topic: <https://tangowebframework.dev/topics/model-lifecycle-hooks>
|
|
106
|
+
- Schema API reference: <https://tangowebframework.dev/reference/schema-api>
|
|
107
|
+
|
|
108
|
+
## Development
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pnpm --filter @danceroutine/tango-schema build
|
|
112
|
+
pnpm --filter @danceroutine/tango-schema typecheck
|
|
113
|
+
pnpm --filter @danceroutine/tango-schema test
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
For the wider contributor workflow, use:
|
|
117
|
+
|
|
118
|
+
- <https://tangowebframework.dev/contributing>
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export type DeleteReferentialAction = typeof InternalReferentialAction.CASCADE | typeof InternalReferentialAction.SET_NULL | typeof InternalReferentialAction.RESTRICT | typeof InternalReferentialAction.NO_ACTION;
|
|
1
|
+
export type DeleteReferentialAction = 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
|
package/dist/domain/Model.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
2
|
import type { ModelMetadata } from './ModelMetadata';
|
|
3
|
-
|
|
3
|
+
import type { ModelWriteHooks } from './ModelWriteHooks';
|
|
4
|
+
declare const MODEL_AUGMENTATION_SCHEMA: unique symbol;
|
|
5
|
+
type ModelAugmentationCarrier<TSchema extends z.ZodObject<z.ZodRawShape>> = {
|
|
6
|
+
readonly [MODEL_AUGMENTATION_SCHEMA]?: TSchema;
|
|
7
|
+
};
|
|
8
|
+
declare global {
|
|
9
|
+
interface TangoSchemaModelAugmentations<TSchema extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>> {
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export interface ModelAugmentations<TSchema extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>> extends ModelAugmentationCarrier<TSchema>, TangoSchemaModelAugmentations<TSchema> {
|
|
13
|
+
}
|
|
14
|
+
export interface Model<TSchema extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>> extends ModelAugmentations<TSchema> {
|
|
4
15
|
metadata: ModelMetadata;
|
|
5
16
|
schema: TSchema;
|
|
17
|
+
/**
|
|
18
|
+
* Model-owned write lifecycle hooks preserved from the definition.
|
|
19
|
+
*/
|
|
20
|
+
hooks?: ModelWriteHooks<z.output<TSchema>>;
|
|
6
21
|
}
|
|
22
|
+
export {};
|
|
@@ -2,8 +2,15 @@ import type { Field } from './Field';
|
|
|
2
2
|
import type { IndexDef } from './IndexDef';
|
|
3
3
|
import type { RelationDef } from './RelationDef';
|
|
4
4
|
export interface ModelMetadata {
|
|
5
|
+
namespace: string;
|
|
6
|
+
name: string;
|
|
7
|
+
key: string;
|
|
5
8
|
table: string;
|
|
6
9
|
fields: Field[];
|
|
7
10
|
indexes?: IndexDef[];
|
|
8
11
|
relations?: Record<string, RelationDef>;
|
|
12
|
+
ordering?: string[];
|
|
13
|
+
managed?: boolean;
|
|
14
|
+
defaultRelatedName?: string;
|
|
15
|
+
constraints?: unknown[];
|
|
9
16
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export interface ModelWriteHookManager<TModel extends Record<string, unknown>> {
|
|
2
|
+
create(input: Partial<TModel>): Promise<TModel>;
|
|
3
|
+
update(id: TModel[keyof TModel], patch: Partial<TModel>): Promise<TModel>;
|
|
4
|
+
delete(id: TModel[keyof TModel]): Promise<void>;
|
|
5
|
+
bulkCreate(inputs: Partial<TModel>[]): Promise<TModel[]>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Structural model contract passed into write lifecycle hooks.
|
|
9
|
+
*/
|
|
10
|
+
export interface ModelHookModel<TModel extends Record<string, unknown>> {
|
|
11
|
+
metadata: {
|
|
12
|
+
table: string;
|
|
13
|
+
};
|
|
14
|
+
schema: {
|
|
15
|
+
parse(input: unknown): TModel;
|
|
16
|
+
};
|
|
17
|
+
hooks?: ModelWriteHooks<TModel>;
|
|
18
|
+
}
|
|
19
|
+
export interface BeforeCreateHookArgs<TModel extends Record<string, unknown>> {
|
|
20
|
+
data: Partial<TModel>;
|
|
21
|
+
model: ModelHookModel<TModel>;
|
|
22
|
+
manager: ModelWriteHookManager<TModel>;
|
|
23
|
+
}
|
|
24
|
+
export interface AfterCreateHookArgs<TModel extends Record<string, unknown>> {
|
|
25
|
+
record: TModel;
|
|
26
|
+
model: ModelHookModel<TModel>;
|
|
27
|
+
manager: ModelWriteHookManager<TModel>;
|
|
28
|
+
}
|
|
29
|
+
export interface BeforeUpdateHookArgs<TModel extends Record<string, unknown>> {
|
|
30
|
+
id: TModel[keyof TModel];
|
|
31
|
+
patch: Partial<TModel>;
|
|
32
|
+
current: TModel;
|
|
33
|
+
model: ModelHookModel<TModel>;
|
|
34
|
+
manager: ModelWriteHookManager<TModel>;
|
|
35
|
+
}
|
|
36
|
+
export interface AfterUpdateHookArgs<TModel extends Record<string, unknown>> {
|
|
37
|
+
id: TModel[keyof TModel];
|
|
38
|
+
patch: Partial<TModel>;
|
|
39
|
+
previous: TModel;
|
|
40
|
+
record: TModel;
|
|
41
|
+
model: ModelHookModel<TModel>;
|
|
42
|
+
manager: ModelWriteHookManager<TModel>;
|
|
43
|
+
}
|
|
44
|
+
export interface BeforeDeleteHookArgs<TModel extends Record<string, unknown>> {
|
|
45
|
+
id: TModel[keyof TModel];
|
|
46
|
+
current: TModel;
|
|
47
|
+
model: ModelHookModel<TModel>;
|
|
48
|
+
manager: ModelWriteHookManager<TModel>;
|
|
49
|
+
}
|
|
50
|
+
export interface AfterDeleteHookArgs<TModel extends Record<string, unknown>> {
|
|
51
|
+
id: TModel[keyof TModel];
|
|
52
|
+
previous: TModel;
|
|
53
|
+
model: ModelHookModel<TModel>;
|
|
54
|
+
manager: ModelWriteHookManager<TModel>;
|
|
55
|
+
}
|
|
56
|
+
export interface BeforeBulkCreateHookArgs<TModel extends Record<string, unknown>> {
|
|
57
|
+
rows: Partial<TModel>[];
|
|
58
|
+
model: ModelHookModel<TModel>;
|
|
59
|
+
manager: ModelWriteHookManager<TModel>;
|
|
60
|
+
}
|
|
61
|
+
export interface AfterBulkCreateHookArgs<TModel extends Record<string, unknown>> {
|
|
62
|
+
records: TModel[];
|
|
63
|
+
model: ModelHookModel<TModel>;
|
|
64
|
+
manager: ModelWriteHookManager<TModel>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Async-capable model-owned write lifecycle hooks.
|
|
68
|
+
*
|
|
69
|
+
* Use model hooks for persistence rules that should apply everywhere the model
|
|
70
|
+
* is written, including serializers, viewsets, scripts, and direct manager
|
|
71
|
+
* calls.
|
|
72
|
+
*/
|
|
73
|
+
export interface ModelWriteHooks<TModel extends Record<string, unknown>> {
|
|
74
|
+
beforeCreate?(args: BeforeCreateHookArgs<TModel>): Promise<Partial<TModel> | void> | Partial<TModel> | void;
|
|
75
|
+
afterCreate?(args: AfterCreateHookArgs<TModel>): Promise<void> | void;
|
|
76
|
+
beforeUpdate?(args: BeforeUpdateHookArgs<TModel>): Promise<Partial<TModel> | void> | Partial<TModel> | void;
|
|
77
|
+
afterUpdate?(args: AfterUpdateHookArgs<TModel>): Promise<void> | void;
|
|
78
|
+
beforeDelete?(args: BeforeDeleteHookArgs<TModel>): Promise<void> | void;
|
|
79
|
+
afterDelete?(args: AfterDeleteHookArgs<TModel>): Promise<void> | void;
|
|
80
|
+
beforeBulkCreate?(args: BeforeBulkCreateHookArgs<TModel>): Promise<Partial<TModel>[] | void> | Partial<TModel>[] | void;
|
|
81
|
+
afterBulkCreate?(args: AfterBulkCreateHookArgs<TModel>): Promise<void> | void;
|
|
82
|
+
}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export type UpdateReferentialAction = typeof InternalReferentialAction.CASCADE | typeof InternalReferentialAction.RESTRICT | typeof InternalReferentialAction.NO_ACTION;
|
|
1
|
+
export type UpdateReferentialAction = 'CASCADE' | 'RESTRICT' | 'NO ACTION';
|
package/dist/domain/index.d.ts
CHANGED
|
@@ -9,4 +9,5 @@ export type { Field } from './Field';
|
|
|
9
9
|
export type { IndexDef } from './IndexDef';
|
|
10
10
|
export type { RelationDef } from './RelationDef';
|
|
11
11
|
export type { ModelMetadata } from './ModelMetadata';
|
|
12
|
-
export type { Model } from './Model';
|
|
12
|
+
export type { Model, ModelAugmentations } from './Model';
|
|
13
|
+
export type { ModelHookModel, ModelWriteHookManager, ModelWriteHooks, BeforeCreateHookArgs, AfterCreateHookArgs, BeforeUpdateHookArgs, AfterUpdateHookArgs, BeforeDeleteHookArgs, AfterDeleteHookArgs, BeforeBulkCreateHookArgs, AfterBulkCreateHookArgs, } from './ModelWriteHooks';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-Cufz6y1q.js","names":[],"sources":["../src/domain/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport type { FieldType } from './FieldType';\nexport type { DeleteReferentialAction } from './DeleteReferentialAction';\nexport type { UpdateReferentialAction } from './UpdateReferentialAction';\nexport type { RelationType } from './RelationType';\nexport type { Field } from './Field';\nexport type { IndexDef } from './IndexDef';\nexport type { RelationDef } from './RelationDef';\nexport type { ModelMetadata } from './ModelMetadata';\nexport type { Model } from './Model';\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"domain-Cufz6y1q.js","names":[],"sources":["../src/domain/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport type { FieldType } from './FieldType';\nexport type { DeleteReferentialAction } from './DeleteReferentialAction';\nexport type { UpdateReferentialAction } from './UpdateReferentialAction';\nexport type { RelationType } from './RelationType';\nexport type { Field } from './Field';\nexport type { IndexDef } from './IndexDef';\nexport type { RelationDef } from './RelationDef';\nexport type { ModelMetadata } from './ModelMetadata';\nexport type { Model, ModelAugmentations } from './Model';\nexport type {\n ModelHookModel,\n ModelWriteHookManager,\n ModelWriteHooks,\n BeforeCreateHookArgs,\n AfterCreateHookArgs,\n BeforeUpdateHookArgs,\n AfterUpdateHookArgs,\n BeforeDeleteHookArgs,\n AfterDeleteHookArgs,\n BeforeBulkCreateHookArgs,\n AfterBulkCreateHookArgs,\n} from './ModelWriteHooks';\n"],"mappings":""}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export * as domain from './domain/index';
|
|
6
6
|
export * as model from './model/index';
|
|
7
|
-
export type { DeleteReferentialAction, Field, FieldType, IndexDef, ModelMetadata, RelationDef, RelationType, UpdateReferentialAction, } from './domain/index';
|
|
8
|
-
export { Model, RelationBuilder, type ModelDefinition } from './model/index';
|
|
7
|
+
export type { DeleteReferentialAction, Field, FieldType, IndexDef, ModelHookModel, ModelAugmentations, ModelMetadata, ModelWriteHookManager, ModelWriteHooks, BeforeCreateHookArgs, AfterCreateHookArgs, BeforeUpdateHookArgs, AfterUpdateHookArgs, BeforeDeleteHookArgs, AfterDeleteHookArgs, BeforeBulkCreateHookArgs, AfterBulkCreateHookArgs, RelationDef, RelationType, UpdateReferentialAction, } from './domain/index';
|
|
8
|
+
export { Model, RelationBuilder, ModelRegistry, registerModelAugmentor, Constraints, Decorators, Indexes, Meta, c, i, m, t, type ModelDefinition, } from './model/index';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Model, RelationBuilder, model_exports } from "./model-
|
|
1
|
+
import { Constraints, Decorators, Indexes, Meta, Model, ModelRegistry, RelationBuilder, model_exports, registerModelAugmentor } from "./model-DI8lQH1W.js";
|
|
2
2
|
import { domain_exports } from "./domain-Cufz6y1q.js";
|
|
3
3
|
|
|
4
|
-
export { Model, RelationBuilder, domain_exports as domain, model_exports as model };
|
|
4
|
+
export { Constraints, Decorators, Indexes, Meta, Model, ModelRegistry, RelationBuilder, Constraints as c, domain_exports as domain, Indexes as i, Meta as m, model_exports as model, registerModelAugmentor, Decorators as t };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { Model } from '../domain/Model';
|
|
3
|
+
export type ModelAugmentor = <TSchema extends z.ZodObject<z.ZodRawShape>>(model: Model<TSchema>) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Register a model augmentor that runs for existing and future models.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerModelAugmentor(augmentor: ModelAugmentor): () => void;
|
|
8
|
+
/**
|
|
9
|
+
* Apply all registered augmentors to a model before it is returned publicly.
|
|
10
|
+
*/
|
|
11
|
+
export declare function applyModelAugmentors<TSchema extends z.ZodObject<z.ZodRawShape>>(model: Model<TSchema>): Model<TSchema>;
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { Field, IndexDef, RelationDef } from '../domain/index';
|
|
3
|
+
import type { ModelWriteHooks } from '../domain/index';
|
|
3
4
|
import type { RelationBuilder } from './RelationBuilder';
|
|
4
5
|
export interface ModelDefinition<TSchema extends z.ZodObject<z.ZodRawShape>> {
|
|
5
|
-
|
|
6
|
+
namespace: string;
|
|
7
|
+
name: string;
|
|
8
|
+
table?: string;
|
|
6
9
|
schema: TSchema;
|
|
7
10
|
fields?: Field[];
|
|
8
11
|
indexes?: IndexDef[];
|
|
9
12
|
relations?: (builder: RelationBuilder) => Record<string, RelationDef>;
|
|
13
|
+
ordering?: string[];
|
|
14
|
+
managed?: boolean;
|
|
15
|
+
defaultRelatedName?: string;
|
|
16
|
+
constraints?: unknown[];
|
|
17
|
+
/**
|
|
18
|
+
* Model-owned write lifecycle hooks that run inside `Model.objects`.
|
|
19
|
+
*/
|
|
20
|
+
hooks?: ModelWriteHooks<z.output<TSchema>>;
|
|
10
21
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { RelationDef } from '../domain/index';
|
|
2
|
+
/**
|
|
3
|
+
* Fluent helper for declaring model relation metadata.
|
|
4
|
+
*/
|
|
2
5
|
export declare class RelationBuilder {
|
|
6
|
+
/** Declare a one-to-many relation from this model to `target`. */
|
|
3
7
|
hasMany(target: string, foreignKey: string): RelationDef;
|
|
8
|
+
/** Declare an owning relation to a parent model. */
|
|
4
9
|
belongsTo(target: string, foreignKey: string, localKey?: string): RelationDef;
|
|
10
|
+
/** Declare a one-to-one relation from this model to `target`. */
|
|
5
11
|
hasOne(target: string, foreignKey: string): RelationDef;
|
|
6
12
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ConstraintDefinition = {
|
|
2
|
+
kind: string;
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
};
|
|
5
|
+
export declare const Constraints: {
|
|
6
|
+
unique(fields: string[], options?: {
|
|
7
|
+
name?: string;
|
|
8
|
+
where?: string;
|
|
9
|
+
}): ConstraintDefinition;
|
|
10
|
+
check(condition: string, options?: {
|
|
11
|
+
name?: string;
|
|
12
|
+
}): ConstraintDefinition;
|
|
13
|
+
exclusion(definition: {
|
|
14
|
+
using?: string;
|
|
15
|
+
elements: string[];
|
|
16
|
+
where?: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
}): ConstraintDefinition;
|
|
19
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ModelRef, ReferentialOptions, ZodTypeAny } from './types';
|
|
3
|
+
type UnaryFieldDecorator = {
|
|
4
|
+
<T extends ZodTypeAny>(schema: T): T;
|
|
5
|
+
<T extends ZodTypeAny>(): (input: T) => T;
|
|
6
|
+
};
|
|
7
|
+
type RelationshipDecorator = {
|
|
8
|
+
<T extends ZodTypeAny>(target: ModelRef, schema: T, options?: ReferentialOptions): T;
|
|
9
|
+
(target: ModelRef, options?: ReferentialOptions): z.ZodNumber;
|
|
10
|
+
};
|
|
11
|
+
type ManyToManyDecorator = {
|
|
12
|
+
<T extends ZodTypeAny>(target: ModelRef, schema: T): T;
|
|
13
|
+
(target: ModelRef): z.ZodArray<z.ZodNumber>;
|
|
14
|
+
};
|
|
15
|
+
export interface TangoDecorators {
|
|
16
|
+
primaryKey: UnaryFieldDecorator;
|
|
17
|
+
unique: UnaryFieldDecorator;
|
|
18
|
+
null: UnaryFieldDecorator;
|
|
19
|
+
notNull: UnaryFieldDecorator;
|
|
20
|
+
default: <T extends ZodTypeAny>(schema: T, value: string | {
|
|
21
|
+
now: true;
|
|
22
|
+
} | null) => T;
|
|
23
|
+
dbDefault: <T extends ZodTypeAny>(schema: T, value: string) => T;
|
|
24
|
+
dbColumn: <T extends ZodTypeAny>(schema: T, name: string) => T;
|
|
25
|
+
dbIndex: <T extends ZodTypeAny>(schema: T) => T;
|
|
26
|
+
choices: <T extends ZodTypeAny>(schema: T, values: readonly unknown[]) => T;
|
|
27
|
+
validators: <T extends ZodTypeAny>(schema: T, ...values: readonly ((value: unknown) => unknown)[]) => T;
|
|
28
|
+
helpText: <T extends ZodTypeAny>(schema: T, text: string) => T;
|
|
29
|
+
errorMessages: <T extends ZodTypeAny>(schema: T, map: Record<string, string>) => T;
|
|
30
|
+
foreignKey: RelationshipDecorator;
|
|
31
|
+
oneToOne: RelationshipDecorator;
|
|
32
|
+
manyToMany: ManyToManyDecorator;
|
|
33
|
+
}
|
|
34
|
+
export declare const Decorators: TangoDecorators;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain boundary barrel: centralizes this subdomain's public contract.
|
|
3
|
+
*/
|
|
4
|
+
export { Decorators, Decorators as t } from './Decorators';
|
|
5
|
+
export type { TangoDecorators } from './Decorators';
|
|
6
|
+
export type { ModelRef, ReferentialOptions, TangoFieldMeta, ZodTypeAny } from './types';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { DeleteReferentialAction, Model, UpdateReferentialAction } from '../../domain/index';
|
|
3
|
+
export type ModelRef = string | Model | (() => Model);
|
|
4
|
+
export interface ReferentialOptions {
|
|
5
|
+
column?: string;
|
|
6
|
+
onDelete?: DeleteReferentialAction;
|
|
7
|
+
onUpdate?: UpdateReferentialAction;
|
|
8
|
+
}
|
|
9
|
+
export interface TangoFieldMeta {
|
|
10
|
+
primaryKey?: boolean;
|
|
11
|
+
unique?: boolean;
|
|
12
|
+
notNull?: boolean;
|
|
13
|
+
dbIndex?: boolean;
|
|
14
|
+
dbColumn?: string;
|
|
15
|
+
default?: string | {
|
|
16
|
+
now: true;
|
|
17
|
+
} | null;
|
|
18
|
+
dbDefault?: string;
|
|
19
|
+
helpText?: string;
|
|
20
|
+
choices?: readonly unknown[];
|
|
21
|
+
validators?: readonly ((value: unknown) => unknown)[];
|
|
22
|
+
errorMessages?: Record<string, string>;
|
|
23
|
+
references?: {
|
|
24
|
+
target: ModelRef;
|
|
25
|
+
options?: ReferentialOptions;
|
|
26
|
+
};
|
|
27
|
+
relationKind?: 'foreignKey' | 'oneToOne' | 'manyToMany';
|
|
28
|
+
}
|
|
29
|
+
export type ZodTypeAny = z.ZodTypeAny;
|
package/dist/model/index.d.ts
CHANGED
|
@@ -4,3 +4,11 @@
|
|
|
4
4
|
export type { ModelDefinition } from './ModelDefinition';
|
|
5
5
|
export { RelationBuilder } from './RelationBuilder';
|
|
6
6
|
export { Model } from './Model';
|
|
7
|
+
export { registerModelAugmentor } from './ModelAugmentorRegistry';
|
|
8
|
+
export { Decorators, t } from './decorators/index';
|
|
9
|
+
export type { TangoDecorators } from './decorators/index';
|
|
10
|
+
export { Meta, m } from './meta/index';
|
|
11
|
+
export type { ModelConstraint, ModelMetaFragment } from './meta/index';
|
|
12
|
+
export { Constraints, Indexes, c, i } from './constraints/index';
|
|
13
|
+
export type { ConstraintDefinition } from './constraints/index';
|
|
14
|
+
export { ModelRegistry } from './registry/ModelRegistry';
|
package/dist/model/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Model, RelationBuilder } from "../model-
|
|
1
|
+
import { Constraints, Decorators, Indexes, Meta, Model, ModelRegistry, RelationBuilder, registerModelAugmentor } from "../model-DI8lQH1W.js";
|
|
2
2
|
|
|
3
|
-
export { Model, RelationBuilder };
|
|
3
|
+
export { Constraints, Decorators, Indexes, Meta, Model, ModelRegistry, RelationBuilder, Constraints as c, Indexes as i, Meta as m, registerModelAugmentor, Decorators as t };
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { Field } from '../domain/index';
|
|
3
|
-
|
|
3
|
+
import { ModelRegistry } from './registry/ModelRegistry';
|
|
4
|
+
export type InferFieldsOptions = {
|
|
5
|
+
registry?: ModelRegistry;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Infer Tango field metadata from a Zod object schema and any attached field decorators.
|
|
9
|
+
*/
|
|
10
|
+
export declare function inferFieldsFromSchema(schema: z.ZodObject<z.ZodRawShape>, options?: InferFieldsOptions): Field[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IndexDef } from '../../domain/index';
|
|
2
|
+
export type ModelConstraint = {
|
|
3
|
+
kind: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
export type ModelMetaFragment = {
|
|
7
|
+
ordering?: string[];
|
|
8
|
+
managed?: boolean;
|
|
9
|
+
defaultRelatedName?: string;
|
|
10
|
+
indexes?: IndexDef[];
|
|
11
|
+
constraints?: ModelConstraint[];
|
|
12
|
+
};
|
|
13
|
+
export declare const Meta: {
|
|
14
|
+
ordering(...fields: string[]): ModelMetaFragment;
|
|
15
|
+
managed(value: boolean): ModelMetaFragment;
|
|
16
|
+
defaultRelatedName(value: string): ModelMetaFragment;
|
|
17
|
+
indexes(...indexes: IndexDef[]): ModelMetaFragment;
|
|
18
|
+
constraints(...constraints: ModelConstraint[]): ModelMetaFragment;
|
|
19
|
+
uniqueTogether(...sets: string[][]): ModelMetaFragment;
|
|
20
|
+
indexTogether(...sets: string[][]): ModelMetaFragment;
|
|
21
|
+
merge(...fragments: readonly ModelMetaFragment[]): ModelMetaFragment;
|
|
22
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Model } from '../../domain/index';
|
|
2
|
+
import type { ModelRef } from '../decorators/types';
|
|
3
|
+
/**
|
|
4
|
+
* Registry that resolves Tango models by stable identity.
|
|
5
|
+
*
|
|
6
|
+
* The global registry is convenient for application bootstrapping, while
|
|
7
|
+
* dedicated instances are useful in tests and tooling.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ModelRegistry {
|
|
10
|
+
private static globalRegistry?;
|
|
11
|
+
private readonly models;
|
|
12
|
+
/**
|
|
13
|
+
* Return the shared process-wide registry used by `Model(...)`.
|
|
14
|
+
*/
|
|
15
|
+
static global(): ModelRegistry;
|
|
16
|
+
/**
|
|
17
|
+
* Register a model on the shared global registry.
|
|
18
|
+
*/
|
|
19
|
+
static register(model: Model): void;
|
|
20
|
+
/**
|
|
21
|
+
* Register several models on the shared global registry.
|
|
22
|
+
*/
|
|
23
|
+
static registerMany(models: readonly Model[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a model from the shared registry by namespace and name.
|
|
26
|
+
*/
|
|
27
|
+
static get(namespace: string, name: string): Model | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a model from the shared registry by its `namespace/name` key.
|
|
30
|
+
*/
|
|
31
|
+
static getByKey(key: string): Model | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve any supported model reference form against the shared registry.
|
|
34
|
+
*/
|
|
35
|
+
static resolveRef(ref: ModelRef): Model;
|
|
36
|
+
/**
|
|
37
|
+
* Clear the shared registry, which is mainly useful in tests.
|
|
38
|
+
*/
|
|
39
|
+
static clear(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Register a model on this registry instance.
|
|
42
|
+
*/
|
|
43
|
+
register(model: Model): void;
|
|
44
|
+
/**
|
|
45
|
+
* Register several models on this registry instance.
|
|
46
|
+
*/
|
|
47
|
+
registerMany(models: readonly Model[]): void;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a model from this registry instance by namespace and name.
|
|
50
|
+
*/
|
|
51
|
+
get(namespace: string, name: string): Model | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve a model from this registry instance by its `namespace/name` key.
|
|
54
|
+
*/
|
|
55
|
+
getByKey(key: string): Model | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a string, callback, or direct model reference into a model object.
|
|
58
|
+
*/
|
|
59
|
+
resolveRef(ref: ModelRef): Model;
|
|
60
|
+
/**
|
|
61
|
+
* Remove all registered models from this registry instance.
|
|
62
|
+
*/
|
|
63
|
+
clear(): void;
|
|
64
|
+
/**
|
|
65
|
+
* Return all registered models in insertion order.
|
|
66
|
+
*/
|
|
67
|
+
values(): readonly Model[];
|
|
68
|
+
}
|