@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.
- package/dist/cjs/env.js +8 -0
- package/dist/cjs/search.js +40 -30
- package/package.json +1 -1
- package/src/env.js +1 -0
- package/src/search.js +45 -22
- package/types/env.d.ts +2 -0
- package/types/env.d.ts.map +1 -0
- package/types/search.d.ts.map +1 -1
package/dist/cjs/env.js
ADDED
package/dist/cjs/search.js
CHANGED
|
@@ -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
|
-
|
|
172
|
+
queries = buildRegexQuery(keyword, fields);
|
|
173
|
+
} else if (hasTextIndex(schema)) {
|
|
174
|
+
queries = [getTextQuery(keyword)];
|
|
164
175
|
} else {
|
|
165
|
-
|
|
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
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
$
|
|
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
|
-
|
|
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
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
|
-
|
|
183
|
+
queries = buildRegexQuery(keyword, fields);
|
|
184
|
+
} else if (hasTextIndex(schema)) {
|
|
185
|
+
queries = [getTextQuery(keyword)];
|
|
171
186
|
} else {
|
|
172
|
-
|
|
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
|
-
|
|
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
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.js"],"names":[],"mappings":"AAAA,4BAAyC"}
|
package/types/search.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.js"],"names":[],"mappings":"AAcA,gEAgEC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBC"}
|