@storecraft/database-mongodb 1.0.20 → 1.2.5
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/README.md +7 -7
- package/index.js +22 -39
- package/migrate.js +0 -1
- package/migrations/00005_add_chats_collection.js +57 -0
- package/package.json +1 -2
- package/src/con.auth_users.js +3 -15
- package/src/con.chats.js +119 -0
- package/src/con.collections.js +2 -11
- package/src/con.customers.js +5 -14
- package/src/con.discounts.js +6 -11
- package/src/con.discounts.utils.js +2 -3
- package/src/con.images.js +9 -17
- package/src/con.notifications.js +4 -11
- package/src/con.orders.js +4 -7
- package/src/con.posts.js +0 -15
- package/src/con.products.js +1 -9
- package/src/con.search.js +28 -14
- package/src/con.shared.js +23 -45
- package/src/con.shipping.js +0 -7
- package/src/con.storefronts.js +6 -9
- package/src/con.tags.js +7 -11
- package/src/con.templates.js +4 -8
- package/src/utils.funcs.js +5 -6
- package/src/utils.query.js +165 -140
- package/src/utils.query_OLD.js +189 -0
- package/src/utils.relations.js +43 -76
- package/tests/runner.test.js +9 -5
- package/tests/sandbox.js +5 -5
- package/vector-store/index.js +44 -10
- package/tests/query.cursor.test.js +0 -389
- package/tests/query.vql.test.js +0 -71
package/src/utils.funcs.js
CHANGED
@@ -11,7 +11,6 @@ export const isDef = v => v!==undefined && v!==null;
|
|
11
11
|
export const isUndef = v => !isDef(v);
|
12
12
|
|
13
13
|
/**
|
14
|
-
*
|
15
14
|
* @param {...any} keys
|
16
15
|
*/
|
17
16
|
export const delete_keys = (...keys) => {
|
@@ -29,7 +28,7 @@ export const delete_keys = (...keys) => {
|
|
29
28
|
}
|
30
29
|
|
31
30
|
/**
|
32
|
-
* Sanitize hidden properties in-place
|
31
|
+
* @description Sanitize hidden properties in-place
|
33
32
|
* @template {object} T
|
34
33
|
* @param {T} o
|
35
34
|
* @return {Omit<T, '_id' | '_relations'>}
|
@@ -46,7 +45,7 @@ export const sanitize_hidden = o => {
|
|
46
45
|
}
|
47
46
|
|
48
47
|
/**
|
49
|
-
* Sanitize hidden properties in-place recursively
|
48
|
+
* @description Sanitize hidden properties in-place recursively
|
50
49
|
* @template {object} T
|
51
50
|
* @param {T} o
|
52
51
|
* @return {Omit<T, '_id' | '_relations'>}
|
@@ -63,7 +62,7 @@ export const sanitize_recursively = o => {
|
|
63
62
|
}
|
64
63
|
|
65
64
|
/**
|
66
|
-
* Sanitize the mongo document before sending to client
|
65
|
+
* @description Sanitize the mongo document before sending to client
|
67
66
|
* @template T
|
68
67
|
* @param {WithRelations<T>} o
|
69
68
|
*/
|
@@ -72,7 +71,7 @@ export const sanitize_one = o => {
|
|
72
71
|
}
|
73
72
|
|
74
73
|
/**
|
75
|
-
* Sanitize the mongo document before sending to client
|
74
|
+
* @description Sanitize the mongo document before sending to client
|
76
75
|
* @template T
|
77
76
|
* @param {WithRelations<T>[]} o
|
78
77
|
*/
|
@@ -109,7 +108,7 @@ export const to_objid_safe = id => {
|
|
109
108
|
}
|
110
109
|
|
111
110
|
/**
|
112
|
-
* Create a `filter` for `object-id` or `handle`
|
111
|
+
* @description Create a `filter` for `object-id` or `handle`
|
113
112
|
* @template {{handle?: string}} G
|
114
113
|
* @param {string} handle_or_id
|
115
114
|
* @returns {Filter<G>}
|
package/src/utils.query.js
CHANGED
@@ -1,127 +1,152 @@
|
|
1
1
|
/**
|
2
|
-
* @import { ApiQuery,
|
3
|
-
* @import { VQL } from '@storecraft/core/vql'
|
2
|
+
* @import { ApiQuery, Tuple } from '@storecraft/core/api'
|
3
|
+
* @import { VQL, VQL_OPS, legal_value_types } from '@storecraft/core/vql'
|
4
|
+
* @import { Filter, FilterOperators, FindOptions } from 'mongodb'
|
4
5
|
*/
|
5
|
-
|
6
|
+
import {
|
7
|
+
legacy_query_with_cursors_to_vql_string
|
8
|
+
} from "@storecraft/core/api/query.legacy.js";
|
6
9
|
import { to_objid } from "./utils.funcs.js";
|
7
|
-
import { parse } from "@storecraft/core/vql";
|
8
|
-
|
9
|
-
let a = {
|
10
|
-
$or: [
|
11
|
-
{ updated_at: { $gt: '2024-01-24T20:28:24.126Z'} },
|
12
|
-
{ $and : [ { updated_at: '2024-01-24T20:28:24.126Z' }, { id: { $gte : 'tag_65b172ebc4c9552fd46c1027'}}]}
|
13
|
-
],
|
14
|
-
}
|
10
|
+
import { parse, utils } from "@storecraft/core/vql";
|
15
11
|
|
16
12
|
/**
|
17
|
-
* Convert
|
18
|
-
*
|
19
|
-
* 1. (a1, a2) > (b1, b2) ==> (a1 > b1) || (a1=b1 & a2>b2)
|
20
|
-
* 2. (a1, a2) >= (b1, b2) ==> (a1 > b1) || (a1=b1 & a2>=b2)
|
21
|
-
* 3. (a1, a2, a3) > (b1, b2, b3) ==> (a1 > b1) || (a1=b1 & a2>b2) || (a1=b1 & a2=b2 & a3>b3)
|
22
|
-
* 4. (a1, a2, a3) >= (b1, b2, b3) ==> (a1 > b1) || (a1=b1 & a2>b2) || (a1=b1 & a2=b2 & a3>=b3)
|
23
|
-
*
|
24
|
-
*
|
25
|
-
* @param {Cursor} c
|
26
|
-
* @param {'>' | '>=' | '<' | '<='} relation
|
27
|
-
* @param {(x: [k: string, v: any]) => [k: string, v: any]} transformer
|
28
|
-
* Your chance to change key and value
|
29
|
-
*
|
13
|
+
* @description Convert a **VQL** to a mongo filter
|
14
|
+
* @param {VQL} vql
|
30
15
|
*/
|
31
|
-
export const
|
16
|
+
export const query_vql_to_mongo_filter = (vql) => {
|
32
17
|
|
33
|
-
|
34
|
-
|
18
|
+
if(!vql)
|
19
|
+
return undefined;
|
35
20
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
rel_key_2='$gte';
|
21
|
+
/** @template T @param {T} fn @returns {T} */
|
22
|
+
const identity = (fn) => {
|
23
|
+
return fn;
|
40
24
|
}
|
41
|
-
else if (relation==='<' || relation==='<=') {
|
42
|
-
rel_key_1 = rel_key_2 = '$lt';
|
43
|
-
if(relation==='<=')
|
44
|
-
rel_key_2='$lte';
|
45
|
-
} else return undefined;
|
46
|
-
|
47
|
-
const disjunctions = [];
|
48
|
-
// each disjunction clause
|
49
|
-
for (let ix = 0; ix < c.length; ix++) {
|
50
|
-
const is_last_disjunction = ix==c.length-1;
|
51
|
-
const conjunctions = [];
|
52
|
-
// each conjunction clause up until the last term (not inclusive)
|
53
|
-
for (let jx = 0; jx < ix; jx++) {
|
54
|
-
// the a_n=b_n
|
55
|
-
const r = transformer(c[jx]);
|
56
|
-
conjunctions.push({ [r[0]] : r[1] });
|
57
|
-
}
|
58
25
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
26
|
+
/**
|
27
|
+
* @param {VQL_OPS<legal_value_types>} ops
|
28
|
+
* `ops` object about this property
|
29
|
+
* @param {string} name
|
30
|
+
* property name in the table
|
31
|
+
*/
|
32
|
+
const leaf_ops = (ops, name) => {
|
33
|
+
|
34
|
+
const ops_keys = /** @type {(keyof VQL_OPS)[]} */(
|
35
|
+
Object.keys(ops)
|
36
|
+
);
|
37
|
+
|
38
|
+
const values = ops_keys.map(
|
39
|
+
(k) => {
|
40
|
+
/** `arg` is basically the value of `op.$eq` `op.$gte` etc.. */
|
41
|
+
const arg = (ops[k]);
|
42
|
+
|
43
|
+
switch (k) {
|
44
|
+
case '$eq':
|
45
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
46
|
+
$eq: arg
|
47
|
+
});
|
48
|
+
case '$ne':
|
49
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
50
|
+
$ne: arg
|
51
|
+
});
|
52
|
+
case '$gt':
|
53
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
54
|
+
$gt: arg
|
55
|
+
});
|
56
|
+
case '$gte':
|
57
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
58
|
+
$gte: arg
|
59
|
+
});
|
60
|
+
case '$lt':
|
61
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
62
|
+
$lt: arg
|
63
|
+
});
|
64
|
+
case '$lte':
|
65
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
66
|
+
$lte: arg
|
67
|
+
});
|
68
|
+
case '$like':
|
69
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
70
|
+
$regex: String(arg)
|
71
|
+
});
|
72
|
+
case '$in': {
|
73
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
74
|
+
$in: arg
|
75
|
+
});
|
76
|
+
}
|
77
|
+
case '$nin': {
|
78
|
+
return /** @type {FilterOperators<legal_value_types>} */({
|
79
|
+
$nin: arg
|
80
|
+
});
|
81
|
+
}
|
82
|
+
default:
|
83
|
+
throw new Error(
|
84
|
+
`VQL-ops-failed: Unrecognized operator ${k}`
|
85
|
+
);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
);
|
89
|
+
|
90
|
+
if(values.length===0)
|
91
|
+
return undefined;
|
92
|
+
|
93
|
+
return /** @type {Filter<any>} */ ({
|
94
|
+
[name]: values.reduce(
|
95
|
+
(p, c) => {
|
96
|
+
return { ...p, ...c }
|
97
|
+
},
|
98
|
+
{}
|
99
|
+
)
|
100
|
+
})
|
65
101
|
}
|
66
102
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
103
|
+
const reduced = utils.reduce_vql(
|
104
|
+
{
|
105
|
+
vql,
|
106
|
+
|
107
|
+
map_leaf: (node) => {
|
108
|
+
return leaf_ops(
|
109
|
+
node.op,
|
110
|
+
node.name
|
111
|
+
);
|
112
|
+
},
|
113
|
+
|
114
|
+
reduce_AND: identity(
|
115
|
+
(nodes) => {
|
116
|
+
return /** @type {Filter<any>} */({
|
117
|
+
$and: nodes
|
118
|
+
});
|
119
|
+
}
|
120
|
+
),
|
121
|
+
|
122
|
+
reduce_OR: (nodes) => {
|
123
|
+
return /** @type {Filter<any>} */({
|
124
|
+
$or: nodes
|
125
|
+
});
|
126
|
+
},
|
127
|
+
|
128
|
+
reduce_NOT: (node) => {
|
129
|
+
return /** @type {Filter<any>} */({
|
130
|
+
$nor: [node]
|
131
|
+
});
|
132
|
+
},
|
133
|
+
|
134
|
+
reduce_SEARCH: (value) => {
|
135
|
+
return /** @type {Filter<{_relations : { search: string[]}}>} */({
|
136
|
+
'_relations.search': { $regex: value }
|
137
|
+
});
|
138
|
+
},
|
76
139
|
|
77
|
-
/**
|
78
|
-
* @param {VQL.Node} node
|
79
|
-
*/
|
80
|
-
export const query_vql_node_to_mongo = node => {
|
81
|
-
if(node.op==='LEAF') {
|
82
|
-
return {
|
83
|
-
'_relations.search': { $regex: `${node.value}` }
|
84
140
|
}
|
85
|
-
}
|
86
|
-
|
87
|
-
let conjunctions = [];
|
88
|
-
for(let arg of node?.args) {
|
89
|
-
conjunctions.push(query_vql_node_to_mongo(arg));
|
90
|
-
}
|
91
141
|
|
92
|
-
|
93
|
-
case '&':
|
94
|
-
return {
|
95
|
-
$and: conjunctions
|
96
|
-
}
|
97
|
-
case '|':
|
98
|
-
return {
|
99
|
-
$or: conjunctions
|
100
|
-
}
|
101
|
-
case '!':
|
102
|
-
return {
|
103
|
-
$nor: [ conjunctions[0] ]
|
104
|
-
}
|
105
|
-
|
106
|
-
default:
|
107
|
-
throw new Error('VQL-to-mongo-failed')
|
108
|
-
}
|
142
|
+
);
|
109
143
|
|
144
|
+
return reduced;
|
110
145
|
}
|
111
146
|
|
112
147
|
/**
|
113
|
-
*
|
114
|
-
* @param {VQL.Node} root
|
115
|
-
*/
|
116
|
-
export const query_vql_to_mongo = root => {
|
117
|
-
return root ? query_vql_node_to_mongo(root) : undefined;
|
118
|
-
}
|
119
|
-
|
120
|
-
/**
|
121
|
-
* Let's transform ids into mongo ids
|
122
|
-
*
|
148
|
+
* @description Let's transform ids into mongo ids
|
123
149
|
* @param {Tuple} c a cursor record
|
124
|
-
*
|
125
150
|
* @returns {[k: string, v: any]}
|
126
151
|
*/
|
127
152
|
const transform = c => {
|
@@ -131,55 +156,55 @@ const transform = c => {
|
|
131
156
|
}
|
132
157
|
|
133
158
|
/**
|
134
|
-
* Convert an API Query into mongo dialect,
|
135
|
-
*
|
136
|
-
*
|
159
|
+
* @description Convert an API Query into mongo dialect,
|
160
|
+
* also sanitize.
|
137
161
|
* @param {ApiQuery<any>} q
|
138
162
|
*/
|
139
163
|
export const query_to_mongo = (q) => {
|
140
|
-
|
141
|
-
|
142
|
-
|
164
|
+
|
165
|
+
try { // compute VQL clauses
|
166
|
+
const parts = [
|
167
|
+
parse(q.vql),
|
168
|
+
// supports legacy queries with cursors, will be deprecated
|
169
|
+
// in future versions.
|
170
|
+
parse(
|
171
|
+
legacy_query_with_cursors_to_vql_string(q)
|
172
|
+
)
|
173
|
+
].filter(Boolean);
|
174
|
+
|
175
|
+
if(parts.length>0) {
|
176
|
+
q.vql = /** @type {VQL} */({
|
177
|
+
$and: parts
|
178
|
+
});
|
143
179
|
}
|
144
|
-
} catch(e) {
|
180
|
+
} catch(e) {
|
181
|
+
console.error('VQL parse error:\n', e, '\nfor query:\n', q);
|
182
|
+
}
|
183
|
+
|
184
|
+
/** @type {Filter<any>} */
|
185
|
+
const filter = query_vql_to_mongo_filter(
|
186
|
+
/** @type {VQL} */(q.vql)
|
187
|
+
);
|
145
188
|
|
146
|
-
const filter = {};
|
147
|
-
const clauses = [];
|
148
189
|
// `reverse_sign=-1` means we need to reverse because of `limitToLast`
|
149
|
-
const reverse_sign =
|
190
|
+
const reverse_sign = q.limitToLast ? -1 : 1;
|
150
191
|
const asc = q.order === 'asc';
|
151
192
|
const sort_sign = (asc ? 1 : -1) * reverse_sign;
|
152
193
|
|
153
|
-
// const sort_sign = (q.order === 'asc' ? 1 : -1) * reverse_sign;
|
154
|
-
// const asc = (sort_sign * reverse_sign)==1;
|
155
|
-
|
156
|
-
// compute index clauses
|
157
|
-
if(q.startAt) {
|
158
|
-
clauses.push(query_cursor_to_mongo(q.startAt, asc ? '>=' : '<=', transform));
|
159
|
-
} else if(q.startAfter) {
|
160
|
-
clauses.push(query_cursor_to_mongo(q.startAfter, asc ? '>' : '<', transform));
|
161
|
-
}
|
162
|
-
|
163
|
-
if(q.endAt) {
|
164
|
-
clauses.push(query_cursor_to_mongo(q.endAt, asc ? '<=' : '>=', transform));
|
165
|
-
} else if(q.endBefore) {
|
166
|
-
clauses.push(query_cursor_to_mongo(q.endBefore, asc ? '<' : '>', transform));
|
167
|
-
}
|
168
|
-
|
169
|
-
// compute VQL clauses
|
170
|
-
const vql_clause = query_vql_to_mongo(q.vqlParsed)
|
171
|
-
vql_clause && clauses.push(vql_clause);
|
172
|
-
|
173
194
|
// compute sort fields and order
|
174
|
-
|
175
|
-
|
195
|
+
/** @type {FindOptions["sort"]} */
|
196
|
+
const sort = (
|
197
|
+
q.sortBy?.length ?
|
198
|
+
q.sortBy :
|
199
|
+
['updated_at', 'id']
|
200
|
+
)
|
201
|
+
.reduce(
|
202
|
+
(p, c) => (
|
203
|
+
p[c]=sort_sign
|
204
|
+
) && p,
|
176
205
|
{}
|
177
206
|
);
|
178
207
|
|
179
|
-
if(clauses?.length) {
|
180
|
-
filter['$and'] = clauses;
|
181
|
-
}
|
182
|
-
|
183
208
|
return {
|
184
209
|
filter,
|
185
210
|
sort,
|
@@ -0,0 +1,189 @@
|
|
1
|
+
// /**
|
2
|
+
// * @import { ApiQuery, Cursor, Tuple } from '@storecraft/core/api'
|
3
|
+
// * @import { BOOLQL } from '@storecraft/core/vql'
|
4
|
+
// */
|
5
|
+
|
6
|
+
// import { to_objid } from "./utils.funcs.js";
|
7
|
+
// import { parse } from "@storecraft/core/vql";
|
8
|
+
|
9
|
+
// let a = {
|
10
|
+
// $or: [
|
11
|
+
// { updated_at: { $gt: '2024-01-24T20:28:24.126Z'} },
|
12
|
+
// { $and : [ { updated_at: '2024-01-24T20:28:24.126Z' }, { id: { $gte : 'tag_65b172ebc4c9552fd46c1027'}}]}
|
13
|
+
// ],
|
14
|
+
// }
|
15
|
+
|
16
|
+
// /**
|
17
|
+
// * Convert an API Query cursor into mongo dialect, also sanitize.
|
18
|
+
// *
|
19
|
+
// * 1. (a1, a2) > (b1, b2) ==> (a1 > b1) || (a1=b1 & a2>b2)
|
20
|
+
// * 2. (a1, a2) >= (b1, b2) ==> (a1 > b1) || (a1=b1 & a2>=b2)
|
21
|
+
// * 3. (a1, a2, a3) > (b1, b2, b3) ==> (a1 > b1) || (a1=b1 & a2>b2) || (a1=b1 & a2=b2 & a3>b3)
|
22
|
+
// * 4. (a1, a2, a3) >= (b1, b2, b3) ==> (a1 > b1) || (a1=b1 & a2>b2) || (a1=b1 & a2=b2 & a3>=b3)
|
23
|
+
// *
|
24
|
+
// *
|
25
|
+
// * @param {Cursor} c
|
26
|
+
// * @param {'>' | '>=' | '<' | '<='} relation
|
27
|
+
// * @param {(x: [k: string, v: any]) => [k: string, v: any]} transformer
|
28
|
+
// * Your chance to change key and value
|
29
|
+
// *
|
30
|
+
// */
|
31
|
+
// export const query_cursor_to_mongo = (c, relation, transformer=(x)=>x) => {
|
32
|
+
|
33
|
+
// let rel_key_1; // relation in last conjunction term in [0, n-1] disjunctions
|
34
|
+
// let rel_key_2; // relation in last conjunction term in last disjunction
|
35
|
+
|
36
|
+
// if (relation==='>' || relation==='>=') {
|
37
|
+
// rel_key_1 = rel_key_2 = '$gt';
|
38
|
+
// if(relation==='>=')
|
39
|
+
// rel_key_2='$gte';
|
40
|
+
// }
|
41
|
+
// else if (relation==='<' || relation==='<=') {
|
42
|
+
// rel_key_1 = rel_key_2 = '$lt';
|
43
|
+
// if(relation==='<=')
|
44
|
+
// rel_key_2='$lte';
|
45
|
+
// } else return undefined;
|
46
|
+
|
47
|
+
// const disjunctions = [];
|
48
|
+
// // each disjunction clause
|
49
|
+
// for (let ix = 0; ix < c.length; ix++) {
|
50
|
+
// const is_last_disjunction = ix==c.length-1;
|
51
|
+
// const conjunctions = [];
|
52
|
+
// // each conjunction clause up until the last term (not inclusive)
|
53
|
+
// for (let jx = 0; jx < ix; jx++) {
|
54
|
+
// // the a_n=b_n
|
55
|
+
// const r = transformer(c[jx]);
|
56
|
+
// conjunctions.push({ [r[0]] : r[1] });
|
57
|
+
// }
|
58
|
+
|
59
|
+
// // Last conjunction term
|
60
|
+
// const relation_key = is_last_disjunction ? rel_key_2 : rel_key_1;
|
61
|
+
// const r = transformer(c[ix]);
|
62
|
+
// conjunctions.push({ [r[0]] : { [relation_key]: r[1] } });
|
63
|
+
// // Add to disjunctions list
|
64
|
+
// disjunctions.push({ $and: conjunctions });
|
65
|
+
// }
|
66
|
+
|
67
|
+
// if(disjunctions.length==0)
|
68
|
+
// return undefined;
|
69
|
+
|
70
|
+
// const result = {
|
71
|
+
// $or: disjunctions
|
72
|
+
// };
|
73
|
+
|
74
|
+
// return result;
|
75
|
+
// }
|
76
|
+
|
77
|
+
// /**
|
78
|
+
// * @param {VQL.Node} node
|
79
|
+
// */
|
80
|
+
// export const query_vql_node_to_mongo = node => {
|
81
|
+
// if(node.op==='LEAF') {
|
82
|
+
// return {
|
83
|
+
// '_relations.search': { $regex: `${node.value}` }
|
84
|
+
// }
|
85
|
+
// }
|
86
|
+
|
87
|
+
// let conjunctions = [];
|
88
|
+
// for(let arg of node?.args) {
|
89
|
+
// conjunctions.push(query_vql_node_to_mongo(arg));
|
90
|
+
// }
|
91
|
+
|
92
|
+
// switch (node.op) {
|
93
|
+
// case '&':
|
94
|
+
// return {
|
95
|
+
// $and: conjunctions
|
96
|
+
// }
|
97
|
+
// case '|':
|
98
|
+
// return {
|
99
|
+
// $or: conjunctions
|
100
|
+
// }
|
101
|
+
// case '!':
|
102
|
+
// return {
|
103
|
+
// $nor: [ conjunctions[0] ]
|
104
|
+
// }
|
105
|
+
|
106
|
+
// default:
|
107
|
+
// throw new Error('VQL-to-mongo-failed')
|
108
|
+
// }
|
109
|
+
|
110
|
+
// }
|
111
|
+
|
112
|
+
// /**
|
113
|
+
// *
|
114
|
+
// * @param {VQL.Node} root
|
115
|
+
// */
|
116
|
+
// export const query_vql_to_mongo = root => {
|
117
|
+
// return root ? query_vql_node_to_mongo(root) : undefined;
|
118
|
+
// }
|
119
|
+
|
120
|
+
// /**
|
121
|
+
// * Let's transform ids into mongo ids
|
122
|
+
// *
|
123
|
+
// * @param {Tuple} c a cursor record
|
124
|
+
// *
|
125
|
+
// * @returns {[k: string, v: any]}
|
126
|
+
// */
|
127
|
+
// const transform = c => {
|
128
|
+
// if(c[0]!=='id')
|
129
|
+
// return c;
|
130
|
+
// return [ '_id', to_objid(String(c[1])) ];
|
131
|
+
// }
|
132
|
+
|
133
|
+
// /**
|
134
|
+
// * Convert an API Query into mongo dialect, also sanitize.
|
135
|
+
// *
|
136
|
+
// *
|
137
|
+
// * @param {ApiQuery<any>} q
|
138
|
+
// */
|
139
|
+
// export const query_to_mongo = (q) => {
|
140
|
+
// try {
|
141
|
+
// if(q.vql && !q.vqlParsed) {
|
142
|
+
// q.vqlParsed = parse(q.vql)
|
143
|
+
// }
|
144
|
+
// } catch(e) {}
|
145
|
+
|
146
|
+
// const filter = {};
|
147
|
+
// const clauses = [];
|
148
|
+
// // `reverse_sign=-1` means we need to reverse because of `limitToLast`
|
149
|
+
// const reverse_sign = (q.limitToLast && !q.limit) ? -1 : 1;
|
150
|
+
// const asc = q.order === 'asc';
|
151
|
+
// const sort_sign = (asc ? 1 : -1) * reverse_sign;
|
152
|
+
|
153
|
+
// // const sort_sign = (q.order === 'asc' ? 1 : -1) * reverse_sign;
|
154
|
+
// // const asc = (sort_sign * reverse_sign)==1;
|
155
|
+
|
156
|
+
// // compute index clauses
|
157
|
+
// if(q.startAt) {
|
158
|
+
// clauses.push(query_cursor_to_mongo(q.startAt, asc ? '>=' : '<=', transform));
|
159
|
+
// } else if(q.startAfter) {
|
160
|
+
// clauses.push(query_cursor_to_mongo(q.startAfter, asc ? '>' : '<', transform));
|
161
|
+
// }
|
162
|
+
|
163
|
+
// if(q.endAt) {
|
164
|
+
// clauses.push(query_cursor_to_mongo(q.endAt, asc ? '<=' : '>=', transform));
|
165
|
+
// } else if(q.endBefore) {
|
166
|
+
// clauses.push(query_cursor_to_mongo(q.endBefore, asc ? '<' : '>', transform));
|
167
|
+
// }
|
168
|
+
|
169
|
+
// // compute VQL clauses
|
170
|
+
// const vql_clause = query_vql_to_mongo(q.vqlParsed)
|
171
|
+
// vql_clause && clauses.push(vql_clause);
|
172
|
+
|
173
|
+
// // compute sort fields and order
|
174
|
+
// const sort = (q.sortBy?.length ? q.sortBy : ['updated_at', 'id']).reduce(
|
175
|
+
// (p, c) => (p[c==='id' ? '_id' : c]=sort_sign) && p,
|
176
|
+
// {}
|
177
|
+
// );
|
178
|
+
|
179
|
+
// if(clauses?.length) {
|
180
|
+
// filter['$and'] = clauses;
|
181
|
+
// }
|
182
|
+
|
183
|
+
// return {
|
184
|
+
// filter,
|
185
|
+
// sort,
|
186
|
+
// reverse_sign
|
187
|
+
// }
|
188
|
+
|
189
|
+
// }
|