@uwdata/mosaic-core 0.17.0 → 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 (178) hide show
  1. package/LICENSE +47 -0
  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/src/MosaicClient.d.ts +138 -0
  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/src/connectors/Connector.d.ts +26 -0
  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/src/preagg/PreAggregator.d.ts +150 -0
  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/src/preagg/preagg-columns.d.ts +16 -0
  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/src/types.d.ts +77 -0
  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/src/util/AsyncDispatch.d.ts +121 -0
  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/src/util/priority-queue.d.ts +35 -0
  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 +16 -10
  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} +160 -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/src/Coordinator.js +0 -313
  165. package/src/Selection.js +0 -380
  166. package/src/SelectionClause.js +0 -159
  167. package/src/connectors/rest.js +0 -38
  168. package/src/index-types.ts +0 -5
  169. package/src/make-client.js +0 -101
  170. package/src/util/is-activatable.js +0 -8
  171. package/src/util/is-arrow-table.js +0 -10
  172. package/src/util/selection-types.ts +0 -137
  173. package/src/util/synchronizer.js +0 -47
  174. package/src/util/throttle.js +0 -54
  175. package/src/util/to-data-columns.js +0 -60
  176. package/src/util/void-logger.js +0 -13
  177. package/tsconfig.json +0 -9
  178. package/vitest.config.ts +0 -3
@@ -1,43 +1,57 @@
1
+ type EventCallback<T = unknown> = (value: T) => void | Promise<unknown>;
2
+
3
+ interface DispatchEntry<T = unknown> {
4
+ callbacks: Set<EventCallback<T>>;
5
+ pending: Promise<unknown> | null;
6
+ queue: DispatchQueue<T>;
7
+ }
8
+
9
+ interface QueueNode<T = unknown> {
10
+ value: T;
11
+ next?: QueueNode<T> | null;
12
+ }
13
+
1
14
  /**
2
15
  * Event dispatcher supporting asynchronous updates. If an event handler
3
16
  * callback returns a Promise, the dispatcher waits for all such Promises
4
17
  * to settle before dispatching future events of the same type.
5
18
  */
6
- export class AsyncDispatch {
19
+ export class AsyncDispatch<T> {
20
+ _callbacks: Map<string, DispatchEntry<T>>;
7
21
 
8
22
  /**
9
23
  * Create a new asynchronous dispatcher instance.
10
24
  */
11
25
  constructor() {
12
- this._callbacks = new Map;
26
+ this._callbacks = new Map();
13
27
  }
14
28
 
15
29
  /**
16
30
  * Add an event listener callback for the provided event type.
17
- * @param {string} type The event type.
18
- * @param {(value: *) => void | Promise} callback The event handler
31
+ * @param type The event type.
32
+ * @param callback The event handler
19
33
  * callback function to add. If the callback has already been
20
34
  * added for the event type, this method has no effect.
21
35
  */
22
- addEventListener(type, callback) {
36
+ addEventListener(type: string, callback: EventCallback<T>): void {
23
37
  if (!this._callbacks.has(type)) {
24
38
  this._callbacks.set(type, {
25
- callbacks: new Set,
39
+ callbacks: new Set<EventCallback<T>>(),
26
40
  pending: null,
27
- queue: new DispatchQueue()
41
+ queue: new DispatchQueue<T>()
28
42
  });
29
43
  }
30
- const entry = this._callbacks.get(type);
44
+ const entry = this._callbacks.get(type)!;
31
45
  entry.callbacks.add(callback);
32
46
  }
33
47
 
34
48
  /**
35
49
  * Remove an event listener callback for the provided event type.
36
- * @param {string} type The event type.
37
- * @param {(value: *) => void | Promise} callback The event handler
50
+ * @param type The event type.
51
+ * @param callback The event handler
38
52
  * callback function to remove.
39
53
  */
40
- removeEventListener(type, callback) {
54
+ removeEventListener(type: string, callback: EventCallback<T>): void {
41
55
  const entry = this._callbacks.get(type);
42
56
  if (entry) {
43
57
  entry.callbacks.delete(callback);
@@ -49,11 +63,11 @@ export class AsyncDispatch {
49
63
  * This default implementation simply returns the input value as-is.
50
64
  * Subclasses may override this method to implement custom transformations
51
65
  * prior to emitting an event value to all listeners.
52
- * @param {string} type The event type.
53
- * @param {*} value The event value.
66
+ * @param type The event type.
67
+ * @param value The event value.
54
68
  * @returns The (possibly transformed) event value to emit.
55
69
  */
56
- willEmit(type, value) {
70
+ willEmit(type: string, value: T): T {
57
71
  return value;
58
72
  }
59
73
 
@@ -61,35 +75,38 @@ export class AsyncDispatch {
61
75
  * Lifecycle method that returns a filter function for updating the
62
76
  * queue of unemitted event values prior to enqueueing a new value.
63
77
  * This default implementation simply returns null, indicating that
64
- * any other unemitted event values should be dropped (that is, all
78
+ * unknown other unemitted event values should be dropped (that is, all
65
79
  * queued events are filtered).
66
- * @param {string} type The event type.
67
- * @param {*} value The new event value that will be enqueued.
68
- * @returns {(value: *) => boolean|null} A dispatch queue filter
80
+ * @param type The event type.
81
+ * @param value The new event value that will be enqueued.
82
+ * @returns A dispatch queue filter
69
83
  * function, or null if all unemitted event values should be filtered.
70
84
  */
71
- emitQueueFilter(type, value) { // eslint-disable-line no-unused-vars
85
+ emitQueueFilter(
86
+ _type: string, // eslint-disable-line @typescript-eslint/no-unused-vars
87
+ _value: unknown // eslint-disable-line @typescript-eslint/no-unused-vars
88
+ ): ((value: unknown) => boolean | null) | null {
72
89
  // removes all pending items
73
90
  return null;
74
91
  }
75
92
 
76
93
  /**
77
94
  * Cancel all unemitted event values for the given event type.
78
- * @param {string} type The event type.
95
+ * @param type The event type.
79
96
  */
80
- cancel(type) {
97
+ cancel(type: string): void {
81
98
  const entry = this._callbacks.get(type);
82
99
  entry?.queue.clear();
83
100
  }
84
101
 
85
102
  /**
86
- * Returns a promise that resolves when any pending updates complete for
103
+ * Returns a promise that resolves when unknown pending updates complete for
87
104
  * the event of the given type currently being processed. The Promise will
88
105
  * resolve immediately if the queue for the given event type is empty.
89
- * @param {string} type The event type to wait for.
90
- * @returns {Promise} A pending event promise.
106
+ * @param type The event type to wait for.
107
+ * @returns A pending event promise.
91
108
  */
92
- async pending(type) {
109
+ async pending(type: string): Promise<void> {
93
110
  await this._callbacks.get(type)?.pending;
94
111
  }
95
112
 
@@ -99,11 +116,11 @@ export class AsyncDispatch {
99
116
  * will be queued to be emitted later.
100
117
  * The actual event value given to listeners will be the result
101
118
  * of passing the input value through the emitValue() method.
102
- * @param {string} type The event type.
103
- * @param {*} value The event value.
119
+ * @param type The event type.
120
+ * @param value The event value.
104
121
  */
105
- emit(type, value) {
106
- const entry = this._callbacks.get(type) || {};
122
+ emit(type: string, value: T): void {
123
+ const entry = this._callbacks.get(type) || {} as DispatchEntry<T>;
107
124
  if (entry.pending) {
108
125
  // an earlier emit is still processing
109
126
  // enqueue the current update, possibly filtering other pending updates
@@ -118,7 +135,7 @@ export class AsyncDispatch {
118
135
  entry.pending = Promise.allSettled(callbackValues).then(() => {
119
136
  entry.pending = null;
120
137
  if (!queue.isEmpty()) {
121
- this.emit(type, queue.dequeue());
138
+ this.emit(type, queue.dequeue()!);
122
139
  }
123
140
  });
124
141
  }
@@ -129,7 +146,8 @@ export class AsyncDispatch {
129
146
  /**
130
147
  * Queue for managing unemitted event values.
131
148
  */
132
- export class DispatchQueue {
149
+ export class DispatchQueue<T = unknown> {
150
+ next: QueueNode<T> | null = null;
133
151
 
134
152
  /**
135
153
  * Create a new dispatch queue instance.
@@ -141,33 +159,34 @@ export class DispatchQueue {
141
159
  /**
142
160
  * Clear the queue state of all event values.
143
161
  */
144
- clear() {
162
+ clear(): void {
145
163
  this.next = null;
146
164
  }
147
165
 
148
166
  /**
149
167
  * Indicate if the queue is empty.
150
- * @returns {boolean} True if queue is empty, false otherwise.
168
+ * @returns True if queue is empty, false otherwise.
151
169
  */
152
- isEmpty() {
170
+ isEmpty(): boolean {
153
171
  return !this.next;
154
172
  }
155
173
 
156
174
  /**
157
175
  * Add a new value to the queue, and optionally filter the
158
176
  * current queue content in response.
159
- * @param {*} value The value to add.
160
- * @param {(value: *) => boolean} [filter] An optional filter
177
+ * @param value The value to add.
178
+ * @param filter An optional filter
161
179
  * function to apply to existing queue content. If unspecified
162
180
  * or falsy, all previously queued values are removed. Otherwise,
163
181
  * the provided function is applied to all queue entries. The
164
182
  * entry is retained if the filter function returns a truthy value,
165
183
  * otherwise the entry is removed.
166
184
  */
167
- enqueue(value, filter) {
168
- const tail = { value };
185
+ enqueue(value: T, filter?: ((value: T) => boolean | null) | null): void {
186
+ const tail: QueueNode<T> = { value };
169
187
  if (filter && this.next) {
170
- let curr = this;
188
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
189
+ let curr: QueueNode<T> | DispatchQueue<T> = this;
171
190
  while (curr.next) {
172
191
  if (filter(curr.next.value)) {
173
192
  curr = curr.next;
@@ -183,11 +202,11 @@ export class DispatchQueue {
183
202
 
184
203
  /**
185
204
  * Remove and return the next queued event value.
186
- * @returns {*} The next event value in the queue.
205
+ * @returns The next event value in the queue.
187
206
  */
188
- dequeue() {
207
+ dequeue(): T | undefined {
189
208
  const { next } = this;
190
- this.next = next?.next;
209
+ this.next = next?.next || null;
191
210
  return next?.value;
192
211
  }
193
- }
212
+ }
@@ -1,14 +1,19 @@
1
- /** @import { Cache } from '../types.js' */
1
+ import type { Cache } from '../types.js';
2
2
 
3
3
  const requestIdle = typeof requestIdleCallback !== 'undefined'
4
4
  ? requestIdleCallback
5
5
  : setTimeout;
6
6
 
7
+ interface CacheEntry<T = unknown> {
8
+ last: number;
9
+ value: T;
10
+ }
11
+
7
12
  /**
8
13
  * Create a new cache that ignores all values.
9
- * @returns {Cache}
14
+ * @returns A void cache implementation.
10
15
  */
11
- export function voidCache() {
16
+ export function voidCache(): Cache {
12
17
  return {
13
18
  get: () => undefined,
14
19
  set: (key, value) => value,
@@ -18,20 +23,23 @@ export function voidCache() {
18
23
 
19
24
  /**
20
25
  * Create a new cache that uses an LRU eviction policy.
21
- * @param {object} [options] Cache options.
22
- * @param {number} [options.max] Maximum number of cache entries.
23
- * @param {number} [options.ttl] Time-to-live for cache entries.
24
- * @returns {Cache}
26
+ * @param options Cache options.
27
+ * @param options.max Maximum number of cache entries.
28
+ * @param options.ttl Time-to-live for cache entries.
29
+ * @returns An LRU cache implementation.
25
30
  */
26
31
  export function lruCache({
27
32
  max = 1000, // max entries
28
33
  ttl = 3 * 60 * 60 * 1000 // time-to-live, default 3 hours
29
- } = {}) {
30
- let cache = new Map;
34
+ }: {
35
+ max?: number;
36
+ ttl?: number;
37
+ } = {}): Cache {
38
+ let cache = new Map<string, CacheEntry>();
31
39
 
32
- function evict() {
40
+ function evict(): void {
33
41
  const expire = performance.now() - ttl;
34
- let lruKey = null;
42
+ let lruKey: string | null = null;
35
43
  let lruLast = Infinity;
36
44
 
37
45
  for (const [key, value] of cache) {
@@ -56,18 +64,20 @@ export function lruCache({
56
64
  }
57
65
 
58
66
  return {
59
- get(key) {
67
+ get(key: string): unknown {
60
68
  const entry = cache.get(key);
61
69
  if (entry) {
62
70
  entry.last = performance.now();
63
71
  return entry.value;
64
72
  }
65
73
  },
66
- set(key, value) {
74
+ set(key: string, value: unknown): unknown {
67
75
  cache.set(key, { last: performance.now(), value });
68
76
  if (cache.size > max) requestIdle(evict);
69
77
  return value;
70
78
  },
71
- clear() { cache = new Map; }
79
+ clear(): void {
80
+ cache = new Map();
81
+ }
72
82
  };
73
- }
83
+ }
@@ -0,0 +1,15 @@
1
+ import type { ExtractionOptions, Table } from '@uwdata/flechette';
2
+ import { tableFromIPC } from '@uwdata/flechette';
3
+
4
+ /**
5
+ * Decode Arrow IPC bytes to a table instance.
6
+ * The default options map date and timestamp values to JS Date objects.
7
+ * @param data Arrow IPC bytes.
8
+ * @param options Arrow IPC extraction options.
9
+ * If unspecified, the default options will extract date and timestamp
10
+ * values to JS Date objects.
11
+ * @returns A table instance.
12
+ */
13
+ export function decodeIPC(data: ArrayBuffer | Uint8Array, options: ExtractionOptions = { useDate: true }): Table {
14
+ return tableFromIPC(data, options);
15
+ }
@@ -1,14 +1,14 @@
1
- export function distinct(a, b) {
1
+ export function distinct(a: unknown, b: unknown): boolean {
2
2
  return a === b ? false
3
3
  : a instanceof Date && b instanceof Date ? +a !== +b
4
4
  : Array.isArray(a) && Array.isArray(b) ? distinctArray(a, b)
5
5
  : true;
6
6
  }
7
7
 
8
- export function distinctArray(a, b) {
8
+ export function distinctArray(a: unknown[], b: unknown[]): boolean {
9
9
  if (a.length !== b.length) return true;
10
10
  for (let i = 0; i < a.length; ++i) {
11
11
  if (a[i] !== b[i]) return true;
12
12
  }
13
13
  return false;
14
- }
14
+ }
@@ -1,6 +1,9 @@
1
- /** @import { AggregateNode } from '@uwdata/mosaic-sql' */
1
+ import type { AggregateNode } from '@uwdata/mosaic-sql';
2
2
  import { Query, asTableRef, count, isAggregateExpression, isNode, isNull, max, min, sql } from '@uwdata/mosaic-sql';
3
3
  import { jsType } from './js-type.js';
4
+ import type { Coordinator } from '../Coordinator.js';
5
+ import type { FieldInfoRequest, FieldInfo, Stat, FieldRef, ColumnDescription } from '../types.js';
6
+ import { Table } from '@uwdata/flechette';
4
7
 
5
8
  export const Count = 'count';
6
9
  export const Nulls = 'nulls';
@@ -9,13 +12,7 @@ export const Min = 'min';
9
12
  export const Distinct = 'distinct';
10
13
  export const Stats = { Count, Nulls, Max, Min, Distinct };
11
14
 
12
- /**
13
- * @type {Record<
14
- * import('../types.js').Stat,
15
- * (column: import('../types.js').FieldRef) => AggregateNode
16
- * >}
17
- */
18
- const statMap = {
15
+ const statMap: Record<Stat, (column: FieldRef) => AggregateNode> = {
19
16
  [Count]: count,
20
17
  [Distinct]: column => count(column).distinct(),
21
18
  [Max]: max,
@@ -25,13 +22,13 @@ const statMap = {
25
22
 
26
23
  /**
27
24
  * Get summary stats of the given column
28
- * @param {import('../types.js').FieldInfoRequest} field
29
- * @returns {Query}
25
+ * @param field Field information request
26
+ * @returns Query for field statistics
30
27
  */
31
- function summarize({ table, column, stats }) {
28
+ function summarize({ table, column, stats }: FieldInfoRequest): Query {
32
29
  return Query
33
30
  .from(table)
34
- .select(Array.from(stats, s => ({ [s]: statMap[s](column) })));
31
+ .select(Array.from(stats!, s => ({ [s]: statMap[s](column) })));
35
32
  }
36
33
 
37
34
  /**
@@ -40,27 +37,27 @@ function summarize({ table, column, stats }) {
40
37
  * the function will retrieve and return the table information using `getTableInfo`.
41
38
  * Otherwise, it will query individual field information using `getFieldInfo`
42
39
  * for each field in the `fields` array.
43
- * @param {import('../Coordinator.js').Coordinator} mc A Mosaic coordinator.
44
- * @param {import('../types.js').FieldInfoRequest[]} fields
45
- * @returns {Promise<import('../types.js').FieldInfo[]>}
40
+ * @param mc A Mosaic coordinator.
41
+ * @param fields Array of field information requests.
42
+ * @returns Promise resolving to array of field information.
46
43
  */
47
- export async function queryFieldInfo(mc, fields) {
44
+ export async function queryFieldInfo(mc: Coordinator, fields: FieldInfoRequest[]): Promise<FieldInfo[]> {
48
45
  if (fields.length === 1 && fields[0].column === '*') {
49
46
  return getTableInfo(mc, fields[0].table);
50
47
  } else {
51
48
  return (await Promise
52
49
  .all(fields.map(f => getFieldInfo(mc, f))))
53
- .filter(x => x);
50
+ .filter((x): x is FieldInfo => x !== undefined);
54
51
  }
55
52
  }
56
53
 
57
54
  /**
58
55
  * Get information about a single field of a table.
59
- * @param {import('../Coordinator.js').Coordinator} mc A Mosaic coordinator.
60
- * @param {import('../types.js').FieldInfoRequest} field
61
- * @returns {Promise<import('../types.js').FieldInfo>}
56
+ * @param mc A Mosaic coordinator.
57
+ * @param field Field information request.
58
+ * @returns Promise resolving to field information.
62
59
  */
63
- async function getFieldInfo(mc, { table, column, stats }) {
60
+ async function getFieldInfo(mc: Coordinator, { table, column, stats }: FieldInfoRequest): Promise<FieldInfo> {
64
61
  // generate and issue a query for field metadata info
65
62
  // use GROUP BY ALL to differentiate & consolidate aggregates
66
63
  const q = Query
@@ -68,9 +65,10 @@ async function getFieldInfo(mc, { table, column, stats }) {
68
65
  .select({ column })
69
66
  .groupby(isNode(column) && isAggregateExpression(column) ? sql`ALL` : []);
70
67
 
71
- /** @type {import('../types.js').ColumnDescription[]} */
72
- const [desc] = Array.from(await mc.query(Query.describe(q)));
73
- const info = {
68
+ const [desc] = Array.from(
69
+ await mc.query(Query.describe(q)) as Table
70
+ ) as ColumnDescription[];
71
+ const info: FieldInfo = {
74
72
  table,
75
73
  column: `${column}`,
76
74
  sqlType: desc.column_type,
@@ -85,7 +83,7 @@ async function getFieldInfo(mc, { table, column, stats }) {
85
83
  const [result] = await mc.query(
86
84
  summarize({ table, column, stats }),
87
85
  { persist: true }
88
- );
86
+ ) as Table;
89
87
 
90
88
  // extract summary stats, copy to field info, and return
91
89
  return Object.assign(info, result);
@@ -93,13 +91,14 @@ async function getFieldInfo(mc, { table, column, stats }) {
93
91
 
94
92
  /**
95
93
  * Get information about the fields of a table.
96
- * @param {import('../Coordinator.js').Coordinator} mc A Mosaic coordinator.
97
- * @param {string} table The table name.
98
- * @returns {Promise<import('../types.js').FieldInfo[]>}
94
+ * @param mc A Mosaic coordinator.
95
+ * @param table The table name.
96
+ * @returns Promise resolving to array of field information.
99
97
  */
100
- async function getTableInfo(mc, table) {
101
- /** @type {import('../types.js').ColumnDescription[]} */
102
- const result = Array.from(await mc.query(`DESCRIBE ${asTableRef(table)}`));
98
+ async function getTableInfo(mc: Coordinator, table: string): Promise<FieldInfo[]> {
99
+ const result = Array.from(
100
+ await mc.query(`DESCRIBE ${asTableRef(table)}`) as Table
101
+ ) as ColumnDescription[];
103
102
  return result.map(desc => ({
104
103
  table,
105
104
  column: desc.column_name,
@@ -107,4 +106,4 @@ async function getTableInfo(mc, table) {
107
106
  type: jsType(desc.column_type),
108
107
  nullable: desc.null === 'YES'
109
108
  }));
110
- }
109
+ }
@@ -1,5 +1,5 @@
1
1
  // Fowler/Noll/Vo hashing.
2
- export function fnv_hash(v) {
2
+ export function fnv_hash(v: string): number {
3
3
  let a = 2166136261;
4
4
  for (let i = 0, n = v.length; i < n; ++i) {
5
5
  const c = v.charCodeAt(i);
@@ -11,16 +11,16 @@ export function fnv_hash(v) {
11
11
  }
12
12
 
13
13
  // a * 16777619 mod 2**32
14
- function fnv_multiply(a) {
14
+ function fnv_multiply(a: number): number {
15
15
  return a + (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
16
16
  }
17
17
 
18
18
  // See https://web.archive.org/web/20131019013225/http://home.comcast.net/~bretm/hash/6.html
19
- function fnv_mix(a) {
19
+ function fnv_mix(a: number): number {
20
20
  a += a << 13;
21
21
  a ^= a >>> 7;
22
22
  a += a << 3;
23
23
  a ^= a >>> 17;
24
24
  a += a << 5;
25
25
  return a & 0xffffffff;
26
- }
26
+ }
@@ -0,0 +1,11 @@
1
+ import type { Activatable } from '../types.js';
2
+
3
+ /**
4
+ * Test if a value implements the Activatable interface.
5
+ * @param value The value to test.
6
+ * @returns True if value implements Activatable interface.
7
+ */
8
+ export function isActivatable(value: unknown): value is Activatable {
9
+ // @ts-expect-error check properties of unknown value
10
+ return typeof value?.activate === 'function' && value.activate.length === 0;
11
+ }
@@ -0,0 +1,12 @@
1
+ import type { Table } from '@uwdata/flechette';
2
+
3
+ /**
4
+ * Test if a value is a Flechette Arrow table.
5
+ * We use a "duck typing" approach and check for a getChild function.
6
+ * @param values The value to test
7
+ * @returns true if the value duck types as Arrow data
8
+ */
9
+ export function isArrowTable(values: unknown): values is Table {
10
+ // @ts-expect-error check property of unknown value
11
+ return typeof values?.getChild === 'function';
12
+ }
@@ -1,10 +1,12 @@
1
+ import type { JSType } from '../types.js';
2
+
1
3
  /**
2
4
  * Maps a SQL data type to its corresponding JavaScript type.
3
- * @param {string} type The name of a SQL data type
4
- * @returns {import('../types.js').JSType} The corresponding JavaScript type name
5
- * @throws {Error} Throws an error if the given SQL type name is unsupported or unrecognized.
5
+ * @param type The name of a SQL data type
6
+ * @returns The corresponding JavaScript type name
7
+ * @throws Throws an error if the given SQL type name is unsupported or unrecognized.
6
8
  */
7
- export function jsType(type) {
9
+ export function jsType(type: string): JSType {
8
10
  switch (type) {
9
11
  case 'BIGINT':
10
12
  case 'HUGEINT':
@@ -52,4 +54,4 @@ export function jsType(type) {
52
54
  }
53
55
  throw new Error(`Unsupported type: ${type}`);
54
56
  }
55
- }
57
+ }
@@ -1,60 +1,72 @@
1
- export class PriorityQueue {
1
+ interface ListNode<T> {
2
+ item: T;
3
+ next: ListNode<T> | null;
4
+ }
5
+
6
+ interface List<T> {
7
+ head: ListNode<T> | null;
8
+ tail: ListNode<T> | null;
9
+ }
10
+
11
+ export class PriorityQueue<T = unknown> {
12
+ private queue: List<T>[];
13
+
2
14
  /**
3
15
  * Create a new priority queue instance.
4
- * @param {number} ranks An integer number of rank-order priority levels.
16
+ * @param ranks An integer number of rank-order priority levels.
5
17
  */
6
- constructor(ranks) {
18
+ constructor(ranks: number) {
7
19
  // one list for each integer priority level
8
20
  this.queue = Array.from(
9
- { length: ranks },
10
- () => ({ head: null, tail: null })
11
- );
21
+ { length: ranks },
22
+ (): List<T> => ({ head: null, tail: null })
23
+ );
12
24
  }
13
25
 
14
26
  /**
15
27
  * Indicate if the queue is empty.
16
- * @returns {boolean} true if empty, false otherwise.
28
+ * @returns true if empty, false otherwise.
17
29
  */
18
- isEmpty() {
30
+ isEmpty(): boolean {
19
31
  return this.queue.every(list => !list.head);
20
32
  }
21
33
 
22
34
  /**
23
35
  * Insert an item into the queue with a given priority rank.
24
- * @param {*} item The item to add.
25
- * @param {number} rank The integer priority rank.
36
+ * @param item The item to add.
37
+ * @param rank The integer priority rank.
26
38
  * Priority ranks are integers starting at zero.
27
39
  * Lower ranks indicate higher priority.
28
40
  */
29
- insert(item, rank) {
41
+ insert(item: T, rank: number): void {
30
42
  const list = this.queue[rank];
31
43
  if (!list) {
32
44
  throw new Error(`Invalid queue priority rank: ${rank}`);
33
45
  }
34
46
 
35
- const node = { item, next: null };
47
+ const node: ListNode<T> = { item, next: null };
36
48
  if (list.head === null) {
37
49
  list.head = list.tail = node;
38
50
  } else {
39
- list.tail = list.tail.next = node;
51
+ list.tail = list.tail!.next = node;
40
52
  }
41
53
  }
42
54
 
43
55
  /**
44
56
  * Remove a set of items from the queue, regardless of priority rank.
45
57
  * If a provided item is not in the queue it will be ignored.
46
- * @param {(item: *) => boolean} test A predicate function to test
58
+ * @param test A predicate function to test
47
59
  * if an item should be removed (true to drop, false to keep).
48
60
  */
49
- remove(test) {
61
+ remove(test: (item: T) => boolean): void {
50
62
  for (const list of this.queue) {
51
63
  let { head, tail } = list;
52
- for (let prev = null, curr = head; curr; prev = curr, curr = curr.next) {
64
+ for (let prev: ListNode<T> | null = null, curr = head; curr; prev = curr, curr = curr.next) {
53
65
  if (test(curr.item)) {
54
66
  if (curr === head) {
55
67
  head = curr.next;
56
68
  } else {
57
- prev.next = curr.next;
69
+ prev!.next = curr.next;
58
70
  }
59
71
  if (curr === tail) tail = prev || head;
60
72
  }
@@ -66,10 +78,10 @@ export class PriorityQueue {
66
78
 
67
79
  /**
68
80
  * Remove and return the next highest priority item.
69
- * @returns {*} The next item in the queue,
81
+ * @returns The next item in the queue,
70
82
  * or undefined if this queue is empty.
71
83
  */
72
- next() {
84
+ next(): T | undefined {
73
85
  for (const list of this.queue) {
74
86
  const { head } = list;
75
87
  if (head !== null) {
@@ -81,4 +93,4 @@ export class PriorityQueue {
81
93
  }
82
94
  }
83
95
  }
84
- }
96
+ }