@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
@@ -0,0 +1,275 @@
1
+
2
+ import { isMosaicClient, MosaicClient } from './MosaicClient.js';
3
+ import { type ExprNode, type ExprValue, type ScaleOptions, type ScaleDomain, and, contains, isBetween, isIn, isNotDistinct, literal, or, prefix, regexp_matches, suffix } from '@uwdata/mosaic-sql';
4
+
5
+ /**
6
+ * Selection clause metadata to guide possible query optimizations.
7
+ * Sub-interfaces provide more information about the specifics of a
8
+ * given selection based on the selection type.
9
+ */
10
+ export interface ClauseMetadata {
11
+ /**
12
+ * The selection type, such as `'point'`, `'interval'`, or `'match'`.
13
+ */
14
+ type: string;
15
+ }
16
+
17
+ /**
18
+ * Selection clause metadata indicating selection of one or more discrete
19
+ * point values, typically based on equality or is distinctiveness checks.
20
+ */
21
+ export interface PointMetadata extends ClauseMetadata {
22
+ type: 'point';
23
+ }
24
+
25
+ /**
26
+ * Selection clause metadata indicating text search matching.
27
+ */
28
+ export interface MatchMetadata extends ClauseMetadata {
29
+ type: MatchMethod;
30
+ /** The text search matching method used. */
31
+ method?: 'contains' | 'prefix' | 'suffix' | 'regexp' | (string & {});
32
+ }
33
+
34
+ /** A binning method name. */
35
+ export type BinMethod = 'floor' | 'ceil' | 'round';
36
+
37
+ /**
38
+ * Selection clause metadata for one or more selected intervals. This
39
+ * metadata can be used to determine appropriate data-space binning
40
+ * schemes that correspond to pixel-level bins in screen space.
41
+ */
42
+ export interface IntervalMetadata extends ClauseMetadata {
43
+ type: 'interval';
44
+ /**
45
+ * The interactive pixel size used by the generating component.
46
+ * Values larger than one indicate intervals that "snap-to" values
47
+ * greater than a single pixel. If unspecified, assumed to be `1`.
48
+ */
49
+ pixelSize?: number;
50
+ /**
51
+ * An array of one or more scale descriptors that describe the
52
+ * mapping from data values to screen pixels.
53
+ */
54
+ scales?: ScaleOptions[];
55
+ /**
56
+ * A hint for the binning method to use when discretizing the
57
+ * interval domain. If unspecified, the default is `'floor'`.
58
+ */
59
+ bin?: BinMethod
60
+ }
61
+
62
+ export interface ClauseSource {
63
+ reset?: () => void;
64
+ }
65
+
66
+ /**
67
+ * A selection clause representing filtering criteria
68
+ * to apply within a Mosaic Selection.
69
+ */
70
+ export interface SelectionClause {
71
+ /**
72
+ * A unique identifier (according to object equality) for the source
73
+ * component that generated this clause. In many cases, this is a
74
+ * reference to the originating component itself.
75
+ */
76
+ source: ClauseSource;
77
+ /**
78
+ * A set of Mosaic clients associated with this clause that should not
79
+ * be updated when this clause is applied in a cross-filtering context.
80
+ */
81
+ clients?: Set<MosaicClient>;
82
+ /**
83
+ * A selected value associated with this clause. For example, for a 1D
84
+ * interval selection clause the value may be a [lo, hi] array.
85
+ */
86
+ value: unknown;
87
+ /**
88
+ * A predicate SQL expression suitable for use in a query WHERE clause.
89
+ * The predicate should apply filtering criteria consistent with this
90
+ * clause's *value* property.
91
+ */
92
+ predicate: ExprNode | null;
93
+ /**
94
+ * Optional clause metadata that varies based on the selection type.
95
+ * The metadata can be used to optimize selection queries, for example
96
+ * by creating materialized views of pre-aggregated data when applicable.
97
+ */
98
+ meta?: ClauseMetadata;
99
+ }
100
+
101
+ /**
102
+ * Generate a selection clause for a single selected point value.
103
+ * @param field The table column or expression to select.
104
+ * @param value The selected value.
105
+ * @param options Additional clause properties.
106
+ * @param options.source The source component generating this clause.
107
+ * @param options.clients The Mosaic clients associated
108
+ * with this clause. These clients are not filtered by this clause in
109
+ * cross-filtering contexts.
110
+ * @returns The generated selection clause.
111
+ */
112
+ export function clausePoint(field: ExprValue, value: unknown, {
113
+ source,
114
+ clients = isMosaicClient(source) ? new Set([source]) : undefined
115
+ }: {
116
+ source: ClauseSource;
117
+ clients?: Set<MosaicClient>;
118
+ }): SelectionClause {
119
+ const predicate: ExprNode | null = value !== undefined
120
+ ? isIn(field, [literal(value)])
121
+ : null;
122
+ return {
123
+ meta: { type: 'point' },
124
+ source,
125
+ clients,
126
+ value,
127
+ predicate
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Generate a selection clause for multiple selected point values.
133
+ * @param fields The table columns or expressions to select.
134
+ * @param value The selected values, as an array of
135
+ * arrays. Each subarray contains values for each *fields* entry.
136
+ * @param options Additional clause properties.
137
+ * @param options.source The source component generating this clause.
138
+ * @param options.clients The Mosaic clients associated
139
+ * with this clause. These clients are not filtered by this clause in
140
+ * cross-filtering contexts.
141
+ * @returns The generated selection clause.
142
+ */
143
+ export function clausePoints(fields: ExprValue[], value: unknown[][] | null | undefined, {
144
+ source,
145
+ clients = isMosaicClient(source) ? new Set([source]) : undefined
146
+ }: {
147
+ source: ClauseSource;
148
+ clients?: Set<MosaicClient>;
149
+ }): SelectionClause {
150
+ let predicate: ExprNode | null = null;
151
+ if (value) {
152
+ const clauses = value.length && fields.length === 1
153
+ ? [isIn(fields[0], value.map(v => literal(v[0])))]
154
+ : value.map(v => and(v.map((_, i) => isNotDistinct(fields[i], literal(_)))));
155
+ predicate = value.length === 0 ? literal(false)
156
+ : clauses.length > 1 ? or(clauses)
157
+ : clauses[0];
158
+ }
159
+ return {
160
+ meta: { type: 'point' },
161
+ source,
162
+ clients,
163
+ value,
164
+ predicate
165
+ };
166
+ }
167
+
168
+ /**
169
+ * Generate a selection clause for a selected 1D interval.
170
+ * @param field The table column or expression to select.
171
+ * @param value The selected interval as a [lo, hi] array.
172
+ * @param options Additional clause properties.
173
+ * @param options.source The source component generating this clause.
174
+ * @param options.clients The Mosaic clients associated
175
+ * with this clause. These clients are not filtered by this clause in
176
+ * cross-filtering contexts.
177
+ * @param options.scale The scale mapping descriptor.
178
+ * @param options.bin A binning method hint.
179
+ * @param options.pixelSize The interactive pixel size.
180
+ * @returns The generated selection clause.
181
+ */
182
+ export function clauseInterval(field: ExprValue, value: ScaleDomain | null | undefined, {
183
+ source,
184
+ clients = isMosaicClient(source) ? new Set([source]) : undefined,
185
+ bin,
186
+ scale,
187
+ pixelSize = 1
188
+ }: {
189
+ source: ClauseSource;
190
+ clients?: Set<MosaicClient>;
191
+ scale?: ScaleOptions;
192
+ bin?: BinMethod;
193
+ pixelSize?: number;
194
+ }): SelectionClause {
195
+ const predicate = value != null ? isBetween(field, value) : null;
196
+ const meta: IntervalMetadata = {
197
+ type: 'interval',
198
+ scales: scale && [scale],
199
+ bin,
200
+ pixelSize
201
+ };
202
+ return { meta, source, clients, value, predicate };
203
+ }
204
+
205
+ /**
206
+ * Generate a selection clause for multiple selected intervals.
207
+ * @param fields The table columns or expressions to select.
208
+ * @param value The selected intervals, as an array of extents.
209
+ * @param options Additional clause properties.
210
+ * @param options.source The source component generating this clause.
211
+ * @param options.clients The Mosaic clients associated
212
+ * with this clause. These clients are not filtered by this clause in
213
+ * cross-filtering contexts.
214
+ * @param options.scales The scale mapping descriptors,
215
+ * in an order matching the given *fields* and *value* extents.
216
+ * @param options.bin A binning method hint.
217
+ * @param options.pixelSize The interactive pixel size.
218
+ * @returns The generated selection clause.
219
+ */
220
+ export function clauseIntervals(fields: ExprValue[], value: ScaleDomain[] | null | undefined, {
221
+ source,
222
+ clients = isMosaicClient(source) ? new Set([source]) : undefined,
223
+ bin,
224
+ scales = [],
225
+ pixelSize = 1
226
+ }: {
227
+ source: ClauseSource;
228
+ clients?: Set<MosaicClient>;
229
+ scales?: ScaleOptions[];
230
+ bin?: BinMethod;
231
+ pixelSize?: number;
232
+ }): SelectionClause {
233
+ const predicate = value != null
234
+ ? and(fields.map((f, i) => isBetween(f, value[i])))
235
+ : null;
236
+ const meta: IntervalMetadata = {
237
+ type: 'interval',
238
+ scales,
239
+ bin,
240
+ pixelSize
241
+ };
242
+ return { meta, source, clients, value, predicate };
243
+ }
244
+
245
+ const MATCH_METHODS = { contains, prefix, suffix, regexp: regexp_matches };
246
+
247
+ /** Text search matching methods. */
248
+ export type MatchMethod = keyof typeof MATCH_METHODS | (string & {});
249
+
250
+ /**
251
+ * Generate a selection clause for text search matching.
252
+ * @param field The table column or expression to select.
253
+ * @param value The selected text search query string.
254
+ * @param options Additional clause properties.
255
+ * @param options.source The source component generating this clause.
256
+ * @param options.clients The Mosaic clients associated
257
+ * with this clause. These clients are not filtered by this clause in
258
+ * cross-filtering contexts.
259
+ * @param options.method The text matching method to use. Defaults to `'contains'`.
260
+ * @returns The generated selection clause.
261
+ */
262
+ export function clauseMatch(field: ExprValue, value: string | null | undefined, {
263
+ source,
264
+ clients = undefined,
265
+ method = 'contains'
266
+ }: {
267
+ source: ClauseSource;
268
+ clients?: Set<MosaicClient>;
269
+ method?: MatchMethod;
270
+ }): SelectionClause {
271
+ const fn = MATCH_METHODS[method as keyof typeof MATCH_METHODS];
272
+ const predicate: ExprNode | null = value ? fn(field, literal(value)) : null;
273
+ const meta: MatchMetadata = { type: 'match', method };
274
+ return { meta, source, clients, value, predicate };
275
+ }
@@ -1,23 +1,23 @@
1
1
  import type { Table } from '@uwdata/flechette';
2
2
 
3
- export interface QueryRequest {
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 QueryRequest {
10
+ export interface ArrowQueryRequest extends ConnectorQueryRequest {
11
11
  /** The query type. */
12
12
  type?: 'arrow';
13
13
  }
14
14
 
15
- export interface ExecQueryRequest extends QueryRequest {
15
+ export interface ExecQueryRequest extends ConnectorQueryRequest {
16
16
  /** The query type. */
17
17
  type: 'exec';
18
18
  }
19
19
 
20
- export interface JSONQueryRequest extends QueryRequest {
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, any>[]>;
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
- /** @import { ExtractionOptions, Table } from '@uwdata/flechette' */
2
- /** @import { ArrowQueryRequest, Connector, ExecQueryRequest, JSONQueryRequest } from './Connector.js' */
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 {object} [options] Connector options.
8
- * @param {string} [options.uri] The URI for the DuckDB REST server.
9
- * @param {ExtractionOptions} [options.ipc] Arrow IPC extraction options.
10
- * @returns {SocketConnector} A connector instance.
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 {object} [options] Connector options.
23
- * @param {string} [options.uri] The URI for the DuckDB REST server.
24
- * @param {ExtractionOptions} [options.ipc] Arrow IPC extraction options.
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().reject('Socket closed');
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({ data }) {
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(query, resolve, reject) {
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.send(JSON.stringify(this._request.query));
133
+ this._request = this._queue.shift()!;
134
+ this._ws!.send(JSON.stringify(this._request.query));
111
135
  }
112
136
  }
113
137
 
114
- /**
115
- * @overload
116
- * @param {ArrowQueryRequest} query
117
- * @returns {Promise<Table>}
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
+ }