@danceroutine/tango-resources 1.11.1 → 1.11.2
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/dist/chunk-D7D4PA-g.js +13 -0
- package/dist/index-D6sfTSEj.d.ts +902 -0
- package/dist/index.d.ts +12 -23
- package/dist/index.js +96 -152
- package/dist/index.js.map +1 -1
- package/dist/view/index.d.ts +2 -8
- package/dist/view/index.js +2 -3
- package/dist/{view-DUHg6AXl.js → view-C9B5Lln3.js} +151 -59
- package/dist/view-C9B5Lln3.js.map +1 -0
- package/package.json +6 -6
- package/dist/context/RequestContext.d.ts +0 -46
- package/dist/context/index.d.ts +0 -5
- package/dist/filters/FilterSet.d.ts +0 -95
- package/dist/filters/FilterType.d.ts +0 -2
- package/dist/filters/RangeOperator.d.ts +0 -2
- package/dist/filters/index.d.ts +0 -7
- package/dist/filters/inferModelFieldParsers.d.ts +0 -9
- package/dist/filters/internal/InternalFilterLookup.d.ts +0 -15
- package/dist/filters/internal/InternalFilterType.d.ts +0 -7
- package/dist/filters/internal/InternalRangeOperator.d.ts +0 -6
- package/dist/pagination/BasePaginator.d.ts +0 -4
- package/dist/pagination/CursorPaginationInput.d.ts +0 -7
- package/dist/pagination/OffsetPaginationInput.d.ts +0 -7
- package/dist/pagination/PaginatedResponse.d.ts +0 -12
- package/dist/pagination/Paginator.d.ts +0 -21
- package/dist/pagination/index.d.ts +0 -12
- package/dist/paginators/CursorPaginator.d.ts +0 -65
- package/dist/paginators/OffsetPaginator.d.ts +0 -74
- package/dist/paginators/index.d.ts +0 -5
- package/dist/resource/OpenAPIDescription.d.ts +0 -23
- package/dist/resource/ResourceModelLike.d.ts +0 -22
- package/dist/resource/index.d.ts +0 -5
- package/dist/serializer/ModelSerializer.d.ts +0 -67
- package/dist/serializer/Serializer.d.ts +0 -75
- package/dist/serializer/index.d.ts +0 -6
- package/dist/serializer/internal/InternalSerializerRelationKind.d.ts +0 -11
- package/dist/serializer/relation.d.ts +0 -45
- package/dist/view/APIView.d.ts +0 -26
- package/dist/view/GenericAPIView.d.ts +0 -60
- package/dist/view/generics/CreateAPIView.d.ts +0 -10
- package/dist/view/generics/ListAPIView.d.ts +0 -10
- package/dist/view/generics/ListCreateAPIView.d.ts +0 -11
- package/dist/view/generics/RetrieveAPIView.d.ts +0 -10
- package/dist/view/generics/RetrieveDestroyAPIView.d.ts +0 -11
- package/dist/view/generics/RetrieveUpdateAPIView.d.ts +0 -12
- package/dist/view/generics/RetrieveUpdateDestroyAPIView.d.ts +0 -13
- package/dist/view/generics/index.d.ts +0 -10
- package/dist/view/mixins/CreateModelMixin.d.ts +0 -11
- package/dist/view/mixins/DestroyModelMixin.d.ts +0 -11
- package/dist/view/mixins/ListModelMixin.d.ts +0 -11
- package/dist/view/mixins/RetrieveModelMixin.d.ts +0 -11
- package/dist/view/mixins/UpdateModelMixin.d.ts +0 -12
- package/dist/view/mixins/index.d.ts +0 -8
- package/dist/view-DUHg6AXl.js.map +0 -1
- package/dist/viewset/ModelViewSet.d.ts +0 -112
- package/dist/viewset/index.d.ts +0 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
export { RequestContext } from './context/index';
|
|
14
|
-
export type { BaseUser } from './context/index';
|
|
15
|
-
export { FilterSet, type AliasFilterDeclaration, type FieldFilterDeclaration, type FilterLookup, type FilterResolver, type FilterSetDefineConfig, type FilterValueParser, } from './filters/index';
|
|
16
|
-
export type { FilterType, RangeOperator } from './filters/index';
|
|
17
|
-
export { CursorPaginator, OffsetPaginator, CursorPaginationInput, OffsetPaginationInput, type Page, type BasePaginatedResponse, type CursorPaginatedResponse, type OffsetPaginatedResponse, type PaginatedResponse, type Paginator, } from './pagination/index';
|
|
18
|
-
export { Serializer, ModelSerializer, relation, type SerializerClass, type AnySerializerClass, type SerializerCreateInput, type SerializerUpdateInput, type SerializerOutput, type SerializerSchema, type ModelSerializerClass, type AnyModelSerializer, type AnyModelSerializerClass, type ModelSerializerRelationFields, type ManyToManyManagerKeys, type ManyToManyRelationField, type ManyToManyReadStrategy, type ManyToManyWriteStrategy, } from './serializer/index';
|
|
19
|
-
export { ModelViewSet } from './viewset/index';
|
|
20
|
-
export type { ModelViewSetOpenAPIDescription, ModelViewSetConfig, ViewSetActionDescriptor, ViewSetActionMethod, ViewSetActionScope, ResolvedViewSetActionDescriptor, } from './viewset/index';
|
|
21
|
-
export { APIView, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, ListAPIView, CreateAPIView, RetrieveAPIView, ListCreateAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView, RetrieveUpdateDestroyAPIView, } from './view/index';
|
|
22
|
-
export type { APIViewMethod, GenericAPIViewConfig, GenericAPIViewOpenAPIDescription } from './view/index';
|
|
23
|
-
export type { ResourceModelFieldMetadata, ResourceModelLike, ResourceModelMetadata } from './resource/index';
|
|
1
|
+
import { $ as Page, A as ManyToManyManagerKeys, B as SerializerOutput, C as ViewSetActionMethod, D as AnyModelSerializerClass, E as AnyModelSerializer, F as relation, G as ResourceModelFieldMetadata, H as SerializerUpdateInput, I as AnySerializerClass, J as index_d_exports$2, K as ResourceModelLike, L as Serializer, M as ManyToManyRelationField, N as ManyToManyWriteStrategy, O as ModelSerializer, P as ModelSerializerRelationFields, Q as OffsetPaginator, R as SerializerClass, S as ViewSetActionDescriptor, T as index_d_exports$5, U as APIView, V as SerializerSchema, W as APIViewMethod, X as OffsetPaginationInput, Y as CursorPaginationInput, Z as CursorPaginator, _ as GenericAPIViewOpenAPIDescription, _t as RequestContext, a as ListCreateAPIView, at as index_d_exports$1, b as ModelViewSetConfig, c as ListAPIView, ct as FilterLookup, d as RetrieveModelMixin, dt as FilterSetDefineConfig, et as Paginator, f as CreateModelMixin, ft as FilterValueParser, g as index_d_exports$4, gt as BaseUser, h as GenericAPIViewConfig, ht as index_d_exports, i as RetrieveUpdateAPIView, it as PaginatedResponse, j as ManyToManyReadStrategy, k as ModelSerializerClass, l as DestroyModelMixin, lt as FilterResolver, m as GenericAPIView, mt as FilterType, n as RetrieveUpdateDestroyAPIView, nt as CursorPaginatedResponse, o as RetrieveAPIView, ot as AliasFilterDeclaration, p as ListModelMixin, pt as RangeOperator, q as ResourceModelMetadata, r as RetrieveDestroyAPIView, rt as OffsetPaginatedResponse, s as CreateAPIView, st as FieldFilterDeclaration, t as index_d_exports$6, tt as BasePaginatedResponse, u as UpdateModelMixin, ut as FilterSet, v as ModelViewSetOpenAPIDescription, w as ViewSetActionScope, x as ResolvedViewSetActionDescriptor, y as ModelViewSet, z as SerializerCreateInput } from "./index-D6sfTSEj.js";
|
|
2
|
+
|
|
3
|
+
//#region src/paginators/index.d.ts
|
|
4
|
+
declare namespace index_d_exports$3 {
|
|
5
|
+
export { CursorPaginator, OffsetPaginator };
|
|
6
|
+
}
|
|
7
|
+
declare namespace index_d_exports$7 {
|
|
8
|
+
export { ModelViewSet, ModelViewSetConfig, ModelViewSetOpenAPIDescription, ResolvedViewSetActionDescriptor, ViewSetActionDescriptor, ViewSetActionMethod, ViewSetActionScope };
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { APIView, type APIViewMethod, type AliasFilterDeclaration, type AnyModelSerializer, type AnyModelSerializerClass, type AnySerializerClass, type BasePaginatedResponse, type BaseUser, CreateAPIView, CreateModelMixin, type CursorPaginatedResponse, CursorPaginationInput, CursorPaginator, DestroyModelMixin, type FieldFilterDeclaration, type FilterLookup, type FilterResolver, FilterSet, type FilterSetDefineConfig, type FilterType, type FilterValueParser, GenericAPIView, type GenericAPIViewConfig, type GenericAPIViewOpenAPIDescription, ListAPIView, ListCreateAPIView, ListModelMixin, type ManyToManyManagerKeys, type ManyToManyReadStrategy, type ManyToManyRelationField, type ManyToManyWriteStrategy, ModelSerializer, type ModelSerializerClass, type ModelSerializerRelationFields, ModelViewSet, type ModelViewSetConfig, type ModelViewSetOpenAPIDescription, type OffsetPaginatedResponse, OffsetPaginationInput, OffsetPaginator, type Page, type PaginatedResponse, type Paginator, type RangeOperator, RequestContext, type ResolvedViewSetActionDescriptor, type ResourceModelFieldMetadata, type ResourceModelLike, type ResourceModelMetadata, RetrieveAPIView, RetrieveDestroyAPIView, RetrieveModelMixin, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, Serializer, type SerializerClass, type SerializerCreateInput, type SerializerOutput, type SerializerSchema, type SerializerUpdateInput, UpdateModelMixin, type ViewSetActionDescriptor, type ViewSetActionMethod, type ViewSetActionScope, index_d_exports as context, index_d_exports$1 as filters, index_d_exports$2 as pagination, index_d_exports$3 as paginators, relation, index_d_exports$4 as resource, index_d_exports$5 as serializer, index_d_exports$6 as view, index_d_exports$7 as viewset };
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,64 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as __exportAll } from "./chunk-D7D4PA-g.js";
|
|
2
|
+
import { _ as OffsetPaginator, a as ListCreateAPIView, b as context_exports, c as ListAPIView, d as RetrieveModelMixin, f as CreateModelMixin, g as inferModelFieldParsers, 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, t as view_exports, u as UpdateModelMixin, v as OffsetPaginationInput, x as RequestContext, y as BasePaginator } from "./view-C9B5Lln3.js";
|
|
3
|
+
import { HttpErrorFactory, NotFoundError, TangoResponse, getLogger } from "@danceroutine/tango-core";
|
|
3
4
|
import { ManyToManyRelatedManager, Q } from "@danceroutine/tango-orm";
|
|
4
|
-
import { z
|
|
5
|
-
|
|
6
|
-
//#region src/context/RequestContext.ts
|
|
7
|
-
var RequestContext = class RequestContext {
|
|
8
|
-
static BRAND = "tango.resources.request_context";
|
|
9
|
-
__tangoBrand = RequestContext.BRAND;
|
|
10
|
-
state = new Map();
|
|
11
|
-
constructor(request, user = null, params = {}) {
|
|
12
|
-
this.request = request;
|
|
13
|
-
this.user = user;
|
|
14
|
-
this.params = params;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Narrow an unknown value to `RequestContext`.
|
|
18
|
-
*/
|
|
19
|
-
static isRequestContext(value) {
|
|
20
|
-
return typeof value === "object" && value !== null && value.__tangoBrand === RequestContext.BRAND;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Construct a context with optional user payload.
|
|
24
|
-
*/
|
|
25
|
-
static create(request, user) {
|
|
26
|
-
return new RequestContext(TangoRequest.isTangoRequest(request) ? request : new TangoRequest(request), user ?? null);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Store arbitrary per-request state for downstream middleware/handlers.
|
|
30
|
-
*/
|
|
31
|
-
setState(key, value) {
|
|
32
|
-
this.state.set(key, value);
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Retrieve previously stored request state.
|
|
36
|
-
*/
|
|
37
|
-
getState(key) {
|
|
38
|
-
return this.state.get(key);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Check whether a state key has been set.
|
|
42
|
-
*/
|
|
43
|
-
hasState(key) {
|
|
44
|
-
return this.state.has(key);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Clone the context, including route params and request-local state.
|
|
48
|
-
*/
|
|
49
|
-
clone() {
|
|
50
|
-
const cloned = new RequestContext(this.request, this.user, { ...this.params });
|
|
51
|
-
cloned.state = new Map(this.state);
|
|
52
|
-
return cloned;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/context/index.ts
|
|
58
|
-
var context_exports = {};
|
|
59
|
-
__export(context_exports, { RequestContext: () => RequestContext });
|
|
60
|
-
|
|
61
|
-
//#endregion
|
|
5
|
+
import { z } from "zod";
|
|
62
6
|
//#region src/filters/internal/InternalFilterType.ts
|
|
63
7
|
const InternalFilterType = {
|
|
64
8
|
SCALAR: "scalar",
|
|
@@ -67,7 +11,6 @@ const InternalFilterType = {
|
|
|
67
11
|
IN: "in",
|
|
68
12
|
CUSTOM: "custom"
|
|
69
13
|
};
|
|
70
|
-
|
|
71
14
|
//#endregion
|
|
72
15
|
//#region src/filters/internal/InternalFilterLookup.ts
|
|
73
16
|
const InternalFilterLookup = {
|
|
@@ -85,14 +28,21 @@ const InternalFilterLookup = {
|
|
|
85
28
|
ENDSWITH: "endswith",
|
|
86
29
|
IENDSWITH: "iendswith"
|
|
87
30
|
};
|
|
88
|
-
|
|
89
31
|
//#endregion
|
|
90
32
|
//#region src/filters/FilterSet.ts
|
|
91
33
|
const FILTER_LOOKUPS = Object.values(InternalFilterLookup);
|
|
92
34
|
function isFilterLookup(value) {
|
|
93
35
|
return FILTER_LOOKUPS.includes(value);
|
|
94
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Declarative query-param to filter translation.
|
|
39
|
+
*
|
|
40
|
+
* A `FilterSet` lets viewsets expose safe, explicit filtering behavior
|
|
41
|
+
* without leaking raw ORM filter syntax to request handlers.
|
|
42
|
+
*/
|
|
95
43
|
var FilterSet = class FilterSet {
|
|
44
|
+
spec;
|
|
45
|
+
allowAllParams;
|
|
96
46
|
static BRAND = "tango.resources.filter_set";
|
|
97
47
|
__tangoBrand = FilterSet.BRAND;
|
|
98
48
|
/**
|
|
@@ -106,8 +56,7 @@ var FilterSet = class FilterSet {
|
|
|
106
56
|
* Build a filter set from Django-style field declarations.
|
|
107
57
|
*/
|
|
108
58
|
static define(config) {
|
|
109
|
-
|
|
110
|
-
return new FilterSet(spec, config.all === "__all__");
|
|
59
|
+
return new FilterSet(FilterSet.normalizeDefineConfig(config), config.all === "__all__");
|
|
111
60
|
}
|
|
112
61
|
/**
|
|
113
62
|
* Narrow an unknown value to `FilterSet`.
|
|
@@ -121,7 +70,7 @@ var FilterSet = class FilterSet {
|
|
|
121
70
|
const fieldParsers = config.parsers ?? {};
|
|
122
71
|
for (const rawField of Object.keys(fieldDeclarations)) {
|
|
123
72
|
const declaration = fieldDeclarations[rawField];
|
|
124
|
-
if (declaration ===
|
|
73
|
+
if (declaration === void 0) continue;
|
|
125
74
|
const parser = fieldParsers[rawField];
|
|
126
75
|
FilterSet.addFieldDeclaration(spec, rawField, declaration, parser);
|
|
127
76
|
}
|
|
@@ -171,7 +120,7 @@ var FilterSet = class FilterSet {
|
|
|
171
120
|
].includes(value.type);
|
|
172
121
|
}
|
|
173
122
|
static createMultiFieldResolver(fields, lookup, parser) {
|
|
174
|
-
if (lookup === InternalFilterLookup.ICONTAINS && parser ===
|
|
123
|
+
if (lookup === InternalFilterLookup.ICONTAINS && parser === void 0) return {
|
|
175
124
|
type: InternalFilterType.ILIKE,
|
|
176
125
|
columns: [...fields]
|
|
177
126
|
};
|
|
@@ -179,23 +128,23 @@ var FilterSet = class FilterSet {
|
|
|
179
128
|
type: InternalFilterType.CUSTOM,
|
|
180
129
|
apply: (raw) => {
|
|
181
130
|
const parsed = FilterSet.resolveParserValue(raw, parser);
|
|
182
|
-
if (parsed ===
|
|
131
|
+
if (parsed === void 0) return void 0;
|
|
183
132
|
const composed = {};
|
|
184
133
|
for (const field of fields) {
|
|
185
134
|
const segment = FilterSet.resolveLookupFilter(field, lookup, parsed);
|
|
186
135
|
if (!segment) continue;
|
|
187
136
|
Object.assign(composed, segment);
|
|
188
137
|
}
|
|
189
|
-
return Object.keys(composed).length > 0 ? composed :
|
|
138
|
+
return Object.keys(composed).length > 0 ? composed : void 0;
|
|
190
139
|
}
|
|
191
140
|
};
|
|
192
141
|
}
|
|
193
142
|
static createLookupResolver(field, lookup, parser) {
|
|
194
|
-
if (parser !==
|
|
143
|
+
if (parser !== void 0) return {
|
|
195
144
|
type: InternalFilterType.CUSTOM,
|
|
196
145
|
apply: (raw) => {
|
|
197
146
|
const parsed = FilterSet.resolveParserValue(raw, parser);
|
|
198
|
-
if (parsed ===
|
|
147
|
+
if (parsed === void 0) return void 0;
|
|
199
148
|
return FilterSet.resolveLookupFilter(field, lookup, parsed);
|
|
200
149
|
}
|
|
201
150
|
};
|
|
@@ -227,27 +176,22 @@ var FilterSet = class FilterSet {
|
|
|
227
176
|
}
|
|
228
177
|
}
|
|
229
178
|
static resolveLookupFilter(field, lookup, value) {
|
|
230
|
-
if (value ===
|
|
179
|
+
if (value === void 0) return void 0;
|
|
231
180
|
if (lookup === "exact") return { [field]: value };
|
|
232
181
|
if (lookup === "in") {
|
|
233
182
|
const arr = Array.isArray(value) ? value : String(value).split(",");
|
|
234
|
-
|
|
235
|
-
return { [lookupKey$1]: arr };
|
|
183
|
+
return { [`${String(field)}__in`]: arr };
|
|
236
184
|
}
|
|
237
|
-
if (lookup === "icontains") {
|
|
238
|
-
|
|
239
|
-
return { [lookupKey$1]: `%${FilterSet.toScalarString(value)}%` };
|
|
240
|
-
}
|
|
241
|
-
const lookupKey = `${String(field)}__${lookup}`;
|
|
242
|
-
return { [lookupKey]: value };
|
|
185
|
+
if (lookup === "icontains") return { [`${String(field)}__icontains`]: `%${FilterSet.toScalarString(value)}%` };
|
|
186
|
+
return { [`${String(field)}__${lookup}`]: value };
|
|
243
187
|
}
|
|
244
188
|
static resolveLookupParam(baseParam, lookup) {
|
|
245
189
|
if (lookup === "exact") return baseParam;
|
|
246
190
|
return `${baseParam}__${lookup}`;
|
|
247
191
|
}
|
|
248
192
|
static resolveParserValue(value, parser) {
|
|
249
|
-
if (value ===
|
|
250
|
-
if (parser ===
|
|
193
|
+
if (value === void 0) return;
|
|
194
|
+
if (parser === void 0) return value;
|
|
251
195
|
return parser(value);
|
|
252
196
|
}
|
|
253
197
|
static toScalarString(value) {
|
|
@@ -272,14 +216,14 @@ var FilterSet = class FilterSet {
|
|
|
272
216
|
*/
|
|
273
217
|
apply(params) {
|
|
274
218
|
const filters = [];
|
|
275
|
-
const keys = new Set();
|
|
219
|
+
const keys = /* @__PURE__ */ new Set();
|
|
276
220
|
for (const [key] of params.entries()) keys.add(key);
|
|
277
221
|
for (const key of keys) {
|
|
278
|
-
const resolver = this.spec[key] ?? (this.allowAllParams ? this.buildAllResolver(key) :
|
|
222
|
+
const resolver = this.spec[key] ?? (this.allowAllParams ? this.buildAllResolver(key) : void 0);
|
|
279
223
|
if (!resolver) continue;
|
|
280
224
|
const rawValue = params.getAll(key);
|
|
281
225
|
const value = rawValue.length > 1 ? rawValue : rawValue[0];
|
|
282
|
-
if (value ===
|
|
226
|
+
if (value === void 0) continue;
|
|
283
227
|
const filter = this.resolveFilter(resolver, value);
|
|
284
228
|
if (filter) filters.push(filter);
|
|
285
229
|
}
|
|
@@ -287,11 +231,11 @@ var FilterSet = class FilterSet {
|
|
|
287
231
|
}
|
|
288
232
|
buildAllResolver(param) {
|
|
289
233
|
const segments = param.split("__").filter(Boolean);
|
|
290
|
-
if (segments.length === 0) return
|
|
234
|
+
if (segments.length === 0) return;
|
|
291
235
|
const lastSegment = segments.at(-1);
|
|
292
236
|
const lookup = isFilterLookup(lastSegment) ? lastSegment : "exact";
|
|
293
237
|
const field = (lookup === "exact" ? segments : segments.slice(0, -1)).join("__");
|
|
294
|
-
if (!field) return
|
|
238
|
+
if (!field) return;
|
|
295
239
|
if (lookup === "exact") return {
|
|
296
240
|
type: InternalFilterType.SCALAR,
|
|
297
241
|
column: field
|
|
@@ -299,7 +243,7 @@ var FilterSet = class FilterSet {
|
|
|
299
243
|
return FilterSet.createLookupResolver(field, lookup);
|
|
300
244
|
}
|
|
301
245
|
resolveFilter(resolver, value) {
|
|
302
|
-
if (value ===
|
|
246
|
+
if (value === void 0) return void 0;
|
|
303
247
|
switch (resolver.type) {
|
|
304
248
|
case InternalFilterType.SCALAR: return { [resolver.column]: value };
|
|
305
249
|
case InternalFilterType.ILIKE: {
|
|
@@ -310,17 +254,13 @@ var FilterSet = class FilterSet {
|
|
|
310
254
|
});
|
|
311
255
|
return filter;
|
|
312
256
|
}
|
|
313
|
-
case InternalFilterType.RANGE: {
|
|
314
|
-
const lookupKey = `${String(resolver.column)}__${resolver.op}`;
|
|
315
|
-
return { [lookupKey]: value };
|
|
316
|
-
}
|
|
257
|
+
case InternalFilterType.RANGE: return { [`${String(resolver.column)}__${resolver.op}`]: value };
|
|
317
258
|
case InternalFilterType.IN: {
|
|
318
259
|
const arr = Array.isArray(value) ? value : String(value).split(",");
|
|
319
|
-
|
|
320
|
-
return { [lookupKey]: arr };
|
|
260
|
+
return { [`${String(resolver.column)}__in`]: arr };
|
|
321
261
|
}
|
|
322
262
|
case InternalFilterType.CUSTOM: return resolver.apply(value);
|
|
323
|
-
default: return
|
|
263
|
+
default: return;
|
|
324
264
|
}
|
|
325
265
|
}
|
|
326
266
|
applyFieldParserOverride(resolver, parsers) {
|
|
@@ -341,28 +281,31 @@ var FilterSet = class FilterSet {
|
|
|
341
281
|
}
|
|
342
282
|
}
|
|
343
283
|
};
|
|
344
|
-
|
|
345
284
|
//#endregion
|
|
346
285
|
//#region src/filters/index.ts
|
|
347
|
-
var filters_exports = {};
|
|
348
|
-
__export(filters_exports, { FilterSet: () => FilterSet });
|
|
349
|
-
|
|
286
|
+
var filters_exports = /* @__PURE__ */ __exportAll({ FilterSet: () => FilterSet });
|
|
350
287
|
//#endregion
|
|
351
288
|
//#region src/pagination/CursorPaginationInput.ts
|
|
352
|
-
const CursorPaginationInput = z
|
|
353
|
-
limit: z
|
|
354
|
-
if (value ===
|
|
289
|
+
const CursorPaginationInput = z.object({
|
|
290
|
+
limit: z.preprocess((value) => {
|
|
291
|
+
if (value === void 0 || value === null || value === "") return;
|
|
355
292
|
const parsed = Number.parseInt(String(value), 10);
|
|
356
|
-
if (!Number.isFinite(parsed) || parsed <= 0) return
|
|
293
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return;
|
|
357
294
|
return parsed;
|
|
358
|
-
}, z
|
|
359
|
-
cursor: z
|
|
360
|
-
ordering: z
|
|
295
|
+
}, z.number().int().min(1).transform((value) => Math.min(value, 100)).optional()),
|
|
296
|
+
cursor: z.string().nullable().default(null),
|
|
297
|
+
ordering: z.string().optional()
|
|
361
298
|
});
|
|
362
|
-
|
|
363
299
|
//#endregion
|
|
364
300
|
//#region src/paginators/CursorPaginator.ts
|
|
301
|
+
/**
|
|
302
|
+
* Represents a single cursor page of results.
|
|
303
|
+
* Cursor pages do not expose numeric page navigation like offset pagination.
|
|
304
|
+
*/
|
|
365
305
|
var CursorPage = class CursorPage {
|
|
306
|
+
results;
|
|
307
|
+
nextCursor;
|
|
308
|
+
previousCursor;
|
|
366
309
|
static BRAND = "tango.resources.cursor_page";
|
|
367
310
|
__tangoBrand = CursorPage.BRAND;
|
|
368
311
|
constructor(results, nextCursor, previousCursor) {
|
|
@@ -394,7 +337,15 @@ var CursorPage = class CursorPage {
|
|
|
394
337
|
return this.results.length;
|
|
395
338
|
}
|
|
396
339
|
};
|
|
340
|
+
/**
|
|
341
|
+
* Cursor-based paginator for stable forward navigation with opaque cursor tokens.
|
|
342
|
+
* It supports `limit`, `cursor`, and `ordering` query params and returns DRF-style
|
|
343
|
+
* paginated envelopes with cursor links.
|
|
344
|
+
*/
|
|
397
345
|
var CursorPaginator = class CursorPaginator extends BasePaginator {
|
|
346
|
+
queryset;
|
|
347
|
+
perPage;
|
|
348
|
+
cursorField;
|
|
398
349
|
static BRAND = "tango.resources.cursor_paginator";
|
|
399
350
|
__tangoBrand = CursorPaginator.BRAND;
|
|
400
351
|
limit;
|
|
@@ -420,9 +371,9 @@ var CursorPaginator = class CursorPaginator extends BasePaginator {
|
|
|
420
371
|
*/
|
|
421
372
|
parse(params) {
|
|
422
373
|
const parsed = CursorPaginationInput.parse({
|
|
423
|
-
limit: params.get("limit") ??
|
|
374
|
+
limit: params.get("limit") ?? void 0,
|
|
424
375
|
cursor: params.get("cursor"),
|
|
425
|
-
ordering: params.get("ordering") ??
|
|
376
|
+
ordering: params.get("ordering") ?? void 0
|
|
426
377
|
});
|
|
427
378
|
this.limit = parsed.limit ?? this.perPage;
|
|
428
379
|
this.cursor = parsed.cursor;
|
|
@@ -470,8 +421,7 @@ var CursorPaginator = class CursorPaginator extends BasePaginator {
|
|
|
470
421
|
const decoded = this.decodeCursor(this.cursor);
|
|
471
422
|
if (decoded.field !== String(this.cursorField)) throw new Error("Invalid cursor: field mismatch");
|
|
472
423
|
const lookup = this.direction === "asc" ? "__gt" : "__lt";
|
|
473
|
-
const
|
|
474
|
-
const filterInput = { [fieldLookup]: decoded.value };
|
|
424
|
+
const filterInput = { [`${String(this.cursorField)}${lookup}`]: decoded.value };
|
|
475
425
|
qs = qs.filter(filterInput);
|
|
476
426
|
}
|
|
477
427
|
const orderToken = this.direction === "asc" ? String(this.cursorField) : `-${String(this.cursorField)}`;
|
|
@@ -523,39 +473,40 @@ var CursorPaginator = class CursorPaginator extends BasePaginator {
|
|
|
523
473
|
return parsed;
|
|
524
474
|
}
|
|
525
475
|
};
|
|
526
|
-
|
|
527
476
|
//#endregion
|
|
528
477
|
//#region src/pagination/index.ts
|
|
529
|
-
var pagination_exports = {
|
|
530
|
-
__export(pagination_exports, {
|
|
478
|
+
var pagination_exports = /* @__PURE__ */ __exportAll({
|
|
531
479
|
BasePaginator: () => BasePaginator,
|
|
532
480
|
CursorPaginationInput: () => CursorPaginationInput,
|
|
533
481
|
CursorPaginator: () => CursorPaginator,
|
|
534
482
|
OffsetPaginationInput: () => OffsetPaginationInput,
|
|
535
483
|
OffsetPaginator: () => OffsetPaginator
|
|
536
484
|
});
|
|
537
|
-
|
|
538
485
|
//#endregion
|
|
539
486
|
//#region src/paginators/index.ts
|
|
540
|
-
var paginators_exports = {
|
|
541
|
-
__export(paginators_exports, {
|
|
487
|
+
var paginators_exports = /* @__PURE__ */ __exportAll({
|
|
542
488
|
CursorPaginator: () => CursorPaginator,
|
|
543
489
|
OffsetPaginator: () => OffsetPaginator
|
|
544
490
|
});
|
|
545
|
-
|
|
546
491
|
//#endregion
|
|
547
492
|
//#region src/resource/index.ts
|
|
548
|
-
var resource_exports = {};
|
|
549
|
-
|
|
493
|
+
var resource_exports = /* @__PURE__ */ __exportAll({});
|
|
550
494
|
//#endregion
|
|
551
495
|
//#region src/serializer/Serializer.ts
|
|
552
496
|
const logger = getLogger("tango.resources.serializer");
|
|
553
497
|
let hasWarnedAboutToRepresentationDeprecation = false;
|
|
498
|
+
/**
|
|
499
|
+
* DRF-inspired base serializer backed by Zod schemas.
|
|
500
|
+
*
|
|
501
|
+
* Tango serializers keep Zod as the source of truth for validation and type
|
|
502
|
+
* inference while centralizing create, update, and representation workflows in
|
|
503
|
+
* one class-owned contract.
|
|
504
|
+
*/
|
|
554
505
|
var Serializer = class {
|
|
555
506
|
static createSchema = z.unknown();
|
|
556
507
|
static updateSchema = z.unknown();
|
|
557
508
|
static outputSchema = z.unknown();
|
|
558
|
-
static outputResolvers =
|
|
509
|
+
static outputResolvers = void 0;
|
|
559
510
|
/**
|
|
560
511
|
* Return the serializer class for the current instance.
|
|
561
512
|
*/
|
|
@@ -636,7 +587,6 @@ var Serializer = class {
|
|
|
636
587
|
};
|
|
637
588
|
}
|
|
638
589
|
};
|
|
639
|
-
|
|
640
590
|
//#endregion
|
|
641
591
|
//#region src/serializer/internal/InternalSerializerRelationKind.ts
|
|
642
592
|
const InternalSerializerRelationKind = { MANY_TO_MANY: "manyToMany" };
|
|
@@ -648,12 +598,14 @@ const InternalManyToManyWriteStrategyKind = {
|
|
|
648
598
|
PK_LIST: "pkList",
|
|
649
599
|
SLUG_LIST: "slugList"
|
|
650
600
|
};
|
|
651
|
-
|
|
652
601
|
//#endregion
|
|
653
602
|
//#region src/serializer/ModelSerializer.ts
|
|
603
|
+
/**
|
|
604
|
+
* Zod-backed serializer with default model-manager persistence behavior.
|
|
605
|
+
*/
|
|
654
606
|
var ModelSerializer = class extends Serializer {
|
|
655
607
|
static model;
|
|
656
|
-
static relationFields =
|
|
608
|
+
static relationFields = void 0;
|
|
657
609
|
/**
|
|
658
610
|
* Return the Tango model backing this serializer.
|
|
659
611
|
*/
|
|
@@ -680,9 +632,8 @@ var ModelSerializer = class extends Serializer {
|
|
|
680
632
|
getOutputResolvers() {
|
|
681
633
|
const baseResolvers = super.getOutputResolvers();
|
|
682
634
|
const relationFields = this.getRelationFields();
|
|
683
|
-
const relationResolvers = Object.fromEntries(Object.entries(relationFields).map(([fieldName, field]) => [fieldName, async (record) => this.serializeRelationField(record, fieldName, field)]));
|
|
684
635
|
return {
|
|
685
|
-
...
|
|
636
|
+
...Object.fromEntries(Object.entries(relationFields).map(([fieldName, field]) => [fieldName, async (record) => this.serializeRelationField(record, fieldName, field)])),
|
|
686
637
|
...baseResolvers
|
|
687
638
|
};
|
|
688
639
|
}
|
|
@@ -743,14 +694,12 @@ var ModelSerializer = class extends Serializer {
|
|
|
743
694
|
async applyRelationWrites(record, writes) {
|
|
744
695
|
const relationFields = this.getRelationFields();
|
|
745
696
|
for (const [fieldName, value] of Object.entries(writes)) {
|
|
746
|
-
|
|
747
|
-
if (!field) continue;
|
|
697
|
+
if (!relationFields[fieldName]) continue;
|
|
748
698
|
await this.syncManyToManyRelation(record, fieldName, value);
|
|
749
699
|
}
|
|
750
700
|
}
|
|
751
701
|
async serializeRelationField(record, fieldName, field) {
|
|
752
|
-
const
|
|
753
|
-
const rows = (await manager.all().fetch()).results;
|
|
702
|
+
const rows = (await this.getManyToManyManager(record, fieldName).all().fetch()).results;
|
|
754
703
|
const relationMeta = this.getManyToManyRelationMeta(fieldName);
|
|
755
704
|
switch (field.read.kind) {
|
|
756
705
|
case InternalManyToManyReadStrategyKind.PK_LIST: return rows.map((row) => row[relationMeta.targetPrimaryKey]);
|
|
@@ -758,7 +707,7 @@ var ModelSerializer = class extends Serializer {
|
|
|
758
707
|
}
|
|
759
708
|
}
|
|
760
709
|
async syncManyToManyRelation(record, fieldName, value) {
|
|
761
|
-
if (value ===
|
|
710
|
+
if (value === void 0) return;
|
|
762
711
|
const manager = this.getManyToManyManager(record, fieldName);
|
|
763
712
|
const field = this.getRelationFields()[fieldName];
|
|
764
713
|
if (!field) return;
|
|
@@ -798,12 +747,11 @@ var ModelSerializer = class extends Serializer {
|
|
|
798
747
|
return manager;
|
|
799
748
|
}
|
|
800
749
|
getManyToManyRelationMeta(fieldName) {
|
|
801
|
-
const relation
|
|
802
|
-
if (!relation
|
|
803
|
-
return relation
|
|
750
|
+
const relation = this.getManager().meta.relations?.[fieldName];
|
|
751
|
+
if (!relation || relation.kind !== InternalSerializerRelationKind.MANY_TO_MANY) throw new Error(`Relation field '${fieldName}' is not a persisted many-to-many edge.`);
|
|
752
|
+
return relation;
|
|
804
753
|
}
|
|
805
754
|
};
|
|
806
|
-
|
|
807
755
|
//#endregion
|
|
808
756
|
//#region src/serializer/relation.ts
|
|
809
757
|
function pkList() {
|
|
@@ -834,18 +782,20 @@ const relation = {
|
|
|
834
782
|
nested,
|
|
835
783
|
slugList
|
|
836
784
|
};
|
|
837
|
-
|
|
838
785
|
//#endregion
|
|
839
786
|
//#region src/serializer/index.ts
|
|
840
|
-
var serializer_exports = {
|
|
841
|
-
__export(serializer_exports, {
|
|
787
|
+
var serializer_exports = /* @__PURE__ */ __exportAll({
|
|
842
788
|
ModelSerializer: () => ModelSerializer,
|
|
843
789
|
Serializer: () => Serializer,
|
|
844
790
|
relation: () => relation
|
|
845
791
|
});
|
|
846
|
-
|
|
847
792
|
//#endregion
|
|
848
793
|
//#region src/viewset/ModelViewSet.ts
|
|
794
|
+
/**
|
|
795
|
+
* Base class for creating RESTful API viewsets with built-in CRUD operations.
|
|
796
|
+
* Provides list, retrieve, create, update, and delete methods with filtering,
|
|
797
|
+
* search, pagination, and ordering support.
|
|
798
|
+
*/
|
|
849
799
|
var ModelViewSet = class ModelViewSet {
|
|
850
800
|
static BRAND = "tango.resources.model_view_set";
|
|
851
801
|
static actions = [];
|
|
@@ -869,8 +819,7 @@ var ModelViewSet = class ModelViewSet {
|
|
|
869
819
|
static getActions(viewsetOrConstructor) {
|
|
870
820
|
const viewset = ModelViewSet.isModelViewSet(viewsetOrConstructor) ? viewsetOrConstructor : null;
|
|
871
821
|
const constructorValue = viewset ? viewset.constructor : viewsetOrConstructor;
|
|
872
|
-
|
|
873
|
-
return actions.map((action) => ({
|
|
822
|
+
return (Array.isArray(constructorValue.actions) ? constructorValue.actions : []).map((action) => ({
|
|
874
823
|
...action,
|
|
875
824
|
path: viewset ? viewset.resolveActionPath(action) : ModelViewSet.resolvePathFromDescriptor(action.name, action.path)
|
|
876
825
|
}));
|
|
@@ -950,8 +899,7 @@ var ModelViewSet = class ModelViewSet {
|
|
|
950
899
|
const search = params.getSearch();
|
|
951
900
|
if (search && this.searchFields.length > 0) {
|
|
952
901
|
const searchFilters = this.searchFields.map((field) => {
|
|
953
|
-
|
|
954
|
-
return { [lookup]: search };
|
|
902
|
+
return { [`${String(field)}__icontains`]: search };
|
|
955
903
|
});
|
|
956
904
|
qs = qs.filter(Q.or(...searchFilters));
|
|
957
905
|
}
|
|
@@ -963,12 +911,10 @@ var ModelViewSet = class ModelViewSet {
|
|
|
963
911
|
});
|
|
964
912
|
if (orderTokens.length > 0) qs = qs.orderBy(...orderTokens.map((token) => token));
|
|
965
913
|
}
|
|
966
|
-
const
|
|
967
|
-
const
|
|
968
|
-
const totalCountPromise = paginator.needsTotalCount() ? qs.count() : Promise.resolve(undefined);
|
|
914
|
+
const resultPromise = paginator.apply(qs).fetch();
|
|
915
|
+
const totalCountPromise = paginator.needsTotalCount() ? qs.count() : Promise.resolve(void 0);
|
|
969
916
|
const [result, totalCount] = await Promise.all([resultPromise, totalCountPromise]);
|
|
970
|
-
const
|
|
971
|
-
const rows = await serializer.serializeMany(result.items);
|
|
917
|
+
const rows = await this.getSerializer().serializeMany(result.items);
|
|
972
918
|
const response = paginator.toResponse(rows, { totalCount });
|
|
973
919
|
return TangoResponse.json(response, { status: 200 });
|
|
974
920
|
} catch (error) {
|
|
@@ -997,7 +943,7 @@ var ModelViewSet = class ModelViewSet {
|
|
|
997
943
|
try {
|
|
998
944
|
const body = await ctx.request.json();
|
|
999
945
|
const result = await this.getSerializer().create(body);
|
|
1000
|
-
return TangoResponse.created(
|
|
946
|
+
return TangoResponse.created(void 0, result);
|
|
1001
947
|
} catch (error) {
|
|
1002
948
|
return this.handleError(error);
|
|
1003
949
|
}
|
|
@@ -1059,12 +1005,10 @@ var ModelViewSet = class ModelViewSet {
|
|
|
1059
1005
|
return primaryKeyField.name;
|
|
1060
1006
|
}
|
|
1061
1007
|
};
|
|
1062
|
-
|
|
1063
1008
|
//#endregion
|
|
1064
1009
|
//#region src/viewset/index.ts
|
|
1065
|
-
var viewset_exports = {};
|
|
1066
|
-
__export(viewset_exports, { ModelViewSet: () => ModelViewSet });
|
|
1067
|
-
|
|
1010
|
+
var viewset_exports = /* @__PURE__ */ __exportAll({ ModelViewSet: () => ModelViewSet });
|
|
1068
1011
|
//#endregion
|
|
1069
1012
|
export { APIView, CreateAPIView, CreateModelMixin, CursorPaginationInput, CursorPaginator, DestroyModelMixin, FilterSet, GenericAPIView, ListAPIView, ListCreateAPIView, ListModelMixin, ModelSerializer, ModelViewSet, OffsetPaginationInput, OffsetPaginator, RequestContext, RetrieveAPIView, RetrieveDestroyAPIView, RetrieveModelMixin, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, Serializer, UpdateModelMixin, context_exports as context, filters_exports as filters, pagination_exports as pagination, paginators_exports as paginators, relation, resource_exports as resource, serializer_exports as serializer, view_exports as view, viewset_exports as viewset };
|
|
1013
|
+
|
|
1070
1014
|
//# sourceMappingURL=index.js.map
|