@uwdata/mosaic-core 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/LICENSE +47 -0
  2. package/README.md +0 -1
  3. package/dist/src/Coordinator.d.ts +159 -0
  4. package/dist/src/Coordinator.d.ts.map +1 -0
  5. package/dist/src/Coordinator.js +250 -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 +214 -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 +322 -0
  26. package/dist/src/Selection.js.map +1 -0
  27. package/dist/src/SelectionClause.d.ts +222 -0
  28. package/dist/src/SelectionClause.d.ts.map +1 -0
  29. package/dist/src/SelectionClause.js +168 -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 +56 -0
  44. package/dist/src/connectors/wasm.d.ts.map +1 -0
  45. package/dist/src/connectors/wasm.js +116 -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/{src → dist/src}/index.js +8 -11
  50. package/dist/src/index.js.map +1 -0
  51. package/dist/src/make-client.d.ts +33 -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 +17 -11
  132. package/src/Coordinator.ts +396 -0
  133. package/src/{MosaicClient.js → MosaicClient.ts} +50 -43
  134. package/src/{Param.js → Param.ts} +29 -28
  135. package/src/{QueryConsolidator.js → QueryConsolidator.ts} +85 -62
  136. package/src/{QueryManager.js → QueryManager.ts} +61 -54
  137. package/src/Selection.ts +391 -0
  138. package/src/SelectionClause.ts +357 -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} +52 -63
  143. package/src/index.ts +42 -0
  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} +30 -31
  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
@@ -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,19 +95,19 @@ 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 (
86
- query._orderby.length || query._where.length ||
87
- query._qualify.length || query._having.length
106
+ query._where.length || query._qualify.length || query._having.length ||
107
+ query._orderby.length || query._distinct
88
108
  ) {
89
- // do not try to analyze if query includes clauses
90
- // that may refer to *derived* columns we can't resolve
109
+ // bail if query includes clauses that may refer to *derived* columns
110
+ // that we can't resolve. also do not consolidate distinct queries
91
111
  return sql;
92
112
  }
93
113
 
@@ -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
+ }
@@ -1,5 +1,5 @@
1
- /** @import { Connector } from './connectors/Connector.js' */
2
- /** @import { Cache, Logger } from './types.js' */
1
+ import type { Connector } from './connectors/Connector.js';
2
+ import type { Cache, Logger, QueryEntry, QueryRequest } from './types.js';
3
3
  import { consolidator } from './QueryConsolidator.js';
4
4
  import { lruCache, voidCache } from './util/cache.js';
5
5
  import { PriorityQueue } from './util/priority-queue.js';
@@ -9,38 +9,38 @@ import { voidLogger } from './util/void-logger.js';
9
9
  export const Priority = Object.freeze({ High: 0, Normal: 1, Low: 2 });
10
10
 
11
11
  export class QueryManager {
12
- constructor(
13
- maxConcurrentRequests = 32
14
- ) {
15
- /** @type {PriorityQueue} */
12
+ private queue: PriorityQueue<QueryEntry>;
13
+ private db: Connector | null;
14
+ private clientCache: Cache | null;
15
+ private _logger: Logger;
16
+ private _logQueries: boolean;
17
+ private _consolidate: ReturnType<typeof consolidator> | null;
18
+ /** Requests pending with the query manager. */
19
+ public pendingResults: QueryResult[];
20
+ private maxConcurrentRequests: number;
21
+ private pendingExec: boolean;
22
+
23
+ constructor(maxConcurrentRequests: number = 32) {
16
24
  this.queue = new PriorityQueue(3);
17
- /** @type {Connector} */
18
25
  this.db = null;
19
- /** @type {Cache} */
20
26
  this.clientCache = null;
21
- /** @type {Logger} */
22
27
  this._logger = voidLogger();
23
- /** @type {boolean} */
24
28
  this._logQueries = false;
25
- /** @type {ReturnType<typeof consolidator> | null} */
26
29
  this._consolidate = null;
27
- /**
28
- * Requests pending with the query manager.
29
- * @type {QueryResult[]}
30
- */
31
30
  this.pendingResults = [];
32
- /** @type {number} */
33
31
  this.maxConcurrentRequests = maxConcurrentRequests;
34
- /** @type {boolean} */
35
32
  this.pendingExec = false;
36
33
  }
37
34
 
38
- next() {
35
+ next(): void {
39
36
  if (this.queue.isEmpty() || this.pendingResults.length > this.maxConcurrentRequests || this.pendingExec) {
40
37
  return;
41
38
  }
42
39
 
43
- const { request, result } = this.queue.next();
40
+ const entry = this.queue.next();
41
+ if (!entry) return;
42
+
43
+ const { request, result } = entry;
44
44
 
45
45
  this.pendingResults.push(result);
46
46
  if (request.type === 'exec') this.pendingExec = true;
@@ -48,7 +48,7 @@ export class QueryManager {
48
48
  this.submit(request, result).finally(() => {
49
49
  // return from the queue all requests that are ready
50
50
  while (this.pendingResults.length && this.pendingResults[0].state !== QueryState.pending) {
51
- const result = this.pendingResults.shift();
51
+ const result = this.pendingResults.shift()!;
52
52
  if (result.state === QueryState.ready) {
53
53
  result.fulfill();
54
54
  } else if (result.state === QueryState.done) {
@@ -62,29 +62,27 @@ export class QueryManager {
62
62
 
63
63
  /**
64
64
  * Add an entry to the query queue with a priority.
65
- * @param {object} entry The entry to add.
66
- * @param {*} [entry.request] The query request.
67
- * @param {QueryResult} [entry.result] The query result.
68
- * @param {number} priority The query priority, defaults to `Priority.Normal`.
65
+ * @param entry The entry to add.
66
+ * @param priority The query priority, defaults to `Priority.Normal`.
69
67
  */
70
- enqueue(entry, priority = Priority.Normal) {
68
+ enqueue(entry: QueryEntry, priority: number = Priority.Normal): void {
71
69
  this.queue.insert(entry, priority);
72
70
  this.next();
73
71
  }
74
72
 
75
73
  /**
76
74
  * Submit the query to the connector.
77
- * @param {*} request The request.
78
- * @param {QueryResult} result The query result.
75
+ * @param request The request.
76
+ * @param result The query result.
79
77
  */
80
- async submit(request, result) {
78
+ async submit(request: QueryRequest, result: QueryResult): Promise<void> {
81
79
  try {
82
80
  const { query, type, cache = false, options } = request;
83
81
  const sql = query ? `${query}` : null;
84
82
 
85
83
  // check query cache
86
84
  if (cache) {
87
- const cached = this.clientCache.get(sql);
85
+ const cached = this.clientCache!.get(sql!);
88
86
  if (cached) {
89
87
  const data = await cached;
90
88
  this._logger.debug('Cache');
@@ -99,12 +97,13 @@ export class QueryManager {
99
97
  this._logger.debug('Query', { type, sql, ...options });
100
98
  }
101
99
 
102
- const promise = this.db.query({ type, sql, ...options });
103
- if (cache) this.clientCache.set(sql, promise);
100
+ // @ts-expect-error type may be exec | json | arrow
101
+ const promise = this.db!.query({ type, sql: sql!, ...options });
102
+ if (cache) this.clientCache!.set(sql!, promise);
104
103
 
105
104
  const data = await promise;
106
105
 
107
- if (cache) this.clientCache.set(sql, data);
106
+ if (cache) this.clientCache!.set(sql!, data);
108
107
 
109
108
  this._logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
110
109
  result.ready(type === 'exec' ? null : data);
@@ -115,10 +114,12 @@ export class QueryManager {
115
114
 
116
115
  /**
117
116
  * Get or set the current query cache.
118
- * @param {Cache | boolean} [value]
119
- * @returns {Cache}
117
+ * @param value Cache value to set
118
+ * @returns Current cache
120
119
  */
121
- cache(value) {
120
+ cache(): Cache | null;
121
+ cache(value: Cache | boolean): Cache;
122
+ cache(value?: Cache | boolean): Cache | null {
122
123
  return value !== undefined
123
124
  ? (this.clientCache = value === true ? lruCache() : (value || voidCache()))
124
125
  : this.clientCache;
@@ -126,38 +127,44 @@ export class QueryManager {
126
127
 
127
128
  /**
128
129
  * Get or set the current logger.
129
- * @param {Logger} [value]
130
- * @returns {Logger}
130
+ * @param value Logger to set
131
+ * @returns Current logger
131
132
  */
132
- logger(value) {
133
+ logger(): Logger;
134
+ logger(value: Logger): Logger;
135
+ logger(value?: Logger): Logger {
133
136
  return value ? (this._logger = value) : this._logger;
134
137
  }
135
138
 
136
139
  /**
137
140
  * Get or set if queries should be logged.
138
- * @param {boolean} [value]
139
- * @returns {boolean}
141
+ * @param value Whether to log queries
142
+ * @returns Current logging state
140
143
  */
141
- logQueries(value) {
144
+ logQueries(): boolean;
145
+ logQueries(value: boolean): boolean;
146
+ logQueries(value?: boolean): boolean {
142
147
  return value !== undefined ? this._logQueries = !!value : this._logQueries;
143
148
  }
144
149
 
145
150
  /**
146
151
  * Get or set the database connector.
147
- * @param {Connector} [connector]
148
- * @returns {Connector}
152
+ * @param connector Connector to set
153
+ * @returns Current connector
149
154
  */
150
- connector(connector) {
155
+ connector(): Connector | null;
156
+ connector(connector: Connector): Connector;
157
+ connector(connector?: Connector): Connector | null {
151
158
  return connector ? (this.db = connector) : this.db;
152
159
  }
153
160
 
154
161
  /**
155
162
  * Indicate if query consolidation should be performed.
156
- * @param {boolean} flag
163
+ * @param flag Whether to enable consolidation
157
164
  */
158
- consolidate(flag) {
165
+ consolidate(flag: boolean): void {
159
166
  if (flag && !this._consolidate) {
160
- this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache);
167
+ this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache!);
161
168
  } else if (!flag && this._consolidate) {
162
169
  this._consolidate = null;
163
170
  }
@@ -165,11 +172,11 @@ export class QueryManager {
165
172
 
166
173
  /**
167
174
  * Request a query result.
168
- * @param {*} request The request.
169
- * @param {number} priority The query priority, defaults to `Priority.Normal`.
170
- * @returns {QueryResult} A query result promise.
175
+ * @param request The request.
176
+ * @param priority The query priority, defaults to `Priority.Normal`.
177
+ * @returns A query result promise.
171
178
  */
172
- request(request, priority = Priority.Normal) {
179
+ request(request: QueryRequest, priority: number = Priority.Normal): QueryResult {
173
180
  const result = new QueryResult();
174
181
  const entry = { request, result };
175
182
  if (this._consolidate) {
@@ -180,7 +187,7 @@ export class QueryManager {
180
187
  return result;
181
188
  }
182
189
 
183
- cancel(requests) {
190
+ cancel(requests: QueryResult[]): void {
184
191
  const set = new Set(requests);
185
192
  if (set.size) {
186
193
  this.queue.remove(({ result }) => {
@@ -199,7 +206,7 @@ export class QueryManager {
199
206
  }
200
207
  }
201
208
 
202
- clear() {
209
+ clear(): void {
203
210
  this.queue.remove(({ result }) => {
204
211
  result.reject('Cleared');
205
212
  return true;
@@ -210,4 +217,4 @@ export class QueryManager {
210
217
  }
211
218
  this.pendingResults = [];
212
219
  }
213
- }
220
+ }