@thi.ng/column-store 0.10.1 → 0.11.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/README.md +12 -1
- package/columns/vector.d.ts +1 -1
- package/internal/serialize.d.ts +1 -1
- package/package.json +8 -7
- package/query.d.ts +19 -3
- package/query.js +54 -3
- package/table.d.ts +11 -0
- package/table.js +19 -4
package/README.md
CHANGED
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
- [Predicate-based matchers](#predicate-based-matchers)
|
|
40
40
|
- [Row ranges](#row-ranges)
|
|
41
41
|
- [Value ranges](#value-ranges)
|
|
42
|
+
- [Result order and pagination](#result-order-and-pagination)
|
|
42
43
|
- [Custom operators](#custom-operators)
|
|
43
44
|
- [Result aggregation](#result-aggregation)
|
|
44
45
|
- [Query ranges](#query-ranges)
|
|
@@ -450,6 +451,15 @@ operator selects rows based on a given column's `start` .. `end` vaulue range
|
|
|
450
451
|
query.valueRange("id", 100, 109);
|
|
451
452
|
```
|
|
452
453
|
|
|
454
|
+
### Result order and pagination
|
|
455
|
+
|
|
456
|
+
- [`sortBy()`](https://docs.thi.ng/umbrella/column-store/classes/Query.html#sortby)
|
|
457
|
+
allows query results to be ordered (ascending or descending) via an arbitrary
|
|
458
|
+
number of sort columns or criteria, applied in the given order.
|
|
459
|
+
- [`limit()`](https://docs.thi.ng/umbrella/column-store/classes/Query.html#limit)
|
|
460
|
+
provides basic pagination of query results by specifying a max. number of
|
|
461
|
+
results and start offset
|
|
462
|
+
|
|
453
463
|
### Custom operators
|
|
454
464
|
|
|
455
465
|
Custom query operators can be registered via
|
|
@@ -495,13 +505,14 @@ For Node.js REPL:
|
|
|
495
505
|
const cs = await import("@thi.ng/column-store");
|
|
496
506
|
```
|
|
497
507
|
|
|
498
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
508
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 6.28 KB
|
|
499
509
|
|
|
500
510
|
## Dependencies
|
|
501
511
|
|
|
502
512
|
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
|
|
503
513
|
- [@thi.ng/bidir-index](https://github.com/thi-ng/umbrella/tree/develop/packages/bidir-index)
|
|
504
514
|
- [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
|
|
515
|
+
- [@thi.ng/compare](https://github.com/thi-ng/umbrella/tree/develop/packages/compare)
|
|
505
516
|
- [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)
|
|
506
517
|
- [@thi.ng/rle-pack](https://github.com/thi-ng/umbrella/tree/develop/packages/rle-pack)
|
|
507
518
|
|
package/columns/vector.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare class VectorColumn<T extends Row = Row> extends AColumn<T> {
|
|
|
15
15
|
validate(value: any): boolean;
|
|
16
16
|
ensureRows(): void;
|
|
17
17
|
setRow(i: number, value: any): void;
|
|
18
|
-
getRow(i: number):
|
|
18
|
+
getRow(i: number): Float32Array<ArrayBufferLike> | Float64Array<ArrayBufferLike> | Int8Array<ArrayBufferLike> | Int16Array<ArrayBufferLike> | Int32Array<ArrayBufferLike> | Uint8Array<ArrayBufferLike> | Uint8ClampedArray<ArrayBufferLike> | Uint16Array<ArrayBufferLike> | Uint32Array<ArrayBufferLike>;
|
|
19
19
|
getRowKey(i: number): string;
|
|
20
20
|
valueKey(value: any): string | string[];
|
|
21
21
|
removeRow(i: number): void;
|
package/internal/serialize.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export declare const __serializeTyped: ($values: NumericArray, spec: ColumnSpec,
|
|
|
11
11
|
values: any[];
|
|
12
12
|
};
|
|
13
13
|
/** @internal */
|
|
14
|
-
export declare const __deserializeTyped: (type: Type, flags: number, values: number[]) =>
|
|
14
|
+
export declare const __deserializeTyped: (type: Type, flags: number, values: number[]) => Float32Array<ArrayBufferLike> | Float64Array<ArrayBufferLike> | Int8Array<ArrayBufferLike> | Int16Array<ArrayBufferLike> | Int32Array<ArrayBufferLike> | Uint8Array<ArrayBufferLike> | Uint8ClampedArray<ArrayBufferLike> | Uint16Array<ArrayBufferLike> | Uint32Array<ArrayBufferLike>;
|
|
15
15
|
//# sourceMappingURL=serialize.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/column-store",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
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",
|
|
@@ -40,11 +40,12 @@
|
|
|
40
40
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@thi.ng/api": "^8.12.
|
|
44
|
-
"@thi.ng/bidir-index": "^1.5.
|
|
45
|
-
"@thi.ng/checks": "^3.8.
|
|
46
|
-
"@thi.ng/
|
|
47
|
-
"@thi.ng/
|
|
43
|
+
"@thi.ng/api": "^8.12.15",
|
|
44
|
+
"@thi.ng/bidir-index": "^1.5.1",
|
|
45
|
+
"@thi.ng/checks": "^3.8.5",
|
|
46
|
+
"@thi.ng/compare": "^2.5.1",
|
|
47
|
+
"@thi.ng/errors": "^2.6.4",
|
|
48
|
+
"@thi.ng/rle-pack": "^3.2.2"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"esbuild": "^0.27.2",
|
|
@@ -129,5 +130,5 @@
|
|
|
129
130
|
"status": "alpha",
|
|
130
131
|
"year": 2025
|
|
131
132
|
},
|
|
132
|
-
"gitHead": "
|
|
133
|
+
"gitHead": "8f50352caab9ec7757d645c0afa605dfb5427abe\n"
|
|
133
134
|
}
|
package/query.d.ts
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
|
-
import type { Predicate } from "@thi.ng/api";
|
|
2
|
-
import type { ColumnID, QueryTerm, QueryTermOpSpec, Row } from "./api.js";
|
|
1
|
+
import type { Comparator, Predicate } from "@thi.ng/api";
|
|
2
|
+
import type { ColumnID, QueryTerm, QueryTermOpSpec, Row, RowWithMeta } from "./api.js";
|
|
3
3
|
import type { Table } from "./table.js";
|
|
4
4
|
export declare class Query<T extends Row> {
|
|
5
5
|
readonly table: Table<T>;
|
|
6
6
|
terms: QueryTerm<T>[];
|
|
7
|
+
protected _cmp?: Comparator<any>;
|
|
8
|
+
protected _limit: number;
|
|
9
|
+
protected _offset: number;
|
|
7
10
|
constructor(table: Table<T>, terms?: QueryTerm<T>[]);
|
|
8
11
|
addTerm(term: QueryTerm<T>): this;
|
|
12
|
+
limit(limit: number, offset?: number): void;
|
|
13
|
+
/**
|
|
14
|
+
* Constructs a comparator for query results based on given sort criteria,
|
|
15
|
+
* which are applied in given order. Each criteria can be on of:
|
|
16
|
+
*
|
|
17
|
+
* - comparator (applied to full rows)
|
|
18
|
+
* - columnID
|
|
19
|
+
* - tuple of `[columnID, boolean]` (if boolean is true, sorts in ascending order)
|
|
20
|
+
* - tuple of `[columnID, comparator]`
|
|
21
|
+
*
|
|
22
|
+
* @param order
|
|
23
|
+
*/
|
|
24
|
+
sortBy(...order: (ColumnID<T> | Comparator<T> | [ColumnID<T>, boolean | Comparator<any>])[]): this;
|
|
9
25
|
/** Alias for {@link Query.or} */
|
|
10
26
|
where: (column: ColumnID<T>, value: any) => this;
|
|
11
27
|
/** Alias for {@link Query.nor} */
|
|
@@ -19,7 +35,7 @@ export declare class Query<T extends Row> {
|
|
|
19
35
|
matchRow(pred: Predicate<T>): this;
|
|
20
36
|
valueRange(column: ColumnID<T>, start: any, end?: any): this;
|
|
21
37
|
rowRange(start?: number, end?: number): this;
|
|
22
|
-
[Symbol.iterator](): Generator<
|
|
38
|
+
[Symbol.iterator](): Generator<RowWithMeta<T>, void, unknown>;
|
|
23
39
|
}
|
|
24
40
|
export declare class QueryCtx<T extends Row> {
|
|
25
41
|
readonly query: Query<T>;
|
package/query.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { isArray } from "@thi.ng/checks/is-array";
|
|
2
|
+
import { isFunction } from "@thi.ng/checks/is-function";
|
|
2
3
|
import { isNumber } from "@thi.ng/checks/is-number";
|
|
4
|
+
import { isString } from "@thi.ng/checks/is-string";
|
|
5
|
+
import { compare } from "@thi.ng/compare/compare";
|
|
6
|
+
import { composeComparators } from "@thi.ng/compare/compose";
|
|
7
|
+
import { compareByKey } from "@thi.ng/compare/keys";
|
|
8
|
+
import { reverse } from "@thi.ng/compare/reverse";
|
|
3
9
|
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
4
10
|
import { unsupportedOp } from "@thi.ng/errors/unsupported";
|
|
5
11
|
import { Bitfield } from "./bitmap.js";
|
|
@@ -11,11 +17,39 @@ class Query {
|
|
|
11
17
|
for (let term of terms) this.addTerm(term);
|
|
12
18
|
}
|
|
13
19
|
terms = [];
|
|
20
|
+
_cmp;
|
|
21
|
+
_limit = Infinity;
|
|
22
|
+
_offset = 0;
|
|
14
23
|
addTerm(term) {
|
|
15
24
|
if (!QUERY_OPS[term.type]) unsupportedOp(`query type: ${term.type}`);
|
|
16
25
|
this.terms.push(term);
|
|
17
26
|
return this;
|
|
18
27
|
}
|
|
28
|
+
limit(limit, offset = 0) {
|
|
29
|
+
this._limit = limit;
|
|
30
|
+
this._offset = offset;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Constructs a comparator for query results based on given sort criteria,
|
|
34
|
+
* which are applied in given order. Each criteria can be on of:
|
|
35
|
+
*
|
|
36
|
+
* - comparator (applied to full rows)
|
|
37
|
+
* - columnID
|
|
38
|
+
* - tuple of `[columnID, boolean]` (if boolean is true, sorts in ascending order)
|
|
39
|
+
* - tuple of `[columnID, comparator]`
|
|
40
|
+
*
|
|
41
|
+
* @param order
|
|
42
|
+
*/
|
|
43
|
+
sortBy(...order) {
|
|
44
|
+
const fns = order.map(
|
|
45
|
+
(x) => isFunction(x) ? x : isString(x) ? compareByKey(x) : compareByKey(
|
|
46
|
+
x[0],
|
|
47
|
+
isFunction(x[1]) ? x[1] : x[1] ? compare : reverse(compare)
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
this._cmp = composeComparators(...fns);
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
19
53
|
/** Alias for {@link Query.or} */
|
|
20
54
|
where = (column, value) => this.or(column, value);
|
|
21
55
|
/** Alias for {@link Query.nor} */
|
|
@@ -66,7 +100,7 @@ class Query {
|
|
|
66
100
|
return this;
|
|
67
101
|
}
|
|
68
102
|
*[Symbol.iterator]() {
|
|
69
|
-
const { table } = this;
|
|
103
|
+
const { table, _limit, _offset } = this;
|
|
70
104
|
const ctx = new QueryCtx(this);
|
|
71
105
|
for (let term of this.terms) {
|
|
72
106
|
const op = QUERY_OPS[term.type];
|
|
@@ -81,8 +115,25 @@ class Query {
|
|
|
81
115
|
}
|
|
82
116
|
if (!op.fn(ctx, term, column)) return;
|
|
83
117
|
}
|
|
84
|
-
if (ctx.bitmap)
|
|
85
|
-
|
|
118
|
+
if (!ctx.bitmap) return;
|
|
119
|
+
if (this._cmp) {
|
|
120
|
+
const rows = [];
|
|
121
|
+
for (let i of ctx) {
|
|
122
|
+
rows.push(table.getRow(i, false, true));
|
|
123
|
+
}
|
|
124
|
+
rows.sort(this._cmp);
|
|
125
|
+
for (let i = this._offset, n = Math.min(rows.length, i + this._limit); i < n; i++) {
|
|
126
|
+
yield rows[i];
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let j = 0;
|
|
131
|
+
for (let i of ctx) {
|
|
132
|
+
if (j >= _offset) {
|
|
133
|
+
if (j >= _limit) return;
|
|
134
|
+
yield table.getRow(i, false, true);
|
|
135
|
+
}
|
|
136
|
+
j++;
|
|
86
137
|
}
|
|
87
138
|
}
|
|
88
139
|
}
|
package/table.d.ts
CHANGED
|
@@ -35,6 +35,17 @@ export declare class Table<T extends Row> implements IClear, ICopy<Table<T>>, IE
|
|
|
35
35
|
getPartialRow<K extends ColumnID<T>>(i: number, columns: K[], safe?: boolean): Maybe<Pick<T, K>>;
|
|
36
36
|
getPartialRow<K extends ColumnID<T>>(i: number, columns: K[], safe?: boolean, includeID?: false): Maybe<Pick<T, K>>;
|
|
37
37
|
getPartialRow<K extends ColumnID<T>>(i: number, columns: K[], safe?: boolean, includeID?: true): Maybe<RowWithMeta<Pick<T, K>>>;
|
|
38
|
+
getRows(start?: number, end?: number, includeID?: false): IterableIterator<T>;
|
|
39
|
+
getRows(start?: number, end?: number, includeID?: true): IterableIterator<RowWithMeta<T>>;
|
|
40
|
+
getPartialRows<K extends ColumnID<T>>(columns: K[], start?: number, end?: number, includeID?: false): IterableIterator<Pick<T, K>>;
|
|
41
|
+
getPartialRows<K extends ColumnID<T>>(columns: K[], start?: number, end?: number, includeID?: true): IterableIterator<RowWithMeta<Pick<T, K>>>;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new table with same schema and options, but only containing the
|
|
44
|
+
* subset of rows in the `[start,end)` interval.
|
|
45
|
+
*
|
|
46
|
+
* @param start
|
|
47
|
+
* @param end
|
|
48
|
+
*/
|
|
38
49
|
slice(start?: number, end?: number): Table<T>;
|
|
39
50
|
indexOf(id: ColumnID<T>, value: any, start?: number, end?: number): number;
|
|
40
51
|
lastIndexOf(id: ColumnID<T>, value: any, start?: number, end?: number): number;
|
package/table.js
CHANGED
|
@@ -13,7 +13,7 @@ import { TupleColumn } from "./columns/tuple.js";
|
|
|
13
13
|
import { TypedArrayColumn } from "./columns/typedarray.js";
|
|
14
14
|
import { VectorColumn } from "./columns/vector.js";
|
|
15
15
|
import { __columnError } from "./internal/checks.js";
|
|
16
|
-
import {
|
|
16
|
+
import { __clampRange } from "./internal/indexof.js";
|
|
17
17
|
import { Query } from "./query.js";
|
|
18
18
|
class Table {
|
|
19
19
|
opts;
|
|
@@ -118,10 +118,25 @@ class Table {
|
|
|
118
118
|
}
|
|
119
119
|
return row;
|
|
120
120
|
}
|
|
121
|
+
*getRows(start = 0, end, includeID = false) {
|
|
122
|
+
[start, end] = __clampRange(this.length, start, end);
|
|
123
|
+
for (let i = start; i < end; i++)
|
|
124
|
+
yield this.getRow(i, false, includeID);
|
|
125
|
+
}
|
|
126
|
+
*getPartialRows(columns, start = 0, end, includeID = false) {
|
|
127
|
+
[start, end] = __clampRange(this.length, start, end);
|
|
128
|
+
for (let i = start; i < end; i++)
|
|
129
|
+
yield this.getPartialRow(i, columns, false, includeID);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Creates a new table with same schema and options, but only containing the
|
|
133
|
+
* subset of rows in the `[start,end)` interval.
|
|
134
|
+
*
|
|
135
|
+
* @param start
|
|
136
|
+
* @param end
|
|
137
|
+
*/
|
|
121
138
|
slice(start = 0, end) {
|
|
122
|
-
|
|
123
|
-
start = __clamp(start, 0, max);
|
|
124
|
-
end = __clamp(end ?? max, start, max);
|
|
139
|
+
[start, end] = __clampRange(this.length, start, end);
|
|
125
140
|
const copy = this.empty();
|
|
126
141
|
for (let i = start; i < end; i++) copy.addRow(this.getRow(i, true));
|
|
127
142
|
return copy;
|