@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.
Files changed (206) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +0 -1
  3. package/dist/src/Coordinator.d.ts +147 -0
  4. package/dist/src/Coordinator.d.ts.map +1 -0
  5. package/dist/src/Coordinator.js +269 -0
  6. package/dist/src/Coordinator.js.map +1 -0
  7. package/dist/{types → src}/MosaicClient.d.ts +37 -42
  8. package/dist/src/MosaicClient.d.ts.map +1 -0
  9. package/dist/src/MosaicClient.js +213 -0
  10. package/dist/src/MosaicClient.js.map +1 -0
  11. package/dist/src/Param.d.ts +56 -0
  12. package/dist/src/Param.d.ts.map +1 -0
  13. package/dist/src/Param.js +89 -0
  14. package/dist/src/Param.js.map +1 -0
  15. package/dist/src/QueryConsolidator.d.ts +11 -0
  16. package/dist/src/QueryConsolidator.d.ts.map +1 -0
  17. package/dist/src/QueryConsolidator.js +249 -0
  18. package/dist/src/QueryConsolidator.js.map +1 -0
  19. package/dist/src/QueryManager.d.ts +77 -0
  20. package/dist/src/QueryManager.d.ts.map +1 -0
  21. package/dist/src/QueryManager.js +174 -0
  22. package/dist/src/QueryManager.js.map +1 -0
  23. package/dist/src/Selection.d.ts +222 -0
  24. package/dist/src/Selection.d.ts.map +1 -0
  25. package/dist/src/Selection.js +319 -0
  26. package/dist/src/Selection.js.map +1 -0
  27. package/dist/src/SelectionClause.d.ts +192 -0
  28. package/dist/src/SelectionClause.d.ts.map +1 -0
  29. package/dist/src/SelectionClause.js +126 -0
  30. package/dist/src/SelectionClause.js.map +1 -0
  31. package/dist/{types → src}/connectors/Connector.d.ts +6 -5
  32. package/dist/src/connectors/Connector.d.ts.map +1 -0
  33. package/dist/src/connectors/Connector.js +2 -0
  34. package/dist/src/connectors/Connector.js.map +1 -0
  35. package/dist/src/connectors/rest.d.ts +24 -0
  36. package/dist/src/connectors/rest.d.ts.map +1 -0
  37. package/dist/src/connectors/rest.js +37 -0
  38. package/dist/src/connectors/rest.js.map +1 -0
  39. package/dist/src/connectors/socket.d.ts +40 -0
  40. package/dist/src/connectors/socket.d.ts.map +1 -0
  41. package/dist/src/connectors/socket.js +115 -0
  42. package/dist/src/connectors/socket.js.map +1 -0
  43. package/dist/src/connectors/wasm.d.ts +53 -0
  44. package/dist/src/connectors/wasm.d.ts.map +1 -0
  45. package/dist/src/connectors/wasm.js +113 -0
  46. package/dist/src/connectors/wasm.js.map +1 -0
  47. package/dist/src/index.d.ts +28 -0
  48. package/dist/src/index.d.ts.map +1 -0
  49. package/dist/src/index.js +25 -0
  50. package/dist/src/index.js.map +1 -0
  51. package/dist/src/make-client.d.ts +35 -0
  52. package/dist/src/make-client.d.ts.map +1 -0
  53. package/dist/src/make-client.js +52 -0
  54. package/dist/src/make-client.js.map +1 -0
  55. package/dist/{types → src}/preagg/PreAggregator.d.ts +64 -94
  56. package/dist/src/preagg/PreAggregator.d.ts.map +1 -0
  57. package/dist/src/preagg/PreAggregator.js +382 -0
  58. package/dist/src/preagg/PreAggregator.js.map +1 -0
  59. package/dist/{types → src}/preagg/preagg-columns.d.ts +10 -8
  60. package/dist/src/preagg/preagg-columns.d.ts.map +1 -0
  61. package/dist/src/preagg/preagg-columns.js +95 -0
  62. package/dist/src/preagg/preagg-columns.js.map +1 -0
  63. package/dist/src/preagg/sufficient-statistics.d.ts +14 -0
  64. package/dist/src/preagg/sufficient-statistics.d.ts.map +1 -0
  65. package/dist/src/preagg/sufficient-statistics.js +446 -0
  66. package/dist/src/preagg/sufficient-statistics.js.map +1 -0
  67. package/dist/{types → src}/types.d.ts +23 -9
  68. package/dist/src/types.d.ts.map +1 -0
  69. package/dist/src/types.js +2 -0
  70. package/dist/src/types.js.map +1 -0
  71. package/dist/{types → src}/util/AsyncDispatch.d.ts +53 -32
  72. package/dist/src/util/AsyncDispatch.d.ts.map +1 -0
  73. package/dist/src/util/AsyncDispatch.js +188 -0
  74. package/dist/src/util/AsyncDispatch.js.map +1 -0
  75. package/dist/src/util/cache.d.ts +19 -0
  76. package/dist/src/util/cache.d.ts.map +1 -0
  77. package/dist/src/util/cache.js +66 -0
  78. package/dist/src/util/cache.js.map +1 -0
  79. package/dist/src/util/decode-ipc.d.ts +12 -0
  80. package/dist/src/util/decode-ipc.d.ts.map +1 -0
  81. package/{src → dist/src}/util/decode-ipc.js +5 -6
  82. package/dist/src/util/decode-ipc.js.map +1 -0
  83. package/dist/src/util/distinct.d.ts +3 -0
  84. package/dist/src/util/distinct.d.ts.map +1 -0
  85. package/dist/src/util/distinct.js +16 -0
  86. package/dist/src/util/distinct.js.map +1 -0
  87. package/dist/src/util/field-info.d.ts +26 -0
  88. package/dist/src/util/field-info.d.ts.map +1 -0
  89. package/dist/src/util/field-info.js +91 -0
  90. package/dist/src/util/field-info.js.map +1 -0
  91. package/dist/src/util/hash.d.ts +2 -0
  92. package/dist/src/util/hash.d.ts.map +1 -0
  93. package/dist/src/util/hash.js +26 -0
  94. package/dist/src/util/hash.js.map +1 -0
  95. package/dist/src/util/is-activatable.d.ts +8 -0
  96. package/dist/src/util/is-activatable.d.ts.map +1 -0
  97. package/dist/src/util/is-activatable.js +10 -0
  98. package/dist/src/util/is-activatable.js.map +1 -0
  99. package/dist/src/util/is-arrow-table.d.ts +9 -0
  100. package/dist/src/util/is-arrow-table.d.ts.map +1 -0
  101. package/dist/src/util/is-arrow-table.js +11 -0
  102. package/dist/src/util/is-arrow-table.js.map +1 -0
  103. package/dist/src/util/js-type.d.ts +9 -0
  104. package/dist/src/util/js-type.d.ts.map +1 -0
  105. package/dist/src/util/js-type.js +59 -0
  106. package/dist/src/util/js-type.js.map +1 -0
  107. package/dist/{types → src}/util/priority-queue.d.ts +12 -14
  108. package/dist/src/util/priority-queue.d.ts.map +1 -0
  109. package/dist/src/util/priority-queue.js +81 -0
  110. package/dist/src/util/priority-queue.js.map +1 -0
  111. package/dist/src/util/query-result.d.ts +47 -0
  112. package/dist/src/util/query-result.d.ts.map +1 -0
  113. package/dist/src/util/query-result.js +83 -0
  114. package/dist/src/util/query-result.js.map +1 -0
  115. package/dist/src/util/synchronizer.d.ts +36 -0
  116. package/dist/src/util/synchronizer.d.ts.map +1 -0
  117. package/dist/src/util/synchronizer.js +52 -0
  118. package/dist/src/util/synchronizer.js.map +1 -0
  119. package/dist/src/util/throttle.d.ts +12 -0
  120. package/dist/src/util/throttle.d.ts.map +1 -0
  121. package/dist/src/util/throttle.js +51 -0
  122. package/dist/src/util/throttle.js.map +1 -0
  123. package/dist/src/util/to-data-columns.d.ts +22 -0
  124. package/dist/src/util/to-data-columns.d.ts.map +1 -0
  125. package/dist/src/util/to-data-columns.js +51 -0
  126. package/dist/src/util/to-data-columns.js.map +1 -0
  127. package/dist/src/util/void-logger.d.ts +13 -0
  128. package/dist/src/util/void-logger.d.ts.map +1 -0
  129. package/dist/src/util/void-logger.js +13 -0
  130. package/dist/src/util/void-logger.js.map +1 -0
  131. package/package.json +15 -13
  132. package/src/Coordinator.ts +367 -0
  133. package/src/{MosaicClient.js → MosaicClient.ts} +49 -43
  134. package/src/{Param.js → Param.ts} +29 -28
  135. package/src/{QueryConsolidator.js → QueryConsolidator.ts} +81 -58
  136. package/src/{QueryManager.js → QueryManager.ts} +61 -54
  137. package/src/Selection.ts +388 -0
  138. package/src/SelectionClause.ts +275 -0
  139. package/src/connectors/Connector.ts +6 -6
  140. package/src/connectors/rest.ts +56 -0
  141. package/src/connectors/{socket.js → socket.ts} +53 -42
  142. package/src/connectors/{wasm.js → wasm.ts} +46 -62
  143. package/src/{index.js → index.ts} +13 -1
  144. package/src/make-client.ts +93 -0
  145. package/src/preagg/{PreAggregator.js → PreAggregator.ts} +164 -145
  146. package/src/preagg/{preagg-columns.js → preagg-columns.ts} +27 -24
  147. package/src/preagg/{sufficient-statistics.js → sufficient-statistics.ts} +161 -110
  148. package/src/types.ts +24 -9
  149. package/src/util/{AsyncDispatch.js → AsyncDispatch.ts} +62 -43
  150. package/src/util/{cache.js → cache.ts} +25 -15
  151. package/src/util/decode-ipc.ts +15 -0
  152. package/src/util/{distinct.js → distinct.ts} +3 -3
  153. package/src/util/{field-info.js → field-info.ts} +31 -32
  154. package/src/util/{hash.js → hash.ts} +4 -4
  155. package/src/util/is-activatable.ts +11 -0
  156. package/src/util/is-arrow-table.ts +12 -0
  157. package/src/util/{js-type.js → js-type.ts} +7 -5
  158. package/src/util/{priority-queue.js → priority-queue.ts} +32 -20
  159. package/src/util/{query-result.js → query-result.ts} +24 -17
  160. package/src/util/synchronizer.ts +56 -0
  161. package/src/util/throttle.ts +59 -0
  162. package/src/util/to-data-columns.ts +65 -0
  163. package/src/util/void-logger.ts +23 -0
  164. package/dist/types/Coordinator.d.ts +0 -164
  165. package/dist/types/Param.d.ts +0 -47
  166. package/dist/types/QueryConsolidator.d.ts +0 -9
  167. package/dist/types/QueryManager.d.ts +0 -91
  168. package/dist/types/Selection.d.ts +0 -235
  169. package/dist/types/SelectionClause.d.ts +0 -105
  170. package/dist/types/connectors/rest.d.ts +0 -13
  171. package/dist/types/connectors/socket.d.ts +0 -100
  172. package/dist/types/connectors/wasm.d.ts +0 -135
  173. package/dist/types/index-types.d.ts +0 -4
  174. package/dist/types/index.d.ts +0 -19
  175. package/dist/types/make-client.d.ts +0 -78
  176. package/dist/types/preagg/sufficient-statistics.d.ts +0 -13
  177. package/dist/types/util/cache.d.ts +0 -17
  178. package/dist/types/util/decode-ipc.d.ts +0 -12
  179. package/dist/types/util/distinct.d.ts +0 -2
  180. package/dist/types/util/field-info.d.ts +0 -23
  181. package/dist/types/util/hash.d.ts +0 -1
  182. package/dist/types/util/is-activatable.d.ts +0 -6
  183. package/dist/types/util/is-arrow-table.d.ts +0 -8
  184. package/dist/types/util/js-type.d.ts +0 -7
  185. package/dist/types/util/query-result.d.ts +0 -44
  186. package/dist/types/util/selection-types.d.ts +0 -114
  187. package/dist/types/util/synchronizer.d.ts +0 -29
  188. package/dist/types/util/throttle.d.ts +0 -13
  189. package/dist/types/util/to-data-columns.d.ts +0 -29
  190. package/dist/types/util/void-logger.d.ts +0 -10
  191. package/jsconfig.json +0 -11
  192. package/src/Coordinator.js +0 -337
  193. package/src/Selection.js +0 -380
  194. package/src/SelectionClause.js +0 -159
  195. package/src/connectors/rest.js +0 -38
  196. package/src/index-types.ts +0 -4
  197. package/src/make-client.js +0 -101
  198. package/src/util/is-activatable.js +0 -8
  199. package/src/util/is-arrow-table.js +0 -10
  200. package/src/util/selection-types.ts +0 -137
  201. package/src/util/synchronizer.js +0 -47
  202. package/src/util/throttle.js +0 -54
  203. package/src/util/to-data-columns.js +0 -60
  204. package/src/util/void-logger.js +0 -13
  205. package/tsconfig.json +0 -11
  206. package/vitest.config.ts +0 -3
@@ -1,8 +1,14 @@
1
- /** @import { Query } from '@uwdata/mosaic-sql' */
2
- /** @import { Coordinator } from './Coordinator.js' */
3
- /** @import { Selection } from './Selection.js' */
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 {Selection} [filterSelection] An optional selection to
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 {Coordinator | null} this client's connected coordinator.
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 {Selection | undefined} this client's filter selection.
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 {*} [filter] The filtering criteria to apply in the query.
121
- * @returns {*} The client query
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 {this}
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 {*} data The query result.
138
- * @returns {this}
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 {*} error
147
- * @returns {this}
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 {Query} [query] The query to request. If unspecified, the query
162
- * will be determind by the client's `query` method and the current
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?.requestQuery(this, q);
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 {*} x The value to test.
7
- * @returns {x is Param} True if the input is a Param, false otherwise.
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 {*} value The initial value of the 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 {*} value The initial value of the Param.
31
- * @returns {Param} The new Param instance.
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 {*} values The initial values of the Param.
41
- * @returns {Param} The new Param instance.
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 {*} value The new value of the Param.
66
- * @param {object} [options] The update options.
67
- * @param {boolean} [options.force] A boolean flag indicating if the 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 {this} This Param instance.
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 {string} type The event type.
85
- * @param {*} value The input event value.
86
- * @returns {*} The input event value.
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
- /** @import { DescribeQuery, Query } from '@uwdata/mosaic-sql' */
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
- function wait(callback) {
6
- const method = typeof requestAnimationFrame !== 'undefined'
7
- ? requestAnimationFrame
8
- : typeof setImmediate !== 'undefined' ? setImmediate : setTimeout;
9
- // @ts-ignore
10
- return method(callback);
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 {*} enqueue Query manager enqueue method
16
- * @param {*} cache Client-side query cache (sql -> data)
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(enqueue, cache) {
20
- let pending = [];
21
- let id = 0;
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 = id || wait(() => run());
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 {*} entries Query request entries ({ request, result } objects)
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).push(query);
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 {Query | DescribeQuery} query The input query.
79
- * @param {*} cache The query cache (sql -> data).
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 {*} group Array of bundled query entries
123
- * @param {*} enqueue Add entry to query queue
142
+ * @param group Array of bundled query entries
143
+ * @param enqueue Add entry to query queue
124
144
  */
125
- function consolidate(group, enqueue) {
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 {*} group Array of bundled query entries
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 {*} group Array of bundled query entries
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 { query } = item.entry.request;
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(groupby.map(e => (isColumnRef(e) && map[e.column]) || e));
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 {*} group Array of query requests
204
- * @param {*} cache Client-side query cache (sql -> data)
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 {import('@uwdata/flechette').Table} data
244
- * Consolidated query result, as an Arrow Table
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 {import('@uwdata/flechette').Table} data
255
- * Consolidated query result, as an Arrow Table
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
+ }