@uwdata/mosaic-core 0.17.0 → 0.19.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 +47 -0
- package/README.md +0 -1
- package/dist/src/Coordinator.d.ts +159 -0
- package/dist/src/Coordinator.d.ts.map +1 -0
- package/dist/src/Coordinator.js +250 -0
- package/dist/src/Coordinator.js.map +1 -0
- package/dist/src/MosaicClient.d.ts +138 -0
- package/dist/src/MosaicClient.d.ts.map +1 -0
- package/dist/src/MosaicClient.js +214 -0
- package/dist/src/MosaicClient.js.map +1 -0
- package/dist/src/Param.d.ts +56 -0
- package/dist/src/Param.d.ts.map +1 -0
- package/dist/src/Param.js +89 -0
- package/dist/src/Param.js.map +1 -0
- package/dist/src/QueryConsolidator.d.ts +11 -0
- package/dist/src/QueryConsolidator.d.ts.map +1 -0
- package/dist/src/QueryConsolidator.js +249 -0
- package/dist/src/QueryConsolidator.js.map +1 -0
- package/dist/src/QueryManager.d.ts +77 -0
- package/dist/src/QueryManager.d.ts.map +1 -0
- package/dist/src/QueryManager.js +174 -0
- package/dist/src/QueryManager.js.map +1 -0
- package/dist/src/Selection.d.ts +222 -0
- package/dist/src/Selection.d.ts.map +1 -0
- package/dist/src/Selection.js +322 -0
- package/dist/src/Selection.js.map +1 -0
- package/dist/src/SelectionClause.d.ts +222 -0
- package/dist/src/SelectionClause.d.ts.map +1 -0
- package/dist/src/SelectionClause.js +168 -0
- package/dist/src/SelectionClause.js.map +1 -0
- package/dist/src/connectors/Connector.d.ts +26 -0
- package/dist/src/connectors/Connector.d.ts.map +1 -0
- package/dist/src/connectors/Connector.js +2 -0
- package/dist/src/connectors/Connector.js.map +1 -0
- package/dist/src/connectors/rest.d.ts +24 -0
- package/dist/src/connectors/rest.d.ts.map +1 -0
- package/dist/src/connectors/rest.js +37 -0
- package/dist/src/connectors/rest.js.map +1 -0
- package/dist/src/connectors/socket.d.ts +40 -0
- package/dist/src/connectors/socket.d.ts.map +1 -0
- package/dist/src/connectors/socket.js +115 -0
- package/dist/src/connectors/socket.js.map +1 -0
- package/dist/src/connectors/wasm.d.ts +56 -0
- package/dist/src/connectors/wasm.d.ts.map +1 -0
- package/dist/src/connectors/wasm.js +116 -0
- package/dist/src/connectors/wasm.js.map +1 -0
- package/dist/src/index.d.ts +28 -0
- package/dist/src/index.d.ts.map +1 -0
- package/{src → dist/src}/index.js +8 -11
- package/dist/src/index.js.map +1 -0
- package/dist/src/make-client.d.ts +33 -0
- package/dist/src/make-client.d.ts.map +1 -0
- package/dist/src/make-client.js +52 -0
- package/dist/src/make-client.js.map +1 -0
- package/dist/src/preagg/PreAggregator.d.ts +150 -0
- package/dist/src/preagg/PreAggregator.d.ts.map +1 -0
- package/dist/src/preagg/PreAggregator.js +382 -0
- package/dist/src/preagg/PreAggregator.js.map +1 -0
- package/dist/src/preagg/preagg-columns.d.ts +16 -0
- package/dist/src/preagg/preagg-columns.d.ts.map +1 -0
- package/dist/src/preagg/preagg-columns.js +95 -0
- package/dist/src/preagg/preagg-columns.js.map +1 -0
- package/dist/src/preagg/sufficient-statistics.d.ts +14 -0
- package/dist/src/preagg/sufficient-statistics.d.ts.map +1 -0
- package/dist/src/preagg/sufficient-statistics.js +446 -0
- package/dist/src/preagg/sufficient-statistics.js.map +1 -0
- package/dist/src/types.d.ts +77 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/util/AsyncDispatch.d.ts +121 -0
- package/dist/src/util/AsyncDispatch.d.ts.map +1 -0
- package/dist/src/util/AsyncDispatch.js +188 -0
- package/dist/src/util/AsyncDispatch.js.map +1 -0
- package/dist/src/util/cache.d.ts +19 -0
- package/dist/src/util/cache.d.ts.map +1 -0
- package/dist/src/util/cache.js +66 -0
- package/dist/src/util/cache.js.map +1 -0
- package/dist/src/util/decode-ipc.d.ts +12 -0
- package/dist/src/util/decode-ipc.d.ts.map +1 -0
- package/{src → dist/src}/util/decode-ipc.js +5 -6
- package/dist/src/util/decode-ipc.js.map +1 -0
- package/dist/src/util/distinct.d.ts +3 -0
- package/dist/src/util/distinct.d.ts.map +1 -0
- package/dist/src/util/distinct.js +16 -0
- package/dist/src/util/distinct.js.map +1 -0
- package/dist/src/util/field-info.d.ts +26 -0
- package/dist/src/util/field-info.d.ts.map +1 -0
- package/dist/src/util/field-info.js +91 -0
- package/dist/src/util/field-info.js.map +1 -0
- package/dist/src/util/hash.d.ts +2 -0
- package/dist/src/util/hash.d.ts.map +1 -0
- package/dist/src/util/hash.js +26 -0
- package/dist/src/util/hash.js.map +1 -0
- package/dist/src/util/is-activatable.d.ts +8 -0
- package/dist/src/util/is-activatable.d.ts.map +1 -0
- package/dist/src/util/is-activatable.js +10 -0
- package/dist/src/util/is-activatable.js.map +1 -0
- package/dist/src/util/is-arrow-table.d.ts +9 -0
- package/dist/src/util/is-arrow-table.d.ts.map +1 -0
- package/dist/src/util/is-arrow-table.js +11 -0
- package/dist/src/util/is-arrow-table.js.map +1 -0
- package/dist/src/util/js-type.d.ts +9 -0
- package/dist/src/util/js-type.d.ts.map +1 -0
- package/dist/src/util/js-type.js +59 -0
- package/dist/src/util/js-type.js.map +1 -0
- package/dist/src/util/priority-queue.d.ts +35 -0
- package/dist/src/util/priority-queue.d.ts.map +1 -0
- package/dist/src/util/priority-queue.js +81 -0
- package/dist/src/util/priority-queue.js.map +1 -0
- package/dist/src/util/query-result.d.ts +47 -0
- package/dist/src/util/query-result.d.ts.map +1 -0
- package/dist/src/util/query-result.js +83 -0
- package/dist/src/util/query-result.js.map +1 -0
- package/dist/src/util/synchronizer.d.ts +36 -0
- package/dist/src/util/synchronizer.d.ts.map +1 -0
- package/dist/src/util/synchronizer.js +52 -0
- package/dist/src/util/synchronizer.js.map +1 -0
- package/dist/src/util/throttle.d.ts +12 -0
- package/dist/src/util/throttle.d.ts.map +1 -0
- package/dist/src/util/throttle.js +51 -0
- package/dist/src/util/throttle.js.map +1 -0
- package/dist/src/util/to-data-columns.d.ts +22 -0
- package/dist/src/util/to-data-columns.d.ts.map +1 -0
- package/dist/src/util/to-data-columns.js +51 -0
- package/dist/src/util/to-data-columns.js.map +1 -0
- package/dist/src/util/void-logger.d.ts +13 -0
- package/dist/src/util/void-logger.d.ts.map +1 -0
- package/dist/src/util/void-logger.js +13 -0
- package/dist/src/util/void-logger.js.map +1 -0
- package/package.json +17 -11
- package/src/Coordinator.ts +396 -0
- package/src/{MosaicClient.js → MosaicClient.ts} +50 -43
- package/src/{Param.js → Param.ts} +29 -28
- package/src/{QueryConsolidator.js → QueryConsolidator.ts} +85 -62
- package/src/{QueryManager.js → QueryManager.ts} +61 -54
- package/src/Selection.ts +391 -0
- package/src/SelectionClause.ts +357 -0
- package/src/connectors/Connector.ts +6 -6
- package/src/connectors/rest.ts +56 -0
- package/src/connectors/{socket.js → socket.ts} +53 -42
- package/src/connectors/{wasm.js → wasm.ts} +52 -63
- package/src/index.ts +42 -0
- package/src/make-client.ts +93 -0
- package/src/preagg/{PreAggregator.js → PreAggregator.ts} +164 -145
- package/src/preagg/{preagg-columns.js → preagg-columns.ts} +27 -24
- package/src/preagg/{sufficient-statistics.js → sufficient-statistics.ts} +160 -110
- package/src/types.ts +24 -9
- package/src/util/{AsyncDispatch.js → AsyncDispatch.ts} +62 -43
- package/src/util/{cache.js → cache.ts} +25 -15
- package/src/util/decode-ipc.ts +15 -0
- package/src/util/{distinct.js → distinct.ts} +3 -3
- package/src/util/{field-info.js → field-info.ts} +30 -31
- package/src/util/{hash.js → hash.ts} +4 -4
- package/src/util/is-activatable.ts +11 -0
- package/src/util/is-arrow-table.ts +12 -0
- package/src/util/{js-type.js → js-type.ts} +7 -5
- package/src/util/{priority-queue.js → priority-queue.ts} +32 -20
- package/src/util/{query-result.js → query-result.ts} +24 -17
- package/src/util/synchronizer.ts +56 -0
- package/src/util/throttle.ts +59 -0
- package/src/util/to-data-columns.ts +65 -0
- package/src/util/void-logger.ts +23 -0
- package/src/Coordinator.js +0 -313
- package/src/Selection.js +0 -380
- package/src/SelectionClause.js +0 -159
- package/src/connectors/rest.js +0 -38
- package/src/index-types.ts +0 -5
- package/src/make-client.js +0 -101
- package/src/util/is-activatable.js +0 -8
- package/src/util/is-arrow-table.js +0 -10
- package/src/util/selection-types.ts +0 -137
- package/src/util/synchronizer.js +0 -47
- package/src/util/throttle.js +0 -54
- package/src/util/to-data-columns.js +0 -60
- package/src/util/void-logger.js +0 -13
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -3
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { isMosaicClient, MosaicClient } from './MosaicClient.js';
|
|
2
|
+
import { type ExprNode, type ExprValue, type ScaleOptions, type ScaleDomain, and, contains, isBetween, isIn, isNotDistinct, literal, or, prefix, regexp_matches, suffix, listHasAny, listHasAll, lower } from '@uwdata/mosaic-sql';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Selection clause metadata to guide possible query optimizations.
|
|
6
|
+
* Sub-interfaces provide more information about the specifics of a
|
|
7
|
+
* given selection based on the selection type.
|
|
8
|
+
*/
|
|
9
|
+
export interface ClauseMetadata {
|
|
10
|
+
/**
|
|
11
|
+
* The selection type, such as `'point'`, `'interval'`, or `'match'`.
|
|
12
|
+
*/
|
|
13
|
+
type: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Selection clause metadata indicating selection of one or more discrete
|
|
18
|
+
* point values, typically based on equality or is distinctiveness checks.
|
|
19
|
+
*/
|
|
20
|
+
export interface PointMetadata extends ClauseMetadata {
|
|
21
|
+
type: 'point';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Selection clause metadata indicating text search matching.
|
|
26
|
+
*/
|
|
27
|
+
export interface MatchMetadata extends ClauseMetadata {
|
|
28
|
+
type: 'match';
|
|
29
|
+
/** The text search matching method used. */
|
|
30
|
+
method?: 'contains' | 'prefix' | 'suffix' | 'regexp' | (string & {});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** A binning method name. */
|
|
34
|
+
export type BinMethod = 'floor' | 'ceil' | 'round';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Selection clause metadata for one or more selected intervals. This
|
|
38
|
+
* metadata can be used to determine appropriate data-space binning
|
|
39
|
+
* schemes that correspond to pixel-level bins in screen space.
|
|
40
|
+
*/
|
|
41
|
+
export interface IntervalMetadata extends ClauseMetadata {
|
|
42
|
+
type: 'interval';
|
|
43
|
+
/**
|
|
44
|
+
* The interactive pixel size used by the generating component.
|
|
45
|
+
* Values larger than one indicate intervals that "snap-to" values
|
|
46
|
+
* greater than a single pixel. If unspecified, assumed to be `1`.
|
|
47
|
+
*/
|
|
48
|
+
pixelSize?: number;
|
|
49
|
+
/**
|
|
50
|
+
* An array of one or more scale descriptors that describe the
|
|
51
|
+
* mapping from data values to screen pixels.
|
|
52
|
+
*/
|
|
53
|
+
scales?: ScaleOptions[];
|
|
54
|
+
/**
|
|
55
|
+
* A hint for the binning method to use when discretizing the
|
|
56
|
+
* interval domain. If unspecified, the default is `'floor'`.
|
|
57
|
+
*/
|
|
58
|
+
bin?: BinMethod
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type ClauseSource = object & { reset?: () => void; };
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A selection clause representing filtering criteria
|
|
65
|
+
* to apply within a Mosaic Selection.
|
|
66
|
+
*/
|
|
67
|
+
export interface SelectionClause {
|
|
68
|
+
/**
|
|
69
|
+
* A unique identifier (according to object equality) for the source
|
|
70
|
+
* component that generated this clause. In many cases, this is a
|
|
71
|
+
* reference to the originating component itself.
|
|
72
|
+
*/
|
|
73
|
+
source: ClauseSource;
|
|
74
|
+
/**
|
|
75
|
+
* A set of Mosaic clients associated with this clause that should not
|
|
76
|
+
* be updated when this clause is applied in a cross-filtering context.
|
|
77
|
+
*/
|
|
78
|
+
clients?: Set<MosaicClient>;
|
|
79
|
+
/**
|
|
80
|
+
* A selected value associated with this clause. For example, for a 1D
|
|
81
|
+
* interval selection clause the value may be a [lo, hi] array.
|
|
82
|
+
*/
|
|
83
|
+
value: unknown;
|
|
84
|
+
/**
|
|
85
|
+
* A predicate SQL expression suitable for use in a query WHERE clause.
|
|
86
|
+
* The predicate should apply filtering criteria consistent with this
|
|
87
|
+
* clause's *value* property.
|
|
88
|
+
*/
|
|
89
|
+
predicate: ExprNode | null;
|
|
90
|
+
/**
|
|
91
|
+
* Optional clause metadata that varies based on the selection type.
|
|
92
|
+
* The metadata can be used to optimize selection queries, for example
|
|
93
|
+
* by creating materialized views of pre-aggregated data when applicable.
|
|
94
|
+
*/
|
|
95
|
+
meta?: ClauseMetadata;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
interface PointOptions {
|
|
99
|
+
source: ClauseSource;
|
|
100
|
+
clients?: Set<MosaicClient>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Generate a selection clause for a single selected point value.
|
|
105
|
+
* @param field The table column or expression to select.
|
|
106
|
+
* @param value The selected value.
|
|
107
|
+
* @param options Additional clause properties.
|
|
108
|
+
* @param options.source The source component generating this clause.
|
|
109
|
+
* @param options.clients The Mosaic clients associated
|
|
110
|
+
* with this clause. These clients are not filtered by this clause in
|
|
111
|
+
* cross-filtering contexts.
|
|
112
|
+
* @returns The generated selection clause.
|
|
113
|
+
*/
|
|
114
|
+
export function clausePoint(
|
|
115
|
+
field: ExprValue,
|
|
116
|
+
value: unknown, {
|
|
117
|
+
source,
|
|
118
|
+
clients = isMosaicClient(source) ? new Set([source]) : undefined
|
|
119
|
+
}: PointOptions
|
|
120
|
+
): SelectionClause {
|
|
121
|
+
const predicate: ExprNode | null = value !== undefined
|
|
122
|
+
? isIn(field, [literal(value)])
|
|
123
|
+
: null;
|
|
124
|
+
return {
|
|
125
|
+
meta: { type: 'point' },
|
|
126
|
+
source,
|
|
127
|
+
clients,
|
|
128
|
+
value,
|
|
129
|
+
predicate
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Generate a selection clause for multiple selected point values.
|
|
135
|
+
* @param fields The table columns or expressions to select.
|
|
136
|
+
* @param value The selected values, as an array of
|
|
137
|
+
* arrays. Each subarray contains values for each *fields* entry.
|
|
138
|
+
* @param options Additional clause properties.
|
|
139
|
+
* @param options.source The source component generating this clause.
|
|
140
|
+
* @param options.clients The Mosaic clients associated
|
|
141
|
+
* with this clause. These clients are not filtered by this clause in
|
|
142
|
+
* cross-filtering contexts.
|
|
143
|
+
* @returns The generated selection clause.
|
|
144
|
+
*/
|
|
145
|
+
export function clausePoints(
|
|
146
|
+
fields: ExprValue[],
|
|
147
|
+
value: unknown[][] | null | undefined,
|
|
148
|
+
{
|
|
149
|
+
source,
|
|
150
|
+
clients = isMosaicClient(source) ? new Set([source]) : undefined
|
|
151
|
+
}: PointOptions
|
|
152
|
+
): SelectionClause {
|
|
153
|
+
let predicate: ExprNode | null = null;
|
|
154
|
+
if (value?.length) {
|
|
155
|
+
const clauses = value.length && fields.length === 1
|
|
156
|
+
? [isIn(fields[0], value.map(v => literal(v[0])))]
|
|
157
|
+
: value.map(v => and(v.map((_, i) => isNotDistinct(fields[i], literal(_)))));
|
|
158
|
+
predicate = value.length === 0 ? literal(false)
|
|
159
|
+
: clauses.length > 1 ? or(clauses)
|
|
160
|
+
: clauses[0];
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
meta: { type: 'point' },
|
|
164
|
+
source,
|
|
165
|
+
clients,
|
|
166
|
+
value,
|
|
167
|
+
predicate
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Interval selection clause options. */
|
|
172
|
+
interface IntervalOptions {
|
|
173
|
+
source: ClauseSource;
|
|
174
|
+
clients?: Set<MosaicClient>;
|
|
175
|
+
bin?: BinMethod;
|
|
176
|
+
pixelSize?: number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Generate a selection clause for a selected 1D interval.
|
|
181
|
+
* @param field The table column or expression to select.
|
|
182
|
+
* @param value The selected interval as a [lo, hi] array.
|
|
183
|
+
* @param options Additional clause properties.
|
|
184
|
+
* @param options.source The source component generating this clause.
|
|
185
|
+
* @param options.clients The Mosaic clients associated
|
|
186
|
+
* with this clause. These clients are not filtered by this clause in
|
|
187
|
+
* cross-filtering contexts.
|
|
188
|
+
* @param options.scale The scale mapping descriptor.
|
|
189
|
+
* @param options.bin A binning method hint.
|
|
190
|
+
* @param options.pixelSize The interactive pixel size.
|
|
191
|
+
* @returns The generated selection clause.
|
|
192
|
+
*/
|
|
193
|
+
export function clauseInterval(
|
|
194
|
+
field: ExprValue,
|
|
195
|
+
value: ScaleDomain | null | undefined,
|
|
196
|
+
{
|
|
197
|
+
source,
|
|
198
|
+
clients = isMosaicClient(source) ? new Set([source]) : undefined,
|
|
199
|
+
bin,
|
|
200
|
+
scale,
|
|
201
|
+
pixelSize = 1
|
|
202
|
+
}: IntervalOptions & { scale?: ScaleOptions }
|
|
203
|
+
): SelectionClause {
|
|
204
|
+
const predicate = value != null ? isBetween(field, value) : null;
|
|
205
|
+
const meta: IntervalMetadata = {
|
|
206
|
+
type: 'interval',
|
|
207
|
+
scales: scale && [scale],
|
|
208
|
+
bin,
|
|
209
|
+
pixelSize
|
|
210
|
+
};
|
|
211
|
+
return { meta, source, clients, value, predicate };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Generate a selection clause for multiple selected intervals.
|
|
216
|
+
* @param fields The table columns or expressions to select.
|
|
217
|
+
* @param value The selected intervals, as an array of extents.
|
|
218
|
+
* @param options Additional clause properties.
|
|
219
|
+
* @param options.source The source component generating this clause.
|
|
220
|
+
* @param options.clients The Mosaic clients associated
|
|
221
|
+
* with this clause. These clients are not filtered by this clause in
|
|
222
|
+
* cross-filtering contexts.
|
|
223
|
+
* @param options.scales The scale mapping descriptors,
|
|
224
|
+
* in an order matching the given *fields* and *value* extents.
|
|
225
|
+
* @param options.bin A binning method hint.
|
|
226
|
+
* @param options.pixelSize The interactive pixel size.
|
|
227
|
+
* @returns The generated selection clause.
|
|
228
|
+
*/
|
|
229
|
+
export function clauseIntervals(
|
|
230
|
+
fields: ExprValue[],
|
|
231
|
+
value: ScaleDomain[] | null | undefined,
|
|
232
|
+
{
|
|
233
|
+
source,
|
|
234
|
+
clients = isMosaicClient(source) ? new Set([source]) : undefined,
|
|
235
|
+
bin,
|
|
236
|
+
scales = [],
|
|
237
|
+
pixelSize = 1
|
|
238
|
+
}: IntervalOptions & { scales?: ScaleOptions[] }
|
|
239
|
+
): SelectionClause {
|
|
240
|
+
const predicate = value != null
|
|
241
|
+
? and(fields.map((f, i) => isBetween(f, value[i])))
|
|
242
|
+
: null;
|
|
243
|
+
const meta: IntervalMetadata = {
|
|
244
|
+
type: 'interval',
|
|
245
|
+
scales,
|
|
246
|
+
bin,
|
|
247
|
+
pixelSize
|
|
248
|
+
};
|
|
249
|
+
return { meta, source, clients, value, predicate };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const identity = (x: string | ExprNode) => x;
|
|
253
|
+
|
|
254
|
+
const MATCH_METHODS = { contains, prefix, suffix, regexp: regexp_matches };
|
|
255
|
+
|
|
256
|
+
/** Text search matching methods. */
|
|
257
|
+
export type MatchMethod = keyof typeof MATCH_METHODS;
|
|
258
|
+
|
|
259
|
+
/** Text matching selection clause options. */
|
|
260
|
+
export interface MatchOptions {
|
|
261
|
+
source: ClauseSource;
|
|
262
|
+
clients?: Set<MosaicClient>;
|
|
263
|
+
method?: MatchMethod;
|
|
264
|
+
caseSensitive?: boolean;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Generate a selection clause for text search matching over a single column.
|
|
269
|
+
* @param field The table column or expression to match.
|
|
270
|
+
* @param value The selected text search query string.
|
|
271
|
+
* @param options Additional clause properties.
|
|
272
|
+
* @param options.source The source component generating this clause.
|
|
273
|
+
* @param options.clients Mosaic clients associated with this clause.
|
|
274
|
+
* These clients are not filtered by this clause in cross-filtering contexts.
|
|
275
|
+
* @param options.method The text matching method to use, default `'contains'`.
|
|
276
|
+
* @param options.caseSensitive Flag for case sensitive matching, default `false`.
|
|
277
|
+
* @returns The generated selection clause.
|
|
278
|
+
*/
|
|
279
|
+
export function clauseMatch(
|
|
280
|
+
field: string | ExprNode,
|
|
281
|
+
value: string | null | undefined,
|
|
282
|
+
{
|
|
283
|
+
source,
|
|
284
|
+
clients = undefined,
|
|
285
|
+
method = 'contains',
|
|
286
|
+
caseSensitive = false
|
|
287
|
+
}: MatchOptions
|
|
288
|
+
): SelectionClause {
|
|
289
|
+
const fn = MATCH_METHODS[method as keyof typeof MATCH_METHODS];
|
|
290
|
+
const transform = caseSensitive ? identity: lower;
|
|
291
|
+
const predicate = value ? fn(transform(field), transform(literal(value))) : null;
|
|
292
|
+
const meta: MatchMetadata = { type: 'match', method };
|
|
293
|
+
return { meta, source, clients, value, predicate };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Generate a selection clause for text search matching over multiple columns.
|
|
298
|
+
* A match will succeed if any field successfully matches.
|
|
299
|
+
* @param fields The table columns or expressions to match.
|
|
300
|
+
* @param value The selected text search query string.
|
|
301
|
+
* @param options Additional clause properties.
|
|
302
|
+
* @param options.source The source component generating this clause.
|
|
303
|
+
* @param options.clients Mosaic clients associated with this clause.
|
|
304
|
+
* These clients are not filtered by this clause in cross-filtering contexts.
|
|
305
|
+
* @param options.method The text matching method to use, default `'contains'`.
|
|
306
|
+
* @param options.caseSensitive Flag for case sensitive matching, default `false`.
|
|
307
|
+
* @returns The generated selection clause.
|
|
308
|
+
*/
|
|
309
|
+
export function clauseMatchAny(
|
|
310
|
+
fields: (string | ExprNode)[],
|
|
311
|
+
value: string | null,
|
|
312
|
+
{
|
|
313
|
+
source,
|
|
314
|
+
clients = undefined,
|
|
315
|
+
method = 'contains',
|
|
316
|
+
caseSensitive = false
|
|
317
|
+
}: MatchOptions
|
|
318
|
+
): SelectionClause {
|
|
319
|
+
value = value || null;
|
|
320
|
+
const fn = MATCH_METHODS[method];
|
|
321
|
+
const transform = caseSensitive ? identity : lower;
|
|
322
|
+
const query = transform(literal(value));
|
|
323
|
+
const predicate = value
|
|
324
|
+
? or(fields.flatMap(field => value ? fn(transform(field), query) : []))
|
|
325
|
+
: null;
|
|
326
|
+
const meta: MatchMetadata = { type: 'match', method };
|
|
327
|
+
return { meta, source, clients, value, predicate };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Generate a selection clause for a single selected point value in a list.
|
|
332
|
+
* @param field The table column or expression to select, which must be a list.
|
|
333
|
+
* @param value The selected value.
|
|
334
|
+
* @param options Additional clause properties.
|
|
335
|
+
* @param options.source The source component generating this clause.
|
|
336
|
+
* @param options.clients The Mosaic clients associated
|
|
337
|
+
* with this clause. These clients are not filtered by this clause in
|
|
338
|
+
* cross-filtering contexts.
|
|
339
|
+
* @returns The generated selection clause.
|
|
340
|
+
*/
|
|
341
|
+
export function clauseList(
|
|
342
|
+
field: ExprValue,
|
|
343
|
+
value: unknown,
|
|
344
|
+
{
|
|
345
|
+
source,
|
|
346
|
+
clients = isMosaicClient(source) ? new Set([source]) : undefined,
|
|
347
|
+
listMatch = 'any'
|
|
348
|
+
}: {
|
|
349
|
+
source: ClauseSource;
|
|
350
|
+
clients?: Set<MosaicClient>;
|
|
351
|
+
listMatch?: 'any' | 'all';
|
|
352
|
+
}
|
|
353
|
+
): SelectionClause {
|
|
354
|
+
const listFn = listMatch === 'all' ? listHasAll : listHasAny;
|
|
355
|
+
const predicate = value !== undefined ? listFn(field, literal(value)) : null;
|
|
356
|
+
return { source, clients, value, predicate };
|
|
357
|
+
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import type { Table } from '@uwdata/flechette';
|
|
2
2
|
|
|
3
|
-
export interface
|
|
3
|
+
export interface ConnectorQueryRequest {
|
|
4
4
|
/** The query type. */
|
|
5
5
|
type?: string;
|
|
6
6
|
/** A SQL query string. */
|
|
7
7
|
sql: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export interface ArrowQueryRequest extends
|
|
10
|
+
export interface ArrowQueryRequest extends ConnectorQueryRequest {
|
|
11
11
|
/** The query type. */
|
|
12
12
|
type?: 'arrow';
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export interface ExecQueryRequest extends
|
|
15
|
+
export interface ExecQueryRequest extends ConnectorQueryRequest {
|
|
16
16
|
/** The query type. */
|
|
17
17
|
type: 'exec';
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export interface JSONQueryRequest extends
|
|
20
|
+
export interface JSONQueryRequest extends ConnectorQueryRequest {
|
|
21
21
|
/** The query type. */
|
|
22
22
|
type: 'json';
|
|
23
23
|
}
|
|
@@ -26,5 +26,5 @@ export interface Connector {
|
|
|
26
26
|
/** Issue a query and return the result. */
|
|
27
27
|
query(query: ArrowQueryRequest): Promise<Table>;
|
|
28
28
|
query(query: ExecQueryRequest): Promise<void>;
|
|
29
|
-
query(query: JSONQueryRequest): Promise<Record<string,
|
|
30
|
-
}
|
|
29
|
+
query(query: JSONQueryRequest): Promise<Record<string, unknown>[]>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ExtractionOptions, Table } from '@uwdata/flechette';
|
|
2
|
+
import type { ArrowQueryRequest, Connector, ExecQueryRequest, JSONQueryRequest, ConnectorQueryRequest } from './Connector.js';
|
|
3
|
+
import { decodeIPC } from '../util/decode-ipc.js';
|
|
4
|
+
|
|
5
|
+
interface RestOptions {
|
|
6
|
+
uri?: string;
|
|
7
|
+
ipc?: ExtractionOptions;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Connect to a DuckDB server over an HTTP REST interface.
|
|
12
|
+
* @param options Connector options.
|
|
13
|
+
* @param options.uri The URI for the DuckDB REST server.
|
|
14
|
+
* @param options.ipc Arrow IPC extraction options.
|
|
15
|
+
* @returns A connector instance.
|
|
16
|
+
*/
|
|
17
|
+
export function restConnector(options?: RestOptions) {
|
|
18
|
+
return new RestConnector(options);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class RestConnector implements Connector {
|
|
22
|
+
private _uri: string;
|
|
23
|
+
private _ipc?: ExtractionOptions;
|
|
24
|
+
|
|
25
|
+
constructor({
|
|
26
|
+
uri = 'http://localhost:3000/',
|
|
27
|
+
ipc = undefined
|
|
28
|
+
}: RestOptions = {}) {
|
|
29
|
+
this._uri = uri;
|
|
30
|
+
this._ipc = ipc;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async query(query: ArrowQueryRequest): Promise<Table>;
|
|
34
|
+
async query(query: ExecQueryRequest): Promise<void>;
|
|
35
|
+
async query(query: JSONQueryRequest): Promise<Record<string, unknown>[]>;
|
|
36
|
+
async query(query: ConnectorQueryRequest): Promise<unknown> {
|
|
37
|
+
const req = fetch(this._uri, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
mode: 'cors',
|
|
40
|
+
cache: 'no-cache',
|
|
41
|
+
credentials: 'omit',
|
|
42
|
+
headers: { 'Content-Type': 'application/json' },
|
|
43
|
+
body: JSON.stringify(query)
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const res = await req;
|
|
47
|
+
|
|
48
|
+
if (!res.ok) {
|
|
49
|
+
throw new Error(`Query failed with HTTP status ${res.status}: ${await res.text()}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return query.type === 'exec' ? req
|
|
53
|
+
: query.type === 'arrow' ? decodeIPC(await res.arrayBuffer(), this._ipc)
|
|
54
|
+
: res.json();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,38 +1,56 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type { ExtractionOptions, Table } from '@uwdata/flechette';
|
|
2
|
+
import type { ArrowQueryRequest, Connector, ExecQueryRequest, JSONQueryRequest, ConnectorQueryRequest } from './Connector.js';
|
|
3
3
|
import { decodeIPC } from '../util/decode-ipc.js';
|
|
4
4
|
|
|
5
|
+
interface SocketOptions {
|
|
6
|
+
uri?: string;
|
|
7
|
+
ipc?: ExtractionOptions;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface QueueItem<T = unknown> {
|
|
11
|
+
query: ConnectorQueryRequest;
|
|
12
|
+
resolve: (value?: T) => void;
|
|
13
|
+
reject: (reason?: unknown) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
/**
|
|
6
17
|
* Connect to a DuckDB server over a WebSocket interface.
|
|
7
|
-
* @param
|
|
8
|
-
* @param
|
|
9
|
-
* @param
|
|
10
|
-
* @returns
|
|
18
|
+
* @param options Connector options.
|
|
19
|
+
* @param options.uri The URI for the DuckDB REST server.
|
|
20
|
+
* @param options.ipc Arrow IPC extraction options.
|
|
21
|
+
* @returns A connector instance.
|
|
11
22
|
*/
|
|
12
|
-
export function socketConnector(options) {
|
|
23
|
+
export function socketConnector(options?: SocketOptions) {
|
|
13
24
|
return new SocketConnector(options);
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
/**
|
|
17
28
|
* DuckDB socket connector.
|
|
18
|
-
* @implements {Connector}
|
|
19
29
|
*/
|
|
20
|
-
export class SocketConnector {
|
|
30
|
+
export class SocketConnector implements Connector {
|
|
31
|
+
private _uri: string;
|
|
32
|
+
private _queue: QueueItem[];
|
|
33
|
+
private _connected: boolean;
|
|
34
|
+
private _request: QueueItem | null;
|
|
35
|
+
private _ws: WebSocket | null;
|
|
36
|
+
private _events: Record<string, (event?: unknown) => void>;
|
|
37
|
+
|
|
21
38
|
/**
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
39
|
+
* @param options Connector options.
|
|
40
|
+
* @param options.uri The URI for the DuckDB REST server.
|
|
41
|
+
* @param options.ipc Arrow IPC extraction options.
|
|
25
42
|
*/
|
|
26
43
|
constructor({
|
|
27
44
|
uri = 'ws://localhost:3000/',
|
|
28
45
|
ipc = undefined,
|
|
29
|
-
} = {}) {
|
|
46
|
+
}: SocketOptions = {}) {
|
|
30
47
|
this._uri = uri;
|
|
31
48
|
this._queue = [];
|
|
32
49
|
this._connected = false;
|
|
33
50
|
this._request = null;
|
|
34
51
|
this._ws = null;
|
|
35
52
|
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
36
54
|
const c = this;
|
|
37
55
|
this._events = {
|
|
38
56
|
open() {
|
|
@@ -45,11 +63,11 @@ export class SocketConnector {
|
|
|
45
63
|
c._request = null;
|
|
46
64
|
c._ws = null;
|
|
47
65
|
while (c._queue.length) {
|
|
48
|
-
c._queue.shift()
|
|
66
|
+
c._queue.shift()!.reject('Socket closed');
|
|
49
67
|
}
|
|
50
68
|
},
|
|
51
69
|
|
|
52
|
-
error(event) {
|
|
70
|
+
error(event: unknown) {
|
|
53
71
|
if (c._request) {
|
|
54
72
|
const { reject } = c._request;
|
|
55
73
|
c._request = null;
|
|
@@ -60,7 +78,8 @@ export class SocketConnector {
|
|
|
60
78
|
}
|
|
61
79
|
},
|
|
62
80
|
|
|
63
|
-
message(
|
|
81
|
+
message(msg: unknown) {
|
|
82
|
+
const { data } = msg as { data: unknown };
|
|
64
83
|
if (c._request) {
|
|
65
84
|
const { query, resolve, reject } = c._request;
|
|
66
85
|
|
|
@@ -71,11 +90,12 @@ export class SocketConnector {
|
|
|
71
90
|
// process result
|
|
72
91
|
if (typeof data === 'string') {
|
|
73
92
|
const json = JSON.parse(data);
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
74
94
|
json.error ? reject(json.error) : resolve(json);
|
|
75
95
|
} else if (query.type === 'exec') {
|
|
76
96
|
resolve();
|
|
77
97
|
} else if (query.type === 'arrow') {
|
|
78
|
-
resolve(decodeIPC(data, ipc));
|
|
98
|
+
resolve(decodeIPC(data as Uint8Array, ipc));
|
|
79
99
|
} else {
|
|
80
100
|
throw new Error(`Unexpected socket data: ${data}`);
|
|
81
101
|
}
|
|
@@ -83,14 +103,14 @@ export class SocketConnector {
|
|
|
83
103
|
console.log('WebSocket message: ', data);
|
|
84
104
|
}
|
|
85
105
|
}
|
|
86
|
-
}
|
|
106
|
+
};
|
|
87
107
|
}
|
|
88
108
|
|
|
89
|
-
get connected() {
|
|
109
|
+
get connected(): boolean {
|
|
90
110
|
return this._connected;
|
|
91
111
|
}
|
|
92
112
|
|
|
93
|
-
init() {
|
|
113
|
+
init(): void {
|
|
94
114
|
this._ws = new WebSocket(this._uri);
|
|
95
115
|
this._ws.binaryType = 'arraybuffer';
|
|
96
116
|
for (const type in this._events) {
|
|
@@ -98,38 +118,29 @@ export class SocketConnector {
|
|
|
98
118
|
}
|
|
99
119
|
}
|
|
100
120
|
|
|
101
|
-
enqueue(
|
|
121
|
+
enqueue(
|
|
122
|
+
query: ConnectorQueryRequest,
|
|
123
|
+
resolve: (value?: unknown) => void,
|
|
124
|
+
reject: (reason?: unknown) => void
|
|
125
|
+
): void {
|
|
102
126
|
if (this._ws == null) this.init();
|
|
103
127
|
this._queue.push({ query, resolve, reject });
|
|
104
128
|
if (this._connected && !this._request) this.next();
|
|
105
129
|
}
|
|
106
130
|
|
|
107
|
-
next() {
|
|
131
|
+
next(): void {
|
|
108
132
|
if (this._queue.length) {
|
|
109
|
-
this._request = this._queue.shift()
|
|
110
|
-
this._ws
|
|
133
|
+
this._request = this._queue.shift()!;
|
|
134
|
+
this._ws!.send(JSON.stringify(this._request.query));
|
|
111
135
|
}
|
|
112
136
|
}
|
|
113
137
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
*
|
|
119
|
-
* @overload
|
|
120
|
-
* @param {ExecQueryRequest} query
|
|
121
|
-
* @returns {Promise<void>}
|
|
122
|
-
*
|
|
123
|
-
* @overload
|
|
124
|
-
* @param {JSONQueryRequest} query
|
|
125
|
-
* @returns {Promise<Record<string, any>[]>}
|
|
126
|
-
*
|
|
127
|
-
* @param {ArrowQueryRequest | ExecQueryRequest | JSONQueryRequest} query
|
|
128
|
-
* @returns {Promise<Table | void | Record<string, any>[]>}}
|
|
129
|
-
*/
|
|
130
|
-
query(query) {
|
|
138
|
+
query(query: ArrowQueryRequest): Promise<Table>;
|
|
139
|
+
query(query: ExecQueryRequest): Promise<void>;
|
|
140
|
+
query(query: JSONQueryRequest): Promise<Record<string, unknown>[]>;
|
|
141
|
+
query(query: ConnectorQueryRequest): Promise<unknown> {
|
|
131
142
|
return new Promise(
|
|
132
143
|
(resolve, reject) => this.enqueue(query, resolve, reject)
|
|
133
144
|
);
|
|
134
145
|
}
|
|
135
|
-
}
|
|
146
|
+
}
|