rads-db 3.0.42 → 3.0.43

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
@@ -126,6 +126,20 @@ const operatorFns = {
126
126
  iendsWith: (x, w) => x?.toLowerCase()?.endsWith(w.toLowerCase()),
127
127
  contains: (x, w) => x?.includes(w),
128
128
  icontains: (x, w) => x?.toLowerCase()?.includes(w.toLowerCase()),
129
+ jsonContains: (x, w) => {
130
+ const { path, isNull, value } = w;
131
+ const val = ___default.get(x, path);
132
+ if (val === void 0)
133
+ return false;
134
+ if (isNull === false && val === null)
135
+ return false;
136
+ if (isNull === true && val !== null)
137
+ return false;
138
+ if (value != null && val !== value)
139
+ return false;
140
+ return true;
141
+ },
142
+ arrayContains: (x, w) => x?.includes(w),
129
143
  isNull: (x, w) => {
130
144
  if (w === true)
131
145
  return x == null;
package/dist/index.d.ts CHANGED
@@ -355,6 +355,15 @@ interface FileSystemNode {
355
355
  size?: number;
356
356
  type: 'blob' | 'tree';
357
357
  }
358
+ interface WhereJsonContains {
359
+ /** Checks for existence of this path inside json object
360
+ * Example: "meta.countries[0].name". */
361
+ path: string;
362
+ /** Checks if value from "path" is exactly null. Note: it is not the same as not having the key in the object. */
363
+ isNull?: boolean;
364
+ /** Checks if value from "path" equals provided value */
365
+ value?: number | string | boolean;
366
+ }
358
367
  type RadsUiSlotName = 'entityListActions' | 'entityActions' | 'fieldActions';
359
368
  interface RadsUiSlotDefinition {
360
369
  entityName?: string | {
@@ -411,4 +420,4 @@ declare function createRadsDb(args?: CreateRadsDbArgs): RadsDb;
411
420
  */
412
421
  declare function createRadsDbClient(args?: CreateRadsDbClientArgs): RadsDb;
413
422
 
414
- export { Change, ComputedContext, ComputedContextGlobal, ComputedDecoratorArgs, CreateRadsArgsDrivers, CreateRadsDbArgs, CreateRadsDbArgsNormalized, CreateRadsDbClientArgs, DeepPartial, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, EnumDefinition, FieldDecoratorArgs, FieldDefinition, FileSystemNode, FileUploadArgs, FileUploadDriver, FileUploadResult, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, MinimalDriver, PutArgs, PutEffect, RadsFeature, RadsHookDoc, RadsRequestContext, RadsUiSlotDefinition, RadsUiSlotName, RadsVitePluginOptions, Relation, RequiredFields, RestDriverOptions, RestFileUploadDriverOptions, Schema, SchemaValidators, TypeDefinition, UiDecoratorArgs, UiFieldDecoratorArgs, ValidateEntityDecoratorArgs, ValidateFieldDecoratorArgs, ValidateStringDecoratorArgs, VerifyManyArgs, VerifyManyArgsAny, VerifyManyResponse, cleanUndefinedAndNull, computed, createRadsDb, createRadsDbClient, diff, entity, field, getDriverInstance, handlePrecomputed, keepHistory, merge, precomputed, ui, validate };
423
+ export { Change, ComputedContext, ComputedContextGlobal, ComputedDecoratorArgs, CreateRadsArgsDrivers, CreateRadsDbArgs, CreateRadsDbArgsNormalized, CreateRadsDbClientArgs, DeepPartial, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, EnumDefinition, FieldDecoratorArgs, FieldDefinition, FileSystemNode, FileUploadArgs, FileUploadDriver, FileUploadResult, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, MinimalDriver, PutArgs, PutEffect, RadsFeature, RadsHookDoc, RadsRequestContext, RadsUiSlotDefinition, RadsUiSlotName, RadsVitePluginOptions, Relation, RequiredFields, RestDriverOptions, RestFileUploadDriverOptions, Schema, SchemaValidators, TypeDefinition, UiDecoratorArgs, UiFieldDecoratorArgs, ValidateEntityDecoratorArgs, ValidateFieldDecoratorArgs, ValidateStringDecoratorArgs, VerifyManyArgs, VerifyManyArgsAny, VerifyManyResponse, WhereJsonContains, cleanUndefinedAndNull, computed, createRadsDb, createRadsDbClient, diff, entity, field, getDriverInstance, handlePrecomputed, keepHistory, merge, precomputed, ui, validate };
package/dist/index.mjs CHANGED
@@ -118,6 +118,20 @@ const operatorFns = {
118
118
  iendsWith: (x, w) => x?.toLowerCase()?.endsWith(w.toLowerCase()),
119
119
  contains: (x, w) => x?.includes(w),
120
120
  icontains: (x, w) => x?.toLowerCase()?.includes(w.toLowerCase()),
121
+ jsonContains: (x, w) => {
122
+ const { path, isNull, value } = w;
123
+ const val = _.get(x, path);
124
+ if (val === void 0)
125
+ return false;
126
+ if (isNull === false && val === null)
127
+ return false;
128
+ if (isNull === true && val !== null)
129
+ return false;
130
+ if (value != null && val !== value)
131
+ return false;
132
+ return true;
133
+ },
134
+ arrayContains: (x, w) => x?.includes(w),
121
135
  isNull: (x, w) => {
122
136
  if (w === true)
123
137
  return x == null;
@@ -11,6 +11,7 @@ const cosmosClientCache = {};
11
11
  const databaseClientCache = {};
12
12
  const containerClientCache = {};
13
13
  const simpleSubclauseRegex = /^[a-z0-9_@]+.[a-z0-9_@]+ = [a-z0-9_@.]+$/i;
14
+ const sanitizePathRegex = /^[a-z0-9_\[\]\.]+$/i;
14
15
  var _default = options => (schema, entity) => {
15
16
  const normalizedOptions = {
16
17
  databaseName: "main",
@@ -326,12 +327,8 @@ const operatorHandlers = {
326
327
  paramNamePrefix,
327
328
  whereVal
328
329
  } = whereArgs;
329
- const fieldType = ctx.schema[ctx.entity].fields[ctx.field];
330
330
  const pn = `${paramNamePrefix}${paramName}`;
331
331
  parameters[pn] = whereVal;
332
- if (fieldType.isArray) {
333
- return `array_contains(${namePrefix}${name}, @${pn})`;
334
- }
335
332
  return `contains(${namePrefix}${name}, @${pn})`;
336
333
  },
337
334
  icontains: (ctx, parameters, whereArgs) => {
@@ -346,6 +343,49 @@ const operatorHandlers = {
346
343
  parameters[pn] = whereVal;
347
344
  return `contains(${namePrefix}${name}, @${pn}, true)`;
348
345
  },
346
+ arrayContains: (ctx, parameters, whereArgs) => {
347
+ const {
348
+ name,
349
+ namePrefix,
350
+ paramName,
351
+ paramNamePrefix,
352
+ whereVal
353
+ } = whereArgs;
354
+ const pn = `${paramNamePrefix}${paramName}`;
355
+ parameters[pn] = whereVal;
356
+ return `array_contains(${namePrefix}${name}, @${pn})`;
357
+ },
358
+ jsonContains: (ctx, parameters, whereArgs) => {
359
+ const {
360
+ name,
361
+ namePrefix,
362
+ paramName,
363
+ paramNamePrefix,
364
+ whereVal
365
+ } = whereArgs;
366
+ const {
367
+ path,
368
+ isNull,
369
+ value
370
+ } = whereVal;
371
+ if (!path) return "";
372
+ if (!sanitizePathRegex.test(path)) throw new Error(`Invalid path ${path}`);
373
+ const pn = `${paramNamePrefix}${paramName}`;
374
+ parameters[pn] = whereVal;
375
+ const fullPath = `${namePrefix}${name}.${path}`;
376
+ if (value != null) {
377
+ const valuePn = `${paramNamePrefix}${paramName}_value`;
378
+ parameters[valuePn] = value;
379
+ return `${fullPath} = @${valuePn}`;
380
+ }
381
+ if (isNull != null) {
382
+ if (isNull) {
383
+ return `${fullPath} = null`;
384
+ }
385
+ return `${fullPath} != null`;
386
+ }
387
+ return `is_defined(${fullPath})`;
388
+ },
349
389
  ieq: (ctx, parameters, whereArgs) => {
350
390
  const {
351
391
  name,
@@ -447,7 +487,10 @@ function getCosmosQueryWhereInner(ctx, parameters, whereArgs) {
447
487
  return getCosmosQueryWhere(ctx, parameters, whereVal, `${namePrefix}${name}.`, `${paramNamePrefix}${paramName}_`);
448
488
  }
449
489
  const fn = operatorHandlers[operator || "eq"];
450
- if (!fn) console.warn(`Unsupported operator: "${operator}"`);
490
+ if (!fn) {
491
+ console.warn(`Unsupported operator: "${operator}"`);
492
+ return null;
493
+ }
451
494
  return fn(ctx, parameters, whereArgs);
452
495
  }
453
496
  function getCosmosContainerClient(options) {
@@ -4,6 +4,7 @@ const cosmosClientCache = {};
4
4
  const databaseClientCache = {};
5
5
  const containerClientCache = {};
6
6
  const simpleSubclauseRegex = /^[a-z0-9_@]+.[a-z0-9_@]+ = [a-z0-9_@.]+$/i;
7
+ const sanitizePathRegex = /^[a-z0-9_\[\]\.]+$/i;
7
8
  export default (options) => (schema, entity) => {
8
9
  const normalizedOptions = {
9
10
  databaseName: "main",
@@ -205,12 +206,8 @@ const operatorHandlers = {
205
206
  },
206
207
  contains: (ctx, parameters, whereArgs) => {
207
208
  const { name, namePrefix, paramName, paramNamePrefix, whereVal } = whereArgs;
208
- const fieldType = ctx.schema[ctx.entity].fields[ctx.field];
209
209
  const pn = `${paramNamePrefix}${paramName}`;
210
210
  parameters[pn] = whereVal;
211
- if (fieldType.isArray) {
212
- return `array_contains(${namePrefix}${name}, @${pn})`;
213
- }
214
211
  return `contains(${namePrefix}${name}, @${pn})`;
215
212
  },
216
213
  icontains: (ctx, parameters, whereArgs) => {
@@ -219,6 +216,35 @@ const operatorHandlers = {
219
216
  parameters[pn] = whereVal;
220
217
  return `contains(${namePrefix}${name}, @${pn}, true)`;
221
218
  },
219
+ arrayContains: (ctx, parameters, whereArgs) => {
220
+ const { name, namePrefix, paramName, paramNamePrefix, whereVal } = whereArgs;
221
+ const pn = `${paramNamePrefix}${paramName}`;
222
+ parameters[pn] = whereVal;
223
+ return `array_contains(${namePrefix}${name}, @${pn})`;
224
+ },
225
+ jsonContains: (ctx, parameters, whereArgs) => {
226
+ const { name, namePrefix, paramName, paramNamePrefix, whereVal } = whereArgs;
227
+ const { path, isNull, value } = whereVal;
228
+ if (!path)
229
+ return "";
230
+ if (!sanitizePathRegex.test(path))
231
+ throw new Error(`Invalid path ${path}`);
232
+ const pn = `${paramNamePrefix}${paramName}`;
233
+ parameters[pn] = whereVal;
234
+ const fullPath = `${namePrefix}${name}.${path}`;
235
+ if (value != null) {
236
+ const valuePn = `${paramNamePrefix}${paramName}_value`;
237
+ parameters[valuePn] = value;
238
+ return `${fullPath} = @${valuePn}`;
239
+ }
240
+ if (isNull != null) {
241
+ if (isNull) {
242
+ return `${fullPath} = null`;
243
+ }
244
+ return `${fullPath} != null`;
245
+ }
246
+ return `is_defined(${fullPath})`;
247
+ },
222
248
  ieq: (ctx, parameters, whereArgs) => {
223
249
  const { name, namePrefix, paramName, paramNamePrefix, whereVal } = whereArgs;
224
250
  const pn = `${paramNamePrefix}${paramName}`;
@@ -282,8 +308,10 @@ function getCosmosQueryWhereInner(ctx, parameters, whereArgs) {
282
308
  return getCosmosQueryWhere(ctx, parameters, whereVal, `${namePrefix}${name}.`, `${paramNamePrefix}${paramName}_`);
283
309
  }
284
310
  const fn = operatorHandlers[operator || "eq"];
285
- if (!fn)
311
+ if (!fn) {
286
312
  console.warn(`Unsupported operator: "${operator}"`);
313
+ return null;
314
+ }
287
315
  return fn(ctx, parameters, whereArgs);
288
316
  }
289
317
  function getCosmosContainerClient(options) {
@@ -19,6 +19,20 @@ const operatorFns = {
19
19
  iendsWith: (x, w) => x?.toLowerCase()?.endsWith(w.toLowerCase()),
20
20
  contains: (x, w) => x?.includes(w),
21
21
  icontains: (x, w) => x?.toLowerCase()?.includes(w.toLowerCase()),
22
+ jsonContains: (x, w) => {
23
+ const {
24
+ path,
25
+ isNull,
26
+ value
27
+ } = w;
28
+ const val = _lodash.default.get(x, path);
29
+ if (val === void 0) return false;
30
+ if (isNull === false && val === null) return false;
31
+ if (isNull === true && val !== null) return false;
32
+ if (value != null && val !== value) return false;
33
+ return true;
34
+ },
35
+ arrayContains: (x, w) => x?.includes(w),
22
36
  isNull: (x, w) => {
23
37
  if (w === true) return x == null;
24
38
  if (w === false) return x != null;
@@ -9,6 +9,20 @@ const operatorFns = {
9
9
  iendsWith: (x, w) => x?.toLowerCase()?.endsWith(w.toLowerCase()),
10
10
  contains: (x, w) => x?.includes(w),
11
11
  icontains: (x, w) => x?.toLowerCase()?.includes(w.toLowerCase()),
12
+ jsonContains: (x, w) => {
13
+ const { path, isNull, value } = w;
14
+ const val = _.get(x, path);
15
+ if (val === void 0)
16
+ return false;
17
+ if (isNull === false && val === null)
18
+ return false;
19
+ if (isNull === true && val !== null)
20
+ return false;
21
+ if (value != null && val !== value)
22
+ return false;
23
+ return true;
24
+ },
25
+ arrayContains: (x, w) => x?.includes(w),
12
26
  isNull: (x, w) => {
13
27
  if (w === true)
14
28
  return x == null;
@@ -137,7 +137,7 @@ ${whereFields.join("\n")}
137
137
  }
138
138
  `.trim()).join("\n");
139
139
  return `
140
- import type { EntityMethods, FileUploadArgs, RadsRequestContext } from 'rads-db'
140
+ import type { EntityMethods, FileUploadArgs, RadsRequestContext, WhereJsonContains } from 'rads-db'
141
141
  ${imports.join("\n")}
142
142
  ${schemaTypesStr}
143
143
 
@@ -211,7 +211,7 @@ function getWhereFieldsFor(schema, type, fieldKey) {
211
211
  const arrayWhereFields = [`${name}_isEmpty?: boolean`];
212
212
  if (!isRequired) arrayWhereFields.push(`${name}_isNull?: boolean`);
213
213
  if (isPrimitive || isEnum) {
214
- return [`${name}_contains?: ${fieldTypeName}`, ...arrayWhereFields];
214
+ return [`${name}_arrayContains?: ${fieldTypeName}`, ...arrayWhereFields];
215
215
  }
216
216
  if (isRelation) {
217
217
  return [`${name}_some?: ${getRelationWhereType()}`, ...arrayWhereFields];
@@ -257,6 +257,9 @@ function getWhereFieldsForPrimitive(schema, type, fieldKey) {
257
257
  if (field.type === "Record<string, string>") {
258
258
  return [];
259
259
  }
260
+ if (field.type === "Record<string, any>") {
261
+ return [`${name}_jsonContains?: WhereJsonContains`];
262
+ }
260
263
  throw new Error(`Unknown primitive type: ${field.type}`);
261
264
  }
262
265
  function getWhereFieldsForString(name) {
@@ -137,7 +137,7 @@ ${whereFields.join("\n")}
137
137
  `.trim()
138
138
  ).join("\n");
139
139
  return `
140
- import type { EntityMethods, FileUploadArgs, RadsRequestContext } from 'rads-db'
140
+ import type { EntityMethods, FileUploadArgs, RadsRequestContext, WhereJsonContains } from 'rads-db'
141
141
  ${imports.join("\n")}
142
142
  ${schemaTypesStr}
143
143
 
@@ -218,7 +218,7 @@ function getWhereFieldsFor(schema, type, fieldKey) {
218
218
  if (!isRequired)
219
219
  arrayWhereFields.push(`${name}_isNull?: boolean`);
220
220
  if (isPrimitive || isEnum) {
221
- return [`${name}_contains?: ${fieldTypeName}`, ...arrayWhereFields];
221
+ return [`${name}_arrayContains?: ${fieldTypeName}`, ...arrayWhereFields];
222
222
  }
223
223
  if (isRelation) {
224
224
  return [`${name}_some?: ${getRelationWhereType()}`, ...arrayWhereFields];
@@ -273,6 +273,9 @@ function getWhereFieldsForPrimitive(schema, type, fieldKey) {
273
273
  if (field.type === "Record<string, string>") {
274
274
  return [];
275
275
  }
276
+ if (field.type === "Record<string, any>") {
277
+ return [`${name}_jsonContains?: WhereJsonContains`];
278
+ }
276
279
  throw new Error(`Unknown primitive type: ${field.type}`);
277
280
  }
278
281
  function getWhereFieldsForString(name) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rads-db",
3
- "version": "3.0.42",
3
+ "version": "3.0.43",
4
4
  "files": [
5
5
  "dist",
6
6
  "drivers",
@@ -109,7 +109,7 @@
109
109
  "generate-test-schema": "ts-node ./src/integrations/cli -d './test/entities'",
110
110
  "dev": "pnpm install && pnpm link-rads-db && pnpm build && pnpm generate-test-schema && vitest --ui --test-timeout 300000",
111
111
  "lint": "cross-env NODE_ENV=production eslint src/**/*.* test/**/*.*",
112
- "dev-typecheck": "pnpm install && pnpm build && pnpm generate-test-schema && pnpm link-rads-db && vitest typecheck --ui",
112
+ "dev-typecheck": "pnpm install && pnpm build && pnpm generate-test-schema && pnpm link-rads-db && vitest typecheck",
113
113
  "build": "unbuild"
114
114
  }
115
115
  }