@signaldb/svelte 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.
@@ -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`: the previous items are projected, so the field the sort is keyed
30
- * on may no longer be there to sort by.
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.
@@ -21,8 +21,10 @@ const sortItems_1 = __importDefault(require("./sortItems"));
21
21
  * the query after all:
22
22
  * - `limit` or `skip`: the result is a window onto a larger set, and an item leaving the window has
23
23
  * to be replaced by one the previous result never contained.
24
- * - `fields` together with `sort`: the previous items are projected, so the field the sort is keyed
25
- * on may no longer be there to sort by.
24
+ * - `fields` together with a `sort` the projection does not keep: the previous items are
25
+ * projected, so a sort key the projection dropped is no longer there to sort by. A projection
26
+ * that keeps every sort key is fine, and is the common case — a list sorted by the same date it
27
+ * displays.
26
28
  * - a `null` selector, which matches nothing and is not worth a special case.
27
29
  * @template T - The type of the items.
28
30
  * @param previous - The query's previous result.
@@ -37,12 +39,48 @@ function incrementalQueryUpdate(previous, selector, options, changes) {
37
39
  const { sort, skip, limit, fields } = options || {};
38
40
  if (skip != null)
39
41
  return null;
40
- if (fields != null && sort != null)
42
+ if (fields != null && sort != null && !sortKeysSurviveProjection(sort, fields))
41
43
  return null;
42
44
  if (limit != null && !windowStaysClosed(previous, selector, options, changes))
43
45
  return null;
44
46
  return mergeChangesetIntoResult(previous, selector, options, changes);
45
47
  }
48
+ /**
49
+ * Whether a projection keeps every field a sort is keyed on.
50
+ *
51
+ * The previous result is the projected items, so this decides whether they still carry what the
52
+ * sort needs. Both projection modes are covered, because `project` treats an all-zero spec as an
53
+ * exclusion and anything else as an inclusion:
54
+ *
55
+ * - An inclusion keeps a key when the key itself is included, or an ancestor of it is (`{a: 1}`
56
+ * keeps `a.b`), and always keeps `id` unless the spec excludes it outright.
57
+ * - An exclusion keeps a key unless the key or an ancestor of it is excluded.
58
+ *
59
+ * Anything it cannot account for is a "no": re-executing is slower, not wrong.
60
+ * @template T - The type of the items.
61
+ * @param sort - The query's sort.
62
+ * @param fields - The query's projection.
63
+ * @returns `true` when every sort key survives the projection.
64
+ */
65
+ function sortKeysSurviveProjection(sort, fields) {
66
+ const entries = Object.entries(fields);
67
+ if (entries.length === 0)
68
+ return true;
69
+ const isExclusion = entries.every(([, value]) => value === 0);
70
+ // `a.b.c` is kept by `a`, by `a.b` and by `a.b.c`, and dropped by any of them under an
71
+ // exclusion — so both modes ask about the key and each of its ancestors.
72
+ const pathsFor = (key) => key
73
+ .split('.')
74
+ .map((_, index, parts) => parts.slice(0, index + 1).join('.'));
75
+ return Object.keys(sort).every((key) => {
76
+ const paths = pathsFor(key);
77
+ if (isExclusion)
78
+ return paths.every(path => fields[path] !== 0);
79
+ if (key === 'id')
80
+ return fields.id !== 0;
81
+ return paths.some(path => fields[path] === 1);
82
+ });
83
+ }
46
84
  /**
47
85
  * Whether two items are in the given order under the given sort, deciding ties against the caller.
48
86
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@signaldb/svelte",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.19",
4
+ "version": "2.0.0-beta.20",
5
5
  "scripts": {
6
6
  "build": "tsc -d --noEmit false",
7
7
  "analyze-bundle": "bundle-analyzer ./dist --upload-token=$BUNDLE_ANALYZER_UPLOAD_TOKEN --bundle-name=@signaldb/svelte",