arrowbase 0.1.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/CHANGELOG.md +27 -0
- package/COMPATIBILITY.md +398 -0
- package/LICENSE +21 -0
- package/MIGRATING.md +238 -0
- package/README.md +897 -0
- package/RELEASE_NOTES.md +68 -0
- package/dist/arrow.d.ts +93 -0
- package/dist/arrow.js +5366 -0
- package/dist/arrow.js.map +1 -0
- package/dist/broadcast.d.ts +173 -0
- package/dist/broadcast.js +319 -0
- package/dist/broadcast.js.map +1 -0
- package/dist/collection-DGlKgOGi.d.ts +1932 -0
- package/dist/idb.d.ts +146 -0
- package/dist/idb.js +6193 -0
- package/dist/idb.js.map +1 -0
- package/dist/index.d.ts +1802 -0
- package/dist/index.js +13924 -0
- package/dist/index.js.map +1 -0
- package/dist/query-CzV9E57Y.d.ts +279 -0
- package/dist/react.d.ts +51 -0
- package/dist/react.js +1633 -0
- package/dist/react.js.map +1 -0
- package/dist/tanstack.d.ts +51 -0
- package/dist/tanstack.js +191 -0
- package/dist/tanstack.js.map +1 -0
- package/dist/types-CSoU6uED.d.ts +50 -0
- package/package.json +139 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { R as RowValue, C as Collection } from './collection-DGlKgOGi.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Column-op filter DSL. A vectorizable alternative to `.where(fn)`.
|
|
5
|
+
*
|
|
6
|
+
* The surface is deliberately tiny — eq/neq/gt/gte/lt/lte for scalars,
|
|
7
|
+
* and/or/not for composition, plus a column-ref helper. Predicates built
|
|
8
|
+
* here are compiled to a `RowTest` closure that reads directly from the
|
|
9
|
+
* column typed-arrays, skipping proxy allocation and per-row row-object
|
|
10
|
+
* materialization. Anything outside this surface still works via
|
|
11
|
+
* `.where(fn)` at normal (proxy) speed.
|
|
12
|
+
*
|
|
13
|
+
* Example:
|
|
14
|
+
* import { query, f, eq, and, gt } from 'arrowbase';
|
|
15
|
+
* query(c).filter(and(eq(f('tag'), 'asphalt'), gt(f('speed'), 40)));
|
|
16
|
+
*/
|
|
17
|
+
type Scalar = number | bigint | boolean | string | null;
|
|
18
|
+
/** A reference to a column by name. */
|
|
19
|
+
interface ColumnRef {
|
|
20
|
+
readonly kind: 'col';
|
|
21
|
+
readonly name: string;
|
|
22
|
+
}
|
|
23
|
+
interface LiteralNode {
|
|
24
|
+
readonly kind: 'lit';
|
|
25
|
+
readonly value: Scalar;
|
|
26
|
+
}
|
|
27
|
+
type Operand = ColumnRef | LiteralNode;
|
|
28
|
+
type CmpOp = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte';
|
|
29
|
+
interface CompareNode {
|
|
30
|
+
readonly kind: 'cmp';
|
|
31
|
+
readonly op: CmpOp;
|
|
32
|
+
readonly left: Operand;
|
|
33
|
+
readonly right: Operand;
|
|
34
|
+
}
|
|
35
|
+
interface AndNode {
|
|
36
|
+
readonly kind: 'and';
|
|
37
|
+
readonly args: readonly FilterExpr[];
|
|
38
|
+
}
|
|
39
|
+
interface OrNode {
|
|
40
|
+
readonly kind: 'or';
|
|
41
|
+
readonly args: readonly FilterExpr[];
|
|
42
|
+
}
|
|
43
|
+
interface NotNode {
|
|
44
|
+
readonly kind: 'not';
|
|
45
|
+
readonly arg: FilterExpr;
|
|
46
|
+
}
|
|
47
|
+
interface IsNullNode {
|
|
48
|
+
readonly kind: 'isNull';
|
|
49
|
+
readonly col: ColumnRef;
|
|
50
|
+
readonly negated: boolean;
|
|
51
|
+
}
|
|
52
|
+
interface InNode {
|
|
53
|
+
readonly kind: 'in';
|
|
54
|
+
readonly col: ColumnRef;
|
|
55
|
+
readonly values: readonly Scalar[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* String predicate. Covers the common text-matching cases with a
|
|
59
|
+
* vectorizable shape so the kernel can pre-compute (e.g., the matching
|
|
60
|
+
* set of dict codes) instead of walking characters per row.
|
|
61
|
+
*
|
|
62
|
+
* `op`:
|
|
63
|
+
* - `contains` / `startsWith` / `endsWith`: plain substring match.
|
|
64
|
+
* - `like`: SQL LIKE, with `%` = any sequence, `_` = any single char,
|
|
65
|
+
* and `\` as an escape for literal `%` / `_`.
|
|
66
|
+
* - `matches`: raw RegExp pattern (string + optional flags) run with
|
|
67
|
+
* `RegExp.prototype.test`. Use sparingly; engines inline the other
|
|
68
|
+
* ops much more aggressively.
|
|
69
|
+
*
|
|
70
|
+
* `caseInsensitive` performs ASCII-fold case folding (fast). For
|
|
71
|
+
* locale-aware folding (German ß, Turkish dotted-I, etc.) use
|
|
72
|
+
* `matches` with an explicit RegExp containing the `i` flag, which the
|
|
73
|
+
* engine delegates to the platform.
|
|
74
|
+
*/
|
|
75
|
+
type StringOp = 'contains' | 'startsWith' | 'endsWith' | 'like' | 'matches';
|
|
76
|
+
interface StringOpNode {
|
|
77
|
+
readonly kind: 'str';
|
|
78
|
+
readonly op: StringOp;
|
|
79
|
+
readonly col: ColumnRef;
|
|
80
|
+
/** Pattern or substring. For `matches`, the regex source. */
|
|
81
|
+
readonly value: string;
|
|
82
|
+
/** Flags (for `matches` only). Ignored for other ops. */
|
|
83
|
+
readonly flags?: string;
|
|
84
|
+
/** ASCII-fold case-insensitive compare. Ignored by `matches`. */
|
|
85
|
+
readonly caseInsensitive?: boolean;
|
|
86
|
+
/** If true, the match result is inverted (NOT contains/like/...). */
|
|
87
|
+
readonly negated?: boolean;
|
|
88
|
+
}
|
|
89
|
+
type FilterExpr = CompareNode | AndNode | OrNode | NotNode | IsNullNode | InNode | StringOpNode | ColumnRef;
|
|
90
|
+
/** Build a column ref. `f('speed')` reads shorter at the call site. */
|
|
91
|
+
declare function f(name: string): ColumnRef;
|
|
92
|
+
declare function eq(a: Operand | Scalar, b: Operand | Scalar): CompareNode;
|
|
93
|
+
declare function neq(a: Operand | Scalar, b: Operand | Scalar): CompareNode;
|
|
94
|
+
declare function gt(a: Operand | Scalar, b: Operand | Scalar): CompareNode;
|
|
95
|
+
declare function gte(a: Operand | Scalar, b: Operand | Scalar): CompareNode;
|
|
96
|
+
declare function lt(a: Operand | Scalar, b: Operand | Scalar): CompareNode;
|
|
97
|
+
declare function lte(a: Operand | Scalar, b: Operand | Scalar): CompareNode;
|
|
98
|
+
declare function and(...args: FilterExpr[]): AndNode;
|
|
99
|
+
declare function or(...args: FilterExpr[]): OrNode;
|
|
100
|
+
declare function not(arg: FilterExpr): NotNode;
|
|
101
|
+
declare function isNull(col: ColumnRef): IsNullNode;
|
|
102
|
+
declare function isNotNull(col: ColumnRef): IsNullNode;
|
|
103
|
+
declare function inArray(col: ColumnRef, values: readonly Scalar[]): InNode;
|
|
104
|
+
interface StringOpOptions {
|
|
105
|
+
/** ASCII-fold case-insensitive. Ignored by `matches`. */
|
|
106
|
+
caseInsensitive?: boolean;
|
|
107
|
+
/** Invert match. */
|
|
108
|
+
negated?: boolean;
|
|
109
|
+
}
|
|
110
|
+
declare function contains(col: ColumnRef, value: string, opts?: StringOpOptions): StringOpNode;
|
|
111
|
+
declare function startsWith(col: ColumnRef, value: string, opts?: StringOpOptions): StringOpNode;
|
|
112
|
+
declare function endsWith(col: ColumnRef, value: string, opts?: StringOpOptions): StringOpNode;
|
|
113
|
+
declare function like(col: ColumnRef, pattern: string, opts?: StringOpOptions): StringOpNode;
|
|
114
|
+
declare function matches(col: ColumnRef, pattern: string | RegExp, opts?: StringOpOptions): StringOpNode;
|
|
115
|
+
|
|
116
|
+
type Predicate = (row: RowValue) => boolean;
|
|
117
|
+
type SortDir = 'asc' | 'desc';
|
|
118
|
+
interface JoinSpecLike {
|
|
119
|
+
readonly on: {
|
|
120
|
+
readonly left: string;
|
|
121
|
+
readonly right: string;
|
|
122
|
+
};
|
|
123
|
+
readonly as: string;
|
|
124
|
+
readonly type?: 'inner';
|
|
125
|
+
}
|
|
126
|
+
type JoinQueryLike = any;
|
|
127
|
+
interface OrderSpec {
|
|
128
|
+
readonly column: string;
|
|
129
|
+
readonly dir: SortDir;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Immutable query spec. Each builder method returns a new Query. Deps are
|
|
133
|
+
* either `'all'` (everything) or a concrete set of column names. When a
|
|
134
|
+
* predicate is present and no explicit `.deps(...)` override was applied,
|
|
135
|
+
* deps are inferred on first evaluation via the tracking proxy and grow
|
|
136
|
+
* monotonically over time.
|
|
137
|
+
*/
|
|
138
|
+
declare class Query<TRow extends RowValue = RowValue> {
|
|
139
|
+
readonly collection: Collection;
|
|
140
|
+
readonly predicate: Predicate | null;
|
|
141
|
+
/** Column-op filter DSL expression (vectorizable). */
|
|
142
|
+
readonly filterExpr: FilterExpr | null;
|
|
143
|
+
readonly selection: readonly string[] | null;
|
|
144
|
+
readonly order: readonly OrderSpec[];
|
|
145
|
+
readonly limitN: number | null;
|
|
146
|
+
readonly offsetN: number;
|
|
147
|
+
/** Explicit deps override. If null, deps are inferred. */
|
|
148
|
+
readonly explicitDeps: ReadonlySet<string> | null;
|
|
149
|
+
constructor(collection: Collection, predicate?: Predicate | null, selection?: readonly string[] | null, order?: readonly OrderSpec[], limitN?: number | null, offsetN?: number, explicitDeps?: ReadonlySet<string> | null, filterExpr?: FilterExpr | null);
|
|
150
|
+
where(predicate: Predicate): Query<TRow>;
|
|
151
|
+
/**
|
|
152
|
+
* Add a vectorizable column-op filter. Composes with prior `filter()`
|
|
153
|
+
* calls via AND. Anything that fits the `FilterExpr` DSL takes the
|
|
154
|
+
* vectorized fast path in `QueryExecutor`; combine with `.where(fn)`
|
|
155
|
+
* when you need an escape hatch for logic outside the DSL — the fast
|
|
156
|
+
* path still runs first for the DSL portion.
|
|
157
|
+
*/
|
|
158
|
+
filter(expr: FilterExpr): Query<TRow>;
|
|
159
|
+
select(columns: readonly string[]): Query<TRow>;
|
|
160
|
+
orderBy(column: string, dir?: SortDir): Query<TRow>;
|
|
161
|
+
limit(n: number): Query<TRow>;
|
|
162
|
+
offset(n: number): Query<TRow>;
|
|
163
|
+
/**
|
|
164
|
+
* Equijoin against another collection. Returns a `JoinQuery` that
|
|
165
|
+
* exposes the post-join builder surface (where / select / orderBy /
|
|
166
|
+
* limit / offset).
|
|
167
|
+
*
|
|
168
|
+
* ```ts
|
|
169
|
+
* query(orders)
|
|
170
|
+
* .filter(f('amount').gt(100))
|
|
171
|
+
* .join(users, { on: { left: 'userId', right: '__id' }, as: 'user' })
|
|
172
|
+
* .orderBy('user.name')
|
|
173
|
+
* .select(['id', 'amount', 'user.name']);
|
|
174
|
+
* ```
|
|
175
|
+
*
|
|
176
|
+
* Implementation: to avoid a static cycle between query.ts and
|
|
177
|
+
* join.ts, join.ts registers its factory via `registerJoinFactory`
|
|
178
|
+
* at module-load time. Importing `arrowbase` (or
|
|
179
|
+
* `arrowbase/query/join`) before calling `.join()` is sufficient.
|
|
180
|
+
*/
|
|
181
|
+
join(right: Collection, spec: JoinSpecLike): JoinQueryLike;
|
|
182
|
+
/**
|
|
183
|
+
* Explicit dep override. Use this when:
|
|
184
|
+
* - your predicate reads columns conditionally and you want stable deps
|
|
185
|
+
* - you want to force reactivity on a superset of columns
|
|
186
|
+
*/
|
|
187
|
+
deps(columns: readonly string[]): Query<TRow>;
|
|
188
|
+
/** Columns that must be materialized for this query (deps + filter + selection + order). */
|
|
189
|
+
requiredColumns(inferredDeps: ReadonlySet<string>): ReadonlySet<string>;
|
|
190
|
+
private requireKnownColumn;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Snapshot = result of evaluating a Query at a specific global version.
|
|
194
|
+
* Rows are plain JS objects shaped by `selection` (or full rows if null).
|
|
195
|
+
*/
|
|
196
|
+
interface QuerySnapshot<TRow extends RowValue = RowValue> {
|
|
197
|
+
readonly rows: readonly TRow[];
|
|
198
|
+
/** Collection.globalVersion at the moment of the snapshot. */
|
|
199
|
+
readonly version: number;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Executor = caches the last snapshot + dep set for a Query so we can skip
|
|
203
|
+
* recomputation when only untouched columns changed.
|
|
204
|
+
*
|
|
205
|
+
* Executors are created by `run(query)` and held by callers (including the
|
|
206
|
+
* subscribe wrapper below). A single Query instance may have multiple
|
|
207
|
+
* executors in flight; each owns its own cache.
|
|
208
|
+
*/
|
|
209
|
+
declare class QueryExecutor<TRow extends RowValue = RowValue> {
|
|
210
|
+
readonly query: Query<TRow>;
|
|
211
|
+
private deps;
|
|
212
|
+
private cachedSnapshot;
|
|
213
|
+
/** Per-column version seen at the time `cachedSnapshot` was produced. */
|
|
214
|
+
private cachedVersions;
|
|
215
|
+
/**
|
|
216
|
+
* When the predicate trips (throws) during the tracking dry-run, we
|
|
217
|
+
* fall back to `deps = all`. We still try inference again after the
|
|
218
|
+
* predicate changes, but a single Query instance keeps this bit sticky.
|
|
219
|
+
*/
|
|
220
|
+
private depsAreAll;
|
|
221
|
+
/**
|
|
222
|
+
* Inserts, deletes, and rollbacks invalidate any cached snapshot because
|
|
223
|
+
* they may change the live row set even when no observed value column
|
|
224
|
+
* moves (soft-delete notwithstanding). We flip this flag from a passive
|
|
225
|
+
* change listener and clear it on recompute.
|
|
226
|
+
*/
|
|
227
|
+
private staleFromInsertOrDelete;
|
|
228
|
+
private readonly unsubscribePassive;
|
|
229
|
+
constructor(query: Query<TRow>);
|
|
230
|
+
/** Release the passive change listener. */
|
|
231
|
+
dispose(): void;
|
|
232
|
+
/** True if the cached snapshot is still valid given current column versions. */
|
|
233
|
+
private cacheIsFresh;
|
|
234
|
+
/**
|
|
235
|
+
* Columns this query observes for invalidation purposes. Includes:
|
|
236
|
+
* - inferred or explicit deps (from predicate / .deps())
|
|
237
|
+
* - selection columns (stale projection otherwise)
|
|
238
|
+
* - order-by columns (stale sort otherwise)
|
|
239
|
+
*/
|
|
240
|
+
private observedColumns;
|
|
241
|
+
/** Lazily compile the filterExpr. Cached for executor lifetime. */
|
|
242
|
+
private compiledFilter;
|
|
243
|
+
private compiledFilterExpr;
|
|
244
|
+
private compiledFilterError;
|
|
245
|
+
private getCompiledFilter;
|
|
246
|
+
/** Recompute the snapshot, updating cache. */
|
|
247
|
+
private recompute;
|
|
248
|
+
/** Legacy scan: materialize + run fn predicate with dep tracking. Returns ordinals of survivors. */
|
|
249
|
+
private legacyScan;
|
|
250
|
+
/**
|
|
251
|
+
* Map the sequential index returned by `rows()` to the live row
|
|
252
|
+
* ordinal. `rows()` yields in the same order as `_internalLiveOrdinals()`,
|
|
253
|
+
* so we lazily keep a parallel ordinal buffer.
|
|
254
|
+
*/
|
|
255
|
+
private cachedOrdinalBuffer;
|
|
256
|
+
private cachedOrdinalVersion;
|
|
257
|
+
private getOrdinalFor;
|
|
258
|
+
/** Apply the fn predicate to a candidate ordinal set (post-kernel filter). */
|
|
259
|
+
private applyFnPredicate;
|
|
260
|
+
private materializeFullRow;
|
|
261
|
+
/** Return a snapshot, reusing the cached one if all observed columns are unchanged. */
|
|
262
|
+
snapshot(): QuerySnapshot<TRow>;
|
|
263
|
+
/**
|
|
264
|
+
* Subscribe to reactive updates. `listener` fires once with the initial
|
|
265
|
+
* snapshot and then again after every mutation that touches an observed
|
|
266
|
+
* column. Returns an unsubscribe function.
|
|
267
|
+
*/
|
|
268
|
+
subscribe(listener: (snap: QuerySnapshot<TRow>) => void): () => void;
|
|
269
|
+
/** Visible for tests: introspect current inferred deps. */
|
|
270
|
+
get inferredDeps(): ReadonlySet<string>;
|
|
271
|
+
get isDepsAll(): boolean;
|
|
272
|
+
private shouldReact;
|
|
273
|
+
}
|
|
274
|
+
/** Shorthand entry point: `query(collection).where(...).select(...)`. */
|
|
275
|
+
declare function query<TRow extends RowValue = RowValue>(collection: Collection): Query<TRow>;
|
|
276
|
+
/** Build an executor for a Query. */
|
|
277
|
+
declare function run<TRow extends RowValue = RowValue>(q: Query<TRow>): QueryExecutor<TRow>;
|
|
278
|
+
|
|
279
|
+
export { type ColumnRef as C, type FilterExpr as F, type InNode as I, type OrderSpec as O, type Predicate as P, Query as Q, type SortDir as S, type Scalar as a, QueryExecutor as b, type QuerySnapshot as c, type StringOp as d, type StringOpNode as e, type StringOpOptions as f, f as g, and as h, contains as i, endsWith as j, eq as k, gt as l, gte as m, inArray as n, isNotNull as o, isNull as p, like as q, lt as r, lte as s, matches as t, neq as u, not as v, or as w, startsWith as x, query as y, run as z };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { R as RowValue, C as Collection } from './collection-DGlKgOGi.js';
|
|
2
|
+
import { c as QuerySnapshot, Q as Query } from './query-CzV9E57Y.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Subscribe a React component to a Query. Returns the latest snapshot
|
|
6
|
+
* (`{ rows, version }`); the component re-renders when the query's
|
|
7
|
+
* observed columns change.
|
|
8
|
+
*
|
|
9
|
+
* The executor is created on first mount and cached for the lifetime of
|
|
10
|
+
* the owning component (not the Query instance). When the query
|
|
11
|
+
* identity changes between renders, a fresh executor is created and
|
|
12
|
+
* the previous one is disposed.
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* const q = useMemo(() => query(users).filter(fEq(f('active'), true)), [users]);
|
|
16
|
+
* const { rows } = useLiveQuery(q);
|
|
17
|
+
* return <ul>{rows.map(r => <li key={r.__id}>{r.name}</li>)}</ul>;
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* The snapshot `rows` reference is stable across renders when the
|
|
21
|
+
* executor determined nothing changed (internal caching), so users can
|
|
22
|
+
* pass it directly into `React.memo`'d children without extra memo.
|
|
23
|
+
*/
|
|
24
|
+
declare function useLiveQuery<TRow extends RowValue>(query: Query<TRow>, options?: UseLiveQueryOptions<TRow>): QuerySnapshot<TRow>;
|
|
25
|
+
interface UseLiveQueryOptions<TRow extends RowValue> {
|
|
26
|
+
/** Value returned during SSR. Defaults to an empty-rows snapshot. */
|
|
27
|
+
readonly ssrSnapshot?: QuerySnapshot<TRow>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builder-closure variant. Accepts a function that composes a Query
|
|
31
|
+
* (typically a `.filter().orderBy()...` chain) and a dependency array
|
|
32
|
+
* for when to rebuild. This avoids making callers memoize the Query
|
|
33
|
+
* object themselves.
|
|
34
|
+
*
|
|
35
|
+
* ```tsx
|
|
36
|
+
* const { rows } = useLiveQueryResult(
|
|
37
|
+
* users,
|
|
38
|
+
* (q) => q.filter(fEq(f('team'), team)).orderBy('name'),
|
|
39
|
+
* [team],
|
|
40
|
+
* );
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare function useLiveQueryResult<TRow extends RowValue>(collection: Collection, build: (q: Query<TRow>) => Query<TRow>, deps?: readonly unknown[], options?: UseLiveQueryOptions<TRow>): QuerySnapshot<TRow>;
|
|
44
|
+
/**
|
|
45
|
+
* Subscribe to a collection's `globalVersion`. Returns a monotonically
|
|
46
|
+
* increasing number that bumps on every mutation. Useful as a cache-bust
|
|
47
|
+
* key or a dependency to other hooks.
|
|
48
|
+
*/
|
|
49
|
+
declare function useCollectionVersion(collection: Collection): number;
|
|
50
|
+
|
|
51
|
+
export { type UseLiveQueryOptions, useCollectionVersion, useLiveQuery, useLiveQueryResult };
|