rads-db 0.1.92 → 0.1.94

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 CHANGED
@@ -131,23 +131,26 @@ const operatorFns = {
131
131
  }
132
132
  };
133
133
  const memory = (options) => (schema, entity) => {
134
- let cache = {};
134
+ let itemsById = {};
135
135
  function getItemById(id) {
136
- return cache[id] ?? null;
136
+ return itemsById[id] ?? null;
137
137
  }
138
138
  function getItemByIds(ids) {
139
- return ids.map((id) => cache[id]);
139
+ return ids.map((id) => itemsById[id]);
140
140
  }
141
141
  const instance = {
142
142
  driverName: "memory",
143
+ get itemsById() {
144
+ return itemsById;
145
+ },
143
146
  clear() {
144
- cache = {};
147
+ itemsById = {};
145
148
  },
146
149
  putMany(items) {
147
150
  for (const item of items) {
148
151
  if (!item?.id)
149
152
  throw new Error(`You must provide an id`);
150
- cache[item.id] = item;
153
+ itemsById[item.id] = item;
151
154
  }
152
155
  },
153
156
  getMany(args) {
@@ -160,7 +163,7 @@ const memory = (options) => (schema, entity) => {
160
163
  if (whereKeys[0] === "id_in")
161
164
  return { nodes: ___default.cloneDeep(getItemByIds(where.id_in).filter((x) => x)), cursor: null };
162
165
  }
163
- return queryArray(Object.values(cache), args);
166
+ return queryArray(Object.values(itemsById), args);
164
167
  }
165
168
  };
166
169
  return instance;
@@ -267,7 +270,7 @@ function getFilterInner(operator, whereVal, name, namePrefix) {
267
270
  if (operatorFn) {
268
271
  return (x) => operatorFn(___default.get(x, name), whereVal);
269
272
  }
270
- console.warn(`[rads-cache] Operator not supported: ${operator || "eq"}`);
273
+ console.warn(`[rads-db] Operator not supported: ${operator || "eq"}`);
271
274
  return null;
272
275
  }
273
276
  function prepareArgs(args) {
@@ -705,14 +708,15 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
705
708
  const { precomputedFields } = schema[key];
706
709
  async function getMany(args, ctx) {
707
710
  args = { ...args, where: { ...args?.where } };
708
- ctx = { ...options.context, ...ctx };
709
- await beforeGet(args, ctx, computedContext);
710
- const result = await driverInstance.getMany(args, ctx);
711
+ ctx = { ...options.context, ...ctx, method: "getMany" };
712
+ let result2 = await beforeGet(args, ctx, computedContext);
713
+ if (!result2)
714
+ result2 = await driverInstance.getMany(args, ctx);
711
715
  if (args.include)
712
- await handleInclude(computedContext, args.include, result.nodes, ctx);
713
- await handleComputed(computedContext, result.nodes, ctx);
714
- await afterGet(result.nodes, args, ctx, computedContext);
715
- return result;
716
+ await handleInclude(computedContext, args.include, result2.nodes, ctx);
717
+ await handleComputed(computedContext, result2.nodes, ctx);
718
+ await afterGet(result2.nodes, args, ctx, computedContext);
719
+ return result2;
716
720
  }
717
721
  async function putMany(docs, ctx) {
718
722
  const precomputed = schema[key].decorators.precomputed;
@@ -726,7 +730,7 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
726
730
  throw new Error("Id is required");
727
731
  return i.id;
728
732
  });
729
- ctx = { ...options.context, ...ctx };
733
+ ctx = { ...options.context, ...ctx, method: "putMany" };
730
734
  const oldDocs = await driverInstance.getAll({ where: { id_in: ids } }, ctx);
731
735
  const oldDocsById = ___default.keyBy(oldDocs, "id");
732
736
  const docArgsToSave = docs.map((doc) => {
@@ -753,7 +757,10 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
753
757
  await afterPut(docArgsToSave, ctx, computedContext);
754
758
  return docsToSave;
755
759
  }
756
- return {
760
+ const result = {
761
+ createObject() {
762
+ throw new Error("Not implemented");
763
+ },
757
764
  getMany,
758
765
  putMany,
759
766
  driver: driverInstance,
@@ -761,34 +768,37 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
761
768
  args = { ...args, where: { ...args?.where } };
762
769
  if (!args.agg)
763
770
  throw new Error(`Please provide 'agg' argument`);
764
- ctx = { ...options.context, ...ctx };
765
- await beforeGet(args, ctx, computedContext);
766
- const result = await driverInstance.getAgg(args, ctx);
767
- return result;
771
+ ctx = { ...options.context, ...ctx, method: "getAgg" };
772
+ let result2 = await beforeGet(args, ctx, computedContext);
773
+ if (!result2)
774
+ result2 = await driverInstance.getAgg(args, ctx);
775
+ return result2;
768
776
  },
769
777
  get: async (args, ctx) => {
770
778
  args = { ...args, where: { ...args?.where } };
771
- ctx = { ...options.context, ...ctx };
772
- await beforeGet(args, ctx, computedContext);
773
- const result = await driverInstance.get(args, ctx);
774
- const resultArray = [result];
775
- if (result && args.include)
779
+ ctx = { ...options.context, ...ctx, method: "get" };
780
+ let result2 = await beforeGet(args, ctx, computedContext);
781
+ if (!result2)
782
+ result2 = await driverInstance.get(args, ctx);
783
+ const resultArray = result2 ? [result2] : [];
784
+ if (result2 && args.include)
776
785
  await handleInclude(computedContext, args.include, resultArray, ctx);
777
- if (result)
786
+ if (result2)
778
787
  await handleComputed(computedContext, resultArray, ctx);
779
788
  await afterGet(resultArray, args, ctx, computedContext);
780
- return result;
789
+ return result2;
781
790
  },
782
791
  getAll: async (args, ctx) => {
783
792
  args = { ...args, where: { ...args?.where } };
784
- ctx = { ...options.context, ...ctx };
785
- await beforeGet(args, ctx, computedContext);
786
- const result = await driverInstance.getAll(args, ctx);
793
+ ctx = { ...options.context, ...ctx, method: "getAll" };
794
+ let result2 = await beforeGet(args, ctx, computedContext);
795
+ if (!result2)
796
+ result2 = await driverInstance.getAll(args, ctx);
787
797
  if (args.include)
788
- await handleInclude(computedContext, args.include, result, ctx);
789
- await handleComputed(computedContext, result, ctx);
790
- await afterGet(result, args, ctx, computedContext);
791
- return result;
798
+ await handleInclude(computedContext, args.include, result2, ctx);
799
+ await handleComputed(computedContext, result2, ctx);
800
+ await afterGet(result2, args, ctx, computedContext);
801
+ return result2;
792
802
  },
793
803
  put: async (doc, ctx) => {
794
804
  const precomputed = schema[key].decorators.precomputed;
@@ -881,10 +891,17 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
881
891
  return driverInstance.clear(ctx);
882
892
  }
883
893
  };
894
+ for (const f of options.features) {
895
+ if (f.enhanceEntityMethods)
896
+ f.enhanceEntityMethods(computedContext, result);
897
+ }
898
+ return result;
884
899
  }
885
900
  async function beforeGet(args, ctx, computedContext) {
886
901
  for (const f of computedContext.options.features) {
887
- await f.beforeGet?.(args, ctx, computedContext);
902
+ const result = await f.beforeGet?.(args, ctx, computedContext);
903
+ if (result)
904
+ return result;
888
905
  }
889
906
  }
890
907
  async function afterGet(items, args, ctx, computedContext) {
@@ -980,6 +997,14 @@ function generateMethods(schema, validators, options) {
980
997
  }
981
998
  verifyEventSourcingSetup(schema, effects);
982
999
  verifyRelationsSetup(schema, effects);
1000
+ const computedContextGlobal = {
1001
+ schema,
1002
+ validators,
1003
+ options: opts,
1004
+ drivers,
1005
+ effects,
1006
+ db
1007
+ };
983
1008
  for (const key in schema) {
984
1009
  if (!schema[key].decorators.entity)
985
1010
  continue;
@@ -987,17 +1012,17 @@ function generateMethods(schema, validators, options) {
987
1012
  if (!handle)
988
1013
  throw new Error(`Missing handle for entity ${key}`);
989
1014
  const computedContext = {
990
- schema,
1015
+ ...computedContextGlobal,
991
1016
  typeName: key,
992
- validators,
993
- options: opts,
994
- drivers,
995
- effects,
996
- db
1017
+ handle: schema[key].handle
997
1018
  };
998
1019
  const driverInstance = getDriverInstance(schema, key, opts.driver, drivers);
999
1020
  db[handle] = getRadsDbMethods(key, computedContext, driverInstance);
1000
1021
  }
1022
+ for (const f of opts.features) {
1023
+ if (f.init)
1024
+ f.init(db, computedContextGlobal);
1025
+ }
1001
1026
  return db;
1002
1027
  }
1003
1028
  function getDriverInstance(schema, key, driver, drivers) {
@@ -1011,6 +1036,7 @@ function getDriverInstanceInner(schema, key, driverConstructor) {
1011
1036
  addDryRunSupport(driverInstance, key);
1012
1037
  async function getAll(args, ctx) {
1013
1038
  const result = [];
1039
+ args = args || {};
1014
1040
  let cursor = args.cursor;
1015
1041
  let maxItemCount = args.maxItemCount || 1e3;
1016
1042
  if (maxItemCount < 1e3)
@@ -1122,6 +1148,7 @@ exports.computed = computed;
1122
1148
  exports.createRads = createRads;
1123
1149
  exports.entity = entity;
1124
1150
  exports.field = field;
1151
+ exports.getDriverInstance = getDriverInstance;
1125
1152
  exports.precomputed = precomputed;
1126
1153
  exports.ui = ui;
1127
1154
  exports.validate = validate;
package/dist/index.d.ts CHANGED
@@ -234,15 +234,18 @@ interface FieldDefinition {
234
234
  comment?: string;
235
235
  decorators?: Record<string, Record<string, any>>;
236
236
  }
237
- interface ComputedContext {
237
+ interface ComputedContextGlobal {
238
238
  db: RadsDb;
239
239
  schema: Schema;
240
- typeName: string;
241
240
  validators: SchemaValidators;
242
241
  options: CreateRadsArgs;
243
242
  drivers: Record<string, Driver>;
244
243
  effects: Record<string, PutEffect[]>;
245
244
  }
245
+ interface ComputedContext extends ComputedContextGlobal {
246
+ typeName: string;
247
+ handle: string;
248
+ }
246
249
  interface PutEffect {
247
250
  beforePut?: (computedContext: ComputedContext, docs: {
248
251
  oldDoc: any;
@@ -290,6 +293,11 @@ interface RadsRequestContext {
290
293
  silent?: boolean;
291
294
  /** Mostly for internal use. When entity name is specified, indicates that calling put* on this entity is allowed, even if it's marked as @precomputed or @readonly */
292
295
  skipPrecomputedCheckFor?: string;
296
+ /** Mostly for internal use. Method that was called - get, getAll, getMany, getAgg, put, putMany, etc */
297
+ method?: string;
298
+ /** if true, all cache layers will be bypassed */
299
+ noCache?: boolean;
300
+ [key: string]: any;
293
301
  }
294
302
  interface FileSystemNode {
295
303
  path: string;
@@ -298,7 +306,9 @@ interface FileSystemNode {
298
306
  }
299
307
  interface RadsFeature {
300
308
  name: string;
301
- beforeGet?: (args: GetArgsAny, ctx: RadsRequestContext, context: ComputedContext) => MaybePromise<void>;
309
+ init?: (db: Record<string, any>, context: ComputedContextGlobal) => void;
310
+ enhanceEntityMethods?: (context: ComputedContext, entityMethodsObj: EntityMethods<any, any, any>) => void;
311
+ beforeGet?: (args: GetArgsAny, ctx: RadsRequestContext, context: ComputedContext) => MaybePromise<any>;
302
312
  afterGet?: (items: any[], args: GetArgsAny, ctx: RadsRequestContext, context: ComputedContext) => MaybePromise<void>;
303
313
  beforePut?: (items: {
304
314
  oldDoc: any;
@@ -317,6 +327,8 @@ declare function field(meta?: FieldDecoratorArgs): (a: any, b?: ClassFieldDecora
317
327
  declare function precomputed(meta?: ComputedDecoratorArgs): (a: any, b?: ClassFieldDecoratorContext | ClassDecoratorContext) => void;
318
328
  declare function computed(meta?: ComputedDecoratorArgs): (a: any, b?: ClassFieldDecoratorContext | ClassDecoratorContext) => void;
319
329
 
330
+ declare function getDriverInstance(schema: Schema, key: string, driver: DriverConstructor, drivers: Record<string, Driver>): Driver;
331
+
320
332
  declare function createRads(args?: CreateRadsArgs): RadsDb;
321
333
 
322
- export { Change, ComputedContext, ComputedDecoratorArgs, CreateRadsArgs, DeepPartial, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, FieldDecoratorArgs, FieldDefinition, FileSystemNode, FileUploadArgs, FileUploadDriver, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, 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 };
334
+ export { Change, ComputedContext, ComputedContextGlobal, ComputedDecoratorArgs, CreateRadsArgs, DeepPartial, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, FieldDecoratorArgs, FieldDefinition, FileSystemNode, FileUploadArgs, FileUploadDriver, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, MinimalDriver, PutArgs, PutEffect, RadsFeature, RadsRequestContext, RadsVitePluginOptions, Relation, RestFileUploadDriverOptions, Schema, SchemaValidators, TypeDefinition, UiDecoratorArgs, UiFieldDecoratorArgs, ValidateEntityDecoratorArgs, ValidateFieldDecoratorArgs, ValidateStringDecoratorArgs, VerifyManyArgs, VerifyManyArgsAny, VerifyManyResponse, computed, createRads, entity, field, getDriverInstance, precomputed, ui, validate };
package/dist/index.mjs CHANGED
@@ -124,23 +124,26 @@ const operatorFns = {
124
124
  }
125
125
  };
126
126
  const memory = (options) => (schema, entity) => {
127
- let cache = {};
127
+ let itemsById = {};
128
128
  function getItemById(id) {
129
- return cache[id] ?? null;
129
+ return itemsById[id] ?? null;
130
130
  }
131
131
  function getItemByIds(ids) {
132
- return ids.map((id) => cache[id]);
132
+ return ids.map((id) => itemsById[id]);
133
133
  }
134
134
  const instance = {
135
135
  driverName: "memory",
136
+ get itemsById() {
137
+ return itemsById;
138
+ },
136
139
  clear() {
137
- cache = {};
140
+ itemsById = {};
138
141
  },
139
142
  putMany(items) {
140
143
  for (const item of items) {
141
144
  if (!item?.id)
142
145
  throw new Error(`You must provide an id`);
143
- cache[item.id] = item;
146
+ itemsById[item.id] = item;
144
147
  }
145
148
  },
146
149
  getMany(args) {
@@ -153,7 +156,7 @@ const memory = (options) => (schema, entity) => {
153
156
  if (whereKeys[0] === "id_in")
154
157
  return { nodes: _.cloneDeep(getItemByIds(where.id_in).filter((x) => x)), cursor: null };
155
158
  }
156
- return queryArray(Object.values(cache), args);
159
+ return queryArray(Object.values(itemsById), args);
157
160
  }
158
161
  };
159
162
  return instance;
@@ -260,7 +263,7 @@ function getFilterInner(operator, whereVal, name, namePrefix) {
260
263
  if (operatorFn) {
261
264
  return (x) => operatorFn(_.get(x, name), whereVal);
262
265
  }
263
- console.warn(`[rads-cache] Operator not supported: ${operator || "eq"}`);
266
+ console.warn(`[rads-db] Operator not supported: ${operator || "eq"}`);
264
267
  return null;
265
268
  }
266
269
  function prepareArgs(args) {
@@ -698,14 +701,15 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
698
701
  const { precomputedFields } = schema[key];
699
702
  async function getMany(args, ctx) {
700
703
  args = { ...args, where: { ...args?.where } };
701
- ctx = { ...options.context, ...ctx };
702
- await beforeGet(args, ctx, computedContext);
703
- const result = await driverInstance.getMany(args, ctx);
704
+ ctx = { ...options.context, ...ctx, method: "getMany" };
705
+ let result2 = await beforeGet(args, ctx, computedContext);
706
+ if (!result2)
707
+ result2 = await driverInstance.getMany(args, ctx);
704
708
  if (args.include)
705
- await handleInclude(computedContext, args.include, result.nodes, ctx);
706
- await handleComputed(computedContext, result.nodes, ctx);
707
- await afterGet(result.nodes, args, ctx, computedContext);
708
- return result;
709
+ await handleInclude(computedContext, args.include, result2.nodes, ctx);
710
+ await handleComputed(computedContext, result2.nodes, ctx);
711
+ await afterGet(result2.nodes, args, ctx, computedContext);
712
+ return result2;
709
713
  }
710
714
  async function putMany(docs, ctx) {
711
715
  const precomputed = schema[key].decorators.precomputed;
@@ -719,7 +723,7 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
719
723
  throw new Error("Id is required");
720
724
  return i.id;
721
725
  });
722
- ctx = { ...options.context, ...ctx };
726
+ ctx = { ...options.context, ...ctx, method: "putMany" };
723
727
  const oldDocs = await driverInstance.getAll({ where: { id_in: ids } }, ctx);
724
728
  const oldDocsById = _.keyBy(oldDocs, "id");
725
729
  const docArgsToSave = docs.map((doc) => {
@@ -746,7 +750,10 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
746
750
  await afterPut(docArgsToSave, ctx, computedContext);
747
751
  return docsToSave;
748
752
  }
749
- return {
753
+ const result = {
754
+ createObject() {
755
+ throw new Error("Not implemented");
756
+ },
750
757
  getMany,
751
758
  putMany,
752
759
  driver: driverInstance,
@@ -754,34 +761,37 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
754
761
  args = { ...args, where: { ...args?.where } };
755
762
  if (!args.agg)
756
763
  throw new Error(`Please provide 'agg' argument`);
757
- ctx = { ...options.context, ...ctx };
758
- await beforeGet(args, ctx, computedContext);
759
- const result = await driverInstance.getAgg(args, ctx);
760
- return result;
764
+ ctx = { ...options.context, ...ctx, method: "getAgg" };
765
+ let result2 = await beforeGet(args, ctx, computedContext);
766
+ if (!result2)
767
+ result2 = await driverInstance.getAgg(args, ctx);
768
+ return result2;
761
769
  },
762
770
  get: async (args, ctx) => {
763
771
  args = { ...args, where: { ...args?.where } };
764
- ctx = { ...options.context, ...ctx };
765
- await beforeGet(args, ctx, computedContext);
766
- const result = await driverInstance.get(args, ctx);
767
- const resultArray = [result];
768
- if (result && args.include)
772
+ ctx = { ...options.context, ...ctx, method: "get" };
773
+ let result2 = await beforeGet(args, ctx, computedContext);
774
+ if (!result2)
775
+ result2 = await driverInstance.get(args, ctx);
776
+ const resultArray = result2 ? [result2] : [];
777
+ if (result2 && args.include)
769
778
  await handleInclude(computedContext, args.include, resultArray, ctx);
770
- if (result)
779
+ if (result2)
771
780
  await handleComputed(computedContext, resultArray, ctx);
772
781
  await afterGet(resultArray, args, ctx, computedContext);
773
- return result;
782
+ return result2;
774
783
  },
775
784
  getAll: async (args, ctx) => {
776
785
  args = { ...args, where: { ...args?.where } };
777
- ctx = { ...options.context, ...ctx };
778
- await beforeGet(args, ctx, computedContext);
779
- const result = await driverInstance.getAll(args, ctx);
786
+ ctx = { ...options.context, ...ctx, method: "getAll" };
787
+ let result2 = await beforeGet(args, ctx, computedContext);
788
+ if (!result2)
789
+ result2 = await driverInstance.getAll(args, ctx);
780
790
  if (args.include)
781
- await handleInclude(computedContext, args.include, result, ctx);
782
- await handleComputed(computedContext, result, ctx);
783
- await afterGet(result, args, ctx, computedContext);
784
- return result;
791
+ await handleInclude(computedContext, args.include, result2, ctx);
792
+ await handleComputed(computedContext, result2, ctx);
793
+ await afterGet(result2, args, ctx, computedContext);
794
+ return result2;
785
795
  },
786
796
  put: async (doc, ctx) => {
787
797
  const precomputed = schema[key].decorators.precomputed;
@@ -874,10 +884,17 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
874
884
  return driverInstance.clear(ctx);
875
885
  }
876
886
  };
887
+ for (const f of options.features) {
888
+ if (f.enhanceEntityMethods)
889
+ f.enhanceEntityMethods(computedContext, result);
890
+ }
891
+ return result;
877
892
  }
878
893
  async function beforeGet(args, ctx, computedContext) {
879
894
  for (const f of computedContext.options.features) {
880
- await f.beforeGet?.(args, ctx, computedContext);
895
+ const result = await f.beforeGet?.(args, ctx, computedContext);
896
+ if (result)
897
+ return result;
881
898
  }
882
899
  }
883
900
  async function afterGet(items, args, ctx, computedContext) {
@@ -973,6 +990,14 @@ function generateMethods(schema, validators, options) {
973
990
  }
974
991
  verifyEventSourcingSetup(schema, effects);
975
992
  verifyRelationsSetup(schema, effects);
993
+ const computedContextGlobal = {
994
+ schema,
995
+ validators,
996
+ options: opts,
997
+ drivers,
998
+ effects,
999
+ db
1000
+ };
976
1001
  for (const key in schema) {
977
1002
  if (!schema[key].decorators.entity)
978
1003
  continue;
@@ -980,17 +1005,17 @@ function generateMethods(schema, validators, options) {
980
1005
  if (!handle)
981
1006
  throw new Error(`Missing handle for entity ${key}`);
982
1007
  const computedContext = {
983
- schema,
1008
+ ...computedContextGlobal,
984
1009
  typeName: key,
985
- validators,
986
- options: opts,
987
- drivers,
988
- effects,
989
- db
1010
+ handle: schema[key].handle
990
1011
  };
991
1012
  const driverInstance = getDriverInstance(schema, key, opts.driver, drivers);
992
1013
  db[handle] = getRadsDbMethods(key, computedContext, driverInstance);
993
1014
  }
1015
+ for (const f of opts.features) {
1016
+ if (f.init)
1017
+ f.init(db, computedContextGlobal);
1018
+ }
994
1019
  return db;
995
1020
  }
996
1021
  function getDriverInstance(schema, key, driver, drivers) {
@@ -1004,6 +1029,7 @@ function getDriverInstanceInner(schema, key, driverConstructor) {
1004
1029
  addDryRunSupport(driverInstance, key);
1005
1030
  async function getAll(args, ctx) {
1006
1031
  const result = [];
1032
+ args = args || {};
1007
1033
  let cursor = args.cursor;
1008
1034
  let maxItemCount = args.maxItemCount || 1e3;
1009
1035
  if (maxItemCount < 1e3)
@@ -1111,4 +1137,4 @@ function createRads(args) {
1111
1137
  return generateMethods(s, validators, args);
1112
1138
  }
1113
1139
 
1114
- export { computed, createRads, entity, field, precomputed, ui, validate };
1140
+ export { computed, createRads, entity, field, getDriverInstance, precomputed, ui, validate };
@@ -39,22 +39,25 @@ const operatorFns = {
39
39
  }
40
40
  };
41
41
  var _default = options => (schema, entity) => {
42
- let cache = {};
42
+ let itemsById = {};
43
43
  function getItemById(id) {
44
- return cache[id] ?? null;
44
+ return itemsById[id] ?? null;
45
45
  }
46
46
  function getItemByIds(ids) {
47
- return ids.map(id => cache[id]);
47
+ return ids.map(id => itemsById[id]);
48
48
  }
49
49
  const instance = {
50
50
  driverName: "memory",
51
+ get itemsById() {
52
+ return itemsById;
53
+ },
51
54
  clear() {
52
- cache = {};
55
+ itemsById = {};
53
56
  },
54
57
  putMany(items) {
55
58
  for (const item of items) {
56
59
  if (!item?.id) throw new Error(`You must provide an id`);
57
- cache[item.id] = item;
60
+ itemsById[item.id] = item;
58
61
  }
59
62
  },
60
63
  getMany(args) {
@@ -71,7 +74,7 @@ var _default = options => (schema, entity) => {
71
74
  cursor: null
72
75
  };
73
76
  }
74
- return queryArray(Object.values(cache), args);
77
+ return queryArray(Object.values(itemsById), args);
75
78
  }
76
79
  };
77
80
  return instance;
@@ -169,7 +172,7 @@ function getFilterInner(operator, whereVal, name, namePrefix) {
169
172
  if (operatorFn) {
170
173
  return x => operatorFn(_lodash.default.get(x, name), whereVal);
171
174
  }
172
- console.warn(`[rads-cache] Operator not supported: ${operator || "eq"}`);
175
+ console.warn(`[rads-db] Operator not supported: ${operator || "eq"}`);
173
176
  return null;
174
177
  }
175
178
  function prepareArgs(args) {
@@ -31,23 +31,26 @@ const operatorFns = {
31
31
  }
32
32
  };
33
33
  export default (options) => (schema, entity) => {
34
- let cache = {};
34
+ let itemsById = {};
35
35
  function getItemById(id) {
36
- return cache[id] ?? null;
36
+ return itemsById[id] ?? null;
37
37
  }
38
38
  function getItemByIds(ids) {
39
- return ids.map((id) => cache[id]);
39
+ return ids.map((id) => itemsById[id]);
40
40
  }
41
41
  const instance = {
42
42
  driverName: "memory",
43
+ get itemsById() {
44
+ return itemsById;
45
+ },
43
46
  clear() {
44
- cache = {};
47
+ itemsById = {};
45
48
  },
46
49
  putMany(items) {
47
50
  for (const item of items) {
48
51
  if (!item?.id)
49
52
  throw new Error(`You must provide an id`);
50
- cache[item.id] = item;
53
+ itemsById[item.id] = item;
51
54
  }
52
55
  },
53
56
  getMany(args) {
@@ -60,7 +63,7 @@ export default (options) => (schema, entity) => {
60
63
  if (whereKeys[0] === "id_in")
61
64
  return { nodes: _.cloneDeep(getItemByIds(where.id_in).filter((x) => x)), cursor: null };
62
65
  }
63
- return queryArray(Object.values(cache), args);
66
+ return queryArray(Object.values(itemsById), args);
64
67
  }
65
68
  };
66
69
  return instance;
@@ -167,7 +170,7 @@ function getFilterInner(operator, whereVal, name, namePrefix) {
167
170
  if (operatorFn) {
168
171
  return (x) => operatorFn(_.get(x, name), whereVal);
169
172
  }
170
- console.warn(`[rads-cache] Operator not supported: ${operator || "eq"}`);
173
+ console.warn(`[rads-db] Operator not supported: ${operator || "eq"}`);
171
174
  return null;
172
175
  }
173
176
  function prepareArgs(args) {
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ module.exports = void 0;
7
+ var _memory = _interopRequireDefault(require("@/drivers/memory"));
8
+ var _radsDb = require("rads-db");
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ var _default = options => {
11
+ const normalizedOptions = normalizeOptions(options);
12
+ const cacheDrivers = {};
13
+ const cacheStatus = {};
14
+ return {
15
+ name: "cache",
16
+ init(db, context) {
17
+ const entitiesToCache = Object.keys(normalizedOptions.entities);
18
+ const {
19
+ schema,
20
+ drivers
21
+ } = context;
22
+ for (const typeName of entitiesToCache) {
23
+ const handle = schema[typeName].handle;
24
+ const cacheEntityName = `Cache_${typeName}`;
25
+ schema[cacheEntityName] = {
26
+ ...schema[typeName],
27
+ name: cacheEntityName,
28
+ handle: cacheEntityName,
29
+ handlePlural: `${cacheEntityName}s`
30
+ };
31
+ cacheDrivers[handle] = (0, _radsDb.getDriverInstance)(schema, cacheEntityName, normalizedOptions.driver, drivers);
32
+ cacheStatus[handle] = {
33
+ preloadStatus: normalizedOptions.preload ? "neverLoaded" : void 0
34
+ };
35
+ }
36
+ db.cache = {
37
+ drivers: cacheDrivers,
38
+ status: cacheStatus,
39
+ async preload() {
40
+ if (!entitiesToCache.length) {
41
+ console.warn('No entities found to preload. Please, add "preload: true" to your cache configuration.');
42
+ }
43
+ for (const typeName of entitiesToCache) {
44
+ const handle = schema[typeName].handle;
45
+ cacheStatus[handle].preloadStatus = "loading";
46
+ try {
47
+ const allData = await db[handle].getAll({}, {
48
+ noCache: true
49
+ });
50
+ const now = Date.now();
51
+ await cacheDrivers[handle].putMany(allData.map(item => ({
52
+ ...item,
53
+ _cacheUpdatedAt: now
54
+ })));
55
+ cacheStatus[handle].preloadStatus = "upToDate";
56
+ } catch (e) {
57
+ cacheStatus[handle].preloadStatus = "error";
58
+ console.error(`Error preloading db.${handle}`, e);
59
+ }
60
+ }
61
+ }
62
+ };
63
+ },
64
+ // enhanceEntityMethods(context, entityMethodsObj) {
65
+ // if (normalizedOptions.entities && !normalizedOptions.entities[context.typeName]) return
66
+ // const { typeName, schema, drivers } = context
67
+ // const cacheEntityName = `Cache_${typeName}`
68
+ // schema[cacheEntityName] = {
69
+ // ...schema[typeName],
70
+ // name: cacheEntityName,
71
+ // handle: cacheEntityName,
72
+ // handlePlural: `${cacheEntityName}s`,
73
+ // } // A bit of a hack. Maybe better approach is to adjust driver constructor to accept entityPrefix
74
+ // cacheDrivers[typeName] = getDriverInstance(schema, cacheEntityName, normalizedOptions.driver, drivers)
75
+ // const emo = entityMethodsObj as any
76
+ // emo.cache = {
77
+ // driver: cacheDrivers[typeName],
78
+ // }
79
+ // },
80
+ async beforeGet(args, ctx, context) {
81
+ if (ctx.noCache) return;
82
+ const {
83
+ handle
84
+ } = context;
85
+ const d = cacheDrivers[handle];
86
+ if (!d) return;
87
+ if (ctx.method === "get") {
88
+ const result2 = await d[ctx.method](args, ctx);
89
+ if (!result2) return;
90
+ const ageMs = Date.now() - result2._cacheUpdatedAt;
91
+ const maxAge = ctx.maxAge ?? normalizedOptions.maxAge;
92
+ const staleWhileRevalidate = ctx.staleWhileRevalidate ?? normalizedOptions.staleWhileRevalidate;
93
+ if (maxAge !== -1 && (maxAge === 0 || ageMs > maxAge * 1e3)) {
94
+ if (staleWhileRevalidate !== 0 && (staleWhileRevalidate === -1 || ageMs <= staleWhileRevalidate * 1e3)) {
95
+ const db = context.db;
96
+ await context.db[handle].get(args, {
97
+ maxAge: 0,
98
+ staleWhileRevalidate: 0
99
+ });
100
+ return result2;
101
+ }
102
+ return;
103
+ }
104
+ return result2;
105
+ }
106
+ if (cacheStatus[handle].preloadStatus !== "upToDate") return;
107
+ const result = await d[ctx.method](args, ctx);
108
+ return result;
109
+ },
110
+ async afterGet(items, args, ctx, context) {
111
+ const {
112
+ handle
113
+ } = context;
114
+ const d = cacheDrivers[handle];
115
+ if (!d || !items?.length) return;
116
+ if (items[0]._cacheUpdatedAt) return;
117
+ const now = Date.now();
118
+ await d.putMany(items.map(item => ({
119
+ ...item,
120
+ _cacheUpdatedAt: now
121
+ })));
122
+ },
123
+ async afterPut(items, ctx, computedContext) {
124
+ const {
125
+ handle
126
+ } = computedContext;
127
+ const d = cacheDrivers[handle];
128
+ if (!d) return;
129
+ const now = Date.now();
130
+ await d.putMany(items.map(item => item.doc).map(item => ({
131
+ ...item,
132
+ _cacheUpdatedAt: now
133
+ })));
134
+ }
135
+ };
136
+ };
137
+ module.exports = _default;
138
+ function normalizeOptions(options) {
139
+ return {
140
+ driver: (0, _memory.default)(),
141
+ maxAge: 300,
142
+ staleWhileRevalidate: 0,
143
+ entities: {},
144
+ ...options
145
+ };
146
+ }
@@ -0,0 +1,30 @@
1
+ import type { DriverConstructor } from '@/types';
2
+ declare const _default: (options?: CacheOptions) => RadsFeature;
3
+ export default _default;
4
+ export interface CacheOptions {
5
+ entities: Record<string, boolean>;
6
+ driver?: DriverConstructor;
7
+ /**
8
+ * Number in seconds. If document was stored in cache more than maxAge seconds ago, cache is ignored.
9
+ * 0 = 0s = all documents immediately expire, so never get anything from cache.
10
+ * -1 = infinity = documents never expire (always returned from cache if exist)
11
+ * defaults to 300 (5 minutes)
12
+ * */
13
+ maxAge?: number;
14
+ /**
15
+ * Number in seconds.
16
+ * If document was stored in cache more than staleWhileRevalidate seconds ago, cache is ignored.
17
+ * If document was stored in cache less than staleWhileRevalidate seconds ago,
18
+ * but more than maxAge seconds ago, it is immediately returned form cache, but also is downloaded again in the background.
19
+ * 0 = 0s = documents are never revalidated in background
20
+ * -1 = infinity = documents always are returned from cache immediately and revalidated in background
21
+ * defaults to 0
22
+ * */
23
+ staleWhileRevalidate?: number;
24
+ /**
25
+ * Start preloading all data into cache immediately in the background.
26
+ * After data are preloaded, getAll/getMany queries will start working from cache as well.
27
+ * If your driver already contains data, "preload" will download only newly changed records (based on `updatedAt`)
28
+ */
29
+ preload?: boolean;
30
+ }
@@ -0,0 +1,123 @@
1
+ import memory from "@/drivers/memory";
2
+ import { getDriverInstance } from "rads-db";
3
+ export default (options) => {
4
+ const normalizedOptions = normalizeOptions(options);
5
+ const cacheDrivers = {};
6
+ const cacheStatus = {};
7
+ return {
8
+ name: "cache",
9
+ init(db, context) {
10
+ const entitiesToCache = Object.keys(normalizedOptions.entities);
11
+ const { schema, drivers } = context;
12
+ for (const typeName of entitiesToCache) {
13
+ const handle = schema[typeName].handle;
14
+ const cacheEntityName = `Cache_${typeName}`;
15
+ schema[cacheEntityName] = {
16
+ ...schema[typeName],
17
+ name: cacheEntityName,
18
+ handle: cacheEntityName,
19
+ handlePlural: `${cacheEntityName}s`
20
+ };
21
+ cacheDrivers[handle] = getDriverInstance(schema, cacheEntityName, normalizedOptions.driver, drivers);
22
+ cacheStatus[handle] = { preloadStatus: normalizedOptions.preload ? "neverLoaded" : void 0 };
23
+ }
24
+ db.cache = {
25
+ drivers: cacheDrivers,
26
+ status: cacheStatus,
27
+ async preload() {
28
+ if (!entitiesToCache.length) {
29
+ console.warn('No entities found to preload. Please, add "preload: true" to your cache configuration.');
30
+ }
31
+ for (const typeName of entitiesToCache) {
32
+ const handle = schema[typeName].handle;
33
+ cacheStatus[handle].preloadStatus = "loading";
34
+ try {
35
+ const allData = await db[handle].getAll({}, { noCache: true });
36
+ const now = Date.now();
37
+ await cacheDrivers[handle].putMany(allData.map((item) => ({ ...item, _cacheUpdatedAt: now })));
38
+ cacheStatus[handle].preloadStatus = "upToDate";
39
+ } catch (e) {
40
+ cacheStatus[handle].preloadStatus = "error";
41
+ console.error(`Error preloading db.${handle}`, e);
42
+ }
43
+ }
44
+ }
45
+ };
46
+ },
47
+ // enhanceEntityMethods(context, entityMethodsObj) {
48
+ // if (normalizedOptions.entities && !normalizedOptions.entities[context.typeName]) return
49
+ // const { typeName, schema, drivers } = context
50
+ // const cacheEntityName = `Cache_${typeName}`
51
+ // schema[cacheEntityName] = {
52
+ // ...schema[typeName],
53
+ // name: cacheEntityName,
54
+ // handle: cacheEntityName,
55
+ // handlePlural: `${cacheEntityName}s`,
56
+ // } // A bit of a hack. Maybe better approach is to adjust driver constructor to accept entityPrefix
57
+ // cacheDrivers[typeName] = getDriverInstance(schema, cacheEntityName, normalizedOptions.driver, drivers)
58
+ // const emo = entityMethodsObj as any
59
+ // emo.cache = {
60
+ // driver: cacheDrivers[typeName],
61
+ // }
62
+ // },
63
+ async beforeGet(args, ctx, context) {
64
+ if (ctx.noCache)
65
+ return;
66
+ const { handle } = context;
67
+ const d = cacheDrivers[handle];
68
+ if (!d)
69
+ return;
70
+ if (ctx.method === "get") {
71
+ const result2 = await d[ctx.method](args, ctx);
72
+ if (!result2)
73
+ return;
74
+ const ageMs = Date.now() - result2._cacheUpdatedAt;
75
+ const maxAge = ctx.maxAge ?? normalizedOptions.maxAge;
76
+ const staleWhileRevalidate = ctx.staleWhileRevalidate ?? normalizedOptions.staleWhileRevalidate;
77
+ if (maxAge !== -1 && (maxAge === 0 || ageMs > maxAge * 1e3)) {
78
+ if (staleWhileRevalidate !== 0 && (staleWhileRevalidate === -1 || ageMs <= staleWhileRevalidate * 1e3)) {
79
+ const db = context.db;
80
+ await context.db[handle].get(args, {
81
+ maxAge: 0,
82
+ staleWhileRevalidate: 0
83
+ });
84
+ return result2;
85
+ }
86
+ return;
87
+ }
88
+ return result2;
89
+ }
90
+ if (cacheStatus[handle].preloadStatus !== "upToDate")
91
+ return;
92
+ const result = await d[ctx.method](args, ctx);
93
+ return result;
94
+ },
95
+ async afterGet(items, args, ctx, context) {
96
+ const { handle } = context;
97
+ const d = cacheDrivers[handle];
98
+ if (!d || !items?.length)
99
+ return;
100
+ if (items[0]._cacheUpdatedAt)
101
+ return;
102
+ const now = Date.now();
103
+ await d.putMany(items.map((item) => ({ ...item, _cacheUpdatedAt: now })));
104
+ },
105
+ async afterPut(items, ctx, computedContext) {
106
+ const { handle } = computedContext;
107
+ const d = cacheDrivers[handle];
108
+ if (!d)
109
+ return;
110
+ const now = Date.now();
111
+ await d.putMany(items.map((item) => item.doc).map((item) => ({ ...item, _cacheUpdatedAt: now })));
112
+ }
113
+ };
114
+ };
115
+ function normalizeOptions(options) {
116
+ return {
117
+ driver: memory(),
118
+ maxAge: 300,
119
+ staleWhileRevalidate: 0,
120
+ entities: {},
121
+ ...options
122
+ };
123
+ }
@@ -150,7 +150,7 @@ function getWhereFieldsFor(schema, type, fieldKey) {
150
150
  throw new Error(`Unknown array type: ${fieldTypeName}`);
151
151
  }
152
152
  const commonWhereFields = [];
153
- if (isRequired) commonWhereFields.push(`${name}_isNull?: boolean`);
153
+ if (!isRequired) commonWhereFields.push(`${name}_isNull?: boolean`);
154
154
  if (isRelation) {
155
155
  return [`${name}?: ${getRelationWhereType()}`, ...commonWhereFields];
156
156
  }
@@ -156,7 +156,7 @@ function getWhereFieldsFor(schema, type, fieldKey) {
156
156
  throw new Error(`Unknown array type: ${fieldTypeName}`);
157
157
  }
158
158
  const commonWhereFields = [];
159
- if (isRequired)
159
+ if (!isRequired)
160
160
  commonWhereFields.push(`${name}_isNull?: boolean`);
161
161
  if (isRelation) {
162
162
  return [`${name}?: ${getRelationWhereType()}`, ...commonWhereFields];
@@ -14,6 +14,10 @@ var _default = {
14
14
  sanitizeFilepath(filepath);
15
15
  return await _promises.default.mkdir(filepath, options);
16
16
  },
17
+ async rm(filepath, options) {
18
+ sanitizeFilepath(filepath);
19
+ return await _promises.default.rm(filepath, options);
20
+ },
17
21
  async rmdir(filepath, options) {
18
22
  sanitizeFilepath(filepath);
19
23
  return await _promises.default.rmdir(filepath, options);
@@ -1,6 +1,7 @@
1
1
  import type { FileSystemNode } from '../types';
2
2
  declare const _default: {
3
3
  mkdir(filepath: string, options?: any): Promise<any>;
4
+ rm(filepath: string, options?: any): Promise<any>;
4
5
  rmdir(filepath: string, options?: any): Promise<any>;
5
6
  readdir(filepath: string, options?: any): Promise<FileSystemNode[]>;
6
7
  writeFile(filepath: string, data: string | Uint8Array, options?: any): Promise<any>;
@@ -7,6 +7,10 @@ export default {
7
7
  sanitizeFilepath(filepath);
8
8
  return await fs.mkdir(filepath, options);
9
9
  },
10
+ async rm(filepath, options) {
11
+ sanitizeFilepath(filepath);
12
+ return await fs.rm(filepath, options);
13
+ },
10
14
  async rmdir(filepath, options) {
11
15
  sanitizeFilepath(filepath);
12
16
  return await fs.rmdir(filepath, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rads-db",
3
- "version": "0.1.92",
3
+ "version": "0.1.94",
4
4
  "files": [
5
5
  "dist",
6
6
  "drivers",
@@ -95,7 +95,7 @@
95
95
  "test": "vitest --run && vitest typecheck --run",
96
96
  "link-rads-db": "symlink-dir ./test/_rads-db ./node_modules/_rads-db",
97
97
  "generate-test-schema": "rads-db",
98
- "dev": "pnpm install && pnpm build && pnpm generate-test-schema && pnpm link-rads-db && vitest --ui",
98
+ "dev": "pnpm install && pnpm build && pnpm generate-test-schema && pnpm link-rads-db && vitest --ui --test-timeout 300000",
99
99
  "lint": "cross-env NODE_ENV=production eslint src/**/*.* test/**/*.*",
100
100
  "dev-typecheck": "pnpm install && pnpm build && pnpm generate-test-schema && pnpm link-rads-db && vitest typecheck --ui",
101
101
  "build": "unbuild"