@statezero/core 0.1.97 → 0.1.99

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.
@@ -223,7 +223,7 @@ export class QueryExecutor {
223
223
  };
224
224
  const operation = OperationFactory.createUpdateOperation(querySet, apiCallArgs.data, querySet.build().filter);
225
225
  const estimatedCount = operation.instances.length;
226
- let liveResult = [estimatedCount, { [modelName]: estimatedCount }];
226
+ let liveResult = [estimatedCount, { [modelName]: estimatedCount }, []];
227
227
  const promise = makeApiCall(querySet, operationType, apiCallArgs, operation.operationId)
228
228
  .then((response) => {
229
229
  const { data, included } = response.data || {};
@@ -233,7 +233,7 @@ export class QueryExecutor {
233
233
  : [];
234
234
  operation.updateStatus(Status.CONFIRMED, updatedObjects);
235
235
  const updatedCount = response.metadata?.updated_count ?? 0;
236
- liveResult = [updatedCount, { [modelName]: updatedCount }];
236
+ liveResult = [updatedCount, { [modelName]: updatedCount }, updatedObjects];
237
237
  breakThenable(liveResult);
238
238
  return liveResult;
239
239
  })
@@ -258,13 +258,13 @@ export class QueryExecutor {
258
258
  const operation = OperationFactory.createDeleteOperation(querySet);
259
259
  // live placeholder: assume we delete all existing pks
260
260
  const estimatedCount = operation.instances.length;
261
- let liveResult = [estimatedCount, { [modelName]: estimatedCount }];
261
+ let liveResult = [estimatedCount, { [modelName]: estimatedCount }, []];
262
262
  const promise = makeApiCall(querySet, operationType, {}, operation.operationId)
263
263
  .then((response) => {
264
264
  const deletedCount = response.metadata.deleted_count;
265
265
  const deletedInstances = response.metadata.rows_deleted;
266
266
  operation.updateStatus(Status.CONFIRMED, deletedInstances);
267
- liveResult = [deletedCount, { [modelName]: deletedCount }];
267
+ liveResult = [deletedCount, { [modelName]: deletedCount }, deletedInstances || []];
268
268
  breakThenable(liveResult);
269
269
  return liveResult;
270
270
  })
@@ -468,7 +468,7 @@ export class QueryExecutor {
468
468
  // Use factory to create operation
469
469
  const operation = OperationFactory.createDeleteInstanceOperation(querySet, args);
470
470
  // 1) placeholder result
471
- let liveResult = [1, { [modelName]: 1 }];
471
+ let liveResult = [1, { [modelName]: 1 }, []];
472
472
  // 2) async call
473
473
  const promise = makeApiCall(querySet, operationType, args, operation.operationId)
474
474
  .then((response) => {
@@ -477,10 +477,12 @@ export class QueryExecutor {
477
477
  if (typeof response.data === "number") {
478
478
  deletedCount = response.data;
479
479
  }
480
+ // Get deleted instances from metadata if available
481
+ const deletedInstances = response.metadata?.rows_deleted || [args];
480
482
  // Confirm operation
481
483
  operation.updateStatus(Status.CONFIRMED, [args]);
482
484
  // Swap in real result and freeze
483
- liveResult = [deletedCount, { [modelName]: deletedCount }];
485
+ liveResult = [deletedCount, { [modelName]: deletedCount }, deletedInstances];
484
486
  breakThenable(liveResult);
485
487
  return liveResult;
486
488
  })
@@ -80,6 +80,14 @@ export class QuerySet<T> {
80
80
  * @returns {Object} The serialized conditions.
81
81
  */
82
82
  private _serializeConditions;
83
+ /**
84
+ * Serializes a value based on its type (handles arrays, Model instances, Dates, primitives)
85
+ *
86
+ * @private
87
+ * @param {any} value - The value to serialize
88
+ * @returns {any} The serialized value
89
+ */
90
+ private _serializeValue;
83
91
  /**
84
92
  * Filters the QuerySet with the provided conditions.
85
93
  *
@@ -1,6 +1,6 @@
1
1
  import { MultipleObjectsReturned, DoesNotExist, parseStateZeroError, } from "./errors.js";
2
2
  import { Model } from "./model.js";
3
- import { ModelSerializer } from "./serializers.js"; // Import the ModelSerializer
3
+ import { ModelSerializer, relationshipFieldSerializer, dateFieldSerializer } from "./serializers.js";
4
4
  import axios from "axios";
5
5
  import { QueryExecutor } from "./queryExecutor.js";
6
6
  import { json } from "stream/consumers";
@@ -110,8 +110,57 @@ export class QuerySet {
110
110
  if (!conditions || typeof conditions !== "object") {
111
111
  return conditions;
112
112
  }
113
- // Use the model serializer to convert conditions to internal format
114
- return this._serializer.toInternal(conditions);
113
+ const serializedConditions = {};
114
+ for (const [fieldPath, value] of Object.entries(conditions)) {
115
+ serializedConditions[fieldPath] = this._serializeValue(value);
116
+ }
117
+ return serializedConditions;
118
+ }
119
+ /**
120
+ * Serializes a value based on its type (handles arrays, Model instances, Dates, primitives)
121
+ *
122
+ * @private
123
+ * @param {any} value - The value to serialize
124
+ * @returns {any} The serialized value
125
+ */
126
+ _serializeValue(value) {
127
+ // Handle arrays (for __in lookups)
128
+ if (Array.isArray(value)) {
129
+ return value.map(item => this._serializeValue(item));
130
+ }
131
+ // Handle Model instances (objects with pk, serialize method, and constructor with configKey/modelName)
132
+ // Note: Model instances are objects, not classes (typeof instance === 'object')
133
+ if (value &&
134
+ typeof value === 'object' &&
135
+ !(value instanceof Date) && // Exclude Date objects
136
+ 'pk' in value &&
137
+ 'serialize' in value &&
138
+ typeof value.serialize === 'function' &&
139
+ value.constructor &&
140
+ 'configKey' in value.constructor &&
141
+ 'modelName' in value.constructor) {
142
+ return relationshipFieldSerializer.toInternal(value);
143
+ }
144
+ // Handle Date objects
145
+ // Without field context, we default to datetime format (ISO string with time)
146
+ // Unless it's exactly midnight in UTC, which likely indicates a date-only field
147
+ if (value instanceof Date) {
148
+ // Check if it's midnight UTC (likely a date-only value)
149
+ const hours = value.getUTCHours();
150
+ const minutes = value.getUTCMinutes();
151
+ const seconds = value.getUTCSeconds();
152
+ const milliseconds = value.getUTCMilliseconds();
153
+ if (hours === 0 && minutes === 0 && seconds === 0 && milliseconds === 0) {
154
+ // It's midnight UTC - serialize as date-only (YYYY-MM-DD)
155
+ return value.toISOString().split('T')[0];
156
+ }
157
+ else {
158
+ // Has time component - serialize as full datetime
159
+ return value.toISOString();
160
+ }
161
+ }
162
+ // Everything else (strings, numbers, booleans, null) - return as-is
163
+ return value;
115
164
  }
116
165
  /**
117
166
  * Filters the QuerySet with the provided conditions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statezero/core",
3
- "version": "0.1.97",
3
+ "version": "0.1.99",
4
4
  "type": "module",
5
5
  "module": "ESNext",
6
6
  "description": "The type-safe frontend client for StateZero - connect directly to your backend models with zero boilerplate",