@rebasepro/client 0.14.0 → 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/dist/index.es.js +47 -27
- package/dist/index.es.js.map +1 -1
- package/dist/offline-query.d.ts +10 -3
- package/dist/sdk_query_builder.d.ts +5 -0
- package/package.json +4 -4
- package/src/collection.ts +6 -3
- package/src/offline-query.test.ts +20 -3
- package/src/offline-query.ts +54 -28
- package/src/sdk_query_builder.ts +9 -1
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_STORAGE_SOURCE_KEY, EntityReference, EntityRelation, GeoPoint, PUBLIC_STORAGE_PREFIX, RebaseApiError, RebaseApiError as RebaseApiError$1, RebaseClientError, RebaseClientError as RebaseClientError$1, Vector, isPublicStoragePath, toCanonicalOp } from "@rebasepro/types";
|
|
2
|
-
import { COMPOSITE_ID_SEPARATOR, QueryBuilder, RebasePaginationError, and, buildCompositeId, collectAllPages, cond, or, paginateFind, resolveFindWindow, serializeFilter, serializeLogicalCondition, serializeOrderBy } from "@rebasepro/common";
|
|
2
|
+
import { COMPOSITE_ID_SEPARATOR, QueryBuilder, RebasePaginationError, and, buildCompositeId, collectAllPages, cond, normalizeOrderBy, or, paginateFind, resolveFindWindow, serializeFilter, serializeLogicalCondition, serializeOrderBy } from "@rebasepro/common";
|
|
3
3
|
import { toSnakeCase } from "@rebasepro/utils";
|
|
4
4
|
//#region src/reviver.ts
|
|
5
5
|
function rebaseReviver(_key, value) {
|
|
@@ -1277,9 +1277,15 @@ var SDKQueryBuilder = class {
|
|
|
1277
1277
|
}
|
|
1278
1278
|
/**
|
|
1279
1279
|
* Order the results by a specific column.
|
|
1280
|
+
*
|
|
1281
|
+
* Call it again to add a tie-breaker rather than replace the sort: keys
|
|
1282
|
+
* apply in the order they were added, so
|
|
1283
|
+
* `.orderBy("roles").orderBy("created_at", "desc")` sorts by role and
|
|
1284
|
+
* shows the newest first within each one.
|
|
1280
1285
|
*/
|
|
1281
1286
|
orderBy(column, direction = "asc") {
|
|
1282
|
-
this.params.orderBy
|
|
1287
|
+
const existing = normalizeOrderBy(this.params.orderBy) ?? [];
|
|
1288
|
+
this.params.orderBy = [...existing, [column, direction]];
|
|
1283
1289
|
return this;
|
|
1284
1290
|
}
|
|
1285
1291
|
/**
|
|
@@ -1596,8 +1602,7 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
1596
1602
|
logical: params?.logical,
|
|
1597
1603
|
limit: params?.limit,
|
|
1598
1604
|
offset: window.driverOffset,
|
|
1599
|
-
orderBy: params?.orderBy
|
|
1600
|
-
order: params?.orderBy?.[1],
|
|
1605
|
+
orderBy: normalizeOrderBy(params?.orderBy),
|
|
1601
1606
|
searchString: params?.searchString,
|
|
1602
1607
|
searchExplain: params?.searchExplain
|
|
1603
1608
|
}, (incomingRows) => {
|
|
@@ -4099,27 +4104,43 @@ function matchesParams(row, params) {
|
|
|
4099
4104
|
* Sort in place, Postgres-style: nulls last ascending, first descending, with
|
|
4100
4105
|
* the row id as a tiebreak so paging through an unsorted-but-equal run does
|
|
4101
4106
|
* not shuffle rows between pages.
|
|
4107
|
+
*
|
|
4108
|
+
* The tiebreak runs *descending*, which is not a taste: every server-side sort
|
|
4109
|
+
* ends on `id DESC` — `FetchService.buildOrderExpressions` appends it to make
|
|
4110
|
+
* the ordering total, and the keyset cursor is built to match. This ran
|
|
4111
|
+
* ascending, so two rows sharing a sort value came back from the local overlay
|
|
4112
|
+
* in the opposite order to the server's, and {@link isLocallySortable} called
|
|
4113
|
+
* that page exactly reproducible while it was not.
|
|
4102
4114
|
*/
|
|
4103
4115
|
function sortRows(rows, orderBy) {
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
const sign = direction === "desc" ? -1 : 1;
|
|
4116
|
+
const keys = normalizeOrderBy(orderBy);
|
|
4117
|
+
if (!keys) return rows;
|
|
4107
4118
|
return rows.sort((a, b) => {
|
|
4108
|
-
const
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
const bNull = isNullish(toComparable(bv));
|
|
4112
|
-
if (aNull || bNull) {
|
|
4113
|
-
if (aNull && bNull) return tiebreak(a, b);
|
|
4114
|
-
return (aNull ? 1 : -1) * (direction === "desc" ? -1 : 1);
|
|
4119
|
+
for (const [field, direction = "asc"] of keys) {
|
|
4120
|
+
const cmp = compareOnKey(a, b, field, direction);
|
|
4121
|
+
if (cmp !== 0) return cmp;
|
|
4115
4122
|
}
|
|
4116
|
-
|
|
4117
|
-
if (cmp === void 0 || cmp === 0) return tiebreak(a, b);
|
|
4118
|
-
return cmp * sign;
|
|
4123
|
+
return tiebreak(a, b);
|
|
4119
4124
|
});
|
|
4120
4125
|
}
|
|
4126
|
+
/** One key's verdict: negative, positive, or 0 for "these two are equal here". */
|
|
4127
|
+
function compareOnKey(a, b, field, direction) {
|
|
4128
|
+
const av = a[field];
|
|
4129
|
+
const bv = b[field];
|
|
4130
|
+
const aNull = isNullish(toComparable(av));
|
|
4131
|
+
const bNull = isNullish(toComparable(bv));
|
|
4132
|
+
if (aNull || bNull) {
|
|
4133
|
+
if (aNull && bNull) return 0;
|
|
4134
|
+
return (aNull ? 1 : -1) * (direction === "desc" ? -1 : 1);
|
|
4135
|
+
}
|
|
4136
|
+
const cmp = compareValues(av, bv);
|
|
4137
|
+
if (cmp === void 0 || cmp === 0) return 0;
|
|
4138
|
+
return cmp * (direction === "desc" ? -1 : 1);
|
|
4139
|
+
}
|
|
4140
|
+
/** The last word, and the server's: `id DESC`. */
|
|
4121
4141
|
function tiebreak(a, b) {
|
|
4122
|
-
|
|
4142
|
+
const cmp = compareValues(a.id, b.id);
|
|
4143
|
+
return cmp === void 0 ? 0 : -cmp;
|
|
4123
4144
|
}
|
|
4124
4145
|
/**
|
|
4125
4146
|
* Resolve `page`/`offset`/`limit` the way the server does.
|
|
@@ -4214,17 +4235,16 @@ function isExactlyEvaluable(params) {
|
|
|
4214
4235
|
* comparator.
|
|
4215
4236
|
*/
|
|
4216
4237
|
function isLocallySortable(rows, orderBy) {
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4238
|
+
const keys = normalizeOrderBy(orderBy);
|
|
4239
|
+
if (!keys) return true;
|
|
4240
|
+
return keys.every(([field]) => rows.every((row) => {
|
|
4220
4241
|
const value = toComparable(row[field]);
|
|
4221
|
-
if (isNullish(value))
|
|
4222
|
-
if (typeof value === "number" || typeof value === "boolean")
|
|
4223
|
-
if (typeof value === "bigint")
|
|
4224
|
-
if (typeof value === "string" && value.trim() !== "" && !Number.isNaN(Number(value)))
|
|
4242
|
+
if (isNullish(value)) return true;
|
|
4243
|
+
if (typeof value === "number" || typeof value === "boolean") return true;
|
|
4244
|
+
if (typeof value === "bigint") return true;
|
|
4245
|
+
if (typeof value === "string" && value.trim() !== "" && !Number.isNaN(Number(value))) return true;
|
|
4225
4246
|
return false;
|
|
4226
|
-
}
|
|
4227
|
-
return true;
|
|
4247
|
+
}));
|
|
4228
4248
|
}
|
|
4229
4249
|
/** Run a full query — filter, sort, paginate — over a set of rows. */
|
|
4230
4250
|
function runLocalQuery(rows, params) {
|