@rebasepro/server-mongo 0.14.1-canary.g7e666eb → 0.14.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/server-mongo",
3
3
  "type": "module",
4
- "version": "0.14.1-canary.g7e666eb",
4
+ "version": "0.14.1",
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.14.1-canary.g7e666eb",
44
- "@rebasepro/types": "0.14.1-canary.g7e666eb",
45
- "@rebasepro/utils": "0.14.1-canary.g7e666eb"
43
+ "@rebasepro/common": "0.14.1",
44
+ "@rebasepro/types": "0.14.1",
45
+ "@rebasepro/utils": "0.14.1"
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.14.1-canary.g7e666eb"
58
+ "@rebasepro/server": "0.14.1"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "@rebasepro/server": {
@@ -292,6 +292,18 @@ export class MongoConditionBuilder {
292
292
  return this.combineConditionsWithAnd(conditions) ?? {};
293
293
  }
294
294
 
295
+ /**
296
+ * The primary key's name in a stored document.
297
+ *
298
+ * Rows leave this driver with `_id` renamed to `id` — see
299
+ * `MongoDataService.documentToRow` — so `id` is the only name a caller ever
300
+ * sees, and the one the SDK's own examples use for a tie-breaker. A sort
301
+ * document naming `id` names a field no document has: Mongo does not
302
+ * complain, it just returns them in natural order, so `.orderBy("id")` read
303
+ * as "no sort at all" with a 200 to go with it.
304
+ */
305
+ private static readonly ID_FIELD = "_id";
306
+
295
307
  /**
296
308
  * Build MongoDB sort options from Rebase options
297
309
  *
@@ -299,6 +311,15 @@ export class MongoConditionBuilder {
299
311
  * a multi-key sort is expressed directly: the keys are applied in insertion
300
312
  * order, each breaking ties on the one before it.
301
313
  *
314
+ * The id closes every sort, descending, for the same reason the Postgres
315
+ * driver appends `id DESC`: it is what makes the ordering *total*. Without
316
+ * it, two rows sharing a sort value are returned in whatever order the
317
+ * engine pleases, and that order is free to differ between two executions of
318
+ * the same query — so paging by `offset` over a non-unique sort column
319
+ * repeats some rows and skips others. A single-column sort has always had
320
+ * this exposure here; a multi-key sort merely made it easier to reach, since
321
+ * the whole point of the later keys is that the earlier ones tie.
322
+ *
302
323
  * @param orderBy - Field to order by, or the `[field, direction]` list
303
324
  * @param order - Sort direction, for the single-field spelling
304
325
  * @returns MongoDB sort object
@@ -314,7 +335,13 @@ export class MongoConditionBuilder {
314
335
  // would sort by, and letting a later duplicate overwrite it would order
315
336
  // by a direction the caller listed as less significant.
316
337
  for (const [field, direction] of keys) {
317
- if (!(field in sort)) sort[field] = direction === "desc" ? -1 : 1;
338
+ const key = field === "id" ? MongoConditionBuilder.ID_FIELD : field;
339
+ if (!(key in sort)) sort[key] = direction === "desc" ? -1 : 1;
340
+ }
341
+ // Already named by the caller — at whatever direction and rank they
342
+ // chose — the sort is total and there is nothing left to break.
343
+ if (!(MongoConditionBuilder.ID_FIELD in sort)) {
344
+ sort[MongoConditionBuilder.ID_FIELD] = -1;
318
345
  }
319
346
  return sort;
320
347
  }