@rebasepro/server-mongo 0.13.0 → 0.13.1-canary.g3660bd5
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/db/MongoConditionBuilder.d.ts +25 -1
- package/dist/db/MongoConditionBuilder.d.ts.map +1 -1
- package/dist/db/MongoDataService.d.ts +8 -1
- package/dist/db/MongoDataService.d.ts.map +1 -1
- package/dist/index.es.js +68 -30
- package/dist/index.es.js.map +1 -1
- package/dist/services/MongoDriver.d.ts +2 -2
- package/dist/services/MongoDriver.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/db/MongoConditionBuilder.ts +78 -35
- package/src/db/MongoDataService.ts +24 -5
- package/src/services/MongoDriver.ts +21 -18
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Translates Rebase filter conditions to MongoDB query operators.
|
|
5
5
|
*/
|
|
6
|
-
import { CollectionConfig, FilterValues } from "@rebasepro/types";
|
|
6
|
+
import { CollectionConfig, FilterValues, LogicalCondition } from "@rebasepro/types";
|
|
7
7
|
import { Filter, Document } from "mongodb";
|
|
8
8
|
/**
|
|
9
9
|
* MongoDB Condition Builder
|
|
@@ -19,6 +19,23 @@ export declare class MongoConditionBuilder {
|
|
|
19
19
|
* @returns Array of MongoDB filter objects
|
|
20
20
|
*/
|
|
21
21
|
static buildFilterConditions<M extends Record<string, any>>(filter: FilterValues<Extract<keyof M, string>>): Filter<Document>[];
|
|
22
|
+
/**
|
|
23
|
+
* One field, one operator, one value.
|
|
24
|
+
*
|
|
25
|
+
* Extracted so that `logical` groups translate through exactly this code.
|
|
26
|
+
* A group written as a second dialect is a group where `array-contains` or
|
|
27
|
+
* `ilike` quietly means something else than it does in `filter`, which is
|
|
28
|
+
* the kind of difference nobody finds until a query returns the wrong rows.
|
|
29
|
+
*/
|
|
30
|
+
private static buildCondition;
|
|
31
|
+
/**
|
|
32
|
+
* Translate an `or(...)` / `and(...)` group, nesting included.
|
|
33
|
+
*
|
|
34
|
+
* Returns `undefined` for a group with nothing in it. `$or: []` is an error
|
|
35
|
+
* in Mongo and `$and: []` matches every document, so neither is a
|
|
36
|
+
* defensible reading of "no conditions".
|
|
37
|
+
*/
|
|
38
|
+
static buildLogicalConditions(logical: LogicalCondition | undefined): Filter<Document> | undefined;
|
|
22
39
|
/**
|
|
23
40
|
* Build search conditions for text search
|
|
24
41
|
*
|
|
@@ -49,6 +66,13 @@ export declare class MongoConditionBuilder {
|
|
|
49
66
|
*/
|
|
50
67
|
static buildQuery<M extends Record<string, any>>(options: {
|
|
51
68
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
69
|
+
/**
|
|
70
|
+
* An `or(...)`/`and(...)` group, AND-ed with `filter` and
|
|
71
|
+
* `searchString` — the three are independent, as `FindParams`
|
|
72
|
+
* documents. Absent here until now, so a group that reached this
|
|
73
|
+
* driver was dropped and the read ran unfiltered.
|
|
74
|
+
*/
|
|
75
|
+
logical?: LogicalCondition;
|
|
52
76
|
searchString?: string;
|
|
53
77
|
properties?: CollectionConfig["properties"];
|
|
54
78
|
}): Filter<Document>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoConditionBuilder.d.ts","sourceRoot":"","sources":["../../src/db/MongoConditionBuilder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"MongoConditionBuilder.d.ts","sourceRoot":"","sources":["../../src/db/MongoConditionBuilder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAmB,YAAY,EAAE,gBAAgB,EAAiB,MAAM,kBAAkB,CAAC;AACpH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAsC3C;;;;;GAKG;AACH,qBAAa,qBAAqB;IAC9B;;;;;OAKG;IACH,MAAM,CAAC,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACtD,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GAC/C,MAAM,CAAC,QAAQ,CAAC,EAAE;IAgBrB;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IA+B7B;;;;;;OAMG;IACH,MAAM,CAAC,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,SAAS;IAwBlG;;;;;;OAMG;IACH,MAAM,CAAC,qBAAqB,CACxB,YAAY,EAAE,MAAM,EAKpB,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,GAC3C,MAAM,CAAC,QAAQ,CAAC,EAAE;IAkCrB;;;;;OAKG;IACH,MAAM,CAAC,wBAAwB,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,SAAS;IAM7F;;;;;OAKG;IACH,MAAM,CAAC,uBAAuB,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,SAAS;IAM5F;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE;QACtD,MAAM,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD;;;;;WAKG;QACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;KAC/C,GAAG,MAAM,CAAC,QAAQ,CAAC;IA8BpB;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CACZ,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,GACvB,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS;CAIxC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provides all CRUD operations for rows.
|
|
6
6
|
*/
|
|
7
7
|
import { Db, Document, Filter } from "mongodb";
|
|
8
|
-
import { FilterValues, DataRepository, CollectionConfig } from "@rebasepro/types";
|
|
8
|
+
import { FilterValues, DataRepository, CollectionConfig, LogicalCondition } from "@rebasepro/types";
|
|
9
9
|
/**
|
|
10
10
|
* MongoDB Row Service
|
|
11
11
|
*
|
|
@@ -52,9 +52,12 @@ export declare class MongoDataService implements DataRepository {
|
|
|
52
52
|
*/
|
|
53
53
|
fetchCollection<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
54
54
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
55
|
+
/** An `or(...)`/`and(...)` group, AND-ed with `filter`. */
|
|
56
|
+
logical?: LogicalCondition;
|
|
55
57
|
orderBy?: string;
|
|
56
58
|
order?: "desc" | "asc";
|
|
57
59
|
limit?: number;
|
|
60
|
+
offset?: number;
|
|
58
61
|
startAfter?: any;
|
|
59
62
|
searchString?: string;
|
|
60
63
|
databaseId?: string;
|
|
@@ -78,6 +81,10 @@ export declare class MongoDataService implements DataRepository {
|
|
|
78
81
|
*/
|
|
79
82
|
count<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
80
83
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
84
|
+
/** An `or(...)`/`and(...)` group, AND-ed with `filter`. */
|
|
85
|
+
logical?: LogicalCondition;
|
|
86
|
+
searchString?: string;
|
|
87
|
+
collection?: CollectionConfig;
|
|
81
88
|
databaseId?: string;
|
|
82
89
|
rawQuery?: Filter<Document>;
|
|
83
90
|
}): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoDataService.d.ts","sourceRoot":"","sources":["../../src/db/MongoDataService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,EAAE,EAAwB,QAAQ,EAAe,MAAM,EAAE,MAAM,SAAS,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAmB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"MongoDataService.d.ts","sourceRoot":"","sources":["../../src/db/MongoDataService.ts"],"names":[],"mappings":"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"}
|
package/dist/index.es.js
CHANGED
|
@@ -114,29 +114,57 @@ var MongoConditionBuilder = class {
|
|
|
114
114
|
for (const [field, filterParam] of Object.entries(filter)) {
|
|
115
115
|
if (!filterParam) continue;
|
|
116
116
|
const [op, value] = filterParam;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
117
|
+
const condition = this.buildCondition(field, op, value);
|
|
118
|
+
if (condition) conditions.push(condition);
|
|
119
|
+
}
|
|
120
|
+
return conditions;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* One field, one operator, one value.
|
|
124
|
+
*
|
|
125
|
+
* Extracted so that `logical` groups translate through exactly this code.
|
|
126
|
+
* A group written as a second dialect is a group where `array-contains` or
|
|
127
|
+
* `ilike` quietly means something else than it does in `filter`, which is
|
|
128
|
+
* the kind of difference nobody finds until a query returns the wrong rows.
|
|
129
|
+
*/
|
|
130
|
+
static buildCondition(field, op, value) {
|
|
131
|
+
if (op === "is-null") return { [field]: { $eq: null } };
|
|
132
|
+
if (op === "is-not-null") return { [field]: { $ne: null } };
|
|
133
|
+
if (op === "like" || op === "ilike" || op === "not-like" || op === "not-ilike") {
|
|
134
|
+
const regex = likePatternToRegExp(value, op === "ilike" || op === "not-ilike");
|
|
135
|
+
const negated = op === "not-like" || op === "not-ilike";
|
|
136
|
+
return { [field]: negated ? { $not: regex } : { $regex: regex } };
|
|
137
|
+
}
|
|
138
|
+
const mongoOp = REBASE_TO_MONGO_OP[op];
|
|
139
|
+
if (!mongoOp) {
|
|
140
|
+
logger.warn(`Unsupported filter operator: ${op}`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (op === "array-contains") return { [field]: { $elemMatch: { $eq: value } } };
|
|
144
|
+
return { [field]: { [mongoOp]: value } };
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Translate an `or(...)` / `and(...)` group, nesting included.
|
|
148
|
+
*
|
|
149
|
+
* Returns `undefined` for a group with nothing in it. `$or: []` is an error
|
|
150
|
+
* in Mongo and `$and: []` matches every document, so neither is a
|
|
151
|
+
* defensible reading of "no conditions".
|
|
152
|
+
*/
|
|
153
|
+
static buildLogicalConditions(logical) {
|
|
154
|
+
if (!logical || !Array.isArray(logical.conditions)) return void 0;
|
|
155
|
+
const parts = [];
|
|
156
|
+
for (const entry of logical.conditions) {
|
|
157
|
+
if (!entry) continue;
|
|
158
|
+
if ("type" in entry && "conditions" in entry) {
|
|
159
|
+
const nested = this.buildLogicalConditions(entry);
|
|
160
|
+
if (nested) parts.push(nested);
|
|
134
161
|
continue;
|
|
135
162
|
}
|
|
136
|
-
|
|
137
|
-
|
|
163
|
+
const { column, operator, value } = entry;
|
|
164
|
+
const condition = this.buildCondition(column, operator, value);
|
|
165
|
+
if (condition) parts.push(condition);
|
|
138
166
|
}
|
|
139
|
-
return
|
|
167
|
+
return logical.type === "or" ? this.combineConditionsWithOr(parts) : this.combineConditionsWithAnd(parts);
|
|
140
168
|
}
|
|
141
169
|
/**
|
|
142
170
|
* Build search conditions for text search
|
|
@@ -188,6 +216,8 @@ var MongoConditionBuilder = class {
|
|
|
188
216
|
const filterConditions = this.buildFilterConditions(options.filter);
|
|
189
217
|
conditions.push(...filterConditions);
|
|
190
218
|
}
|
|
219
|
+
const logicalCondition = this.buildLogicalConditions(options.logical);
|
|
220
|
+
if (logicalCondition) conditions.push(logicalCondition);
|
|
191
221
|
if (options.searchString && options.properties) {
|
|
192
222
|
const searchConditions = this.buildSearchConditions(options.searchString, options.properties);
|
|
193
223
|
if (searchConditions.length > 0) {
|
|
@@ -327,6 +357,7 @@ var MongoDataService = class {
|
|
|
327
357
|
const collection = this.getCollection(collectionPath);
|
|
328
358
|
const query = options.rawQuery ?? MongoConditionBuilder.buildQuery({
|
|
329
359
|
filter: options.filter,
|
|
360
|
+
logical: options.logical,
|
|
330
361
|
searchString: options.searchString,
|
|
331
362
|
properties: options.collection?.properties ?? {}
|
|
332
363
|
});
|
|
@@ -335,6 +366,7 @@ var MongoDataService = class {
|
|
|
335
366
|
if (sort) findOptions.sort = sort;
|
|
336
367
|
if (options.limit) findOptions.limit = options.limit;
|
|
337
368
|
if (options.startAfter !== void 0) findOptions.skip = Number(options.startAfter);
|
|
369
|
+
else if (options.offset) findOptions.skip = options.offset;
|
|
338
370
|
return (await collection.find(query, findOptions).toArray()).map((doc) => this.documentToRow(doc));
|
|
339
371
|
}
|
|
340
372
|
/**
|
|
@@ -351,7 +383,12 @@ var MongoDataService = class {
|
|
|
351
383
|
*/
|
|
352
384
|
async count(collectionPath, options = {}) {
|
|
353
385
|
const collection = this.getCollection(collectionPath);
|
|
354
|
-
const query = options.rawQuery ??
|
|
386
|
+
const query = options.rawQuery ?? MongoConditionBuilder.buildQuery({
|
|
387
|
+
filter: options.filter,
|
|
388
|
+
logical: options.logical,
|
|
389
|
+
searchString: options.searchString,
|
|
390
|
+
properties: options.collection?.properties ?? {}
|
|
391
|
+
});
|
|
355
392
|
return collection.countDocuments(query);
|
|
356
393
|
}
|
|
357
394
|
/**
|
|
@@ -876,14 +913,10 @@ var MongoDriver = class {
|
|
|
876
913
|
/**
|
|
877
914
|
* Fetch a collection of rows
|
|
878
915
|
*/
|
|
879
|
-
async fetchCollection(
|
|
916
|
+
async fetchCollection(props) {
|
|
917
|
+
const { path, collection, ...query } = props;
|
|
880
918
|
const rows = await this.dataService.fetchCollection(path, {
|
|
881
|
-
|
|
882
|
-
limit,
|
|
883
|
-
startAfter,
|
|
884
|
-
orderBy,
|
|
885
|
-
order,
|
|
886
|
-
searchString,
|
|
919
|
+
...query,
|
|
887
920
|
collection
|
|
888
921
|
});
|
|
889
922
|
const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);
|
|
@@ -1257,8 +1290,13 @@ var MongoDriver = class {
|
|
|
1257
1290
|
/**
|
|
1258
1291
|
* Count rows in a collection
|
|
1259
1292
|
*/
|
|
1260
|
-
async count({ path, collection, filter }) {
|
|
1261
|
-
return this.dataService.count(path, {
|
|
1293
|
+
async count({ path, collection, filter, logical, searchString }) {
|
|
1294
|
+
return this.dataService.count(path, {
|
|
1295
|
+
filter,
|
|
1296
|
+
logical,
|
|
1297
|
+
searchString,
|
|
1298
|
+
collection
|
|
1299
|
+
});
|
|
1262
1300
|
}
|
|
1263
1301
|
/**
|
|
1264
1302
|
* Generate a unique subscription ID
|