@danceroutine/tango-resources 1.11.2 → 1.11.4
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/README.md +2 -2
- package/dist/CursorPaginator-B_8MhYZY.js +195 -0
- package/dist/CursorPaginator-B_8MhYZY.js.map +1 -0
- package/dist/CursorPaginator-CfeMQCdJ.d.ts +177 -0
- package/dist/OffsetPaginator-CaycvxJU.js +188 -0
- package/dist/OffsetPaginator-CaycvxJU.js.map +1 -0
- package/dist/context/index.d.ts +2 -0
- package/dist/context/index.js +2 -0
- package/dist/context-euBQvNRT.js +65 -0
- package/dist/context-euBQvNRT.js.map +1 -0
- package/dist/filters/index.d.ts +2 -0
- package/dist/filters/index.js +2 -0
- package/dist/filters-46d2Nr5C.js +287 -0
- package/dist/filters-46d2Nr5C.js.map +1 -0
- package/dist/index-Ac94YL5S.d.ts +24 -0
- package/dist/index-BJJalUDB.d.ts +54 -0
- package/dist/index-Bg6TtnmQ.d.ts +175 -0
- package/dist/index-C55GDIOn.d.ts +222 -0
- package/dist/index-CiIB-1Ac.d.ts +123 -0
- package/dist/index-DkJtxvKu.d.ts +164 -0
- package/dist/index.d.ts +10 -12
- package/dist/index.js +10 -1013
- package/dist/inferModelFieldParsers-2irv7j1T.js +70 -0
- package/dist/inferModelFieldParsers-2irv7j1T.js.map +1 -0
- package/dist/pagination/index.d.ts +3 -0
- package/dist/pagination/index.js +15 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/paginators/index.d.ts +9 -0
- package/dist/paginators/index.js +12 -0
- package/dist/paginators/index.js.map +1 -0
- package/dist/resource/index.d.ts +3 -0
- package/dist/resource/index.js +7 -0
- package/dist/resource/index.js.map +1 -0
- package/dist/serializer/index.d.ts +2 -0
- package/dist/serializer/index.js +2 -0
- package/dist/serializer-RSwlXWls.js +305 -0
- package/dist/serializer-RSwlXWls.js.map +1 -0
- package/dist/view/index.d.ts +2 -1
- package/dist/view/index.js +1 -1
- package/dist/{view-C9B5Lln3.js → view-CYdJAO4t.js} +7 -314
- package/dist/view-CYdJAO4t.js.map +1 -0
- package/dist/viewset/index.d.ts +9 -0
- package/dist/viewset/index.js +2 -0
- package/dist/viewset-C9j-2U29.js +227 -0
- package/dist/viewset-C9j-2U29.js.map +1 -0
- package/package.json +21 -17
- package/dist/index-D6sfTSEj.d.ts +0 -902
- package/dist/index.js.map +0 -1
- package/dist/view-C9B5Lln3.js.map +0 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/filters/inferModelFieldParsers.ts
|
|
2
|
+
function normalizeParserTokens(raw) {
|
|
3
|
+
const normalized = (Array.isArray(raw) ? raw : String(raw).split(",")).map((value) => value.trim());
|
|
4
|
+
return normalized.every((value) => value.length > 0) ? normalized : [];
|
|
5
|
+
}
|
|
6
|
+
function createBooleanParser() {
|
|
7
|
+
return (raw) => {
|
|
8
|
+
const values = normalizeParserTokens(raw);
|
|
9
|
+
if (values.length === 0) return;
|
|
10
|
+
const parsed = values.map((value) => {
|
|
11
|
+
const normalized = value.toLowerCase();
|
|
12
|
+
if (normalized === "true" || normalized === "1") return true;
|
|
13
|
+
if (normalized === "false" || normalized === "0") return false;
|
|
14
|
+
return null;
|
|
15
|
+
});
|
|
16
|
+
if (parsed.some((value) => value === null)) return;
|
|
17
|
+
return parsed.length === 1 ? parsed[0] : parsed;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function createIntegerParser() {
|
|
21
|
+
return (raw) => {
|
|
22
|
+
const values = normalizeParserTokens(raw);
|
|
23
|
+
if (values.length === 0) return;
|
|
24
|
+
const parsed = values.map(Number);
|
|
25
|
+
if (parsed.some((value) => !Number.isInteger(value))) return;
|
|
26
|
+
return parsed.length === 1 ? parsed[0] : parsed;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function createTimestampParser() {
|
|
30
|
+
return (raw) => {
|
|
31
|
+
const values = normalizeParserTokens(raw);
|
|
32
|
+
if (values.length === 0) return;
|
|
33
|
+
const parsed = values.map((value) => {
|
|
34
|
+
const date = new Date(value);
|
|
35
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
36
|
+
});
|
|
37
|
+
if (parsed.some((value) => value === null)) return;
|
|
38
|
+
return parsed.length === 1 ? parsed[0] : parsed;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Infer resource-level query-value parsers from Tango model metadata.
|
|
43
|
+
*
|
|
44
|
+
* Parsers are inferred conservatively from field metadata so HTTP query filters
|
|
45
|
+
* can be coerced into typed ORM inputs without framework-specific glue.
|
|
46
|
+
*/
|
|
47
|
+
function inferModelFieldParsers(model) {
|
|
48
|
+
const metadata = model.metadata;
|
|
49
|
+
if (!metadata) return {};
|
|
50
|
+
const parsers = {};
|
|
51
|
+
for (const field of metadata.fields) switch (field.type) {
|
|
52
|
+
case "bool":
|
|
53
|
+
parsers[field.name] = createBooleanParser();
|
|
54
|
+
break;
|
|
55
|
+
case "serial":
|
|
56
|
+
case "int":
|
|
57
|
+
case "bigint":
|
|
58
|
+
parsers[field.name] = createIntegerParser();
|
|
59
|
+
break;
|
|
60
|
+
case "timestamptz":
|
|
61
|
+
parsers[field.name] = createTimestampParser();
|
|
62
|
+
break;
|
|
63
|
+
default: break;
|
|
64
|
+
}
|
|
65
|
+
return parsers;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { inferModelFieldParsers as t };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=inferModelFieldParsers-2irv7j1T.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inferModelFieldParsers-2irv7j1T.js","names":[],"sources":["../src/filters/inferModelFieldParsers.ts"],"sourcesContent":["import type { ResourceModelLike } from '../resource/index';\nimport type { FilterValueParser } from './FilterSet';\n\nfunction normalizeParserTokens(raw: string | string[]): string[] {\n const tokens = Array.isArray(raw) ? raw : String(raw).split(',');\n const normalized = tokens.map((value) => value.trim());\n return normalized.every((value) => value.length > 0) ? normalized : [];\n}\n\nfunction createBooleanParser(): FilterValueParser {\n return (raw) => {\n const values = normalizeParserTokens(raw);\n if (values.length === 0) {\n return undefined;\n }\n\n const parsed = values.map((value) => {\n const normalized = value.toLowerCase();\n\n if (normalized === 'true' || normalized === '1') {\n return true;\n }\n\n if (normalized === 'false' || normalized === '0') {\n return false;\n }\n\n return null;\n });\n\n if (parsed.some((value) => value === null)) {\n return undefined;\n }\n\n return parsed.length === 1 ? parsed[0]! : (parsed as boolean[]);\n };\n}\n\nfunction createIntegerParser(): FilterValueParser {\n return (raw) => {\n const values = normalizeParserTokens(raw);\n if (values.length === 0) {\n return undefined;\n }\n\n const parsed = values.map(Number);\n\n if (parsed.some((value) => !Number.isInteger(value))) {\n return undefined;\n }\n\n return parsed.length === 1 ? parsed[0] : parsed;\n };\n}\n\nfunction createTimestampParser(): FilterValueParser {\n return (raw) => {\n const values = normalizeParserTokens(raw);\n if (values.length === 0) {\n return undefined;\n }\n\n const parsed = values.map((value) => {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n });\n\n if (parsed.some((value) => value === null)) {\n return undefined;\n }\n\n return parsed.length === 1 ? parsed[0]! : (parsed as Date[]);\n };\n}\n\n/**\n * Infer resource-level query-value parsers from Tango model metadata.\n *\n * Parsers are inferred conservatively from field metadata so HTTP query filters\n * can be coerced into typed ORM inputs without framework-specific glue.\n */\nexport function inferModelFieldParsers<T extends Record<string, unknown>>(\n model: ResourceModelLike<T>\n): Partial<Record<keyof T, FilterValueParser>> {\n const metadata = model.metadata;\n if (!metadata) {\n return {};\n }\n\n const parsers: Partial<Record<keyof T, FilterValueParser>> = {};\n\n for (const field of metadata.fields) {\n switch (field.type) {\n case 'bool':\n parsers[field.name as keyof T] = createBooleanParser();\n break;\n case 'serial':\n case 'int':\n case 'bigint':\n parsers[field.name as keyof T] = createIntegerParser();\n break;\n case 'timestamptz':\n parsers[field.name as keyof T] = createTimestampParser();\n break;\n default:\n break;\n }\n }\n\n return parsers;\n}\n"],"mappings":";AAGA,SAAS,sBAAsB,KAAkC;CAE7D,MAAM,cADS,MAAM,QAAQ,GAAG,IAAI,MAAM,OAAO,GAAG,EAAE,MAAM,GAAG,GACrC,KAAK,UAAU,MAAM,KAAK,CAAC;CACrD,OAAO,WAAW,OAAO,UAAU,MAAM,SAAS,CAAC,IAAI,aAAa,CAAC;AACzE;AAEA,SAAS,sBAAyC;CAC9C,QAAQ,QAAQ;EACZ,MAAM,SAAS,sBAAsB,GAAG;EACxC,IAAI,OAAO,WAAW,GAClB;EAGJ,MAAM,SAAS,OAAO,KAAK,UAAU;GACjC,MAAM,aAAa,MAAM,YAAY;GAErC,IAAI,eAAe,UAAU,eAAe,KACxC,OAAO;GAGX,IAAI,eAAe,WAAW,eAAe,KACzC,OAAO;GAGX,OAAO;EACX,CAAC;EAED,IAAI,OAAO,MAAM,UAAU,UAAU,IAAI,GACrC;EAGJ,OAAO,OAAO,WAAW,IAAI,OAAO,KAAO;CAC/C;AACJ;AAEA,SAAS,sBAAyC;CAC9C,QAAQ,QAAQ;EACZ,MAAM,SAAS,sBAAsB,GAAG;EACxC,IAAI,OAAO,WAAW,GAClB;EAGJ,MAAM,SAAS,OAAO,IAAI,MAAM;EAEhC,IAAI,OAAO,MAAM,UAAU,CAAC,OAAO,UAAU,KAAK,CAAC,GAC/C;EAGJ,OAAO,OAAO,WAAW,IAAI,OAAO,KAAK;CAC7C;AACJ;AAEA,SAAS,wBAA2C;CAChD,QAAQ,QAAQ;EACZ,MAAM,SAAS,sBAAsB,GAAG;EACxC,IAAI,OAAO,WAAW,GAClB;EAGJ,MAAM,SAAS,OAAO,KAAK,UAAU;GACjC,MAAM,OAAO,IAAI,KAAK,KAAK;GAC3B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;EACjD,CAAC;EAED,IAAI,OAAO,MAAM,UAAU,UAAU,IAAI,GACrC;EAGJ,OAAO,OAAO,WAAW,IAAI,OAAO,KAAO;CAC/C;AACJ;;;;;;;AAQA,SAAgB,uBACZ,OAC2C;CAC3C,MAAM,WAAW,MAAM;CACvB,IAAI,CAAC,UACD,OAAO,CAAC;CAGZ,MAAM,UAAuD,CAAC;CAE9D,KAAK,MAAM,SAAS,SAAS,QACzB,QAAQ,MAAM,MAAd;EACI,KAAK;GACD,QAAQ,MAAM,QAAmB,oBAAoB;GACrD;EACJ,KAAK;EACL,KAAK;EACL,KAAK;GACD,QAAQ,MAAM,QAAmB,oBAAoB;GACrD;EACJ,KAAK;GACD,QAAQ,MAAM,QAAmB,sBAAsB;GACvD;EACJ,SACI;CACR;CAGJ,OAAO;AACX"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as BasePaginatedResponse, c as PaginatedResponse, i as Paginator, l as BasePaginator, n as OffsetPaginator, o as CursorPaginatedResponse, r as Page, s as OffsetPaginatedResponse, t as CursorPaginator } from "../CursorPaginator-CfeMQCdJ.js";
|
|
2
|
+
import { a as OffsetPaginationInputValue, i as OffsetPaginationInput, n as CursorPaginationInput, r as CursorPaginationInputValue } from "../index-Ac94YL5S.js";
|
|
3
|
+
export { type BasePaginatedResponse, BasePaginator, type CursorPaginatedResponse, CursorPaginationInput, type CursorPaginationInputValue, CursorPaginator, type OffsetPaginatedResponse, OffsetPaginationInput, type OffsetPaginationInputValue, OffsetPaginator, type Page, type PaginatedResponse, type Paginator };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { t as __exportAll } from "../chunk-D7D4PA-g.js";
|
|
2
|
+
import { n as OffsetPaginationInput, r as BasePaginator, t as OffsetPaginator } from "../OffsetPaginator-CaycvxJU.js";
|
|
3
|
+
import { n as CursorPaginationInput, t as CursorPaginator } from "../CursorPaginator-B_8MhYZY.js";
|
|
4
|
+
//#region src/pagination/index.ts
|
|
5
|
+
var pagination_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
BasePaginator: () => BasePaginator,
|
|
7
|
+
CursorPaginationInput: () => CursorPaginationInput,
|
|
8
|
+
CursorPaginator: () => CursorPaginator,
|
|
9
|
+
OffsetPaginationInput: () => OffsetPaginationInput,
|
|
10
|
+
OffsetPaginator: () => OffsetPaginator
|
|
11
|
+
});
|
|
12
|
+
//#endregion
|
|
13
|
+
export { BasePaginator, CursorPaginationInput, CursorPaginator, OffsetPaginationInput, OffsetPaginator, pagination_exports as t };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/pagination/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { OffsetPaginator } from '../paginators/OffsetPaginator';\nexport { CursorPaginator } from '../paginators/CursorPaginator';\nexport { OffsetPaginationInput } from './OffsetPaginationInput';\nexport type { OffsetPaginationInputValue } from './OffsetPaginationInput';\nexport { CursorPaginationInput } from './CursorPaginationInput';\nexport type { CursorPaginationInputValue } from './CursorPaginationInput';\nexport type { Paginator, Page } from './Paginator';\nexport type {\n BasePaginatedResponse,\n CursorPaginatedResponse,\n OffsetPaginatedResponse,\n PaginatedResponse,\n} from './PaginatedResponse';\nexport { BasePaginator } from './BasePaginator';\n"],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { n as OffsetPaginator, t as CursorPaginator } from "../CursorPaginator-CfeMQCdJ.js";
|
|
2
|
+
|
|
3
|
+
//#region src/paginators/index.d.ts
|
|
4
|
+
declare namespace index_d_exports {
|
|
5
|
+
export { CursorPaginator, OffsetPaginator };
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { CursorPaginator, OffsetPaginator, index_d_exports as t };
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { t as __exportAll } from "../chunk-D7D4PA-g.js";
|
|
2
|
+
import { t as OffsetPaginator } from "../OffsetPaginator-CaycvxJU.js";
|
|
3
|
+
import { t as CursorPaginator } from "../CursorPaginator-B_8MhYZY.js";
|
|
4
|
+
//#region src/paginators/index.ts
|
|
5
|
+
var paginators_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
CursorPaginator: () => CursorPaginator,
|
|
7
|
+
OffsetPaginator: () => OffsetPaginator
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
export { CursorPaginator, OffsetPaginator, paginators_exports as t };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/paginators/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { CursorPaginator } from './CursorPaginator';\nexport { OffsetPaginator } from './OffsetPaginator';\n"],"mappings":""}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { C as ResourceModelMetadata, S as ResourceModelLike, x as ResourceModelFieldMetadata } from "../index-C55GDIOn.js";
|
|
2
|
+
import { n as GenericAPIViewOpenAPIDescription, r as ModelViewSetOpenAPIDescription } from "../index-DkJtxvKu.js";
|
|
3
|
+
export type { GenericAPIViewOpenAPIDescription, ModelViewSetOpenAPIDescription, ResourceModelFieldMetadata, ResourceModelLike, ResourceModelMetadata };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/resource/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes shared resource metadata contracts.\n */\n\nexport type { ResourceModelFieldMetadata, ResourceModelLike, ResourceModelMetadata } from './ResourceModelLike';\nexport type { GenericAPIViewOpenAPIDescription, ModelViewSetOpenAPIDescription } from './OpenAPIDescription';\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as SerializerOutputResolver, a as ModelSerializerClass, b as SerializerUpdateInput, c as ManyToManyRelationField, d as relation, f as AnySerializerClass, g as SerializerOutput, h as SerializerCreateInput, i as ModelSerializer, l as ManyToManyWriteStrategy, m as SerializerClass, n as AnyModelSerializer, o as ManyToManyManagerKeys, p as Serializer, r as AnyModelSerializerClass, s as ManyToManyReadStrategy, u as ModelSerializerRelationFields, v as SerializerOutputResolvers, y as SerializerSchema } from "../index-C55GDIOn.js";
|
|
2
|
+
export { type AnyModelSerializer, type AnyModelSerializerClass, type AnySerializerClass, type ManyToManyManagerKeys, type ManyToManyReadStrategy, type ManyToManyRelationField, type ManyToManyWriteStrategy, ModelSerializer, type ModelSerializerClass, type ModelSerializerRelationFields, Serializer, type SerializerClass, type SerializerCreateInput, type SerializerOutput, type SerializerOutputResolver, type SerializerOutputResolvers, type SerializerSchema, type SerializerUpdateInput, relation };
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-D7D4PA-g.js";
|
|
2
|
+
import { getLogger } from "@danceroutine/tango-core";
|
|
3
|
+
import { ManyToManyRelatedManager } from "@danceroutine/tango-orm";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/serializer/Serializer.ts
|
|
6
|
+
const logger = getLogger("tango.resources.serializer");
|
|
7
|
+
let hasWarnedAboutToRepresentationDeprecation = false;
|
|
8
|
+
/**
|
|
9
|
+
* DRF-inspired base serializer backed by Zod schemas.
|
|
10
|
+
*
|
|
11
|
+
* Tango serializers keep Zod as the source of truth for validation and type
|
|
12
|
+
* inference while centralizing create, update, and representation workflows in
|
|
13
|
+
* one class-owned contract.
|
|
14
|
+
*/
|
|
15
|
+
var Serializer = class {
|
|
16
|
+
static createSchema = z.unknown();
|
|
17
|
+
static updateSchema = z.unknown();
|
|
18
|
+
static outputSchema = z.unknown();
|
|
19
|
+
static outputResolvers = void 0;
|
|
20
|
+
/**
|
|
21
|
+
* Return the serializer class for the current instance.
|
|
22
|
+
*/
|
|
23
|
+
getSerializerClass() {
|
|
24
|
+
return this.constructor;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Return the Zod schema used for create payloads.
|
|
28
|
+
*/
|
|
29
|
+
getCreateSchema() {
|
|
30
|
+
return this.getSerializerClass().createSchema;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Return the Zod schema used for update payloads.
|
|
34
|
+
*/
|
|
35
|
+
getUpdateSchema() {
|
|
36
|
+
return this.getSerializerClass().updateSchema;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Return the Zod schema used for serialized output.
|
|
40
|
+
*/
|
|
41
|
+
getOutputSchema() {
|
|
42
|
+
return this.getSerializerClass().outputSchema;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Return the resolver map used to enrich serializer output fields before
|
|
46
|
+
* the outward Zod schema parses the final response shape.
|
|
47
|
+
*/
|
|
48
|
+
getOutputResolvers() {
|
|
49
|
+
return this.getSerializerClass().outputResolvers ?? {};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validate unknown input for create workflows.
|
|
53
|
+
*/
|
|
54
|
+
deserializeCreate(input) {
|
|
55
|
+
return this.getCreateSchema().parse(input);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validate unknown input for update workflows.
|
|
59
|
+
*/
|
|
60
|
+
deserializeUpdate(input) {
|
|
61
|
+
return this.getUpdateSchema().parse(input);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert a persisted record into its outward-facing representation.
|
|
65
|
+
*
|
|
66
|
+
* @deprecated Use `serialize(...)` instead so serializer-owned output
|
|
67
|
+
* resolvers run before the outward Zod schema parses the response shape.
|
|
68
|
+
*/
|
|
69
|
+
toRepresentation(record) {
|
|
70
|
+
if (!hasWarnedAboutToRepresentationDeprecation) {
|
|
71
|
+
hasWarnedAboutToRepresentationDeprecation = true;
|
|
72
|
+
logger.warn("`Serializer.toRepresentation(...)` is deprecated. Use `serialize(...)` instead so output resolvers run before outward parsing.");
|
|
73
|
+
}
|
|
74
|
+
return this.getOutputSchema().parse(record);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve serializer-owned output fields and parse the outward response
|
|
78
|
+
* contract.
|
|
79
|
+
*/
|
|
80
|
+
async serialize(record) {
|
|
81
|
+
return this.getOutputSchema().parse(await this.applyOutputResolvers(record));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Serialize many records through the same outward response contract.
|
|
85
|
+
*/
|
|
86
|
+
async serializeMany(records) {
|
|
87
|
+
return Promise.all(records.map((record) => this.serialize(record)));
|
|
88
|
+
}
|
|
89
|
+
async applyOutputResolvers(record) {
|
|
90
|
+
const resolvers = this.getOutputResolvers();
|
|
91
|
+
const resolverEntries = Object.entries(resolvers);
|
|
92
|
+
if (resolverEntries.length === 0 || typeof record !== "object" || record === null) return record;
|
|
93
|
+
const resolved = await Promise.all(resolverEntries.map(async ([key, resolver]) => [key, await resolver(record)]));
|
|
94
|
+
return {
|
|
95
|
+
...record,
|
|
96
|
+
...Object.fromEntries(resolved)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/serializer/internal/InternalSerializerRelationKind.ts
|
|
102
|
+
const InternalSerializerRelationKind = { MANY_TO_MANY: "manyToMany" };
|
|
103
|
+
const InternalManyToManyReadStrategyKind = {
|
|
104
|
+
PK_LIST: "pkList",
|
|
105
|
+
NESTED: "nested"
|
|
106
|
+
};
|
|
107
|
+
const InternalManyToManyWriteStrategyKind = {
|
|
108
|
+
PK_LIST: "pkList",
|
|
109
|
+
SLUG_LIST: "slugList"
|
|
110
|
+
};
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/serializer/ModelSerializer.ts
|
|
113
|
+
/**
|
|
114
|
+
* Zod-backed serializer with default model-manager persistence behavior.
|
|
115
|
+
*/
|
|
116
|
+
var ModelSerializer = class extends Serializer {
|
|
117
|
+
static model;
|
|
118
|
+
static relationFields = void 0;
|
|
119
|
+
/**
|
|
120
|
+
* Return the Tango model backing this serializer.
|
|
121
|
+
*/
|
|
122
|
+
getModel() {
|
|
123
|
+
const model = this.constructor.model;
|
|
124
|
+
if (!model) throw new Error(`${this.constructor.name} must define a static model or override getModel().`);
|
|
125
|
+
return model;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Return the manager used for create and update workflows.
|
|
129
|
+
*/
|
|
130
|
+
getManager() {
|
|
131
|
+
return this.getModel().objects;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Return the declarative relation-field map for this serializer.
|
|
135
|
+
*/
|
|
136
|
+
getRelationFields() {
|
|
137
|
+
return this.constructor.relationFields ?? {};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Merge relation-field read resolvers into the serializer output path.
|
|
141
|
+
*/
|
|
142
|
+
getOutputResolvers() {
|
|
143
|
+
const baseResolvers = super.getOutputResolvers();
|
|
144
|
+
const relationFields = this.getRelationFields();
|
|
145
|
+
return {
|
|
146
|
+
...Object.fromEntries(Object.entries(relationFields).map(([fieldName, field]) => [fieldName, async (record) => this.serializeRelationField(record, fieldName, field)])),
|
|
147
|
+
...baseResolvers
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Validate, enrich, persist, and serialize a create workflow.
|
|
152
|
+
*/
|
|
153
|
+
async create(input) {
|
|
154
|
+
const validated = this.deserializeCreate(input);
|
|
155
|
+
const relationWrites = this.extractRelationWrites(validated, input);
|
|
156
|
+
const prepared = await this.beforeCreate(validated);
|
|
157
|
+
const created = await this.getManager().create(this.stripRelationFields(prepared));
|
|
158
|
+
await this.applyRelationWrites(created, relationWrites);
|
|
159
|
+
return this.serialize(created);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Validate, enrich, persist, and serialize an update workflow.
|
|
163
|
+
*/
|
|
164
|
+
async update(id, input) {
|
|
165
|
+
const validated = this.deserializeUpdate(input);
|
|
166
|
+
const relationWrites = this.extractRelationWrites(validated, input);
|
|
167
|
+
const prepared = await this.beforeUpdate(id, validated);
|
|
168
|
+
const updated = await this.getManager().update(id, this.stripRelationFields(prepared));
|
|
169
|
+
await this.applyRelationWrites(updated, relationWrites);
|
|
170
|
+
return this.serialize(updated);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Override to normalize create input for this resource workflow before the
|
|
174
|
+
* manager call.
|
|
175
|
+
*
|
|
176
|
+
* Model-owned persistence rules belong in model hooks so they also run for
|
|
177
|
+
* scripts and direct manager usage.
|
|
178
|
+
*/
|
|
179
|
+
async beforeCreate(data) {
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Override to normalize update input for this resource workflow before the
|
|
184
|
+
* manager call.
|
|
185
|
+
*
|
|
186
|
+
* Model-owned persistence rules belong in model hooks so they also run for
|
|
187
|
+
* scripts and direct manager usage.
|
|
188
|
+
*/
|
|
189
|
+
async beforeUpdate(_id, data) {
|
|
190
|
+
return data;
|
|
191
|
+
}
|
|
192
|
+
extractRelationWrites(data, rawInput) {
|
|
193
|
+
if (typeof data !== "object" || data === null || typeof rawInput !== "object" || rawInput === null) return {};
|
|
194
|
+
const relationFields = this.getRelationFields();
|
|
195
|
+
const writes = {};
|
|
196
|
+
for (const fieldName of Object.keys(relationFields)) if (fieldName in rawInput) writes[fieldName] = data[fieldName];
|
|
197
|
+
return writes;
|
|
198
|
+
}
|
|
199
|
+
stripRelationFields(data) {
|
|
200
|
+
const relationFieldNames = new Set(Object.keys(this.getRelationFields()));
|
|
201
|
+
if (relationFieldNames.size === 0) return data;
|
|
202
|
+
return Object.fromEntries(Object.entries(data).filter(([fieldName]) => !relationFieldNames.has(fieldName)));
|
|
203
|
+
}
|
|
204
|
+
async applyRelationWrites(record, writes) {
|
|
205
|
+
const relationFields = this.getRelationFields();
|
|
206
|
+
for (const [fieldName, value] of Object.entries(writes)) {
|
|
207
|
+
if (!relationFields[fieldName]) continue;
|
|
208
|
+
await this.syncManyToManyRelation(record, fieldName, value);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async serializeRelationField(record, fieldName, field) {
|
|
212
|
+
const rows = (await this.getManyToManyManager(record, fieldName).all().fetch()).results;
|
|
213
|
+
const relationMeta = this.getManyToManyRelationMeta(fieldName);
|
|
214
|
+
switch (field.read.kind) {
|
|
215
|
+
case InternalManyToManyReadStrategyKind.PK_LIST: return rows.map((row) => row[relationMeta.targetPrimaryKey]);
|
|
216
|
+
case InternalManyToManyReadStrategyKind.NESTED: return rows.map((row) => field.read.schema.parse(row));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async syncManyToManyRelation(record, fieldName, value) {
|
|
220
|
+
if (value === void 0) return;
|
|
221
|
+
const manager = this.getManyToManyManager(record, fieldName);
|
|
222
|
+
const field = this.getRelationFields()[fieldName];
|
|
223
|
+
if (!field) return;
|
|
224
|
+
const nextTargets = await this.resolveWriteTargets(fieldName, field.write, value);
|
|
225
|
+
await manager.set(...nextTargets);
|
|
226
|
+
}
|
|
227
|
+
async resolveWriteTargets(fieldName, strategy, value) {
|
|
228
|
+
switch (strategy.kind) {
|
|
229
|
+
case InternalManyToManyWriteStrategyKind.PK_LIST:
|
|
230
|
+
if (!Array.isArray(value)) throw new TypeError(`Relation field '${String(fieldName)}' expects an array of primary-key values.`);
|
|
231
|
+
return value;
|
|
232
|
+
case InternalManyToManyWriteStrategyKind.SLUG_LIST: {
|
|
233
|
+
if (!Array.isArray(value)) throw new TypeError(`Relation field '${String(fieldName)}' expects an array of lookup values.`);
|
|
234
|
+
const lookupValues = [...new Set(value.map((entry) => String(entry).trim()).filter(Boolean))];
|
|
235
|
+
if (lookupValues.length === 0) return [];
|
|
236
|
+
const filter = { [`${strategy.lookupField}__in`]: lookupValues };
|
|
237
|
+
const existing = await strategy.model.objects.query().filter(filter).fetch();
|
|
238
|
+
const byLookup = new Map(existing.results.map((row) => [String(row[strategy.lookupField]), row]));
|
|
239
|
+
const resolved = [];
|
|
240
|
+
for (const lookupValue of lookupValues) {
|
|
241
|
+
const found = byLookup.get(lookupValue);
|
|
242
|
+
if (found) {
|
|
243
|
+
resolved.push(found);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (!strategy.createIfMissing) throw new Error(`Relation field '${String(fieldName)}' could not resolve '${lookupValue}' via '${strategy.lookupField}'.`);
|
|
247
|
+
const created = await strategy.model.objects.create(strategy.buildCreateInput?.(lookupValue) ?? { [strategy.lookupField]: lookupValue });
|
|
248
|
+
resolved.push(created);
|
|
249
|
+
}
|
|
250
|
+
return resolved;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
getManyToManyManager(record, fieldName) {
|
|
255
|
+
const manager = record[fieldName];
|
|
256
|
+
if (!ManyToManyRelatedManager.isManyToManyRelatedManager(manager)) throw new Error(`Relation field '${fieldName}' is not backed by a many-to-many related manager.`);
|
|
257
|
+
return manager;
|
|
258
|
+
}
|
|
259
|
+
getManyToManyRelationMeta(fieldName) {
|
|
260
|
+
const relation = this.getManager().meta.relations?.[fieldName];
|
|
261
|
+
if (!relation || relation.kind !== InternalSerializerRelationKind.MANY_TO_MANY) throw new Error(`Relation field '${fieldName}' is not a persisted many-to-many edge.`);
|
|
262
|
+
return relation;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/serializer/relation.ts
|
|
267
|
+
function pkList() {
|
|
268
|
+
return { kind: InternalManyToManyReadStrategyKind.PK_LIST };
|
|
269
|
+
}
|
|
270
|
+
function nested(schema) {
|
|
271
|
+
return {
|
|
272
|
+
kind: InternalManyToManyReadStrategyKind.NESTED,
|
|
273
|
+
schema
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function slugList(options) {
|
|
277
|
+
return {
|
|
278
|
+
kind: InternalManyToManyWriteStrategyKind.SLUG_LIST,
|
|
279
|
+
...options
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function manyToMany(config = {}) {
|
|
283
|
+
return {
|
|
284
|
+
kind: InternalSerializerRelationKind.MANY_TO_MANY,
|
|
285
|
+
read: config.read ?? pkList(),
|
|
286
|
+
write: config.write ?? pkList()
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const relation = {
|
|
290
|
+
manyToMany,
|
|
291
|
+
pkList,
|
|
292
|
+
nested,
|
|
293
|
+
slugList
|
|
294
|
+
};
|
|
295
|
+
//#endregion
|
|
296
|
+
//#region src/serializer/index.ts
|
|
297
|
+
var serializer_exports = /* @__PURE__ */ __exportAll({
|
|
298
|
+
ModelSerializer: () => ModelSerializer,
|
|
299
|
+
Serializer: () => Serializer,
|
|
300
|
+
relation: () => relation
|
|
301
|
+
});
|
|
302
|
+
//#endregion
|
|
303
|
+
export { Serializer as i, relation as n, ModelSerializer as r, serializer_exports as t };
|
|
304
|
+
|
|
305
|
+
//# sourceMappingURL=serializer-RSwlXWls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializer-RSwlXWls.js","names":[],"sources":["../src/serializer/Serializer.ts","../src/serializer/internal/InternalSerializerRelationKind.ts","../src/serializer/ModelSerializer.ts","../src/serializer/relation.ts","../src/serializer/index.ts"],"sourcesContent":["import { getLogger } from '@danceroutine/tango-core';\nimport { z } from 'zod';\n\nexport type SerializerSchema = z.ZodTypeAny;\n\nexport type SerializerClass<\n TCreateSchema extends SerializerSchema = SerializerSchema,\n TUpdateSchema extends SerializerSchema = SerializerSchema,\n TOutputSchema extends SerializerSchema = SerializerSchema,\n TRecord = unknown,\n> = {\n new (): Serializer<TCreateSchema, TUpdateSchema, TOutputSchema, TRecord>;\n readonly createSchema: TCreateSchema;\n readonly updateSchema: TUpdateSchema;\n readonly outputSchema: TOutputSchema;\n readonly outputResolvers?: SerializerOutputResolvers<TRecord>;\n};\n\nexport type AnySerializerClass = SerializerClass<\n SerializerSchema,\n SerializerSchema,\n SerializerSchema,\n // oxlint-disable-next-line typescript/no-explicit-any\n any\n>;\n\nexport type SerializerCreateInput<TSerializer extends AnySerializerClass> = z.output<TSerializer['createSchema']>;\nexport type SerializerUpdateInput<TSerializer extends AnySerializerClass> = z.output<TSerializer['updateSchema']>;\nexport type SerializerOutput<TSerializer extends AnySerializerClass> = z.output<TSerializer['outputSchema']>;\nexport type SerializerOutputResolver<TRecord = unknown> = (record: TRecord) => unknown | Promise<unknown>;\nexport type SerializerOutputResolvers<TRecord = unknown> = Record<string, SerializerOutputResolver<TRecord>>;\n\nconst logger = getLogger('tango.resources.serializer');\nlet hasWarnedAboutToRepresentationDeprecation = false;\n\n/**\n * DRF-inspired base serializer backed by Zod schemas.\n *\n * Tango serializers keep Zod as the source of truth for validation and type\n * inference while centralizing create, update, and representation workflows in\n * one class-owned contract.\n */\nexport abstract class Serializer<\n TCreateSchema extends SerializerSchema,\n TUpdateSchema extends SerializerSchema,\n TOutputSchema extends SerializerSchema,\n TRecord = unknown,\n> {\n static readonly createSchema: SerializerSchema = z.unknown();\n static readonly updateSchema: SerializerSchema = z.unknown();\n static readonly outputSchema: SerializerSchema = z.unknown();\n static readonly outputResolvers:\n | SerializerOutputResolvers<// oxlint-disable-next-line typescript/no-explicit-any\n any>\n | undefined = undefined;\n\n /**\n * Return the serializer class for the current instance.\n */\n getSerializerClass(): SerializerClass<TCreateSchema, TUpdateSchema, TOutputSchema, TRecord> {\n return this.constructor as SerializerClass<TCreateSchema, TUpdateSchema, TOutputSchema, TRecord>;\n }\n\n /**\n * Return the Zod schema used for create payloads.\n */\n getCreateSchema(): TCreateSchema {\n return this.getSerializerClass().createSchema;\n }\n\n /**\n * Return the Zod schema used for update payloads.\n */\n getUpdateSchema(): TUpdateSchema {\n return this.getSerializerClass().updateSchema;\n }\n\n /**\n * Return the Zod schema used for serialized output.\n */\n getOutputSchema(): TOutputSchema {\n return this.getSerializerClass().outputSchema;\n }\n\n /**\n * Return the resolver map used to enrich serializer output fields before\n * the outward Zod schema parses the final response shape.\n */\n getOutputResolvers(): SerializerOutputResolvers<TRecord> {\n return this.getSerializerClass().outputResolvers ?? {};\n }\n\n /**\n * Validate unknown input for create workflows.\n */\n deserializeCreate(input: unknown): z.output<TCreateSchema> {\n return this.getCreateSchema().parse(input);\n }\n\n /**\n * Validate unknown input for update workflows.\n */\n deserializeUpdate(input: unknown): z.output<TUpdateSchema> {\n return this.getUpdateSchema().parse(input);\n }\n\n /**\n * Convert a persisted record into its outward-facing representation.\n *\n * @deprecated Use `serialize(...)` instead so serializer-owned output\n * resolvers run before the outward Zod schema parses the response shape.\n */\n toRepresentation(record: TRecord): z.output<TOutputSchema> {\n if (!hasWarnedAboutToRepresentationDeprecation) {\n hasWarnedAboutToRepresentationDeprecation = true;\n logger.warn(\n '`Serializer.toRepresentation(...)` is deprecated. Use `serialize(...)` instead so output resolvers run before outward parsing.'\n );\n }\n return this.getOutputSchema().parse(record);\n }\n\n /**\n * Resolve serializer-owned output fields and parse the outward response\n * contract.\n */\n async serialize(record: TRecord): Promise<z.output<TOutputSchema>> {\n return this.getOutputSchema().parse(await this.applyOutputResolvers(record));\n }\n\n /**\n * Serialize many records through the same outward response contract.\n */\n async serializeMany(records: readonly TRecord[]): Promise<z.output<TOutputSchema>[]> {\n return Promise.all(records.map((record) => this.serialize(record)));\n }\n\n private async applyOutputResolvers(record: TRecord): Promise<unknown> {\n const resolvers = this.getOutputResolvers();\n const resolverEntries = Object.entries(resolvers);\n\n if (resolverEntries.length === 0 || typeof record !== 'object' || record === null) {\n return record;\n }\n\n const resolved = await Promise.all(\n resolverEntries.map(async ([key, resolver]) => [key, await resolver(record)] as const)\n );\n\n return {\n ...(record as Record<string, unknown>),\n ...Object.fromEntries(resolved),\n };\n }\n}\n","export const InternalSerializerRelationKind = {\n MANY_TO_MANY: 'manyToMany',\n} as const;\n\nexport const InternalManyToManyReadStrategyKind = {\n PK_LIST: 'pkList',\n NESTED: 'nested',\n} as const;\n\nexport const InternalManyToManyWriteStrategyKind = {\n PK_LIST: 'pkList',\n SLUG_LIST: 'slugList',\n} as const;\n","import type { FilterInput, ManagerLike, ManyToManyTargetRef } from '@danceroutine/tango-orm';\nimport { ManyToManyRelatedManager } from '@danceroutine/tango-orm';\nimport type { ResourceModelLike } from '../resource/ResourceModelLike';\nimport {\n Serializer,\n type AnySerializerClass,\n type SerializerClass,\n type SerializerCreateInput,\n type SerializerOutput,\n type SerializerOutputResolvers,\n type SerializerSchema,\n type SerializerUpdateInput,\n} from './Serializer';\nimport type { ManyToManyManagerKeys, ManyToManyRelationField, ModelSerializerRelationFields } from './relation';\nimport {\n InternalManyToManyReadStrategyKind,\n InternalManyToManyWriteStrategyKind,\n InternalSerializerRelationKind,\n} from './internal/InternalSerializerRelationKind';\n\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyRelationField = ManyToManyRelationField<any, any>;\n\nexport type ModelSerializerClass<\n TModel extends Record<string, unknown> = Record<string, unknown>,\n TCreateSchema extends SerializerSchema = SerializerSchema,\n TUpdateSchema extends SerializerSchema = SerializerSchema,\n TOutputSchema extends SerializerSchema = SerializerSchema,\n TModelRecord extends Record<string, unknown> = TModel,\n> = SerializerClass<TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord> & {\n new (): ModelSerializer<TModel, TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord>;\n readonly model?: ResourceModelLike<TModel, TModelRecord>;\n readonly relationFields?: ModelSerializerRelationFields<TModelRecord>;\n};\n\n//\nexport type AnyModelSerializer<TModel extends Record<string, unknown> = Record<string, unknown>> = ModelSerializerClass<\n TModel,\n SerializerSchema,\n SerializerSchema,\n SerializerSchema,\n // oxlint-disable-next-line typescript/no-explicit-any\n any\n>;\n\nexport type AnyModelSerializerClass = AnyModelSerializer;\n\n/**\n * Zod-backed serializer with default model-manager persistence behavior.\n */\nexport abstract class ModelSerializer<\n TModel extends Record<string, unknown>,\n TCreateSchema extends SerializerSchema,\n TUpdateSchema extends SerializerSchema,\n TOutputSchema extends SerializerSchema,\n TModelRecord extends Record<string, unknown> = TModel,\n> extends Serializer<TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord> {\n static readonly model?: unknown;\n static readonly relationFields: ModelSerializerRelationFields<Record<string, unknown>> | undefined = undefined;\n\n /**\n * Return the Tango model backing this serializer.\n */\n getModel(): ResourceModelLike<TModel, TModelRecord> {\n const model = (\n this.constructor as Partial<\n ModelSerializerClass<TModel, TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord>\n >\n ).model;\n\n if (!model) {\n throw new Error(`${this.constructor.name} must define a static model or override getModel().`);\n }\n\n return model;\n }\n\n /**\n * Return the manager used for create and update workflows.\n */\n getManager(): ManagerLike<TModelRecord> {\n return this.getModel().objects as ManagerLike<TModelRecord>;\n }\n\n /**\n * Return the declarative relation-field map for this serializer.\n */\n getRelationFields(): ModelSerializerRelationFields<TModelRecord> {\n return (\n (\n this.constructor as Partial<\n ModelSerializerClass<TModel, TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord>\n >\n ).relationFields ?? {}\n );\n }\n\n /**\n * Merge relation-field read resolvers into the serializer output path.\n */\n override getOutputResolvers(): SerializerOutputResolvers<TModelRecord> {\n const baseResolvers = super.getOutputResolvers();\n const relationFields = this.getRelationFields() as Record<string, AnyRelationField>;\n const relationResolvers = Object.fromEntries(\n Object.entries(relationFields).map(([fieldName, field]) => [\n fieldName,\n async (record: TModelRecord) => this.serializeRelationField(record, fieldName, field),\n ])\n ) as SerializerOutputResolvers<TModelRecord>;\n\n return {\n ...relationResolvers,\n ...baseResolvers,\n };\n }\n\n /**\n * Validate, enrich, persist, and serialize a create workflow.\n */\n async create(\n input: unknown\n ): Promise<\n SerializerOutput<ModelSerializerClass<TModel, TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord>>\n > {\n const validated = this.deserializeCreate(input);\n const relationWrites = this.extractRelationWrites(validated, input);\n const prepared = await this.beforeCreate(validated);\n const created = await this.getManager().create(this.stripRelationFields(prepared));\n await this.applyRelationWrites(created, relationWrites);\n return this.serialize(created);\n }\n\n /**\n * Validate, enrich, persist, and serialize an update workflow.\n */\n async update(\n id: TModelRecord[keyof TModelRecord],\n input: unknown\n ): Promise<\n SerializerOutput<ModelSerializerClass<TModel, TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord>>\n > {\n const validated = this.deserializeUpdate(input);\n const relationWrites = this.extractRelationWrites(validated, input);\n const prepared = await this.beforeUpdate(id, validated);\n const updated = await this.getManager().update(id, this.stripRelationFields(prepared));\n await this.applyRelationWrites(updated, relationWrites);\n return this.serialize(updated);\n }\n\n /**\n * Override to normalize create input for this resource workflow before the\n * manager call.\n *\n * Model-owned persistence rules belong in model hooks so they also run for\n * scripts and direct manager usage.\n */\n protected async beforeCreate(\n data: SerializerCreateInput<\n ModelSerializerClass<TModel, TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord>\n >\n ): Promise<Partial<TModelRecord>> {\n return data as Partial<TModelRecord>;\n }\n\n /**\n * Override to normalize update input for this resource workflow before the\n * manager call.\n *\n * Model-owned persistence rules belong in model hooks so they also run for\n * scripts and direct manager usage.\n */\n protected async beforeUpdate(\n _id: TModelRecord[keyof TModelRecord],\n data: SerializerUpdateInput<\n ModelSerializerClass<TModel, TCreateSchema, TUpdateSchema, TOutputSchema, TModelRecord>\n >\n ): Promise<Partial<TModelRecord>> {\n return data as Partial<TModelRecord>;\n }\n\n private extractRelationWrites(\n data: unknown,\n rawInput: unknown\n ): Partial<Record<ManyToManyManagerKeys<TModelRecord>, unknown>> {\n if (typeof data !== 'object' || data === null || typeof rawInput !== 'object' || rawInput === null) {\n return {};\n }\n\n const relationFields = this.getRelationFields() as Record<string, AnyRelationField>;\n const writes: Partial<Record<ManyToManyManagerKeys<TModelRecord>, unknown>> = {};\n\n for (const fieldName of Object.keys(relationFields) as ManyToManyManagerKeys<TModelRecord>[]) {\n if (fieldName in rawInput) {\n writes[fieldName] = (data as Record<string, unknown>)[fieldName];\n }\n }\n\n return writes;\n }\n\n private stripRelationFields(data: Partial<TModelRecord>): Partial<TModelRecord> {\n const relationFieldNames = new Set(Object.keys(this.getRelationFields()));\n if (relationFieldNames.size === 0) {\n return data;\n }\n\n return Object.fromEntries(\n Object.entries(data as Record<string, unknown>).filter(([fieldName]) => !relationFieldNames.has(fieldName))\n ) as Partial<TModelRecord>;\n }\n\n private async applyRelationWrites(\n record: TModelRecord,\n writes: Partial<Record<ManyToManyManagerKeys<TModelRecord>, unknown>>\n ): Promise<void> {\n const relationFields = this.getRelationFields() as Record<string, AnyRelationField>;\n\n for (const [fieldName, value] of Object.entries(writes) as Array<\n [ManyToManyManagerKeys<TModelRecord>, unknown]\n >) {\n const field = relationFields[fieldName];\n if (!field) {\n continue;\n }\n await this.syncManyToManyRelation(record, fieldName, value);\n }\n }\n\n private async serializeRelationField(\n record: TModelRecord,\n fieldName: string,\n field: AnyRelationField\n ): Promise<unknown> {\n const manager = this.getManyToManyManager(record, fieldName);\n const rows = (await manager.all().fetch()).results;\n const relationMeta = this.getManyToManyRelationMeta(fieldName);\n\n switch (field.read.kind) {\n case InternalManyToManyReadStrategyKind.PK_LIST:\n return rows.map((row) => row[relationMeta.targetPrimaryKey]);\n case InternalManyToManyReadStrategyKind.NESTED:\n return rows.map((row) =>\n (field.read as { schema: { parse: (input: unknown) => unknown } }).schema.parse(row)\n );\n }\n }\n\n private async syncManyToManyRelation(\n record: TModelRecord,\n fieldName: ManyToManyManagerKeys<TModelRecord>,\n value: unknown\n ): Promise<void> {\n if (value === undefined) {\n return;\n }\n\n const manager = this.getManyToManyManager(record, fieldName);\n const field = (this.getRelationFields() as Record<string, AnyRelationField>)[fieldName];\n if (!field) {\n return;\n }\n\n const nextTargets = await this.resolveWriteTargets(fieldName, field.write, value);\n await manager.set(...nextTargets);\n }\n\n private async resolveWriteTargets(\n fieldName: ManyToManyManagerKeys<TModelRecord>,\n strategy: AnyRelationField['write'],\n value: unknown\n ): Promise<readonly ManyToManyTargetRef<Record<string, unknown>>[]> {\n switch (strategy.kind) {\n case InternalManyToManyWriteStrategyKind.PK_LIST:\n if (!Array.isArray(value)) {\n throw new TypeError(\n `Relation field '${String(fieldName)}' expects an array of primary-key values.`\n );\n }\n return value as readonly ManyToManyTargetRef<Record<string, unknown>>[];\n case InternalManyToManyWriteStrategyKind.SLUG_LIST: {\n if (!Array.isArray(value)) {\n throw new TypeError(`Relation field '${String(fieldName)}' expects an array of lookup values.`);\n }\n\n const lookupValues = [...new Set(value.map((entry) => String(entry).trim()).filter(Boolean))];\n if (lookupValues.length === 0) {\n return [];\n }\n\n const filter = {\n [`${strategy.lookupField}__in`]: lookupValues,\n } as FilterInput<Record<string, unknown>>;\n const existing = await strategy.model.objects.query().filter(filter).fetch();\n const byLookup = new Map(\n existing.results.map((row) => [String((row as Record<string, unknown>)[strategy.lookupField]), row])\n );\n const resolved: Record<string, unknown>[] = [];\n\n for (const lookupValue of lookupValues) {\n const found = byLookup.get(lookupValue);\n if (found) {\n resolved.push(found);\n continue;\n }\n\n if (!strategy.createIfMissing) {\n throw new Error(\n `Relation field '${String(fieldName)}' could not resolve '${lookupValue}' via '${strategy.lookupField}'.`\n );\n }\n\n const created = await strategy.model.objects.create(\n strategy.buildCreateInput?.(lookupValue) ??\n ({ [strategy.lookupField]: lookupValue } as Record<string, unknown>)\n );\n resolved.push(created as Record<string, unknown>);\n }\n\n return resolved;\n }\n }\n }\n\n private getManyToManyManager(\n record: TModelRecord,\n fieldName: string\n ): ManyToManyRelatedManager<Record<string, unknown>> {\n const manager = (record as Record<string, unknown>)[fieldName];\n if (!ManyToManyRelatedManager.isManyToManyRelatedManager(manager)) {\n throw new Error(`Relation field '${fieldName}' is not backed by a many-to-many related manager.`);\n }\n return manager as ManyToManyRelatedManager<Record<string, unknown>>;\n }\n\n private getManyToManyRelationMeta(\n fieldName: string\n ): NonNullable<NonNullable<ManagerLike<TModelRecord>['meta']['relations']>[string]> {\n const relation = this.getManager().meta.relations?.[fieldName];\n if (!relation || relation.kind !== InternalSerializerRelationKind.MANY_TO_MANY) {\n throw new Error(`Relation field '${fieldName}' is not a persisted many-to-many edge.`);\n }\n return relation;\n }\n}\n\nexport type { AnySerializerClass };\n","import { z } from 'zod';\nimport type { ManyToManyRelatedManager } from '@danceroutine/tango-orm';\nimport type { ResourceModelLike } from '../resource/ResourceModelLike';\nimport {\n InternalManyToManyReadStrategyKind,\n InternalManyToManyWriteStrategyKind,\n InternalSerializerRelationKind,\n} from './internal/InternalSerializerRelationKind';\n\ntype AnyRecord = Record<string, unknown>;\n\nexport type ManyToManyManagerKeys<TRecord extends AnyRecord> = Extract<\n {\n [K in keyof TRecord]: TRecord[K] extends ManyToManyRelatedManager<AnyRecord> ? K : never;\n }[keyof TRecord],\n string\n>;\n\nexport type ManyToManyTargetRow<TRecord extends AnyRecord, TFieldName extends ManyToManyManagerKeys<TRecord>> =\n TRecord[TFieldName] extends ManyToManyRelatedManager<infer TTarget extends AnyRecord> ? TTarget : never;\n\nexport type ManyToManyPkListStrategy = {\n kind: typeof InternalManyToManyReadStrategyKind.PK_LIST | typeof InternalManyToManyWriteStrategyKind.PK_LIST;\n};\n\nexport type ManyToManyNestedStrategy = {\n kind: typeof InternalManyToManyReadStrategyKind.NESTED;\n schema: z.ZodTypeAny;\n};\n\nexport type ManyToManySlugListStrategy<TTarget extends AnyRecord> = {\n kind: typeof InternalManyToManyWriteStrategyKind.SLUG_LIST;\n // oxlint-disable-next-line typescript/no-explicit-any\n model: ResourceModelLike<any, any>;\n lookupField: Extract<keyof TTarget, string>;\n createIfMissing?: boolean;\n buildCreateInput?: (value: string) => Partial<TTarget>;\n};\n\nexport type ManyToManyReadStrategy = ManyToManyPkListStrategy | ManyToManyNestedStrategy;\nexport type ManyToManyWriteStrategy<TTarget extends AnyRecord> =\n | ManyToManyPkListStrategy\n | ManyToManySlugListStrategy<TTarget>;\n\nexport type ManyToManyRelationField<TRecord extends AnyRecord, TFieldName extends ManyToManyManagerKeys<TRecord>> = {\n kind: typeof InternalSerializerRelationKind.MANY_TO_MANY;\n read: ManyToManyReadStrategy;\n write: ManyToManyWriteStrategy<ManyToManyTargetRow<TRecord, TFieldName>>;\n};\n\nexport type ModelSerializerRelationFields<TRecord extends AnyRecord> = Partial<{\n [K in ManyToManyManagerKeys<TRecord>]: ManyToManyRelationField<TRecord, K>;\n}>;\n\nfunction pkList(): ManyToManyPkListStrategy {\n return { kind: InternalManyToManyReadStrategyKind.PK_LIST };\n}\n\nfunction nested(schema: z.ZodTypeAny): ManyToManyNestedStrategy {\n return { kind: InternalManyToManyReadStrategyKind.NESTED, schema };\n}\n\nfunction slugList<TTarget extends AnyRecord>(\n options: Omit<ManyToManySlugListStrategy<TTarget>, 'kind'>\n): ManyToManySlugListStrategy<TTarget> {\n return {\n kind: InternalManyToManyWriteStrategyKind.SLUG_LIST,\n ...options,\n };\n}\n\nfunction manyToMany(\n // oxlint-disable-next-line typescript/no-explicit-any\n config: Partial<Pick<ManyToManyRelationField<any, any>, 'read' | 'write'>> = {}\n // oxlint-disable-next-line typescript/no-explicit-any\n): ManyToManyRelationField<any, any> {\n return {\n kind: InternalSerializerRelationKind.MANY_TO_MANY,\n read: config.read ?? pkList(),\n write: config.write ?? pkList(),\n };\n}\n\nexport type RelationHelpers = {\n manyToMany: typeof manyToMany;\n pkList: typeof pkList;\n nested: typeof nested;\n slugList: typeof slugList;\n};\n\nexport const relation: RelationHelpers = {\n manyToMany: manyToMany,\n pkList: pkList,\n nested: nested,\n slugList: slugList,\n};\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport {\n Serializer,\n type SerializerClass,\n type AnySerializerClass,\n type SerializerCreateInput,\n type SerializerOutputResolver,\n type SerializerOutputResolvers,\n type SerializerUpdateInput,\n type SerializerOutput,\n type SerializerSchema,\n} from './Serializer';\nexport {\n ModelSerializer,\n type ModelSerializerClass,\n type AnyModelSerializer,\n type AnyModelSerializerClass,\n} from './ModelSerializer';\nexport {\n relation,\n type ModelSerializerRelationFields,\n type ManyToManyManagerKeys,\n type ManyToManyRelationField,\n type ManyToManyReadStrategy,\n type ManyToManyWriteStrategy,\n} from './relation';\n"],"mappings":";;;;;AAgCA,MAAM,SAAS,UAAU,4BAA4B;AACrD,IAAI,4CAA4C;;;;;;;;AAShD,IAAsB,aAAtB,MAKE;CACE,OAAgB,eAAiC,EAAE,QAAQ;CAC3D,OAAgB,eAAiC,EAAE,QAAQ;CAC3D,OAAgB,eAAiC,EAAE,QAAQ;CAC3D,OAAgB,kBAGE,KAAA;;;;CAKlB,qBAA4F;EACxF,OAAO,KAAK;CAChB;;;;CAKA,kBAAiC;EAC7B,OAAO,KAAK,mBAAmB,EAAE;CACrC;;;;CAKA,kBAAiC;EAC7B,OAAO,KAAK,mBAAmB,EAAE;CACrC;;;;CAKA,kBAAiC;EAC7B,OAAO,KAAK,mBAAmB,EAAE;CACrC;;;;;CAMA,qBAAyD;EACrD,OAAO,KAAK,mBAAmB,EAAE,mBAAmB,CAAC;CACzD;;;;CAKA,kBAAkB,OAAyC;EACvD,OAAO,KAAK,gBAAgB,EAAE,MAAM,KAAK;CAC7C;;;;CAKA,kBAAkB,OAAyC;EACvD,OAAO,KAAK,gBAAgB,EAAE,MAAM,KAAK;CAC7C;;;;;;;CAQA,iBAAiB,QAA0C;EACvD,IAAI,CAAC,2CAA2C;GAC5C,4CAA4C;GAC5C,OAAO,KACH,gIACJ;EACJ;EACA,OAAO,KAAK,gBAAgB,EAAE,MAAM,MAAM;CAC9C;;;;;CAMA,MAAM,UAAU,QAAmD;EAC/D,OAAO,KAAK,gBAAgB,EAAE,MAAM,MAAM,KAAK,qBAAqB,MAAM,CAAC;CAC/E;;;;CAKA,MAAM,cAAc,SAAiE;EACjF,OAAO,QAAQ,IAAI,QAAQ,KAAK,WAAW,KAAK,UAAU,MAAM,CAAC,CAAC;CACtE;CAEA,MAAc,qBAAqB,QAAmC;EAClE,MAAM,YAAY,KAAK,mBAAmB;EAC1C,MAAM,kBAAkB,OAAO,QAAQ,SAAS;EAEhD,IAAI,gBAAgB,WAAW,KAAK,OAAO,WAAW,YAAY,WAAW,MACzE,OAAO;EAGX,MAAM,WAAW,MAAM,QAAQ,IAC3B,gBAAgB,IAAI,OAAO,CAAC,KAAK,cAAc,CAAC,KAAK,MAAM,SAAS,MAAM,CAAC,CAAU,CACzF;EAEA,OAAO;GACH,GAAI;GACJ,GAAG,OAAO,YAAY,QAAQ;EAClC;CACJ;AACJ;;;AC1JA,MAAa,iCAAiC,EAC1C,cAAc,aAClB;AAEA,MAAa,qCAAqC;CAC9C,SAAS;CACT,QAAQ;AACZ;AAEA,MAAa,sCAAsC;CAC/C,SAAS;CACT,WAAW;AACf;;;;;;ACsCA,IAAsB,kBAAtB,cAMU,WAAsE;CAC5E,OAAgB;CAChB,OAAgB,iBAAqF,KAAA;;;;CAKrG,WAAoD;EAChD,MAAM,QACF,KAAK,YAGP;EAEF,IAAI,CAAC,OACD,MAAM,IAAI,MAAM,GAAG,KAAK,YAAY,KAAK,oDAAoD;EAGjG,OAAO;CACX;;;;CAKA,aAAwC;EACpC,OAAO,KAAK,SAAS,EAAE;CAC3B;;;;CAKA,oBAAiE;EAC7D,OAEQ,KAAK,YAGP,kBAAkB,CAAC;CAE7B;;;;CAKA,qBAAuE;EACnE,MAAM,gBAAgB,MAAM,mBAAmB;EAC/C,MAAM,iBAAiB,KAAK,kBAAkB;EAQ9C,OAAO;GACH,GARsB,OAAO,YAC7B,OAAO,QAAQ,cAAc,EAAE,KAAK,CAAC,WAAW,WAAW,CACvD,WACA,OAAO,WAAyB,KAAK,uBAAuB,QAAQ,WAAW,KAAK,CACxF,CAAC,CAIkB;GACnB,GAAG;EACP;CACJ;;;;CAKA,MAAM,OACF,OAGF;EACE,MAAM,YAAY,KAAK,kBAAkB,KAAK;EAC9C,MAAM,iBAAiB,KAAK,sBAAsB,WAAW,KAAK;EAClE,MAAM,WAAW,MAAM,KAAK,aAAa,SAAS;EAClD,MAAM,UAAU,MAAM,KAAK,WAAW,EAAE,OAAO,KAAK,oBAAoB,QAAQ,CAAC;EACjF,MAAM,KAAK,oBAAoB,SAAS,cAAc;EACtD,OAAO,KAAK,UAAU,OAAO;CACjC;;;;CAKA,MAAM,OACF,IACA,OAGF;EACE,MAAM,YAAY,KAAK,kBAAkB,KAAK;EAC9C,MAAM,iBAAiB,KAAK,sBAAsB,WAAW,KAAK;EAClE,MAAM,WAAW,MAAM,KAAK,aAAa,IAAI,SAAS;EACtD,MAAM,UAAU,MAAM,KAAK,WAAW,EAAE,OAAO,IAAI,KAAK,oBAAoB,QAAQ,CAAC;EACrF,MAAM,KAAK,oBAAoB,SAAS,cAAc;EACtD,OAAO,KAAK,UAAU,OAAO;CACjC;;;;;;;;CASA,MAAgB,aACZ,MAG8B;EAC9B,OAAO;CACX;;;;;;;;CASA,MAAgB,aACZ,KACA,MAG8B;EAC9B,OAAO;CACX;CAEA,sBACI,MACA,UAC6D;EAC7D,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,OAAO,aAAa,YAAY,aAAa,MAC1F,OAAO,CAAC;EAGZ,MAAM,iBAAiB,KAAK,kBAAkB;EAC9C,MAAM,SAAwE,CAAC;EAE/E,KAAK,MAAM,aAAa,OAAO,KAAK,cAAc,GAC9C,IAAI,aAAa,UACb,OAAO,aAAc,KAAiC;EAI9D,OAAO;CACX;CAEA,oBAA4B,MAAoD;EAC5E,MAAM,qBAAqB,IAAI,IAAI,OAAO,KAAK,KAAK,kBAAkB,CAAC,CAAC;EACxE,IAAI,mBAAmB,SAAS,GAC5B,OAAO;EAGX,OAAO,OAAO,YACV,OAAO,QAAQ,IAA+B,EAAE,QAAQ,CAAC,eAAe,CAAC,mBAAmB,IAAI,SAAS,CAAC,CAC9G;CACJ;CAEA,MAAc,oBACV,QACA,QACa;EACb,MAAM,iBAAiB,KAAK,kBAAkB;EAE9C,KAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,MAAM,GAEnD;GAEC,IAAI,CADU,eAAe,YAEzB;GAEJ,MAAM,KAAK,uBAAuB,QAAQ,WAAW,KAAK;EAC9D;CACJ;CAEA,MAAc,uBACV,QACA,WACA,OACgB;EAEhB,MAAM,QAAQ,MADE,KAAK,qBAAqB,QAAQ,SACxB,EAAE,IAAI,EAAE,MAAM,GAAG;EAC3C,MAAM,eAAe,KAAK,0BAA0B,SAAS;EAE7D,QAAQ,MAAM,KAAK,MAAnB;GACI,KAAK,mCAAmC,SACpC,OAAO,KAAK,KAAK,QAAQ,IAAI,aAAa,iBAAiB;GAC/D,KAAK,mCAAmC,QACpC,OAAO,KAAK,KAAK,QACZ,MAAM,KAA4D,OAAO,MAAM,GAAG,CACvF;EACR;CACJ;CAEA,MAAc,uBACV,QACA,WACA,OACa;EACb,IAAI,UAAU,KAAA,GACV;EAGJ,MAAM,UAAU,KAAK,qBAAqB,QAAQ,SAAS;EAC3D,MAAM,QAAS,KAAK,kBAAkB,EAAuC;EAC7E,IAAI,CAAC,OACD;EAGJ,MAAM,cAAc,MAAM,KAAK,oBAAoB,WAAW,MAAM,OAAO,KAAK;EAChF,MAAM,QAAQ,IAAI,GAAG,WAAW;CACpC;CAEA,MAAc,oBACV,WACA,UACA,OACgE;EAChE,QAAQ,SAAS,MAAjB;GACI,KAAK,oCAAoC;IACrC,IAAI,CAAC,MAAM,QAAQ,KAAK,GACpB,MAAM,IAAI,UACN,mBAAmB,OAAO,SAAS,EAAE,0CACzC;IAEJ,OAAO;GACX,KAAK,oCAAoC,WAAW;IAChD,IAAI,CAAC,MAAM,QAAQ,KAAK,GACpB,MAAM,IAAI,UAAU,mBAAmB,OAAO,SAAS,EAAE,qCAAqC;IAGlG,MAAM,eAAe,CAAC,GAAG,IAAI,IAAI,MAAM,KAAK,UAAU,OAAO,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;IAC5F,IAAI,aAAa,WAAW,GACxB,OAAO,CAAC;IAGZ,MAAM,SAAS,GACV,GAAG,SAAS,YAAY,QAAQ,aACrC;IACA,MAAM,WAAW,MAAM,SAAS,MAAM,QAAQ,MAAM,EAAE,OAAO,MAAM,EAAE,MAAM;IAC3E,MAAM,WAAW,IAAI,IACjB,SAAS,QAAQ,KAAK,QAAQ,CAAC,OAAQ,IAAgC,SAAS,YAAY,GAAG,GAAG,CAAC,CACvG;IACA,MAAM,WAAsC,CAAC;IAE7C,KAAK,MAAM,eAAe,cAAc;KACpC,MAAM,QAAQ,SAAS,IAAI,WAAW;KACtC,IAAI,OAAO;MACP,SAAS,KAAK,KAAK;MACnB;KACJ;KAEA,IAAI,CAAC,SAAS,iBACV,MAAM,IAAI,MACN,mBAAmB,OAAO,SAAS,EAAE,uBAAuB,YAAY,SAAS,SAAS,YAAY,GAC1G;KAGJ,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ,OACzC,SAAS,mBAAmB,WAAW,KAClC,GAAG,SAAS,cAAc,YAAY,CAC/C;KACA,SAAS,KAAK,OAAkC;IACpD;IAEA,OAAO;GACX;EACJ;CACJ;CAEA,qBACI,QACA,WACiD;EACjD,MAAM,UAAW,OAAmC;EACpD,IAAI,CAAC,yBAAyB,2BAA2B,OAAO,GAC5D,MAAM,IAAI,MAAM,mBAAmB,UAAU,mDAAmD;EAEpG,OAAO;CACX;CAEA,0BACI,WACgF;EAChF,MAAM,WAAW,KAAK,WAAW,EAAE,KAAK,YAAY;EACpD,IAAI,CAAC,YAAY,SAAS,SAAS,+BAA+B,cAC9D,MAAM,IAAI,MAAM,mBAAmB,UAAU,wCAAwC;EAEzF,OAAO;CACX;AACJ;;;ACjSA,SAAS,SAAmC;CACxC,OAAO,EAAE,MAAM,mCAAmC,QAAQ;AAC9D;AAEA,SAAS,OAAO,QAAgD;CAC5D,OAAO;EAAE,MAAM,mCAAmC;EAAQ;CAAO;AACrE;AAEA,SAAS,SACL,SACmC;CACnC,OAAO;EACH,MAAM,oCAAoC;EAC1C,GAAG;CACP;AACJ;AAEA,SAAS,WAEL,SAA6E,CAAC,GAE7C;CACjC,OAAO;EACH,MAAM,+BAA+B;EACrC,MAAM,OAAO,QAAQ,OAAO;EAC5B,OAAO,OAAO,SAAS,OAAO;CAClC;AACJ;AASA,MAAa,WAA4B;CACzB;CACJ;CACA;CACE;AACd"}
|
package/dist/view/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as APIViewMethod, n as GenericAPIViewOpenAPIDescription, u as APIView } from "../index-DkJtxvKu.js";
|
|
2
|
+
import { a as ListCreateAPIView, c as ListAPIView, d as RetrieveModelMixin, f as CreateModelMixin, h as GenericAPIViewConfig, i as RetrieveUpdateAPIView, l as DestroyModelMixin, m as GenericAPIView, n as RetrieveUpdateDestroyAPIView, o as RetrieveAPIView, p as ListModelMixin, r as RetrieveDestroyAPIView, s as CreateAPIView, u as UpdateModelMixin } from "../index-Bg6TtnmQ.js";
|
|
2
3
|
export { APIView, type APIViewMethod, CreateAPIView, CreateModelMixin, DestroyModelMixin, GenericAPIView, type GenericAPIViewConfig, type GenericAPIViewOpenAPIDescription, ListAPIView, ListCreateAPIView, ListModelMixin, RetrieveAPIView, RetrieveDestroyAPIView, RetrieveModelMixin, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, UpdateModelMixin };
|
package/dist/view/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ListCreateAPIView, c as ListAPIView, d as RetrieveModelMixin, f as CreateModelMixin, h as APIView, i as RetrieveUpdateAPIView, l as DestroyModelMixin, m as GenericAPIView, n as RetrieveUpdateDestroyAPIView, o as RetrieveAPIView, p as ListModelMixin, r as RetrieveDestroyAPIView, s as CreateAPIView, u as UpdateModelMixin } from "../view-
|
|
1
|
+
import { a as ListCreateAPIView, c as ListAPIView, d as RetrieveModelMixin, f as CreateModelMixin, h as APIView, i as RetrieveUpdateAPIView, l as DestroyModelMixin, m as GenericAPIView, n as RetrieveUpdateDestroyAPIView, o as RetrieveAPIView, p as ListModelMixin, r as RetrieveDestroyAPIView, s as CreateAPIView, u as UpdateModelMixin } from "../view-CYdJAO4t.js";
|
|
2
2
|
export { APIView, CreateAPIView, CreateModelMixin, DestroyModelMixin, GenericAPIView, ListAPIView, ListCreateAPIView, ListModelMixin, RetrieveAPIView, RetrieveDestroyAPIView, RetrieveModelMixin, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, UpdateModelMixin };
|