@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.
@@ -49,7 +49,7 @@ export declare class MongoDriver implements DataDriver {
49
49
  /**
50
50
  * Fetch a collection of rows
51
51
  */
52
- fetchCollection<M extends Record<string, any>>({ path, collection, filter, limit, startAfter, orderBy, searchString, order }: FetchCollectionProps<M>): Promise<Record<string, unknown>[]>;
52
+ fetchCollection<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<Record<string, unknown>[]>;
53
53
  /**
54
54
  * Listen to collection changes
55
55
  */
@@ -81,7 +81,7 @@ export declare class MongoDriver implements DataDriver {
81
81
  /**
82
82
  * Count rows in a collection
83
83
  */
84
- count<M extends Record<string, any>>({ path, collection, filter }: FetchCollectionProps<M>): Promise<number>;
84
+ count<M extends Record<string, any>>({ path, collection, filter, logical, searchString }: FetchCollectionProps<M>): Promise<number>;
85
85
  /**
86
86
  * Generate a unique subscription ID
87
87
  */
@@ -1 +1 @@
1
- {"version":3,"file":"MongoDriver.d.ts","sourceRoot":"","sources":["../../src/services/MongoDriver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MongoDriver.d.ts","sourceRoot":"","sources":["../../src/services/MongoDriver.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/server-mongo",
3
3
  "type": "module",
4
- "version": "0.13.0",
4
+ "version": "0.13.1-canary.g3660bd5",
5
5
  "description": "MongoDB backend for Rebase",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -40,9 +40,9 @@
40
40
  "dependencies": {
41
41
  "mongodb": "^7.5.0",
42
42
  "ws": "^8.21.1",
43
- "@rebasepro/common": "0.13.0",
44
- "@rebasepro/types": "0.13.0",
45
- "@rebasepro/utils": "0.13.0"
43
+ "@rebasepro/types": "0.13.1-canary.g3660bd5",
44
+ "@rebasepro/utils": "0.13.1-canary.g3660bd5",
45
+ "@rebasepro/common": "0.13.1-canary.g3660bd5"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/jest": "^30.0.0",
@@ -55,7 +55,7 @@
55
55
  "vite": "^8.1.5"
56
56
  },
57
57
  "peerDependencies": {
58
- "@rebasepro/server": "0.13.0"
58
+ "@rebasepro/server": "0.13.1-canary.g3660bd5"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "@rebasepro/server": {
@@ -4,7 +4,7 @@
4
4
  * Translates Rebase filter conditions to MongoDB query operators.
5
5
  */
6
6
 
7
- import { CollectionConfig, FilterValues, WhereFilterOp } from "@rebasepro/types";
7
+ import { CollectionConfig, FilterCondition, FilterValues, LogicalCondition, WhereFilterOp } from "@rebasepro/types";
8
8
  import { Filter, Document } from "mongodb";
9
9
  import { logger } from "@rebasepro/server";
10
10
 
@@ -67,48 +67,81 @@ export class MongoConditionBuilder {
67
67
  if (!filterParam) continue;
68
68
 
69
69
  const [op, value] = filterParam as [WhereFilterOp, any];
70
+ const condition = this.buildCondition(field, op, value);
71
+ if (condition) conditions.push(condition);
72
+ }
70
73
 
71
- // Null-testing operators ignore their value.
72
- if (op === "is-null") {
73
- conditions.push({ [field]: { $eq: null } });
74
- continue;
75
- }
76
- if (op === "is-not-null") {
77
- conditions.push({ [field]: { $ne: null } });
78
- continue;
79
- }
74
+ return conditions;
75
+ }
80
76
 
81
- // Pattern matching → regular expressions.
82
- if (op === "like" || op === "ilike" || op === "not-like" || op === "not-ilike") {
83
- const caseInsensitive = op === "ilike" || op === "not-ilike";
84
- const regex = likePatternToRegExp(value, caseInsensitive);
85
- const negated = op === "not-like" || op === "not-ilike";
86
- conditions.push({
87
- [field]: negated ? { $not: regex } : { $regex: regex }
88
- });
89
- continue;
90
- }
77
+ /**
78
+ * One field, one operator, one value.
79
+ *
80
+ * Extracted so that `logical` groups translate through exactly this code.
81
+ * A group written as a second dialect is a group where `array-contains` or
82
+ * `ilike` quietly means something else than it does in `filter`, which is
83
+ * the kind of difference nobody finds until a query returns the wrong rows.
84
+ */
85
+ private static buildCondition(
86
+ field: string,
87
+ op: WhereFilterOp,
88
+ value: any
89
+ ): Filter<Document> | undefined {
90
+ // Null-testing operators ignore their value.
91
+ if (op === "is-null") return { [field]: { $eq: null } };
92
+ if (op === "is-not-null") return { [field]: { $ne: null } };
91
93
 
92
- const mongoOp = REBASE_TO_MONGO_OP[op];
94
+ // Pattern matching → regular expressions.
95
+ if (op === "like" || op === "ilike" || op === "not-like" || op === "not-ilike") {
96
+ const caseInsensitive = op === "ilike" || op === "not-ilike";
97
+ const regex = likePatternToRegExp(value, caseInsensitive);
98
+ const negated = op === "not-like" || op === "not-ilike";
99
+ return { [field]: negated ? { $not: regex } : { $regex: regex } };
100
+ }
93
101
 
94
- if (!mongoOp) {
95
- logger.warn(`Unsupported filter operator: ${op}`);
96
- continue;
97
- }
102
+ const mongoOp = REBASE_TO_MONGO_OP[op];
98
103
 
99
- // Handle array-contains specially
100
- if (op === "array-contains") {
101
- conditions.push({
102
- [field]: { $elemMatch: { $eq: value } }
103
- });
104
- } else {
105
- conditions.push({
106
- [field]: { [mongoOp]: value }
107
- });
104
+ if (!mongoOp) {
105
+ logger.warn(`Unsupported filter operator: ${op}`);
106
+ return undefined;
107
+ }
108
+
109
+ // Handle array-contains specially
110
+ if (op === "array-contains") {
111
+ return { [field]: { $elemMatch: { $eq: value } } };
112
+ }
113
+ return { [field]: { [mongoOp]: value } };
114
+ }
115
+
116
+ /**
117
+ * Translate an `or(...)` / `and(...)` group, nesting included.
118
+ *
119
+ * Returns `undefined` for a group with nothing in it. `$or: []` is an error
120
+ * in Mongo and `$and: []` matches every document, so neither is a
121
+ * defensible reading of "no conditions".
122
+ */
123
+ static buildLogicalConditions(logical: LogicalCondition | undefined): Filter<Document> | undefined {
124
+ if (!logical || !Array.isArray(logical.conditions)) return undefined;
125
+
126
+ const parts: Filter<Document>[] = [];
127
+ for (const entry of logical.conditions) {
128
+ if (!entry) continue;
129
+ if ("type" in entry && "conditions" in entry) {
130
+ const nested = this.buildLogicalConditions(entry as LogicalCondition);
131
+ if (nested) parts.push(nested);
132
+ continue;
108
133
  }
134
+ const { column, operator, value } = entry as FilterCondition;
135
+ const condition = this.buildCondition(column, operator, value);
136
+ if (condition) parts.push(condition);
109
137
  }
110
138
 
111
- return conditions;
139
+ // Through the same combiners the rest of this class uses, so a
140
+ // one-condition group reads as the bare condition — identical to how
141
+ // `filter` would have expressed it — rather than as `{ $and: [x] }`.
142
+ return logical.type === "or"
143
+ ? this.combineConditionsWithOr(parts)
144
+ : this.combineConditionsWithAnd(parts);
112
145
  }
113
146
 
114
147
  /**
@@ -191,6 +224,13 @@ export class MongoConditionBuilder {
191
224
  */
192
225
  static buildQuery<M extends Record<string, any>>(options: {
193
226
  filter?: FilterValues<Extract<keyof M, string>>;
227
+ /**
228
+ * An `or(...)`/`and(...)` group, AND-ed with `filter` and
229
+ * `searchString` — the three are independent, as `FindParams`
230
+ * documents. Absent here until now, so a group that reached this
231
+ * driver was dropped and the read ran unfiltered.
232
+ */
233
+ logical?: LogicalCondition;
194
234
  searchString?: string;
195
235
  properties?: CollectionConfig["properties"];
196
236
  }): Filter<Document> {
@@ -202,6 +242,9 @@ export class MongoConditionBuilder {
202
242
  conditions.push(...filterConditions);
203
243
  }
204
244
 
245
+ const logicalCondition = this.buildLogicalConditions(options.logical);
246
+ if (logicalCondition) conditions.push(logicalCondition);
247
+
205
248
  // Add search conditions
206
249
  if (options.searchString && options.properties) {
207
250
  const searchConditions = this.buildSearchConditions(
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { Db, ObjectId, Collection, Document, FindOptions, Filter } from "mongodb";
9
- import { FilterValues, DataRepository, CollectionConfig, EntityReference } from "@rebasepro/types";
9
+ import { FilterValues, DataRepository, CollectionConfig, EntityReference, LogicalCondition } from "@rebasepro/types";
10
10
  import { MongoConditionBuilder } from "./MongoConditionBuilder";
11
11
  import { logger } from "@rebasepro/server";
12
12
 
@@ -193,9 +193,12 @@ export class MongoDataService implements DataRepository {
193
193
  collectionPath: string,
194
194
  options: {
195
195
  filter?: FilterValues<Extract<keyof M, string>>;
196
+ /** An `or(...)`/`and(...)` group, AND-ed with `filter`. */
197
+ logical?: LogicalCondition;
196
198
  orderBy?: string;
197
199
  order?: "desc" | "asc";
198
200
  limit?: number;
201
+ offset?: number;
199
202
  startAfter?: any;
200
203
  searchString?: string;
201
204
  databaseId?: string;
@@ -208,6 +211,7 @@ export class MongoDataService implements DataRepository {
208
211
  // Build query
209
212
  const query = options.rawQuery ?? MongoConditionBuilder.buildQuery<M>({
210
213
  filter: options.filter,
214
+ logical: options.logical,
211
215
  searchString: options.searchString,
212
216
  properties: options.collection?.properties ?? {}
213
217
  });
@@ -226,9 +230,14 @@ export class MongoDataService implements DataRepository {
226
230
  findOptions.limit = options.limit;
227
231
  }
228
232
 
229
- // Apply pagination (skip-based for now, cursor-based would be better)
233
+ // Apply pagination. `offset` is the parameter the REST layer and the
234
+ // SDK both speak; it was absent here, so every `?offset=` reaching this
235
+ // driver was discarded and page three served page one. `startAfter`
236
+ // stays as the older spelling and wins when both are given.
230
237
  if (options.startAfter !== undefined) {
231
238
  findOptions.skip = Number(options.startAfter);
239
+ } else if (options.offset) {
240
+ findOptions.skip = options.offset;
232
241
  }
233
242
 
234
243
  const docs = await collection.find(query, findOptions).toArray();
@@ -265,15 +274,25 @@ export class MongoDataService implements DataRepository {
265
274
  collectionPath: string,
266
275
  options: {
267
276
  filter?: FilterValues<Extract<keyof M, string>>;
277
+ /** An `or(...)`/`and(...)` group, AND-ed with `filter`. */
278
+ logical?: LogicalCondition;
279
+ searchString?: string;
280
+ collection?: CollectionConfig;
268
281
  databaseId?: string;
269
282
  rawQuery?: Filter<Document>;
270
283
  } = {}
271
284
  ): Promise<number> {
272
285
  const collection = this.getCollection(collectionPath);
273
286
 
274
- const query = options.rawQuery ?? (options.filter
275
- ? MongoConditionBuilder.buildQuery<M>({ filter: options.filter })
276
- : {});
287
+ // Every narrowing the listing applies has to apply here too, or the
288
+ // count describes a different query than the one it is reported
289
+ // against. `logical` and `searchString` were both missing.
290
+ const query = options.rawQuery ?? MongoConditionBuilder.buildQuery<M>({
291
+ filter: options.filter,
292
+ logical: options.logical,
293
+ searchString: options.searchString,
294
+ properties: options.collection?.properties ?? {}
295
+ });
277
296
 
278
297
  return collection.countDocuments(query);
279
298
  }
@@ -109,23 +109,17 @@ propertyCallbacks: undefined };
109
109
  /**
110
110
  * Fetch a collection of rows
111
111
  */
112
- async fetchCollection<M extends Record<string, any>>({
113
- path,
114
- collection,
115
- filter,
116
- limit,
117
- startAfter,
118
- orderBy,
119
- searchString,
120
- order
121
- }: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> {
112
+ async fetchCollection<M extends Record<string, any>>(
113
+ props: FetchCollectionProps<M>
114
+ ): Promise<Record<string, unknown>[]> {
115
+ // Forwarded whole rather than re-listed. The hand-written list here
116
+ // named eight of the eleven fields `FetchCollectionProps` declares, so
117
+ // `logical` and `offset` were accepted by every type-checked boundary
118
+ // above and then dropped — an `or(...)` query ran unfiltered and
119
+ // `?offset=` served page one.
120
+ const { path, collection, ...query } = props;
122
121
  const rows = await this.dataService.fetchCollection<M>(path, {
123
- filter,
124
- limit,
125
- startAfter,
126
- orderBy,
127
- order,
128
- searchString,
122
+ ...query,
129
123
  collection: collection as CollectionConfig
130
124
  });
131
125
 
@@ -656,9 +650,18 @@ propertyCallbacks: undefined };
656
650
  async count<M extends Record<string, any>>({
657
651
  path,
658
652
  collection,
659
- filter
653
+ filter,
654
+ logical,
655
+ searchString
660
656
  }: FetchCollectionProps<M>): Promise<number> {
661
- return this.dataService.count<M>(path, { filter });
657
+ // The same narrowing the listing gets, or the total describes a
658
+ // different query than the rows it is reported beside.
659
+ return this.dataService.count<M>(path, {
660
+ filter,
661
+ logical,
662
+ searchString,
663
+ collection: collection as CollectionConfig
664
+ });
662
665
  }
663
666
 
664
667
  /**