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.
- package/package.json +3 -3
- package/src/helpers/fs_manager.js +9 -7
- package/src/helpers/peripherals.js +3 -3
- package/src/helpers/purger.js +6 -6
- package/src/helpers/utils.js +47 -26
- package/src/helpers/values.js +1 -1
- package/src/helpers/variables.js +2 -9
- package/src/index.js +1 -1
- package/src/products/auth/index.js +1 -1
- package/src/products/database/accessor.js +106 -63
- package/src/products/database/bson.js +44 -2
- package/src/products/database/counter.js +5 -6
- package/src/products/database/index.js +28 -14
- package/src/products/database/types.js +16 -11
- package/src/products/database/validator.js +5 -5
- package/src/products/http_callable/counter.js +3 -4
- package/src/vendor/bson.d.ts +1723 -0
- package/src/vendor/bson.js +4650 -0
- package/src/vendor/encoder.js +37 -0
- package/src/vendor/utf8-validator.js +60 -0
- package/src/vendor/utf8-validator.test.js +35 -0
|
@@ -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 "
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 &&
|
|
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 =
|
|
138
|
-
const resultData =
|
|
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
|
-
|
|
161
|
-
if (isEpisode)
|
|
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 &&
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =>
|
|
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 =>
|
|
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:
|
|
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
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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 =
|
|
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(
|
|
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 =>
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
772
|
-
if (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 (
|
|
819
|
+
if (grab(data, e) && e !== '_id') unpoke(output, e);
|
|
777
820
|
});
|
|
778
821
|
}
|
|
779
822
|
|
|
780
823
|
getFindFields(find).forEach(field => {
|
|
781
|
-
if (!
|
|
782
|
-
const mainData =
|
|
783
|
-
if (mainData !== undefined)
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
909
|
+
poke(object, field, Validator.NUMBER(castedCurrent) ? defaultBSON(castedCurrent + castedValue, current) : value);
|
|
867
910
|
},
|
|
868
911
|
$min: (field, value, object) => {
|
|
869
|
-
const current =
|
|
912
|
+
const current = grab(object, field);
|
|
870
913
|
if (CompareBson.lesser(value, current)) {
|
|
871
|
-
|
|
914
|
+
poke(object, field, value);
|
|
872
915
|
}
|
|
873
916
|
},
|
|
874
917
|
$max: (field, value, object) => {
|
|
875
|
-
const current =
|
|
918
|
+
const current = grab(object, field);
|
|
876
919
|
if (CompareBson.greater(value, current)) {
|
|
877
|
-
|
|
920
|
+
poke(object, field, value);
|
|
878
921
|
}
|
|
879
922
|
},
|
|
880
923
|
$mul: (field, value, object) => {
|
|
881
|
-
const current =
|
|
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
|
-
|
|
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
|
-
: [
|
|
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
|
-
|
|
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
|
-
|
|
963
|
+
unpoke(object, field);
|
|
921
964
|
},
|
|
922
965
|
$addToSet: (field, value, object) => {
|
|
923
|
-
const current =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
1018
|
+
poke(object, field, remainingCurrent);
|
|
976
1019
|
}
|
|
977
1020
|
},
|
|
978
1021
|
$push: (field, value, object) => {
|
|
979
|
-
const current =
|
|
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 =
|
|
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
|
-
|
|
1075
|
+
poke(object, field, remainingCurrent);
|
|
1033
1076
|
}
|
|
1034
1077
|
}
|
|
1035
1078
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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 =
|
|
15
|
-
|
|
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 ?
|
|
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 "
|
|
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,
|
|
631
|
+
await addPendingWrites(builder, writeId, { value, type, config: stripUndefined({ disableAuth, stepping }) });
|
|
630
632
|
Scoped.OutgoingWrites[writeId] = true;
|
|
631
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
+
};
|