rads-db 3.1.9 → 3.1.12
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/README.md +19 -0
- package/dist/config.d.ts +1 -1
- package/dist/index.cjs +56 -22
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +56 -22
- package/dist/{types-9c3659f0.d.ts → types-9cb9d6e7.d.ts} +9 -0
- package/drivers/azureCosmos.cjs +57 -14
- package/drivers/azureCosmos.d.ts +1 -0
- package/drivers/azureCosmos.mjs +68 -40
- package/drivers/azureStorageBlob.cjs +2 -2
- package/drivers/azureStorageBlob.d.ts +1 -0
- package/drivers/azureStorageBlob.mjs +4 -8
- package/drivers/indexedDb.cjs +2 -2
- package/drivers/indexedDb.d.ts +1 -0
- package/drivers/indexedDb.mjs +6 -12
- package/drivers/memory.cjs +38 -21
- package/drivers/memory.d.ts +1 -0
- package/drivers/memory.mjs +61 -78
- package/drivers/restApi.cjs +1 -1
- package/drivers/restApi.d.ts +2 -1
- package/drivers/restApi.mjs +2 -4
- package/features/cache.cjs +2 -2
- package/features/cache.mjs +15 -30
- package/features/eventSourcing.cjs +2 -2
- package/features/eventSourcing.d.ts +1 -0
- package/features/eventSourcing.mjs +8 -16
- package/features/softDelete.cjs +1 -1
- package/features/softDelete.mjs +2 -4
- package/fileUploadDrivers/azureStorageBlob.cjs +1 -1
- package/fileUploadDrivers/cloudinary.cjs +1 -1
- package/fileUploadDrivers/memory.cjs +1 -1
- package/fileUploadDrivers/restApi.cjs +1 -1
- package/fileUploadDrivers/restApi.d.ts +1 -0
- package/fileUploadDrivers/restApi.mjs +1 -2
- package/fileUploadDrivers/supabaseStorage.cjs +1 -1
- package/fileUploadDrivers/supabaseStorage.mjs +3 -6
- package/integrations/node.cjs +2 -2
- package/integrations/node.mjs +12 -22
- package/integrations/nuxtModule.cjs +2 -3
- package/integrations/restEndpoints.cjs +1 -1
- package/integrations/restEndpoints.mjs +8 -16
- package/integrations/restEndpointsDev/restEndpointsDevLint.cjs +2 -3
- package/integrations/restEndpointsDev/restEndpointsDevLint.d.ts +1 -1
- package/integrations/restEndpointsDev/restEndpointsDevLint.mjs +5 -10
- package/integrations/restEndpointsDev.cjs +3 -4
- package/integrations/restEndpointsDev.d.ts +1 -1
- package/integrations/restEndpointsDev.mjs +9 -18
- package/integrations/restEndpointsDev2.cjs +3 -4
- package/integrations/restEndpointsDev2.d.ts +0 -1
- package/integrations/restEndpointsDev2.mjs +3 -6
- package/integrations/vite.mjs +3 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -53,3 +53,22 @@ Consensus among the developer community is to use “simple” ORM, and use raw
|
|
|
53
53
|
We wanted to have features that are not supported in current ORMs:
|
|
54
54
|
|
|
55
55
|
- [This](https://medium.com/@rogerpadillac/in-search-of-the-perfect-orm-e01fcc9bce3d) article gives good overview
|
|
56
|
+
|
|
57
|
+
# Development tips
|
|
58
|
+
|
|
59
|
+
## Usage with `npm link`
|
|
60
|
+
|
|
61
|
+
When you want to test changes in this package, it may be useful to test with `pnpm link`.
|
|
62
|
+
|
|
63
|
+
But due to specifics of how this package uses peer dependencies, it won't work well.
|
|
64
|
+
|
|
65
|
+
Use file protocol instead:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
// package.json
|
|
69
|
+
{
|
|
70
|
+
"dependencies": {
|
|
71
|
+
"rads-db": "file:../rads-db"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
package/dist/config.d.ts
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -204,10 +204,17 @@ const memory = (options) => (schema, entity) => {
|
|
|
204
204
|
const where = args.where || {};
|
|
205
205
|
const whereKeys = ___default.keys(where);
|
|
206
206
|
if (whereKeys.length === 1) {
|
|
207
|
-
if (whereKeys[0] === "id")
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
if (whereKeys[0] === "id") {
|
|
208
|
+
const node = ___default.cloneDeep([getItemById(where.id)].filter((x) => x));
|
|
209
|
+
return { nodes: node, cursor: null };
|
|
210
|
+
}
|
|
211
|
+
if (whereKeys[0] === "id_in") {
|
|
212
|
+
const nodes = ___default.cloneDeep(getItemByIds(where.id_in).filter((x) => x));
|
|
213
|
+
return {
|
|
214
|
+
nodes,
|
|
215
|
+
cursor: null
|
|
216
|
+
};
|
|
217
|
+
}
|
|
211
218
|
}
|
|
212
219
|
return queryArray(Object.values(itemsById), args);
|
|
213
220
|
}
|
|
@@ -261,14 +268,14 @@ function queryArray(array, args) {
|
|
|
261
268
|
if (!array)
|
|
262
269
|
return array;
|
|
263
270
|
let result = array;
|
|
264
|
-
const { where,
|
|
271
|
+
const { where, orderByProperties, orderByDirections, maxItemCount, cursor } = prepareArgs(args);
|
|
265
272
|
const startIndex = Number(cursor) || 0;
|
|
266
273
|
const endIndex = startIndex + maxItemCount;
|
|
267
274
|
const f = getFilter(where);
|
|
268
275
|
if (f)
|
|
269
276
|
result = result.filter(f);
|
|
270
|
-
if (
|
|
271
|
-
result = ___default.orderBy(result,
|
|
277
|
+
if (orderByProperties)
|
|
278
|
+
result = ___default.orderBy(result, orderByProperties, orderByDirections);
|
|
272
279
|
if (maxItemCount)
|
|
273
280
|
result = result.slice(startIndex, endIndex);
|
|
274
281
|
const newCursor = endIndex >= array.length ? null : endIndex;
|
|
@@ -355,15 +362,25 @@ function getFilterInner(operator, whereVal, name, namePrefix) {
|
|
|
355
362
|
function prepareArgs(args) {
|
|
356
363
|
args = args || {};
|
|
357
364
|
const where = { ...args.where };
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
365
|
+
const orderByProperties = [];
|
|
366
|
+
const orderByDirections = [];
|
|
367
|
+
if (args.orderBy) {
|
|
368
|
+
let orderBy = args.orderBy || "";
|
|
369
|
+
if (Array.isArray(orderBy))
|
|
370
|
+
orderBy = orderBy[0] || "";
|
|
371
|
+
const orderByParts = orderBy.split("_");
|
|
372
|
+
orderByProperties.push(orderByParts.slice(0, -1).join("."));
|
|
373
|
+
orderByDirections.push(orderByParts.slice(-1)[0]);
|
|
374
|
+
} else if (args.orderByArray) {
|
|
375
|
+
for (const order of args.orderByArray) {
|
|
376
|
+
const [property, direction] = order.split("_");
|
|
377
|
+
orderByProperties.push(property);
|
|
378
|
+
orderByDirections.push(direction);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
364
381
|
let maxItemCount = args.maxItemCount;
|
|
365
382
|
maxItemCount = maxItemCount || 100;
|
|
366
|
-
return { where,
|
|
383
|
+
return { where, orderByProperties, orderByDirections, maxItemCount, cursor: args.cursor, pick: args.include };
|
|
367
384
|
}
|
|
368
385
|
|
|
369
386
|
const computedPresets = {
|
|
@@ -690,7 +707,7 @@ async function handleInclude(computedContext, include, result, ctx) {
|
|
|
690
707
|
return;
|
|
691
708
|
const { schema, typeName } = computedContext;
|
|
692
709
|
const fields = schema[typeName].fields || {};
|
|
693
|
-
const fieldsToInclude = ___default.keys(include).filter((key) => include[key]);
|
|
710
|
+
const fieldsToInclude = ___default.keys(include).filter((key) => include[key] && key !== "_pick");
|
|
694
711
|
const nestedFieldsToInclude = fieldsToInclude.filter(
|
|
695
712
|
(key) => !fields[key].isRelation && !fields[key].isInverseRelation && schema[fields[key].type]?.fields
|
|
696
713
|
);
|
|
@@ -795,7 +812,7 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
795
812
|
const { precomputedFields } = entitySchema;
|
|
796
813
|
async function getMany(args, ctx) {
|
|
797
814
|
args = { ...args, where: { ...args?.where } };
|
|
798
|
-
ctx = { ...options.context, ...ctx, method: "getMany" };
|
|
815
|
+
ctx = { ...options.context, ...ctx, method: "getMany", _isRecursiveRoot: !ctx?._isRecursiveRoot };
|
|
799
816
|
let result2 = await beforeGet(args, ctx, computedContext);
|
|
800
817
|
if (!result2)
|
|
801
818
|
result2 = await driverInstance.getMany(args, ctx);
|
|
@@ -803,6 +820,8 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
803
820
|
await radsDbRelations.handleInclude(computedContext, args.include, result2.nodes, ctx);
|
|
804
821
|
await handleComputed(computedContext, result2.nodes, ctx);
|
|
805
822
|
await afterGet(result2.nodes, args, ctx, computedContext);
|
|
823
|
+
if (ctx._isRecursiveRoot && args.include?._pick)
|
|
824
|
+
result2.nodes = await pickPropsFromObjectAsync(result2.nodes, args.include);
|
|
806
825
|
return result2;
|
|
807
826
|
}
|
|
808
827
|
async function putMany(docs, ctx) {
|
|
@@ -946,7 +965,7 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
946
965
|
},
|
|
947
966
|
get: async (args, ctx) => {
|
|
948
967
|
args = { ...args, where: { ...args?.where } };
|
|
949
|
-
ctx = { ...options.context, ...ctx, method: "get" };
|
|
968
|
+
ctx = { ...options.context, ...ctx, method: "get", _isRecursiveRoot: !ctx?._isRecursiveRoot };
|
|
950
969
|
let result2 = await beforeGet(args, ctx, computedContext);
|
|
951
970
|
if (!result2)
|
|
952
971
|
result2 = await driverInstance.get(args, ctx);
|
|
@@ -956,11 +975,13 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
956
975
|
if (result2)
|
|
957
976
|
await handleComputed(computedContext, resultArray, ctx);
|
|
958
977
|
await afterGet(resultArray, args, ctx, computedContext);
|
|
978
|
+
if (ctx._isRecursiveRoot && args.include?._pick)
|
|
979
|
+
result2 = await pickPropsFromObjectAsync(result2, args.include);
|
|
959
980
|
return result2;
|
|
960
981
|
},
|
|
961
982
|
getAll: async (args, ctx) => {
|
|
962
983
|
args = { ...args, where: { ...args?.where } };
|
|
963
|
-
ctx = { ...options.context, ...ctx, method: "getAll" };
|
|
984
|
+
ctx = { ...options.context, ...ctx, method: "getAll", _isRecursiveRoot: !ctx?._isRecursiveRoot };
|
|
964
985
|
let result2 = await beforeGet(args, ctx, computedContext);
|
|
965
986
|
if (!result2)
|
|
966
987
|
result2 = await driverInstance.getAll(args, ctx);
|
|
@@ -968,6 +989,9 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
968
989
|
await radsDbRelations.handleInclude(computedContext, args.include, result2, ctx);
|
|
969
990
|
await handleComputed(computedContext, result2, ctx);
|
|
970
991
|
await afterGet(result2, args, ctx, computedContext);
|
|
992
|
+
if (ctx._isRecursiveRoot && args.include?._pick) {
|
|
993
|
+
result2 = await pickPropsFromObjectAsync(result2, args.include);
|
|
994
|
+
}
|
|
971
995
|
return result2;
|
|
972
996
|
},
|
|
973
997
|
verifyAll: async (args, ctx) => {
|
|
@@ -1043,6 +1067,18 @@ async function afterPut(items, ctx, computedContext) {
|
|
|
1043
1067
|
await f.afterPut?.(items, ctx, computedContext);
|
|
1044
1068
|
}
|
|
1045
1069
|
}
|
|
1070
|
+
async function pickPropsFromObjectAsync(obj, args) {
|
|
1071
|
+
if (Array.isArray(obj)) {
|
|
1072
|
+
return Promise.all(obj.map((o) => pickPropsFromObjectAsync(o, args)));
|
|
1073
|
+
}
|
|
1074
|
+
const result = args._pick ? ___default.pick(obj, args._pick) : {};
|
|
1075
|
+
for (const key of Object.keys(args)) {
|
|
1076
|
+
if (key !== "_pick" && typeof args[key] === "object" && obj[key]) {
|
|
1077
|
+
result[key] = await pickPropsFromObjectAsync(obj[key], args[key]);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
return result;
|
|
1081
|
+
}
|
|
1046
1082
|
|
|
1047
1083
|
function generateMethods(schema, validators, options) {
|
|
1048
1084
|
const drivers = {};
|
|
@@ -1233,16 +1269,14 @@ const restApi = (options) => (schema, entity) => {
|
|
|
1233
1269
|
if (!response.ok) {
|
|
1234
1270
|
const msg = responseJson?.message || responseJson?.statusMessage || response.statusText || "Server error.";
|
|
1235
1271
|
const err = new Error(msg);
|
|
1236
|
-
if (responseJson?.code)
|
|
1237
|
-
err.code = responseJson?.code;
|
|
1272
|
+
if (responseJson?.code) err.code = responseJson?.code;
|
|
1238
1273
|
err.fetchResponseJson = responseJson;
|
|
1239
1274
|
throw err;
|
|
1240
1275
|
}
|
|
1241
1276
|
return responseJson;
|
|
1242
1277
|
}
|
|
1243
1278
|
const { handlePlural } = schema[entity] || {};
|
|
1244
|
-
if (!handlePlural)
|
|
1245
|
-
throw new Error(`Entity ${entity} was not found in schema`);
|
|
1279
|
+
if (!handlePlural) throw new Error(`Entity ${entity} was not found in schema`);
|
|
1246
1280
|
const instance = {
|
|
1247
1281
|
driverName: "restApi",
|
|
1248
1282
|
async getMany(args, ctx) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as EntityDecoratorArgs, U as UiDecoratorArgs, a as UiFieldDecoratorArgs, V as ValidateEntityDecoratorArgs, b as ValidateFieldDecoratorArgs, F as FieldDecoratorArgs, C as ComputedDecoratorArgs, S as Schema, D as DriverConstructor, c as Driver, d as ComputedContext, R as RadsRequestContext, e as CreateRadsDbArgs, f as CreateRadsDbClientArgs } from './types-
|
|
2
|
-
export { N as Change, x as ComputedContextGlobal, k as CreateRadsArgsDrivers, m as CreateRadsDbArgsNormalized, aj as DeepKeys, ae as DeepPartial, ac as DeepPartialWithNulls, ad as DeepPartialWithNullsItem, ak as EntityMethods, w as EnumDefinition, v as FieldDefinition, I as FileSystemNode, u as FileUploadArgs, q as FileUploadDriver, p as FileUploadResult, B as GenerateClientNormalizedOptions, A as GenerateClientOptions, a8 as Get, _ as GetAggArgs, $ as GetAggArgsAgg, a2 as GetAggArgsAny, a5 as GetAggResponse, Z as GetArgs, a1 as GetArgsAny, a4 as GetArgsInclude, O as GetManyArgs, a0 as GetManyArgsAny, a6 as GetManyResponse, a7 as GetResponse, a9 as GetResponseInclude, aa as GetResponseIncludeSelect, ab as GetResponseNoInclude, s as GetRestRoutesArgs, G as GetRestRoutesOptions, t as GetRestRoutesResponse, ag as InverseRelation, M as MinimalDriver, ai as Put, ah as PutArgs, P as PutEffect, g as RadsConfig, h as RadsConfigDataSource, r as RadsDbInstance, L as RadsFeature, y as RadsHookDoc, K as RadsUiSlotDefinition, J as RadsUiSlotName, H as RadsVitePluginOptions, af as Relation, i as RequiredFields, l as RestDriverOptions, z as RestFileUploadDriverOptions, n as SchemaLoadResult, o as SchemaValidators, T as TypeDefinition, j as ValidateStringDecoratorArgs, Q as VerifyManyArgs, a3 as VerifyManyArgsAny, X as VerifyManyResponse, Y as Where, W as WhereJsonContains } from './types-
|
|
1
|
+
import { E as EntityDecoratorArgs, U as UiDecoratorArgs, a as UiFieldDecoratorArgs, V as ValidateEntityDecoratorArgs, b as ValidateFieldDecoratorArgs, F as FieldDecoratorArgs, C as ComputedDecoratorArgs, S as Schema, D as DriverConstructor, c as Driver, d as ComputedContext, R as RadsRequestContext, e as CreateRadsDbArgs, f as CreateRadsDbClientArgs } from './types-9cb9d6e7.js';
|
|
2
|
+
export { N as Change, x as ComputedContextGlobal, k as CreateRadsArgsDrivers, m as CreateRadsDbArgsNormalized, aj as DeepKeys, ae as DeepPartial, ac as DeepPartialWithNulls, ad as DeepPartialWithNullsItem, ak as EntityMethods, w as EnumDefinition, v as FieldDefinition, I as FileSystemNode, u as FileUploadArgs, q as FileUploadDriver, p as FileUploadResult, B as GenerateClientNormalizedOptions, A as GenerateClientOptions, a8 as Get, _ as GetAggArgs, $ as GetAggArgsAgg, a2 as GetAggArgsAny, a5 as GetAggResponse, Z as GetArgs, a1 as GetArgsAny, a4 as GetArgsInclude, O as GetManyArgs, a0 as GetManyArgsAny, a6 as GetManyResponse, a7 as GetResponse, a9 as GetResponseInclude, aa as GetResponseIncludeSelect, ab as GetResponseNoInclude, s as GetRestRoutesArgs, G as GetRestRoutesOptions, t as GetRestRoutesResponse, ag as InverseRelation, M as MinimalDriver, ai as Put, ah as PutArgs, P as PutEffect, g as RadsConfig, h as RadsConfigDataSource, r as RadsDbInstance, L as RadsFeature, y as RadsHookDoc, K as RadsUiSlotDefinition, J as RadsUiSlotName, H as RadsVitePluginOptions, af as Relation, i as RequiredFields, l as RestDriverOptions, z as RestFileUploadDriverOptions, n as SchemaLoadResult, o as SchemaValidators, T as TypeDefinition, j as ValidateStringDecoratorArgs, Q as VerifyManyArgs, a3 as VerifyManyArgsAny, X as VerifyManyResponse, Y as Where, W as WhereJsonContains } from './types-9cb9d6e7.js';
|
|
3
3
|
import { RadsDb } from '_rads-db';
|
|
4
4
|
export { RadsDb } from '_rads-db';
|
|
5
5
|
|
package/dist/index.mjs
CHANGED
|
@@ -197,10 +197,17 @@ const memory = (options) => (schema, entity) => {
|
|
|
197
197
|
const where = args.where || {};
|
|
198
198
|
const whereKeys = _.keys(where);
|
|
199
199
|
if (whereKeys.length === 1) {
|
|
200
|
-
if (whereKeys[0] === "id")
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
if (whereKeys[0] === "id") {
|
|
201
|
+
const node = _.cloneDeep([getItemById(where.id)].filter((x) => x));
|
|
202
|
+
return { nodes: node, cursor: null };
|
|
203
|
+
}
|
|
204
|
+
if (whereKeys[0] === "id_in") {
|
|
205
|
+
const nodes = _.cloneDeep(getItemByIds(where.id_in).filter((x) => x));
|
|
206
|
+
return {
|
|
207
|
+
nodes,
|
|
208
|
+
cursor: null
|
|
209
|
+
};
|
|
210
|
+
}
|
|
204
211
|
}
|
|
205
212
|
return queryArray(Object.values(itemsById), args);
|
|
206
213
|
}
|
|
@@ -254,14 +261,14 @@ function queryArray(array, args) {
|
|
|
254
261
|
if (!array)
|
|
255
262
|
return array;
|
|
256
263
|
let result = array;
|
|
257
|
-
const { where,
|
|
264
|
+
const { where, orderByProperties, orderByDirections, maxItemCount, cursor } = prepareArgs(args);
|
|
258
265
|
const startIndex = Number(cursor) || 0;
|
|
259
266
|
const endIndex = startIndex + maxItemCount;
|
|
260
267
|
const f = getFilter(where);
|
|
261
268
|
if (f)
|
|
262
269
|
result = result.filter(f);
|
|
263
|
-
if (
|
|
264
|
-
result = _.orderBy(result,
|
|
270
|
+
if (orderByProperties)
|
|
271
|
+
result = _.orderBy(result, orderByProperties, orderByDirections);
|
|
265
272
|
if (maxItemCount)
|
|
266
273
|
result = result.slice(startIndex, endIndex);
|
|
267
274
|
const newCursor = endIndex >= array.length ? null : endIndex;
|
|
@@ -348,15 +355,25 @@ function getFilterInner(operator, whereVal, name, namePrefix) {
|
|
|
348
355
|
function prepareArgs(args) {
|
|
349
356
|
args = args || {};
|
|
350
357
|
const where = { ...args.where };
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
358
|
+
const orderByProperties = [];
|
|
359
|
+
const orderByDirections = [];
|
|
360
|
+
if (args.orderBy) {
|
|
361
|
+
let orderBy = args.orderBy || "";
|
|
362
|
+
if (Array.isArray(orderBy))
|
|
363
|
+
orderBy = orderBy[0] || "";
|
|
364
|
+
const orderByParts = orderBy.split("_");
|
|
365
|
+
orderByProperties.push(orderByParts.slice(0, -1).join("."));
|
|
366
|
+
orderByDirections.push(orderByParts.slice(-1)[0]);
|
|
367
|
+
} else if (args.orderByArray) {
|
|
368
|
+
for (const order of args.orderByArray) {
|
|
369
|
+
const [property, direction] = order.split("_");
|
|
370
|
+
orderByProperties.push(property);
|
|
371
|
+
orderByDirections.push(direction);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
357
374
|
let maxItemCount = args.maxItemCount;
|
|
358
375
|
maxItemCount = maxItemCount || 100;
|
|
359
|
-
return { where,
|
|
376
|
+
return { where, orderByProperties, orderByDirections, maxItemCount, cursor: args.cursor, pick: args.include };
|
|
360
377
|
}
|
|
361
378
|
|
|
362
379
|
const computedPresets = {
|
|
@@ -683,7 +700,7 @@ async function handleInclude(computedContext, include, result, ctx) {
|
|
|
683
700
|
return;
|
|
684
701
|
const { schema, typeName } = computedContext;
|
|
685
702
|
const fields = schema[typeName].fields || {};
|
|
686
|
-
const fieldsToInclude = _.keys(include).filter((key) => include[key]);
|
|
703
|
+
const fieldsToInclude = _.keys(include).filter((key) => include[key] && key !== "_pick");
|
|
687
704
|
const nestedFieldsToInclude = fieldsToInclude.filter(
|
|
688
705
|
(key) => !fields[key].isRelation && !fields[key].isInverseRelation && schema[fields[key].type]?.fields
|
|
689
706
|
);
|
|
@@ -788,7 +805,7 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
788
805
|
const { precomputedFields } = entitySchema;
|
|
789
806
|
async function getMany(args, ctx) {
|
|
790
807
|
args = { ...args, where: { ...args?.where } };
|
|
791
|
-
ctx = { ...options.context, ...ctx, method: "getMany" };
|
|
808
|
+
ctx = { ...options.context, ...ctx, method: "getMany", _isRecursiveRoot: !ctx?._isRecursiveRoot };
|
|
792
809
|
let result2 = await beforeGet(args, ctx, computedContext);
|
|
793
810
|
if (!result2)
|
|
794
811
|
result2 = await driverInstance.getMany(args, ctx);
|
|
@@ -796,6 +813,8 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
796
813
|
await radsDbRelations.handleInclude(computedContext, args.include, result2.nodes, ctx);
|
|
797
814
|
await handleComputed(computedContext, result2.nodes, ctx);
|
|
798
815
|
await afterGet(result2.nodes, args, ctx, computedContext);
|
|
816
|
+
if (ctx._isRecursiveRoot && args.include?._pick)
|
|
817
|
+
result2.nodes = await pickPropsFromObjectAsync(result2.nodes, args.include);
|
|
799
818
|
return result2;
|
|
800
819
|
}
|
|
801
820
|
async function putMany(docs, ctx) {
|
|
@@ -939,7 +958,7 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
939
958
|
},
|
|
940
959
|
get: async (args, ctx) => {
|
|
941
960
|
args = { ...args, where: { ...args?.where } };
|
|
942
|
-
ctx = { ...options.context, ...ctx, method: "get" };
|
|
961
|
+
ctx = { ...options.context, ...ctx, method: "get", _isRecursiveRoot: !ctx?._isRecursiveRoot };
|
|
943
962
|
let result2 = await beforeGet(args, ctx, computedContext);
|
|
944
963
|
if (!result2)
|
|
945
964
|
result2 = await driverInstance.get(args, ctx);
|
|
@@ -949,11 +968,13 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
949
968
|
if (result2)
|
|
950
969
|
await handleComputed(computedContext, resultArray, ctx);
|
|
951
970
|
await afterGet(resultArray, args, ctx, computedContext);
|
|
971
|
+
if (ctx._isRecursiveRoot && args.include?._pick)
|
|
972
|
+
result2 = await pickPropsFromObjectAsync(result2, args.include);
|
|
952
973
|
return result2;
|
|
953
974
|
},
|
|
954
975
|
getAll: async (args, ctx) => {
|
|
955
976
|
args = { ...args, where: { ...args?.where } };
|
|
956
|
-
ctx = { ...options.context, ...ctx, method: "getAll" };
|
|
977
|
+
ctx = { ...options.context, ...ctx, method: "getAll", _isRecursiveRoot: !ctx?._isRecursiveRoot };
|
|
957
978
|
let result2 = await beforeGet(args, ctx, computedContext);
|
|
958
979
|
if (!result2)
|
|
959
980
|
result2 = await driverInstance.getAll(args, ctx);
|
|
@@ -961,6 +982,9 @@ function getRadsDbMethods(key, computedContext, driverInstance) {
|
|
|
961
982
|
await radsDbRelations.handleInclude(computedContext, args.include, result2, ctx);
|
|
962
983
|
await handleComputed(computedContext, result2, ctx);
|
|
963
984
|
await afterGet(result2, args, ctx, computedContext);
|
|
985
|
+
if (ctx._isRecursiveRoot && args.include?._pick) {
|
|
986
|
+
result2 = await pickPropsFromObjectAsync(result2, args.include);
|
|
987
|
+
}
|
|
964
988
|
return result2;
|
|
965
989
|
},
|
|
966
990
|
verifyAll: async (args, ctx) => {
|
|
@@ -1036,6 +1060,18 @@ async function afterPut(items, ctx, computedContext) {
|
|
|
1036
1060
|
await f.afterPut?.(items, ctx, computedContext);
|
|
1037
1061
|
}
|
|
1038
1062
|
}
|
|
1063
|
+
async function pickPropsFromObjectAsync(obj, args) {
|
|
1064
|
+
if (Array.isArray(obj)) {
|
|
1065
|
+
return Promise.all(obj.map((o) => pickPropsFromObjectAsync(o, args)));
|
|
1066
|
+
}
|
|
1067
|
+
const result = args._pick ? _.pick(obj, args._pick) : {};
|
|
1068
|
+
for (const key of Object.keys(args)) {
|
|
1069
|
+
if (key !== "_pick" && typeof args[key] === "object" && obj[key]) {
|
|
1070
|
+
result[key] = await pickPropsFromObjectAsync(obj[key], args[key]);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
return result;
|
|
1074
|
+
}
|
|
1039
1075
|
|
|
1040
1076
|
function generateMethods(schema, validators, options) {
|
|
1041
1077
|
const drivers = {};
|
|
@@ -1226,16 +1262,14 @@ const restApi = (options) => (schema, entity) => {
|
|
|
1226
1262
|
if (!response.ok) {
|
|
1227
1263
|
const msg = responseJson?.message || responseJson?.statusMessage || response.statusText || "Server error.";
|
|
1228
1264
|
const err = new Error(msg);
|
|
1229
|
-
if (responseJson?.code)
|
|
1230
|
-
err.code = responseJson?.code;
|
|
1265
|
+
if (responseJson?.code) err.code = responseJson?.code;
|
|
1231
1266
|
err.fetchResponseJson = responseJson;
|
|
1232
1267
|
throw err;
|
|
1233
1268
|
}
|
|
1234
1269
|
return responseJson;
|
|
1235
1270
|
}
|
|
1236
1271
|
const { handlePlural } = schema[entity] || {};
|
|
1237
|
-
if (!handlePlural)
|
|
1238
|
-
throw new Error(`Entity ${entity} was not found in schema`);
|
|
1272
|
+
if (!handlePlural) throw new Error(`Entity ${entity} was not found in schema`);
|
|
1239
1273
|
const instance = {
|
|
1240
1274
|
driverName: "restApi",
|
|
1241
1275
|
async getMany(args, ctx) {
|
|
@@ -8,6 +8,7 @@ interface GetManyArgs<EN extends keyof EntityMeta> extends GetArgs<EN> {
|
|
|
8
8
|
cursor?: string | null;
|
|
9
9
|
maxItemCount?: number;
|
|
10
10
|
orderBy?: string;
|
|
11
|
+
orderByArray?: OrderBy<EntityMeta[EN]>;
|
|
11
12
|
}
|
|
12
13
|
interface VerifyManyArgs<EN extends keyof EntityMeta> extends GetManyArgs<EN> {
|
|
13
14
|
recompute?: string[];
|
|
@@ -122,6 +123,14 @@ interface EntityMethods<E, EN extends keyof EntityMeta> {
|
|
|
122
123
|
verifyMany<A extends VerifyManyArgs<EN>>(args?: A, ctx?: RadsRequestContext): MaybePromise$1<VerifyManyResponse>;
|
|
123
124
|
verifyAll<A extends VerifyManyArgs<EN>>(args?: A, ctx?: RadsRequestContext): MaybePromise$1<Pick<VerifyManyResponse, 'correctCount' | 'incorrectCount'>>;
|
|
124
125
|
}
|
|
126
|
+
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...0[]];
|
|
127
|
+
type Primitive = string | number | boolean | symbol | null | undefined;
|
|
128
|
+
type OrderByDeepKeys<T, Prefix extends string = '', MaxDepth extends number = 5, Depth extends number = MaxDepth> = Depth extends 0 ? '' : T extends Primitive ? Prefix extends '' ? never : Prefix : T extends object ? {
|
|
129
|
+
[K in keyof T]-?: K extends string | number ? OrderByDeepKeys<T[K], `${Prefix}${K & string}`, MaxDepth, Prev[Depth]> : never;
|
|
130
|
+
}[keyof T] : never;
|
|
131
|
+
type TrimEnd<T extends string, S extends string> = T extends `${infer R}${S}` ? R : T;
|
|
132
|
+
type ValidOrderByKey<T> = TrimEnd<OrderByDeepKeys<T>, '.'>;
|
|
133
|
+
type OrderBy<T> = Array<`${ValidOrderByKey<T>}_${'asc' | 'desc'}`>;
|
|
125
134
|
|
|
126
135
|
interface RadsConfig {
|
|
127
136
|
dataSources: Record<string, RadsConfigDataSource>;
|
package/drivers/azureCosmos.cjs
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
var _cosmos = require("@azure/cosmos");
|
|
8
8
|
var _lodash = _interopRequireDefault(require("lodash"));
|
|
9
|
-
function _interopRequireDefault(
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
10
|
const cosmosClientCache = {};
|
|
11
11
|
const databaseClientCache = {};
|
|
12
12
|
const containerClientCache = {};
|
|
@@ -24,14 +24,15 @@ var _default = options => (schema, entity) => {
|
|
|
24
24
|
if (options.createDatabaseIfNotExists) {
|
|
25
25
|
createDatabaseIfNotExists(normalizedOptions, client.database.client);
|
|
26
26
|
}
|
|
27
|
-
async function getItemByIds(ids, ctx) {
|
|
27
|
+
async function getItemByIds(ids, ctx, include) {
|
|
28
28
|
const {
|
|
29
29
|
query,
|
|
30
30
|
parameters
|
|
31
31
|
} = getCosmosQuery(schema, entity, {
|
|
32
32
|
where: {
|
|
33
33
|
id_in: ids
|
|
34
|
-
}
|
|
34
|
+
},
|
|
35
|
+
include
|
|
35
36
|
});
|
|
36
37
|
const response = client.items.query({
|
|
37
38
|
query,
|
|
@@ -53,14 +54,14 @@ var _default = options => (schema, entity) => {
|
|
|
53
54
|
const whereKeys = _lodash.default.keys(where);
|
|
54
55
|
if (whereKeys.length === 1) {
|
|
55
56
|
if (whereKeys[0] === "id" && where.id != null) {
|
|
56
|
-
const items = await getItemByIds([where.id], ctx);
|
|
57
|
+
const items = await getItemByIds([where.id], ctx, args.include);
|
|
57
58
|
return {
|
|
58
59
|
nodes: [items[0]].filter(x => x),
|
|
59
60
|
cursor: null
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
if (whereKeys[0] === "id_in" && where.id_in != null) {
|
|
63
|
-
const items = await getItemByIds(where.id_in, ctx);
|
|
64
|
+
const items = await getItemByIds(where.id_in, ctx, args.include);
|
|
64
65
|
return {
|
|
65
66
|
nodes: items.filter(x => x),
|
|
66
67
|
cursor: null
|
|
@@ -153,15 +154,12 @@ function getCosmosQuery(schema, entity, args) {
|
|
|
153
154
|
schema,
|
|
154
155
|
entity
|
|
155
156
|
}, parameters, where)].filter(x => x);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const orderDirection = orderByParts.at(-1);
|
|
161
|
-
const orderProp = orderPropFromOrderBy === "value" ? `r["value"]` : `r.${orderPropFromOrderBy}`;
|
|
162
|
-
orderByClause = `order by ${orderProp} ${orderDirection}`;
|
|
157
|
+
const orderByClause = getCosmosOrderBy(args);
|
|
158
|
+
let colums = "*";
|
|
159
|
+
if (args.include?._pick) {
|
|
160
|
+
colums = getCosmosSelectValue(args.include);
|
|
163
161
|
}
|
|
164
|
-
const query = `select
|
|
162
|
+
const query = `select ${colums} from r where ${whereClauses.join(" AND ")} ${orderByClause}`;
|
|
165
163
|
return {
|
|
166
164
|
query,
|
|
167
165
|
parameters
|
|
@@ -461,6 +459,28 @@ const operatorHandlers = {
|
|
|
461
459
|
return `${namePrefix}${name} <= @${pn}`;
|
|
462
460
|
}
|
|
463
461
|
};
|
|
462
|
+
function getCosmosOrderBy(args) {
|
|
463
|
+
let orderByClause = "";
|
|
464
|
+
if (args.orderByArray) {
|
|
465
|
+
orderByClause = `order by `;
|
|
466
|
+
const orderByColumns = [];
|
|
467
|
+
for (const order of args.orderByArray) {
|
|
468
|
+
orderByColumns.push(parseOrderBy(order));
|
|
469
|
+
}
|
|
470
|
+
orderByClause = orderByClause + orderByColumns.join(",");
|
|
471
|
+
} else if (args.orderBy) {
|
|
472
|
+
orderByClause = `order by ${parseOrderBy(args.orderBy)}`;
|
|
473
|
+
}
|
|
474
|
+
return orderByClause;
|
|
475
|
+
}
|
|
476
|
+
function parseOrderBy(order) {
|
|
477
|
+
const orderByParts = order.split("_");
|
|
478
|
+
const orderPropFromOrderBy = orderByParts.slice(0, -1).join(".");
|
|
479
|
+
const orderDirection = orderByParts.at(-1);
|
|
480
|
+
const orderProp = orderPropFromOrderBy === "value" ? `r["value"]` : `r.${orderPropFromOrderBy}`;
|
|
481
|
+
const ordr = `${orderProp} ${orderDirection}`;
|
|
482
|
+
return ordr;
|
|
483
|
+
}
|
|
464
484
|
function getCosmosQueryWhere(ctx, parameters, where, namePrefix = "r.", paramNamePrefix = "") {
|
|
465
485
|
const whereClauses = [];
|
|
466
486
|
for (const key in where) {
|
|
@@ -589,4 +609,27 @@ async function bulkSendWithRetry(client, chunkToSend) {
|
|
|
589
609
|
});
|
|
590
610
|
}
|
|
591
611
|
return responses;
|
|
612
|
+
}
|
|
613
|
+
function buildSelectValue(includeArgs, path = "r") {
|
|
614
|
+
const parts = [];
|
|
615
|
+
if (Array.isArray(includeArgs._pick)) {
|
|
616
|
+
for (const key of includeArgs._pick) {
|
|
617
|
+
parts.push(`${key}: ${path}.${key}`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
for (const key of Object.keys(includeArgs)) {
|
|
621
|
+
if (key === "_pick") continue;
|
|
622
|
+
const nested = includeArgs[key];
|
|
623
|
+
if (typeof nested === "object" && nested !== null) {
|
|
624
|
+
const nestedSelect = buildSelectValue(nested, `${path}.${key}`);
|
|
625
|
+
parts.push(`${key}: { ${nestedSelect} }`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return parts.join(", ");
|
|
629
|
+
}
|
|
630
|
+
function getCosmosSelectValue(includeArgs) {
|
|
631
|
+
const projection = buildSelectValue(includeArgs);
|
|
632
|
+
return `VALUE {
|
|
633
|
+
${projection}
|
|
634
|
+
} `;
|
|
592
635
|
}
|
package/drivers/azureCosmos.d.ts
CHANGED