mongoose-smart-query 1.3.2 → 1.4.0
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.d.ts +5 -0
- package/dist/index.js +24 -0
- package/dist/plugin/index.d.ts +3 -0
- package/dist/plugin/index.js +22 -0
- package/dist/plugin/methods.d.ts +8 -0
- package/dist/plugin/methods.js +250 -0
- package/dist/plugin/pipeline.d.ts +8 -0
- package/dist/plugin/pipeline.js +434 -0
- package/dist/{mongoose-smart-query.d.ts → types/index.d.ts} +48 -32
- package/dist/types/index.js +2 -0
- package/dist/typesense/builder.d.ts +5 -0
- package/dist/typesense/builder.js +147 -0
- package/dist/typesense/config.d.ts +4 -0
- package/dist/typesense/config.js +9 -0
- package/dist/typesense/index.d.ts +2 -0
- package/dist/typesense/index.js +18 -0
- package/dist/utils/helpers.d.ts +27 -0
- package/dist/utils/helpers.js +116 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/lookups.d.ts +12 -0
- package/dist/utils/lookups.js +97 -0
- package/dist/utils/object.d.ts +3 -0
- package/dist/utils/object.js +26 -0
- package/package.json +11 -11
- package/dist/mongoose-smart-query.js +0 -1
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
24
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
50
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
51
|
+
if (ar || !(i in from)) {
|
|
52
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
53
|
+
ar[i] = from[i];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
57
|
+
};
|
|
58
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
|
+
exports.createSmartQueryGetPipeline = createSmartQueryGetPipeline;
|
|
60
|
+
var mongoose_1 = require("mongoose");
|
|
61
|
+
var utils_1 = require("../utils");
|
|
62
|
+
function createSmartQueryGetPipeline(schema, options) {
|
|
63
|
+
var _a = options.protectedFields, protectedFields = _a === void 0 ? '' : _a, _b = options.defaultFields, defaultFields = _b === void 0 ? '_id' : _b, _c = options.defaultSort, defaultSort = _c === void 0 ? '-_id' : _c, _d = options.defaultLimit, defaultLimit = _d === void 0 ? 20 : _d, _e = options.fieldsForDefaultQuery, fieldsForDefaultQuery = _e === void 0 ? '' : _e, _f = options.pageQueryName, pageQueryName = _f === void 0 ? '$page' : _f, _g = options.limitQueryName, limitQueryName = _g === void 0 ? '$limit' : _g, _h = options.fieldsQueryName, fieldsQueryName = _h === void 0 ? '$fields' : _h, _j = options.sortQueryName, sortQueryName = _j === void 0 ? '$sort' : _j, _k = options.queryName, queryName = _k === void 0 ? '$q' : _k, _l = options.textQueryName, textQueryName = _l === void 0 ? '$text' : _l, _m = options.unwindName, unwindName = _m === void 0 ? '$unwind' : _m, _o = options.allFieldsQueryName, allFieldsQueryName = _o === void 0 ? '$getAllFields' : _o, _p = options.normalizeSearchQuery, normalizeSearchQuery = _p === void 0 ? false : _p;
|
|
64
|
+
var __protected = (0, utils_1.stringToQuery)(protectedFields);
|
|
65
|
+
return function (query_1) {
|
|
66
|
+
return __awaiter(this, arguments, void 0, function (query, forCount, prePipeline, typesenseIds) {
|
|
67
|
+
function getFieldsProject(query) {
|
|
68
|
+
if (!query[fieldsQueryName] && defaultFields) {
|
|
69
|
+
query[fieldsQueryName] = defaultFields;
|
|
70
|
+
}
|
|
71
|
+
var $project = (0, utils_1.stringToQuery)(query[fieldsQueryName]);
|
|
72
|
+
$project = (0, utils_1.removeKeys)($project, __protected);
|
|
73
|
+
return $project;
|
|
74
|
+
}
|
|
75
|
+
var hasTextIndex, queryEmpresa, $page, $limit, getDefault, getMatch, getUnwind, _a, $match, usingTextSearch, $project, lookupsConfirmados, pipeline, getSort, sort, projectStage, finalProject;
|
|
76
|
+
var _this = this;
|
|
77
|
+
var _b;
|
|
78
|
+
if (forCount === void 0) { forCount = false; }
|
|
79
|
+
if (prePipeline === void 0) { prePipeline = []; }
|
|
80
|
+
return __generator(this, function (_c) {
|
|
81
|
+
switch (_c.label) {
|
|
82
|
+
case 0:
|
|
83
|
+
hasTextIndex = schema.indexes().some(function (_a) {
|
|
84
|
+
var index = _a[0];
|
|
85
|
+
return Object.values(index).includes('text');
|
|
86
|
+
});
|
|
87
|
+
queryEmpresa = query.business
|
|
88
|
+
? { business: new mongoose_1.Types.ObjectId(query.business) }
|
|
89
|
+
: {};
|
|
90
|
+
$page = parseInt(query[pageQueryName]) || 1;
|
|
91
|
+
$limit = parseInt(query[limitQueryName]) || defaultLimit;
|
|
92
|
+
getDefault = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
93
|
+
var $localMatch, lookupFinalMatch, $or, _loop_1, keyInicial;
|
|
94
|
+
var _this = this;
|
|
95
|
+
return __generator(this, function (_a) {
|
|
96
|
+
switch (_a.label) {
|
|
97
|
+
case 0:
|
|
98
|
+
$localMatch = {};
|
|
99
|
+
lookupFinalMatch = {};
|
|
100
|
+
$or = [];
|
|
101
|
+
_loop_1 = function (keyInicial) {
|
|
102
|
+
var _b, _c;
|
|
103
|
+
var path = schema.path(keyInicial);
|
|
104
|
+
if (!path && !keyInicial.includes('.'))
|
|
105
|
+
return "continue";
|
|
106
|
+
var key = keyInicial;
|
|
107
|
+
var lookupKey = void 0;
|
|
108
|
+
var valorQuery = query[key];
|
|
109
|
+
if (keyInicial.includes('.')) {
|
|
110
|
+
var _d = keyInicial.split('.'), keyForanea = _d[0], subKey = _d[1];
|
|
111
|
+
var foraneaKey = schema.path(keyForanea);
|
|
112
|
+
if (foraneaKey && foraneaKey.options.ref) {
|
|
113
|
+
key = subKey;
|
|
114
|
+
lookupKey = keyForanea;
|
|
115
|
+
lookupFinalMatch[lookupKey] = {
|
|
116
|
+
collection: foraneaKey.options.ref,
|
|
117
|
+
$match: {},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
var $toAdd = lookupKey
|
|
122
|
+
? lookupFinalMatch[lookupKey].$match
|
|
123
|
+
: $localMatch;
|
|
124
|
+
var queryRegex = /(?:\{(\$?[\w ]+)\})?([^{}\n]+)/g;
|
|
125
|
+
var match = void 0;
|
|
126
|
+
var values = [];
|
|
127
|
+
if (typeof valorQuery === 'string') {
|
|
128
|
+
var $filtroActual = {};
|
|
129
|
+
var valor = valorQuery;
|
|
130
|
+
var tieneOperadorOr = valor.startsWith('{$or}');
|
|
131
|
+
if (tieneOperadorOr)
|
|
132
|
+
valor = valor.replace('{$or}', '');
|
|
133
|
+
while ((match = queryRegex.exec(valor)) !== null) {
|
|
134
|
+
values.push([match[0], match[1], match[2]]);
|
|
135
|
+
}
|
|
136
|
+
for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {
|
|
137
|
+
var _e = values_1[_i], operator = _e[1], value = _e[2];
|
|
138
|
+
switch (operator) {
|
|
139
|
+
case '$exists':
|
|
140
|
+
$filtroActual[key] = { $exists: value !== 'false' };
|
|
141
|
+
break;
|
|
142
|
+
case '$includes':
|
|
143
|
+
$filtroActual[key] = {
|
|
144
|
+
$regex: RegExp(value.replace(/[^\w]/g, '.'), 'i'),
|
|
145
|
+
};
|
|
146
|
+
break;
|
|
147
|
+
case '$in':
|
|
148
|
+
case '$nin': {
|
|
149
|
+
var findin = value
|
|
150
|
+
.split(',')
|
|
151
|
+
.map(function (item) { return (0, utils_1.parseValue)(item.trim(), path === null || path === void 0 ? void 0 : path.instance); });
|
|
152
|
+
$filtroActual[key] = (_b = {}, _b[operator] = findin, _b);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
default: {
|
|
156
|
+
var parsedValue = (0, utils_1.parseValue)(value, path === null || path === void 0 ? void 0 : path.instance);
|
|
157
|
+
if (operator) {
|
|
158
|
+
if (typeof $filtroActual[key] === 'object') {
|
|
159
|
+
$filtroActual[key][operator] = parsedValue;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
$filtroActual[key] = (_c = {}, _c[operator] = parsedValue, _c);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
if (typeof value === 'string' && value.includes('$exists')) {
|
|
167
|
+
$filtroActual[key] = { $exists: true, $ne: [] };
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
$filtroActual[key] = parsedValue;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (tieneOperadorOr) {
|
|
178
|
+
$or.push($filtroActual);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
Object.assign($toAdd, $filtroActual);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
$toAdd[key] = (0, utils_1.parseValue)(valorQuery, path === null || path === void 0 ? void 0 : path.instance);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
for (keyInicial in query) {
|
|
189
|
+
_loop_1(keyInicial);
|
|
190
|
+
}
|
|
191
|
+
if ($or.length !== 0)
|
|
192
|
+
$localMatch.$or = $or;
|
|
193
|
+
if (!(Object.keys(lookupFinalMatch).length !== 0)) return [3 /*break*/, 2];
|
|
194
|
+
return [4 /*yield*/, Promise.all(Object.entries(lookupFinalMatch).map(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
|
|
195
|
+
var docs;
|
|
196
|
+
var key = _b[0], value = _b[1];
|
|
197
|
+
return __generator(this, function (_c) {
|
|
198
|
+
switch (_c.label) {
|
|
199
|
+
case 0: return [4 /*yield*/, mongoose_1.connection
|
|
200
|
+
.collection(value.collection)
|
|
201
|
+
.find(__assign(__assign({}, value.$match), queryEmpresa))
|
|
202
|
+
.project({ _id: 1 })
|
|
203
|
+
.toArray()];
|
|
204
|
+
case 1:
|
|
205
|
+
docs = _c.sent();
|
|
206
|
+
$localMatch[key] = { $in: docs.map(function (item) { return item._id; }) };
|
|
207
|
+
return [2 /*return*/];
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}); }))];
|
|
211
|
+
case 1:
|
|
212
|
+
_a.sent();
|
|
213
|
+
_a.label = 2;
|
|
214
|
+
case 2: return [2 /*return*/, $localMatch];
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}); };
|
|
218
|
+
getMatch = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
219
|
+
var $queryMatch, _lookupsMatch, usingTextSearch, fields, searchValue, regexParseado, subWordArray, regexFlags_1, regex, _loop_2, _i, fields_1, field, $queryDefault, $or;
|
|
220
|
+
var _this = this;
|
|
221
|
+
return __generator(this, function (_a) {
|
|
222
|
+
switch (_a.label) {
|
|
223
|
+
case 0:
|
|
224
|
+
if (typesenseIds) {
|
|
225
|
+
return [2 /*return*/, {
|
|
226
|
+
match: {
|
|
227
|
+
_id: { $in: typesenseIds.map(function (id) { return new mongoose_1.Types.ObjectId(id); }) },
|
|
228
|
+
},
|
|
229
|
+
usingTextSearch: false,
|
|
230
|
+
}];
|
|
231
|
+
}
|
|
232
|
+
$queryMatch = {};
|
|
233
|
+
_lookupsMatch = {};
|
|
234
|
+
usingTextSearch = false;
|
|
235
|
+
if (!(hasTextIndex && query[textQueryName])) return [3 /*break*/, 1];
|
|
236
|
+
$queryMatch = { $text: { $search: query[textQueryName] } };
|
|
237
|
+
usingTextSearch = true;
|
|
238
|
+
return [3 /*break*/, 3];
|
|
239
|
+
case 1:
|
|
240
|
+
if (!(query[queryName] && fieldsForDefaultQuery)) return [3 /*break*/, 3];
|
|
241
|
+
fields = fieldsForDefaultQuery.split(' ');
|
|
242
|
+
searchValue = normalizeSearchQuery
|
|
243
|
+
? (0, utils_1.normalizeSearchText)(query[queryName])
|
|
244
|
+
: query[queryName];
|
|
245
|
+
regexParseado = searchValue
|
|
246
|
+
.replace(/[()[\\\]]/g, '.')
|
|
247
|
+
.replace(/[+]/g, '\\+')
|
|
248
|
+
.replace(/[*]/g, '\\*');
|
|
249
|
+
subWordArray = regexParseado.split(' ');
|
|
250
|
+
regexFlags_1 = normalizeSearchQuery ? '' : 'i';
|
|
251
|
+
regex = { $regex: RegExp(regexParseado, regexFlags_1) };
|
|
252
|
+
_loop_2 = function (field) {
|
|
253
|
+
var _b, _c, _d;
|
|
254
|
+
var path = schema.path(field);
|
|
255
|
+
if (path) {
|
|
256
|
+
if (!$queryMatch.$or)
|
|
257
|
+
$queryMatch.$or = [];
|
|
258
|
+
if (subWordArray.length <= 1) {
|
|
259
|
+
$queryMatch.$or.push((_b = {}, _b[field] = regex, _b));
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
$queryMatch.$or.push({
|
|
263
|
+
$and: subWordArray.map(function (word) {
|
|
264
|
+
var _a;
|
|
265
|
+
return (_a = {},
|
|
266
|
+
_a[field] = { $regex: RegExp(word, regexFlags_1) },
|
|
267
|
+
_a);
|
|
268
|
+
}),
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
else if (field.includes('.')) {
|
|
273
|
+
var _e = field.split('.'), subField = _e[0], busqueda = _e[1];
|
|
274
|
+
var subpath = schema.path(subField);
|
|
275
|
+
if (subpath && subpath.options.ref) {
|
|
276
|
+
if (!_lookupsMatch[subField])
|
|
277
|
+
_lookupsMatch[subField] = {
|
|
278
|
+
collection: subpath.options.ref,
|
|
279
|
+
$match: { $or: [(_c = {}, _c[busqueda] = regex, _c)] },
|
|
280
|
+
};
|
|
281
|
+
else
|
|
282
|
+
_lookupsMatch[subField].$match.$or.push((_d = {}, _d[busqueda] = regex, _d));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
for (_i = 0, fields_1 = fields; _i < fields_1.length; _i++) {
|
|
287
|
+
field = fields_1[_i];
|
|
288
|
+
_loop_2(field);
|
|
289
|
+
}
|
|
290
|
+
if (!(Object.keys(_lookupsMatch).length !== 0)) return [3 /*break*/, 3];
|
|
291
|
+
return [4 /*yield*/, Promise.all(Object.entries(_lookupsMatch).map(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
|
|
292
|
+
var docs, idsDocs;
|
|
293
|
+
var _c;
|
|
294
|
+
var key = _b[0], value = _b[1];
|
|
295
|
+
return __generator(this, function (_d) {
|
|
296
|
+
switch (_d.label) {
|
|
297
|
+
case 0: return [4 /*yield*/, mongoose_1.connection
|
|
298
|
+
.collection(value.collection)
|
|
299
|
+
.find(__assign(__assign({}, value.$match), queryEmpresa))
|
|
300
|
+
.project({ _id: 1 })
|
|
301
|
+
.toArray()];
|
|
302
|
+
case 1:
|
|
303
|
+
docs = _d.sent();
|
|
304
|
+
idsDocs = docs.map(function (item) { return item._id; });
|
|
305
|
+
if (idsDocs.length) {
|
|
306
|
+
if (!$queryMatch.$or)
|
|
307
|
+
$queryMatch.$or = [];
|
|
308
|
+
$queryMatch.$or.push((_c = {}, _c[key] = { $in: idsDocs }, _c));
|
|
309
|
+
}
|
|
310
|
+
return [2 /*return*/];
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}); }))];
|
|
314
|
+
case 2:
|
|
315
|
+
_a.sent();
|
|
316
|
+
_a.label = 3;
|
|
317
|
+
case 3: return [4 /*yield*/, getDefault()];
|
|
318
|
+
case 4:
|
|
319
|
+
$queryDefault = _a.sent();
|
|
320
|
+
$or = $queryDefault.$or;
|
|
321
|
+
if ($or) {
|
|
322
|
+
delete $queryDefault.$or;
|
|
323
|
+
if (Array.isArray($queryMatch.$or)) {
|
|
324
|
+
$queryMatch.$or = $queryMatch.$or.concat($or);
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
$queryMatch.$or = $or;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return [2 /*return*/, { match: __assign(__assign({}, $queryDefault), $queryMatch), usingTextSearch: usingTextSearch }];
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}); };
|
|
334
|
+
getUnwind = function () {
|
|
335
|
+
return !query[unwindName]
|
|
336
|
+
? []
|
|
337
|
+
: [
|
|
338
|
+
{
|
|
339
|
+
$unwind: {
|
|
340
|
+
path: "$".concat(query[unwindName]),
|
|
341
|
+
preserveNullAndEmptyArrays: true,
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
];
|
|
345
|
+
};
|
|
346
|
+
return [4 /*yield*/, getMatch()];
|
|
347
|
+
case 1:
|
|
348
|
+
_a = _c.sent(), $match = _a.match, usingTextSearch = _a.usingTextSearch;
|
|
349
|
+
$project = getFieldsProject(query);
|
|
350
|
+
lookupsConfirmados = (0, utils_1.getListOfPossibleLookups)(schema, $project);
|
|
351
|
+
pipeline = [];
|
|
352
|
+
if (Object.keys($match).length !== 0) {
|
|
353
|
+
pipeline.push({ $match: $match });
|
|
354
|
+
}
|
|
355
|
+
pipeline.push.apply(pipeline, prePipeline);
|
|
356
|
+
if (forCount) {
|
|
357
|
+
pipeline.push.apply(pipeline, __spreadArray(__spreadArray([], getUnwind(), false), [{ $count: 'size' }], false));
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
getSort = function () {
|
|
361
|
+
if (usingTextSearch) {
|
|
362
|
+
return { $localSort: { score: { $meta: 'textScore' }, _id: -1 } };
|
|
363
|
+
}
|
|
364
|
+
if (!query[sortQueryName]) {
|
|
365
|
+
if (!defaultSort)
|
|
366
|
+
return {};
|
|
367
|
+
query[sortQueryName] = defaultSort;
|
|
368
|
+
}
|
|
369
|
+
var regex = /(-)?([\w.]+)/g;
|
|
370
|
+
var $localSort = {};
|
|
371
|
+
var $foreignSort = {};
|
|
372
|
+
var matched;
|
|
373
|
+
while ((matched = regex.exec(query[sortQueryName])) !== null) {
|
|
374
|
+
var order = matched[1];
|
|
375
|
+
var localfield = matched[2];
|
|
376
|
+
var path = !!schema.path(localfield);
|
|
377
|
+
if (path) {
|
|
378
|
+
$localSort[localfield] = order ? -1 : 1;
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
$foreignSort[localfield] = order ? -1 : 1;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
$localSort: Object.keys($localSort).length !== 0 ? $localSort : undefined,
|
|
386
|
+
$foreignSort: Object.keys($foreignSort).length !== 0 ? $foreignSort : undefined,
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
sort = getSort();
|
|
390
|
+
projectStage = [];
|
|
391
|
+
if (!(((_b = query[allFieldsQueryName]) === null || _b === void 0 ? void 0 : _b.toString()) === 'true')) {
|
|
392
|
+
(0, utils_1.asignarLookups)($project, lookupsConfirmados);
|
|
393
|
+
finalProject = __assign({}, $project);
|
|
394
|
+
if (usingTextSearch) {
|
|
395
|
+
finalProject.score = { $meta: 'textScore' };
|
|
396
|
+
}
|
|
397
|
+
projectStage.push({ $project: finalProject });
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
if (protectedFields) {
|
|
401
|
+
projectStage.push({
|
|
402
|
+
$project: (0, utils_1.stringToQuery)(protectedFields, '0'),
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
if (usingTextSearch) {
|
|
406
|
+
projectStage.push({
|
|
407
|
+
$addFields: { score: { $meta: 'textScore' } },
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (typesenseIds) {
|
|
412
|
+
pipeline.push.apply(pipeline, __spreadArray(__spreadArray(__spreadArray([], getUnwind(), false), [{
|
|
413
|
+
$addFields: {
|
|
414
|
+
__order: {
|
|
415
|
+
$indexOfArray: [
|
|
416
|
+
typesenseIds.map(function (id) { return new mongoose_1.Types.ObjectId(id); }),
|
|
417
|
+
'$_id',
|
|
418
|
+
],
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
{ $sort: { __order: 1 } }], false), projectStage, false));
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
pipeline.push.apply(pipeline, __spreadArray(__spreadArray(__spreadArray(__spreadArray([], (sort.$localSort ? [{ $sort: sort.$localSort }] : []), false), getUnwind(), false), [{ $skip: ($page - 1) * $limit },
|
|
426
|
+
{ $limit: $limit }], false), projectStage, false));
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return [2 /*return*/, { pipeline: pipeline, lookupsConfirmados: lookupsConfirmados }];
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
};
|
|
434
|
+
}
|
|
@@ -1,24 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { PipelineStage } from 'mongoose';
|
|
2
|
+
import type { CollectionCreateSchema } from 'typesense/lib/Typesense/Collections';
|
|
3
|
+
export interface SmartQueryFieldSchema {
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
facet?: boolean;
|
|
7
|
+
optional?: boolean;
|
|
8
|
+
index?: boolean;
|
|
9
|
+
sort?: boolean;
|
|
10
|
+
infix?: boolean;
|
|
11
|
+
locale?: string;
|
|
12
|
+
drop?: boolean;
|
|
13
|
+
mongoField?: string;
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}
|
|
16
|
+
export interface PluginTypesenseOptions {
|
|
17
|
+
schema: Omit<CollectionCreateSchema, 'fields'> & {
|
|
18
|
+
fields?: SmartQueryFieldSchema[];
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface LookupConfirmado {
|
|
22
|
+
field: string;
|
|
23
|
+
from: string;
|
|
24
|
+
project: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export type QueryForeign = Record<string, {
|
|
27
|
+
collection: string;
|
|
28
|
+
$match: Record<string, any>;
|
|
29
|
+
}>;
|
|
30
|
+
export interface SmartQueryOptions {
|
|
12
31
|
prePipeline?: PipelineStage[];
|
|
13
32
|
autoPaginate?: boolean;
|
|
14
33
|
}
|
|
15
|
-
interface SmartQueryPagination {
|
|
34
|
+
export interface SmartQueryPagination {
|
|
16
35
|
total: number;
|
|
17
36
|
page: number;
|
|
18
37
|
pages: number;
|
|
19
38
|
limit: number;
|
|
20
39
|
}
|
|
21
|
-
interface SmartQueryResult<T = any> {
|
|
40
|
+
export interface SmartQueryResult<T = any> {
|
|
22
41
|
data: T[];
|
|
23
42
|
pagination: SmartQueryPagination;
|
|
24
43
|
}
|
|
@@ -30,8 +49,14 @@ export interface SmartQueryStatics {
|
|
|
30
49
|
autoPaginate?: false;
|
|
31
50
|
}): Promise<T[]>;
|
|
32
51
|
smartCount(query?: Record<string, any>): Promise<number>;
|
|
52
|
+
__smartQueryGetPipeline(query: {
|
|
53
|
+
[key: string]: string;
|
|
54
|
+
}, forCount?: boolean, prePipeline?: PipelineStage[], typesenseIds?: string[]): Promise<{
|
|
55
|
+
pipeline: PipelineStage[];
|
|
56
|
+
lookupsConfirmados: LookupConfirmado[];
|
|
57
|
+
}>;
|
|
33
58
|
}
|
|
34
|
-
interface PluginOptions {
|
|
59
|
+
export interface PluginOptions {
|
|
35
60
|
/**
|
|
36
61
|
* Fields that should not be included in the query results. Default: `''`.
|
|
37
62
|
*/
|
|
@@ -88,24 +113,15 @@ interface PluginOptions {
|
|
|
88
113
|
* If true, applies `normalizeSearchText` to the `$q` search value before executing the query. Default: `false`.
|
|
89
114
|
*/
|
|
90
115
|
normalizeSearchQuery?: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Collation to be applied to the aggregate queries. Default: `undefined`.
|
|
118
|
+
*/
|
|
119
|
+
collation?: any;
|
|
120
|
+
/**
|
|
121
|
+
* Configuration for Typesense integration.
|
|
122
|
+
*/
|
|
123
|
+
typesense?: PluginTypesenseOptions;
|
|
91
124
|
}
|
|
92
|
-
interface TObject {
|
|
125
|
+
export interface TObject {
|
|
93
126
|
[value: string]: any;
|
|
94
127
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Converts a string to object. Example:
|
|
97
|
-
* 'name age friends { name }' => { name: 1, age: 1, friends: { name: 1 } }
|
|
98
|
-
* @param query String to convert to object.
|
|
99
|
-
* @returns The resulting object.
|
|
100
|
-
*/
|
|
101
|
-
export declare function stringToQuery(query?: string, value?: string): object;
|
|
102
|
-
/**
|
|
103
|
-
* Remove the keys from the initial object. If after this process the property
|
|
104
|
-
* is empty it is removed
|
|
105
|
-
* @param initial The main object
|
|
106
|
-
* @param toRemove The object with the keys to remove
|
|
107
|
-
* @returns The object without the keys
|
|
108
|
-
*/
|
|
109
|
-
export declare function removeKeys(initial: TObject, toRemove: TObject): TObject;
|
|
110
|
-
export default function (schema: Schema, { protectedFields, defaultFields, defaultSort, defaultLimit, fieldsForDefaultQuery, pageQueryName, limitQueryName, fieldsQueryName, sortQueryName, queryName, textQueryName, unwindName, allFieldsQueryName, normalizeSearchQuery, }: PluginOptions): void;
|
|
111
|
-
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SearchParams } from 'typesense/lib/Typesense/Documents';
|
|
2
|
+
import type { PluginOptions, PluginTypesenseOptions } from '../types';
|
|
3
|
+
export declare const buildTypesenseSearchParameters: (query: {
|
|
4
|
+
[key: string]: string;
|
|
5
|
+
}, tsSchema: PluginTypesenseOptions["schema"], options: PluginOptions) => SearchParams<any>;
|