@danceroutine/tango-schema 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 (62) hide show
  1. package/dist/domain/DeleteReferentialAction.d.ts +2 -0
  2. package/dist/domain/DeleteReferentialAction.js +1 -0
  3. package/dist/domain/Field.d.ts +20 -0
  4. package/dist/domain/FieldType.d.ts +2 -0
  5. package/dist/domain/IndexDef.d.ts +6 -0
  6. package/dist/domain/Model.d.ts +6 -0
  7. package/dist/domain/Model.js +1 -0
  8. package/dist/domain/ModelMetadata.d.ts +9 -0
  9. package/dist/domain/RelationDef.d.ts +7 -0
  10. package/dist/domain/RelationType.d.ts +2 -0
  11. package/dist/domain/UpdateReferentialAction.d.ts +2 -0
  12. package/dist/domain/UpdateReferentialAction.js +1 -0
  13. package/dist/domain/index.d.ts +12 -0
  14. package/dist/domain/index.js +1 -0
  15. package/dist/domain/internal/InternalFieldType.d.ts +10 -0
  16. package/dist/domain/internal/InternalFieldType.js +10 -0
  17. package/dist/domain/internal/InternalReferentialAction.d.ts +6 -0
  18. package/dist/domain/internal/InternalReferentialAction.js +6 -0
  19. package/dist/domain/internal/InternalRelationType.d.ts +5 -0
  20. package/dist/domain/internal/InternalRelationType.js +5 -0
  21. package/dist/domain/internal/ZodGuards.d.ts +13 -0
  22. package/dist/domain/internal/ZodGuards.js +39 -0
  23. package/dist/domain/internal/zod/hasConstructorName.d.ts +1 -0
  24. package/dist/domain/internal/zod/hasConstructorName.js +5 -0
  25. package/dist/domain/internal/zod/index.d.ts +13 -0
  26. package/dist/domain/internal/zod/index.js +13 -0
  27. package/dist/domain/internal/zod/isDate.d.ts +1 -0
  28. package/dist/domain/internal/zod/isDate.js +3 -0
  29. package/dist/domain/internal/zod/isZodArray.d.ts +2 -0
  30. package/dist/domain/internal/zod/isZodArray.js +5 -0
  31. package/dist/domain/internal/zod/isZodBoolean.d.ts +2 -0
  32. package/dist/domain/internal/zod/isZodBoolean.js +5 -0
  33. package/dist/domain/internal/zod/isZodDate.d.ts +2 -0
  34. package/dist/domain/internal/zod/isZodDate.js +5 -0
  35. package/dist/domain/internal/zod/isZodDefault.d.ts +2 -0
  36. package/dist/domain/internal/zod/isZodDefault.js +5 -0
  37. package/dist/domain/internal/zod/isZodNullable.d.ts +2 -0
  38. package/dist/domain/internal/zod/isZodNullable.js +5 -0
  39. package/dist/domain/internal/zod/isZodNumber.d.ts +2 -0
  40. package/dist/domain/internal/zod/isZodNumber.js +5 -0
  41. package/dist/domain/internal/zod/isZodObject.d.ts +2 -0
  42. package/dist/domain/internal/zod/isZodObject.js +5 -0
  43. package/dist/domain/internal/zod/isZodOptional.d.ts +2 -0
  44. package/dist/domain/internal/zod/isZodOptional.js +5 -0
  45. package/dist/domain/internal/zod/isZodString.d.ts +2 -0
  46. package/dist/domain/internal/zod/isZodString.js +5 -0
  47. package/dist/domain-Cufz6y1q.js +7 -0
  48. package/dist/domain-Cufz6y1q.js.map +1 -0
  49. package/dist/index.d.ts +8 -0
  50. package/dist/index.js +4 -0
  51. package/dist/model/Model.d.ts +8 -0
  52. package/dist/model/Model.js +22 -0
  53. package/dist/model/ModelDefinition.d.ts +10 -0
  54. package/dist/model/ModelDefinition.js +1 -0
  55. package/dist/model/RelationBuilder.d.ts +6 -0
  56. package/dist/model/index.d.ts +6 -0
  57. package/dist/model/index.js +3 -0
  58. package/dist/model/inferFields.d.ts +3 -0
  59. package/dist/model/inferFields.js +64 -0
  60. package/dist/model-DE1qDItF.js +174 -0
  61. package/dist/model-DE1qDItF.js.map +1 -0
  62. package/package.json +54 -0
@@ -0,0 +1,2 @@
1
+ import { InternalReferentialAction } from './internal/InternalReferentialAction';
2
+ export type DeleteReferentialAction = typeof InternalReferentialAction.CASCADE | typeof InternalReferentialAction.SET_NULL | typeof InternalReferentialAction.RESTRICT | typeof InternalReferentialAction.NO_ACTION;
@@ -0,0 +1 @@
1
+ import { InternalReferentialAction } from './internal/InternalReferentialAction';
@@ -0,0 +1,20 @@
1
+ import type { FieldType } from './FieldType';
2
+ import type { DeleteReferentialAction } from './DeleteReferentialAction';
3
+ import type { UpdateReferentialAction } from './UpdateReferentialAction';
4
+ export interface Field {
5
+ name: string;
6
+ type: FieldType;
7
+ notNull?: boolean;
8
+ default?: string | {
9
+ now: true;
10
+ } | null;
11
+ primaryKey?: boolean;
12
+ unique?: boolean;
13
+ references?: {
14
+ table: string;
15
+ column: string;
16
+ onDelete?: DeleteReferentialAction;
17
+ onUpdate?: UpdateReferentialAction;
18
+ };
19
+ renameFrom?: string;
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { InternalFieldType } from './internal/InternalFieldType';
2
+ export type FieldType = (typeof InternalFieldType)[keyof typeof InternalFieldType];
@@ -0,0 +1,6 @@
1
+ export interface IndexDef {
2
+ name: string;
3
+ on: string[];
4
+ unique?: boolean;
5
+ where?: string;
6
+ }
@@ -0,0 +1,6 @@
1
+ import type { z } from 'zod';
2
+ import type { ModelMetadata } from './ModelMetadata';
3
+ export interface Model<TSchema extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>> {
4
+ metadata: ModelMetadata;
5
+ schema: TSchema;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { Field } from './Field';
2
+ import type { IndexDef } from './IndexDef';
3
+ import type { RelationDef } from './RelationDef';
4
+ export interface ModelMetadata {
5
+ table: string;
6
+ fields: Field[];
7
+ indexes?: IndexDef[];
8
+ relations?: Record<string, RelationDef>;
9
+ }
@@ -0,0 +1,7 @@
1
+ import type { RelationType } from './RelationType';
2
+ export interface RelationDef {
3
+ type: RelationType;
4
+ target: string;
5
+ foreignKey: string;
6
+ localKey?: string;
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { InternalRelationType } from './internal/InternalRelationType';
2
+ export type RelationType = (typeof InternalRelationType)[keyof typeof InternalRelationType];
@@ -0,0 +1,2 @@
1
+ import { InternalReferentialAction } from './internal/InternalReferentialAction';
2
+ export type UpdateReferentialAction = typeof InternalReferentialAction.CASCADE | typeof InternalReferentialAction.RESTRICT | typeof InternalReferentialAction.NO_ACTION;
@@ -0,0 +1 @@
1
+ import { InternalReferentialAction } from './internal/InternalReferentialAction';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Domain boundary barrel: centralizes this subdomain's public contract.
3
+ */
4
+ export type { FieldType } from './FieldType';
5
+ export type { DeleteReferentialAction } from './DeleteReferentialAction';
6
+ export type { UpdateReferentialAction } from './UpdateReferentialAction';
7
+ export type { RelationType } from './RelationType';
8
+ export type { Field } from './Field';
9
+ export type { IndexDef } from './IndexDef';
10
+ export type { RelationDef } from './RelationDef';
11
+ export type { ModelMetadata } from './ModelMetadata';
12
+ export type { Model } from './Model';
@@ -0,0 +1 @@
1
+ import "../domain-Cufz6y1q.js";
@@ -0,0 +1,10 @@
1
+ export declare const InternalFieldType: {
2
+ readonly SERIAL: "serial";
3
+ readonly INT: "int";
4
+ readonly BIGINT: "bigint";
5
+ readonly TEXT: "text";
6
+ readonly BOOL: "bool";
7
+ readonly TIMESTAMPTZ: "timestamptz";
8
+ readonly JSONB: "jsonb";
9
+ readonly UUID: "uuid";
10
+ };
@@ -0,0 +1,10 @@
1
+ export const InternalFieldType = {
2
+ SERIAL: 'serial',
3
+ INT: 'int',
4
+ BIGINT: 'bigint',
5
+ TEXT: 'text',
6
+ BOOL: 'bool',
7
+ TIMESTAMPTZ: 'timestamptz',
8
+ JSONB: 'jsonb',
9
+ UUID: 'uuid',
10
+ };
@@ -0,0 +1,6 @@
1
+ export declare const InternalReferentialAction: {
2
+ readonly CASCADE: "CASCADE";
3
+ readonly SET_NULL: "SET NULL";
4
+ readonly RESTRICT: "RESTRICT";
5
+ readonly NO_ACTION: "NO ACTION";
6
+ };
@@ -0,0 +1,6 @@
1
+ export const InternalReferentialAction = {
2
+ CASCADE: 'CASCADE',
3
+ SET_NULL: 'SET NULL',
4
+ RESTRICT: 'RESTRICT',
5
+ NO_ACTION: 'NO ACTION',
6
+ };
@@ -0,0 +1,5 @@
1
+ export declare const InternalRelationType: {
2
+ readonly HAS_MANY: "hasMany";
3
+ readonly BELONGS_TO: "belongsTo";
4
+ readonly HAS_ONE: "hasOne";
5
+ };
@@ -0,0 +1,5 @@
1
+ export const InternalRelationType = {
2
+ HAS_MANY: 'hasMany',
3
+ BELONGS_TO: 'belongsTo',
4
+ HAS_ONE: 'hasOne',
5
+ };
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ export declare class ZodGuards {
3
+ static isZodOptional(value: unknown): value is z.ZodOptional<z.ZodTypeAny>;
4
+ static isZodNullable(value: unknown): value is z.ZodNullable<z.ZodTypeAny>;
5
+ static isZodDefault(value: unknown): value is z.ZodDefault<z.ZodTypeAny>;
6
+ static isZodString(value: unknown): value is z.ZodString;
7
+ static isZodNumber(value: unknown): value is z.ZodNumber;
8
+ static isZodBoolean(value: unknown): value is z.ZodBoolean;
9
+ static isZodDate(value: unknown): value is z.ZodDate;
10
+ static isZodObject(value: unknown): value is z.ZodObject<z.ZodRawShape>;
11
+ static isZodArray(value: unknown): value is z.ZodArray<z.ZodTypeAny>;
12
+ static isDate(value: unknown): value is Date;
13
+ }
@@ -0,0 +1,39 @@
1
+ import { z } from 'zod';
2
+ function hasConstructorName(value, name) {
3
+ return (!!value &&
4
+ typeof value === 'object' &&
5
+ value.constructor?.name === name);
6
+ }
7
+ // TODO not sure this justifies being a class, typeguards being handled as first class functions would be better
8
+ export class ZodGuards {
9
+ static isZodOptional(value) {
10
+ return hasConstructorName(value, 'ZodOptional');
11
+ }
12
+ static isZodNullable(value) {
13
+ return hasConstructorName(value, 'ZodNullable');
14
+ }
15
+ static isZodDefault(value) {
16
+ return hasConstructorName(value, 'ZodDefault');
17
+ }
18
+ static isZodString(value) {
19
+ return hasConstructorName(value, 'ZodString');
20
+ }
21
+ static isZodNumber(value) {
22
+ return hasConstructorName(value, 'ZodNumber');
23
+ }
24
+ static isZodBoolean(value) {
25
+ return hasConstructorName(value, 'ZodBoolean');
26
+ }
27
+ static isZodDate(value) {
28
+ return hasConstructorName(value, 'ZodDate');
29
+ }
30
+ static isZodObject(value) {
31
+ return hasConstructorName(value, 'ZodObject');
32
+ }
33
+ static isZodArray(value) {
34
+ return hasConstructorName(value, 'ZodArray');
35
+ }
36
+ static isDate(value) {
37
+ return value != null && Object.prototype.toString.call(value) === '[object Date]';
38
+ }
39
+ }
@@ -0,0 +1 @@
1
+ export declare function hasConstructorName(value: unknown, name: string): boolean;
@@ -0,0 +1,5 @@
1
+ export function hasConstructorName(value, name) {
2
+ return (!!value &&
3
+ typeof value === 'object' &&
4
+ value.constructor?.name === name);
5
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Domain boundary barrel: centralizes this subdomain's public contract.
3
+ */
4
+ export { isDate } from './isDate';
5
+ export { isZodArray } from './isZodArray';
6
+ export { isZodBoolean } from './isZodBoolean';
7
+ export { isZodDate } from './isZodDate';
8
+ export { isZodDefault } from './isZodDefault';
9
+ export { isZodNullable } from './isZodNullable';
10
+ export { isZodNumber } from './isZodNumber';
11
+ export { isZodObject } from './isZodObject';
12
+ export { isZodOptional } from './isZodOptional';
13
+ export { isZodString } from './isZodString';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Domain boundary barrel: centralizes this subdomain's public contract.
3
+ */
4
+ export { isDate } from './isDate';
5
+ export { isZodArray } from './isZodArray';
6
+ export { isZodBoolean } from './isZodBoolean';
7
+ export { isZodDate } from './isZodDate';
8
+ export { isZodDefault } from './isZodDefault';
9
+ export { isZodNullable } from './isZodNullable';
10
+ export { isZodNumber } from './isZodNumber';
11
+ export { isZodObject } from './isZodObject';
12
+ export { isZodOptional } from './isZodOptional';
13
+ export { isZodString } from './isZodString';
@@ -0,0 +1 @@
1
+ export declare function isDate(value: unknown): value is Date;
@@ -0,0 +1,3 @@
1
+ export function isDate(value) {
2
+ return value != null && Object.prototype.toString.call(value) === '[object Date]';
3
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodArray(value: unknown): value is z.ZodArray<z.ZodTypeAny>;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodArray(value) {
4
+ return hasConstructorName(value, 'ZodArray');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodBoolean(value: unknown): value is z.ZodBoolean;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodBoolean(value) {
4
+ return hasConstructorName(value, 'ZodBoolean');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodDate(value: unknown): value is z.ZodDate;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodDate(value) {
4
+ return hasConstructorName(value, 'ZodDate');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodDefault(value: unknown): value is z.ZodDefault<z.ZodTypeAny>;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodDefault(value) {
4
+ return hasConstructorName(value, 'ZodDefault');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodNullable(value: unknown): value is z.ZodNullable<z.ZodTypeAny>;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodNullable(value) {
4
+ return hasConstructorName(value, 'ZodNullable');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodNumber(value: unknown): value is z.ZodNumber;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodNumber(value) {
4
+ return hasConstructorName(value, 'ZodNumber');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodObject(value: unknown): value is z.ZodObject<z.ZodRawShape>;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodObject(value) {
4
+ return hasConstructorName(value, 'ZodObject');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodOptional(value: unknown): value is z.ZodOptional<z.ZodTypeAny>;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodOptional(value) {
4
+ return hasConstructorName(value, 'ZodOptional');
5
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare function isZodString(value: unknown): value is z.ZodString;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import { hasConstructorName } from './hasConstructorName';
3
+ export function isZodString(value) {
4
+ return hasConstructorName(value, 'ZodString');
5
+ }
@@ -0,0 +1,7 @@
1
+
2
+ //#region src/domain/index.ts
3
+ var domain_exports = {};
4
+
5
+ //#endregion
6
+ export { domain_exports };
7
+ //# sourceMappingURL=domain-Cufz6y1q.js.map
@@ -0,0 +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":""}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Bundled exports for Django-style domain drill-down imports, plus curated
3
+ * top-level symbols for TS-native ergonomic imports.
4
+ */
5
+ export * as domain from './domain/index';
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';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { Model, RelationBuilder, model_exports } from "./model-DE1qDItF.js";
2
+ import { domain_exports } from "./domain-Cufz6y1q.js";
3
+
4
+ export { Model, RelationBuilder, domain_exports as domain, model_exports as model };
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ import type { Model as SchemaModel } from '../domain/Model';
3
+ import type { ModelDefinition } from './ModelDefinition';
4
+ /**
5
+ * Creates a model definition with metadata and schema validation.
6
+ * Automatically infers field types from Zod schema if fields are not explicitly provided.
7
+ */
8
+ export declare function Model<TSchema extends z.ZodObject<z.ZodRawShape>>(definition: ModelDefinition<TSchema>): SchemaModel<TSchema>;
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ import { RelationBuilder } from './RelationBuilder';
3
+ import { inferFieldsFromSchema } from './inferFields';
4
+ /**
5
+ * Creates a model definition with metadata and schema validation.
6
+ * Automatically infers field types from Zod schema if fields are not explicitly provided.
7
+ */
8
+ export function Model(definition) {
9
+ const builder = new RelationBuilder();
10
+ const relations = definition.relations ? definition.relations(builder) : undefined;
11
+ const fields = definition.fields || inferFieldsFromSchema(definition.schema);
12
+ const metadata = {
13
+ table: definition.table,
14
+ fields,
15
+ indexes: definition.indexes,
16
+ relations,
17
+ };
18
+ return {
19
+ metadata,
20
+ schema: definition.schema,
21
+ };
22
+ }
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod';
2
+ import type { Field, IndexDef, RelationDef } from '../domain/index';
3
+ import type { RelationBuilder } from './RelationBuilder';
4
+ export interface ModelDefinition<TSchema extends z.ZodObject<z.ZodRawShape>> {
5
+ table: string;
6
+ schema: TSchema;
7
+ fields?: Field[];
8
+ indexes?: IndexDef[];
9
+ relations?: (builder: RelationBuilder) => Record<string, RelationDef>;
10
+ }
@@ -0,0 +1 @@
1
+ import { z } from 'zod';
@@ -0,0 +1,6 @@
1
+ import type { RelationDef } from '../domain/index';
2
+ export declare class RelationBuilder {
3
+ hasMany(target: string, foreignKey: string): RelationDef;
4
+ belongsTo(target: string, foreignKey: string, localKey?: string): RelationDef;
5
+ hasOne(target: string, foreignKey: string): RelationDef;
6
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Domain boundary barrel: centralizes this subdomain's public contract.
3
+ */
4
+ export type { ModelDefinition } from './ModelDefinition';
5
+ export { RelationBuilder } from './RelationBuilder';
6
+ export { Model } from './Model';
@@ -0,0 +1,3 @@
1
+ import { Model, RelationBuilder } from "../model-DE1qDItF.js";
2
+
3
+ export { Model, RelationBuilder };
@@ -0,0 +1,3 @@
1
+ import { z } from 'zod';
2
+ import type { Field } from '../domain/index';
3
+ export declare function inferFieldsFromSchema(schema: z.ZodObject<z.ZodRawShape>): Field[];
@@ -0,0 +1,64 @@
1
+ import { z } from 'zod';
2
+ import { InternalFieldType } from '../domain/internal/InternalFieldType';
3
+ import { isDate, isZodArray, isZodBoolean, isZodDate, isZodDefault, isZodNullable, isZodNumber, isZodObject, isZodOptional, isZodString, } from '../domain/internal/zod/index';
4
+ export function inferFieldsFromSchema(schema) {
5
+ const shape = schema.shape;
6
+ const fields = [];
7
+ for (const [name, zodType] of Object.entries(shape)) {
8
+ const field = inferField(name, zodType);
9
+ if (field) {
10
+ fields.push(field);
11
+ }
12
+ }
13
+ return fields;
14
+ }
15
+ function inferField(name, zodType) {
16
+ let type = InternalFieldType.TEXT;
17
+ let notNull = true;
18
+ let defaultValue = undefined;
19
+ let unwrapped = zodType;
20
+ if (isZodOptional(unwrapped)) {
21
+ notNull = false;
22
+ unwrapped = unwrapped.unwrap();
23
+ }
24
+ if (isZodNullable(unwrapped)) {
25
+ notNull = false;
26
+ unwrapped = unwrapped.unwrap();
27
+ }
28
+ if (isZodDefault(unwrapped)) {
29
+ const def = unwrapped._zod.def.defaultValue;
30
+ if (isDate(def)) {
31
+ defaultValue = { now: true };
32
+ }
33
+ else if (typeof def === 'string' || typeof def === 'number') {
34
+ defaultValue = String(def);
35
+ }
36
+ unwrapped = unwrapped.removeDefault();
37
+ }
38
+ if (isZodString(unwrapped)) {
39
+ type = InternalFieldType.TEXT;
40
+ }
41
+ else if (isZodNumber(unwrapped)) {
42
+ const checks = unwrapped._zod.def.checks ?? [];
43
+ const isInt = checks.some((c) => 'format' in c._zod.def && c._zod.def.format === 'safeint');
44
+ type = isInt ? InternalFieldType.INT : InternalFieldType.BIGINT;
45
+ }
46
+ else if (isZodBoolean(unwrapped)) {
47
+ type = InternalFieldType.BOOL;
48
+ }
49
+ else if (isZodDate(unwrapped)) {
50
+ type = InternalFieldType.TIMESTAMPTZ;
51
+ }
52
+ else if (isZodObject(unwrapped) || isZodArray(unwrapped)) {
53
+ type = InternalFieldType.JSONB;
54
+ }
55
+ else {
56
+ return null;
57
+ }
58
+ return {
59
+ name,
60
+ type,
61
+ notNull,
62
+ default: defaultValue,
63
+ };
64
+ }
@@ -0,0 +1,174 @@
1
+
2
+ //#region rolldown:runtime
3
+ var __defProp = Object.defineProperty;
4
+ var __export = (target, all) => {
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ };
10
+
11
+ //#endregion
12
+ //#region src/domain/internal/InternalRelationType.ts
13
+ let InternalRelationType = function(InternalRelationType$1) {
14
+ InternalRelationType$1["HAS_MANY"] = "hasMany";
15
+ InternalRelationType$1["BELONGS_TO"] = "belongsTo";
16
+ InternalRelationType$1["HAS_ONE"] = "hasOne";
17
+ return InternalRelationType$1;
18
+ }({});
19
+
20
+ //#endregion
21
+ //#region src/model/RelationBuilder.ts
22
+ var RelationBuilder = class {
23
+ hasMany(target, foreignKey) {
24
+ return {
25
+ type: InternalRelationType.HAS_MANY,
26
+ target,
27
+ foreignKey
28
+ };
29
+ }
30
+ belongsTo(target, foreignKey, localKey) {
31
+ return {
32
+ type: InternalRelationType.BELONGS_TO,
33
+ target,
34
+ foreignKey,
35
+ localKey
36
+ };
37
+ }
38
+ hasOne(target, foreignKey) {
39
+ return {
40
+ type: InternalRelationType.HAS_ONE,
41
+ target,
42
+ foreignKey
43
+ };
44
+ }
45
+ };
46
+
47
+ //#endregion
48
+ //#region src/domain/internal/InternalFieldType.ts
49
+ let InternalFieldType = function(InternalFieldType$1) {
50
+ InternalFieldType$1["SERIAL"] = "serial";
51
+ InternalFieldType$1["INT"] = "int";
52
+ InternalFieldType$1["BIGINT"] = "bigint";
53
+ InternalFieldType$1["TEXT"] = "text";
54
+ InternalFieldType$1["BOOL"] = "bool";
55
+ InternalFieldType$1["TIMESTAMPTZ"] = "timestamptz";
56
+ InternalFieldType$1["JSONB"] = "jsonb";
57
+ InternalFieldType$1["UUID"] = "uuid";
58
+ return InternalFieldType$1;
59
+ }({});
60
+
61
+ //#endregion
62
+ //#region src/domain/internal/ZodGuards.ts
63
+ function hasConstructorName(value, name) {
64
+ return !!value && typeof value === "object" && value.constructor?.name === name;
65
+ }
66
+ var ZodGuards = class {
67
+ static isZodOptional(value) {
68
+ return hasConstructorName(value, "ZodOptional");
69
+ }
70
+ static isZodNullable(value) {
71
+ return hasConstructorName(value, "ZodNullable");
72
+ }
73
+ static isZodDefault(value) {
74
+ return hasConstructorName(value, "ZodDefault");
75
+ }
76
+ static isZodString(value) {
77
+ return hasConstructorName(value, "ZodString");
78
+ }
79
+ static isZodNumber(value) {
80
+ return hasConstructorName(value, "ZodNumber");
81
+ }
82
+ static isZodBoolean(value) {
83
+ return hasConstructorName(value, "ZodBoolean");
84
+ }
85
+ static isZodDate(value) {
86
+ return hasConstructorName(value, "ZodDate");
87
+ }
88
+ static isZodObject(value) {
89
+ return hasConstructorName(value, "ZodObject");
90
+ }
91
+ static isZodArray(value) {
92
+ return hasConstructorName(value, "ZodArray");
93
+ }
94
+ static isDate(value) {
95
+ return value != null && Object.prototype.toString.call(value) === "[object Date]";
96
+ }
97
+ };
98
+
99
+ //#endregion
100
+ //#region src/model/inferFields.ts
101
+ function inferFieldsFromSchema(schema) {
102
+ const shape = schema.shape;
103
+ const fields = [];
104
+ for (const [name, zodType] of Object.entries(shape)) {
105
+ const field = inferField(name, zodType);
106
+ if (field) fields.push(field);
107
+ }
108
+ return fields;
109
+ }
110
+ function inferField(name, zodType) {
111
+ let type = InternalFieldType.TEXT;
112
+ let notNull = true;
113
+ let defaultValue = undefined;
114
+ let unwrapped = zodType;
115
+ if (ZodGuards.isZodOptional(unwrapped)) {
116
+ notNull = false;
117
+ unwrapped = unwrapped.unwrap();
118
+ }
119
+ if (ZodGuards.isZodNullable(unwrapped)) {
120
+ notNull = false;
121
+ unwrapped = unwrapped.unwrap();
122
+ }
123
+ if (ZodGuards.isZodDefault(unwrapped)) {
124
+ const def = unwrapped._zod.def.defaultValue;
125
+ if (ZodGuards.isDate(def)) defaultValue = { now: true };
126
+ else if (typeof def === "string" || typeof def === "number") defaultValue = String(def);
127
+ unwrapped = unwrapped.removeDefault();
128
+ }
129
+ if (ZodGuards.isZodString(unwrapped)) type = InternalFieldType.TEXT;
130
+ else if (ZodGuards.isZodNumber(unwrapped)) {
131
+ const checks = unwrapped._zod.def.checks ?? [];
132
+ const isInt = checks.some((c) => "format" in c._zod.def && c._zod.def.format === "safeint");
133
+ type = isInt ? InternalFieldType.INT : InternalFieldType.BIGINT;
134
+ } else if (ZodGuards.isZodBoolean(unwrapped)) type = InternalFieldType.BOOL;
135
+ else if (ZodGuards.isZodDate(unwrapped)) type = InternalFieldType.TIMESTAMPTZ;
136
+ else if (ZodGuards.isZodObject(unwrapped) || ZodGuards.isZodArray(unwrapped)) type = InternalFieldType.JSONB;
137
+ else return null;
138
+ return {
139
+ name,
140
+ type,
141
+ notNull,
142
+ default: defaultValue
143
+ };
144
+ }
145
+
146
+ //#endregion
147
+ //#region src/model/Model.ts
148
+ function Model(definition) {
149
+ const builder = new RelationBuilder();
150
+ const relations = definition.relations ? definition.relations(builder) : undefined;
151
+ const fields = definition.fields || inferFieldsFromSchema(definition.schema);
152
+ const metadata = {
153
+ table: definition.table,
154
+ fields,
155
+ indexes: definition.indexes,
156
+ relations
157
+ };
158
+ return {
159
+ metadata,
160
+ schema: definition.schema
161
+ };
162
+ }
163
+
164
+ //#endregion
165
+ //#region src/model/index.ts
166
+ var model_exports = {};
167
+ __export(model_exports, {
168
+ Model: () => Model,
169
+ RelationBuilder: () => RelationBuilder
170
+ });
171
+
172
+ //#endregion
173
+ export { Model, RelationBuilder, model_exports };
174
+ //# sourceMappingURL=model-DE1qDItF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-DE1qDItF.js","names":["target: string","foreignKey: string","localKey?: string","value: unknown","name: string","schema: z.ZodObject<any>","fields: Field[]","name: string","zodType: z.ZodType","type: FieldType","defaultValue: Field['default']","unwrapped: z.ZodType","definition: ModelDefinition<TSchema>","metadata: ModelMetadata"],"sources":["../src/domain/internal/InternalRelationType.ts","../src/model/RelationBuilder.ts","../src/domain/internal/InternalFieldType.ts","../src/domain/internal/ZodGuards.ts","../src/model/inferFields.ts","../src/model/Model.ts","../src/model/index.ts"],"sourcesContent":["export enum InternalRelationType {\n HAS_MANY = 'hasMany',\n BELONGS_TO = 'belongsTo',\n HAS_ONE = 'hasOne',\n}\n","import type { RelationDef } from '../domain/index';\nimport { InternalRelationType } from '../domain/internal/InternalRelationType';\n\nexport class RelationBuilder {\n hasMany(target: string, foreignKey: string): RelationDef {\n return {\n type: InternalRelationType.HAS_MANY,\n target,\n foreignKey,\n };\n }\n\n belongsTo(target: string, foreignKey: string, localKey?: string): RelationDef {\n return {\n type: InternalRelationType.BELONGS_TO,\n target,\n foreignKey,\n localKey,\n };\n }\n\n hasOne(target: string, foreignKey: string): RelationDef {\n return {\n type: InternalRelationType.HAS_ONE,\n target,\n foreignKey,\n };\n }\n}\n","export enum InternalFieldType {\n SERIAL = 'serial',\n INT = 'int',\n BIGINT = 'bigint',\n TEXT = 'text',\n BOOL = 'bool',\n TIMESTAMPTZ = 'timestamptz',\n JSONB = 'jsonb',\n UUID = 'uuid',\n}\n","import { z } from 'zod';\n\nfunction hasConstructorName(value: unknown, name: string): boolean {\n return !!value && typeof value === 'object' && (value as { constructor?: { name?: unknown } }).constructor?.name === name;\n}\n\nexport class ZodGuards {\n static isZodOptional(value: unknown): value is z.ZodOptional<z.ZodTypeAny> {\n return hasConstructorName(value, 'ZodOptional');\n }\n\n static isZodNullable(value: unknown): value is z.ZodNullable<z.ZodTypeAny> {\n return hasConstructorName(value, 'ZodNullable');\n }\n\n static isZodDefault(value: unknown): value is z.ZodDefault<z.ZodTypeAny> {\n return hasConstructorName(value, 'ZodDefault');\n }\n\n static isZodString(value: unknown): value is z.ZodString {\n return hasConstructorName(value, 'ZodString');\n }\n\n static isZodNumber(value: unknown): value is z.ZodNumber {\n return hasConstructorName(value, 'ZodNumber');\n }\n\n static isZodBoolean(value: unknown): value is z.ZodBoolean {\n return hasConstructorName(value, 'ZodBoolean');\n }\n\n static isZodDate(value: unknown): value is z.ZodDate {\n return hasConstructorName(value, 'ZodDate');\n }\n\n static isZodObject(value: unknown): value is z.ZodObject<any> {\n return hasConstructorName(value, 'ZodObject');\n }\n\n static isZodArray(value: unknown): value is z.ZodArray<any> {\n return hasConstructorName(value, 'ZodArray');\n }\n\n static isDate(value: unknown): value is Date {\n return value != null && Object.prototype.toString.call(value) === '[object Date]';\n }\n}\n","import { z } from 'zod';\nimport type { Field, FieldType } from '../domain/index';\nimport { InternalFieldType } from '../domain/internal/InternalFieldType';\nimport { ZodGuards } from '../domain/internal/ZodGuards';\n\nexport function inferFieldsFromSchema(schema: z.ZodObject<any>): Field[] {\n const shape = schema.shape;\n const fields: Field[] = [];\n\n for (const [name, zodType] of Object.entries(shape)) {\n const field = inferField(name, zodType as z.ZodType);\n if (field) {\n fields.push(field);\n }\n }\n\n return fields;\n}\n\nfunction inferField(name: string, zodType: z.ZodType): Field | null {\n let type: FieldType = InternalFieldType.TEXT;\n let notNull = true;\n let defaultValue: Field['default'] = undefined;\n\n let unwrapped: z.ZodType = zodType;\n\n if (ZodGuards.isZodOptional(unwrapped)) {\n notNull = false;\n unwrapped = unwrapped.unwrap() as z.ZodType;\n }\n\n if (ZodGuards.isZodNullable(unwrapped)) {\n notNull = false;\n unwrapped = unwrapped.unwrap() as z.ZodType;\n }\n\n if (ZodGuards.isZodDefault(unwrapped)) {\n const def = unwrapped._zod.def.defaultValue;\n if (ZodGuards.isDate(def)) {\n defaultValue = { now: true };\n } else if (typeof def === 'string' || typeof def === 'number') {\n defaultValue = String(def);\n }\n unwrapped = unwrapped.removeDefault() as z.ZodType;\n }\n\n if (ZodGuards.isZodString(unwrapped)) {\n type = InternalFieldType.TEXT;\n } else if (ZodGuards.isZodNumber(unwrapped)) {\n const checks = unwrapped._zod.def.checks ?? [];\n const isInt = checks.some((c) => 'format' in c._zod.def && c._zod.def.format === 'safeint');\n type = isInt ? InternalFieldType.INT : InternalFieldType.BIGINT;\n } else if (ZodGuards.isZodBoolean(unwrapped)) {\n type = InternalFieldType.BOOL;\n } else if (ZodGuards.isZodDate(unwrapped)) {\n type = InternalFieldType.TIMESTAMPTZ;\n } else if (ZodGuards.isZodObject(unwrapped) || ZodGuards.isZodArray(unwrapped)) {\n type = InternalFieldType.JSONB;\n } else {\n return null;\n }\n\n return {\n name,\n type,\n notNull,\n default: defaultValue,\n };\n}\n","import { z } from 'zod';\nimport type { Model as SchemaModel } from '../domain/Model';\nimport type { ModelMetadata } from '../domain/index';\nimport type { ModelDefinition } from './ModelDefinition';\nimport { RelationBuilder } from './RelationBuilder';\nimport { inferFieldsFromSchema } from './inferFields';\n\n/**\n * Creates a model definition with metadata and schema validation.\n * Automatically infers field types from Zod schema if fields are not explicitly provided.\n */\nexport function Model<TSchema extends z.ZodObject<any>>(definition: ModelDefinition<TSchema>): SchemaModel<TSchema> {\n const builder = new RelationBuilder();\n const relations = definition.relations ? definition.relations(builder) : undefined;\n\n const fields = definition.fields || inferFieldsFromSchema(definition.schema);\n\n const metadata: ModelMetadata = {\n table: definition.table,\n fields,\n indexes: definition.indexes,\n relations,\n };\n\n return {\n metadata,\n schema: definition.schema,\n };\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport type { ModelDefinition } from './ModelDefinition';\nexport { RelationBuilder } from './RelationBuilder';\nexport { Model } from './Model';\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@danceroutine/tango-schema",
3
+ "version": "0.1.0",
4
+ "description": "Model factory, Zod helpers, and metadata utilities for Tango",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./domain": {
14
+ "types": "./dist/domain/index.d.ts",
15
+ "import": "./dist/domain/index.js"
16
+ },
17
+ "./model": {
18
+ "types": "./dist/model/index.d.ts",
19
+ "import": "./dist/model/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsdown",
27
+ "test": "vitest run --coverage",
28
+ "test:watch": "vitest",
29
+ "typecheck": "tsc --noEmit"
30
+ },
31
+ "keywords": [
32
+ "tango",
33
+ "schema",
34
+ "model",
35
+ "zod",
36
+ "validation"
37
+ ],
38
+ "author": "Pedro Del Moral Lopez",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/danceroutine/tango.git",
43
+ "directory": "packages/schema"
44
+ },
45
+ "dependencies": {
46
+ "zod": "^4.0.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^22.9.0",
50
+ "tsdown": "^0.4.0",
51
+ "typescript": "^5.6.3",
52
+ "vitest": "^4.0.6"
53
+ }
54
+ }