@thomasfosterau/pulpit 0.0.0 → 0.1.0

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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1271 -1
  3. package/dist/blobs.d.ts +249 -0
  4. package/dist/blobs.d.ts.map +1 -0
  5. package/dist/blobs.js +193 -0
  6. package/dist/blobs.js.map +1 -0
  7. package/dist/budgets.d.ts +255 -0
  8. package/dist/budgets.d.ts.map +1 -0
  9. package/dist/budgets.js +211 -0
  10. package/dist/budgets.js.map +1 -0
  11. package/dist/cache.d.ts +154 -0
  12. package/dist/cache.d.ts.map +1 -0
  13. package/dist/cache.js +118 -0
  14. package/dist/cache.js.map +1 -0
  15. package/dist/collections.d.ts +242 -0
  16. package/dist/collections.d.ts.map +1 -0
  17. package/dist/collections.js +215 -0
  18. package/dist/collections.js.map +1 -0
  19. package/dist/comments.d.ts +212 -0
  20. package/dist/comments.d.ts.map +1 -0
  21. package/dist/comments.js +192 -0
  22. package/dist/comments.js.map +1 -0
  23. package/dist/content.d.ts +231 -0
  24. package/dist/content.d.ts.map +1 -0
  25. package/dist/content.js +204 -0
  26. package/dist/content.js.map +1 -0
  27. package/dist/documents.d.ts +184 -0
  28. package/dist/documents.d.ts.map +1 -0
  29. package/dist/documents.js +190 -0
  30. package/dist/documents.js.map +1 -0
  31. package/dist/edges.d.ts +645 -0
  32. package/dist/edges.d.ts.map +1 -0
  33. package/dist/edges.js +558 -0
  34. package/dist/edges.js.map +1 -0
  35. package/dist/filter.d.ts +461 -0
  36. package/dist/filter.d.ts.map +1 -0
  37. package/dist/filter.js +387 -0
  38. package/dist/filter.js.map +1 -0
  39. package/dist/index.d.ts +133 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +133 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/internal/filter-columns.d.ts +8 -0
  44. package/dist/internal/filter-columns.d.ts.map +1 -0
  45. package/dist/internal/filter-columns.js +43 -0
  46. package/dist/internal/filter-columns.js.map +1 -0
  47. package/dist/internal/list-order.d.ts +26 -0
  48. package/dist/internal/list-order.d.ts.map +1 -0
  49. package/dist/internal/list-order.js +92 -0
  50. package/dist/internal/list-order.js.map +1 -0
  51. package/dist/internal/owned-columns.d.ts +93 -0
  52. package/dist/internal/owned-columns.d.ts.map +1 -0
  53. package/dist/internal/owned-columns.js +98 -0
  54. package/dist/internal/owned-columns.js.map +1 -0
  55. package/dist/internal/plain-rows.d.ts +32 -0
  56. package/dist/internal/plain-rows.d.ts.map +1 -0
  57. package/dist/internal/plain-rows.js +32 -0
  58. package/dist/internal/plain-rows.js.map +1 -0
  59. package/dist/internal/reference-columns.d.ts +80 -0
  60. package/dist/internal/reference-columns.d.ts.map +1 -0
  61. package/dist/internal/reference-columns.js +102 -0
  62. package/dist/internal/reference-columns.js.map +1 -0
  63. package/dist/moderation.d.ts +392 -0
  64. package/dist/moderation.d.ts.map +1 -0
  65. package/dist/moderation.js +375 -0
  66. package/dist/moderation.js.map +1 -0
  67. package/dist/paths.d.ts +204 -0
  68. package/dist/paths.d.ts.map +1 -0
  69. package/dist/paths.js +165 -0
  70. package/dist/paths.js.map +1 -0
  71. package/dist/proposals.d.ts +523 -0
  72. package/dist/proposals.d.ts.map +1 -0
  73. package/dist/proposals.js +505 -0
  74. package/dist/proposals.js.map +1 -0
  75. package/dist/publication.d.ts +148 -0
  76. package/dist/publication.d.ts.map +1 -0
  77. package/dist/publication.js +183 -0
  78. package/dist/publication.js.map +1 -0
  79. package/dist/purge.d.ts +224 -0
  80. package/dist/purge.d.ts.map +1 -0
  81. package/dist/purge.js +151 -0
  82. package/dist/purge.js.map +1 -0
  83. package/dist/reactions.d.ts +246 -0
  84. package/dist/reactions.d.ts.map +1 -0
  85. package/dist/reactions.js +183 -0
  86. package/dist/reactions.js.map +1 -0
  87. package/dist/registry.d.ts +316 -0
  88. package/dist/registry.d.ts.map +1 -0
  89. package/dist/registry.js +305 -0
  90. package/dist/registry.js.map +1 -0
  91. package/dist/search.d.ts +366 -0
  92. package/dist/search.d.ts.map +1 -0
  93. package/dist/search.js +273 -0
  94. package/dist/search.js.map +1 -0
  95. package/dist/social.d.ts +311 -0
  96. package/dist/social.d.ts.map +1 -0
  97. package/dist/social.js +205 -0
  98. package/dist/social.js.map +1 -0
  99. package/dist/subtype.d.ts +1613 -0
  100. package/dist/subtype.d.ts.map +1 -0
  101. package/dist/subtype.js +1300 -0
  102. package/dist/subtype.js.map +1 -0
  103. package/dist/testing.d.ts +675 -0
  104. package/dist/testing.d.ts.map +1 -0
  105. package/dist/testing.js +1022 -0
  106. package/dist/testing.js.map +1 -0
  107. package/dist/version-chain.d.ts +702 -0
  108. package/dist/version-chain.d.ts.map +1 -0
  109. package/dist/version-chain.js +489 -0
  110. package/dist/version-chain.js.map +1 -0
  111. package/dist/working-copy.d.ts +116 -0
  112. package/dist/working-copy.d.ts.map +1 -0
  113. package/dist/working-copy.js +95 -0
  114. package/dist/working-copy.js.map +1 -0
  115. package/package.json +138 -4
  116. package/src/blobs.ts +384 -0
  117. package/src/budgets.ts +338 -0
  118. package/src/cache.ts +218 -0
  119. package/src/collections.ts +427 -0
  120. package/src/comments.ts +392 -0
  121. package/src/content.ts +238 -0
  122. package/src/documents.ts +284 -0
  123. package/src/edges.ts +1185 -0
  124. package/src/filter.ts +523 -0
  125. package/src/index.ts +153 -0
  126. package/src/internal/filter-columns.ts +50 -0
  127. package/src/internal/list-order.ts +117 -0
  128. package/src/internal/owned-columns.ts +140 -0
  129. package/src/internal/plain-rows.ts +54 -0
  130. package/src/internal/reference-columns.ts +156 -0
  131. package/src/moderation.ts +728 -0
  132. package/src/paths.ts +267 -0
  133. package/src/proposals.ts +1014 -0
  134. package/src/publication.ts +225 -0
  135. package/src/purge.ts +313 -0
  136. package/src/reactions.ts +347 -0
  137. package/src/registry.ts +524 -0
  138. package/src/search.ts +540 -0
  139. package/src/social.ts +469 -0
  140. package/src/subtype.ts +3095 -0
  141. package/src/testing.ts +1873 -0
  142. package/src/version-chain.ts +1093 -0
  143. package/src/working-copy.ts +192 -0
package/dist/filter.js ADDED
@@ -0,0 +1,387 @@
1
+ /**
2
+ * **The list-filter vocabulary** — the kernel's read predicates as data.
3
+ *
4
+ * Every visibility, soft-delete and publication rule the kernel owns has two
5
+ * readings: a per-row answer (may this viewer see this row?) and a set-shaped
6
+ * answer a LIST turns into its `WHERE`. In the apps the second is Drizzle SQL
7
+ * built inline (`ownedListFilterE`, `loadListVisibilityFilters`,
8
+ * `publishedFilter`), which ties the rule to one database layer and makes the
9
+ * two readings impossible to compare. Here the set-shaped answer is a small
10
+ * predicate tree, {@link ListFilter}: a Drizzle renderer (the seam
11
+ * effect-drizzle-ext / effect-auth-drizzle fill, see the package README →
12
+ * Seams) turns it into SQL, and
13
+ * {@link evaluate} runs it against an in-memory row — which is what lets the
14
+ * unit suite prove the list filter and the row predicate never disagree.
15
+ *
16
+ * `Following` is whatever a seam hands the `in` node: the follower seam's
17
+ * set of followed accounts, or an edge family's members
18
+ * (`EdgeStore.members`, pulpit#113); a subquery (`SQLWrapper`) for SQL, a
19
+ * set for the in-memory evaluator. The `notIn` node takes the same
20
+ * `Following`, for an exclusion (`EdgeOps.nonMemberFilter`, pulpit#191).
21
+ *
22
+ * Rendering contract a SQL renderer must honour:
23
+ *
24
+ * | node | SQL |
25
+ * | --- | --- |
26
+ * | `always` | no predicate (`undefined` to Drizzle's `.where`) |
27
+ * | `never` | a predicate no row satisfies (the apps: `id = '00000000-…'`) |
28
+ * | `eq` / `ne` | `col = $v` / `col <> $v` — a `NULL` column satisfies neither |
29
+ * | `in` | `col IN (<seam subquery>)` — a subquery, never a materialised array (#1107); a `NULL` column satisfies none |
30
+ * | `notIn` | `(col IS NULL OR col NOT IN (<seam subquery>))` — the complement of `in` over the same subquery (pulpit#191); a `NULL` column satisfies it, and the subquery must never yield a `NULL` (`NOT IN` over a set holding one is `NULL` for every row) |
31
+ * | `gt` / `gte` / `lt` / `lte` | `col > $v` / `col >= $v` / `col < $v` / `col <= $v` — a string compared with `COLLATE "C"` (code-point order), a `Date` as a timestamp, a number numerically (`±Infinity` included); a `NULL` column satisfies none |
32
+ * | `anyOf` | `col = ANY($values)` — a `NULL` column satisfies none; empty is `never`; never a `NULL` element |
33
+ * | `noneOf` | `col <> ALL($values)` — a `NULL` column satisfies none; empty is `always` (`<> ALL` over no values is true); never a `NULL` element (`<> ALL('{1,NULL}')` is `NULL` for every row outside the set) |
34
+ * | `isNull` | `col IS NULL` — the one node a `NULL` column satisfies by itself |
35
+ * | `published` | `(col IS NOT NULL AND col <= now())` — the database's clock, one per query |
36
+ * | `notPublished` | `(col IS NULL OR col > now())` — parenthesised, so it cannot bind to a surrounding `AND` |
37
+ * | `locale` | `col = ANY($locales)` over the view's locale column (pulpit#56) — as `anyOf`; on a view with no locale level, `never` |
38
+ * | `and` / `or` | `AND` / `OR` over the parts |
39
+ *
40
+ * An `anyOf` / `noneOf` node carrying more than {@link MAX_SET_VALUES} values,
41
+ * duplicates counted, is `never`, in the renderer as in {@link evaluate}
42
+ * (`SEC-INPUT-003`); the constructors already fold it so.
43
+ *
44
+ * Outside the contract, where SQL and {@link evaluate} cannot be made to
45
+ * agree, `evaluate` fails closed:
46
+ *
47
+ * - **A column of another type than the comparand** (or than any of a
48
+ * literal set's values) is a caller or schema error. SQL may coerce the
49
+ * parameter (an `integer` column against `'1'`) or raise (against
50
+ * `'abc'`); `evaluate` reads every such row as satisfying no `eq`, `ne`,
51
+ * comparison, `anyOf` or `noneOf`.
52
+ * - **`NaN`** (and an invalid `Date`). PostgreSQL's `float8` / `numeric` hold
53
+ * `NaN` equal to itself and above every number, an order JavaScript's
54
+ * `NaN` does not have. The constructors fold a `NaN` comparand, or a set
55
+ * holding one, to `never`; `evaluate` reads a `NaN` comparand or column as
56
+ * satisfying no `eq`, `ne`, comparison, `anyOf` or `noneOf`; and a renderer
57
+ * must never bind `NaN`, rendering a hand-built node carrying one as `never`.
58
+ * - **Sub-millisecond instants.** A PostgreSQL timestamp keeps microseconds,
59
+ * a JavaScript `Date` milliseconds, so two instants within one millisecond
60
+ * can compare unequal in SQL and equal in `evaluate`.
61
+ *
62
+ * @copyright Thomas Foster
63
+ * @module pulpit/filter
64
+ * @since 0.1.0
65
+ */
66
+ import * as Array from "effect/Array";
67
+ import * as Match from "effect/Match";
68
+ import * as Order from "effect/Order";
69
+ import * as Predicate from "effect/Predicate";
70
+ import { byCodePoint } from "./internal/list-order.js";
71
+ /**
72
+ * The most values an `anyOf` / `noneOf` node carries (`SEC-INPUT-003`): a
73
+ * literal set past it is `never`, so no request drives an unbounded
74
+ * `= ANY($values)` parameter. An application's own bound sits below it:
75
+ * `@thomasfosterau/pulpit-wordpress` caps each list parameter at 100, a cap
76
+ * WordPress core itself doesn't set (pulpit#86).
77
+ *
78
+ * @since 0.1.0
79
+ */
80
+ export const MAX_SET_VALUES = 1000;
81
+ /**
82
+ * No predicate: every row.
83
+ *
84
+ * @since 0.1.0
85
+ */
86
+ export const always = { kind: "always" };
87
+ /**
88
+ * Fail closed: no row.
89
+ *
90
+ * @since 0.1.0
91
+ */
92
+ export const never = { kind: "never" };
93
+ /**
94
+ * A `NaN`, or an invalid `Date`: a value with no place in the order SQL and
95
+ * {@link evaluate} share (see the module's "Outside the contract").
96
+ */
97
+ const isUnordered = (value) => (Predicate.isNumber(value) && Number.isNaN(value)) ||
98
+ (Predicate.isDate(value) && Number.isNaN(value.getTime()));
99
+ /**
100
+ * `column = value`. A `NaN` value is {@link never}: PostgreSQL's `NaN = NaN`
101
+ * is true where JavaScript's is not, so it fails closed.
102
+ *
103
+ * @since 0.1.0
104
+ */
105
+ export const eq = (column, value) => isUnordered(value) ? never : { kind: "eq", column, value };
106
+ /**
107
+ * `column <> value`. A `NULL` or absent column satisfies it no more than it
108
+ * satisfies {@link eq}: SQL's `NULL <> $v` is `NULL`, not true. A `NaN`
109
+ * value is {@link never}, failing closed.
110
+ *
111
+ * @since 0.1.0
112
+ */
113
+ export const ne = (column, value) => isUnordered(value) ? never : { kind: "ne", column, value };
114
+ /**
115
+ * `column IN (following)`. A `NULL` or absent column satisfies none, whatever
116
+ * `following` holds: SQL's `NULL IN (…)` is `NULL`, not true.
117
+ *
118
+ * @since 0.1.0
119
+ */
120
+ export const isIn = (column, set) => ({ kind: "in", column, set });
121
+ /**
122
+ * `(column IS NULL OR column NOT IN (following))` (pulpit#191): the exact
123
+ * complement of {@link isIn} over the same seam set, so `isIn(c, s)` and
124
+ * `isNotIn(c, s)` partition every row. A `NULL` or absent column satisfies
125
+ * it, whatever `following` holds, and is never asked about; the seam's set
126
+ * must never hold a `NULL` (SQL's `NOT IN` over one is `NULL` for every row).
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * import { strictEqual } from "node:assert";
131
+ * import { evaluate, isNotIn } from "@thomasfosterau/pulpit/filter";
132
+ *
133
+ * const excluded = new Set(["a"]);
134
+ * const context = { now: new Date(0), contains: (set: Set<string>, value: unknown) => set.has(String(value)) };
135
+ * strictEqual(evaluate(isNotIn("id", excluded), { id: "a" }, context), false);
136
+ * strictEqual(evaluate(isNotIn("id", excluded), { id: "b" }, context), true);
137
+ * strictEqual(evaluate(isNotIn("id", excluded), { id: null }, context), true);
138
+ * ```
139
+ *
140
+ * @since 0.1.0
141
+ */
142
+ export const isNotIn = (column, set) => ({ kind: "notIn", column, set });
143
+ /**
144
+ * `column > value`. A `NULL` or absent column satisfies it no more than SQL's
145
+ * `NULL > $v` (which is `NULL`); `evaluate` reads a column holding another
146
+ * type than `value` as satisfying none, too. A `NaN` or invalid-`Date` value
147
+ * is {@link never}. See {@link Comparable} for the orders.
148
+ *
149
+ * @since 0.1.0
150
+ */
151
+ export const gt = (column, value) => isUnordered(value) ? never : { kind: "gt", column, value };
152
+ /**
153
+ * `column >= value`; equality satisfies it, `Infinity` against `Infinity`
154
+ * included. A `NULL` or absent column satisfies none (SQL's `NULL >= $v` is
155
+ * `NULL`); `evaluate` reads a column holding another type than `value` as
156
+ * satisfying none, too. A `NaN` or invalid-`Date` value is {@link never}.
157
+ *
158
+ * @since 0.1.0
159
+ */
160
+ export const gte = (column, value) => isUnordered(value) ? never : { kind: "gte", column, value };
161
+ /**
162
+ * `column < value`. A `NULL` or absent column satisfies none (SQL's
163
+ * `NULL < $v` is `NULL`); `evaluate` reads a column holding another type than
164
+ * `value` as satisfying none, too. A `NaN` or invalid-`Date` value is
165
+ * {@link never}.
166
+ *
167
+ * @since 0.1.0
168
+ */
169
+ export const lt = (column, value) => isUnordered(value) ? never : { kind: "lt", column, value };
170
+ /**
171
+ * `column <= value`; equality satisfies it, `-Infinity` against `-Infinity`
172
+ * included. A `NULL` or absent column satisfies none (SQL's `NULL <= $v` is
173
+ * `NULL`); `evaluate` reads a column holding another type than `value` as
174
+ * satisfying none, too. A `NaN` or invalid-`Date` value is {@link never}.
175
+ *
176
+ * @since 0.1.0
177
+ */
178
+ export const lte = (column, value) => isUnordered(value) ? never : { kind: "lte", column, value };
179
+ /**
180
+ * `column = ANY(values)`: the column equals one of a literal set, each tested
181
+ * as {@link eq} tests its value. A `NULL` or absent column is in no set. No
182
+ * values is {@link never}, and so are more than {@link MAX_SET_VALUES}
183
+ * (duplicates counted, `SEC-INPUT-003`) and a set holding a `NaN`, so
184
+ * {@link and} / {@link or} fold each. This is a literal set; a follower
185
+ * subquery is {@link isIn}'s.
186
+ *
187
+ * @since 0.1.0
188
+ */
189
+ export const anyOf = (column, values) => Array.isReadonlyArrayEmpty(values) || values.length > MAX_SET_VALUES || values.some(isUnordered)
190
+ ? never
191
+ : { kind: "anyOf", column, values: [...values] };
192
+ /**
193
+ * `column <> ALL(values)`: the column equals none of a literal set, each
194
+ * tested as {@link ne} tests its value. A `NULL` or absent column satisfies it
195
+ * no more than it satisfies `ne` (SQL's `NULL <> ALL(…)` is `NULL`). No values
196
+ * is {@link always}; more than {@link MAX_SET_VALUES} (duplicates counted) is
197
+ * {@link never}, failing closed rather than excluding only some
198
+ * (`SEC-INPUT-003`), and so is a set holding a `NaN`.
199
+ *
200
+ * @since 0.1.0
201
+ */
202
+ export const noneOf = (column, values) => Array.isReadonlyArrayEmpty(values)
203
+ ? always
204
+ : values.length > MAX_SET_VALUES || values.some(isUnordered)
205
+ ? never
206
+ : { kind: "noneOf", column, values: [...values] };
207
+ /**
208
+ * `column IS NULL`: the column holds no value (`evaluate` reads an absent
209
+ * column so, too). The one node a `NULL` column satisfies on its own, so
210
+ * `or(isNull(column), noneOf(column, values))` is the exclusion that keeps an
211
+ * unset column, which a bare {@link noneOf} drops (pulpit#170).
212
+ *
213
+ * @since 0.1.0
214
+ */
215
+ export const isNull = (column) => ({ kind: "isNull", column });
216
+ /**
217
+ * Stamped, and the stamp has arrived.
218
+ *
219
+ * @since 0.1.0
220
+ */
221
+ export const published = (column) => ({ kind: "published", column });
222
+ /**
223
+ * Not out: unstamped, or stamped in the future — the exact complement of {@link published}.
224
+ *
225
+ * @since 0.1.0
226
+ */
227
+ export const notPublished = (column) => ({ kind: "notPublished", column });
228
+ /**
229
+ * The column a localised leaf's current-version view keys its locale level
230
+ * by (pulpit#56): one view row per `(id, locale)` the head carries, the
231
+ * shared columns joined in, and a node carrying no locale as one row whose
232
+ * `locale` is `NULL`. No leaf column may take the name.
233
+ *
234
+ * @since 0.1.0
235
+ */
236
+ export const LOCALE_COLUMN = "locale";
237
+ /**
238
+ * The locale arm (pulpit#56): the view rows in one of `locales`, read from
239
+ * the view's {@link LOCALE_COLUMN} as {@link anyOf} reads its column. A row
240
+ * carrying no locale (a `NULL` locale), and every row of a view with no
241
+ * locale level, is in none. No locales is {@link never}, and so are more than
242
+ * {@link MAX_SET_VALUES} (`SEC-INPUT-003`).
243
+ *
244
+ * @example
245
+ * ```ts
246
+ * import { strictEqual } from "node:assert";
247
+ * import { evaluate, locale } from "@thomasfosterau/pulpit/filter";
248
+ *
249
+ * const context = { now: new Date(0), contains: () => false };
250
+ * strictEqual(evaluate(locale(["fr", "en"]), { id: "a", locale: "fr" }, context), true);
251
+ * strictEqual(evaluate(locale(["fr", "en"]), { id: "a", locale: "de" }, context), false);
252
+ * strictEqual(evaluate(locale(["fr"]), { id: "a" }, context), false);
253
+ * ```
254
+ *
255
+ * @since 0.1.0
256
+ */
257
+ export const locale = (locales) => Array.isReadonlyArrayEmpty(locales) || locales.length > MAX_SET_VALUES
258
+ ? never
259
+ : { kind: "locale", column: LOCALE_COLUMN, locales: [...locales] };
260
+ /** No parts → the identity; one part → that part, bare; more → the combined node. */
261
+ const collapse = (parts, identity, combine) => Array.match(parts, {
262
+ onEmpty: () => identity,
263
+ onNonEmpty: (nonEmpty) => Array.isReadonlyArrayNonEmpty(Array.tailNonEmpty(nonEmpty))
264
+ ? combine(nonEmpty)
265
+ : Array.headNonEmpty(nonEmpty),
266
+ });
267
+ /**
268
+ * Conjunction. `always` parts drop out, a `never` part makes the whole
269
+ * `never`, and a single remaining part is returned bare — so composing
270
+ * optional filters reads as one call, the shape the apps' `combine` had.
271
+ *
272
+ * @since 0.1.0
273
+ */
274
+ export const and = (...filters) => {
275
+ if (filters.some((filter) => filter.kind === "never"))
276
+ return never;
277
+ return collapse(Array.filter(filters, (filter) => filter.kind !== "always"), always, (parts) => ({ kind: "and", filters: parts }));
278
+ };
279
+ /**
280
+ * Disjunction. `never` parts drop out, an `always` part makes the whole
281
+ * `always`, and a single remaining part is returned bare.
282
+ *
283
+ * @since 0.1.0
284
+ */
285
+ export const or = (...filters) => {
286
+ if (filters.some((filter) => filter.kind === "always"))
287
+ return always;
288
+ return collapse(Array.filter(filters, (filter) => filter.kind !== "never"), never, (parts) => ({ kind: "or", filters: parts }));
289
+ };
290
+ /**
291
+ * Numbers by `<` / `>`, never by subtraction: `Infinity - Infinity` is `NaN`,
292
+ * which would read `Infinity >= Infinity` as false. Either side `NaN` (or an
293
+ * invalid `Date`'s instant) is `NaN`, which every relational test reads as false.
294
+ */
295
+ const byNumber = (column, value) => Number.isNaN(column) || Number.isNaN(value) ? Number.NaN : Order.Number(column, value);
296
+ /**
297
+ * Compare a column with a {@link Comparable}: negative, zero or positive, or
298
+ * `NaN` when the column is `NULL`, absent, of another type or unordered
299
+ * (`NaN`, an invalid `Date`), which every relational test then reads as
300
+ * false, as SQL's `NULL` is.
301
+ */
302
+ const compareTo = (column, value) => {
303
+ if (Predicate.isDate(value)) {
304
+ return Predicate.isDate(column) ? byNumber(column.getTime(), value.getTime()) : Number.NaN;
305
+ }
306
+ if (Predicate.isString(value)) {
307
+ return Predicate.isString(column) ? byCodePoint(column, value) : Number.NaN;
308
+ }
309
+ return Predicate.isNumber(column) ? byNumber(column, value) : Number.NaN;
310
+ };
311
+ /**
312
+ * `column <> value` as SQL reads it where the two readings agree: a `NULL`
313
+ * column differs from nothing (`NULL <> $v` is `NULL`), and outside the
314
+ * contract — a column of another type than `value`, or a `NaN` on either
315
+ * side — it fails closed rather than answer true.
316
+ */
317
+ const differs = (column, value) => sameKind(column, value) && !isUnordered(column) && !isUnordered(value) && column !== value;
318
+ /** Whether `column` holds the same kind of {@link Scalar} as `value`. */
319
+ const sameKind = (column, value) => Predicate.isString(value)
320
+ ? Predicate.isString(column)
321
+ : Predicate.isNumber(value)
322
+ ? Predicate.isNumber(column)
323
+ : Predicate.isBoolean(column);
324
+ /** Read a timestamp column the way the publication axis does: a `Date`, or nothing. */
325
+ const instantOf = (value) => value instanceof Date ? value.getTime() : Number.NaN;
326
+ /**
327
+ * Run a filter against one row — the in-memory reading of the rendering
328
+ * contract above. A column that is `null` or that the row lacks matches no
329
+ * `eq`, satisfies no `ne`, `in`, comparison, `anyOf` or non-empty `noneOf`,
330
+ * satisfies every `notIn`, and is unpublished: SQL reads `NULL = $v`, `NULL <> $v`, `NULL IN (…)`,
331
+ * `NULL > $v` and `NULL <> ALL(…)` as `NULL`, which a `WHERE` drops, so `ne`
332
+ * is not the complement of `eq`, nor `noneOf` of `anyOf`, over a nullable
333
+ * column; {@link isNull} is the one node such a row satisfies. Such a row fails an `in` without `context.contains` being asked, so
334
+ * the answer never depends on the seam (pulpit#94). A set past
335
+ * {@link MAX_SET_VALUES} is `never`. Outside the contract it fails closed: a
336
+ * column of another type than the comparand (or than any of a set's values),
337
+ * and a `NaN` (or invalid `Date`) comparand, set element or column, satisfy
338
+ * no `eq`, `ne`, comparison, `anyOf` or non-empty `noneOf`.
339
+ *
340
+ * @since 0.1.0
341
+ */
342
+ export const evaluate = (filter, row, context) => {
343
+ const arrived = (column) => instantOf(row[column] ?? null) <= context.now.getTime();
344
+ return Match.value(filter).pipe(Match.discriminatorsExhaustive("kind")({
345
+ always: () => true,
346
+ never: () => false,
347
+ // `NaN === NaN` is false, so a `NaN` on either side already matches nothing.
348
+ eq: (node) => row[node.column] === node.value,
349
+ ne: (node) => differs(row[node.column] ?? null, node.value),
350
+ in: (node) => {
351
+ const value = row[node.column] ?? null;
352
+ return value !== null && context.contains(node.set, value);
353
+ },
354
+ notIn: (node) => {
355
+ const value = row[node.column] ?? null;
356
+ return value === null || !context.contains(node.set, value);
357
+ },
358
+ gt: (node) => compareTo(row[node.column] ?? null, node.value) > 0,
359
+ gte: (node) => compareTo(row[node.column] ?? null, node.value) >= 0,
360
+ lt: (node) => compareTo(row[node.column] ?? null, node.value) < 0,
361
+ lte: (node) => compareTo(row[node.column] ?? null, node.value) <= 0,
362
+ anyOf: (node) => node.values.length <= MAX_SET_VALUES &&
363
+ !node.values.some(isUnordered) &&
364
+ node.values.some((value) => row[node.column] === value),
365
+ noneOf: (node) => {
366
+ if (node.values.length > MAX_SET_VALUES)
367
+ return false;
368
+ // `<> ALL` over no values is true, even for NULL; the constructor folds that to `always`.
369
+ if (Array.isReadonlyArrayEmpty(node.values))
370
+ return true;
371
+ const value = row[node.column] ?? null;
372
+ return node.values.every((excluded) => differs(value, excluded));
373
+ },
374
+ isNull: (node) => (row[node.column] ?? null) === null,
375
+ published: (node) => arrived(node.column),
376
+ notPublished: (node) => !arrived(node.column),
377
+ locale: (node) => {
378
+ const value = row[node.column] ?? null;
379
+ return (node.locales.length <= MAX_SET_VALUES &&
380
+ Predicate.isString(value) &&
381
+ node.locales.includes(value));
382
+ },
383
+ and: (node) => node.filters.every((part) => evaluate(part, row, context)),
384
+ or: (node) => node.filters.some((part) => evaluate(part, row, context)),
385
+ }));
386
+ };
387
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * `@thomasfosterau/pulpit` — the versioned-content kernel.
3
+ *
4
+ * Every module is exported as a namespace from the package root, following
5
+ * the convention of `effect` and `@thomasfosterau/effect-jsonapi`; each is
6
+ * also a subpath (`@thomasfosterau/pulpit/content`, …) for a consumer that
7
+ * wants one module without the barrel. The in-memory fakes are the one
8
+ * exception: they are the subpath `@thomasfosterau/pulpit/testing` only, so
9
+ * that production code never pulls them in through the barrel.
10
+ *
11
+ * @copyright Thomas Foster
12
+ * @module pulpit
13
+ */
14
+ /**
15
+ * The Content model fields: `Visibility`, the visibility / draft / timestamp /
16
+ * tombstone spreads, `ownerRef`, the base `content` resource.
17
+ */
18
+ export * as Content from "./content.ts";
19
+ /**
20
+ * The registry flag vocabulary, `validateRegistry`, and the derived families /
21
+ * branches.
22
+ */
23
+ export * as Registry from "./registry.ts";
24
+ /**
25
+ * The append-only node / version chain: create, update, restore, delete,
26
+ * getVersion, compare (with the pure `diffStates`), restoreVersion, history —
27
+ * over a store seam.
28
+ */
29
+ export * as VersionChain from "./version-chain.ts";
30
+ /** The list-filter vocabulary the read predicates render into, and its in-memory evaluator. */
31
+ export * as Filter from "./filter.ts";
32
+ /**
33
+ * The subtype operation factory: `LeafAccess`, the read scope and viewer
34
+ * predicates, the write gates, `defineSubtype` and its handlers seam.
35
+ */
36
+ export * as Subtype from "./subtype.ts";
37
+ /**
38
+ * The publication axis, the moderation state, and the cache serveability
39
+ * policy (`isPubliclyServeable`, the `serveable` hook).
40
+ */
41
+ export * as Publication from "./publication.ts";
42
+ /**
43
+ * The content-addressed document store seam (`DocumentStore`), the
44
+ * `DocumentHash` it is keyed by, and the `documentRef` field spread a version
45
+ * row carries the reference in.
46
+ */
47
+ export * as Documents from "./documents.ts";
48
+ /**
49
+ * The edge operations factory: a relation between nodes as its own family
50
+ * (`defineEdgeOps` over an `EdgeStore` seam), readable only when every end
51
+ * is, with declared cardinality limits.
52
+ */
53
+ export * as Edges from "./edges.ts";
54
+ /**
55
+ * Suggested edits: a contributor's patch against a node's version, accepted
56
+ * through the target's own update or rejected (`defineProposals` over a
57
+ * `ProposalStore` seam), with its two-tier stale / conflict classification.
58
+ */
59
+ export * as Proposals from "./proposals.ts";
60
+ /**
61
+ * File and media leaves: the blob-store seam (`BlobStore`) keyed by the
62
+ * content hash, the file field spread, the commit-ordered byte write
63
+ * (`defineFileWrites`) and the usage index's edge ends.
64
+ */
65
+ export * as Blobs from "./blobs.ts";
66
+ /**
67
+ * Routable content: a leaf's path claims tied to its version chain
68
+ * (`routable` over a `PathStore` seam), the aliases a path change leaves
69
+ * behind, and the gated resolution of a path.
70
+ */
71
+ export * as Paths from "./paths.ts";
72
+ /**
73
+ * The moderation workflow: the transition rules as a before hook
74
+ * (`moderationHook`), the decision (`defineModeration`), the review-queue
75
+ * filter, threshold grading (`gradeScores`) and member reports
76
+ * (`defineReports` over a `ReportStore` seam).
77
+ */
78
+ export * as Moderation from "./moderation.ts";
79
+ /**
80
+ * The working copy: an editor's autosave buffer outside the version chain
81
+ * (`WorkingCopyStore`), committed as one ordinary version
82
+ * (`defineWorkingCopy`).
83
+ */
84
+ export * as WorkingCopy from "./working-copy.ts";
85
+ /**
86
+ * The comments family: threaded comments on any node as versioned owned
87
+ * leaves (`defineComments`), behind the target's read gate and the
88
+ * moderation gate.
89
+ */
90
+ export * as Comments from "./comments.ts";
91
+ /**
92
+ * Purge: erasure, the one destructive path through a node's history. It
93
+ * hard-deletes a node's chain and the rows kept for it, then the documents
94
+ * and bytes nothing else references (`definePurge` over a `PurgeStore`).
95
+ */
96
+ export * as Purge from "./purge.ts";
97
+ /**
98
+ * Hybrid search: reciprocal rank fusion over ranked branches, the reranker
99
+ * and branch seams every branch's scope runs through, and the embedding
100
+ * pipeline as seams (`fuseRankings`, `hybridSearch`, `embedPending`).
101
+ */
102
+ export * as Search from "./search.ts";
103
+ /**
104
+ * Write budgets: a declared ceiling on an account's writes in a rolling
105
+ * window, spent inside the write as a before hook or by a plain-row family,
106
+ * over a `BudgetCounter` seam (`bindBudget`, `budgetHook`).
107
+ */
108
+ export * as Budgets from "./budgets.ts";
109
+ /**
110
+ * Reactions: one reaction per account per node, a kind from the family's
111
+ * vocabulary, behind the target's read gate, with a grouped tally
112
+ * (`defineReactions` over a `ReactionStore`).
113
+ */
114
+ export * as Reactions from "./reactions.ts";
115
+ /**
116
+ * The reference resource cache: `./subtype`'s `ResourceCacheSeam`, with a
117
+ * read-through `get`, over a minimal versioned key-value seam
118
+ * (`makeResourceCache` over a `VersionedKv`).
119
+ */
120
+ export * as Cache from "./cache.ts";
121
+ /**
122
+ * Ordered collections: positioned members of a parent node, the order kept
123
+ * beside the chain or versioned with the parent (`defineCollection` over a
124
+ * `CollectionStore`).
125
+ */
126
+ export * as Collections from "./collections.ts";
127
+ /**
128
+ * The social graph: follow, mute and block between accounts, the follower
129
+ * seam filled from it, and the opt-in read filter over silenced authors
130
+ * (`defineSocial` over a `SocialStore`).
131
+ */
132
+ export * as Social from "./social.ts";
133
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;GAGG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC;;;GAGG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C;;;;GAIG;AACH,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AAEnD,+FAA+F;AAC/F,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC;;;GAGG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC;;;GAGG;AACH,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD;;;;GAIG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;;GAKG;AACH,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAE9C;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AAEjD;;;;GAIG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC;;;;GAIG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC;;;;GAIG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC"}