@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.
@@ -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,EAAE,YAAY,EAAiB,MAAM,kBAAkB,CAAC;AACjF,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;IAqDrB;;;;;;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,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;KAC/C,GAAG,MAAM,CAAC,QAAQ,CAAC;IA2BpB;;;;;;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"}
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":"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"}
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
- if (op === "is-null") {
118
- conditions.push({ [field]: { $eq: null } });
119
- continue;
120
- }
121
- if (op === "is-not-null") {
122
- conditions.push({ [field]: { $ne: null } });
123
- continue;
124
- }
125
- if (op === "like" || op === "ilike" || op === "not-like" || op === "not-ilike") {
126
- const regex = likePatternToRegExp(value, op === "ilike" || op === "not-ilike");
127
- const negated = op === "not-like" || op === "not-ilike";
128
- conditions.push({ [field]: negated ? { $not: regex } : { $regex: regex } });
129
- continue;
130
- }
131
- const mongoOp = REBASE_TO_MONGO_OP[op];
132
- if (!mongoOp) {
133
- logger.warn(`Unsupported filter operator: ${op}`);
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
- if (op === "array-contains") conditions.push({ [field]: { $elemMatch: { $eq: value } } });
137
- else conditions.push({ [field]: { [mongoOp]: value } });
163
+ const { column, operator, value } = entry;
164
+ const condition = this.buildCondition(column, operator, value);
165
+ if (condition) parts.push(condition);
138
166
  }
139
- return conditions;
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 ?? (options.filter ? MongoConditionBuilder.buildQuery({ filter: options.filter }) : {});
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({ path, collection, filter, limit, startAfter, orderBy, searchString, order }) {
916
+ async fetchCollection(props) {
917
+ const { path, collection, ...query } = props;
880
918
  const rows = await this.dataService.fetchCollection(path, {
881
- filter,
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, { filter });
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