@bedrockio/model 0.1.8 → 0.1.9

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.
@@ -3,7 +3,6 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.RESERVED_FIELDS = void 0;
7
6
  exports.createSchema = createSchema;
8
7
  exports.normalizeAttributes = normalizeAttributes;
9
8
  var _mongoose = _interopRequireDefault(require("mongoose"));
@@ -19,8 +18,6 @@ var _softDelete = require("./soft-delete");
19
18
  var _disallowed = require("./disallowed");
20
19
  var _validation = require("./validation");
21
20
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
- const RESERVED_FIELDS = ['createdAt', 'updatedAt', 'deletedAt', 'deleted'];
23
-
24
21
  /**
25
22
  * Creates a new Mongoose schema with Bedrock extensions
26
23
  * applied. For more about syntax and functionality see
@@ -29,7 +26,6 @@ const RESERVED_FIELDS = ['createdAt', 'updatedAt', 'deletedAt', 'deleted'];
29
26
  * @param {mongoose.SchemaOptions} options
30
27
  * @returns mongoose.Schema
31
28
  */
32
- exports.RESERVED_FIELDS = RESERVED_FIELDS;
33
29
  function createSchema(definition, options = {}) {
34
30
  const schema = new _mongoose.default.Schema(attributesToMongoose(normalizeAttributes({
35
31
  ...definition.attributes,
@@ -16,10 +16,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
16
16
  const {
17
17
  ObjectId
18
18
  } = _mongoose.default.Types;
19
- const SORT_SCHEMA = _yada.default.object({
20
- field: _yada.default.string().required(),
21
- order: _yada.default.string().allow('desc', 'asc').required()
22
- }).description('An object describing the sort order of results.');
23
19
  function applySearch(schema, definition) {
24
20
  validateDefinition(definition);
25
21
  schema.static('search', function search(body = {}) {
@@ -47,7 +43,7 @@ function applySearch(schema, definition) {
47
43
  Object.assign(query, buildKeywordQuery(keyword, fields));
48
44
  }
49
45
  Object.assign(query, normalizeQuery(rest, schema.obj));
50
- const mQuery = this.find(query).sort(resolveSort(sort)).skip(skip).limit(limit);
46
+ const mQuery = this.find(query).sort(resolveSort(sort, schema)).skip(skip).limit(limit);
51
47
 
52
48
  // The following construct is awkward but it allows the mongoose query
53
49
  // object to be returned while still ultimately resolving with metadata
@@ -73,36 +69,54 @@ function applySearch(schema, definition) {
73
69
  return mQuery;
74
70
  });
75
71
  }
76
- function searchValidation(definition, options = {}) {
77
- options = {
72
+ function searchValidation(options = {}) {
73
+ const {
74
+ defaults,
75
+ definition,
76
+ appendSchema
77
+ } = options;
78
+ const searchOptions = {
78
79
  ..._const.SEARCH_DEFAULTS,
79
80
  ...(0, _lodash.pick)(definition.search, 'limit', 'sort'),
80
- ...options
81
+ ...defaults
81
82
  };
82
83
  const {
83
84
  limit,
84
- sort,
85
- ...rest
86
- } = options;
85
+ sort
86
+ } = searchOptions;
87
87
  return _yada.default.object({
88
88
  ids: _yada.default.array(_validation.OBJECT_ID_SCHEMA),
89
89
  keyword: _yada.default.string().description('A keyword to perform a text search against.'),
90
90
  skip: _yada.default.number().default(0).description('Number of records to skip.'),
91
- sort: _yada.default.allow(SORT_SCHEMA, _yada.default.array(SORT_SCHEMA)).default(sort),
91
+ sort: getSortSchema(sort),
92
92
  limit: _yada.default.number().positive().default(limit).description('Limits the number of results.'),
93
- ...rest
93
+ ...appendSchema
94
94
  });
95
95
  }
96
+ function getSortSchema(sort) {
97
+ const schema = _yada.default.object({
98
+ field: _yada.default.string().required(),
99
+ order: _yada.default.string().allow('desc', 'asc').required()
100
+ }).description('An object describing the sort order of results.');
101
+ return _yada.default.allow(schema, _yada.default.array(schema)).default(sort);
102
+ }
96
103
  function validateDefinition(definition) {
97
104
  if (Array.isArray(definition.search)) {
98
105
  (0, _warn.default)(['"search" field on model definition must not be an array.', 'Use "search.fields" to define fields for keyword queries.'].join('\n'));
99
106
  throw new Error('Invalid model definition.');
100
107
  }
101
108
  }
102
- function resolveSort(sort) {
109
+ function resolveSort(sort, schema) {
103
110
  if (!Array.isArray(sort)) {
104
111
  sort = [sort];
105
112
  }
113
+ for (let {
114
+ field
115
+ } of sort) {
116
+ if (!schema.path(field)) {
117
+ throw new Error(`Unknown sort field "${field}".`);
118
+ }
119
+ }
106
120
  return sort.map(({
107
121
  field,
108
122
  order
@@ -17,7 +17,6 @@ var _search = require("./search");
17
17
  var _errors = require("./errors");
18
18
  var _softDelete = require("./soft-delete");
19
19
  var _utils = require("./utils");
20
- var _schema = require("./schema");
21
20
  var _include = require("./include");
22
21
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
22
  const DATE_SCHEMA = _yada.default.date().iso().tag({
@@ -76,7 +75,8 @@ function applyValidation(schema, definition) {
76
75
  model: this,
77
76
  appendSchema,
78
77
  allowIncludes: true,
79
- stripReserved: true,
78
+ stripDeleted: true,
79
+ stripTimestamps: true,
80
80
  requireWriteAccess: true,
81
81
  ...(hasUnique && {
82
82
  assertUniqueOptions: {
@@ -91,8 +91,9 @@ function applyValidation(schema, definition) {
91
91
  model: this,
92
92
  appendSchema,
93
93
  skipRequired: true,
94
- stripReserved: true,
95
94
  stripUnknown: true,
95
+ stripDeleted: true,
96
+ stripTimestamps: true,
96
97
  requireWriteAccess: true,
97
98
  ...(hasUnique && {
98
99
  assertUniqueOptions: {
@@ -102,36 +103,57 @@ function applyValidation(schema, definition) {
102
103
  })
103
104
  });
104
105
  });
105
- schema.static('getSearchValidation', function getSearchValidation(searchOptions) {
106
+ schema.static('getSearchValidation', function getSearchValidation(options = {}) {
107
+ const {
108
+ defaults,
109
+ includeDeleted,
110
+ ...appendSchema
111
+ } = options;
106
112
  return getSchemaFromMongoose(schema, {
113
+ model: this,
107
114
  allowSearch: true,
108
115
  skipRequired: true,
109
116
  allowIncludes: true,
110
117
  expandDotSyntax: true,
111
118
  unwindArrayFields: true,
112
119
  requireReadAccess: true,
113
- appendSchema: (0, _search.searchValidation)(definition, searchOptions),
114
- model: this
120
+ stripDeleted: !includeDeleted,
121
+ appendSchema: (0, _search.searchValidation)({
122
+ defaults,
123
+ definition,
124
+ appendSchema
125
+ })
115
126
  });
116
127
  });
117
128
  schema.static('getIncludeValidation', function getIncludeValidation() {
118
129
  return _include.INCLUDE_FIELD_SCHEMA;
119
130
  });
120
131
  schema.static('getBaseSchema', function getBaseSchema() {
121
- return getSchemaFromMongoose(schema);
132
+ return getSchemaFromMongoose(schema, {
133
+ stripDeleted: true
134
+ });
122
135
  });
123
136
  }
124
137
 
125
138
  // Yada schemas
126
139
 
127
140
  function getSchemaFromMongoose(schema, options = {}) {
128
- let {
129
- obj
130
- } = schema;
131
- if (options.stripReserved) {
132
- obj = (0, _lodash.omit)(obj, _schema.RESERVED_FIELDS);
141
+ const fields = getMongooseFields(schema, options);
142
+ return getValidationSchema(fields, options);
143
+ }
144
+ function getMongooseFields(schema, options) {
145
+ const {
146
+ stripTimestamps,
147
+ stripDeleted
148
+ } = options;
149
+ let fields = schema.obj;
150
+ if (stripTimestamps) {
151
+ fields = (0, _lodash.omit)(fields, ['createdAt', 'updatedAt']);
152
+ }
153
+ if (stripDeleted) {
154
+ fields = (0, _lodash.omit)(fields, ['deleted', 'deletedAt']);
133
155
  }
134
- return getValidationSchema(obj, options);
156
+ return fields;
135
157
  }
136
158
 
137
159
  // Exported for testing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/model",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Bedrock utilities for model creation.",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/schema.js CHANGED
@@ -18,13 +18,6 @@ import {
18
18
  getTupleValidator,
19
19
  } from './validation';
20
20
 
21
- export const RESERVED_FIELDS = [
22
- 'createdAt',
23
- 'updatedAt',
24
- 'deletedAt',
25
- 'deleted',
26
- ];
27
-
28
21
  /**
29
22
  * Creates a new Mongoose schema with Bedrock extensions
30
23
  * applied. For more about syntax and functionality see
package/src/search.js CHANGED
@@ -10,13 +10,6 @@ import warn from './warn';
10
10
 
11
11
  const { ObjectId } = mongoose.Types;
12
12
 
13
- const SORT_SCHEMA = yd
14
- .object({
15
- field: yd.string().required(),
16
- order: yd.string().allow('desc', 'asc').required(),
17
- })
18
- .description('An object describing the sort order of results.');
19
-
20
13
  export function applySearch(schema, definition) {
21
14
  validateDefinition(definition);
22
15
 
@@ -42,7 +35,7 @@ export function applySearch(schema, definition) {
42
35
  Object.assign(query, normalizeQuery(rest, schema.obj));
43
36
 
44
37
  const mQuery = this.find(query)
45
- .sort(resolveSort(sort))
38
+ .sort(resolveSort(sort, schema))
46
39
  .skip(skip)
47
40
  .limit(limit);
48
41
 
@@ -76,14 +69,16 @@ export function applySearch(schema, definition) {
76
69
  });
77
70
  }
78
71
 
79
- export function searchValidation(definition, options = {}) {
80
- options = {
72
+ export function searchValidation(options = {}) {
73
+ const { defaults, definition, appendSchema } = options;
74
+
75
+ const searchOptions = {
81
76
  ...SEARCH_DEFAULTS,
82
77
  ...pick(definition.search, 'limit', 'sort'),
83
- ...options,
78
+ ...defaults,
84
79
  };
85
80
 
86
- const { limit, sort, ...rest } = options;
81
+ const { limit, sort } = searchOptions;
87
82
 
88
83
  return yd.object({
89
84
  ids: yd.array(OBJECT_ID_SCHEMA),
@@ -91,16 +86,26 @@ export function searchValidation(definition, options = {}) {
91
86
  .string()
92
87
  .description('A keyword to perform a text search against.'),
93
88
  skip: yd.number().default(0).description('Number of records to skip.'),
94
- sort: yd.allow(SORT_SCHEMA, yd.array(SORT_SCHEMA)).default(sort),
89
+ sort: getSortSchema(sort),
95
90
  limit: yd
96
91
  .number()
97
92
  .positive()
98
93
  .default(limit)
99
94
  .description('Limits the number of results.'),
100
- ...rest,
95
+ ...appendSchema,
101
96
  });
102
97
  }
103
98
 
99
+ function getSortSchema(sort) {
100
+ const schema = yd
101
+ .object({
102
+ field: yd.string().required(),
103
+ order: yd.string().allow('desc', 'asc').required(),
104
+ })
105
+ .description('An object describing the sort order of results.');
106
+ return yd.allow(schema, yd.array(schema)).default(sort);
107
+ }
108
+
104
109
  function validateDefinition(definition) {
105
110
  if (Array.isArray(definition.search)) {
106
111
  warn(
@@ -113,10 +118,15 @@ function validateDefinition(definition) {
113
118
  }
114
119
  }
115
120
 
116
- function resolveSort(sort) {
121
+ function resolveSort(sort, schema) {
117
122
  if (!Array.isArray(sort)) {
118
123
  sort = [sort];
119
124
  }
125
+ for (let { field } of sort) {
126
+ if (!schema.path(field)) {
127
+ throw new Error(`Unknown sort field "${field}".`);
128
+ }
129
+ }
120
130
  return sort.map(({ field, order }) => {
121
131
  return [field, order === 'desc' ? -1 : 1];
122
132
  });
package/src/validation.js CHANGED
@@ -8,7 +8,6 @@ import { searchValidation } from './search';
8
8
  import { PermissionsError, ImplementationError } from './errors';
9
9
  import { hasUniqueConstraints, assertUnique } from './soft-delete';
10
10
  import { isMongooseSchema, isSchemaTypedef } from './utils';
11
- import { RESERVED_FIELDS } from './schema';
12
11
  import { INCLUDE_FIELD_SCHEMA } from './include';
13
12
 
14
13
  const DATE_SCHEMA = yd.date().iso().tag({
@@ -78,7 +77,8 @@ export function applyValidation(schema, definition) {
78
77
  model: this,
79
78
  appendSchema,
80
79
  allowIncludes: true,
81
- stripReserved: true,
80
+ stripDeleted: true,
81
+ stripTimestamps: true,
82
82
  requireWriteAccess: true,
83
83
  ...(hasUnique && {
84
84
  assertUniqueOptions: {
@@ -97,8 +97,9 @@ export function applyValidation(schema, definition) {
97
97
  model: this,
98
98
  appendSchema,
99
99
  skipRequired: true,
100
- stripReserved: true,
101
100
  stripUnknown: true,
101
+ stripDeleted: true,
102
+ stripTimestamps: true,
102
103
  requireWriteAccess: true,
103
104
  ...(hasUnique && {
104
105
  assertUniqueOptions: {
@@ -112,16 +113,23 @@ export function applyValidation(schema, definition) {
112
113
 
113
114
  schema.static(
114
115
  'getSearchValidation',
115
- function getSearchValidation(searchOptions) {
116
+ function getSearchValidation(options = {}) {
117
+ const { defaults, includeDeleted, ...appendSchema } = options;
118
+
116
119
  return getSchemaFromMongoose(schema, {
120
+ model: this,
117
121
  allowSearch: true,
118
122
  skipRequired: true,
119
123
  allowIncludes: true,
120
124
  expandDotSyntax: true,
121
125
  unwindArrayFields: true,
122
126
  requireReadAccess: true,
123
- appendSchema: searchValidation(definition, searchOptions),
124
- model: this,
127
+ stripDeleted: !includeDeleted,
128
+ appendSchema: searchValidation({
129
+ defaults,
130
+ definition,
131
+ appendSchema,
132
+ }),
125
133
  });
126
134
  }
127
135
  );
@@ -131,18 +139,29 @@ export function applyValidation(schema, definition) {
131
139
  });
132
140
 
133
141
  schema.static('getBaseSchema', function getBaseSchema() {
134
- return getSchemaFromMongoose(schema);
142
+ return getSchemaFromMongoose(schema, {
143
+ stripDeleted: true,
144
+ });
135
145
  });
136
146
  }
137
147
 
138
148
  // Yada schemas
139
149
 
140
150
  function getSchemaFromMongoose(schema, options = {}) {
141
- let { obj } = schema;
142
- if (options.stripReserved) {
143
- obj = omit(obj, RESERVED_FIELDS);
151
+ const fields = getMongooseFields(schema, options);
152
+ return getValidationSchema(fields, options);
153
+ }
154
+
155
+ function getMongooseFields(schema, options) {
156
+ const { stripTimestamps, stripDeleted } = options;
157
+ let fields = schema.obj;
158
+ if (stripTimestamps) {
159
+ fields = omit(fields, ['createdAt', 'updatedAt']);
160
+ }
161
+ if (stripDeleted) {
162
+ fields = omit(fields, ['deleted', 'deletedAt']);
144
163
  }
145
- return getValidationSchema(obj, options);
164
+ return fields;
146
165
  }
147
166
 
148
167
  // Exported for testing
package/types/schema.d.ts CHANGED
@@ -66,6 +66,5 @@ export function createSchema(definition: object, options?: mongoose.SchemaOption
66
66
  overwriteModels?: boolean;
67
67
  }, any>;
68
68
  export function normalizeAttributes(arg: any, path?: any[]): any;
69
- export const RESERVED_FIELDS: string[];
70
69
  import mongoose from "mongoose";
71
70
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.js"],"names":[],"mappings":"AA2BA;;;;;;;GAOG;AACH,yCAJW,MAAM,YACN,SAAS,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAoChC;AAED,iEAuBC;AAzED,uCAKE"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.js"],"names":[],"mappings":"AAoBA;;;;;;;GAOG;AACH,yCAJW,MAAM,YACN,SAAS,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAoChC;AAED,iEAuBC"}
package/types/search.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export function applySearch(schema: any, definition: any): void;
2
- export function searchValidation(definition: any, options?: {}): {
2
+ export function searchValidation(options?: {}): {
3
3
  setup: any;
4
4
  getFields: any;
5
5
  append(arg: import("@bedrockio/yada/types/object").SchemaMap | import("@bedrockio/yada/types/Schema").default): any;
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"AAmBA,gEAyDC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBC"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"AAYA,gEAyDC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBC"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"AAkEA,kDAEC;AAED,oEAiEC;AAaD,wEAkBC;AA0PD;;;EAEC;AAED;;;EAOC;AAnZD,8EAUK"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"AAiEA,kDAEC;AAED,oEA4EC;AAsBD,wEAkBC;AA0PD;;;EAEC;AAED;;;EAOC;AAvaD,8EAUK"}