@signaldb/core 2.0.0-beta.19 → 2.0.0-beta.20
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/index25.cjs.js
CHANGED
|
@@ -15,8 +15,10 @@ const require_sortItems = require("./index24.cjs.js");
|
|
|
15
15
|
* the query after all:
|
|
16
16
|
* - `limit` or `skip`: the result is a window onto a larger set, and an item leaving the window has
|
|
17
17
|
* to be replaced by one the previous result never contained.
|
|
18
|
-
* - `fields` together with `sort
|
|
19
|
-
*
|
|
18
|
+
* - `fields` together with a `sort` the projection does not keep: the previous items are
|
|
19
|
+
* projected, so a sort key the projection dropped is no longer there to sort by. A projection
|
|
20
|
+
* that keeps every sort key is fine, and is the common case — a list sorted by the same date it
|
|
21
|
+
* displays.
|
|
20
22
|
* - a `null` selector, which matches nothing and is not worth a special case.
|
|
21
23
|
* @template T - The type of the items.
|
|
22
24
|
* @param previous - The query's previous result.
|
|
@@ -29,11 +31,40 @@ function incrementalQueryUpdate(previous, selector, options, changes) {
|
|
|
29
31
|
if (selector == null) return null;
|
|
30
32
|
const { sort, skip, limit, fields } = options || {};
|
|
31
33
|
if (skip != null) return null;
|
|
32
|
-
if (fields != null && sort != null) return null;
|
|
34
|
+
if (fields != null && sort != null && !sortKeysSurviveProjection(sort, fields)) return null;
|
|
33
35
|
if (limit != null && !windowStaysClosed(previous, selector, options, changes)) return null;
|
|
34
36
|
return mergeChangesetIntoResult(previous, selector, options, changes);
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
39
|
+
* Whether a projection keeps every field a sort is keyed on.
|
|
40
|
+
*
|
|
41
|
+
* The previous result is the projected items, so this decides whether they still carry what the
|
|
42
|
+
* sort needs. Both projection modes are covered, because `project` treats an all-zero spec as an
|
|
43
|
+
* exclusion and anything else as an inclusion:
|
|
44
|
+
*
|
|
45
|
+
* - An inclusion keeps a key when the key itself is included, or an ancestor of it is (`{a: 1}`
|
|
46
|
+
* keeps `a.b`), and always keeps `id` unless the spec excludes it outright.
|
|
47
|
+
* - An exclusion keeps a key unless the key or an ancestor of it is excluded.
|
|
48
|
+
*
|
|
49
|
+
* Anything it cannot account for is a "no": re-executing is slower, not wrong.
|
|
50
|
+
* @template T - The type of the items.
|
|
51
|
+
* @param sort - The query's sort.
|
|
52
|
+
* @param fields - The query's projection.
|
|
53
|
+
* @returns `true` when every sort key survives the projection.
|
|
54
|
+
*/
|
|
55
|
+
function sortKeysSurviveProjection(sort, fields) {
|
|
56
|
+
const entries = Object.entries(fields);
|
|
57
|
+
if (entries.length === 0) return true;
|
|
58
|
+
const isExclusion = entries.every(([, value]) => value === 0);
|
|
59
|
+
const pathsFor = (key) => key.split(".").map((_, index, parts) => parts.slice(0, index + 1).join("."));
|
|
60
|
+
return Object.keys(sort).every((key) => {
|
|
61
|
+
const paths = pathsFor(key);
|
|
62
|
+
if (isExclusion) return paths.every((path) => fields[path] !== 0);
|
|
63
|
+
if (key === "id") return fields.id !== 0;
|
|
64
|
+
return paths.some((path) => fields[path] === 1);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
37
68
|
* Whether two items are in the given order under the given sort, deciding ties against the caller.
|
|
38
69
|
*
|
|
39
70
|
* Uses the sort itself rather than a comparator of its own: a rule about which side of a window an
|
package/dist/index25.mjs
CHANGED
|
@@ -15,8 +15,10 @@ import sortItems from "./index24.mjs";
|
|
|
15
15
|
* the query after all:
|
|
16
16
|
* - `limit` or `skip`: the result is a window onto a larger set, and an item leaving the window has
|
|
17
17
|
* to be replaced by one the previous result never contained.
|
|
18
|
-
* - `fields` together with `sort
|
|
19
|
-
*
|
|
18
|
+
* - `fields` together with a `sort` the projection does not keep: the previous items are
|
|
19
|
+
* projected, so a sort key the projection dropped is no longer there to sort by. A projection
|
|
20
|
+
* that keeps every sort key is fine, and is the common case — a list sorted by the same date it
|
|
21
|
+
* displays.
|
|
20
22
|
* - a `null` selector, which matches nothing and is not worth a special case.
|
|
21
23
|
* @template T - The type of the items.
|
|
22
24
|
* @param previous - The query's previous result.
|
|
@@ -29,11 +31,40 @@ function incrementalQueryUpdate(previous, selector, options, changes) {
|
|
|
29
31
|
if (selector == null) return null;
|
|
30
32
|
const { sort, skip, limit, fields } = options || {};
|
|
31
33
|
if (skip != null) return null;
|
|
32
|
-
if (fields != null && sort != null) return null;
|
|
34
|
+
if (fields != null && sort != null && !sortKeysSurviveProjection(sort, fields)) return null;
|
|
33
35
|
if (limit != null && !windowStaysClosed(previous, selector, options, changes)) return null;
|
|
34
36
|
return mergeChangesetIntoResult(previous, selector, options, changes);
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
39
|
+
* Whether a projection keeps every field a sort is keyed on.
|
|
40
|
+
*
|
|
41
|
+
* The previous result is the projected items, so this decides whether they still carry what the
|
|
42
|
+
* sort needs. Both projection modes are covered, because `project` treats an all-zero spec as an
|
|
43
|
+
* exclusion and anything else as an inclusion:
|
|
44
|
+
*
|
|
45
|
+
* - An inclusion keeps a key when the key itself is included, or an ancestor of it is (`{a: 1}`
|
|
46
|
+
* keeps `a.b`), and always keeps `id` unless the spec excludes it outright.
|
|
47
|
+
* - An exclusion keeps a key unless the key or an ancestor of it is excluded.
|
|
48
|
+
*
|
|
49
|
+
* Anything it cannot account for is a "no": re-executing is slower, not wrong.
|
|
50
|
+
* @template T - The type of the items.
|
|
51
|
+
* @param sort - The query's sort.
|
|
52
|
+
* @param fields - The query's projection.
|
|
53
|
+
* @returns `true` when every sort key survives the projection.
|
|
54
|
+
*/
|
|
55
|
+
function sortKeysSurviveProjection(sort, fields) {
|
|
56
|
+
const entries = Object.entries(fields);
|
|
57
|
+
if (entries.length === 0) return true;
|
|
58
|
+
const isExclusion = entries.every(([, value]) => value === 0);
|
|
59
|
+
const pathsFor = (key) => key.split(".").map((_, index, parts) => parts.slice(0, index + 1).join("."));
|
|
60
|
+
return Object.keys(sort).every((key) => {
|
|
61
|
+
const paths = pathsFor(key);
|
|
62
|
+
if (isExclusion) return paths.every((path) => fields[path] !== 0);
|
|
63
|
+
if (key === "id") return fields.id !== 0;
|
|
64
|
+
return paths.some((path) => fields[path] === 1);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
37
68
|
* Whether two items are in the given order under the given sort, deciding ties against the caller.
|
|
38
69
|
*
|
|
39
70
|
* Uses the sort itself rather than a comparator of its own: a rule about which side of a window an
|
|
@@ -26,8 +26,10 @@ export interface QueryChangeset<T extends BaseItem> {
|
|
|
26
26
|
* the query after all:
|
|
27
27
|
* - `limit` or `skip`: the result is a window onto a larger set, and an item leaving the window has
|
|
28
28
|
* to be replaced by one the previous result never contained.
|
|
29
|
-
* - `fields` together with `sort
|
|
30
|
-
*
|
|
29
|
+
* - `fields` together with a `sort` the projection does not keep: the previous items are
|
|
30
|
+
* projected, so a sort key the projection dropped is no longer there to sort by. A projection
|
|
31
|
+
* that keeps every sort key is fine, and is the common case — a list sorted by the same date it
|
|
32
|
+
* displays.
|
|
31
33
|
* - a `null` selector, which matches nothing and is not worth a special case.
|
|
32
34
|
* @template T - The type of the items.
|
|
33
35
|
* @param previous - The query's previous result.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaldb/core",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.20",
|
|
4
4
|
"description": "SignalDB is a client-side database that provides a simple MongoDB-like interface to the data with first-class typescript support to achieve an optimistic UI. Data persistence can be achieved by using storage providers that store the data through a JSON interface to places such as localStorage.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "rimraf dist && vite build",
|