@statezero/core 0.2.13 → 0.2.15
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.js +43 -9
- package/dist/models/backend1/django_app/comprehensivemodel.js +1 -1
- package/dist/models/backend1/django_app/order.d.ts +4 -1
- package/dist/models/backend1/django_app/order.js +4 -2
- package/dist/models/default/django_app/comprehensivemodel.js +1 -1
- package/dist/models/default/django_app/order.d.ts +4 -1
- package/dist/models/default/django_app/order.js +4 -2
- package/package.json +1 -1
|
@@ -83,6 +83,7 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
|
|
|
83
83
|
let currentModel = ModelClass;
|
|
84
84
|
let processedPath = [];
|
|
85
85
|
let isRelationship = false;
|
|
86
|
+
let isM2M = false; // Track if this is a many-to-many relationship
|
|
86
87
|
let finalFieldName = null; // Track the actual field name for schema lookup
|
|
87
88
|
for (let i = 0; i < fieldParts.length; i++) {
|
|
88
89
|
let part = fieldParts[i];
|
|
@@ -96,6 +97,7 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
|
|
|
96
97
|
// This is a relationship field
|
|
97
98
|
const relationship = currentModel.relationshipFields.get(part);
|
|
98
99
|
const relatedModel = relationship.ModelClass();
|
|
100
|
+
const relationshipType = relationship.relationshipType;
|
|
99
101
|
// Add this relationship field to the path
|
|
100
102
|
processedPath.push(part);
|
|
101
103
|
// If this is not the last part, update the current model to the related model
|
|
@@ -104,13 +106,22 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
|
|
|
104
106
|
}
|
|
105
107
|
else {
|
|
106
108
|
// This is the last part and it's a relationship
|
|
107
|
-
// We need to add the primary key field of the related model
|
|
108
109
|
isRelationship = true;
|
|
109
|
-
// For
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
// For many-to-many relationships, don't append the primary key field
|
|
111
|
+
// M2M fields store an array of PKs directly, not objects
|
|
112
|
+
if (relationshipType === 'many-to-many') {
|
|
113
|
+
isM2M = true;
|
|
114
|
+
// Keep path as-is (e.g., 'comprehensive_models')
|
|
115
|
+
// Sift will handle array membership check
|
|
116
|
+
finalFieldName = part;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// For foreign key relationships, we need to append the primary key field
|
|
120
|
+
// to properly match Django's behavior
|
|
121
|
+
const pkField = relatedModel.primaryKeyField || 'id';
|
|
122
|
+
processedPath.push(pkField);
|
|
123
|
+
finalFieldName = pkField;
|
|
124
|
+
}
|
|
114
125
|
currentModel = relatedModel;
|
|
115
126
|
}
|
|
116
127
|
}
|
|
@@ -145,7 +156,7 @@ function processFieldPath(fieldPath, value, ModelClass, options = {}) {
|
|
|
145
156
|
}
|
|
146
157
|
// Handle the single lookup operation if present
|
|
147
158
|
if (lookup) {
|
|
148
|
-
return createOperatorFromLookup(finalPath, lookup, normalizedValue, isRelationship, currentModel, finalFieldName);
|
|
159
|
+
return createOperatorFromLookup(finalPath, lookup, normalizedValue, isRelationship, currentModel, finalFieldName, isM2M);
|
|
149
160
|
}
|
|
150
161
|
// If there's no explicit lookup and this is a relationship field,
|
|
151
162
|
// we've already appended the PK field name to the path
|
|
@@ -192,9 +203,10 @@ function createDatePartComparisonOperator(field, datePart, comparisonOperator, v
|
|
|
192
203
|
* @param {boolean} isRelationship - Whether the field is a relationship
|
|
193
204
|
* @param {Class} ModelClass - The model class (unused, for future extensibility)
|
|
194
205
|
* @param {string} finalFieldName - The final field name (unused, for future extensibility)
|
|
206
|
+
* @param {boolean} isM2M - Whether the field is a many-to-many relationship
|
|
195
207
|
* @returns {Object} Object with field name and sift operator
|
|
196
208
|
*/
|
|
197
|
-
function createOperatorFromLookup(field, lookup, value, isRelationship, ModelClass, finalFieldName) {
|
|
209
|
+
function createOperatorFromLookup(field, lookup, value, isRelationship, ModelClass, finalFieldName, isM2M = false) {
|
|
198
210
|
// Helper function to escape special characters in regex
|
|
199
211
|
function escapeRegExp(string) {
|
|
200
212
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -203,7 +215,23 @@ function createOperatorFromLookup(field, lookup, value, isRelationship, ModelCla
|
|
|
203
215
|
if (isRelationship) {
|
|
204
216
|
// For relationship fields with lookups, we need special handling
|
|
205
217
|
if (lookup === 'isnull') {
|
|
206
|
-
|
|
218
|
+
if (isM2M) {
|
|
219
|
+
// For M2M fields, isnull=True means null OR empty array, but not undefined because
|
|
220
|
+
// that can mean the field was not fetched so we can't be sure
|
|
221
|
+
// isnull=False means has at least one item
|
|
222
|
+
// Use a custom function since sift doesn't support $or inside field operators
|
|
223
|
+
return {
|
|
224
|
+
field,
|
|
225
|
+
operator: {
|
|
226
|
+
$where: function (fieldValue) {
|
|
227
|
+
const isEmpty = fieldValue === null ||
|
|
228
|
+
(Array.isArray(fieldValue) && fieldValue.length === 0);
|
|
229
|
+
return value ? isEmpty : !isEmpty;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// For FK/O2O, check for both undefined and null values
|
|
207
235
|
return {
|
|
208
236
|
field,
|
|
209
237
|
operator: value ? { $in: [null, undefined] } : { $nin: [null, undefined] }
|
|
@@ -905,6 +933,12 @@ export function pickRequiredFields(requiredPaths, instance) {
|
|
|
905
933
|
// skip missing
|
|
906
934
|
return;
|
|
907
935
|
}
|
|
936
|
+
// Convert M2M arrays from Model instances to PKs for comparison
|
|
937
|
+
// This handles the case where the live representation returns [Model1, Model2]
|
|
938
|
+
// but we need [pk1, pk2] for sift filtering
|
|
939
|
+
if (Array.isArray(value) && value.length > 0 && value[0]?.pk !== undefined) {
|
|
940
|
+
value = value.map(item => item.pk);
|
|
941
|
+
}
|
|
908
942
|
// Build nested structure in the result
|
|
909
943
|
let cursor = result;
|
|
910
944
|
parts.forEach((key, idx) => {
|
|
@@ -64,7 +64,7 @@ ComprehensiveModel.configKey = 'backend1';
|
|
|
64
64
|
ComprehensiveModel.modelName = 'django_app.comprehensivemodel';
|
|
65
65
|
ComprehensiveModel.primaryKeyField = 'id';
|
|
66
66
|
ComprehensiveModel.objects = new ComprehensiveModelManager(ComprehensiveModel);
|
|
67
|
-
ComprehensiveModel.fields = ['id', 'char_field', 'text_field', 'int_field', 'bool_field', 'datetime_field', 'decimal_field', 'json_field', 'money_field_currency', 'money_field', 'related'];
|
|
67
|
+
ComprehensiveModel.fields = ['id', 'char_field', 'text_field', 'int_field', 'bool_field', 'datetime_field', 'decimal_field', 'json_field', 'money_field_currency', 'money_field', 'nullable_money_field_currency', 'nullable_money_field', 'related'];
|
|
68
68
|
ComprehensiveModel.schema = schemaData;
|
|
69
69
|
ComprehensiveModel.relationshipFields = new Map([
|
|
70
70
|
['related', { 'ModelClass': () => getModelClass('django_app.deepmodellevel1', 'backend1'), 'relationshipType': 'foreign-key' }]
|
|
@@ -31,7 +31,10 @@ export class Order extends Model {
|
|
|
31
31
|
static objects: OrderManager;
|
|
32
32
|
static fields: string[];
|
|
33
33
|
static schema: any;
|
|
34
|
-
static relationshipFields: Map<
|
|
34
|
+
static relationshipFields: Map<string, {
|
|
35
|
+
ModelClass: () => Function | null;
|
|
36
|
+
relationshipType: string;
|
|
37
|
+
}>;
|
|
35
38
|
constructor(data: any);
|
|
36
39
|
/**
|
|
37
40
|
* Define property getters and setters for all model fields
|
|
@@ -64,6 +64,8 @@ Order.configKey = 'backend1';
|
|
|
64
64
|
Order.modelName = 'django_app.order';
|
|
65
65
|
Order.primaryKeyField = 'id';
|
|
66
66
|
Order.objects = new OrderManager(Order);
|
|
67
|
-
Order.fields = ['id', 'order_number', 'customer_name', 'customer_email', 'total', 'status', 'created_at', 'last_updated'];
|
|
67
|
+
Order.fields = ['id', 'order_number', 'customer_name', 'customer_email', 'total', 'status', 'created_at', 'last_updated', 'items'];
|
|
68
68
|
Order.schema = schemaData;
|
|
69
|
-
Order.relationshipFields = new Map([
|
|
69
|
+
Order.relationshipFields = new Map([
|
|
70
|
+
['items', { 'ModelClass': () => getModelClass('django_app.orderitem', 'backend1'), 'relationshipType': 'many-to-many' }]
|
|
71
|
+
]);
|
|
@@ -64,7 +64,7 @@ ComprehensiveModel.configKey = 'default';
|
|
|
64
64
|
ComprehensiveModel.modelName = 'django_app.comprehensivemodel';
|
|
65
65
|
ComprehensiveModel.primaryKeyField = 'id';
|
|
66
66
|
ComprehensiveModel.objects = new ComprehensiveModelManager(ComprehensiveModel);
|
|
67
|
-
ComprehensiveModel.fields = ['id', 'char_field', 'text_field', 'int_field', 'bool_field', 'datetime_field', 'decimal_field', 'json_field', 'money_field_currency', 'money_field', 'related'];
|
|
67
|
+
ComprehensiveModel.fields = ['id', 'char_field', 'text_field', 'int_field', 'bool_field', 'datetime_field', 'decimal_field', 'json_field', 'money_field_currency', 'money_field', 'nullable_money_field_currency', 'nullable_money_field', 'related'];
|
|
68
68
|
ComprehensiveModel.schema = schemaData;
|
|
69
69
|
ComprehensiveModel.relationshipFields = new Map([
|
|
70
70
|
['related', { 'ModelClass': () => getModelClass('django_app.deepmodellevel1', 'default'), 'relationshipType': 'foreign-key' }]
|
|
@@ -31,7 +31,10 @@ export class Order extends Model {
|
|
|
31
31
|
static objects: OrderManager;
|
|
32
32
|
static fields: string[];
|
|
33
33
|
static schema: any;
|
|
34
|
-
static relationshipFields: Map<
|
|
34
|
+
static relationshipFields: Map<string, {
|
|
35
|
+
ModelClass: () => Function | null;
|
|
36
|
+
relationshipType: string;
|
|
37
|
+
}>;
|
|
35
38
|
constructor(data: any);
|
|
36
39
|
/**
|
|
37
40
|
* Define property getters and setters for all model fields
|
|
@@ -64,6 +64,8 @@ Order.configKey = 'default';
|
|
|
64
64
|
Order.modelName = 'django_app.order';
|
|
65
65
|
Order.primaryKeyField = 'id';
|
|
66
66
|
Order.objects = new OrderManager(Order);
|
|
67
|
-
Order.fields = ['id', 'order_number', 'customer_name', 'customer_email', 'total', 'status', 'created_at', 'last_updated'];
|
|
67
|
+
Order.fields = ['id', 'order_number', 'customer_name', 'customer_email', 'total', 'status', 'created_at', 'last_updated', 'items'];
|
|
68
68
|
Order.schema = schemaData;
|
|
69
|
-
Order.relationshipFields = new Map([
|
|
69
|
+
Order.relationshipFields = new Map([
|
|
70
|
+
['items', { 'ModelClass': () => getModelClass('django_app.orderitem', 'default'), 'relationshipType': 'many-to-many' }]
|
|
71
|
+
]);
|
package/package.json
CHANGED