@thomasfosterau/pulpit 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +1272 -2
- package/dist/blobs.d.ts +249 -0
- package/dist/blobs.d.ts.map +1 -0
- package/dist/blobs.js +193 -0
- package/dist/blobs.js.map +1 -0
- package/dist/budgets.d.ts +255 -0
- package/dist/budgets.d.ts.map +1 -0
- package/dist/budgets.js +211 -0
- package/dist/budgets.js.map +1 -0
- package/dist/cache.d.ts +154 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +118 -0
- package/dist/cache.js.map +1 -0
- package/dist/collections.d.ts +242 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +215 -0
- package/dist/collections.js.map +1 -0
- package/dist/comments.d.ts +212 -0
- package/dist/comments.d.ts.map +1 -0
- package/dist/comments.js +192 -0
- package/dist/comments.js.map +1 -0
- package/dist/content.d.ts +231 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +204 -0
- package/dist/content.js.map +1 -0
- package/dist/documents.d.ts +184 -0
- package/dist/documents.d.ts.map +1 -0
- package/dist/documents.js +190 -0
- package/dist/documents.js.map +1 -0
- package/dist/edges.d.ts +645 -0
- package/dist/edges.d.ts.map +1 -0
- package/dist/edges.js +558 -0
- package/dist/edges.js.map +1 -0
- package/dist/filter.d.ts +461 -0
- package/dist/filter.d.ts.map +1 -0
- package/dist/filter.js +387 -0
- package/dist/filter.js.map +1 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/filter-columns.d.ts +8 -0
- package/dist/internal/filter-columns.d.ts.map +1 -0
- package/dist/internal/filter-columns.js +43 -0
- package/dist/internal/filter-columns.js.map +1 -0
- package/dist/internal/list-order.d.ts +26 -0
- package/dist/internal/list-order.d.ts.map +1 -0
- package/dist/internal/list-order.js +92 -0
- package/dist/internal/list-order.js.map +1 -0
- package/dist/internal/owned-columns.d.ts +93 -0
- package/dist/internal/owned-columns.d.ts.map +1 -0
- package/dist/internal/owned-columns.js +98 -0
- package/dist/internal/owned-columns.js.map +1 -0
- package/dist/internal/plain-rows.d.ts +32 -0
- package/dist/internal/plain-rows.d.ts.map +1 -0
- package/dist/internal/plain-rows.js +32 -0
- package/dist/internal/plain-rows.js.map +1 -0
- package/dist/internal/reference-columns.d.ts +80 -0
- package/dist/internal/reference-columns.d.ts.map +1 -0
- package/dist/internal/reference-columns.js +102 -0
- package/dist/internal/reference-columns.js.map +1 -0
- package/dist/moderation.d.ts +392 -0
- package/dist/moderation.d.ts.map +1 -0
- package/dist/moderation.js +375 -0
- package/dist/moderation.js.map +1 -0
- package/dist/paths.d.ts +204 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +165 -0
- package/dist/paths.js.map +1 -0
- package/dist/proposals.d.ts +523 -0
- package/dist/proposals.d.ts.map +1 -0
- package/dist/proposals.js +505 -0
- package/dist/proposals.js.map +1 -0
- package/dist/publication.d.ts +148 -0
- package/dist/publication.d.ts.map +1 -0
- package/dist/publication.js +183 -0
- package/dist/publication.js.map +1 -0
- package/dist/purge.d.ts +224 -0
- package/dist/purge.d.ts.map +1 -0
- package/dist/purge.js +151 -0
- package/dist/purge.js.map +1 -0
- package/dist/reactions.d.ts +246 -0
- package/dist/reactions.d.ts.map +1 -0
- package/dist/reactions.js +183 -0
- package/dist/reactions.js.map +1 -0
- package/dist/registry.d.ts +316 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +305 -0
- package/dist/registry.js.map +1 -0
- package/dist/search.d.ts +366 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +273 -0
- package/dist/search.js.map +1 -0
- package/dist/social.d.ts +311 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +205 -0
- package/dist/social.js.map +1 -0
- package/dist/subtype.d.ts +1613 -0
- package/dist/subtype.d.ts.map +1 -0
- package/dist/subtype.js +1300 -0
- package/dist/subtype.js.map +1 -0
- package/dist/testing.d.ts +675 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +1022 -0
- package/dist/testing.js.map +1 -0
- package/dist/version-chain.d.ts +702 -0
- package/dist/version-chain.d.ts.map +1 -0
- package/dist/version-chain.js +489 -0
- package/dist/version-chain.js.map +1 -0
- package/dist/working-copy.d.ts +116 -0
- package/dist/working-copy.d.ts.map +1 -0
- package/dist/working-copy.js +95 -0
- package/dist/working-copy.js.map +1 -0
- package/package.json +145 -3
- package/src/blobs.ts +384 -0
- package/src/budgets.ts +338 -0
- package/src/cache.ts +218 -0
- package/src/collections.ts +427 -0
- package/src/comments.ts +392 -0
- package/src/content.ts +238 -0
- package/src/documents.ts +284 -0
- package/src/edges.ts +1185 -0
- package/src/filter.ts +523 -0
- package/src/index.ts +153 -0
- package/src/internal/filter-columns.ts +50 -0
- package/src/internal/list-order.ts +117 -0
- package/src/internal/owned-columns.ts +140 -0
- package/src/internal/plain-rows.ts +54 -0
- package/src/internal/reference-columns.ts +156 -0
- package/src/moderation.ts +728 -0
- package/src/paths.ts +267 -0
- package/src/proposals.ts +1014 -0
- package/src/publication.ts +225 -0
- package/src/purge.ts +313 -0
- package/src/reactions.ts +347 -0
- package/src/registry.ts +524 -0
- package/src/search.ts +540 -0
- package/src/social.ts +469 -0
- package/src/subtype.ts +3095 -0
- package/src/testing.ts +1873 -0
- package/src/version-chain.ts +1093 -0
- package/src/working-copy.ts +192 -0
package/dist/filter.d.ts
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
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 type { ColumnValue } from "./version-chain.ts";
|
|
67
|
+
/**
|
|
68
|
+
* A value an `eq` / `ne` node compares against. No `null`: `col = NULL` is
|
|
69
|
+
* never true in SQL, so a null comparison would read differently in the
|
|
70
|
+
* renderer and the evaluator.
|
|
71
|
+
*
|
|
72
|
+
* @since 0.1.0
|
|
73
|
+
*/
|
|
74
|
+
export type Scalar = string | number | boolean;
|
|
75
|
+
/**
|
|
76
|
+
* A value a `gt` / `gte` / `lt` / `lte` node compares against. A `string`
|
|
77
|
+
* orders by code point (SQL's `"C"` collation), a `number` numerically and a
|
|
78
|
+
* `Date` by its instant. Kept apart from {@link Scalar}, which `eq` / `ne`
|
|
79
|
+
* test by identity and so cannot hold a `Date`; a `boolean` has no order a
|
|
80
|
+
* filter needs.
|
|
81
|
+
*
|
|
82
|
+
* @since 0.1.0
|
|
83
|
+
*/
|
|
84
|
+
export type Comparable = string | number | Date;
|
|
85
|
+
/**
|
|
86
|
+
* The most values an `anyOf` / `noneOf` node carries (`SEC-INPUT-003`): a
|
|
87
|
+
* literal set past it is `never`, so no request drives an unbounded
|
|
88
|
+
* `= ANY($values)` parameter. An application's own bound sits below it:
|
|
89
|
+
* `@thomasfosterau/pulpit-wordpress` caps each list parameter at 100, a cap
|
|
90
|
+
* WordPress core itself doesn't set (pulpit#86).
|
|
91
|
+
*
|
|
92
|
+
* @since 0.1.0
|
|
93
|
+
*/
|
|
94
|
+
export declare const MAX_SET_VALUES = 1000;
|
|
95
|
+
/**
|
|
96
|
+
* A row as {@link evaluate} reads it: the view's columns by name.
|
|
97
|
+
*
|
|
98
|
+
* @since 0.1.0
|
|
99
|
+
*/
|
|
100
|
+
export type FilterRow = {
|
|
101
|
+
readonly [column: string]: ColumnValue;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* A read predicate over a current-version view's columns.
|
|
105
|
+
*
|
|
106
|
+
* @since 0.1.0
|
|
107
|
+
*/
|
|
108
|
+
export type ListFilter<Following> = {
|
|
109
|
+
readonly kind: "always";
|
|
110
|
+
} | {
|
|
111
|
+
readonly kind: "never";
|
|
112
|
+
} | {
|
|
113
|
+
readonly kind: "eq";
|
|
114
|
+
readonly column: string;
|
|
115
|
+
readonly value: Scalar;
|
|
116
|
+
} | {
|
|
117
|
+
readonly kind: "ne";
|
|
118
|
+
readonly column: string;
|
|
119
|
+
readonly value: Scalar;
|
|
120
|
+
} | {
|
|
121
|
+
readonly kind: "in";
|
|
122
|
+
readonly column: string;
|
|
123
|
+
readonly set: Following;
|
|
124
|
+
} | {
|
|
125
|
+
readonly kind: "notIn";
|
|
126
|
+
readonly column: string;
|
|
127
|
+
readonly set: Following;
|
|
128
|
+
} | {
|
|
129
|
+
readonly kind: "gt";
|
|
130
|
+
readonly column: string;
|
|
131
|
+
readonly value: Comparable;
|
|
132
|
+
} | {
|
|
133
|
+
readonly kind: "gte";
|
|
134
|
+
readonly column: string;
|
|
135
|
+
readonly value: Comparable;
|
|
136
|
+
} | {
|
|
137
|
+
readonly kind: "lt";
|
|
138
|
+
readonly column: string;
|
|
139
|
+
readonly value: Comparable;
|
|
140
|
+
} | {
|
|
141
|
+
readonly kind: "lte";
|
|
142
|
+
readonly column: string;
|
|
143
|
+
readonly value: Comparable;
|
|
144
|
+
} | {
|
|
145
|
+
readonly kind: "anyOf";
|
|
146
|
+
readonly column: string;
|
|
147
|
+
readonly values: ReadonlyArray<Scalar>;
|
|
148
|
+
} | {
|
|
149
|
+
readonly kind: "noneOf";
|
|
150
|
+
readonly column: string;
|
|
151
|
+
readonly values: ReadonlyArray<Scalar>;
|
|
152
|
+
} | {
|
|
153
|
+
readonly kind: "isNull";
|
|
154
|
+
readonly column: string;
|
|
155
|
+
} | {
|
|
156
|
+
readonly kind: "published";
|
|
157
|
+
readonly column: string;
|
|
158
|
+
} | {
|
|
159
|
+
readonly kind: "notPublished";
|
|
160
|
+
readonly column: string;
|
|
161
|
+
} | {
|
|
162
|
+
readonly kind: "locale";
|
|
163
|
+
readonly column: string;
|
|
164
|
+
readonly locales: ReadonlyArray<string>;
|
|
165
|
+
} | {
|
|
166
|
+
readonly kind: "and";
|
|
167
|
+
readonly filters: ReadonlyArray<ListFilter<Following>>;
|
|
168
|
+
} | {
|
|
169
|
+
readonly kind: "or";
|
|
170
|
+
readonly filters: ReadonlyArray<ListFilter<Following>>;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* No predicate: every row.
|
|
174
|
+
*
|
|
175
|
+
* @since 0.1.0
|
|
176
|
+
*/
|
|
177
|
+
export declare const always: {
|
|
178
|
+
readonly kind: "always";
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Fail closed: no row.
|
|
182
|
+
*
|
|
183
|
+
* @since 0.1.0
|
|
184
|
+
*/
|
|
185
|
+
export declare const never: {
|
|
186
|
+
readonly kind: "never";
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* `column = value`. A `NaN` value is {@link never}: PostgreSQL's `NaN = NaN`
|
|
190
|
+
* is true where JavaScript's is not, so it fails closed.
|
|
191
|
+
*
|
|
192
|
+
* @since 0.1.0
|
|
193
|
+
*/
|
|
194
|
+
export declare const eq: (column: string, value: Scalar) => {
|
|
195
|
+
readonly kind: "never";
|
|
196
|
+
} | {
|
|
197
|
+
readonly kind: "eq";
|
|
198
|
+
readonly column: string;
|
|
199
|
+
readonly value: Scalar;
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* `column <> value`. A `NULL` or absent column satisfies it no more than it
|
|
203
|
+
* satisfies {@link eq}: SQL's `NULL <> $v` is `NULL`, not true. A `NaN`
|
|
204
|
+
* value is {@link never}, failing closed.
|
|
205
|
+
*
|
|
206
|
+
* @since 0.1.0
|
|
207
|
+
*/
|
|
208
|
+
export declare const ne: (column: string, value: Scalar) => {
|
|
209
|
+
readonly kind: "never";
|
|
210
|
+
} | {
|
|
211
|
+
readonly kind: "ne";
|
|
212
|
+
readonly column: string;
|
|
213
|
+
readonly value: Scalar;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* `column IN (following)`. A `NULL` or absent column satisfies none, whatever
|
|
217
|
+
* `following` holds: SQL's `NULL IN (…)` is `NULL`, not true.
|
|
218
|
+
*
|
|
219
|
+
* @since 0.1.0
|
|
220
|
+
*/
|
|
221
|
+
export declare const isIn: <Following>(column: string, set: Following) => {
|
|
222
|
+
readonly kind: "in";
|
|
223
|
+
readonly column: string;
|
|
224
|
+
readonly set: Following;
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* `(column IS NULL OR column NOT IN (following))` (pulpit#191): the exact
|
|
228
|
+
* complement of {@link isIn} over the same seam set, so `isIn(c, s)` and
|
|
229
|
+
* `isNotIn(c, s)` partition every row. A `NULL` or absent column satisfies
|
|
230
|
+
* it, whatever `following` holds, and is never asked about; the seam's set
|
|
231
|
+
* must never hold a `NULL` (SQL's `NOT IN` over one is `NULL` for every row).
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* import { strictEqual } from "node:assert";
|
|
236
|
+
* import { evaluate, isNotIn } from "@thomasfosterau/pulpit/filter";
|
|
237
|
+
*
|
|
238
|
+
* const excluded = new Set(["a"]);
|
|
239
|
+
* const context = { now: new Date(0), contains: (set: Set<string>, value: unknown) => set.has(String(value)) };
|
|
240
|
+
* strictEqual(evaluate(isNotIn("id", excluded), { id: "a" }, context), false);
|
|
241
|
+
* strictEqual(evaluate(isNotIn("id", excluded), { id: "b" }, context), true);
|
|
242
|
+
* strictEqual(evaluate(isNotIn("id", excluded), { id: null }, context), true);
|
|
243
|
+
* ```
|
|
244
|
+
*
|
|
245
|
+
* @since 0.1.0
|
|
246
|
+
*/
|
|
247
|
+
export declare const isNotIn: <Following>(column: string, set: Following) => {
|
|
248
|
+
readonly kind: "notIn";
|
|
249
|
+
readonly column: string;
|
|
250
|
+
readonly set: Following;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* `column > value`. A `NULL` or absent column satisfies it no more than SQL's
|
|
254
|
+
* `NULL > $v` (which is `NULL`); `evaluate` reads a column holding another
|
|
255
|
+
* type than `value` as satisfying none, too. A `NaN` or invalid-`Date` value
|
|
256
|
+
* is {@link never}. See {@link Comparable} for the orders.
|
|
257
|
+
*
|
|
258
|
+
* @since 0.1.0
|
|
259
|
+
*/
|
|
260
|
+
export declare const gt: (column: string, value: Comparable) => {
|
|
261
|
+
readonly kind: "never";
|
|
262
|
+
} | {
|
|
263
|
+
readonly kind: "gt";
|
|
264
|
+
readonly column: string;
|
|
265
|
+
readonly value: Comparable;
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* `column >= value`; equality satisfies it, `Infinity` against `Infinity`
|
|
269
|
+
* included. A `NULL` or absent column satisfies none (SQL's `NULL >= $v` is
|
|
270
|
+
* `NULL`); `evaluate` reads a column holding another type than `value` as
|
|
271
|
+
* satisfying none, too. A `NaN` or invalid-`Date` value is {@link never}.
|
|
272
|
+
*
|
|
273
|
+
* @since 0.1.0
|
|
274
|
+
*/
|
|
275
|
+
export declare const gte: (column: string, value: Comparable) => {
|
|
276
|
+
readonly kind: "never";
|
|
277
|
+
} | {
|
|
278
|
+
readonly kind: "gte";
|
|
279
|
+
readonly column: string;
|
|
280
|
+
readonly value: Comparable;
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* `column < value`. A `NULL` or absent column satisfies none (SQL's
|
|
284
|
+
* `NULL < $v` is `NULL`); `evaluate` reads a column holding another type than
|
|
285
|
+
* `value` as satisfying none, too. A `NaN` or invalid-`Date` value is
|
|
286
|
+
* {@link never}.
|
|
287
|
+
*
|
|
288
|
+
* @since 0.1.0
|
|
289
|
+
*/
|
|
290
|
+
export declare const lt: (column: string, value: Comparable) => {
|
|
291
|
+
readonly kind: "never";
|
|
292
|
+
} | {
|
|
293
|
+
readonly kind: "lt";
|
|
294
|
+
readonly column: string;
|
|
295
|
+
readonly value: Comparable;
|
|
296
|
+
};
|
|
297
|
+
/**
|
|
298
|
+
* `column <= value`; equality satisfies it, `-Infinity` against `-Infinity`
|
|
299
|
+
* included. A `NULL` or absent column satisfies none (SQL's `NULL <= $v` is
|
|
300
|
+
* `NULL`); `evaluate` reads a column holding another type than `value` as
|
|
301
|
+
* satisfying none, too. A `NaN` or invalid-`Date` value is {@link never}.
|
|
302
|
+
*
|
|
303
|
+
* @since 0.1.0
|
|
304
|
+
*/
|
|
305
|
+
export declare const lte: (column: string, value: Comparable) => {
|
|
306
|
+
readonly kind: "never";
|
|
307
|
+
} | {
|
|
308
|
+
readonly kind: "lte";
|
|
309
|
+
readonly column: string;
|
|
310
|
+
readonly value: Comparable;
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* `column = ANY(values)`: the column equals one of a literal set, each tested
|
|
314
|
+
* as {@link eq} tests its value. A `NULL` or absent column is in no set. No
|
|
315
|
+
* values is {@link never}, and so are more than {@link MAX_SET_VALUES}
|
|
316
|
+
* (duplicates counted, `SEC-INPUT-003`) and a set holding a `NaN`, so
|
|
317
|
+
* {@link and} / {@link or} fold each. This is a literal set; a follower
|
|
318
|
+
* subquery is {@link isIn}'s.
|
|
319
|
+
*
|
|
320
|
+
* @since 0.1.0
|
|
321
|
+
*/
|
|
322
|
+
export declare const anyOf: (column: string, values: ReadonlyArray<Scalar>) => {
|
|
323
|
+
readonly kind: "never";
|
|
324
|
+
} | {
|
|
325
|
+
readonly kind: "anyOf";
|
|
326
|
+
readonly column: string;
|
|
327
|
+
readonly values: readonly Scalar[];
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* `column <> ALL(values)`: the column equals none of a literal set, each
|
|
331
|
+
* tested as {@link ne} tests its value. A `NULL` or absent column satisfies it
|
|
332
|
+
* no more than it satisfies `ne` (SQL's `NULL <> ALL(…)` is `NULL`). No values
|
|
333
|
+
* is {@link always}; more than {@link MAX_SET_VALUES} (duplicates counted) is
|
|
334
|
+
* {@link never}, failing closed rather than excluding only some
|
|
335
|
+
* (`SEC-INPUT-003`), and so is a set holding a `NaN`.
|
|
336
|
+
*
|
|
337
|
+
* @since 0.1.0
|
|
338
|
+
*/
|
|
339
|
+
export declare const noneOf: (column: string, values: ReadonlyArray<Scalar>) => {
|
|
340
|
+
readonly kind: "always";
|
|
341
|
+
} | {
|
|
342
|
+
readonly kind: "never";
|
|
343
|
+
} | {
|
|
344
|
+
readonly kind: "noneOf";
|
|
345
|
+
readonly column: string;
|
|
346
|
+
readonly values: readonly Scalar[];
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* `column IS NULL`: the column holds no value (`evaluate` reads an absent
|
|
350
|
+
* column so, too). The one node a `NULL` column satisfies on its own, so
|
|
351
|
+
* `or(isNull(column), noneOf(column, values))` is the exclusion that keeps an
|
|
352
|
+
* unset column, which a bare {@link noneOf} drops (pulpit#170).
|
|
353
|
+
*
|
|
354
|
+
* @since 0.1.0
|
|
355
|
+
*/
|
|
356
|
+
export declare const isNull: (column: string) => {
|
|
357
|
+
readonly kind: "isNull";
|
|
358
|
+
readonly column: string;
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
* Stamped, and the stamp has arrived.
|
|
362
|
+
*
|
|
363
|
+
* @since 0.1.0
|
|
364
|
+
*/
|
|
365
|
+
export declare const published: (column: string) => {
|
|
366
|
+
readonly kind: "published";
|
|
367
|
+
readonly column: string;
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* Not out: unstamped, or stamped in the future — the exact complement of {@link published}.
|
|
371
|
+
*
|
|
372
|
+
* @since 0.1.0
|
|
373
|
+
*/
|
|
374
|
+
export declare const notPublished: (column: string) => {
|
|
375
|
+
readonly kind: "notPublished";
|
|
376
|
+
readonly column: string;
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* The column a localised leaf's current-version view keys its locale level
|
|
380
|
+
* by (pulpit#56): one view row per `(id, locale)` the head carries, the
|
|
381
|
+
* shared columns joined in, and a node carrying no locale as one row whose
|
|
382
|
+
* `locale` is `NULL`. No leaf column may take the name.
|
|
383
|
+
*
|
|
384
|
+
* @since 0.1.0
|
|
385
|
+
*/
|
|
386
|
+
export declare const LOCALE_COLUMN = "locale";
|
|
387
|
+
/**
|
|
388
|
+
* The locale arm (pulpit#56): the view rows in one of `locales`, read from
|
|
389
|
+
* the view's {@link LOCALE_COLUMN} as {@link anyOf} reads its column. A row
|
|
390
|
+
* carrying no locale (a `NULL` locale), and every row of a view with no
|
|
391
|
+
* locale level, is in none. No locales is {@link never}, and so are more than
|
|
392
|
+
* {@link MAX_SET_VALUES} (`SEC-INPUT-003`).
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```ts
|
|
396
|
+
* import { strictEqual } from "node:assert";
|
|
397
|
+
* import { evaluate, locale } from "@thomasfosterau/pulpit/filter";
|
|
398
|
+
*
|
|
399
|
+
* const context = { now: new Date(0), contains: () => false };
|
|
400
|
+
* strictEqual(evaluate(locale(["fr", "en"]), { id: "a", locale: "fr" }, context), true);
|
|
401
|
+
* strictEqual(evaluate(locale(["fr", "en"]), { id: "a", locale: "de" }, context), false);
|
|
402
|
+
* strictEqual(evaluate(locale(["fr"]), { id: "a" }, context), false);
|
|
403
|
+
* ```
|
|
404
|
+
*
|
|
405
|
+
* @since 0.1.0
|
|
406
|
+
*/
|
|
407
|
+
export declare const locale: (locales: ReadonlyArray<string>) => {
|
|
408
|
+
readonly kind: "never";
|
|
409
|
+
} | {
|
|
410
|
+
readonly kind: "locale";
|
|
411
|
+
readonly column: "locale";
|
|
412
|
+
readonly locales: readonly string[];
|
|
413
|
+
};
|
|
414
|
+
/**
|
|
415
|
+
* Conjunction. `always` parts drop out, a `never` part makes the whole
|
|
416
|
+
* `never`, and a single remaining part is returned bare — so composing
|
|
417
|
+
* optional filters reads as one call, the shape the apps' `combine` had.
|
|
418
|
+
*
|
|
419
|
+
* @since 0.1.0
|
|
420
|
+
*/
|
|
421
|
+
export declare const and: <Following>(...filters: ReadonlyArray<ListFilter<Following>>) => ListFilter<Following>;
|
|
422
|
+
/**
|
|
423
|
+
* Disjunction. `never` parts drop out, an `always` part makes the whole
|
|
424
|
+
* `always`, and a single remaining part is returned bare.
|
|
425
|
+
*
|
|
426
|
+
* @since 0.1.0
|
|
427
|
+
*/
|
|
428
|
+
export declare const or: <Following>(...filters: ReadonlyArray<ListFilter<Following>>) => ListFilter<Following>;
|
|
429
|
+
/**
|
|
430
|
+
* What {@link evaluate} needs besides the row: the query's clock and the `in` test.
|
|
431
|
+
*
|
|
432
|
+
* @since 0.1.0
|
|
433
|
+
*/
|
|
434
|
+
export interface EvaluationContext<Following> {
|
|
435
|
+
/** The instant `published` / `notPublished` compare against — the query's `now()`. */
|
|
436
|
+
readonly now: Date;
|
|
437
|
+
/**
|
|
438
|
+
* Whether `value` is a member of the follower seam's `set`. {@link evaluate}
|
|
439
|
+
* never asks it about a `null` or absent column: such a row satisfies no
|
|
440
|
+
* `in`, and every `notIn`, whatever this would answer.
|
|
441
|
+
*/
|
|
442
|
+
readonly contains: (set: Following, value: ColumnValue) => boolean;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Run a filter against one row — the in-memory reading of the rendering
|
|
446
|
+
* contract above. A column that is `null` or that the row lacks matches no
|
|
447
|
+
* `eq`, satisfies no `ne`, `in`, comparison, `anyOf` or non-empty `noneOf`,
|
|
448
|
+
* satisfies every `notIn`, and is unpublished: SQL reads `NULL = $v`, `NULL <> $v`, `NULL IN (…)`,
|
|
449
|
+
* `NULL > $v` and `NULL <> ALL(…)` as `NULL`, which a `WHERE` drops, so `ne`
|
|
450
|
+
* is not the complement of `eq`, nor `noneOf` of `anyOf`, over a nullable
|
|
451
|
+
* column; {@link isNull} is the one node such a row satisfies. Such a row fails an `in` without `context.contains` being asked, so
|
|
452
|
+
* the answer never depends on the seam (pulpit#94). A set past
|
|
453
|
+
* {@link MAX_SET_VALUES} is `never`. Outside the contract it fails closed: a
|
|
454
|
+
* column of another type than the comparand (or than any of a set's values),
|
|
455
|
+
* and a `NaN` (or invalid `Date`) comparand, set element or column, satisfy
|
|
456
|
+
* no `eq`, `ne`, comparison, `anyOf` or non-empty `noneOf`.
|
|
457
|
+
*
|
|
458
|
+
* @since 0.1.0
|
|
459
|
+
*/
|
|
460
|
+
export declare const evaluate: <Following>(filter: ListFilter<Following>, row: FilterRow, context: EvaluationContext<Following>) => boolean;
|
|
461
|
+
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"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"}
|