@bedrockio/model 0.1.12 → 0.1.14

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.
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.debug = void 0;
7
+ const debug = !!process.env.DEBUG;
8
+ exports.debug = debug;
@@ -6,11 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.applySearch = applySearch;
7
7
  exports.searchValidation = searchValidation;
8
8
  var _yada = _interopRequireDefault(require("@bedrockio/yada"));
9
+ var _logger = _interopRequireDefault(require("@bedrockio/logger"));
9
10
  var _mongoose = _interopRequireDefault(require("mongoose"));
10
11
  var _lodash = require("lodash");
11
12
  var _utils = require("./utils");
12
13
  var _const = require("./const");
13
14
  var _validation = require("./validation");
15
+ var _env = require("./env");
14
16
  var _warn = _interopRequireDefault(require("./warn"));
15
17
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
18
  const {
@@ -40,9 +42,12 @@ function applySearch(schema, definition) {
40
42
  };
41
43
  }
42
44
  if (keyword) {
43
- Object.assign(query, buildKeywordQuery(keyword, fields));
45
+ Object.assign(query, buildKeywordQuery(schema, keyword, fields));
44
46
  }
45
47
  Object.assign(query, normalizeQuery(rest, schema.obj));
48
+ if (_env.debug) {
49
+ _logger.default.info(`Search query for ${this.modelName}:\n`, JSON.stringify(query, null, 2));
50
+ }
46
51
  const mQuery = this.find(query).sort(resolveSort(sort, schema)).skip(skip).limit(limit);
47
52
 
48
53
  // The following construct is awkward but it allows the mongoose query
@@ -158,15 +163,29 @@ function resolveSort(sort, schema) {
158
163
  // https://stackoverflow.com/questions/44833817/mongodb-full-and-partial-text-search
159
164
  // https://jira.mongodb.org/browse/SERVER-15090
160
165
 
161
- function buildKeywordQuery(keyword, fields) {
166
+ function buildKeywordQuery(schema, keyword, fields) {
167
+ let queries;
168
+
169
+ // Prefer defined search fields over
170
+ // text indexes to perform keyword search.
162
171
  if (fields) {
163
- return buildRegexQuery(keyword, fields);
172
+ queries = buildRegexQuery(keyword, fields);
173
+ } else if (hasTextIndex(schema)) {
174
+ queries = [getTextQuery(keyword)];
164
175
  } else {
165
- return buildTextIndexQuery(keyword);
176
+ queries = [];
177
+ }
178
+ if (ObjectId.isValid(keyword)) {
179
+ queries.push({
180
+ _id: keyword
181
+ });
166
182
  }
183
+ return {
184
+ $or: queries
185
+ };
167
186
  }
168
187
  function buildRegexQuery(keyword, fields) {
169
- const queries = fields.map(field => {
188
+ return fields.map(field => {
170
189
  const regexKeyword = keyword.replace(/\+/g, '\\+');
171
190
  return {
172
191
  [field]: {
@@ -175,34 +194,21 @@ function buildRegexQuery(keyword, fields) {
175
194
  }
176
195
  };
177
196
  });
178
- if (ObjectId.isValid(keyword)) {
179
- queries.push({
180
- _id: keyword
197
+ }
198
+ function hasTextIndex(schema) {
199
+ return schema.indexes().some(([spec]) => {
200
+ return Object.values(spec).some(type => {
201
+ return type === 'text';
181
202
  });
182
- }
203
+ });
204
+ }
205
+ function getTextQuery(keyword) {
183
206
  return {
184
- $or: queries
207
+ $text: {
208
+ $search: keyword
209
+ }
185
210
  };
186
211
  }
187
- function buildTextIndexQuery(keyword) {
188
- if (ObjectId.isValid(keyword)) {
189
- return {
190
- $or: [{
191
- $text: {
192
- $search: keyword
193
- }
194
- }, {
195
- _id: keyword
196
- }]
197
- };
198
- } else {
199
- return {
200
- $text: {
201
- $search: keyword
202
- }
203
- };
204
- }
205
- }
206
212
 
207
213
  // Normalizes mongo queries. Flattens plain nested paths
208
214
  // to dot syntax while preserving mongo operators and
@@ -257,7 +263,11 @@ function isRangeQuery(schema, key, value) {
257
263
  function mapOperatorQuery(obj) {
258
264
  const query = {};
259
265
  for (let [key, val] of Object.entries(obj)) {
260
- query[`$${key}`] = val;
266
+ if (isMongoOperator(key)) {
267
+ query[key] = val;
268
+ } else {
269
+ query[`$${key}`] = val;
270
+ }
261
271
  }
262
272
  return query;
263
273
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/model",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Bedrock utilities for model creation.",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/env.js ADDED
@@ -0,0 +1 @@
1
+ export const debug = !!process.env.DEBUG;
package/src/search.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import yd from '@bedrockio/yada';
2
+ import logger from '@bedrockio/logger';
2
3
  import mongoose from 'mongoose';
3
4
  import { pick, isEmpty, isPlainObject } from 'lodash';
4
5
 
5
6
  import { isDateField, isNumberField, resolveField } from './utils';
6
7
  import { SEARCH_DEFAULTS } from './const';
7
8
  import { OBJECT_ID_SCHEMA } from './validation';
9
+ import { debug } from './env';
8
10
 
9
11
  import warn from './warn';
10
12
 
@@ -29,11 +31,18 @@ export function applySearch(schema, definition) {
29
31
  }
30
32
 
31
33
  if (keyword) {
32
- Object.assign(query, buildKeywordQuery(keyword, fields));
34
+ Object.assign(query, buildKeywordQuery(schema, keyword, fields));
33
35
  }
34
36
 
35
37
  Object.assign(query, normalizeQuery(rest, schema.obj));
36
38
 
39
+ if (debug) {
40
+ logger.info(
41
+ `Search query for ${this.modelName}:\n`,
42
+ JSON.stringify(query, null, 2)
43
+ );
44
+ }
45
+
37
46
  const mQuery = this.find(query)
38
47
  .sort(resolveSort(sort, schema))
39
48
  .skip(skip)
@@ -165,16 +174,28 @@ function resolveSort(sort, schema) {
165
174
  // https://stackoverflow.com/questions/44833817/mongodb-full-and-partial-text-search
166
175
  // https://jira.mongodb.org/browse/SERVER-15090
167
176
 
168
- function buildKeywordQuery(keyword, fields) {
177
+ function buildKeywordQuery(schema, keyword, fields) {
178
+ let queries;
179
+
180
+ // Prefer defined search fields over
181
+ // text indexes to perform keyword search.
169
182
  if (fields) {
170
- return buildRegexQuery(keyword, fields);
183
+ queries = buildRegexQuery(keyword, fields);
184
+ } else if (hasTextIndex(schema)) {
185
+ queries = [getTextQuery(keyword)];
171
186
  } else {
172
- return buildTextIndexQuery(keyword);
187
+ queries = [];
188
+ }
189
+
190
+ if (ObjectId.isValid(keyword)) {
191
+ queries.push({ _id: keyword });
173
192
  }
193
+
194
+ return { $or: queries };
174
195
  }
175
196
 
176
197
  function buildRegexQuery(keyword, fields) {
177
- const queries = fields.map((field) => {
198
+ return fields.map((field) => {
178
199
  const regexKeyword = keyword.replace(/\+/g, '\\+');
179
200
  return {
180
201
  [field]: {
@@ -183,24 +204,22 @@ function buildRegexQuery(keyword, fields) {
183
204
  },
184
205
  };
185
206
  });
186
- if (ObjectId.isValid(keyword)) {
187
- queries.push({ _id: keyword });
188
- }
189
- return { $or: queries };
190
207
  }
191
208
 
192
- function buildTextIndexQuery(keyword) {
193
- if (ObjectId.isValid(keyword)) {
194
- return {
195
- $or: [{ $text: { $search: keyword } }, { _id: keyword }],
196
- };
197
- } else {
198
- return {
199
- $text: {
200
- $search: keyword,
201
- },
202
- };
203
- }
209
+ function hasTextIndex(schema) {
210
+ return schema.indexes().some(([spec]) => {
211
+ return Object.values(spec).some((type) => {
212
+ return type === 'text';
213
+ });
214
+ });
215
+ }
216
+
217
+ function getTextQuery(keyword) {
218
+ return {
219
+ $text: {
220
+ $search: keyword,
221
+ },
222
+ };
204
223
  }
205
224
 
206
225
  // Normalizes mongo queries. Flattens plain nested paths
@@ -257,7 +276,11 @@ function isRangeQuery(schema, key, value) {
257
276
  function mapOperatorQuery(obj) {
258
277
  const query = {};
259
278
  for (let [key, val] of Object.entries(obj)) {
260
- query[`$${key}`] = val;
279
+ if (isMongoOperator(key)) {
280
+ query[key] = val;
281
+ } else {
282
+ query[`$${key}`] = val;
283
+ }
261
284
  }
262
285
  return query;
263
286
  }
package/types/env.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export const debug: boolean;
2
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.js"],"names":[],"mappings":"AAAA,4BAAyC"}
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"AAYA,gEAyDC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBC"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"AAcA,gEAgEC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBC"}