@thi.ng/column-store 0.8.0 → 0.9.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/README.md +45 -8
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +5 -2
- package/predicates.d.ts +25 -0
- package/predicates.js +8 -0
package/README.md
CHANGED
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
- [FLAG_RLE](#flag_rle)
|
|
31
31
|
- [Custom flags](#custom-flags)
|
|
32
32
|
- [Query engine](#query-engine)
|
|
33
|
+
- [Query execution](#query-execution)
|
|
34
|
+
- [Optimized row iteration](#optimized-row-iteration)
|
|
33
35
|
- [Built-in operators](#built-in-operators)
|
|
34
36
|
- [OR](#or)
|
|
35
37
|
- [AND](#and)
|
|
@@ -315,7 +317,9 @@ types](#custom-column-types).
|
|
|
315
317
|
## Query engine
|
|
316
318
|
|
|
317
319
|
The query engine is highly extensible and can be used for executing arbitrarily
|
|
318
|
-
complex queries.
|
|
320
|
+
complex queries via chaining of query operators.
|
|
321
|
+
|
|
322
|
+
### Query execution
|
|
319
323
|
|
|
320
324
|
The system allows predefining queries, which are then only evaluated and produce
|
|
321
325
|
up-to-date results via the standard JS iterable mechanism (i.e. queries
|
|
@@ -328,19 +332,46 @@ const query = table.query().or("name", ["alice", "bob"]);
|
|
|
328
332
|
// actually (re)execute query
|
|
329
333
|
for(let result of query) { ... }
|
|
330
334
|
|
|
331
|
-
// ..or using slice operator
|
|
335
|
+
// ..or collect result into an array using slice operator
|
|
332
336
|
const results = [...query];
|
|
333
337
|
```
|
|
334
338
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
### Built-in operators
|
|
339
|
+
#### Optimized row iteration
|
|
338
340
|
|
|
339
341
|
The query engine works by applying a number of [query
|
|
340
342
|
terms](https://docs.thi.ng/umbrella/column-store/interfaces/QueryTerm.html) in
|
|
341
343
|
series, with each step intersecting (aka logical AND) its results with the
|
|
342
344
|
results of the previous step(s), thereby narrowing down the result set.
|
|
343
345
|
|
|
346
|
+
For each query term, only the rows already marked (aka pre-selected by
|
|
347
|
+
predecessor query terms) are visited. When a query term does not manage to
|
|
348
|
+
select any rows, the query is terminated. Internally, this selecting and
|
|
349
|
+
intersecting of partial query results is done via bitfields only. There's no
|
|
350
|
+
creation of interim result arrays, nor any full decoding/construction of interim
|
|
351
|
+
row records. The latter only happens for the final result rows and/or when using
|
|
352
|
+
the [`matchRow()` or `matchPartialRow()`](#predicate-based-matchers) query
|
|
353
|
+
operators.
|
|
354
|
+
|
|
355
|
+
When a column has an associated bitfield index (enabled via
|
|
356
|
+
[`FLAG_BITMAP`](#flag_bitmap)), some query operators (see below) are optimized
|
|
357
|
+
even further, entirely avoiding the need to visit any individual rows.
|
|
358
|
+
|
|
359
|
+
The diagram below illustrates the application of the following 3-operator query
|
|
360
|
+
and the resulting stepwise narrowing of the result set:
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
table.query()
|
|
364
|
+
.matchColumn("id", inRange(100, 110))
|
|
365
|
+
.matchColumn("age", inRange(20, 50))
|
|
366
|
+
.matchColumn("name", startsWith("a"))
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+

|
|
372
|
+
|
|
373
|
+
### Built-in operators
|
|
374
|
+
|
|
344
375
|
By default, individual query terms operate on a single column, but can also can
|
|
345
376
|
also apply to multiple. Terms are supplied either as array given to the
|
|
346
377
|
[`Query`](https://docs.thi.ng/umbrella/column-store/classes/Query.html)
|
|
@@ -382,12 +413,18 @@ can be used, otherwise the behavior is:
|
|
|
382
413
|
|
|
383
414
|
#### Predicate-based matchers
|
|
384
415
|
|
|
416
|
+
> [!NOTE]
|
|
417
|
+
> For best performance and to minimize/avoid potential decoding and construction
|
|
418
|
+
> of interim row objects, prefer `matchColumn` or `matchPartialRow` over
|
|
419
|
+
> `matchRow` if at all possible. Oftentimes, query predicates requiring multiple
|
|
420
|
+
> column values can be easily refactored into separate query terms.
|
|
421
|
+
|
|
385
422
|
- [`matchColumn`](https://docs.thi.ng/umbrella/column-store/classes/Query.html#matchcolumn):
|
|
386
423
|
apply predicate to column value
|
|
387
|
-
- [`matchRow`](https://docs.thi.ng/umbrella/column-store/classes/Query.html#matchrow):
|
|
388
|
-
apply predicate to full row
|
|
389
424
|
- [`matchPartialRow`](https://docs.thi.ng/umbrella/column-store/classes/Query.html#matchpartialrow):
|
|
390
425
|
apply predicate to partial row (only selected columns)
|
|
426
|
+
- [`matchRow`](https://docs.thi.ng/umbrella/column-store/classes/Query.html#matchrow):
|
|
427
|
+
apply predicate to full row
|
|
391
428
|
|
|
392
429
|
#### Row ranges
|
|
393
430
|
|
|
@@ -458,7 +495,7 @@ For Node.js REPL:
|
|
|
458
495
|
const cs = await import("@thi.ng/column-store");
|
|
459
496
|
```
|
|
460
497
|
|
|
461
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 5.
|
|
498
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 5.78 KB
|
|
462
499
|
|
|
463
500
|
## Dependencies
|
|
464
501
|
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/column-store",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "In-memory column store database with customizable column types, extensible query engine, bitfield indexing for query acceleration, JSON serialization with optional RLE compression",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -115,6 +115,9 @@
|
|
|
115
115
|
"./columns/vector": {
|
|
116
116
|
"default": "./columns/vector.js"
|
|
117
117
|
},
|
|
118
|
+
"./predicates": {
|
|
119
|
+
"default": "./predicates.js"
|
|
120
|
+
},
|
|
118
121
|
"./query": {
|
|
119
122
|
"default": "./query.js"
|
|
120
123
|
},
|
|
@@ -126,5 +129,5 @@
|
|
|
126
129
|
"status": "alpha",
|
|
127
130
|
"year": 2025
|
|
128
131
|
},
|
|
129
|
-
"gitHead": "
|
|
132
|
+
"gitHead": "1138bb64457a415733cf5c05d32c211ccfd6ee72\n"
|
|
130
133
|
}
|
package/predicates.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NumOrString, Predicate } from "@thi.ng/api";
|
|
2
|
+
/**
|
|
3
|
+
* Higher-order query predicate for {@link Query.matchColumn}. The returned
|
|
4
|
+
* predicate returns true if a row value is in the semi-open interval defined by
|
|
5
|
+
* `[min,max)`.
|
|
6
|
+
*
|
|
7
|
+
* @param min
|
|
8
|
+
* @param max
|
|
9
|
+
*/
|
|
10
|
+
export declare const inRange: (min: NumOrString, max: NumOrString) => Predicate<NumOrString | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Higher-order query predicate for {@link Query.matchColumn}. The returned
|
|
13
|
+
* predicate returns true if a row value starts with given `prefix`.
|
|
14
|
+
*
|
|
15
|
+
* @param prefix
|
|
16
|
+
*/
|
|
17
|
+
export declare const startsWith: (prefix: string) => Predicate<string | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Higher-order query predicate for {@link Query.matchColumn}. The returned
|
|
20
|
+
* predicate returns true if a row value matches the given `regexp`.
|
|
21
|
+
*
|
|
22
|
+
* @param re
|
|
23
|
+
*/
|
|
24
|
+
export declare const matchRegExp: (re: RegExp) => Predicate<string | null>;
|
|
25
|
+
//# sourceMappingURL=predicates.d.ts.map
|
package/predicates.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const inRange = (min, max) => (x) => x != null && x >= min && x < max;
|
|
2
|
+
const startsWith = (prefix) => (x) => x?.startsWith(prefix) ?? false;
|
|
3
|
+
const matchRegExp = (re) => (x) => x != null ? re.test(x) : false;
|
|
4
|
+
export {
|
|
5
|
+
inRange,
|
|
6
|
+
matchRegExp,
|
|
7
|
+
startsWith
|
|
8
|
+
};
|