react-native-mosquito-transport 0.0.34 → 0.0.36

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.
@@ -2,17 +2,15 @@ import { niceHash, shuffleArray, sortArrayByObjectKey } from "../../helpers/peri
2
2
  import { awaitStore, updateCacheStore } from "../../helpers/utils";
3
3
  import { CacheStore, Scoped } from "../../helpers/variables";
4
4
  import { assignExtractionFind, CompareBson, confirmFilterDoc, defaultBSON, downcastBSON, validateCollectionName, validateFilter } from "./validator";
5
- import getLodash from 'lodash/get';
6
- import setLodash from 'lodash/set';
7
- import unsetLodash from 'lodash/unset';
8
5
  import { DatabaseRecordsListener } from "../../helpers/listeners";
9
6
  import cloneDeep from "lodash/cloneDeep";
10
- import { BSONRegExp, ObjectId, Timestamp } from "bson/lib/bson.rn.cjs";
7
+ import { BSONRegExp, ObjectId, Timestamp } from "../../vendor/bson";
11
8
  import { niceGuard, Validator } from "guard-object";
12
9
  import { TIMESTAMP } from "../..";
13
10
  import { docSize, incrementDatabaseSize } from "./counter";
14
- import { deserializeBSON, serializeToBase64 } from "./bson";
11
+ import { DatastoreParser, serializeToBase64 } from "./bson";
15
12
  import { FS_PATH, getSystem, useFS } from "../../helpers/fs_manager";
13
+ import { grab, poke, unpoke } from "poke-object";
16
14
 
17
15
  const { LIMITER_DATA, LIMITER_RESULT, DB_COUNT_QUERY } = FS_PATH;
18
16
 
@@ -48,12 +46,12 @@ export const insertCountQuery = async (builder, access_id, value) => {
48
46
 
49
47
  const { io } = Scoped.ReleaseCacheData;
50
48
  if (io) {
51
- setLodash(CacheStore.DatabaseCountResult, [projectUrl, dbUrl, dbName, path, access_id], { value, touched: Date.now() });
49
+ poke(CacheStore.DatabaseCountResult, [projectUrl, dbUrl, dbName, path, access_id], { value, touched: Date.now() });
52
50
  updateCacheStore(['DatabaseCountResult']);
53
51
  } else {
54
52
  await useFS(builder, access_id, 'dbQueryCount')(async fs => {
55
53
  await fs.set(DB_COUNT_QUERY(path), access_id, { value, touched: Date.now() });
56
- setLodash(CacheStore.DatabaseStats.counters, [projectUrl, dbUrl, dbName, path], true);
54
+ poke(CacheStore.DatabaseStats.counters, [projectUrl, dbUrl, dbName, path], true);
57
55
  });
58
56
  updateCacheStore(['DatabaseStats']);
59
57
  }
@@ -64,7 +62,7 @@ export const getCountQuery = async (builder, access_id) => {
64
62
  const { io } = Scoped.ReleaseCacheData;
65
63
 
66
64
  if (io) {
67
- const data = getLodash(CacheStore.DatabaseCountResult, [projectUrl, dbUrl, dbName, path, access_id]);
65
+ const data = grab(CacheStore.DatabaseCountResult, [projectUrl, dbUrl, dbName, path, access_id]);
68
66
  if (data) data.touched = Date.now();
69
67
  return data && data.value;
70
68
  } else {
@@ -102,14 +100,13 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
102
100
  const editionSizeOffset = thisSize - (instanceData?.size || 0);
103
101
  const resultSizeOffset = isEpisode ? thisSize - (resultData?.size || 0) : 0;
104
102
 
105
- const newData = serializeToBase64({
103
+ const newData = DatastoreParser.encode({
106
104
  command,
107
105
  config,
108
106
  latest_limiter: limit,
109
- size: thisSize,
110
107
  data: value ? Array.isArray(value) ? value : [value] : []
111
108
  });
112
- const newResultData = isEpisode && serializeToBase64({
109
+ const newResultData = isEpisode && DatastoreParser.encode({
113
110
  data: value,
114
111
  size: thisSize
115
112
  });
@@ -134,8 +131,8 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
134
131
  return;
135
132
  }
136
133
 
137
- const instanceData = getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', accessIdWithoutLimit]);
138
- const resultData = getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, limit]);
134
+ const instanceData = grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', accessIdWithoutLimit]);
135
+ const resultData = grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, `${limit}`]);
139
136
  const isEpisode = episode === 1 || !!resultData;
140
137
 
141
138
  const editionSizeOffset = thisSize - (instanceData?.size || 0);
@@ -157,8 +154,8 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
157
154
 
158
155
  incrementDatabaseSize(builder, path, editionSizeOffset + resultSizeOffset);
159
156
 
160
- setLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', accessIdWithoutLimit], newData);
161
- if (isEpisode) setLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, limit], cloneDeep(newResultData));
157
+ poke(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', accessIdWithoutLimit], newData);
158
+ if (isEpisode) poke(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, `${limit}`], cloneDeep(newResultData));
162
159
  updateCacheStore(['DatabaseStore', 'DatabaseStats']);
163
160
  };
164
161
 
@@ -197,7 +194,7 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
197
194
  isEpisode ? fs.find(LIMITER_RESULT(path), resultAccessId, ['value']) :
198
195
  fs.find(LIMITER_DATA(path), accessIdWithoutLimit, ['value'])
199
196
  ).catch(() => null);
200
- const thisData = qData && deserializeBSON(qData.value, true);
197
+ const thisData = qData && DatastoreParser.decode(qData.value);
201
198
 
202
199
  if (!thisData) return null;
203
200
 
@@ -221,7 +218,7 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
221
218
  }
222
219
 
223
220
  if (isEpisode) {
224
- const resultData = getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, limit]);
221
+ const resultData = grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, `${limit}`]);
225
222
  if (resultData) {
226
223
  resultData.touched = Date.now();
227
224
  return [cloneDeep(resultData.data)];
@@ -229,7 +226,7 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
229
226
  return null;
230
227
  }
231
228
 
232
- const instanceData = getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', accessIdWithoutLimit]);
229
+ const instanceData = grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', accessIdWithoutLimit]);
233
230
  if (!instanceData) return null;
234
231
  const { latest_limiter, data } = instanceData;
235
232
 
@@ -285,7 +282,7 @@ const arrangeCommands = (c, removeLimit) => {
285
282
  if (c.sort) c.direction = [-1, 'desc', 'descending'].includes(c.direction) ? 'desc' : 'asc';
286
283
  if (c.find) c.find = sortFind(c.find);
287
284
  if (c.findOne) c.findOne = sortFind(c.findOne);
288
- if (removeLimit && 'limit' in c) delete c.limit;
285
+ if (removeLimit && ('limit' in c)) delete c.limit;
289
286
  return sortObject(c);
290
287
  };
291
288
 
@@ -389,19 +386,20 @@ export const addPendingWrites = async (builder, writeId, result) => {
389
386
  const pathChanges = new Set([]);
390
387
  const pendingSnapshot = cloneDeep(result);
391
388
 
392
- await Promise.all((
389
+ const linearWrite =
393
390
  result.type === 'batchWrite' ?
394
391
  result.value.map(({ scope, value, find, path }) =>
395
392
  ({ type: scope, value, find, path })
396
393
  )
397
- : [{ ...result, path: builder.path }]
398
- ).map(async ({ value: writeObj, find, type, path }) => {
394
+ : [{ ...result, find: builder.find, path: builder.path }];
395
+
396
+ await Promise.all(linearWrite.map(async ({ value: writeObj, find, type, path }) => {
399
397
  WriteValidator[type]({ find, value: writeObj });
400
398
  validateCollectionName(path);
401
399
  pathChanges.add(path);
402
400
 
403
401
  if (io) {
404
- const colObj = getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance']);
402
+ const colObj = grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance']);
405
403
 
406
404
  if (colObj)
407
405
  await Promise.all(
@@ -410,7 +408,7 @@ export const addPendingWrites = async (builder, writeId, result) => {
410
408
  e,
411
409
  path =>
412
410
  Object.values(
413
- getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance'], {})
411
+ grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance'], {})
414
412
  ).map(({ data }) => data).flat()
415
413
  )
416
414
  )
@@ -422,18 +420,18 @@ export const addPendingWrites = async (builder, writeId, result) => {
422
420
  await Promise.all(colListing.map(async ([access_id]) =>
423
421
  useFS(builder, access_id, 'database')(async fs => {
424
422
  const data = await fs.find(LIMITER_DATA(path), access_id, ['value'])
425
- .then(r => deserializeBSON(r.value, true));
423
+ .then(r => DatastoreParser.decode(r.value));
426
424
 
427
425
  await MutateDataInstance([access_id, data], path =>
428
426
  pathFinder[path] || (
429
427
  pathFinder[path] = fs.list(LIMITER_DATA(path), ['value'])
430
- .then(v => v.map(d => deserializeBSON(d[1].value, true).data).flat())
428
+ .then(v => v.map(d => DatastoreParser.decode(d[1].value).data).flat())
431
429
  .catch(() => [])
432
430
  )
433
431
  );
434
432
  await fs.set(LIMITER_DATA(path), access_id, {
435
433
  touched: Date.now(),
436
- value: serializeToBase64(data),
434
+ value: DatastoreParser.encode(data),
437
435
  size: data.size
438
436
  });
439
437
  })
@@ -640,12 +638,57 @@ export const addPendingWrites = async (builder, writeId, result) => {
640
638
  };
641
639
  }));
642
640
 
643
- setLodash(CacheStore.PendingWrites, [projectUrl, writeId], cloneDeep({
644
- builder,
645
- snapshot: pendingSnapshot,
646
- editions,
647
- addedOn: Date.now()
648
- }));
641
+ const isStaticWrite = !linearWrite.some(({ value, type }) => {
642
+ if (
643
+ [
644
+ 'updateOne',
645
+ 'updateMany',
646
+ 'mergeOne',
647
+ 'mergeMany'
648
+ ].includes(type)
649
+ ) {
650
+ const operators = Object.keys(value);
651
+ return ['$inc', '$min', '$max', '$mul', '$pop', '$pull', '$push', '$rename'].includes(operators);
652
+ }
653
+ });
654
+ const pureBuilder = {};
655
+
656
+ ['path', 'dbUrl', 'dbName', 'find', 'extraHeaders', 'maxRetries'].forEach(v => {
657
+ if (builder[v] !== undefined) pureBuilder[v] = builder[v];
658
+ });
659
+ pureBuilder.find = serializeToBase64({ _: pureBuilder.find });
660
+ pendingSnapshot.value = serializeToBase64({ _: pendingSnapshot.value });
661
+
662
+ let wasShifted;
663
+
664
+ if (isStaticWrite) {
665
+ // find previously matching pending write
666
+ const entries = Object.entries(CacheStore.PendingWrites[projectUrl] || {});
667
+
668
+ for (const [writeId, obj] of entries) {
669
+ if (!Scoped.OutgoingWrites[writeId]) {
670
+ if (
671
+ niceGuard(
672
+ { builder: obj.builder, snapshot: obj.snapshot },
673
+ { builder: pureBuilder, snapshot: pendingSnapshot }
674
+ )
675
+ ) {
676
+ // shift it to the front
677
+ obj.addedOn = Date.now();
678
+ wasShifted = true;
679
+ break;
680
+ }
681
+ }
682
+ }
683
+ }
684
+
685
+ if (!wasShifted)
686
+ poke(CacheStore.PendingWrites, [projectUrl, writeId], cloneDeep({
687
+ builder: pureBuilder,
688
+ snapshot: pendingSnapshot,
689
+ editions,
690
+ addedOn: Date.now()
691
+ }));
649
692
 
650
693
  updateCacheStore(['DatabaseStore', 'PendingWrites', 'DatabaseStats']);
651
694
  notifyDatabaseNodeChanges(builder, [...pathChanges]);
@@ -654,7 +697,7 @@ export const addPendingWrites = async (builder, writeId, result) => {
654
697
  export const removePendingWrite = async (builder, writeId, revert) => {
655
698
  await awaitStore();
656
699
  const { projectUrl, dbUrl, dbName } = builder;
657
- const pendingData = getLodash(CacheStore.PendingWrites, [projectUrl, writeId]);
700
+ const pendingData = grab(CacheStore.PendingWrites, [projectUrl, writeId]);
658
701
  const { io } = Scoped.ReleaseCacheData;
659
702
 
660
703
  if (!pendingData) return;
@@ -663,16 +706,16 @@ export const removePendingWrite = async (builder, writeId, revert) => {
663
706
  if (revert) {
664
707
  await Promise.all(pendingData.editions.map(async ([access_id, [b4Doc, afDoc], path]) => {
665
708
  if (io) {
666
- RevertMutation(getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', access_id]));
709
+ RevertMutation(grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', access_id]));
667
710
  } else {
668
711
  await useFS(builder, access_id, 'database')(async fs => {
669
712
  const colObj = await fs.find(LIMITER_DATA(path), access_id, ['value'])
670
- .then(v => deserializeBSON(v.value))
713
+ .then(v => DatastoreParser.decode(v.value))
671
714
  .catch(() => null);
672
715
  if (!colObj) return;
673
716
  RevertMutation(colObj);
674
717
  await fs.set(LIMITER_DATA(path), access_id, {
675
- value: serializeToBase64(colObj),
718
+ value: DatastoreParser.encode(colObj),
676
719
  touched: Date.now(),
677
720
  size: colObj.size
678
721
  });
@@ -717,7 +760,7 @@ export const removePendingWrite = async (builder, writeId, revert) => {
717
760
  }));
718
761
  }
719
762
 
720
- unsetLodash(CacheStore.PendingWrites, [projectUrl, writeId]);
763
+ unpoke(CacheStore.PendingWrites, [projectUrl, writeId]);
721
764
  updateCacheStore(['PendingWrites', 'DatabaseStore', 'DatabaseStats']);
722
765
  notifyDatabaseNodeChanges(builder, [...pathChanges]);
723
766
  };
@@ -768,19 +811,19 @@ const snipDocument = (data, find, config) => {
768
811
  if (returnOnly) {
769
812
  output = {};
770
813
  (Array.isArray(returnOnly) ? returnOnly : [returnOnly]).filter(v => v).forEach(e => {
771
- const thisData = getLodash(data, e);
772
- if (thisData) setLodash(output, e, thisData);
814
+ const thisData = grab(data, e);
815
+ if (thisData) poke(output, e, thisData);
773
816
  });
774
817
  } else if (excludeFields) {
775
818
  (Array.isArray(excludeFields) ? excludeFields : [excludeFields]).filter(v => v).forEach(e => {
776
- if (getLodash(data, e) && e !== '_id') unsetLodash(output, e);
819
+ if (grab(data, e) && e !== '_id') unpoke(output, e);
777
820
  });
778
821
  }
779
822
 
780
823
  getFindFields(find).forEach(field => {
781
- if (!getLodash(output, field)) {
782
- const mainData = getLodash(data, field);
783
- if (mainData !== undefined) setLodash(output, field, mainData);
824
+ if (!grab(output, field)) {
825
+ const mainData = grab(data, field);
826
+ if (mainData !== undefined) poke(output, field, mainData);
784
827
  }
785
828
  });
786
829
 
@@ -850,10 +893,10 @@ const AtomicWriter = {
850
893
  !isDate &&
851
894
  !isTimestamp
852
895
  ) throw `invalid value at $currentDate.${field}, expected any of boolean (true), { $type: "timestamp" } or { $type: "date" } but got ${value}`;
853
- setLodash(object, field, isDate ? new Date() : new Timestamp({ t: Math.floor(Date.now() / 1000), i: 0 }));
896
+ poke(object, field, isDate ? new Date() : new Timestamp({ t: Math.floor(Date.now() / 1000), i: 0 }));
854
897
  },
855
898
  $inc: (field, value, object) => {
856
- const current = getLodash(object, field);
899
+ const current = grab(object, field);
857
900
  if (current === null) {
858
901
  console.warn(`cannot use $inc operator on a null value at ${field}`);
859
902
  return;
@@ -863,29 +906,29 @@ const AtomicWriter = {
863
906
 
864
907
  if (!Validator.NUMBER(castedValue)) throw `expected a number at $inc.${field} but got ${value}`;
865
908
 
866
- setLodash(object, field, Validator.NUMBER(castedCurrent) ? defaultBSON(castedCurrent + castedValue, current) : value);
909
+ poke(object, field, Validator.NUMBER(castedCurrent) ? defaultBSON(castedCurrent + castedValue, current) : value);
867
910
  },
868
911
  $min: (field, value, object) => {
869
- const current = getLodash(object, field);
912
+ const current = grab(object, field);
870
913
  if (CompareBson.lesser(value, current)) {
871
- setLodash(object, field, value);
914
+ poke(object, field, value);
872
915
  }
873
916
  },
874
917
  $max: (field, value, object) => {
875
- const current = getLodash(object, field);
918
+ const current = grab(object, field);
876
919
  if (CompareBson.greater(value, current)) {
877
- setLodash(object, field, value);
920
+ poke(object, field, value);
878
921
  }
879
922
  },
880
923
  $mul: (field, value, object) => {
881
- const current = getLodash(object, field);
924
+ const current = grab(object, field);
882
925
  const castedValue = downcastBSON(value);
883
926
  const castedCurrent = downcastBSON(current);
884
927
 
885
928
  if (!Validator.NUMBER(castedValue))
886
929
  throw `expected a number at $mul.${field} but got ${value}`;
887
930
 
888
- setLodash(object, field, Validator.NUMBER(castedCurrent) ? defaultBSON(castedCurrent * castedValue, value) : 0);
931
+ poke(object, field, Validator.NUMBER(castedCurrent) ? defaultBSON(castedCurrent * castedValue, value) : 0);
889
932
  },
890
933
  $rename: (field, value, object) => {
891
934
  if (!Validator.EMPTY_STRING(value))
@@ -903,7 +946,7 @@ const AtomicWriter = {
903
946
  if (!e) throw `empty node for ${field}`;
904
947
  });
905
948
  const [tipObj, tipSource, tipDest] = destStage.length === 1 ? [object, field, value]
906
- : [getLodash(object, destStage.slice(0, -1).join('.')), sourceStage.slice(-1)[0], destStage.slice(-1)[0]];
949
+ : [grab(object, destStage.slice(0, -1).join('.')), sourceStage.slice(-1)[0], destStage.slice(-1)[0]];
907
950
 
908
951
  if (tipObj && tipSource in tipObj) {
909
952
  tipObj[tipDest] = cloneDeep(tipObj[tipSource]);
@@ -911,16 +954,16 @@ const AtomicWriter = {
911
954
  }
912
955
  },
913
956
  $set: (field, value, object) => {
914
- setLodash(object, field, value === undefined ? null : value);
957
+ poke(object, field, value === undefined ? null : value);
915
958
  },
916
959
  $setOnInsert: (field, value, object, isNew) => {
917
960
  if (isNew) AtomicWriter.$set(field, value, object);
918
961
  },
919
962
  $unset: (field, _, object) => {
920
- unsetLodash(object, field);
963
+ unpoke(object, field);
921
964
  },
922
965
  $addToSet: (field, value, object) => {
923
- const current = getLodash(object, field);
966
+ const current = grab(object, field);
924
967
  if (Array.isArray(current)) {
925
968
  if (
926
969
  Validator.OBJECT(value) &&
@@ -942,7 +985,7 @@ const AtomicWriter = {
942
985
  },
943
986
  $pop: (field, value, object) => {
944
987
  if (![1, -1].includes(value)) throw `expected 1 or -1 at "$pop.${field}" but got ${value}`;
945
- const current = getLodash(object, field);
988
+ const current = grab(object, field);
946
989
  if (
947
990
  Array.isArray(current) &&
948
991
  current.length
@@ -950,7 +993,7 @@ const AtomicWriter = {
950
993
  },
951
994
  $pull: (field, value, object) => {
952
995
  // TODO: issues
953
- const current = getLodash(object, field);
996
+ const current = grab(object, field);
954
997
  const isQueryObject = Validator.OBJECT(value);
955
998
 
956
999
  if (
@@ -972,11 +1015,11 @@ const AtomicWriter = {
972
1015
  } catch (_) { }
973
1016
  return true;
974
1017
  });
975
- setLodash(object, field, remainingCurrent);
1018
+ poke(object, field, remainingCurrent);
976
1019
  }
977
1020
  },
978
1021
  $push: (field, value, object) => {
979
- const current = getLodash(object, field);
1022
+ const current = grab(object, field);
980
1023
 
981
1024
  if (Array.isArray(current)) {
982
1025
  if (Validator.OBJECT(value)) {
@@ -1023,13 +1066,13 @@ const AtomicWriter = {
1023
1066
  if (!Array.isArray(value))
1024
1067
  throw `expected an array at $pullAll.${field}`;
1025
1068
 
1026
- const current = getLodash(object, field);
1069
+ const current = grab(object, field);
1027
1070
 
1028
1071
  if (Array.isArray(current)) {
1029
1072
  const remainingCurrent = current.filter(v =>
1030
1073
  !value.some(k => CompareBson.equal(v, k))
1031
1074
  );
1032
- setLodash(object, field, remainingCurrent);
1075
+ poke(object, field, remainingCurrent);
1033
1076
  }
1034
1077
  }
1035
1078
  };
@@ -1,4 +1,5 @@
1
- import { deserialize, serialize } from "bson/lib/bson.rn.cjs";
1
+ import { cloneDeep } from "lodash";
2
+ import { deserialize, serialize } from "../../vendor/bson";
2
3
  import { Buffer } from "buffer";
3
4
 
4
5
  export const deserializeBSON = (data, cast) => {
@@ -13,4 +14,45 @@ export const deserializeBSON = (data, cast) => {
13
14
  });
14
15
  };
15
16
 
16
- export const serializeToBase64 = doc => Buffer.from(serialize(doc)).toString('base64');
17
+ export const serializeToBase64 = doc => Buffer.from(serialize(doc)).toString('base64');
18
+
19
+ export const DatastoreParser = {
20
+ encode: (obj) => {
21
+ obj = cloneDeep(obj);
22
+ const { command, config } = obj;
23
+
24
+ const serializeQuery = (e) =>
25
+ ['find', 'findOne'].forEach(n => {
26
+ if (e?.[n]) e[n] = serializeToBase64({ _: e[n] });
27
+ });
28
+
29
+ if (command) serializeQuery(command);
30
+ if (config) {
31
+ if (config.extraction)
32
+ (Array.isArray(config.extraction) ? config.extraction : [config.extraction]).forEach(e => {
33
+ serializeQuery(e);
34
+ });
35
+ }
36
+ if (obj.data) obj.data = serializeToBase64({ _: obj.data });
37
+ return obj;
38
+ },
39
+ decode: (obj, cast = true) => {
40
+ obj = cloneDeep(obj);
41
+ const { command, config } = obj;
42
+
43
+ const serializeQuery = (e) =>
44
+ ['find', 'findOne'].forEach(n => {
45
+ if (e?.[n]) e[n] = deserializeBSON(e[n], cast)._;
46
+ });
47
+
48
+ if (command) serializeQuery(command);
49
+ if (config) {
50
+ if (config.extraction)
51
+ (Array.isArray(config.extraction) ? config.extraction : [config.extraction]).forEach(e => {
52
+ serializeQuery(e);
53
+ });
54
+ }
55
+ if (obj.data) obj.data = deserializeBSON(obj.data, cast)._;
56
+ return obj;
57
+ }
58
+ };
@@ -1,7 +1,6 @@
1
- import getLodash from "lodash/get";
2
- import setLodash from 'lodash/set';
3
1
  import { CacheStore } from "../../helpers/variables";
4
- import { serializeToBase64 } from "./bson";
2
+ import { grab, poke } from "poke-object";
3
+ import { calculateObjectSize } from '../../vendor/bson';
5
4
 
6
5
  export const incrementDatabaseSize = (builder, path, size) => incrementDatabaseSizeCore(CacheStore.DatabaseStats, builder, path, size);
7
6
 
@@ -11,8 +10,8 @@ export const incrementDatabaseSizeCore = (baseObj, builder, path, size = 0) => {
11
10
 
12
11
  const node = [projectUrl, dbUrl, dbName, path];
13
12
 
14
- const b4 = getLodash(baseObj.database, node, 0);
15
- setLodash(baseObj.database, node, b4 + size);
13
+ const b4 = grab(baseObj.database, node, 0);
14
+ poke(baseObj.database, node, b4 + size);
16
15
  }
17
16
 
18
- export const docSize = doc => doc ? serializeToBase64({ _: doc }).length : 0;
17
+ export const docSize = doc => doc ? calculateObjectSize({ _: doc }) : 0;
@@ -2,13 +2,13 @@ import { io } from "socket.io-client";
2
2
  import EngineApi from "../../helpers/engine_api";
3
3
  import { DatabaseRecordsListener } from "../../helpers/listeners";
4
4
  import { deserializeE2E, listenReachableServer, niceTry, serializeE2E } from "../../helpers/peripherals";
5
- import { awaitStore, buildFetchInterface, buildFetchResult, getReachableServer } from "../../helpers/utils";
5
+ import { awaitStore, buildFetchInterface, buildFetchResult, getReachableServer, updateCacheStore } from "../../helpers/utils";
6
6
  import { CacheStore, Scoped } from "../../helpers/variables";
7
7
  import { addPendingWrites, generateRecordID, getCountQuery, getRecord, insertCountQuery, insertRecord, listenQueryEntry, removePendingWrite, validateWriteValue } from "./accessor";
8
8
  import { validateCollectionName, validateFilter, validateFindConfig, validateFindObject, validateListenFindConfig } from "./validator";
9
9
  import { awaitRefreshToken, listenToken } from "../auth/accessor";
10
10
  import { DELIVERY, RETRIEVAL } from "../../helpers/values";
11
- import { ObjectId } from "bson/lib/bson.rn.cjs";
11
+ import { ObjectId } from "../../vendor/bson";
12
12
  import { guardObject, Validator } from "guard-object";
13
13
  import { simplifyCaughtError } from "simplify-error";
14
14
  import cloneDeep from "lodash/cloneDeep";
@@ -395,6 +395,7 @@ const countCollection = async (builder, config) => {
395
395
  const b4Data = await getCountQuery(builder, accessId).catch(() => null);
396
396
 
397
397
  if (e?.simpleError) {
398
+ e.simpleError.ack = true;
398
399
  finalize(undefined, e.simpleError);
399
400
  } else if (!disableCache && Validator.NUMBER(b4Data)) {
400
401
  finalize(b4Data);
@@ -552,6 +553,7 @@ const findObject = async (builder, config) => {
552
553
  (thisRecord = [await getRecordData()])[0];
553
554
 
554
555
  if (e?.simpleError) {
556
+ e.simpleError.ack = true;
555
557
  finalize(undefined, e?.simpleError);
556
558
  } else if (
557
559
  (retrieval === RETRIEVAL.CACHE_NO_AWAIT && !(await getThisRecord())) ||
@@ -622,13 +624,14 @@ const commitData = async (builder, value, type, config) => {
622
624
  const writeId = `${Date.now() + ++Scoped.PendingIte}`;
623
625
  const isBatchWrite = type === 'batchWrite';
624
626
  const shouldCache = (delivery !== DELIVERY.DEFAULT || !disableCache) &&
625
- ![DELIVERY.NO_CACHE_AWAIT, DELIVERY.NO_CACHE_NO_AWAIT].includes();
627
+ ![DELIVERY.NO_CACHE_AWAIT, DELIVERY.NO_CACHE_NO_AWAIT].includes(delivery);
626
628
 
627
629
  await awaitStore();
628
630
  if (shouldCache) {
629
- await addPendingWrites(builder, writeId, { value, type, find, config });
631
+ await addPendingWrites(builder, writeId, { value, type, config: stripUndefined({ disableAuth, stepping }) });
630
632
  Scoped.OutgoingWrites[writeId] = true;
631
- await Scoped.dispatchingWritesPromise;
633
+ if (Scoped.dispatchingWritesPromise[projectUrl])
634
+ await Scoped.dispatchingWritesPromise[projectUrl];
632
635
  }
633
636
 
634
637
  let retries = 0, hasFinalize;
@@ -649,10 +652,11 @@ const commitData = async (builder, value, type, config) => {
649
652
  } else reject(b);
650
653
  if (hasFinalize || !instantProcess) return;
651
654
  hasFinalize = true;
655
+ if (Scoped.OutgoingWrites[writeId])
656
+ delete Scoped.OutgoingWrites[writeId];
657
+
652
658
  if (shouldCache) {
653
659
  if (removeCache) removePendingWrite(builder, writeId, revertCache);
654
- if (Scoped.OutgoingWrites[writeId])
655
- delete Scoped.OutgoingWrites[writeId];
656
660
  }
657
661
  };
658
662
 
@@ -687,7 +691,8 @@ const commitData = async (builder, value, type, config) => {
687
691
  } catch (e) {
688
692
  if (e?.simpleError) {
689
693
  console.error(`${type} error (${path}), ${e.simpleError?.message}`);
690
- finalize(undefined, e?.simpleError, { removeCache: true, revertCache: true });
694
+ e.simpleError.ack = true;
695
+ finalize(undefined, e.simpleError, { removeCache: true, revertCache: true });
691
696
  } else if (delivery === DELIVERY.NO_CACHE_NO_AWAIT) {
692
697
  finalize(undefined, simplifyCaughtError(e).simpleError);
693
698
  } else if (retries > maxRetries) {
@@ -717,9 +722,9 @@ const commitData = async (builder, value, type, config) => {
717
722
  };
718
723
 
719
724
  export const trySendPendingWrite = (projectUrl) => {
720
- if (Scoped.dispatchingWritesPromise) return;
725
+ if (Scoped.dispatchingWritesPromise[projectUrl]) return;
721
726
 
722
- Scoped.dispatchingWritesPromise = new Promise(async resolve => {
727
+ Scoped.dispatchingWritesPromise[projectUrl] = new Promise(async resolve => {
723
728
  const sortedWrite = Object.entries(CacheStore.PendingWrites[projectUrl] || {})
724
729
  .filter(([k]) => !Scoped.OutgoingWrites[k])
725
730
  .sort((a, b) => a[1].addedOn - b[1].addedOn);
@@ -727,12 +732,18 @@ export const trySendPendingWrite = (projectUrl) => {
727
732
 
728
733
  for (const [writeId, { snapshot, builder, attempts = 1 }] of sortedWrite) {
729
734
  try {
730
- await commitData(builder, snapshot.value, snapshot.type, { ...snapshot.config, delivery: DELIVERY.NO_CACHE_NO_AWAIT });
735
+ await commitData(
736
+ { ...Scoped.InitializedProject[projectUrl], ...builder, find: deserializeBSON(builder.find, true)._ },
737
+ deserializeBSON(snapshot.value, true)._,
738
+ snapshot.type,
739
+ { ...snapshot.config, delivery: DELIVERY.NO_CACHE_NO_AWAIT }
740
+ );
741
+
731
742
  delete CacheStore.PendingWrites[projectUrl][writeId];
732
743
  ++resolveCounts;
733
- } catch (_) {
744
+ } catch (err) {
734
745
  const { maxRetries } = builder;
735
- if (!maxRetries || attempts >= maxRetries) {
746
+ if (err?.ack || !maxRetries || attempts >= maxRetries) {
736
747
  delete CacheStore.PendingWrites[projectUrl][writeId];
737
748
  ++resolveCounts;
738
749
  } else if (CacheStore.PendingWrites[projectUrl]?.[writeId]) {
@@ -741,7 +752,10 @@ export const trySendPendingWrite = (projectUrl) => {
741
752
  }
742
753
  }
743
754
  resolve();
744
- Scoped.dispatchingWritesPromise = undefined;
755
+ if (projectUrl in Scoped.dispatchingWritesPromise)
756
+ delete Scoped.dispatchingWritesPromise[projectUrl];
757
+ updateCacheStore(['PendingWrites']);
758
+
745
759
  if (
746
760
  (sortedWrite.length - resolveCounts) &&
747
761
  await getReachableServer(projectUrl)
@@ -1,8 +1,9 @@
1
+ import { guardObject, GuardSignal, niceGuard } from "guard-object";
1
2
 
2
3
  export const TIMESTAMP = { $timestamp: "now" };
3
4
  export const TIMESTAMP_OFFSET = (v) => ({ $timestamp_offset: v });
4
5
 
5
- export const IS_TIMESTAMP = (t) => t && (typeof t.$timestamp === 'number' || t.$timestamp === 'now') && Object.keys(t).length === 1;
6
+ export const IS_TIMESTAMP = (t) => niceGuard({ $timestamp: t => t === 'now' || typeof t.$timestamp === 'number' }, t);
6
7
 
7
8
  export const DOCUMENT_EXTRACTION = (path) => ({ $dynamicValue: path });
8
9
 
@@ -11,13 +12,17 @@ export const GEO_JSON = (lat, lng) => ({
11
12
  coordinates: [lng, lat],
12
13
  });
13
14
 
14
- export const FIND_GEO_JSON = (location, offSetMeters, centerMeters) => ({
15
- $nearSphere: {
16
- $geometry: {
17
- type: "Point",
18
- coordinates: location.reverse()
19
- },
20
- $minDistance: centerMeters || 0,
21
- $maxDistance: offSetMeters
22
- }
23
- });
15
+ export const FIND_GEO_JSON = (location, offSetMeters, centerMeters) => {
16
+ guardObject(GuardSignal.COORDINATE.LAT_LNG_INT).validate(location);
17
+
18
+ return {
19
+ $nearSphere: {
20
+ $geometry: {
21
+ type: "Point",
22
+ coordinates: location.slice(0).reverse()
23
+ },
24
+ $minDistance: centerMeters || 0,
25
+ $maxDistance: offSetMeters
26
+ }
27
+ };
28
+ };