@uwdata/mosaic-core 0.16.2 → 0.18.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 +1 -1
- package/README.md +0 -1
- package/dist/src/Coordinator.d.ts +147 -0
- package/dist/src/Coordinator.d.ts.map +1 -0
- package/dist/src/Coordinator.js +269 -0
- package/dist/src/Coordinator.js.map +1 -0
- package/dist/{types → src}/MosaicClient.d.ts +37 -42
- package/dist/src/MosaicClient.d.ts.map +1 -0
- package/dist/src/MosaicClient.js +213 -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 +319 -0
- package/dist/src/Selection.js.map +1 -0
- package/dist/src/SelectionClause.d.ts +192 -0
- package/dist/src/SelectionClause.d.ts.map +1 -0
- package/dist/src/SelectionClause.js +126 -0
- package/dist/src/SelectionClause.js.map +1 -0
- package/dist/{types → src}/connectors/Connector.d.ts +6 -5
- 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 +53 -0
- package/dist/src/connectors/wasm.d.ts.map +1 -0
- package/dist/src/connectors/wasm.js +113 -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/dist/src/index.js +25 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/make-client.d.ts +35 -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/{types → src}/preagg/PreAggregator.d.ts +64 -94
- 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/{types → src}/preagg/preagg-columns.d.ts +10 -8
- 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/{types → src}/types.d.ts +23 -9
- 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/{types → src}/util/AsyncDispatch.d.ts +53 -32
- 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/{types → src}/util/priority-queue.d.ts +12 -14
- 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 +15 -13
- package/src/Coordinator.ts +367 -0
- package/src/{MosaicClient.js → MosaicClient.ts} +49 -43
- package/src/{Param.js → Param.ts} +29 -28
- package/src/{QueryConsolidator.js → QueryConsolidator.ts} +81 -58
- package/src/{QueryManager.js → QueryManager.ts} +61 -54
- package/src/Selection.ts +388 -0
- package/src/SelectionClause.ts +275 -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} +46 -62
- package/src/{index.js → index.ts} +13 -1
- 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} +161 -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} +31 -32
- 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/dist/types/Coordinator.d.ts +0 -164
- package/dist/types/Param.d.ts +0 -47
- package/dist/types/QueryConsolidator.d.ts +0 -9
- package/dist/types/QueryManager.d.ts +0 -91
- package/dist/types/Selection.d.ts +0 -235
- package/dist/types/SelectionClause.d.ts +0 -105
- package/dist/types/connectors/rest.d.ts +0 -13
- package/dist/types/connectors/socket.d.ts +0 -100
- package/dist/types/connectors/wasm.d.ts +0 -135
- package/dist/types/index-types.d.ts +0 -4
- package/dist/types/index.d.ts +0 -19
- package/dist/types/make-client.d.ts +0 -78
- package/dist/types/preagg/sufficient-statistics.d.ts +0 -13
- package/dist/types/util/cache.d.ts +0 -17
- package/dist/types/util/decode-ipc.d.ts +0 -12
- package/dist/types/util/distinct.d.ts +0 -2
- package/dist/types/util/field-info.d.ts +0 -23
- package/dist/types/util/hash.d.ts +0 -1
- package/dist/types/util/is-activatable.d.ts +0 -6
- package/dist/types/util/is-arrow-table.d.ts +0 -8
- package/dist/types/util/js-type.d.ts +0 -7
- package/dist/types/util/query-result.d.ts +0 -44
- package/dist/types/util/selection-types.d.ts +0 -114
- package/dist/types/util/synchronizer.d.ts +0 -29
- package/dist/types/util/throttle.d.ts +0 -13
- package/dist/types/util/to-data-columns.d.ts +0 -29
- package/dist/types/util/void-logger.d.ts +0 -10
- package/jsconfig.json +0 -11
- package/src/Coordinator.js +0 -337
- 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 -4
- 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 -11
- package/vitest.config.ts +0 -3
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { FilterExpr, type Query } from '@uwdata/mosaic-sql';
|
|
2
|
+
import { type Coordinator } from './Coordinator.js';
|
|
3
|
+
import { type Selection } from './Selection.js';
|
|
4
4
|
import { throttle } from './util/throttle.js';
|
|
5
5
|
|
|
6
|
+
export type ClientQuery = Query | string | null;
|
|
7
|
+
|
|
8
|
+
export function isMosaicClient(x: unknown): x is MosaicClient {
|
|
9
|
+
return x instanceof MosaicClient;
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
/**
|
|
7
13
|
* A Mosaic client is a data consumer that indicates its data needs to a
|
|
8
14
|
* Mosaic coordinator via the query method. The coordinator is responsible
|
|
@@ -20,53 +26,55 @@ import { throttle } from './util/throttle.js';
|
|
|
20
26
|
* associated interface elements are offscreen or disabled.
|
|
21
27
|
*/
|
|
22
28
|
export class MosaicClient {
|
|
29
|
+
_filterBy: Selection | undefined;
|
|
30
|
+
_requestUpdate: () => void;
|
|
31
|
+
_coordinator: Coordinator | null;
|
|
32
|
+
_pending: Promise<unknown>;
|
|
33
|
+
_enabled: boolean;
|
|
34
|
+
_initialized: boolean;
|
|
35
|
+
_request: Query | boolean | null;
|
|
36
|
+
|
|
23
37
|
/**
|
|
24
38
|
* Create a new client instance.
|
|
25
|
-
* @param
|
|
39
|
+
* @param filterSelection An optional selection to
|
|
26
40
|
* interactively filter this client's data. If provided, a coordinator
|
|
27
41
|
* will re-query and update the client when the selection updates.
|
|
28
42
|
*/
|
|
29
|
-
constructor(filterSelection) {
|
|
30
|
-
/** @type {Selection | undefined} */
|
|
43
|
+
constructor(filterSelection?: Selection) {
|
|
31
44
|
this._filterBy = filterSelection;
|
|
32
45
|
this._requestUpdate = throttle(() => this.requestQuery(), true);
|
|
33
|
-
/** @type {Coordinator | null} */
|
|
34
46
|
this._coordinator = null;
|
|
35
|
-
/** @type {Promise<any>} */
|
|
36
47
|
this._pending = Promise.resolve();
|
|
37
|
-
/** @type {boolean} */
|
|
38
48
|
this._enabled = true;
|
|
39
|
-
/** @type {boolean} */
|
|
40
49
|
this._initialized = false;
|
|
41
|
-
/** @type {Query | boolean | null} */
|
|
42
50
|
this._request = null;
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
/**
|
|
46
|
-
* @returns
|
|
54
|
+
* @returns this client's connected coordinator.
|
|
47
55
|
*/
|
|
48
|
-
get coordinator() {
|
|
56
|
+
get coordinator(): Coordinator | null {
|
|
49
57
|
return this._coordinator;
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
/**
|
|
53
61
|
* Set this client's connected coordinator.
|
|
54
62
|
*/
|
|
55
|
-
set coordinator(coordinator) {
|
|
63
|
+
set coordinator(coordinator: Coordinator | null) {
|
|
56
64
|
this._coordinator = coordinator;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
/**
|
|
60
68
|
* Return this client's enabled state.
|
|
61
69
|
*/
|
|
62
|
-
get enabled() {
|
|
70
|
+
get enabled(): boolean {
|
|
63
71
|
return this._enabled;
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
/**
|
|
67
75
|
* Set this client's enabled state;
|
|
68
76
|
*/
|
|
69
|
-
set enabled(state) {
|
|
77
|
+
set enabled(state: boolean) {
|
|
70
78
|
state = !!state; // ensure boolean
|
|
71
79
|
if (this._enabled !== state) {
|
|
72
80
|
this._enabled = state;
|
|
@@ -86,14 +94,14 @@ export class MosaicClient {
|
|
|
86
94
|
/**
|
|
87
95
|
* Return a Promise that resolves once the client has updated.
|
|
88
96
|
*/
|
|
89
|
-
get pending() {
|
|
97
|
+
get pending(): Promise<unknown> {
|
|
90
98
|
return this._pending;
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
/**
|
|
94
|
-
* @returns
|
|
102
|
+
* @returns this client's filter selection.
|
|
95
103
|
*/
|
|
96
|
-
get filterBy() {
|
|
104
|
+
get filterBy(): Selection | undefined {
|
|
97
105
|
return this._filterBy;
|
|
98
106
|
}
|
|
99
107
|
|
|
@@ -103,7 +111,7 @@ export class MosaicClient {
|
|
|
103
111
|
* to the filterBy selection do not change the groupby domain of the client
|
|
104
112
|
* query.
|
|
105
113
|
*/
|
|
106
|
-
get filterStable() {
|
|
114
|
+
get filterStable(): boolean {
|
|
107
115
|
return true;
|
|
108
116
|
}
|
|
109
117
|
|
|
@@ -112,41 +120,41 @@ export class MosaicClient {
|
|
|
112
120
|
* should override this method as needed, potentially issuing one or more
|
|
113
121
|
* queries to gather data or metadata needed prior to `query` calls.
|
|
114
122
|
*/
|
|
115
|
-
async prepare() {
|
|
123
|
+
async prepare(): Promise<void> {
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
/**
|
|
119
127
|
* Return a query specifying the data needed by this client.
|
|
120
|
-
* @param
|
|
121
|
-
* @returns
|
|
128
|
+
* @param filter The filtering criteria to apply in the query.
|
|
129
|
+
* @returns The client query
|
|
122
130
|
*/
|
|
123
|
-
query(filter) { // eslint-disable-line no-unused-vars
|
|
131
|
+
query(filter?: FilterExpr | null): ClientQuery { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
124
132
|
return null;
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
/**
|
|
128
136
|
* Called by the coordinator to inform the client that a query is pending.
|
|
129
|
-
* @returns
|
|
137
|
+
* @returns this
|
|
130
138
|
*/
|
|
131
|
-
queryPending() {
|
|
139
|
+
queryPending(): this {
|
|
132
140
|
return this;
|
|
133
141
|
}
|
|
134
142
|
|
|
135
143
|
/**
|
|
136
144
|
* Called by the coordinator to return a query result.
|
|
137
|
-
* @param
|
|
138
|
-
* @returns
|
|
145
|
+
* @param data The query result.
|
|
146
|
+
* @returns this
|
|
139
147
|
*/
|
|
140
|
-
queryResult(data) { // eslint-disable-line no-unused-vars
|
|
148
|
+
queryResult(data: unknown): this { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
141
149
|
return this;
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
/**
|
|
145
153
|
* Called by the coordinator to report a query execution error.
|
|
146
|
-
* @param
|
|
147
|
-
* @returns
|
|
154
|
+
* @param error
|
|
155
|
+
* @returns this
|
|
148
156
|
*/
|
|
149
|
-
queryError(error) { // eslint-disable-line no-unused-vars
|
|
157
|
+
queryError(error: Error): this { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
150
158
|
// do nothing, the coordinator logs the error
|
|
151
159
|
return this;
|
|
152
160
|
}
|
|
@@ -158,15 +166,14 @@ export class MosaicClient {
|
|
|
158
166
|
* no effect if the client is not connected to a coordinator. If the client
|
|
159
167
|
* is connected by currently disabled, the request will be serviced if the
|
|
160
168
|
* client is later enabled.
|
|
161
|
-
* @param
|
|
162
|
-
* will be
|
|
169
|
+
* @param query The query to request. If unspecified, the query
|
|
170
|
+
* will be determined by the client's `query` method and the current
|
|
163
171
|
* `filterBy` selection state.
|
|
164
|
-
* @returns {Promise}
|
|
165
172
|
*/
|
|
166
|
-
requestQuery(query) {
|
|
173
|
+
requestQuery(query?: Query): Promise<unknown> | null {
|
|
167
174
|
if (this._enabled) {
|
|
168
175
|
const q = query || this.query(this.filterBy?.predicate(this));
|
|
169
|
-
return this._coordinator
|
|
176
|
+
return this._coordinator!.requestQuery(this, q);
|
|
170
177
|
} else {
|
|
171
178
|
this._request = query ?? true;
|
|
172
179
|
return null;
|
|
@@ -181,7 +188,7 @@ export class MosaicClient {
|
|
|
181
188
|
* connected to a coordinator. If the client is connected but currently
|
|
182
189
|
* disabled, the request will be serviced if the client is later enabled.
|
|
183
190
|
*/
|
|
184
|
-
requestUpdate() {
|
|
191
|
+
requestUpdate(): void {
|
|
185
192
|
if (this._enabled) {
|
|
186
193
|
this._requestUpdate();
|
|
187
194
|
} else {
|
|
@@ -193,7 +200,7 @@ export class MosaicClient {
|
|
|
193
200
|
* Reset this client, calling the prepare method and query requests. This
|
|
194
201
|
* method has no effect if the client is not registered with a coordinator.
|
|
195
202
|
*/
|
|
196
|
-
initialize() {
|
|
203
|
+
initialize(): void {
|
|
197
204
|
if (!this._enabled) {
|
|
198
205
|
// clear flag so we initialize when enabled again
|
|
199
206
|
this._initialized = false;
|
|
@@ -212,16 +219,15 @@ export class MosaicClient {
|
|
|
212
219
|
* If overriding this method in a client subclass, be sure to also
|
|
213
220
|
* disconnect from the coordinator.
|
|
214
221
|
*/
|
|
215
|
-
destroy() {
|
|
222
|
+
destroy(): void {
|
|
216
223
|
this.coordinator?.disconnect(this);
|
|
217
224
|
}
|
|
218
225
|
|
|
219
226
|
/**
|
|
220
227
|
* Requests a client update, for example to (re-)render an interface
|
|
221
228
|
* component.
|
|
222
|
-
* @returns {this | Promise<any>}
|
|
223
229
|
*/
|
|
224
|
-
update() {
|
|
230
|
+
update(): this | Promise<unknown> {
|
|
225
231
|
return this;
|
|
226
232
|
}
|
|
227
|
-
}
|
|
233
|
+
}
|
|
@@ -3,10 +3,10 @@ import { distinct } from './util/distinct.js';
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Test if a value is a Param instance.
|
|
6
|
-
* @param
|
|
7
|
-
* @returns
|
|
6
|
+
* @param x The value to test.
|
|
7
|
+
* @returns True if the input is a Param, false otherwise.
|
|
8
8
|
*/
|
|
9
|
-
export function isParam(x) {
|
|
9
|
+
export function isParam<T>(x: unknown): x is Param<T> {
|
|
10
10
|
return x instanceof Param;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -14,61 +14,62 @@ export function isParam(x) {
|
|
|
14
14
|
* Represents a dynamic parameter that dispatches updates
|
|
15
15
|
* upon parameter changes.
|
|
16
16
|
*/
|
|
17
|
-
export class Param extends AsyncDispatch {
|
|
17
|
+
export class Param<T> extends AsyncDispatch<T> {
|
|
18
|
+
protected _value?: T;
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Create a new Param instance.
|
|
21
|
-
* @param
|
|
22
|
+
* @param value The initial value of the Param.
|
|
22
23
|
*/
|
|
23
|
-
constructor(value) {
|
|
24
|
+
constructor(value?: T) {
|
|
24
25
|
super();
|
|
25
26
|
this._value = value;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Create a new Param instance with the given initial value.
|
|
30
|
-
* @param
|
|
31
|
-
* @returns
|
|
31
|
+
* @param value The initial value of the Param.
|
|
32
|
+
* @returns The new Param instance.
|
|
32
33
|
*/
|
|
33
|
-
static value(value) {
|
|
34
|
+
static value<T>(value: T): Param<T> {
|
|
34
35
|
return new Param(value);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* Create a new Param instance over an array of initial values,
|
|
39
40
|
* which may contain nested Params.
|
|
40
|
-
* @param
|
|
41
|
-
* @returns
|
|
41
|
+
* @param values The initial values of the Param.
|
|
42
|
+
* @returns The new Param instance.
|
|
42
43
|
*/
|
|
43
|
-
static array(values) {
|
|
44
|
+
static array<T>(values: (T|Param<T>)[]): Param<T[]> {
|
|
44
45
|
if (values.some(v => isParam(v))) {
|
|
45
|
-
const p = new Param();
|
|
46
|
-
const update = () => {
|
|
47
|
-
p.update(values.map(v => isParam(v) ? v.value : v));
|
|
46
|
+
const p = new Param<T[]>();
|
|
47
|
+
const update = (): void => {
|
|
48
|
+
p.update(values.map(v => isParam<T>(v) ? v.value! : v));
|
|
48
49
|
};
|
|
49
50
|
update();
|
|
50
51
|
values.forEach(v => isParam(v) ? v.addEventListener('value', update) : 0);
|
|
51
52
|
return p;
|
|
52
53
|
}
|
|
53
|
-
return new Param(values)
|
|
54
|
+
return new Param(values) as Param<T[]>;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* The current value of the Param.
|
|
58
59
|
*/
|
|
59
|
-
get value() {
|
|
60
|
+
get value(): T | undefined {
|
|
60
61
|
return this._value;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
/**
|
|
64
65
|
* Update the Param value
|
|
65
|
-
* @param
|
|
66
|
-
* @param
|
|
67
|
-
* @param
|
|
66
|
+
* @param value The new value of the Param.
|
|
67
|
+
* @param options The update options.
|
|
68
|
+
* @param options.force A boolean flag indicating if the Param
|
|
68
69
|
* should emit a 'value' event even if the internal value is unchanged.
|
|
69
|
-
* @returns
|
|
70
|
+
* @returns This Param instance.
|
|
70
71
|
*/
|
|
71
|
-
update(value, { force } = {}) {
|
|
72
|
+
update(value: T, { force }: { force?: boolean } = {}): this {
|
|
72
73
|
const shouldEmit = distinct(this._value, value) || force;
|
|
73
74
|
if (shouldEmit) {
|
|
74
75
|
this.emit('value', value);
|
|
@@ -81,14 +82,14 @@ export class Param extends AsyncDispatch {
|
|
|
81
82
|
/**
|
|
82
83
|
* Upon value-typed updates, sets the current value to the input value
|
|
83
84
|
* immediately prior to the event value being emitted to listeners.
|
|
84
|
-
* @param
|
|
85
|
-
* @param
|
|
86
|
-
* @returns
|
|
85
|
+
* @param type The event type.
|
|
86
|
+
* @param value The input event value.
|
|
87
|
+
* @returns The input event value.
|
|
87
88
|
*/
|
|
88
|
-
willEmit(type, value) {
|
|
89
|
+
willEmit(type: string, value: T): T {
|
|
89
90
|
if (type === 'value') {
|
|
90
|
-
this._value = value;
|
|
91
|
+
this._value = value as T;
|
|
91
92
|
}
|
|
92
93
|
return value;
|
|
93
94
|
}
|
|
94
|
-
}
|
|
95
|
+
}
|
|
@@ -1,26 +1,45 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ExprNode, Query, SelectQuery } from '@uwdata/mosaic-sql';
|
|
2
|
+
import type { Table } from '@uwdata/flechette';
|
|
2
3
|
import { isAggregateExpression, isColumnRef, isDescribeQuery, isSelectQuery } from '@uwdata/mosaic-sql';
|
|
3
4
|
import { QueryResult } from './util/query-result.js';
|
|
5
|
+
import type { Cache, QueryEntry, QueryType } from './types.js';
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
interface GroupEntry {
|
|
8
|
+
entry: QueryEntry;
|
|
9
|
+
priority: number;
|
|
10
|
+
index: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface QueryGroup extends Array<GroupEntry> {
|
|
14
|
+
query?: Query;
|
|
15
|
+
result?: QueryResult;
|
|
16
|
+
maps?: Array<Array<[string, string]>>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function wait(callback: () => void): unknown {
|
|
20
|
+
if (typeof requestAnimationFrame !== 'undefined') {
|
|
21
|
+
return requestAnimationFrame(callback);
|
|
22
|
+
} else if (typeof setImmediate !== 'undefined') {
|
|
23
|
+
return setImmediate(callback);
|
|
24
|
+
} else {
|
|
25
|
+
return setTimeout(callback);
|
|
26
|
+
}
|
|
11
27
|
}
|
|
12
28
|
|
|
13
29
|
/**
|
|
14
30
|
* Create a consolidator to combine structurally compatible queries.
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
31
|
+
* @param enqueue Query manager enqueue method
|
|
32
|
+
* @param cache Client-side query cache (sql -> data)
|
|
17
33
|
* @returns A consolidator object
|
|
18
34
|
*/
|
|
19
|
-
export function consolidator(
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
export function consolidator(
|
|
36
|
+
enqueue: (entry: QueryEntry, priority?: number) => void,
|
|
37
|
+
cache: Cache
|
|
38
|
+
) {
|
|
39
|
+
let pending: GroupEntry[] = [];
|
|
40
|
+
let id: unknown = 0;
|
|
22
41
|
|
|
23
|
-
function run() {
|
|
42
|
+
function run(): void {
|
|
24
43
|
// group queries into bundles that can be consolidated
|
|
25
44
|
const groups = entryGroups(pending, cache);
|
|
26
45
|
pending = [];
|
|
@@ -34,37 +53,38 @@ export function consolidator(enqueue, cache) {
|
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
return {
|
|
37
|
-
add(entry, priority) {
|
|
56
|
+
add(entry: QueryEntry, priority: number): void {
|
|
38
57
|
if (entry.request.type === 'arrow') {
|
|
39
58
|
// wait one frame, gather an ordered list of queries
|
|
40
59
|
// only Apache Arrow is supported, so we can project efficiently
|
|
41
|
-
id
|
|
60
|
+
id ||= wait(() => run());
|
|
42
61
|
pending.push({ entry, priority, index: pending.length });
|
|
43
62
|
} else {
|
|
44
63
|
enqueue(entry, priority);
|
|
45
64
|
}
|
|
46
65
|
}
|
|
47
|
-
}
|
|
66
|
+
};
|
|
48
67
|
}
|
|
49
68
|
|
|
50
69
|
/**
|
|
51
70
|
* Segment query requests into consolidation-compatible groups.
|
|
52
|
-
* @param
|
|
71
|
+
* @param entries Query request entries ({ request, result } objects)
|
|
72
|
+
* @param cache Client-side query cache
|
|
53
73
|
* @returns An array of grouped entry arrays
|
|
54
74
|
*/
|
|
55
|
-
function entryGroups(entries, cache) {
|
|
56
|
-
const groups = [];
|
|
57
|
-
const groupMap = new Map;
|
|
75
|
+
function entryGroups(entries: GroupEntry[], cache: Cache): QueryGroup[] {
|
|
76
|
+
const groups: QueryGroup[] = [];
|
|
77
|
+
const groupMap = new Map<string, QueryGroup>();
|
|
58
78
|
|
|
59
79
|
for (const query of entries) {
|
|
60
80
|
const { entry: { request } } = query;
|
|
61
81
|
const key = consolidationKey(request.query, cache);
|
|
62
82
|
if (!groupMap.has(key)) {
|
|
63
|
-
const list = [];
|
|
83
|
+
const list: QueryGroup = [];
|
|
64
84
|
groups.push(list);
|
|
65
85
|
groupMap.set(key, list);
|
|
66
86
|
}
|
|
67
|
-
groupMap.get(key)
|
|
87
|
+
groupMap.get(key)!.push(query);
|
|
68
88
|
}
|
|
69
89
|
|
|
70
90
|
return groups;
|
|
@@ -75,11 +95,11 @@ function entryGroups(entries, cache) {
|
|
|
75
95
|
* Queries with matching keys are conosolidation-compatible.
|
|
76
96
|
* If a query is found in the cache, it is exempted from consolidation,
|
|
77
97
|
* which is indicated by returning the precise query SQL as the key.
|
|
78
|
-
* @param
|
|
79
|
-
* @param
|
|
98
|
+
* @param query The input query.
|
|
99
|
+
* @param cache The query cache (sql -> data).
|
|
80
100
|
* @returns a key string
|
|
81
101
|
*/
|
|
82
|
-
function consolidationKey(query, cache) {
|
|
102
|
+
function consolidationKey(query: QueryType, cache: Cache): string {
|
|
83
103
|
const sql = `${query}`;
|
|
84
104
|
if (isSelectQuery(query) && !cache.get(sql)) {
|
|
85
105
|
if (
|
|
@@ -99,11 +119,11 @@ function consolidationKey(query, cache) {
|
|
|
99
119
|
// we resolve these against the true grouping expressions
|
|
100
120
|
const groupby = query._groupby;
|
|
101
121
|
if (groupby.length) {
|
|
102
|
-
const map = {}; // expression map (alias -> expr)
|
|
122
|
+
const map: Record<string, ExprNode> = {}; // expression map (alias -> expr)
|
|
103
123
|
query._select.forEach(({ alias, expr }) => map[alias] = expr);
|
|
104
124
|
q.setGroupby(groupby.map(e => (isColumnRef(e) && map[e.column]) || e));
|
|
105
125
|
}
|
|
106
|
-
else if (query._select.some(e => isAggregateExpression(e.expr))) {
|
|
126
|
+
else if (query._select.some(e => isAggregateExpression(e.expr!))) {
|
|
107
127
|
// if query is an ungrouped aggregate, add an explicit groupby to
|
|
108
128
|
// prevent improper consolidation with non-aggregate queries
|
|
109
129
|
q.setGroupby('ALL');
|
|
@@ -119,10 +139,13 @@ function consolidationKey(query, cache) {
|
|
|
119
139
|
|
|
120
140
|
/**
|
|
121
141
|
* Issue queries, consolidating where possible.
|
|
122
|
-
* @param
|
|
123
|
-
* @param
|
|
142
|
+
* @param group Array of bundled query entries
|
|
143
|
+
* @param enqueue Add entry to query queue
|
|
124
144
|
*/
|
|
125
|
-
function consolidate(
|
|
145
|
+
function consolidate(
|
|
146
|
+
group: QueryGroup,
|
|
147
|
+
enqueue: (entry: QueryEntry, priority?: number) => void
|
|
148
|
+
): void {
|
|
126
149
|
if (shouldConsolidate(group)) {
|
|
127
150
|
// issue a single consolidated query
|
|
128
151
|
enqueue({
|
|
@@ -143,11 +166,11 @@ function consolidate(group, enqueue) {
|
|
|
143
166
|
|
|
144
167
|
/**
|
|
145
168
|
* Check if a group contains multiple distinct queries.
|
|
146
|
-
* @param
|
|
169
|
+
* @param group Array of bundled query entries
|
|
147
170
|
* @returns false if group contains a single (possibly repeated) query,
|
|
148
171
|
* otherwise true
|
|
149
172
|
*/
|
|
150
|
-
function shouldConsolidate(group) {
|
|
173
|
+
function shouldConsolidate(group: QueryGroup): boolean {
|
|
151
174
|
if (group.length > 1) {
|
|
152
175
|
const sql = `${group[0].entry.request.query}`;
|
|
153
176
|
for (let i = 1; i < group.length; ++i) {
|
|
@@ -161,37 +184,39 @@ function shouldConsolidate(group) {
|
|
|
161
184
|
|
|
162
185
|
/**
|
|
163
186
|
* Create a consolidated query for a group.
|
|
164
|
-
* @param
|
|
187
|
+
* @param group Array of bundled query entries
|
|
165
188
|
* @returns A consolidated Query instance
|
|
166
189
|
*/
|
|
167
|
-
function consolidatedQuery(group) {
|
|
168
|
-
const maps = group.maps = [];
|
|
169
|
-
const fields = new Map;
|
|
190
|
+
function consolidatedQuery(group: QueryGroup): Query {
|
|
191
|
+
const maps: Array<Array<[string, string]>> = group.maps = [];
|
|
192
|
+
const fields = new Map<string, [string, ExprNode]>();
|
|
170
193
|
|
|
171
194
|
// gather select fields
|
|
172
195
|
for (const item of group) {
|
|
173
|
-
const
|
|
174
|
-
const fieldMap = [];
|
|
196
|
+
const query = item.entry.request.query as SelectQuery;
|
|
197
|
+
const fieldMap: Array<[string, string]> = [];
|
|
175
198
|
maps.push(fieldMap);
|
|
176
199
|
for (const { alias, expr } of query._select) {
|
|
177
200
|
const e = `${expr}`;
|
|
178
201
|
if (!fields.has(e)) {
|
|
179
202
|
fields.set(e, [`col${fields.size}`, expr]);
|
|
180
203
|
}
|
|
181
|
-
const [name] = fields.get(e)
|
|
204
|
+
const [name] = fields.get(e)!;
|
|
182
205
|
fieldMap.push([name, alias]);
|
|
183
206
|
}
|
|
184
207
|
}
|
|
185
208
|
|
|
186
209
|
// use a cloned query as a starting point
|
|
187
|
-
const query = group[0].entry.request.query.clone();
|
|
210
|
+
const query = (group[0].entry.request.query as SelectQuery).clone();
|
|
188
211
|
|
|
189
212
|
// update group by statement as needed
|
|
190
213
|
const groupby = query._groupby;
|
|
191
214
|
if (groupby.length) {
|
|
192
|
-
const map = {};
|
|
215
|
+
const map: Record<string, string> = {};
|
|
193
216
|
group.maps[0].forEach(([name, as]) => map[as] = name);
|
|
194
|
-
query.setGroupby(
|
|
217
|
+
query.setGroupby(
|
|
218
|
+
groupby.map((e: ExprNode) => (isColumnRef(e) && map[e.column]) || e)
|
|
219
|
+
);
|
|
195
220
|
}
|
|
196
221
|
|
|
197
222
|
// update select statement and return
|
|
@@ -200,10 +225,10 @@ function consolidatedQuery(group) {
|
|
|
200
225
|
|
|
201
226
|
/**
|
|
202
227
|
* Process query results, dispatch results to original requests
|
|
203
|
-
* @param
|
|
204
|
-
* @param
|
|
228
|
+
* @param group Array of query requests
|
|
229
|
+
* @param cache Client-side query cache (sql -> data)
|
|
205
230
|
*/
|
|
206
|
-
async function processResults(group, cache) {
|
|
231
|
+
async function processResults(group: QueryGroup, cache: Cache): Promise<void> {
|
|
207
232
|
const { maps, query, result } = group;
|
|
208
233
|
|
|
209
234
|
// exit early if no consolidation performed
|
|
@@ -211,9 +236,9 @@ async function processResults(group, cache) {
|
|
|
211
236
|
if (!maps) return;
|
|
212
237
|
|
|
213
238
|
// await consolidated query result, pass errors if needed
|
|
214
|
-
let data;
|
|
239
|
+
let data: Table;
|
|
215
240
|
try {
|
|
216
|
-
data = await result;
|
|
241
|
+
data = await result as Table;
|
|
217
242
|
} catch (err) {
|
|
218
243
|
// pass error to consolidated queries
|
|
219
244
|
for (const { entry } of group) {
|
|
@@ -224,7 +249,7 @@ async function processResults(group, cache) {
|
|
|
224
249
|
|
|
225
250
|
// extract result for each query in the consolidation group
|
|
226
251
|
// update cache and pass extract to original issuer
|
|
227
|
-
const describe = isDescribeQuery(query);
|
|
252
|
+
const describe = isDescribeQuery(query!);
|
|
228
253
|
group.forEach(({ entry }, index) => {
|
|
229
254
|
const { request, result } = entry;
|
|
230
255
|
const map = maps[index];
|
|
@@ -240,29 +265,27 @@ async function processResults(group, cache) {
|
|
|
240
265
|
|
|
241
266
|
/**
|
|
242
267
|
* Project a consolidated result to a client result
|
|
243
|
-
* @param
|
|
244
|
-
*
|
|
245
|
-
* @param {[string, string][]} map Column name map as [source, target] pairs
|
|
268
|
+
* @param data Consolidated query result, as an Arrow Table
|
|
269
|
+
* @param map Column name map as [source, target] pairs
|
|
246
270
|
* @returns the projected Apache Arrow table
|
|
247
271
|
*/
|
|
248
|
-
function projectResult(data, map) {
|
|
272
|
+
function projectResult(data: Table, map: Array<[string, string]>): Table {
|
|
249
273
|
return data.select(map.map(x => x[0]), map.map(x => x[1]));
|
|
250
274
|
}
|
|
251
275
|
|
|
252
276
|
/**
|
|
253
277
|
* Filter a consolidated describe query result to a client result
|
|
254
|
-
* @param
|
|
255
|
-
*
|
|
256
|
-
* @param {[string, string][]} map Column name map as [source, target] pairs
|
|
278
|
+
* @param data Consolidated query result, as an Arrow Table
|
|
279
|
+
* @param map Column name map as [source, target] pairs
|
|
257
280
|
* @returns the filtered table data
|
|
258
281
|
*/
|
|
259
|
-
function filterResult(data, map) {
|
|
282
|
+
function filterResult(data: Table, map: Array<[string, string]>): unknown[] {
|
|
260
283
|
const lookup = new Map(map);
|
|
261
|
-
const result = [];
|
|
284
|
+
const result: unknown[] = [];
|
|
262
285
|
for (const d of data) {
|
|
263
286
|
if (lookup.has(d.column_name)) {
|
|
264
287
|
result.push({ ...d, column_name: lookup.get(d.column_name) })
|
|
265
288
|
}
|
|
266
289
|
}
|
|
267
290
|
return result;
|
|
268
|
-
}
|
|
291
|
+
}
|