@statezero/core 0.2.23 → 0.2.26
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/filtering/localFiltering.d.ts +1 -8
- package/dist/filtering/localFiltering.js +129 -47
- package/dist/models/backend1/django_app/comprehensivemodel.schema.json +3 -3
- package/dist/models/backend1/django_app/custompkmodel.schema.json +4 -4
- package/dist/models/backend1/django_app/dailyrate.schema.json +5 -5
- package/dist/models/backend1/django_app/dummymodel.schema.json +2 -2
- package/dist/models/backend1/django_app/index.js +3 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel1.d.ts +118 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel1.js +71 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel1.schema.json +94 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel2.d.ts +118 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel2.js +71 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel2.schema.json +94 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel3.d.ts +134 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel3.js +71 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel3.schema.json +112 -0
- package/dist/models/backend1/django_app/modelwithcustompkrelation.schema.json +2 -2
- package/dist/models/backend1/django_app/modelwithrestrictedfields.d.ts +1 -1
- package/dist/models/backend1/django_app/modelwithrestrictedfields.schema.json +5 -5
- package/dist/models/backend1/django_app/namefiltercustompkmodel.schema.json +4 -4
- package/dist/models/backend1/django_app/order.schema.json +4 -4
- package/dist/models/backend1/django_app/orderitem.schema.json +4 -4
- package/dist/models/backend1/django_app/product.schema.json +11 -11
- package/dist/models/backend1/django_app/productcategory.schema.json +2 -2
- package/dist/models/backend1/django_app/rateplan.schema.json +2 -2
- package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.d.ts +1 -1
- package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.schema.json +4 -4
- package/dist/models/default/django_app/comprehensivemodel.schema.json +3 -3
- package/dist/models/default/django_app/custompkmodel.schema.json +4 -4
- package/dist/models/default/django_app/dailyrate.schema.json +5 -5
- package/dist/models/default/django_app/dummymodel.schema.json +2 -2
- package/dist/models/default/django_app/index.js +3 -0
- package/dist/models/default/django_app/m2mdepthtestlevel1.d.ts +118 -0
- package/dist/models/default/django_app/m2mdepthtestlevel1.js +71 -0
- package/dist/models/default/django_app/m2mdepthtestlevel1.schema.json +94 -0
- package/dist/models/default/django_app/m2mdepthtestlevel2.d.ts +118 -0
- package/dist/models/default/django_app/m2mdepthtestlevel2.js +71 -0
- package/dist/models/default/django_app/m2mdepthtestlevel2.schema.json +94 -0
- package/dist/models/default/django_app/m2mdepthtestlevel3.d.ts +134 -0
- package/dist/models/default/django_app/m2mdepthtestlevel3.js +71 -0
- package/dist/models/default/django_app/m2mdepthtestlevel3.schema.json +112 -0
- package/dist/models/default/django_app/modelwithcustompkrelation.schema.json +2 -2
- package/dist/models/default/django_app/modelwithrestrictedfields.d.ts +1 -1
- package/dist/models/default/django_app/modelwithrestrictedfields.schema.json +5 -5
- package/dist/models/default/django_app/namefiltercustompkmodel.schema.json +4 -4
- package/dist/models/default/django_app/order.schema.json +4 -4
- package/dist/models/default/django_app/orderitem.schema.json +4 -4
- package/dist/models/default/django_app/product.schema.json +11 -11
- package/dist/models/default/django_app/productcategory.schema.json +2 -2
- package/dist/models/default/django_app/rateplan.schema.json +2 -2
- package/dist/models/default/django_app/restrictedfieldrelatedmodel.d.ts +1 -1
- package/dist/models/default/django_app/restrictedfieldrelatedmodel.schema.json +4 -4
- package/package.json +1 -1
|
@@ -7,14 +7,7 @@
|
|
|
7
7
|
* @returns {string[]} Array of dot-notation paths, e.g. ['author.id','createdAt.year']
|
|
8
8
|
*/
|
|
9
9
|
export function getRequiredFields(queryBuild: Object, ModelClass: Class): string[];
|
|
10
|
-
|
|
11
|
-
* Pick out only the required fields from a (possibly nested) model object.
|
|
12
|
-
*
|
|
13
|
-
* @param {string[]} requiredPaths – e.g. ['id','related.name','related.age']
|
|
14
|
-
* @param {Object} instance – e.g. { id: 3, related: { name: 'bob', age: 12, foo: 'bar' } }
|
|
15
|
-
* @returns {Object} – e.g. { id: 3, related: { name: 'bob', age: 12 } }
|
|
16
|
-
*/
|
|
17
|
-
export function pickRequiredFields(requiredPaths: string[], instance: Object): Object;
|
|
10
|
+
export function pickRequiredFields(requiredPaths: any, instance: any): {};
|
|
18
11
|
/**
|
|
19
12
|
* Filter and order a collection of data objects according to a QuerySet's AST.
|
|
20
13
|
* This combines getRequiredFields, pickRequiredFields, and processQuery in one function.
|
|
@@ -99,6 +99,36 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
|
|
|
99
99
|
const relationship = currentModel.relationshipFields.get(part);
|
|
100
100
|
const relatedModel = relationship.ModelClass();
|
|
101
101
|
const relationshipType = relationship.relationshipType;
|
|
102
|
+
// If this is not the last part and it's M2M, recursively process the remaining path
|
|
103
|
+
if (!isLastPart && relationshipType === 'many-to-many') {
|
|
104
|
+
// Build the remaining path including any lookup operators
|
|
105
|
+
const remainingFieldParts = fieldParts.slice(i + 1);
|
|
106
|
+
let fullRemainingPath = remainingFieldParts.join('__');
|
|
107
|
+
if (lookupChain.length > 0) {
|
|
108
|
+
fullRemainingPath += '__' + lookupChain.join('__');
|
|
109
|
+
}
|
|
110
|
+
else if (lookup) {
|
|
111
|
+
fullRemainingPath += '__' + lookup;
|
|
112
|
+
}
|
|
113
|
+
// Recursively process the remaining path with the related model
|
|
114
|
+
const innerResult = processFieldPath(fullRemainingPath, value, relatedModel, options);
|
|
115
|
+
// Build the full field path including any FK traversal before this M2M field
|
|
116
|
+
// e.g., for owner__roles__name, processedPath=['owner'], part='roles'
|
|
117
|
+
// so fullFieldPath becomes 'owner.roles'
|
|
118
|
+
const fullFieldPath = processedPath.length > 0
|
|
119
|
+
? processedPath.join('.') + '.' + part
|
|
120
|
+
: part;
|
|
121
|
+
// Build the required path for data picking (full dot-notation path)
|
|
122
|
+
const innerRequiredPath = innerResult.requiredPath || innerResult.field;
|
|
123
|
+
const requiredPath = `${fullFieldPath}.${innerRequiredPath}`;
|
|
124
|
+
// Wrap the inner result in $elemMatch for this M2M field
|
|
125
|
+
return {
|
|
126
|
+
field: fullFieldPath,
|
|
127
|
+
operator: { $elemMatch: { [innerResult.field]: innerResult.operator } },
|
|
128
|
+
isM2M: true,
|
|
129
|
+
requiredPath // Full path for data picking
|
|
130
|
+
};
|
|
131
|
+
}
|
|
102
132
|
// Add this relationship field to the path
|
|
103
133
|
processedPath.push(part);
|
|
104
134
|
// If this is not the last part, update the current model to the related model
|
|
@@ -168,6 +198,10 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
|
|
|
168
198
|
if (normalizedValue && typeof normalizedValue === 'object' && 'pk' in normalizedValue) {
|
|
169
199
|
raw = normalizedValue.pk;
|
|
170
200
|
}
|
|
201
|
+
// For M2M fields, use $elemMatch to check if any element's pk matches
|
|
202
|
+
if (isM2M) {
|
|
203
|
+
return { field: finalPath, operator: { $elemMatch: { pk: { $eq: raw } } }, isM2M: true };
|
|
204
|
+
}
|
|
171
205
|
return { field: finalPath, operator: { $eq: raw } };
|
|
172
206
|
}
|
|
173
207
|
// Default to direct equality
|
|
@@ -217,18 +251,19 @@ function createOperatorFromLookup(field, lookup, value, isRelationship, ModelCla
|
|
|
217
251
|
// For relationship fields with lookups, we need special handling
|
|
218
252
|
if (lookup === 'isnull') {
|
|
219
253
|
if (isM2M) {
|
|
220
|
-
// For M2M fields, isnull=True means null OR empty array
|
|
221
|
-
// that can mean the field was not fetched so we can't be sure
|
|
254
|
+
// For M2M fields, isnull=True means null OR empty array
|
|
222
255
|
// isnull=False means has at least one item
|
|
223
|
-
// Use
|
|
256
|
+
// Use document-level $where to check the array itself (not iterate elements)
|
|
257
|
+
const m2mField = field;
|
|
258
|
+
const checkEmpty = value;
|
|
224
259
|
return {
|
|
225
|
-
field,
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
260
|
+
field: '$where', // document-level operator
|
|
261
|
+
requiredPath: field, // need the M2M field itself for data picking
|
|
262
|
+
operator: function (doc) {
|
|
263
|
+
const fieldValue = doc[m2mField];
|
|
264
|
+
const isEmpty = fieldValue === null ||
|
|
265
|
+
(Array.isArray(fieldValue) && fieldValue.length === 0);
|
|
266
|
+
return checkEmpty ? isEmpty : !isEmpty;
|
|
232
267
|
}
|
|
233
268
|
};
|
|
234
269
|
}
|
|
@@ -239,10 +274,17 @@ function createOperatorFromLookup(field, lookup, value, isRelationship, ModelCla
|
|
|
239
274
|
};
|
|
240
275
|
}
|
|
241
276
|
else if (lookup === 'in') {
|
|
277
|
+
// For M2M, check if any element's pk is in the provided array
|
|
278
|
+
if (isM2M) {
|
|
279
|
+
return { field, operator: { $elemMatch: { pk: { $in: value } } }, isM2M: true };
|
|
280
|
+
}
|
|
242
281
|
return { field, operator: { $in: value } };
|
|
243
282
|
}
|
|
244
283
|
else {
|
|
245
284
|
// Default handling for relationship fields
|
|
285
|
+
if (isM2M) {
|
|
286
|
+
return { field, operator: { $elemMatch: { pk: { $eq: value } } }, isM2M: true };
|
|
287
|
+
}
|
|
246
288
|
return { field, operator: { $eq: value } };
|
|
247
289
|
}
|
|
248
290
|
}
|
|
@@ -545,10 +587,11 @@ function createFilterWithDateOperations(criteria, ModelClass) {
|
|
|
545
587
|
function convertToSiftCriteria(conditions, ModelClass) {
|
|
546
588
|
const result = {};
|
|
547
589
|
const datePartFilters = new Map(); // Map to collect date part filters by field
|
|
590
|
+
const m2mConditions = new Map(); // Map to collect M2M $elemMatch conditions by field
|
|
548
591
|
for (const [key, value] of Object.entries(conditions)) {
|
|
549
592
|
try {
|
|
550
593
|
const processedResult = processFieldPath(key, value, ModelClass);
|
|
551
|
-
const { field, operator, isDatePart } = processedResult;
|
|
594
|
+
const { field, operator, isDatePart, isM2M } = processedResult;
|
|
552
595
|
if (isDatePart) {
|
|
553
596
|
// Handle date part operators separately
|
|
554
597
|
if (!datePartFilters.has(field)) {
|
|
@@ -556,6 +599,13 @@ function convertToSiftCriteria(conditions, ModelClass) {
|
|
|
556
599
|
}
|
|
557
600
|
datePartFilters.get(field).push({ [field]: operator });
|
|
558
601
|
}
|
|
602
|
+
else if (isM2M && operator.$elemMatch) {
|
|
603
|
+
// Collect M2M conditions to merge into single $elemMatch
|
|
604
|
+
if (!m2mConditions.has(field)) {
|
|
605
|
+
m2mConditions.set(field, []);
|
|
606
|
+
}
|
|
607
|
+
m2mConditions.get(field).push(operator.$elemMatch);
|
|
608
|
+
}
|
|
559
609
|
else {
|
|
560
610
|
// For regular operators, merge if we already have criteria for this field
|
|
561
611
|
if (result[field]) {
|
|
@@ -570,6 +620,17 @@ function convertToSiftCriteria(conditions, ModelClass) {
|
|
|
570
620
|
throw new Error(`Failed to process field '${key}': ${error.message}`);
|
|
571
621
|
}
|
|
572
622
|
}
|
|
623
|
+
// Merge M2M conditions: all conditions on same M2M field go into single $elemMatch
|
|
624
|
+
// so the SAME related object must match ALL conditions
|
|
625
|
+
for (const [field, elemMatchConditions] of m2mConditions.entries()) {
|
|
626
|
+
if (elemMatchConditions.length === 1) {
|
|
627
|
+
result[field] = { $elemMatch: elemMatchConditions[0] };
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
// Multiple conditions - wrap in $and so same element must match all
|
|
631
|
+
result[field] = { $elemMatch: { $and: elemMatchConditions } };
|
|
632
|
+
}
|
|
633
|
+
}
|
|
573
634
|
// If we have date part filters, combine them with the result
|
|
574
635
|
if (datePartFilters.size > 0) {
|
|
575
636
|
const andConditions = [];
|
|
@@ -663,6 +724,9 @@ function convertFilterNodeToSiftCriteria(filterNode, ModelClass) {
|
|
|
663
724
|
return null;
|
|
664
725
|
if (childCriteria.length === 1)
|
|
665
726
|
return childCriteria[0];
|
|
727
|
+
// Chained filters use $and at top level - this gives ANY/ANY semantics for M2M
|
|
728
|
+
// (each $elemMatch can be satisfied by different elements)
|
|
729
|
+
// This matches Django's chained .filter() behavior
|
|
666
730
|
return { $and: childCriteria };
|
|
667
731
|
}
|
|
668
732
|
// For compound OR nodes
|
|
@@ -863,12 +927,24 @@ export function getRequiredFields(queryBuild, ModelClass) {
|
|
|
863
927
|
function addPath(rawKey) {
|
|
864
928
|
try {
|
|
865
929
|
// We pass `null` as the value, since we only care about .field
|
|
866
|
-
const { field } = processFieldPath(rawKey, null, ModelClass);
|
|
867
|
-
|
|
930
|
+
const { field, isM2M, requiredPath } = processFieldPath(rawKey, null, ModelClass);
|
|
931
|
+
// Use requiredPath if available (for M2M traversal), otherwise use field
|
|
932
|
+
// For M2M fields at the end of a path (no requiredPath), we need the pk field
|
|
933
|
+
let finalPath;
|
|
934
|
+
if (requiredPath) {
|
|
935
|
+
finalPath = requiredPath;
|
|
936
|
+
}
|
|
937
|
+
else if (isM2M) {
|
|
938
|
+
finalPath = `${field}.pk`;
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
finalPath = field;
|
|
942
|
+
}
|
|
943
|
+
paths.add(finalPath);
|
|
868
944
|
}
|
|
869
945
|
catch (err) {
|
|
870
|
-
// if a key doesn
|
|
871
|
-
console.warn(`getRequiredFields: couldn
|
|
946
|
+
// if a key doesn't map, warn and skip it
|
|
947
|
+
console.warn(`getRequiredFields: couldn't process "${rawKey}": ${err.message}`);
|
|
872
948
|
}
|
|
873
949
|
}
|
|
874
950
|
// Recursively walk your filter AST
|
|
@@ -917,42 +993,48 @@ export function getRequiredFields(queryBuild, ModelClass) {
|
|
|
917
993
|
* @param {Object} instance – e.g. { id: 3, related: { name: 'bob', age: 12, foo: 'bar' } }
|
|
918
994
|
* @returns {Object} – e.g. { id: 3, related: { name: 'bob', age: 12 } }
|
|
919
995
|
*/
|
|
996
|
+
/**
|
|
997
|
+
* Recursively sets a value in a result object following a path.
|
|
998
|
+
* Handles arrays (M2M fields) by mapping over each element.
|
|
999
|
+
*/
|
|
1000
|
+
function setNestedValueRecursive(result, source, pathParts) {
|
|
1001
|
+
if (source == null || pathParts.length === 0) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const [current, ...rest] = pathParts;
|
|
1005
|
+
const sourceValue = source[current];
|
|
1006
|
+
if (sourceValue === undefined) {
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
if (rest.length === 0) {
|
|
1010
|
+
// Last part - set the value directly, keeping M2M as full objects
|
|
1011
|
+
result[current] = sourceValue;
|
|
1012
|
+
}
|
|
1013
|
+
else if (Array.isArray(sourceValue)) {
|
|
1014
|
+
// M2M array with nested path - recursively extract from each element
|
|
1015
|
+
if (!(current in result)) {
|
|
1016
|
+
result[current] = [];
|
|
1017
|
+
}
|
|
1018
|
+
sourceValue.forEach((item, idx) => {
|
|
1019
|
+
if (result[current][idx] === undefined) {
|
|
1020
|
+
result[current][idx] = {};
|
|
1021
|
+
}
|
|
1022
|
+
setNestedValueRecursive(result[current][idx], item, rest);
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
else if (typeof sourceValue === 'object') {
|
|
1026
|
+
// Regular nested object (FK)
|
|
1027
|
+
if (!(current in result)) {
|
|
1028
|
+
result[current] = {};
|
|
1029
|
+
}
|
|
1030
|
+
setNestedValueRecursive(result[current], sourceValue, rest);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
920
1033
|
export function pickRequiredFields(requiredPaths, instance) {
|
|
921
1034
|
const result = {};
|
|
922
1035
|
requiredPaths.forEach(path => {
|
|
923
1036
|
const parts = path.split('.');
|
|
924
|
-
|
|
925
|
-
let value = instance;
|
|
926
|
-
for (const key of parts) {
|
|
927
|
-
if (value == null || !(key in value)) {
|
|
928
|
-
value = undefined;
|
|
929
|
-
break;
|
|
930
|
-
}
|
|
931
|
-
value = value[key];
|
|
932
|
-
}
|
|
933
|
-
if (value === undefined) {
|
|
934
|
-
// skip missing
|
|
935
|
-
return;
|
|
936
|
-
}
|
|
937
|
-
// Convert M2M arrays from Model instances to PKs for comparison
|
|
938
|
-
// This handles the case where the live representation returns [Model1, Model2]
|
|
939
|
-
// but we need [pk1, pk2] for sift filtering
|
|
940
|
-
if (Array.isArray(value) && value.length > 0 && value[0]?.pk !== undefined) {
|
|
941
|
-
value = value.map(item => item.pk);
|
|
942
|
-
}
|
|
943
|
-
// Build nested structure in the result
|
|
944
|
-
let cursor = result;
|
|
945
|
-
parts.forEach((key, idx) => {
|
|
946
|
-
if (idx === parts.length - 1) {
|
|
947
|
-
cursor[key] = value;
|
|
948
|
-
}
|
|
949
|
-
else {
|
|
950
|
-
if (!(key in cursor)) {
|
|
951
|
-
cursor[key] = {};
|
|
952
|
-
}
|
|
953
|
-
cursor = cursor[key];
|
|
954
|
-
}
|
|
955
|
-
});
|
|
1037
|
+
setNestedValueRecursive(result, instance, parts);
|
|
956
1038
|
});
|
|
957
1039
|
return result;
|
|
958
1040
|
}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"char_field"
|
|
10
10
|
],
|
|
11
11
|
"searchable_fields": [
|
|
12
|
-
"
|
|
13
|
-
"
|
|
12
|
+
"text_field",
|
|
13
|
+
"char_field"
|
|
14
14
|
],
|
|
15
15
|
"ordering_fields": [
|
|
16
16
|
"int_field"
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"format": "date-time",
|
|
106
106
|
"max_length": null,
|
|
107
107
|
"choices": null,
|
|
108
|
-
"default": "2026-01-
|
|
108
|
+
"default": "2026-01-18T17:06:00.558317+00:00",
|
|
109
109
|
"validators": [],
|
|
110
110
|
"max_digits": null,
|
|
111
111
|
"decimal_places": null,
|
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
"plural_title": "Custom Pk Models",
|
|
6
6
|
"primary_key_field": "custom_pk",
|
|
7
7
|
"filterable_fields": [
|
|
8
|
-
"
|
|
9
|
-
"
|
|
8
|
+
"name",
|
|
9
|
+
"custom_pk"
|
|
10
10
|
],
|
|
11
11
|
"searchable_fields": [
|
|
12
12
|
"name"
|
|
13
13
|
],
|
|
14
14
|
"ordering_fields": [
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"name",
|
|
16
|
+
"custom_pk"
|
|
17
17
|
],
|
|
18
18
|
"properties": {
|
|
19
19
|
"custom_pk": {
|
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
"plural_title": "Daily Rates",
|
|
6
6
|
"primary_key_field": "id",
|
|
7
7
|
"filterable_fields": [
|
|
8
|
+
"id",
|
|
9
|
+
"date",
|
|
8
10
|
"rate_plan",
|
|
9
|
-
"closed_to_departure",
|
|
10
11
|
"min_stay_arrival",
|
|
11
|
-
"min_stay_through",
|
|
12
|
-
"stop_sell",
|
|
13
12
|
"price",
|
|
14
|
-
"date",
|
|
15
13
|
"max_stay",
|
|
14
|
+
"min_stay_through",
|
|
15
|
+
"stop_sell",
|
|
16
16
|
"closed_to_arrival",
|
|
17
|
-
"
|
|
17
|
+
"closed_to_departure"
|
|
18
18
|
],
|
|
19
19
|
"searchable_fields": [],
|
|
20
20
|
"ordering_fields": [
|
|
@@ -16,3 +16,6 @@ export * from './rateplan';
|
|
|
16
16
|
export * from './dailyrate';
|
|
17
17
|
export * from './restrictedfieldrelatedmodel';
|
|
18
18
|
export * from './modelwithrestrictedfields';
|
|
19
|
+
export * from './m2mdepthtestlevel3';
|
|
20
|
+
export * from './m2mdepthtestlevel2';
|
|
21
|
+
export * from './m2mdepthtestlevel1';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-specific QuerySet implementation
|
|
3
|
+
*/
|
|
4
|
+
export class M2MDepthTestLevel1QuerySet {
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Model-specific Manager implementation
|
|
8
|
+
*/
|
|
9
|
+
export class M2MDepthTestLevel1Manager {
|
|
10
|
+
constructor(ModelClass: any);
|
|
11
|
+
newQuerySet(): M2MDepthTestLevel1QuerySet;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Implementation of the M2MDepthTestLevel1 model
|
|
15
|
+
*/
|
|
16
|
+
export class M2MDepthTestLevel1 {
|
|
17
|
+
static configKey: string;
|
|
18
|
+
static modelName: string;
|
|
19
|
+
static primaryKeyField: string;
|
|
20
|
+
static objects: M2MDepthTestLevel1Manager;
|
|
21
|
+
static fields: string[];
|
|
22
|
+
static schema: {
|
|
23
|
+
model_name: string;
|
|
24
|
+
title: string;
|
|
25
|
+
class_name: string;
|
|
26
|
+
plural_title: string;
|
|
27
|
+
primary_key_field: string;
|
|
28
|
+
filterable_fields: string[];
|
|
29
|
+
searchable_fields: string[];
|
|
30
|
+
ordering_fields: string[];
|
|
31
|
+
properties: {
|
|
32
|
+
id: {
|
|
33
|
+
type: string;
|
|
34
|
+
title: string;
|
|
35
|
+
required: boolean;
|
|
36
|
+
description: null;
|
|
37
|
+
nullable: boolean;
|
|
38
|
+
format: string;
|
|
39
|
+
max_length: null;
|
|
40
|
+
choices: null;
|
|
41
|
+
default: null;
|
|
42
|
+
validators: never[];
|
|
43
|
+
max_digits: null;
|
|
44
|
+
decimal_places: null;
|
|
45
|
+
read_only: boolean;
|
|
46
|
+
ref: null;
|
|
47
|
+
};
|
|
48
|
+
name: {
|
|
49
|
+
type: string;
|
|
50
|
+
title: string;
|
|
51
|
+
required: boolean;
|
|
52
|
+
description: null;
|
|
53
|
+
nullable: boolean;
|
|
54
|
+
format: null;
|
|
55
|
+
max_length: number;
|
|
56
|
+
choices: null;
|
|
57
|
+
default: null;
|
|
58
|
+
validators: never[];
|
|
59
|
+
max_digits: null;
|
|
60
|
+
decimal_places: null;
|
|
61
|
+
read_only: boolean;
|
|
62
|
+
ref: null;
|
|
63
|
+
};
|
|
64
|
+
level2s: {
|
|
65
|
+
type: string;
|
|
66
|
+
title: string;
|
|
67
|
+
required: boolean;
|
|
68
|
+
description: null;
|
|
69
|
+
nullable: boolean;
|
|
70
|
+
format: string;
|
|
71
|
+
max_length: null;
|
|
72
|
+
choices: null;
|
|
73
|
+
default: null;
|
|
74
|
+
validators: never[];
|
|
75
|
+
max_digits: null;
|
|
76
|
+
decimal_places: null;
|
|
77
|
+
read_only: boolean;
|
|
78
|
+
ref: null;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
relationships: {
|
|
82
|
+
level2s: {
|
|
83
|
+
type: string;
|
|
84
|
+
model: string;
|
|
85
|
+
class_name: string;
|
|
86
|
+
primary_key_field: string;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
default_ordering: null;
|
|
90
|
+
definitions: {
|
|
91
|
+
MoneyField: {
|
|
92
|
+
type: string;
|
|
93
|
+
properties: {
|
|
94
|
+
amount: {
|
|
95
|
+
type: string;
|
|
96
|
+
};
|
|
97
|
+
currency: {
|
|
98
|
+
type: string;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
datetime_format: string;
|
|
104
|
+
date_format: string;
|
|
105
|
+
time_format: string;
|
|
106
|
+
display: null;
|
|
107
|
+
};
|
|
108
|
+
static relationshipFields: Map<string, {
|
|
109
|
+
ModelClass: () => any;
|
|
110
|
+
relationshipType: string;
|
|
111
|
+
}>;
|
|
112
|
+
constructor(data: any);
|
|
113
|
+
/**
|
|
114
|
+
* Define property getters and setters for all model fields
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
private _defineProperties;
|
|
118
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was auto-generated. Do not make direct changes to the file.
|
|
3
|
+
*/
|
|
4
|
+
import { Model, Manager, QuerySet, getModelClass } from '../../../../src';
|
|
5
|
+
import { wrapReactiveModel } from '../../../../src';
|
|
6
|
+
import schemaData from './m2mdepthtestlevel1.schema.json';
|
|
7
|
+
/**
|
|
8
|
+
* Model-specific QuerySet implementation
|
|
9
|
+
*/
|
|
10
|
+
export class M2MDepthTestLevel1QuerySet extends QuerySet {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Model-specific Manager implementation
|
|
14
|
+
*/
|
|
15
|
+
export class M2MDepthTestLevel1Manager extends Manager {
|
|
16
|
+
constructor(ModelClass) {
|
|
17
|
+
super(ModelClass, M2MDepthTestLevel1QuerySet);
|
|
18
|
+
}
|
|
19
|
+
newQuerySet() {
|
|
20
|
+
return new M2MDepthTestLevel1QuerySet(this.ModelClass);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Implementation of the M2MDepthTestLevel1 model
|
|
25
|
+
*/
|
|
26
|
+
export class M2MDepthTestLevel1 extends Model {
|
|
27
|
+
constructor(data) {
|
|
28
|
+
M2MDepthTestLevel1.validateFields(data);
|
|
29
|
+
super(data);
|
|
30
|
+
// Define getters and setters for all fields
|
|
31
|
+
this._defineProperties();
|
|
32
|
+
return wrapReactiveModel(this);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Define property getters and setters for all model fields
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
_defineProperties() {
|
|
39
|
+
// For each field, define a property that gets/sets from internal storage
|
|
40
|
+
M2MDepthTestLevel1.fields.forEach(field => {
|
|
41
|
+
Object.defineProperty(this, field, {
|
|
42
|
+
get: function () {
|
|
43
|
+
return this.getField(field);
|
|
44
|
+
},
|
|
45
|
+
set: function (value) {
|
|
46
|
+
this.setField(field, value);
|
|
47
|
+
},
|
|
48
|
+
enumerable: true, // Make sure fields are enumerable for serialization
|
|
49
|
+
configurable: true
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Bind this model to its backend
|
|
63
|
+
M2MDepthTestLevel1.configKey = 'backend1';
|
|
64
|
+
M2MDepthTestLevel1.modelName = 'django_app.m2mdepthtestlevel1';
|
|
65
|
+
M2MDepthTestLevel1.primaryKeyField = 'id';
|
|
66
|
+
M2MDepthTestLevel1.objects = new M2MDepthTestLevel1Manager(M2MDepthTestLevel1);
|
|
67
|
+
M2MDepthTestLevel1.fields = ['id', 'name', 'level2s'];
|
|
68
|
+
M2MDepthTestLevel1.schema = schemaData;
|
|
69
|
+
M2MDepthTestLevel1.relationshipFields = new Map([
|
|
70
|
+
['level2s', { 'ModelClass': () => getModelClass('django_app.m2mdepthtestlevel2', 'backend1'), 'relationshipType': 'many-to-many' }]
|
|
71
|
+
]);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"model_name": "django_app.m2mdepthtestlevel1",
|
|
3
|
+
"title": "M2M Depth Test Level1",
|
|
4
|
+
"class_name": "M2MDepthTestLevel1",
|
|
5
|
+
"plural_title": "M2M Depth Test Level1S",
|
|
6
|
+
"primary_key_field": "id",
|
|
7
|
+
"filterable_fields": [
|
|
8
|
+
"name",
|
|
9
|
+
"level2s",
|
|
10
|
+
"id"
|
|
11
|
+
],
|
|
12
|
+
"searchable_fields": [
|
|
13
|
+
"name"
|
|
14
|
+
],
|
|
15
|
+
"ordering_fields": [
|
|
16
|
+
"name"
|
|
17
|
+
],
|
|
18
|
+
"properties": {
|
|
19
|
+
"id": {
|
|
20
|
+
"type": "integer",
|
|
21
|
+
"title": "Id",
|
|
22
|
+
"required": true,
|
|
23
|
+
"description": null,
|
|
24
|
+
"nullable": false,
|
|
25
|
+
"format": "id",
|
|
26
|
+
"max_length": null,
|
|
27
|
+
"choices": null,
|
|
28
|
+
"default": null,
|
|
29
|
+
"validators": [],
|
|
30
|
+
"max_digits": null,
|
|
31
|
+
"decimal_places": null,
|
|
32
|
+
"read_only": true,
|
|
33
|
+
"ref": null
|
|
34
|
+
},
|
|
35
|
+
"name": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"title": "Name",
|
|
38
|
+
"required": true,
|
|
39
|
+
"description": null,
|
|
40
|
+
"nullable": false,
|
|
41
|
+
"format": null,
|
|
42
|
+
"max_length": 100,
|
|
43
|
+
"choices": null,
|
|
44
|
+
"default": null,
|
|
45
|
+
"validators": [],
|
|
46
|
+
"max_digits": null,
|
|
47
|
+
"decimal_places": null,
|
|
48
|
+
"read_only": false,
|
|
49
|
+
"ref": null
|
|
50
|
+
},
|
|
51
|
+
"level2s": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"title": "Level2s",
|
|
54
|
+
"required": true,
|
|
55
|
+
"description": null,
|
|
56
|
+
"nullable": false,
|
|
57
|
+
"format": "many-to-many",
|
|
58
|
+
"max_length": null,
|
|
59
|
+
"choices": null,
|
|
60
|
+
"default": null,
|
|
61
|
+
"validators": [],
|
|
62
|
+
"max_digits": null,
|
|
63
|
+
"decimal_places": null,
|
|
64
|
+
"read_only": false,
|
|
65
|
+
"ref": null
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"relationships": {
|
|
69
|
+
"level2s": {
|
|
70
|
+
"type": "many-to-many",
|
|
71
|
+
"model": "django_app.m2mdepthtestlevel2",
|
|
72
|
+
"class_name": "M2MDepthTestLevel2",
|
|
73
|
+
"primary_key_field": "id"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"default_ordering": null,
|
|
77
|
+
"definitions": {
|
|
78
|
+
"MoneyField": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"amount": {
|
|
82
|
+
"type": "number"
|
|
83
|
+
},
|
|
84
|
+
"currency": {
|
|
85
|
+
"type": "string"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"datetime_format": "iso-8601",
|
|
91
|
+
"date_format": "iso-8601",
|
|
92
|
+
"time_format": "iso-8601",
|
|
93
|
+
"display": null
|
|
94
|
+
}
|