rads-db 0.1.72 → 0.1.74
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.cjs +265 -178
- package/dist/index.d.ts +26 -2
- package/dist/index.mjs +265 -178
- package/features/softDelete.cjs +19 -0
- package/features/softDelete.d.ts +2 -0
- package/features/softDelete.mjs +12 -0
- package/package.json +8 -2
package/dist/index.cjs
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const zod = require('zod');
|
|
4
4
|
const _ = require('lodash');
|
|
5
|
-
const createMerge = require('@fastify/deepmerge');
|
|
6
5
|
const uuid = require('uuid');
|
|
6
|
+
const createMerge = require('@fastify/deepmerge');
|
|
7
7
|
const _radsDb = require('_rads-db');
|
|
8
8
|
|
|
9
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
@@ -98,42 +98,6 @@ function getFieldZodSchemaBase(zodSchemas, schema, field, shouldBeLazy) {
|
|
|
98
98
|
throw new Error(`Unknown type: ${field.type}`);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
const mergeFn = createMerge__default({
|
|
102
|
-
mergeArray(options) {
|
|
103
|
-
const clone = options.clone;
|
|
104
|
-
return function(target, source) {
|
|
105
|
-
return clone(source);
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
function merge(target, source) {
|
|
110
|
-
cleanUndefined(source);
|
|
111
|
-
const result = mergeFn(target, source);
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
function cleanUndefined(obj) {
|
|
115
|
-
if (!obj || !___default.isPlainObject(obj))
|
|
116
|
-
return;
|
|
117
|
-
cleanUndefinedInner(obj);
|
|
118
|
-
}
|
|
119
|
-
function cleanUndefinedInner(obj) {
|
|
120
|
-
for (const key in obj) {
|
|
121
|
-
if (obj[key] === void 0)
|
|
122
|
-
delete obj[key];
|
|
123
|
-
if (___default.isPlainObject(obj[key]))
|
|
124
|
-
cleanUndefinedInner(obj[key]);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function cleanUndefinedAndNull(obj) {
|
|
129
|
-
for (const key in obj) {
|
|
130
|
-
if (obj[key] == null)
|
|
131
|
-
delete obj[key];
|
|
132
|
-
if (___default.isPlainObject(obj[key]))
|
|
133
|
-
cleanUndefinedAndNull(obj[key]);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
101
|
const operatorFns = {
|
|
138
102
|
eq: (x, w) => x === w,
|
|
139
103
|
ieq: (x, w) => x?.toLowerCase() === w?.toLowerCase(),
|
|
@@ -446,6 +410,33 @@ async function handleEffectsAfterPut(context, docs, beforePutResults, ctx) {
|
|
|
446
410
|
);
|
|
447
411
|
}
|
|
448
412
|
|
|
413
|
+
const mergeFn = createMerge__default({
|
|
414
|
+
mergeArray(options) {
|
|
415
|
+
const clone = options.clone;
|
|
416
|
+
return function(target, source) {
|
|
417
|
+
return clone(source);
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
function merge(target, source) {
|
|
422
|
+
cleanUndefined(source);
|
|
423
|
+
const result = mergeFn(target, source);
|
|
424
|
+
return result;
|
|
425
|
+
}
|
|
426
|
+
function cleanUndefined(obj) {
|
|
427
|
+
if (!obj || !___default.isPlainObject(obj))
|
|
428
|
+
return;
|
|
429
|
+
cleanUndefinedInner(obj);
|
|
430
|
+
}
|
|
431
|
+
function cleanUndefinedInner(obj) {
|
|
432
|
+
for (const key in obj) {
|
|
433
|
+
if (obj[key] === void 0)
|
|
434
|
+
delete obj[key];
|
|
435
|
+
if (___default.isPlainObject(obj[key]))
|
|
436
|
+
cleanUndefinedInner(obj[key]);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
449
440
|
function diff(object, base, includeDenormFields = false) {
|
|
450
441
|
if (!base)
|
|
451
442
|
return object;
|
|
@@ -640,154 +631,172 @@ async function fillDenormFieldsBeforePut(computedContext, docUpdates, ctx) {
|
|
|
640
631
|
await Promise.all(promises);
|
|
641
632
|
}
|
|
642
633
|
|
|
643
|
-
function
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
if (!opts.fileUploadDriver)
|
|
650
|
-
throw new Error(`Missing configuration. Please specify "fileUploadDriver" argument in "createRads()".`);
|
|
651
|
-
if (!args.containerName)
|
|
652
|
-
args.containerName = "files";
|
|
653
|
-
return opts.fileUploadDriver.uploadFile(args);
|
|
654
|
-
}
|
|
655
|
-
};
|
|
656
|
-
const effects = {};
|
|
657
|
-
for (const key in schema) {
|
|
658
|
-
effects[key] = [];
|
|
634
|
+
function cleanUndefinedAndNull(obj) {
|
|
635
|
+
for (const key in obj) {
|
|
636
|
+
if (obj[key] == null)
|
|
637
|
+
delete obj[key];
|
|
638
|
+
if (___default.isPlainObject(obj[key]))
|
|
639
|
+
cleanUndefinedAndNull(obj[key]);
|
|
659
640
|
}
|
|
660
|
-
|
|
661
|
-
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
644
|
+
const { schema, options, validators } = computedContext;
|
|
645
|
+
const mustCleanNulls = driverInstance.driverName !== "restApi";
|
|
646
|
+
const { precomputedFields } = schema[key];
|
|
647
|
+
async function getMany(args, ctx) {
|
|
648
|
+
args = { ...args, where: { ...args?.where } };
|
|
649
|
+
ctx = { ...options.context, ...ctx };
|
|
650
|
+
await beforeGet(args, ctx, computedContext);
|
|
651
|
+
const result = await driverInstance.getMany(args, ctx);
|
|
652
|
+
if (args.include)
|
|
653
|
+
await handleInclude(computedContext, args.include, result.nodes, ctx);
|
|
654
|
+
await handleComputed(computedContext, result.nodes, ctx);
|
|
655
|
+
await afterGet(result.nodes, args, ctx, computedContext);
|
|
656
|
+
return result;
|
|
662
657
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
await
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
await
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
658
|
+
async function putMany(docs, ctx) {
|
|
659
|
+
if (schema[key].decorators.precomputed)
|
|
660
|
+
throw new Error("Forbidden. Use events instead.");
|
|
661
|
+
const ids = docs.map((i) => {
|
|
662
|
+
if (!i?.id)
|
|
663
|
+
throw new Error("Id is required");
|
|
664
|
+
return i.id;
|
|
665
|
+
});
|
|
666
|
+
ctx = { ...options.context, ...ctx };
|
|
667
|
+
const oldDocs = await driverInstance.getAll({ where: { id_in: ids } }, ctx);
|
|
668
|
+
const oldDocsById = ___default.keyBy(oldDocs, "id");
|
|
669
|
+
const docArgsToSave = docs.map((doc) => {
|
|
670
|
+
const oldDoc = oldDocsById[doc.id];
|
|
671
|
+
doc = merge(oldDoc, doc);
|
|
672
|
+
if (mustCleanNulls)
|
|
673
|
+
cleanUndefinedAndNull(doc);
|
|
674
|
+
doc = validators[key](doc);
|
|
675
|
+
return { oldDoc, doc };
|
|
676
|
+
});
|
|
677
|
+
const docsToSave = docArgsToSave.map((x) => x.doc);
|
|
678
|
+
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
679
|
+
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
680
|
+
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
681
|
+
await beforePut(docArgsToSave, ctx, computedContext);
|
|
682
|
+
await driverInstance.putMany(docsToSave, ctx);
|
|
683
|
+
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
684
|
+
await afterPut(docArgsToSave, ctx, computedContext);
|
|
685
|
+
return docsToSave;
|
|
686
|
+
}
|
|
687
|
+
return {
|
|
688
|
+
getMany,
|
|
689
|
+
putMany,
|
|
690
|
+
driver: driverInstance,
|
|
691
|
+
getAgg: async (args, ctx) => {
|
|
692
|
+
args = { ...args, where: { ...args?.where } };
|
|
693
|
+
if (!args.agg)
|
|
694
|
+
throw new Error(`Please provide 'agg' argument`);
|
|
695
|
+
ctx = { ...options.context, ...ctx };
|
|
696
|
+
await beforeGet(args, ctx, computedContext);
|
|
697
|
+
const result = await driverInstance.getAgg(args, ctx);
|
|
698
|
+
return result;
|
|
699
|
+
},
|
|
700
|
+
get: async (args, ctx) => {
|
|
701
|
+
args = { ...args, where: { ...args?.where } };
|
|
702
|
+
ctx = { ...options.context, ...ctx };
|
|
703
|
+
await beforeGet(args, ctx, computedContext);
|
|
704
|
+
const result = await driverInstance.get(args, ctx);
|
|
705
|
+
const resultArray = [result];
|
|
706
|
+
if (result && args.include)
|
|
707
|
+
await handleInclude(computedContext, args.include, resultArray, ctx);
|
|
708
|
+
if (result)
|
|
709
|
+
await handleComputed(computedContext, resultArray, ctx);
|
|
710
|
+
await afterGet(resultArray, args, ctx, computedContext);
|
|
711
|
+
return result;
|
|
712
|
+
},
|
|
713
|
+
getAll: async (args, ctx) => {
|
|
714
|
+
args = { ...args, where: { ...args?.where } };
|
|
715
|
+
ctx = { ...options.context, ...ctx };
|
|
716
|
+
await beforeGet(args, ctx, computedContext);
|
|
717
|
+
const result = await driverInstance.getAll(args, ctx);
|
|
718
|
+
if (args.include)
|
|
719
|
+
await handleInclude(computedContext, args.include, result, ctx);
|
|
720
|
+
await handleComputed(computedContext, result, ctx);
|
|
721
|
+
await afterGet(result, args, ctx, computedContext);
|
|
722
|
+
return result;
|
|
723
|
+
},
|
|
724
|
+
put: async (doc, ctx) => {
|
|
725
|
+
if (schema[key].decorators.precomputed)
|
|
726
|
+
throw new Error("Forbidden. Use events instead.");
|
|
727
|
+
if (!doc?.id)
|
|
728
|
+
throw new Error("Id is required");
|
|
729
|
+
ctx = { ...options.context, ...ctx };
|
|
730
|
+
const oldDoc = await driverInstance.get({ where: { id: doc.id } }, ctx);
|
|
731
|
+
if (oldDoc)
|
|
732
|
+
doc = merge(oldDoc, doc);
|
|
733
|
+
if (mustCleanNulls)
|
|
734
|
+
cleanUndefinedAndNull(doc);
|
|
735
|
+
doc = validators[key](doc);
|
|
736
|
+
if (oldDoc && precomputedFields) {
|
|
737
|
+
for (const f of precomputedFields) {
|
|
738
|
+
___default.set(doc, f, ___default.get(oldDoc, f));
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const docArgsToSave = [{ doc, oldDoc }];
|
|
742
|
+
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
743
|
+
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
744
|
+
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
745
|
+
await beforePut(docArgsToSave, ctx, computedContext);
|
|
746
|
+
await driverInstance.put(doc, ctx);
|
|
747
|
+
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
748
|
+
await afterPut(docArgsToSave, ctx, computedContext);
|
|
749
|
+
return doc;
|
|
750
|
+
},
|
|
751
|
+
async verifyMany(args, ctx) {
|
|
752
|
+
ctx = { ...options.context, ...ctx };
|
|
753
|
+
if (args?.dryRun) {
|
|
754
|
+
ctx._logs = ctx._logs || [];
|
|
755
|
+
ctx.dryRun = true;
|
|
756
|
+
}
|
|
757
|
+
const { _logs } = ctx;
|
|
758
|
+
const { nodes, cursor } = await driverInstance.getMany(args, ctx);
|
|
759
|
+
let correctCount = 0;
|
|
760
|
+
let incorrectCount = 0;
|
|
761
|
+
const incorrectDocs = [];
|
|
762
|
+
const oldDocs = nodes;
|
|
763
|
+
const docArgsToSave = oldDocs.map((oldDoc) => {
|
|
764
|
+
let doc = merge(oldDoc, {});
|
|
765
|
+
if (args?.recompute) {
|
|
766
|
+
for (const p of args.recompute) {
|
|
767
|
+
delete doc[p];
|
|
768
|
+
}
|
|
769
|
+
}
|
|
737
770
|
if (mustCleanNulls)
|
|
738
771
|
cleanUndefinedAndNull(doc);
|
|
739
772
|
doc = validators[key](doc);
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
773
|
+
return { oldDoc, doc };
|
|
774
|
+
});
|
|
775
|
+
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
776
|
+
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
777
|
+
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
778
|
+
await beforePut(docArgsToSave, ctx, computedContext);
|
|
779
|
+
for (const { oldDoc, doc } of docArgsToSave) {
|
|
780
|
+
const d = diff(doc, oldDoc);
|
|
781
|
+
if (___default.isEmpty(d))
|
|
782
|
+
correctCount++;
|
|
783
|
+
else {
|
|
784
|
+
incorrectCount++;
|
|
785
|
+
const objToAdd = { id: doc.id, diff: d };
|
|
786
|
+
incorrectDocs.push(objToAdd);
|
|
744
787
|
}
|
|
745
|
-
const docArgsToSave = [{ doc, oldDoc }];
|
|
746
|
-
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
747
|
-
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
748
|
-
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
749
|
-
await beforePut(docArgsToSave, ctx, computedContext);
|
|
750
|
-
await driverInstance.put(doc, ctx);
|
|
751
|
-
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
752
|
-
await afterPut(docArgsToSave, ctx, computedContext);
|
|
753
|
-
return doc;
|
|
754
|
-
},
|
|
755
|
-
putMany: async (docs, ctx) => {
|
|
756
|
-
if (schema[key].decorators.precomputed)
|
|
757
|
-
throw new Error("Forbidden. Use events instead.");
|
|
758
|
-
const ids = docs.map((i) => {
|
|
759
|
-
if (!i?.id)
|
|
760
|
-
throw new Error("Id is required");
|
|
761
|
-
return i.id;
|
|
762
|
-
});
|
|
763
|
-
ctx = { ...opts.context, ...ctx };
|
|
764
|
-
const oldDocs = await driverInstance.getAll({ where: { id_in: ids } }, ctx);
|
|
765
|
-
const oldDocsById = ___default.keyBy(oldDocs, "id");
|
|
766
|
-
const docArgsToSave = docs.map((doc) => {
|
|
767
|
-
const oldDoc = oldDocsById[doc.id];
|
|
768
|
-
doc = merge(oldDoc, doc);
|
|
769
|
-
if (mustCleanNulls)
|
|
770
|
-
cleanUndefinedAndNull(doc);
|
|
771
|
-
doc = validators[key](doc);
|
|
772
|
-
return { oldDoc, doc };
|
|
773
|
-
});
|
|
774
|
-
const docsToSave = docArgsToSave.map((x) => x.doc);
|
|
775
|
-
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
776
|
-
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
777
|
-
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
778
|
-
await beforePut(docArgsToSave, ctx, computedContext);
|
|
779
|
-
await driverInstance.putMany(docsToSave, ctx);
|
|
780
|
-
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
781
|
-
await afterPut(docArgsToSave, ctx, computedContext);
|
|
782
|
-
return docsToSave;
|
|
783
|
-
},
|
|
784
|
-
clear: (ctx) => {
|
|
785
|
-
ctx = { ...opts.context, ...ctx };
|
|
786
|
-
return driverInstance.clear(ctx);
|
|
787
788
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
789
|
+
const docsToSave = docArgsToSave.map((x) => x.doc);
|
|
790
|
+
await driverInstance.putMany(docsToSave, ctx);
|
|
791
|
+
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
792
|
+
await afterPut(docArgsToSave, ctx, computedContext);
|
|
793
|
+
return { _logs, cursor, correctCount, incorrectCount, incorrectDocs };
|
|
794
|
+
},
|
|
795
|
+
clear: (ctx) => {
|
|
796
|
+
ctx = { ...options.context, ...ctx };
|
|
797
|
+
return driverInstance.clear(ctx);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
791
800
|
}
|
|
792
801
|
async function beforeGet(args, ctx, computedContext) {
|
|
793
802
|
for (const f of computedContext.options.features) {
|
|
@@ -864,6 +873,49 @@ function getExistingDriverInstance(entityName, drivers) {
|
|
|
864
873
|
}
|
|
865
874
|
return drivers[entityName];
|
|
866
875
|
}
|
|
876
|
+
|
|
877
|
+
function generateMethods(schema, validators, options) {
|
|
878
|
+
const drivers = {};
|
|
879
|
+
const opts = { computed: {}, driver: memory(), features: [], ...options };
|
|
880
|
+
const db = {
|
|
881
|
+
_schema: schema,
|
|
882
|
+
uploadFile(args) {
|
|
883
|
+
if (!opts.fileUploadDriver)
|
|
884
|
+
throw new Error(`Missing configuration. Please specify "fileUploadDriver" argument in "createRads()".`);
|
|
885
|
+
if (!args.containerName)
|
|
886
|
+
args.containerName = "files";
|
|
887
|
+
return opts.fileUploadDriver.uploadFile(args);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
const effects = {};
|
|
891
|
+
for (const key in schema) {
|
|
892
|
+
effects[key] = [];
|
|
893
|
+
}
|
|
894
|
+
if (!opts.skipComputed) {
|
|
895
|
+
verifyComputedPresense(schema, opts.computed);
|
|
896
|
+
}
|
|
897
|
+
verifyEventSourcingSetup(schema, effects);
|
|
898
|
+
verifyRelationsSetup(schema, effects);
|
|
899
|
+
for (const key in schema) {
|
|
900
|
+
if (!schema[key].decorators.entity)
|
|
901
|
+
continue;
|
|
902
|
+
const { handle } = schema[key];
|
|
903
|
+
if (!handle)
|
|
904
|
+
throw new Error(`Missing handle for entity ${key}`);
|
|
905
|
+
const computedContext = {
|
|
906
|
+
schema,
|
|
907
|
+
typeName: key,
|
|
908
|
+
validators,
|
|
909
|
+
options: opts,
|
|
910
|
+
drivers,
|
|
911
|
+
effects,
|
|
912
|
+
db
|
|
913
|
+
};
|
|
914
|
+
const driverInstance = getDriverInstance(schema, key, opts.driver, drivers);
|
|
915
|
+
db[handle] = getRadsDbMethods(key, computedContext, driverInstance);
|
|
916
|
+
}
|
|
917
|
+
return db;
|
|
918
|
+
}
|
|
867
919
|
function getDriverInstance(schema, key, driver, drivers) {
|
|
868
920
|
if (!drivers[key]) {
|
|
869
921
|
drivers[key] = getDriverInstanceInner(schema, key, driver);
|
|
@@ -872,6 +924,7 @@ function getDriverInstance(schema, key, driver, drivers) {
|
|
|
872
924
|
}
|
|
873
925
|
function getDriverInstanceInner(schema, key, driverConstructor) {
|
|
874
926
|
const driverInstance = driverConstructor(schema, key);
|
|
927
|
+
addDryRunSupport(driverInstance, key);
|
|
875
928
|
async function getAll(args, ctx) {
|
|
876
929
|
const result = [];
|
|
877
930
|
let cursor = args.cursor;
|
|
@@ -914,6 +967,40 @@ function getDriverInstanceInner(schema, key, driverConstructor) {
|
|
|
914
967
|
...driverInstance
|
|
915
968
|
};
|
|
916
969
|
}
|
|
970
|
+
function addDryRunSupport(driverInstance, entity) {
|
|
971
|
+
const { clear, put, putMany } = driverInstance;
|
|
972
|
+
if (clear) {
|
|
973
|
+
driverInstance.clear = (ctx) => {
|
|
974
|
+
if (ctx?.dryRun) {
|
|
975
|
+
if (!ctx._logs)
|
|
976
|
+
ctx._logs = [];
|
|
977
|
+
ctx._logs.push({ method: "clear", entity });
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
return clear(ctx);
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
if (put) {
|
|
984
|
+
driverInstance.put = (data, ctx) => {
|
|
985
|
+
if (ctx?.dryRun) {
|
|
986
|
+
if (!ctx._logs)
|
|
987
|
+
ctx._logs = [];
|
|
988
|
+
ctx._logs.push({ method: "put", entity, data });
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
return put(data, ctx);
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
driverInstance.putMany = (data, ctx) => {
|
|
995
|
+
if (ctx?.dryRun) {
|
|
996
|
+
if (!ctx._logs)
|
|
997
|
+
ctx._logs = [];
|
|
998
|
+
ctx._logs.push({ method: "putMany", entity, data });
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
return putMany(data, ctx);
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
917
1004
|
|
|
918
1005
|
function entity(meta) {
|
|
919
1006
|
return function(classConstructor, _ctx) {
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,20 @@ interface GetManyArgs<E, EN extends keyof EntityMeta, W> extends GetArgs<E, EN,
|
|
|
10
10
|
maxItemCount?: number;
|
|
11
11
|
orderBy?: string;
|
|
12
12
|
}
|
|
13
|
+
interface VerifyManyArgs<E, EN extends keyof EntityMeta, W> extends GetManyArgs<E, EN, W> {
|
|
14
|
+
recompute?: string[];
|
|
15
|
+
dryRun?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface VerifyManyResponse {
|
|
18
|
+
cursor: string | null;
|
|
19
|
+
correctCount: number;
|
|
20
|
+
incorrectCount: number;
|
|
21
|
+
incorrectDocs: {
|
|
22
|
+
id: string;
|
|
23
|
+
diff: any;
|
|
24
|
+
toRemove?: any;
|
|
25
|
+
}[];
|
|
26
|
+
}
|
|
13
27
|
interface GetArgs<E, EN extends keyof EntityMeta, W> {
|
|
14
28
|
where?: W;
|
|
15
29
|
include?: GetArgsInclude<E, EN>;
|
|
@@ -22,6 +36,7 @@ type GetAggArgsAgg<EN extends keyof EntityMeta, F extends string = EntityMeta[EN
|
|
|
22
36
|
type GetManyArgsAny = GetManyArgs<any, any, any>;
|
|
23
37
|
type GetArgsAny = GetArgs<any, any, any>;
|
|
24
38
|
type GetAggArgsAny = GetAggArgs<any, any>;
|
|
39
|
+
type VerifyManyArgsAny = VerifyManyArgs<any, any, any>;
|
|
25
40
|
type GetArgsInclude<E, EN extends keyof EntityMeta, R extends keyof E = keyof EntityMeta[EN]['relations'] & keyof E> = [R] extends [never] ? Record<string, never> : {
|
|
26
41
|
_pick?: EntityMeta[EN]['primitives'][];
|
|
27
42
|
} & {
|
|
@@ -61,12 +76,16 @@ type PutArgs<T> = {
|
|
|
61
76
|
} & DeepPartialNullable<T>;
|
|
62
77
|
interface EntityMethods<E, EN extends keyof EntityMeta, W> {
|
|
63
78
|
createObject(defaultValues: Partial<E>): E;
|
|
79
|
+
/** Used to access underlying mechanism of storage directly.
|
|
80
|
+
* Warning: bypasses all rads features - schema won't be validated, default values won't be filled, etc. */
|
|
81
|
+
driver: Driver;
|
|
64
82
|
get<A extends GetArgs<E, EN, W>>(args: A): MaybePromise$1<GetResponse<E, EN, A>>;
|
|
65
83
|
getMany<A extends GetManyArgs<E, EN, W>>(args?: A): MaybePromise$1<GetManyResponse<E, EN, A>>;
|
|
66
84
|
getAgg<A extends GetAggArgs<EN, W>>(args: A): MaybePromise$1<GetAggResponse<EN, A>>;
|
|
67
85
|
getAll<A extends GetManyArgs<E, EN, W>>(args?: A): MaybePromise$1<GetManyResponse<E, EN, A>['nodes']>;
|
|
68
86
|
put(data: PutArgs<E>): MaybePromise$1<GetResponseNoInclude<E, EN>>;
|
|
69
87
|
putMany(data: PutArgs<E>[]): MaybePromise$1<GetResponseNoInclude<E, EN>[]>;
|
|
88
|
+
verifyMany<A extends VerifyManyArgs<E, EN, W>>(args?: A): MaybePromise$1<VerifyManyResponse>;
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
type MaybePromise<T> = Promise<T> | T;
|
|
@@ -142,7 +161,7 @@ interface CreateRadsArgs {
|
|
|
142
161
|
skipComputed?: boolean;
|
|
143
162
|
computed?: Record<string, Record<string, Function>>;
|
|
144
163
|
beforeGet?: (args: GetArgsAny, ctx: RadsRequestContext, context: ComputedContext) => MaybePromise<void>;
|
|
145
|
-
context?: Record<string, any> & RadsRequestContext
|
|
164
|
+
context?: Record<string, any> & Omit<RadsRequestContext, 'dryRun' | 'silent'>;
|
|
146
165
|
features?: RadsFeature[];
|
|
147
166
|
}
|
|
148
167
|
type Schema = Record<string, TypeDefinition>;
|
|
@@ -253,11 +272,16 @@ interface RadsVitePluginOptions extends GenerateClientOptions {
|
|
|
253
272
|
exposeModulesInDev?: boolean | RegExp;
|
|
254
273
|
}
|
|
255
274
|
interface RadsRequestContext {
|
|
275
|
+
_logs?: any[];
|
|
256
276
|
log?: (requestInfo: any) => void;
|
|
257
277
|
getUser?: () => {
|
|
258
278
|
id: string;
|
|
259
279
|
role: string;
|
|
260
280
|
} | undefined;
|
|
281
|
+
/** If true, no changes made to the database - instead, all changes are returned as logs */
|
|
282
|
+
dryRun?: boolean;
|
|
283
|
+
/** (Not supported yet) If true, updatedAt/updatedBy properties are not updated, and log records are not created */
|
|
284
|
+
silent?: boolean;
|
|
261
285
|
}
|
|
262
286
|
interface GithubTreeResponse {
|
|
263
287
|
sha: string;
|
|
@@ -295,4 +319,4 @@ declare function computed(meta?: ComputedDecoratorArgs): (a: any, b?: ClassField
|
|
|
295
319
|
|
|
296
320
|
declare function createRads(args?: CreateRadsArgs): RadsDb;
|
|
297
321
|
|
|
298
|
-
export { Change, ComputedContext, ComputedDecoratorArgs, CreateRadsArgs, DeepPartial, DeepPartialNullable, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, FieldDecoratorArgs, FieldDefinition, FileUploadArgs, FileUploadDriver, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, GithubTreeItem, GithubTreeResponse, MinimalDriver, PutArgs, PutEffect, RadsFeature, RadsRequestContext, RadsVitePluginOptions, Relation, RestFileUploadDriverOptions, Schema, SchemaValidators, TypeDefinition, UiDecoratorArgs, UiFieldDecoratorArgs, ValidateEntityDecoratorArgs, ValidateFieldDecoratorArgs, ValidateStringDecoratorArgs, computed, createRads, entity, field, precomputed, ui, validate };
|
|
322
|
+
export { Change, ComputedContext, ComputedDecoratorArgs, CreateRadsArgs, DeepPartial, DeepPartialNullable, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, FieldDecoratorArgs, FieldDefinition, FileUploadArgs, FileUploadDriver, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, GithubTreeItem, GithubTreeResponse, MinimalDriver, PutArgs, PutEffect, RadsFeature, RadsRequestContext, RadsVitePluginOptions, Relation, RestFileUploadDriverOptions, Schema, SchemaValidators, TypeDefinition, UiDecoratorArgs, UiFieldDecoratorArgs, ValidateEntityDecoratorArgs, ValidateFieldDecoratorArgs, ValidateStringDecoratorArgs, VerifyManyArgs, VerifyManyArgsAny, VerifyManyResponse, computed, createRads, entity, field, precomputed, ui, validate };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import createMerge from '@fastify/deepmerge';
|
|
4
3
|
import { v4 } from 'uuid';
|
|
4
|
+
import createMerge from '@fastify/deepmerge';
|
|
5
5
|
import { schema } from '_rads-db';
|
|
6
6
|
|
|
7
7
|
function generateValidators(schema) {
|
|
@@ -91,42 +91,6 @@ function getFieldZodSchemaBase(zodSchemas, schema, field, shouldBeLazy) {
|
|
|
91
91
|
throw new Error(`Unknown type: ${field.type}`);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
const mergeFn = createMerge({
|
|
95
|
-
mergeArray(options) {
|
|
96
|
-
const clone = options.clone;
|
|
97
|
-
return function(target, source) {
|
|
98
|
-
return clone(source);
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
function merge(target, source) {
|
|
103
|
-
cleanUndefined(source);
|
|
104
|
-
const result = mergeFn(target, source);
|
|
105
|
-
return result;
|
|
106
|
-
}
|
|
107
|
-
function cleanUndefined(obj) {
|
|
108
|
-
if (!obj || !_.isPlainObject(obj))
|
|
109
|
-
return;
|
|
110
|
-
cleanUndefinedInner(obj);
|
|
111
|
-
}
|
|
112
|
-
function cleanUndefinedInner(obj) {
|
|
113
|
-
for (const key in obj) {
|
|
114
|
-
if (obj[key] === void 0)
|
|
115
|
-
delete obj[key];
|
|
116
|
-
if (_.isPlainObject(obj[key]))
|
|
117
|
-
cleanUndefinedInner(obj[key]);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function cleanUndefinedAndNull(obj) {
|
|
122
|
-
for (const key in obj) {
|
|
123
|
-
if (obj[key] == null)
|
|
124
|
-
delete obj[key];
|
|
125
|
-
if (_.isPlainObject(obj[key]))
|
|
126
|
-
cleanUndefinedAndNull(obj[key]);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
94
|
const operatorFns = {
|
|
131
95
|
eq: (x, w) => x === w,
|
|
132
96
|
ieq: (x, w) => x?.toLowerCase() === w?.toLowerCase(),
|
|
@@ -439,6 +403,33 @@ async function handleEffectsAfterPut(context, docs, beforePutResults, ctx) {
|
|
|
439
403
|
);
|
|
440
404
|
}
|
|
441
405
|
|
|
406
|
+
const mergeFn = createMerge({
|
|
407
|
+
mergeArray(options) {
|
|
408
|
+
const clone = options.clone;
|
|
409
|
+
return function(target, source) {
|
|
410
|
+
return clone(source);
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
function merge(target, source) {
|
|
415
|
+
cleanUndefined(source);
|
|
416
|
+
const result = mergeFn(target, source);
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
function cleanUndefined(obj) {
|
|
420
|
+
if (!obj || !_.isPlainObject(obj))
|
|
421
|
+
return;
|
|
422
|
+
cleanUndefinedInner(obj);
|
|
423
|
+
}
|
|
424
|
+
function cleanUndefinedInner(obj) {
|
|
425
|
+
for (const key in obj) {
|
|
426
|
+
if (obj[key] === void 0)
|
|
427
|
+
delete obj[key];
|
|
428
|
+
if (_.isPlainObject(obj[key]))
|
|
429
|
+
cleanUndefinedInner(obj[key]);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
442
433
|
function diff(object, base, includeDenormFields = false) {
|
|
443
434
|
if (!base)
|
|
444
435
|
return object;
|
|
@@ -633,154 +624,172 @@ async function fillDenormFieldsBeforePut(computedContext, docUpdates, ctx) {
|
|
|
633
624
|
await Promise.all(promises);
|
|
634
625
|
}
|
|
635
626
|
|
|
636
|
-
function
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
if (!opts.fileUploadDriver)
|
|
643
|
-
throw new Error(`Missing configuration. Please specify "fileUploadDriver" argument in "createRads()".`);
|
|
644
|
-
if (!args.containerName)
|
|
645
|
-
args.containerName = "files";
|
|
646
|
-
return opts.fileUploadDriver.uploadFile(args);
|
|
647
|
-
}
|
|
648
|
-
};
|
|
649
|
-
const effects = {};
|
|
650
|
-
for (const key in schema) {
|
|
651
|
-
effects[key] = [];
|
|
627
|
+
function cleanUndefinedAndNull(obj) {
|
|
628
|
+
for (const key in obj) {
|
|
629
|
+
if (obj[key] == null)
|
|
630
|
+
delete obj[key];
|
|
631
|
+
if (_.isPlainObject(obj[key]))
|
|
632
|
+
cleanUndefinedAndNull(obj[key]);
|
|
652
633
|
}
|
|
653
|
-
|
|
654
|
-
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
637
|
+
const { schema, options, validators } = computedContext;
|
|
638
|
+
const mustCleanNulls = driverInstance.driverName !== "restApi";
|
|
639
|
+
const { precomputedFields } = schema[key];
|
|
640
|
+
async function getMany(args, ctx) {
|
|
641
|
+
args = { ...args, where: { ...args?.where } };
|
|
642
|
+
ctx = { ...options.context, ...ctx };
|
|
643
|
+
await beforeGet(args, ctx, computedContext);
|
|
644
|
+
const result = await driverInstance.getMany(args, ctx);
|
|
645
|
+
if (args.include)
|
|
646
|
+
await handleInclude(computedContext, args.include, result.nodes, ctx);
|
|
647
|
+
await handleComputed(computedContext, result.nodes, ctx);
|
|
648
|
+
await afterGet(result.nodes, args, ctx, computedContext);
|
|
649
|
+
return result;
|
|
655
650
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
await
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
await
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
651
|
+
async function putMany(docs, ctx) {
|
|
652
|
+
if (schema[key].decorators.precomputed)
|
|
653
|
+
throw new Error("Forbidden. Use events instead.");
|
|
654
|
+
const ids = docs.map((i) => {
|
|
655
|
+
if (!i?.id)
|
|
656
|
+
throw new Error("Id is required");
|
|
657
|
+
return i.id;
|
|
658
|
+
});
|
|
659
|
+
ctx = { ...options.context, ...ctx };
|
|
660
|
+
const oldDocs = await driverInstance.getAll({ where: { id_in: ids } }, ctx);
|
|
661
|
+
const oldDocsById = _.keyBy(oldDocs, "id");
|
|
662
|
+
const docArgsToSave = docs.map((doc) => {
|
|
663
|
+
const oldDoc = oldDocsById[doc.id];
|
|
664
|
+
doc = merge(oldDoc, doc);
|
|
665
|
+
if (mustCleanNulls)
|
|
666
|
+
cleanUndefinedAndNull(doc);
|
|
667
|
+
doc = validators[key](doc);
|
|
668
|
+
return { oldDoc, doc };
|
|
669
|
+
});
|
|
670
|
+
const docsToSave = docArgsToSave.map((x) => x.doc);
|
|
671
|
+
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
672
|
+
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
673
|
+
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
674
|
+
await beforePut(docArgsToSave, ctx, computedContext);
|
|
675
|
+
await driverInstance.putMany(docsToSave, ctx);
|
|
676
|
+
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
677
|
+
await afterPut(docArgsToSave, ctx, computedContext);
|
|
678
|
+
return docsToSave;
|
|
679
|
+
}
|
|
680
|
+
return {
|
|
681
|
+
getMany,
|
|
682
|
+
putMany,
|
|
683
|
+
driver: driverInstance,
|
|
684
|
+
getAgg: async (args, ctx) => {
|
|
685
|
+
args = { ...args, where: { ...args?.where } };
|
|
686
|
+
if (!args.agg)
|
|
687
|
+
throw new Error(`Please provide 'agg' argument`);
|
|
688
|
+
ctx = { ...options.context, ...ctx };
|
|
689
|
+
await beforeGet(args, ctx, computedContext);
|
|
690
|
+
const result = await driverInstance.getAgg(args, ctx);
|
|
691
|
+
return result;
|
|
692
|
+
},
|
|
693
|
+
get: async (args, ctx) => {
|
|
694
|
+
args = { ...args, where: { ...args?.where } };
|
|
695
|
+
ctx = { ...options.context, ...ctx };
|
|
696
|
+
await beforeGet(args, ctx, computedContext);
|
|
697
|
+
const result = await driverInstance.get(args, ctx);
|
|
698
|
+
const resultArray = [result];
|
|
699
|
+
if (result && args.include)
|
|
700
|
+
await handleInclude(computedContext, args.include, resultArray, ctx);
|
|
701
|
+
if (result)
|
|
702
|
+
await handleComputed(computedContext, resultArray, ctx);
|
|
703
|
+
await afterGet(resultArray, args, ctx, computedContext);
|
|
704
|
+
return result;
|
|
705
|
+
},
|
|
706
|
+
getAll: async (args, ctx) => {
|
|
707
|
+
args = { ...args, where: { ...args?.where } };
|
|
708
|
+
ctx = { ...options.context, ...ctx };
|
|
709
|
+
await beforeGet(args, ctx, computedContext);
|
|
710
|
+
const result = await driverInstance.getAll(args, ctx);
|
|
711
|
+
if (args.include)
|
|
712
|
+
await handleInclude(computedContext, args.include, result, ctx);
|
|
713
|
+
await handleComputed(computedContext, result, ctx);
|
|
714
|
+
await afterGet(result, args, ctx, computedContext);
|
|
715
|
+
return result;
|
|
716
|
+
},
|
|
717
|
+
put: async (doc, ctx) => {
|
|
718
|
+
if (schema[key].decorators.precomputed)
|
|
719
|
+
throw new Error("Forbidden. Use events instead.");
|
|
720
|
+
if (!doc?.id)
|
|
721
|
+
throw new Error("Id is required");
|
|
722
|
+
ctx = { ...options.context, ...ctx };
|
|
723
|
+
const oldDoc = await driverInstance.get({ where: { id: doc.id } }, ctx);
|
|
724
|
+
if (oldDoc)
|
|
725
|
+
doc = merge(oldDoc, doc);
|
|
726
|
+
if (mustCleanNulls)
|
|
727
|
+
cleanUndefinedAndNull(doc);
|
|
728
|
+
doc = validators[key](doc);
|
|
729
|
+
if (oldDoc && precomputedFields) {
|
|
730
|
+
for (const f of precomputedFields) {
|
|
731
|
+
_.set(doc, f, _.get(oldDoc, f));
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const docArgsToSave = [{ doc, oldDoc }];
|
|
735
|
+
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
736
|
+
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
737
|
+
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
738
|
+
await beforePut(docArgsToSave, ctx, computedContext);
|
|
739
|
+
await driverInstance.put(doc, ctx);
|
|
740
|
+
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
741
|
+
await afterPut(docArgsToSave, ctx, computedContext);
|
|
742
|
+
return doc;
|
|
743
|
+
},
|
|
744
|
+
async verifyMany(args, ctx) {
|
|
745
|
+
ctx = { ...options.context, ...ctx };
|
|
746
|
+
if (args?.dryRun) {
|
|
747
|
+
ctx._logs = ctx._logs || [];
|
|
748
|
+
ctx.dryRun = true;
|
|
749
|
+
}
|
|
750
|
+
const { _logs } = ctx;
|
|
751
|
+
const { nodes, cursor } = await driverInstance.getMany(args, ctx);
|
|
752
|
+
let correctCount = 0;
|
|
753
|
+
let incorrectCount = 0;
|
|
754
|
+
const incorrectDocs = [];
|
|
755
|
+
const oldDocs = nodes;
|
|
756
|
+
const docArgsToSave = oldDocs.map((oldDoc) => {
|
|
757
|
+
let doc = merge(oldDoc, {});
|
|
758
|
+
if (args?.recompute) {
|
|
759
|
+
for (const p of args.recompute) {
|
|
760
|
+
delete doc[p];
|
|
761
|
+
}
|
|
762
|
+
}
|
|
730
763
|
if (mustCleanNulls)
|
|
731
764
|
cleanUndefinedAndNull(doc);
|
|
732
765
|
doc = validators[key](doc);
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
766
|
+
return { oldDoc, doc };
|
|
767
|
+
});
|
|
768
|
+
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
769
|
+
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
770
|
+
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
771
|
+
await beforePut(docArgsToSave, ctx, computedContext);
|
|
772
|
+
for (const { oldDoc, doc } of docArgsToSave) {
|
|
773
|
+
const d = diff(doc, oldDoc);
|
|
774
|
+
if (_.isEmpty(d))
|
|
775
|
+
correctCount++;
|
|
776
|
+
else {
|
|
777
|
+
incorrectCount++;
|
|
778
|
+
const objToAdd = { id: doc.id, diff: d };
|
|
779
|
+
incorrectDocs.push(objToAdd);
|
|
737
780
|
}
|
|
738
|
-
const docArgsToSave = [{ doc, oldDoc }];
|
|
739
|
-
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
740
|
-
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
741
|
-
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
742
|
-
await beforePut(docArgsToSave, ctx, computedContext);
|
|
743
|
-
await driverInstance.put(doc, ctx);
|
|
744
|
-
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
745
|
-
await afterPut(docArgsToSave, ctx, computedContext);
|
|
746
|
-
return doc;
|
|
747
|
-
},
|
|
748
|
-
putMany: async (docs, ctx) => {
|
|
749
|
-
if (schema[key].decorators.precomputed)
|
|
750
|
-
throw new Error("Forbidden. Use events instead.");
|
|
751
|
-
const ids = docs.map((i) => {
|
|
752
|
-
if (!i?.id)
|
|
753
|
-
throw new Error("Id is required");
|
|
754
|
-
return i.id;
|
|
755
|
-
});
|
|
756
|
-
ctx = { ...opts.context, ...ctx };
|
|
757
|
-
const oldDocs = await driverInstance.getAll({ where: { id_in: ids } }, ctx);
|
|
758
|
-
const oldDocsById = _.keyBy(oldDocs, "id");
|
|
759
|
-
const docArgsToSave = docs.map((doc) => {
|
|
760
|
-
const oldDoc = oldDocsById[doc.id];
|
|
761
|
-
doc = merge(oldDoc, doc);
|
|
762
|
-
if (mustCleanNulls)
|
|
763
|
-
cleanUndefinedAndNull(doc);
|
|
764
|
-
doc = validators[key](doc);
|
|
765
|
-
return { oldDoc, doc };
|
|
766
|
-
});
|
|
767
|
-
const docsToSave = docArgsToSave.map((x) => x.doc);
|
|
768
|
-
await fillDenormFieldsBeforePut(computedContext, docArgsToSave, ctx);
|
|
769
|
-
await handlePrecomputed(computedContext, docArgsToSave, ctx);
|
|
770
|
-
const beforePutResults = await handleEffectsBeforePut(computedContext, docArgsToSave, ctx);
|
|
771
|
-
await beforePut(docArgsToSave, ctx, computedContext);
|
|
772
|
-
await driverInstance.putMany(docsToSave, ctx);
|
|
773
|
-
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
774
|
-
await afterPut(docArgsToSave, ctx, computedContext);
|
|
775
|
-
return docsToSave;
|
|
776
|
-
},
|
|
777
|
-
clear: (ctx) => {
|
|
778
|
-
ctx = { ...opts.context, ...ctx };
|
|
779
|
-
return driverInstance.clear(ctx);
|
|
780
781
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
782
|
+
const docsToSave = docArgsToSave.map((x) => x.doc);
|
|
783
|
+
await driverInstance.putMany(docsToSave, ctx);
|
|
784
|
+
await handleEffectsAfterPut(computedContext, docArgsToSave, beforePutResults, ctx);
|
|
785
|
+
await afterPut(docArgsToSave, ctx, computedContext);
|
|
786
|
+
return { _logs, cursor, correctCount, incorrectCount, incorrectDocs };
|
|
787
|
+
},
|
|
788
|
+
clear: (ctx) => {
|
|
789
|
+
ctx = { ...options.context, ...ctx };
|
|
790
|
+
return driverInstance.clear(ctx);
|
|
791
|
+
}
|
|
792
|
+
};
|
|
784
793
|
}
|
|
785
794
|
async function beforeGet(args, ctx, computedContext) {
|
|
786
795
|
for (const f of computedContext.options.features) {
|
|
@@ -857,6 +866,49 @@ function getExistingDriverInstance(entityName, drivers) {
|
|
|
857
866
|
}
|
|
858
867
|
return drivers[entityName];
|
|
859
868
|
}
|
|
869
|
+
|
|
870
|
+
function generateMethods(schema, validators, options) {
|
|
871
|
+
const drivers = {};
|
|
872
|
+
const opts = { computed: {}, driver: memory(), features: [], ...options };
|
|
873
|
+
const db = {
|
|
874
|
+
_schema: schema,
|
|
875
|
+
uploadFile(args) {
|
|
876
|
+
if (!opts.fileUploadDriver)
|
|
877
|
+
throw new Error(`Missing configuration. Please specify "fileUploadDriver" argument in "createRads()".`);
|
|
878
|
+
if (!args.containerName)
|
|
879
|
+
args.containerName = "files";
|
|
880
|
+
return opts.fileUploadDriver.uploadFile(args);
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
const effects = {};
|
|
884
|
+
for (const key in schema) {
|
|
885
|
+
effects[key] = [];
|
|
886
|
+
}
|
|
887
|
+
if (!opts.skipComputed) {
|
|
888
|
+
verifyComputedPresense(schema, opts.computed);
|
|
889
|
+
}
|
|
890
|
+
verifyEventSourcingSetup(schema, effects);
|
|
891
|
+
verifyRelationsSetup(schema, effects);
|
|
892
|
+
for (const key in schema) {
|
|
893
|
+
if (!schema[key].decorators.entity)
|
|
894
|
+
continue;
|
|
895
|
+
const { handle } = schema[key];
|
|
896
|
+
if (!handle)
|
|
897
|
+
throw new Error(`Missing handle for entity ${key}`);
|
|
898
|
+
const computedContext = {
|
|
899
|
+
schema,
|
|
900
|
+
typeName: key,
|
|
901
|
+
validators,
|
|
902
|
+
options: opts,
|
|
903
|
+
drivers,
|
|
904
|
+
effects,
|
|
905
|
+
db
|
|
906
|
+
};
|
|
907
|
+
const driverInstance = getDriverInstance(schema, key, opts.driver, drivers);
|
|
908
|
+
db[handle] = getRadsDbMethods(key, computedContext, driverInstance);
|
|
909
|
+
}
|
|
910
|
+
return db;
|
|
911
|
+
}
|
|
860
912
|
function getDriverInstance(schema, key, driver, drivers) {
|
|
861
913
|
if (!drivers[key]) {
|
|
862
914
|
drivers[key] = getDriverInstanceInner(schema, key, driver);
|
|
@@ -865,6 +917,7 @@ function getDriverInstance(schema, key, driver, drivers) {
|
|
|
865
917
|
}
|
|
866
918
|
function getDriverInstanceInner(schema, key, driverConstructor) {
|
|
867
919
|
const driverInstance = driverConstructor(schema, key);
|
|
920
|
+
addDryRunSupport(driverInstance, key);
|
|
868
921
|
async function getAll(args, ctx) {
|
|
869
922
|
const result = [];
|
|
870
923
|
let cursor = args.cursor;
|
|
@@ -907,6 +960,40 @@ function getDriverInstanceInner(schema, key, driverConstructor) {
|
|
|
907
960
|
...driverInstance
|
|
908
961
|
};
|
|
909
962
|
}
|
|
963
|
+
function addDryRunSupport(driverInstance, entity) {
|
|
964
|
+
const { clear, put, putMany } = driverInstance;
|
|
965
|
+
if (clear) {
|
|
966
|
+
driverInstance.clear = (ctx) => {
|
|
967
|
+
if (ctx?.dryRun) {
|
|
968
|
+
if (!ctx._logs)
|
|
969
|
+
ctx._logs = [];
|
|
970
|
+
ctx._logs.push({ method: "clear", entity });
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
return clear(ctx);
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
if (put) {
|
|
977
|
+
driverInstance.put = (data, ctx) => {
|
|
978
|
+
if (ctx?.dryRun) {
|
|
979
|
+
if (!ctx._logs)
|
|
980
|
+
ctx._logs = [];
|
|
981
|
+
ctx._logs.push({ method: "put", entity, data });
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
return put(data, ctx);
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
driverInstance.putMany = (data, ctx) => {
|
|
988
|
+
if (ctx?.dryRun) {
|
|
989
|
+
if (!ctx._logs)
|
|
990
|
+
ctx._logs = [];
|
|
991
|
+
ctx._logs.push({ method: "putMany", entity, data });
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
return putMany(data, ctx);
|
|
995
|
+
};
|
|
996
|
+
}
|
|
910
997
|
|
|
911
998
|
function entity(meta) {
|
|
912
999
|
return function(classConstructor, _ctx) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
module.exports = void 0;
|
|
7
|
+
var _default = () => {
|
|
8
|
+
return {
|
|
9
|
+
name: "softDelete",
|
|
10
|
+
beforeGet(args, ctx, context) {
|
|
11
|
+
if (!context.schema[context.typeName]?.fields?.isDeleted) return;
|
|
12
|
+
if (args.where.isDeleted || args.where.isDeleted_in) return;
|
|
13
|
+
args.where._and = [...(args.where._and || []), {
|
|
14
|
+
isDeleted: false
|
|
15
|
+
}];
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
module.exports = _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default () => {
|
|
2
|
+
return {
|
|
3
|
+
name: "softDelete",
|
|
4
|
+
beforeGet(args, ctx, context) {
|
|
5
|
+
if (!context.schema[context.typeName]?.fields?.isDeleted)
|
|
6
|
+
return;
|
|
7
|
+
if (args.where.isDeleted || args.where.isDeleted_in)
|
|
8
|
+
return;
|
|
9
|
+
args.where._and = [...args.where._and || [], { isDeleted: false }];
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
};
|
package/package.json
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
"dist",
|
|
5
5
|
"drivers",
|
|
6
6
|
"fileUploadDrivers",
|
|
7
|
-
"integrations"
|
|
7
|
+
"integrations",
|
|
8
|
+
"features"
|
|
8
9
|
],
|
|
9
10
|
"bin": {
|
|
10
11
|
"rads-db": "integrations/cli.cjs"
|
|
@@ -32,9 +33,14 @@
|
|
|
32
33
|
"types": "./integrations/*.d.ts",
|
|
33
34
|
"import": "./integrations/*.mjs",
|
|
34
35
|
"require": "./integrations/*.cjs"
|
|
36
|
+
},
|
|
37
|
+
"./features/*": {
|
|
38
|
+
"types": "./features/*.d.ts",
|
|
39
|
+
"import": "./features/*.mjs",
|
|
40
|
+
"require": "./features/*.cjs"
|
|
35
41
|
}
|
|
36
42
|
},
|
|
37
|
-
"version": "0.1.
|
|
43
|
+
"version": "0.1.74",
|
|
38
44
|
"description": "Say goodbye to boilerplate code and hello to efficient and elegant syntax.",
|
|
39
45
|
"keywords": [],
|
|
40
46
|
"author": "",
|