@statezero/core 0.2.23 → 0.2.25
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 +123 -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,30 @@ 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 required path for data picking (full dot-notation path)
|
|
116
|
+
const innerRequiredPath = innerResult.requiredPath || innerResult.field;
|
|
117
|
+
const requiredPath = `${part}.${innerRequiredPath}`;
|
|
118
|
+
// Wrap the inner result in $elemMatch for this M2M field
|
|
119
|
+
return {
|
|
120
|
+
field: part,
|
|
121
|
+
operator: { $elemMatch: { [innerResult.field]: innerResult.operator } },
|
|
122
|
+
isM2M: true,
|
|
123
|
+
requiredPath // Full path for data picking
|
|
124
|
+
};
|
|
125
|
+
}
|
|
102
126
|
// Add this relationship field to the path
|
|
103
127
|
processedPath.push(part);
|
|
104
128
|
// If this is not the last part, update the current model to the related model
|
|
@@ -168,6 +192,10 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
|
|
|
168
192
|
if (normalizedValue && typeof normalizedValue === 'object' && 'pk' in normalizedValue) {
|
|
169
193
|
raw = normalizedValue.pk;
|
|
170
194
|
}
|
|
195
|
+
// For M2M fields, use $elemMatch to check if any element's pk matches
|
|
196
|
+
if (isM2M) {
|
|
197
|
+
return { field: finalPath, operator: { $elemMatch: { pk: { $eq: raw } } }, isM2M: true };
|
|
198
|
+
}
|
|
171
199
|
return { field: finalPath, operator: { $eq: raw } };
|
|
172
200
|
}
|
|
173
201
|
// Default to direct equality
|
|
@@ -217,18 +245,19 @@ function createOperatorFromLookup(field, lookup, value, isRelationship, ModelCla
|
|
|
217
245
|
// For relationship fields with lookups, we need special handling
|
|
218
246
|
if (lookup === 'isnull') {
|
|
219
247
|
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
|
|
248
|
+
// For M2M fields, isnull=True means null OR empty array
|
|
222
249
|
// isnull=False means has at least one item
|
|
223
|
-
// Use
|
|
250
|
+
// Use document-level $where to check the array itself (not iterate elements)
|
|
251
|
+
const m2mField = field;
|
|
252
|
+
const checkEmpty = value;
|
|
224
253
|
return {
|
|
225
|
-
field,
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
254
|
+
field: '$where', // document-level operator
|
|
255
|
+
requiredPath: field, // need the M2M field itself for data picking
|
|
256
|
+
operator: function (doc) {
|
|
257
|
+
const fieldValue = doc[m2mField];
|
|
258
|
+
const isEmpty = fieldValue === null ||
|
|
259
|
+
(Array.isArray(fieldValue) && fieldValue.length === 0);
|
|
260
|
+
return checkEmpty ? isEmpty : !isEmpty;
|
|
232
261
|
}
|
|
233
262
|
};
|
|
234
263
|
}
|
|
@@ -239,10 +268,17 @@ function createOperatorFromLookup(field, lookup, value, isRelationship, ModelCla
|
|
|
239
268
|
};
|
|
240
269
|
}
|
|
241
270
|
else if (lookup === 'in') {
|
|
271
|
+
// For M2M, check if any element's pk is in the provided array
|
|
272
|
+
if (isM2M) {
|
|
273
|
+
return { field, operator: { $elemMatch: { pk: { $in: value } } }, isM2M: true };
|
|
274
|
+
}
|
|
242
275
|
return { field, operator: { $in: value } };
|
|
243
276
|
}
|
|
244
277
|
else {
|
|
245
278
|
// Default handling for relationship fields
|
|
279
|
+
if (isM2M) {
|
|
280
|
+
return { field, operator: { $elemMatch: { pk: { $eq: value } } }, isM2M: true };
|
|
281
|
+
}
|
|
246
282
|
return { field, operator: { $eq: value } };
|
|
247
283
|
}
|
|
248
284
|
}
|
|
@@ -545,10 +581,11 @@ function createFilterWithDateOperations(criteria, ModelClass) {
|
|
|
545
581
|
function convertToSiftCriteria(conditions, ModelClass) {
|
|
546
582
|
const result = {};
|
|
547
583
|
const datePartFilters = new Map(); // Map to collect date part filters by field
|
|
584
|
+
const m2mConditions = new Map(); // Map to collect M2M $elemMatch conditions by field
|
|
548
585
|
for (const [key, value] of Object.entries(conditions)) {
|
|
549
586
|
try {
|
|
550
587
|
const processedResult = processFieldPath(key, value, ModelClass);
|
|
551
|
-
const { field, operator, isDatePart } = processedResult;
|
|
588
|
+
const { field, operator, isDatePart, isM2M } = processedResult;
|
|
552
589
|
if (isDatePart) {
|
|
553
590
|
// Handle date part operators separately
|
|
554
591
|
if (!datePartFilters.has(field)) {
|
|
@@ -556,6 +593,13 @@ function convertToSiftCriteria(conditions, ModelClass) {
|
|
|
556
593
|
}
|
|
557
594
|
datePartFilters.get(field).push({ [field]: operator });
|
|
558
595
|
}
|
|
596
|
+
else if (isM2M && operator.$elemMatch) {
|
|
597
|
+
// Collect M2M conditions to merge into single $elemMatch
|
|
598
|
+
if (!m2mConditions.has(field)) {
|
|
599
|
+
m2mConditions.set(field, []);
|
|
600
|
+
}
|
|
601
|
+
m2mConditions.get(field).push(operator.$elemMatch);
|
|
602
|
+
}
|
|
559
603
|
else {
|
|
560
604
|
// For regular operators, merge if we already have criteria for this field
|
|
561
605
|
if (result[field]) {
|
|
@@ -570,6 +614,17 @@ function convertToSiftCriteria(conditions, ModelClass) {
|
|
|
570
614
|
throw new Error(`Failed to process field '${key}': ${error.message}`);
|
|
571
615
|
}
|
|
572
616
|
}
|
|
617
|
+
// Merge M2M conditions: all conditions on same M2M field go into single $elemMatch
|
|
618
|
+
// so the SAME related object must match ALL conditions
|
|
619
|
+
for (const [field, elemMatchConditions] of m2mConditions.entries()) {
|
|
620
|
+
if (elemMatchConditions.length === 1) {
|
|
621
|
+
result[field] = { $elemMatch: elemMatchConditions[0] };
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
// Multiple conditions - wrap in $and so same element must match all
|
|
625
|
+
result[field] = { $elemMatch: { $and: elemMatchConditions } };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
573
628
|
// If we have date part filters, combine them with the result
|
|
574
629
|
if (datePartFilters.size > 0) {
|
|
575
630
|
const andConditions = [];
|
|
@@ -663,6 +718,9 @@ function convertFilterNodeToSiftCriteria(filterNode, ModelClass) {
|
|
|
663
718
|
return null;
|
|
664
719
|
if (childCriteria.length === 1)
|
|
665
720
|
return childCriteria[0];
|
|
721
|
+
// Chained filters use $and at top level - this gives ANY/ANY semantics for M2M
|
|
722
|
+
// (each $elemMatch can be satisfied by different elements)
|
|
723
|
+
// This matches Django's chained .filter() behavior
|
|
666
724
|
return { $and: childCriteria };
|
|
667
725
|
}
|
|
668
726
|
// For compound OR nodes
|
|
@@ -863,12 +921,24 @@ export function getRequiredFields(queryBuild, ModelClass) {
|
|
|
863
921
|
function addPath(rawKey) {
|
|
864
922
|
try {
|
|
865
923
|
// We pass `null` as the value, since we only care about .field
|
|
866
|
-
const { field } = processFieldPath(rawKey, null, ModelClass);
|
|
867
|
-
|
|
924
|
+
const { field, isM2M, requiredPath } = processFieldPath(rawKey, null, ModelClass);
|
|
925
|
+
// Use requiredPath if available (for M2M traversal), otherwise use field
|
|
926
|
+
// For M2M fields at the end of a path (no requiredPath), we need the pk field
|
|
927
|
+
let finalPath;
|
|
928
|
+
if (requiredPath) {
|
|
929
|
+
finalPath = requiredPath;
|
|
930
|
+
}
|
|
931
|
+
else if (isM2M) {
|
|
932
|
+
finalPath = `${field}.pk`;
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
935
|
+
finalPath = field;
|
|
936
|
+
}
|
|
937
|
+
paths.add(finalPath);
|
|
868
938
|
}
|
|
869
939
|
catch (err) {
|
|
870
|
-
// if a key doesn
|
|
871
|
-
console.warn(`getRequiredFields: couldn
|
|
940
|
+
// if a key doesn't map, warn and skip it
|
|
941
|
+
console.warn(`getRequiredFields: couldn't process "${rawKey}": ${err.message}`);
|
|
872
942
|
}
|
|
873
943
|
}
|
|
874
944
|
// Recursively walk your filter AST
|
|
@@ -917,42 +987,48 @@ export function getRequiredFields(queryBuild, ModelClass) {
|
|
|
917
987
|
* @param {Object} instance – e.g. { id: 3, related: { name: 'bob', age: 12, foo: 'bar' } }
|
|
918
988
|
* @returns {Object} – e.g. { id: 3, related: { name: 'bob', age: 12 } }
|
|
919
989
|
*/
|
|
990
|
+
/**
|
|
991
|
+
* Recursively sets a value in a result object following a path.
|
|
992
|
+
* Handles arrays (M2M fields) by mapping over each element.
|
|
993
|
+
*/
|
|
994
|
+
function setNestedValueRecursive(result, source, pathParts) {
|
|
995
|
+
if (source == null || pathParts.length === 0) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const [current, ...rest] = pathParts;
|
|
999
|
+
const sourceValue = source[current];
|
|
1000
|
+
if (sourceValue === undefined) {
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
if (rest.length === 0) {
|
|
1004
|
+
// Last part - set the value directly, keeping M2M as full objects
|
|
1005
|
+
result[current] = sourceValue;
|
|
1006
|
+
}
|
|
1007
|
+
else if (Array.isArray(sourceValue)) {
|
|
1008
|
+
// M2M array with nested path - recursively extract from each element
|
|
1009
|
+
if (!(current in result)) {
|
|
1010
|
+
result[current] = [];
|
|
1011
|
+
}
|
|
1012
|
+
sourceValue.forEach((item, idx) => {
|
|
1013
|
+
if (result[current][idx] === undefined) {
|
|
1014
|
+
result[current][idx] = {};
|
|
1015
|
+
}
|
|
1016
|
+
setNestedValueRecursive(result[current][idx], item, rest);
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
else if (typeof sourceValue === 'object') {
|
|
1020
|
+
// Regular nested object (FK)
|
|
1021
|
+
if (!(current in result)) {
|
|
1022
|
+
result[current] = {};
|
|
1023
|
+
}
|
|
1024
|
+
setNestedValueRecursive(result[current], sourceValue, rest);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
920
1027
|
export function pickRequiredFields(requiredPaths, instance) {
|
|
921
1028
|
const result = {};
|
|
922
1029
|
requiredPaths.forEach(path => {
|
|
923
1030
|
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
|
-
});
|
|
1031
|
+
setNestedValueRecursive(result, instance, parts);
|
|
956
1032
|
});
|
|
957
1033
|
return result;
|
|
958
1034
|
}
|
|
@@ -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
|
+
}
|