@bedrockio/model 0.1.17 → 0.1.19

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.
@@ -28,7 +28,7 @@ function unsetReferenceFields(fields, schema = {}) {
28
28
  if (!value && (0, _utils.isReferenceField)(schema, key)) {
29
29
  fields[key] = undefined;
30
30
  } else if (value && typeof value === 'object') {
31
- unsetReferenceFields(value, (0, _utils.resolveField)(schema, key));
31
+ unsetReferenceFields(value, (0, _utils.getField)(schema, key));
32
32
  }
33
33
  }
34
34
  }
@@ -218,7 +218,7 @@ function setNodePath(node, options) {
218
218
  let halt = false;
219
219
  for (let [key, type] of resolvePaths(schema, str)) {
220
220
  if (type === 'real') {
221
- const field = (0, _utils.resolveInnerField)(schema.obj, key);
221
+ const field = (0, _utils.getInnerField)(schema.obj, key);
222
222
  // Only exclude the field if the match is exact, ie:
223
223
  // -name - Exclude "name"
224
224
  // -user.name - Implies population of "user" but exclude "user.name",
@@ -256,8 +256,8 @@ function resolvePaths(schema, str) {
256
256
  source = source.replaceAll('\\*', '[^.]+');
257
257
  source = `^${source}$`;
258
258
  const reg = RegExp(source);
259
- paths = Object.keys(schema.paths || {}).filter(path => {
260
- return !path.startsWith('_') && reg.test(path);
259
+ paths = getSchemaPaths(schema).filter(path => {
260
+ return reg.test(path);
261
261
  });
262
262
  } else {
263
263
  paths = [str];
@@ -265,4 +265,17 @@ function resolvePaths(schema, str) {
265
265
  return paths.map(path => {
266
266
  return [path, schema.pathType(path)];
267
267
  });
268
+ }
269
+ function getSchemaPaths(schema) {
270
+ return Object.entries(schema.paths || {}).flatMap(([key, schema]) => {
271
+ if (key.startsWith('_')) {
272
+ return [];
273
+ } else if (schema.schema) {
274
+ return getSchemaPaths(schema.schema).map(path => {
275
+ return [key, path].join('.');
276
+ });
277
+ } else {
278
+ return [key];
279
+ }
280
+ });
268
281
  }
@@ -227,7 +227,7 @@ function normalizeQuery(query, schema, root = {}, rootPath = []) {
227
227
  root[path.join('.')] = mapOperatorQuery(value);
228
228
  }
229
229
  } else if (isNestedQuery(key, value)) {
230
- normalizeQuery(value, (0, _utils.resolveField)(schema, key), root, path);
230
+ normalizeQuery(value, (0, _utils.getField)(schema, key), root, path);
231
231
  } else if (isRegexQuery(key, value)) {
232
232
  root[path.join('.')] = parseRegexQuery(value);
233
233
  } else if (isArrayQuery(key, value)) {
@@ -28,7 +28,7 @@ function transformField(obj, field, options) {
28
28
  if (!isAllowedField(key, field, options)) {
29
29
  delete obj[key];
30
30
  } else {
31
- transformField(val, (0, _utils.resolveField)(field, key), options);
31
+ transformField(val, (0, _utils.getInnerField)(field, key), options);
32
32
  }
33
33
  }
34
34
  }
@@ -44,7 +44,7 @@ function isAllowedField(key, field, options) {
44
44
  } else {
45
45
  const {
46
46
  readAccess
47
- } = (0, _utils.resolveField)(field, key);
47
+ } = (0, _utils.getField)(field, key);
48
48
  try {
49
49
  return (0, _access.hasReadAccess)(readAccess, options);
50
50
  } catch {
package/dist/cjs/utils.js CHANGED
@@ -3,13 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.getField = getField;
7
+ exports.getInnerField = getInnerField;
6
8
  exports.isDateField = isDateField;
7
9
  exports.isMongooseSchema = isMongooseSchema;
8
10
  exports.isNumberField = isNumberField;
9
11
  exports.isReferenceField = isReferenceField;
10
12
  exports.isSchemaTypedef = isSchemaTypedef;
11
- exports.resolveField = resolveField;
12
- exports.resolveInnerField = resolveInnerField;
13
13
  var _mongoose = _interopRequireDefault(require("mongoose"));
14
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
15
  function isMongooseSchema(obj) {
@@ -27,47 +27,63 @@ function isNumberField(obj, path) {
27
27
  function isType(obj, path, test) {
28
28
  const {
29
29
  type
30
- } = resolveInnerField(obj, path);
30
+ } = getInnerField(obj, path);
31
31
  return type === test || type === _mongoose.default.Schema.Types[test];
32
32
  }
33
33
  function isSchemaTypedef(arg) {
34
34
  // Has a type defined and is not a literal type field.
35
- return arg?.type && !arg.type?.type;
35
+ return !!arg?.type && !arg.type?.type;
36
36
  }
37
37
 
38
- // Note: Resolved field may be an object or a function
39
- // from mongoose.Schema.Types that is resolved from the
40
- // shorthand: field: 'String'.
41
- function resolveField(obj, path) {
42
- let typedef = obj;
43
- for (let key of path.split('.')) {
44
- typedef = resolveFieldForKey(typedef, key);
38
+ // Gets the schema "field". For a structure like below:
39
+ // {
40
+ // products: {
41
+ // type: [
42
+ // {
43
+ // inventory: {
44
+ // type: [
45
+ // {
46
+ // type: 'Number',
47
+ // },
48
+ // ],
49
+ // writeAccess: 'none',
50
+ // },
51
+ // },
52
+ // ],
53
+ // },
54
+ // }
55
+ //
56
+ // Given a path "products.inventory" it will return the inner
57
+ // "inventory" field. It must traverse into arrays and other mongoose
58
+ // schemas along the way except for the final field.
59
+ function getField(obj, path) {
60
+ let field = obj;
61
+ if (typeof path === 'string') {
62
+ path = path.split('.');
45
63
  }
46
- return typedef;
64
+ path.forEach((key, i) => {
65
+ field = field[key];
66
+ if (i < path.length - 1) {
67
+ field = resolveInnerField(field);
68
+ }
69
+ });
70
+ return field || {};
47
71
  }
48
72
 
49
- // The same as resolveField but gets the element
50
- // typedef in the case of arrays.
51
- function resolveInnerField(obj, path) {
52
- let typedef = resolveField(obj, path);
53
- if (Array.isArray(typedef.type)) {
54
- typedef = typedef.type[0];
55
- }
56
- return typedef;
73
+ // The same as getField but traverses into the final field
74
+ // as well. In the above example this will return:
75
+ // { type: 'Number' }, given "product.inventory"
76
+ function getInnerField(obj, path) {
77
+ return resolveInnerField(getField(obj, path));
57
78
  }
58
- function resolveFieldForKey(obj, key) {
59
- let typedef;
60
- if (isSchemaTypedef(obj)) {
61
- const {
62
- type
63
- } = obj;
64
- if (Array.isArray(type)) {
65
- typedef = type[0][key];
66
- } else {
67
- typedef = type[key];
68
- }
69
- } else {
70
- typedef = obj[key];
79
+ function resolveInnerField(field) {
80
+ if (Array.isArray(field?.type)) {
81
+ field = field.type[0];
82
+ }
83
+ if (field?.type instanceof _mongoose.default.Schema) {
84
+ field = field.type.obj;
85
+ } else if (field instanceof _mongoose.default.Schema) {
86
+ field = field.obj;
71
87
  }
72
- return typedef || {};
88
+ return field;
73
89
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/model",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "Bedrock utilities for model creation.",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/assign.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isPlainObject } from 'lodash';
2
2
 
3
- import { isReferenceField, resolveField } from './utils';
3
+ import { isReferenceField, getField } from './utils';
4
4
 
5
5
  export function applyAssign(schema) {
6
6
  schema.method('assign', function assign(fields) {
@@ -24,7 +24,7 @@ function unsetReferenceFields(fields, schema = {}) {
24
24
  if (!value && isReferenceField(schema, key)) {
25
25
  fields[key] = undefined;
26
26
  } else if (value && typeof value === 'object') {
27
- unsetReferenceFields(value, resolveField(schema, key));
27
+ unsetReferenceFields(value, getField(schema, key));
28
28
  }
29
29
  }
30
30
  }
package/src/include.js CHANGED
@@ -2,7 +2,7 @@ import mongoose from 'mongoose';
2
2
  import { escapeRegExp } from 'lodash';
3
3
  import yd from '@bedrockio/yada';
4
4
 
5
- import { resolveInnerField, isSchemaTypedef } from './utils';
5
+ import { getInnerField, isSchemaTypedef } from './utils';
6
6
  import { POPULATE_MAX_DEPTH } from './const';
7
7
 
8
8
  // @ts-ignore
@@ -202,7 +202,7 @@ function setNodePath(node, options) {
202
202
 
203
203
  for (let [key, type] of resolvePaths(schema, str)) {
204
204
  if (type === 'real') {
205
- const field = resolveInnerField(schema.obj, key);
205
+ const field = getInnerField(schema.obj, key);
206
206
  // Only exclude the field if the match is exact, ie:
207
207
  // -name - Exclude "name"
208
208
  // -user.name - Implies population of "user" but exclude "user.name",
@@ -242,8 +242,8 @@ function resolvePaths(schema, str) {
242
242
  source = source.replaceAll('\\*', '[^.]+');
243
243
  source = `^${source}$`;
244
244
  const reg = RegExp(source);
245
- paths = Object.keys(schema.paths || {}).filter((path) => {
246
- return !path.startsWith('_') && reg.test(path);
245
+ paths = getSchemaPaths(schema).filter((path) => {
246
+ return reg.test(path);
247
247
  });
248
248
  } else {
249
249
  paths = [str];
@@ -252,3 +252,17 @@ function resolvePaths(schema, str) {
252
252
  return [path, schema.pathType(path)];
253
253
  });
254
254
  }
255
+
256
+ function getSchemaPaths(schema) {
257
+ return Object.entries(schema.paths || {}).flatMap(([key, schema]) => {
258
+ if (key.startsWith('_')) {
259
+ return [];
260
+ } else if (schema.schema) {
261
+ return getSchemaPaths(schema.schema).map((path) => {
262
+ return [key, path].join('.');
263
+ });
264
+ } else {
265
+ return [key];
266
+ }
267
+ });
268
+ }
package/src/search.js CHANGED
@@ -3,7 +3,7 @@ import logger from '@bedrockio/logger';
3
3
  import mongoose from 'mongoose';
4
4
  import { pick, isEmpty, isPlainObject } from 'lodash';
5
5
 
6
- import { isDateField, isNumberField, resolveField } from './utils';
6
+ import { isDateField, isNumberField, getField } from './utils';
7
7
  import { SEARCH_DEFAULTS } from './const';
8
8
  import { OBJECT_ID_SCHEMA } from './validation';
9
9
  import { debug } from './env';
@@ -239,7 +239,7 @@ function normalizeQuery(query, schema, root = {}, rootPath = []) {
239
239
  root[path.join('.')] = mapOperatorQuery(value);
240
240
  }
241
241
  } else if (isNestedQuery(key, value)) {
242
- normalizeQuery(value, resolveField(schema, key), root, path);
242
+ normalizeQuery(value, getField(schema, key), root, path);
243
243
  } else if (isRegexQuery(key, value)) {
244
244
  root[path.join('.')] = parseRegexQuery(value);
245
245
  } else if (isArrayQuery(key, value)) {
@@ -2,7 +2,7 @@ import { isPlainObject } from 'lodash';
2
2
 
3
3
  import { checkSelects } from './include';
4
4
  import { hasReadAccess } from './access';
5
- import { resolveField } from './utils';
5
+ import { getField, getInnerField } from './utils';
6
6
 
7
7
  export const serializeOptions = {
8
8
  getters: true,
@@ -24,7 +24,7 @@ function transformField(obj, field, options) {
24
24
  if (!isAllowedField(key, field, options)) {
25
25
  delete obj[key];
26
26
  } else {
27
- transformField(val, resolveField(field, key), options);
27
+ transformField(val, getInnerField(field, key), options);
28
28
  }
29
29
  }
30
30
  }
@@ -39,7 +39,7 @@ function isAllowedField(key, field, options) {
39
39
  // to false and should not be exposed.
40
40
  return false;
41
41
  } else {
42
- const { readAccess } = resolveField(field, key);
42
+ const { readAccess } = getField(field, key);
43
43
  try {
44
44
  return hasReadAccess(readAccess, options);
45
45
  } catch {
package/src/utils.js CHANGED
@@ -17,47 +17,65 @@ export function isNumberField(obj, path) {
17
17
  }
18
18
 
19
19
  function isType(obj, path, test) {
20
- const { type } = resolveInnerField(obj, path);
20
+ const { type } = getInnerField(obj, path);
21
21
  return type === test || type === mongoose.Schema.Types[test];
22
22
  }
23
23
 
24
24
  export function isSchemaTypedef(arg) {
25
25
  // Has a type defined and is not a literal type field.
26
- return arg?.type && !arg.type?.type;
26
+ return !!arg?.type && !arg.type?.type;
27
27
  }
28
28
 
29
- // Note: Resolved field may be an object or a function
30
- // from mongoose.Schema.Types that is resolved from the
31
- // shorthand: field: 'String'.
32
- export function resolveField(obj, path) {
33
- let typedef = obj;
34
- for (let key of path.split('.')) {
35
- typedef = resolveFieldForKey(typedef, key);
29
+ // Gets the schema "field". For a structure like below:
30
+ // {
31
+ // products: {
32
+ // type: [
33
+ // {
34
+ // inventory: {
35
+ // type: [
36
+ // {
37
+ // type: 'Number',
38
+ // },
39
+ // ],
40
+ // writeAccess: 'none',
41
+ // },
42
+ // },
43
+ // ],
44
+ // },
45
+ // }
46
+ //
47
+ // Given a path "products.inventory" it will return the inner
48
+ // "inventory" field. It must traverse into arrays and other mongoose
49
+ // schemas along the way except for the final field.
50
+ export function getField(obj, path) {
51
+ let field = obj;
52
+ if (typeof path === 'string') {
53
+ path = path.split('.');
36
54
  }
37
- return typedef;
55
+ path.forEach((key, i) => {
56
+ field = field[key];
57
+ if (i < path.length - 1) {
58
+ field = resolveInnerField(field);
59
+ }
60
+ });
61
+ return field || {};
38
62
  }
39
63
 
40
- // The same as resolveField but gets the element
41
- // typedef in the case of arrays.
42
- export function resolveInnerField(obj, path) {
43
- let typedef = resolveField(obj, path);
44
- if (Array.isArray(typedef.type)) {
45
- typedef = typedef.type[0];
46
- }
47
- return typedef;
64
+ // The same as getField but traverses into the final field
65
+ // as well. In the above example this will return:
66
+ // { type: 'Number' }, given "product.inventory"
67
+ export function getInnerField(obj, path) {
68
+ return resolveInnerField(getField(obj, path));
48
69
  }
49
70
 
50
- function resolveFieldForKey(obj, key) {
51
- let typedef;
52
- if (isSchemaTypedef(obj)) {
53
- const { type } = obj;
54
- if (Array.isArray(type)) {
55
- typedef = type[0][key];
56
- } else {
57
- typedef = type[key];
58
- }
59
- } else {
60
- typedef = obj[key];
71
+ function resolveInnerField(field) {
72
+ if (Array.isArray(field?.type)) {
73
+ field = field.type[0];
74
+ }
75
+ if (field?.type instanceof mongoose.Schema) {
76
+ field = field.type.obj;
77
+ } else if (field instanceof mongoose.Schema) {
78
+ field = field.obj;
61
79
  }
62
- return typedef || {};
80
+ return field;
63
81
  }
package/types/utils.d.ts CHANGED
@@ -3,6 +3,6 @@ export function isReferenceField(obj: any, path: any): boolean;
3
3
  export function isDateField(obj: any, path: any): boolean;
4
4
  export function isNumberField(obj: any, path: any): boolean;
5
5
  export function isSchemaTypedef(arg: any): boolean;
6
- export function resolveField(obj: any, path: any): any;
7
- export function resolveInnerField(obj: any, path: any): any;
6
+ export function getField(obj: any, path: any): any;
7
+ export function getInnerField(obj: any, path: any): any;
8
8
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAEA,oDAEC;AAED,+DAEC;AAED,0DAEC;AAED,4DAEC;AAOD,mDAGC;AAKD,uDAMC;AAID,4DAMC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAEA,oDAEC;AAED,+DAEC;AAED,0DAEC;AAED,4DAEC;AAOD,mDAGC;AAuBD,mDAYC;AAKD,wDAEC"}