@rebasepro/server-mongo 0.13.0 → 0.13.1-canary.g18cfeb7

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;AAkD3C;;;;;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
@@ -90,9 +90,16 @@ function escapeRegExp$1(str) {
90
90
  */
91
91
  function likePatternToRegExp(pattern, caseInsensitive) {
92
92
  let body = "";
93
- for (const ch of String(pattern)) if (ch === "%") body += ".*";
94
- else if (ch === "_") body += ".";
95
- else body += escapeRegExp$1(ch);
93
+ let lastWasWildcard = false;
94
+ for (const ch of String(pattern)) {
95
+ if (ch === "%") {
96
+ if (!lastWasWildcard) body += ".*";
97
+ lastWasWildcard = true;
98
+ continue;
99
+ }
100
+ body += ch === "_" ? "." : escapeRegExp$1(ch);
101
+ lastWasWildcard = false;
102
+ }
96
103
  return new RegExp(`^${body}$`, caseInsensitive ? "i" : "");
97
104
  }
98
105
  /**
@@ -114,29 +121,57 @@ var MongoConditionBuilder = class {
114
121
  for (const [field, filterParam] of Object.entries(filter)) {
115
122
  if (!filterParam) continue;
116
123
  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}`);
124
+ const condition = this.buildCondition(field, op, value);
125
+ if (condition) conditions.push(condition);
126
+ }
127
+ return conditions;
128
+ }
129
+ /**
130
+ * One field, one operator, one value.
131
+ *
132
+ * Extracted so that `logical` groups translate through exactly this code.
133
+ * A group written as a second dialect is a group where `array-contains` or
134
+ * `ilike` quietly means something else than it does in `filter`, which is
135
+ * the kind of difference nobody finds until a query returns the wrong rows.
136
+ */
137
+ static buildCondition(field, op, value) {
138
+ if (op === "is-null") return { [field]: { $eq: null } };
139
+ if (op === "is-not-null") return { [field]: { $ne: null } };
140
+ if (op === "like" || op === "ilike" || op === "not-like" || op === "not-ilike") {
141
+ const regex = likePatternToRegExp(value, op === "ilike" || op === "not-ilike");
142
+ const negated = op === "not-like" || op === "not-ilike";
143
+ return { [field]: negated ? { $not: regex } : { $regex: regex } };
144
+ }
145
+ const mongoOp = REBASE_TO_MONGO_OP[op];
146
+ if (!mongoOp) {
147
+ logger.warn(`Unsupported filter operator: ${op}`);
148
+ return;
149
+ }
150
+ if (op === "array-contains") return { [field]: { $elemMatch: { $eq: value } } };
151
+ return { [field]: { [mongoOp]: value } };
152
+ }
153
+ /**
154
+ * Translate an `or(...)` / `and(...)` group, nesting included.
155
+ *
156
+ * Returns `undefined` for a group with nothing in it. `$or: []` is an error
157
+ * in Mongo and `$and: []` matches every document, so neither is a
158
+ * defensible reading of "no conditions".
159
+ */
160
+ static buildLogicalConditions(logical) {
161
+ if (!logical || !Array.isArray(logical.conditions)) return void 0;
162
+ const parts = [];
163
+ for (const entry of logical.conditions) {
164
+ if (!entry) continue;
165
+ if ("type" in entry && "conditions" in entry) {
166
+ const nested = this.buildLogicalConditions(entry);
167
+ if (nested) parts.push(nested);
134
168
  continue;
135
169
  }
136
- if (op === "array-contains") conditions.push({ [field]: { $elemMatch: { $eq: value } } });
137
- else conditions.push({ [field]: { [mongoOp]: value } });
170
+ const { column, operator, value } = entry;
171
+ const condition = this.buildCondition(column, operator, value);
172
+ if (condition) parts.push(condition);
138
173
  }
139
- return conditions;
174
+ return logical.type === "or" ? this.combineConditionsWithOr(parts) : this.combineConditionsWithAnd(parts);
140
175
  }
141
176
  /**
142
177
  * Build search conditions for text search
@@ -188,6 +223,8 @@ var MongoConditionBuilder = class {
188
223
  const filterConditions = this.buildFilterConditions(options.filter);
189
224
  conditions.push(...filterConditions);
190
225
  }
226
+ const logicalCondition = this.buildLogicalConditions(options.logical);
227
+ if (logicalCondition) conditions.push(logicalCondition);
191
228
  if (options.searchString && options.properties) {
192
229
  const searchConditions = this.buildSearchConditions(options.searchString, options.properties);
193
230
  if (searchConditions.length > 0) {
@@ -327,6 +364,7 @@ var MongoDataService = class {
327
364
  const collection = this.getCollection(collectionPath);
328
365
  const query = options.rawQuery ?? MongoConditionBuilder.buildQuery({
329
366
  filter: options.filter,
367
+ logical: options.logical,
330
368
  searchString: options.searchString,
331
369
  properties: options.collection?.properties ?? {}
332
370
  });
@@ -335,6 +373,7 @@ var MongoDataService = class {
335
373
  if (sort) findOptions.sort = sort;
336
374
  if (options.limit) findOptions.limit = options.limit;
337
375
  if (options.startAfter !== void 0) findOptions.skip = Number(options.startAfter);
376
+ else if (options.offset) findOptions.skip = options.offset;
338
377
  return (await collection.find(query, findOptions).toArray()).map((doc) => this.documentToRow(doc));
339
378
  }
340
379
  /**
@@ -351,7 +390,12 @@ var MongoDataService = class {
351
390
  */
352
391
  async count(collectionPath, options = {}) {
353
392
  const collection = this.getCollection(collectionPath);
354
- const query = options.rawQuery ?? (options.filter ? MongoConditionBuilder.buildQuery({ filter: options.filter }) : {});
393
+ const query = options.rawQuery ?? MongoConditionBuilder.buildQuery({
394
+ filter: options.filter,
395
+ logical: options.logical,
396
+ searchString: options.searchString,
397
+ properties: options.collection?.properties ?? {}
398
+ });
355
399
  return collection.countDocuments(query);
356
400
  }
357
401
  /**
@@ -876,14 +920,10 @@ var MongoDriver = class {
876
920
  /**
877
921
  * Fetch a collection of rows
878
922
  */
879
- async fetchCollection({ path, collection, filter, limit, startAfter, orderBy, searchString, order }) {
923
+ async fetchCollection(props) {
924
+ const { path, collection, ...query } = props;
880
925
  const rows = await this.dataService.fetchCollection(path, {
881
- filter,
882
- limit,
883
- startAfter,
884
- orderBy,
885
- order,
886
- searchString,
926
+ ...query,
887
927
  collection
888
928
  });
889
929
  const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);
@@ -1257,8 +1297,13 @@ var MongoDriver = class {
1257
1297
  /**
1258
1298
  * Count rows in a collection
1259
1299
  */
1260
- async count({ path, collection, filter }) {
1261
- return this.dataService.count(path, { filter });
1300
+ async count({ path, collection, filter, logical, searchString }) {
1301
+ return this.dataService.count(path, {
1302
+ filter,
1303
+ logical,
1304
+ searchString,
1305
+ collection
1306
+ });
1262
1307
  }
1263
1308
  /**
1264
1309
  * Generate a unique subscription ID