cry-synced-db-client 0.1.164 → 0.1.166

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/index.js CHANGED
@@ -507,6 +507,11 @@ function setSegment(current, part, value) {
507
507
  const idStr = part.slice(1, -1);
508
508
  if (!Array.isArray(current)) return false;
509
509
  const idx = current.findIndex((item) => item && String(item._id) === idStr);
510
+ if (Array.isArray(value) && value.length === 1 && value[0] && typeof value[0] === "object" && String(value[0]._id) === idStr) {
511
+ if (idx >= 0) current[idx] = value[0];
512
+ else current.push(value[0]);
513
+ return true;
514
+ }
510
515
  if (idx < 0) return false;
511
516
  current[idx] = value;
512
517
  return true;
@@ -562,6 +567,14 @@ function isTerminalBracketKey(path) {
562
567
  const last = tokens[tokens.length - 1];
563
568
  return !!(last && last.length >= 2 && last.charCodeAt(0) === 91 && last.charCodeAt(last.length - 1) === 93);
564
569
  }
570
+ function canExpandArrayToBrackets(value) {
571
+ if (!Array.isArray(value) || value.length === 0) return false;
572
+ for (const el of value) {
573
+ if (el === null || typeof el !== "object") return false;
574
+ if (el._id == null) return false;
575
+ }
576
+ return true;
577
+ }
565
578
  function mergeDirtyPath(accumulated, newPath, newValue) {
566
579
  for (const existingKey of Object.keys(accumulated)) {
567
580
  if (existingKey === newPath) continue;
@@ -575,7 +588,16 @@ function mergeDirtyPath(accumulated, newPath, newValue) {
575
588
  if (existingIsTerminal && Array.isArray(existingValue) && existingValue.length === 1) {
576
589
  mutationTarget = existingValue[0];
577
590
  }
578
- const relativePath = newPath.substring(existingKey.length + 1);
591
+ if (!existingIsTerminal && newPath[existingKey.length] === "[" && canExpandArrayToBrackets(existingValue)) {
592
+ delete accumulated[existingKey];
593
+ for (const el of existingValue) {
594
+ accumulated[`${existingKey}[${String(el._id)}]`] = [el];
595
+ }
596
+ mergeDirtyPath(accumulated, newPath, newValue);
597
+ return;
598
+ }
599
+ const sepChar = newPath[existingKey.length];
600
+ const relativePath = sepChar === "[" ? newPath.substring(existingKey.length) : newPath.substring(existingKey.length + 1);
579
601
  const ok = setByPath(mutationTarget, relativePath, newValue);
580
602
  if (ok) return;
581
603
  break;
@@ -4951,6 +4973,9 @@ var _SyncedDb = class _SyncedDb {
4951
4973
  }
4952
4974
  async upsert(collection, query, update) {
4953
4975
  this.assertCollection(collection);
4976
+ if ((query == null ? void 0 : query._id) != null && update._id == null) {
4977
+ update._id = query._id;
4978
+ }
4954
4979
  this.ensureId(update, "upsert", collection);
4955
4980
  query = _SyncedDb.stringifyObjectIds(query);
4956
4981
  update = _SyncedDb.stringifyObjectIds(update);
@@ -5204,16 +5229,31 @@ var _SyncedDb = class _SyncedDb {
5204
5229
  isSyncing() {
5205
5230
  return this.syncing;
5206
5231
  }
5207
- // ==================== Batch Operations (online only) ====================
5232
+ // ==================== Batch Operations ====================
5233
+ /**
5234
+ * Run each batch entry through the standard `upsert()` pipeline so every
5235
+ * write — single or batched — goes through `computeDiff` →
5236
+ * `applyDiffLocally` → in-mem write + Dexie schedule + dirty change.
5237
+ *
5238
+ * Server upload remains batched: dirty entries accumulated by the per-item
5239
+ * calls coalesce into one `updateCollections` request at the next sync
5240
+ * flush. We never bypass the diff pipeline (no separate server-only
5241
+ * `restInterface.upsertBatch` route), so bracket-by-_id sub-field path
5242
+ * generation and conflict resolution behave identically to a sequence of
5243
+ * `upsert()` calls.
5244
+ *
5245
+ * Works offline — items queue as dirty and upload on reconnect.
5246
+ *
5247
+ * Per-entry `opts` (`UpsertOptions` / `FindOneAndUpdateOptions`) is
5248
+ * ignored; the diff pipeline has no mongo-`findOneAndUpdate` knob.
5249
+ */
5208
5250
  async upsertBatch(collection, batch) {
5209
5251
  this.assertCollection(collection);
5210
- if (!this.isOnline()) {
5211
- throw new Error("upsertBatch requires online connection");
5252
+ const results = [];
5253
+ for (const entry of batch) {
5254
+ results.push(await this.upsert(collection, entry.query, entry.update));
5212
5255
  }
5213
- return this.connectionManager.withRestTimeout(
5214
- this.restInterface.upsertBatch(collection, batch),
5215
- "upsertBatch"
5216
- );
5256
+ return results;
5217
5257
  }
5218
5258
  // ==================== In-Memory Access ====================
5219
5259
  getMemoryCollection(collection) {
@@ -156,6 +156,23 @@ export declare class SyncedDb implements I_SyncedDb {
156
156
  sync(calledFrom?: string): Promise<void>;
157
157
  private processQueuedWsUpdates;
158
158
  isSyncing(): boolean;
159
+ /**
160
+ * Run each batch entry through the standard `upsert()` pipeline so every
161
+ * write — single or batched — goes through `computeDiff` →
162
+ * `applyDiffLocally` → in-mem write + Dexie schedule + dirty change.
163
+ *
164
+ * Server upload remains batched: dirty entries accumulated by the per-item
165
+ * calls coalesce into one `updateCollections` request at the next sync
166
+ * flush. We never bypass the diff pipeline (no separate server-only
167
+ * `restInterface.upsertBatch` route), so bracket-by-_id sub-field path
168
+ * generation and conflict resolution behave identically to a sequence of
169
+ * `upsert()` calls.
170
+ *
171
+ * Works offline — items queue as dirty and upload on reconnect.
172
+ *
173
+ * Per-entry `opts` (`UpsertOptions` / `FindOneAndUpdateOptions`) is
174
+ * ignored; the diff pipeline has no mongo-`findOneAndUpdate` knob.
175
+ */
159
176
  upsertBatch<T extends DbEntity>(collection: string, batch: BatchSpec<T>): Promise<T[]>;
160
177
  getMemoryCollection<T extends DbEntity>(collection: string): T[];
161
178
  getDebounceDexieWritesMs(): number;
@@ -866,27 +866,15 @@ export interface I_SyncedDb {
866
866
  */
867
867
  getSyncOnlyTheseCollections(): ReadonlySet<string> | null;
868
868
  /**
869
- * Izvede batch upsert na serverju
869
+ * Batch wrapper around `upsert()` applies each entry via the standard
870
+ * write pipeline (`computeDiff` → `applyDiffLocally` → in-mem + Dexie +
871
+ * dirty change). Dirty entries from all entries coalesce into a single
872
+ * `updateCollections` request at the next sync flush, so the server side
873
+ * still sees one batched upload.
870
874
  *
871
- * IMPORTANT: This method intentionally does NOT update local state (Dexie or in-memory).
872
- * This is by design - upsertBatch is meant for server-only operations where local
873
- * state updates are not needed or will be handled separately.
874
- *
875
- * If you need local state to reflect the changes after calling upsertBatch(),
876
- * call sync() afterward to fetch the updated data from the server.
877
- *
878
- * Note: Server notifications (via serverUpdateNotifier) for upsertBatch changes
879
- * may trigger handleServerUpdate(), which will update local state. However, this
880
- * happens asynchronously and may overwrite concurrent local changes if any exist.
881
- *
882
- * - Deluje samo online, offline vrže napako
883
- * - Ne posodablja dexie ali in-mem baze
884
- * - Uporabljeno za operacije, ki ne potrebujejo lokalne sinhronizacije
885
- *
886
- * @example
887
- * // If you need local state updated after batch operation:
888
- * await syncedDb.upsertBatch('items', batchSpec);
889
- * await syncedDb.sync(); // Fetch changes to local state
875
+ * Works offline; entries queue as dirty and upload on reconnect.
876
+ * Per-entry `opts` is ignored (no mongo-`findOneAndUpdate` knob in the
877
+ * diff pipeline).
890
878
  */
891
879
  upsertBatch<T extends DbEntity>(collection: string, batch: BatchSpec<T>): Promise<T[]>;
892
880
  /** Vrne vse objekte iz in-mem baze za dano kolekcijo */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cry-synced-db-client",
3
- "version": "0.1.164",
3
+ "version": "0.1.166",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",