@uwdata/mosaic-sql 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/mosaic-sql.js +2242 -1064
- package/dist/mosaic-sql.min.js +1 -1
- package/dist/types/ast/aggregate.d.ts +70 -0
- package/dist/types/ast/between-op.d.ts +46 -0
- package/dist/types/ast/binary-op.d.ts +28 -0
- package/dist/types/ast/case.d.ts +68 -0
- package/dist/types/ast/cast.d.ts +21 -0
- package/dist/types/ast/column-param.d.ts +17 -0
- package/dist/types/ast/column-ref.d.ts +39 -0
- package/dist/types/ast/fragment.d.ts +14 -0
- package/dist/types/ast/from.d.ts +21 -0
- package/dist/types/ast/function.d.ts +21 -0
- package/dist/types/ast/in-op.d.ts +21 -0
- package/dist/types/ast/interval.d.ts +21 -0
- package/dist/types/ast/literal.d.ts +15 -0
- package/dist/types/ast/logical-op.d.ts +46 -0
- package/dist/types/ast/node.d.ts +24 -0
- package/dist/types/ast/order-by.d.ts +29 -0
- package/dist/types/ast/param.d.ts +19 -0
- package/dist/types/ast/query.d.ts +268 -0
- package/dist/types/ast/sample.d.ts +42 -0
- package/dist/types/ast/select.d.ts +22 -0
- package/dist/types/ast/table-ref.d.ts +25 -0
- package/dist/types/ast/unary-op.d.ts +39 -0
- package/dist/types/ast/verbatim.d.ts +9 -0
- package/dist/types/ast/window.d.ts +177 -0
- package/dist/types/ast/with.d.ts +22 -0
- package/dist/types/constants.d.ts +38 -0
- package/dist/types/functions/aggregate.d.ts +229 -0
- package/dist/types/functions/case.d.ts +15 -0
- package/dist/types/functions/cast.d.ts +26 -0
- package/dist/types/functions/column.d.ts +9 -0
- package/dist/types/functions/datetime.d.ts +44 -0
- package/dist/types/functions/literal.d.ts +16 -0
- package/dist/types/functions/numeric.d.ts +93 -0
- package/dist/types/functions/operators.d.ts +198 -0
- package/dist/types/functions/order-by.d.ts +17 -0
- package/dist/types/functions/spatial.d.ts +37 -0
- package/dist/types/functions/sql-template-tag.d.ts +16 -0
- package/dist/types/functions/string.d.ts +55 -0
- package/dist/types/functions/table-ref.d.ts +9 -0
- package/dist/types/functions/window.d.ts +87 -0
- package/dist/types/index-types.d.ts +2 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/load/create.d.ts +8 -0
- package/dist/types/load/extension.d.ts +1 -0
- package/dist/types/load/load.d.ts +12 -0
- package/dist/types/load/sql-from.d.ts +11 -0
- package/dist/types/transforms/bin-1d.d.ts +14 -0
- package/dist/types/transforms/bin-2d.d.ts +18 -0
- package/dist/types/transforms/bin-linear-1d.d.ts +9 -0
- package/dist/types/transforms/bin-linear-2d.d.ts +18 -0
- package/dist/types/transforms/line-density.d.ts +23 -0
- package/dist/types/transforms/m4.d.ts +18 -0
- package/dist/types/transforms/scales.d.ts +1 -0
- package/dist/types/types.d.ts +59 -0
- package/dist/types/util/ast.d.ts +60 -0
- package/dist/types/util/function.d.ts +54 -0
- package/dist/types/util/string.d.ts +3 -0
- package/dist/types/util/type-check.d.ts +18 -0
- package/dist/types/visit/recurse.d.ts +28 -0
- package/dist/types/visit/rewrite.d.ts +10 -0
- package/dist/types/visit/visitors.d.ts +33 -0
- package/dist/types/visit/walk.d.ts +7 -0
- package/jsconfig.json +11 -0
- package/package.json +6 -4
- package/src/ast/aggregate.js +164 -0
- package/src/ast/between-op.js +75 -0
- package/src/ast/binary-op.js +40 -0
- package/src/ast/case.js +105 -0
- package/src/ast/cast.js +34 -0
- package/src/ast/column-param.js +29 -0
- package/src/ast/column-ref.js +72 -0
- package/src/ast/fragment.js +26 -0
- package/src/ast/from.js +40 -0
- package/src/ast/function.js +34 -0
- package/src/ast/in-op.js +33 -0
- package/src/ast/interval.js +33 -0
- package/src/ast/literal.js +55 -0
- package/src/ast/logical-op.js +67 -0
- package/src/ast/node.js +29 -0
- package/src/ast/order-by.js +48 -0
- package/src/ast/param.js +35 -0
- package/src/ast/query.js +578 -0
- package/src/ast/sample.js +53 -0
- package/src/ast/select.js +44 -0
- package/src/ast/table-ref.js +44 -0
- package/src/ast/unary-op.js +64 -0
- package/src/ast/verbatim.js +26 -0
- package/src/ast/window.js +290 -0
- package/src/ast/with.js +30 -0
- package/src/constants.js +44 -0
- package/src/functions/aggregate.js +335 -0
- package/src/functions/case.js +21 -0
- package/src/functions/cast.js +39 -0
- package/src/functions/column.js +20 -0
- package/src/functions/datetime.js +65 -0
- package/src/functions/literal.js +22 -0
- package/src/functions/numeric.js +139 -0
- package/src/functions/operators.js +298 -0
- package/src/functions/order-by.js +24 -0
- package/src/functions/spatial.js +56 -0
- package/src/functions/sql-template-tag.js +51 -0
- package/src/functions/string.js +82 -0
- package/src/functions/table-ref.js +14 -0
- package/src/functions/window.js +121 -0
- package/src/index-types.ts +2 -0
- package/src/index.js +57 -155
- package/src/load/create.js +10 -2
- package/src/load/load.js +4 -4
- package/src/load/sql-from.js +7 -6
- package/src/transforms/bin-1d.js +21 -0
- package/src/transforms/bin-2d.js +29 -0
- package/src/transforms/bin-linear-1d.js +26 -0
- package/src/transforms/bin-linear-2d.js +71 -0
- package/src/transforms/line-density.js +113 -0
- package/src/transforms/m4.js +38 -0
- package/src/{scales.js → transforms/scales.js} +31 -17
- package/src/types.ts +96 -0
- package/src/util/ast.js +96 -0
- package/src/util/function.js +78 -0
- package/src/util/string.js +16 -0
- package/src/util/type-check.js +29 -0
- package/src/visit/recurse.js +57 -0
- package/src/visit/rewrite.js +32 -0
- package/src/visit/visitors.js +108 -0
- package/src/visit/walk.js +30 -0
- package/tsconfig.json +12 -0
- package/src/Query.js +0 -593
- package/src/aggregates.js +0 -185
- package/src/cast.js +0 -19
- package/src/datetime.js +0 -31
- package/src/desc.js +0 -13
- package/src/expression.js +0 -170
- package/src/functions.js +0 -25
- package/src/literal.js +0 -6
- package/src/operators.js +0 -54
- package/src/ref.js +0 -109
- package/src/repeat.js +0 -3
- package/src/spatial.js +0 -10
- package/src/to-sql.js +0 -52
- package/src/windows.js +0 -239
package/src/index.js
CHANGED
|
@@ -1,156 +1,58 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from './
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from './
|
|
16
|
-
|
|
17
|
-
export {
|
|
18
|
-
|
|
19
|
-
} from './
|
|
20
|
-
|
|
21
|
-
export {
|
|
22
|
-
|
|
23
|
-
} from './
|
|
24
|
-
|
|
25
|
-
export {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
} from './
|
|
42
|
-
|
|
43
|
-
export {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
argmin,
|
|
47
|
-
arrayAgg,
|
|
48
|
-
avg,
|
|
49
|
-
corr,
|
|
50
|
-
count,
|
|
51
|
-
covariance,
|
|
52
|
-
covarPop,
|
|
53
|
-
entropy,
|
|
54
|
-
first,
|
|
55
|
-
kurtosis,
|
|
56
|
-
mean,
|
|
57
|
-
mad,
|
|
58
|
-
max,
|
|
59
|
-
median,
|
|
60
|
-
min,
|
|
61
|
-
mode,
|
|
62
|
-
last,
|
|
63
|
-
product,
|
|
64
|
-
quantile,
|
|
65
|
-
regrAvgX,
|
|
66
|
-
regrAvgY,
|
|
67
|
-
regrCount,
|
|
68
|
-
regrIntercept,
|
|
69
|
-
regrR2,
|
|
70
|
-
regrSXX,
|
|
71
|
-
regrSXY,
|
|
72
|
-
regrSYY,
|
|
73
|
-
regrSlope,
|
|
74
|
-
skewness,
|
|
75
|
-
stddev,
|
|
76
|
-
stddevPop,
|
|
77
|
-
stringAgg,
|
|
78
|
-
sum,
|
|
79
|
-
variance,
|
|
80
|
-
varPop
|
|
81
|
-
} from './aggregates.js';
|
|
82
|
-
|
|
83
|
-
export {
|
|
84
|
-
cast,
|
|
85
|
-
castDouble,
|
|
86
|
-
castInteger
|
|
87
|
-
} from './cast.js';
|
|
88
|
-
|
|
89
|
-
export {
|
|
90
|
-
epoch_ms,
|
|
91
|
-
dateBin,
|
|
92
|
-
dateMonth,
|
|
93
|
-
dateMonthDay,
|
|
94
|
-
dateDay
|
|
95
|
-
} from './datetime.js';
|
|
96
|
-
|
|
97
|
-
export {
|
|
98
|
-
regexp_matches,
|
|
99
|
-
contains,
|
|
100
|
-
prefix,
|
|
101
|
-
suffix,
|
|
102
|
-
lower,
|
|
103
|
-
upper,
|
|
104
|
-
length,
|
|
105
|
-
isNaN,
|
|
106
|
-
isFinite,
|
|
107
|
-
isInfinite
|
|
108
|
-
} from './functions.js';
|
|
109
|
-
|
|
110
|
-
export {
|
|
111
|
-
centroid,
|
|
112
|
-
centroidX,
|
|
113
|
-
centroidY,
|
|
114
|
-
geojson,
|
|
115
|
-
x,
|
|
116
|
-
y
|
|
117
|
-
} from './spatial.js';
|
|
118
|
-
|
|
119
|
-
export {
|
|
120
|
-
row_number,
|
|
121
|
-
rank,
|
|
122
|
-
dense_rank,
|
|
123
|
-
percent_rank,
|
|
124
|
-
cume_dist,
|
|
125
|
-
ntile,
|
|
126
|
-
lag,
|
|
127
|
-
lead,
|
|
128
|
-
first_value,
|
|
129
|
-
last_value,
|
|
130
|
-
nth_value
|
|
131
|
-
} from './windows.js';
|
|
132
|
-
|
|
133
|
-
export {
|
|
134
|
-
Query,
|
|
135
|
-
isQuery,
|
|
136
|
-
isDescribeQuery
|
|
137
|
-
} from './Query.js';
|
|
138
|
-
|
|
139
|
-
export {
|
|
140
|
-
toSQL,
|
|
141
|
-
literalToSQL
|
|
142
|
-
} from './to-sql.js';
|
|
143
|
-
|
|
144
|
-
export {
|
|
145
|
-
scaleTransform
|
|
146
|
-
} from './scales.js';
|
|
147
|
-
|
|
148
|
-
export { create } from './load/create.js';
|
|
1
|
+
export { AggregateNode } from './ast/aggregate.js';
|
|
2
|
+
export { BetweenOpNode, NotBetweenOpNode } from './ast/between-op.js'
|
|
3
|
+
export { BinaryOpNode } from './ast/binary-op.js';
|
|
4
|
+
export { CaseNode, WhenNode } from './ast/case.js';
|
|
5
|
+
export { CastNode } from './ast/cast.js';
|
|
6
|
+
export { ColumnParamNode } from './ast/column-param.js';
|
|
7
|
+
export { ColumnRefNode, ColumnNameRefNode, isColumnRef } from './ast/column-ref.js';
|
|
8
|
+
export { FragmentNode } from './ast/fragment.js';
|
|
9
|
+
export { FromClauseNode } from './ast/from.js';
|
|
10
|
+
export { FunctionNode } from './ast/function.js';
|
|
11
|
+
export { InOpNode } from './ast/in-op.js';
|
|
12
|
+
export { IntervalNode } from './ast/interval.js';
|
|
13
|
+
export { LiteralNode } from './ast/literal.js';
|
|
14
|
+
export { AndNode, OrNode } from './ast/logical-op.js';
|
|
15
|
+
export { SQLNode, ExprNode, isNode } from './ast/node.js';
|
|
16
|
+
export { OrderByNode } from './ast/order-by.js';
|
|
17
|
+
export { ParamNode } from './ast/param.js';
|
|
18
|
+
export { DescribeQuery, Query, SelectQuery, SetOperation, isDescribeQuery, isQuery, isSelectQuery } from './ast/query.js';
|
|
19
|
+
export { SampleClauseNode } from './ast/sample.js';
|
|
20
|
+
export { SelectClauseNode } from './ast/select.js';
|
|
21
|
+
export { TableRefNode, isTableRef } from './ast/table-ref.js';
|
|
22
|
+
export { UnaryOpNode, UnaryPosftixOpNode } from './ast/unary-op.js';
|
|
23
|
+
export { VerbatimNode } from './ast/verbatim.js';
|
|
24
|
+
export { WindowClauseNode, WindowDefNode, WindowFrameNode, WindowFunctionNode, WindowNode } from './ast/window.js';
|
|
25
|
+
export { WithClauseNode } from './ast/with.js';
|
|
26
|
+
|
|
27
|
+
export { argmax, argmin, arrayAgg, avg, corr, count, covariance, covarPop, entropy, first, kurtosis, mad, max, median, min, mode, last, product, quantile, regrAvgX, regrAvgY, regrCount, regrIntercept, regrR2, regrSXX, regrSXY, regrSYY, regrSlope, skewness, stddev, stddevPop, stringAgg, sum, variance, varPop } from './functions/aggregate.js';
|
|
28
|
+
export { cond } from './functions/case.js';
|
|
29
|
+
export { cast, float32, float64, int32 } from './functions/cast.js';
|
|
30
|
+
export { column } from './functions/column.js';
|
|
31
|
+
export { dateBin, dateMonth, dateMonthDay, dateDay, epoch_ms, interval } from './functions/datetime.js';
|
|
32
|
+
export { literal } from './functions/literal.js';
|
|
33
|
+
export { abs, ceil, exp, floor, greatest, isFinite, isInfinite, isNaN, least, ln, log, round, sign, sqrt, trunc } from './functions/numeric.js';
|
|
34
|
+
export { and, or, not, isNull, isNotNull, bitNot, bitAnd, bitOr, bitLeft, bitRight, add, sub, mul, div, idiv, mod, pow, eq, neq, lt, gt, lte, gte, isDistinct, isNotDistinct, isBetween, isNotBetween, isIn } from './functions/operators.js';
|
|
35
|
+
export { asc, desc } from './functions/order-by.js';
|
|
36
|
+
export { geojson, x, y, centroid, centroidX, centroidY } from './functions/spatial.js';
|
|
37
|
+
export { sql } from './functions/sql-template-tag.js';
|
|
38
|
+
export { regexp_matches, contains, prefix, suffix, lower, upper, length } from './functions/string.js';
|
|
39
|
+
export { cume_dist, dense_rank, first_value, lag, last_value, lead, nth_value, ntile, percent_rank, rank, row_number } from './functions/window.js';
|
|
40
|
+
|
|
41
|
+
export { rewrite } from './visit/rewrite.js';
|
|
42
|
+
export { collectAggregates, collectColumns, collectParams, isAggregateExpression } from './visit/visitors.js';
|
|
43
|
+
export { walk } from './visit/walk.js';
|
|
44
|
+
|
|
45
|
+
export { createTable, createSchema } from './load/create.js';
|
|
149
46
|
export { loadExtension } from './load/extension.js';
|
|
150
|
-
export {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
} from './
|
|
47
|
+
export { loadCSV, loadJSON, loadObjects, loadParquet, loadSpatial } from './load/load.js';
|
|
48
|
+
|
|
49
|
+
export { bin1d } from './transforms/bin-1d.js';
|
|
50
|
+
export { bin2d } from './transforms/bin-2d.js';
|
|
51
|
+
export { binLinear1d } from './transforms/bin-linear-1d.js';
|
|
52
|
+
export { binLinear2d } from './transforms/bin-linear-2d.js';
|
|
53
|
+
export { lineDensity } from './transforms/line-density.js';
|
|
54
|
+
export { m4 } from './transforms/m4.js';
|
|
55
|
+
export { scaleTransform } from './transforms/scales.js';
|
|
56
|
+
|
|
57
|
+
export { asLiteral, asNode, asTableRef, asVerbatim, over } from './util/ast.js';
|
|
58
|
+
export { isParamLike } from './util/type-check.js';
|
package/src/load/create.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function createTable(name, query, {
|
|
2
2
|
replace = false,
|
|
3
|
-
temp =
|
|
3
|
+
temp = false,
|
|
4
4
|
view = false
|
|
5
5
|
} = {}) {
|
|
6
6
|
return 'CREATE'
|
|
@@ -10,3 +10,11 @@ export function create(name, query, {
|
|
|
10
10
|
+ (replace ? ' ' : ' IF NOT EXISTS ')
|
|
11
11
|
+ name + ' AS ' + query;
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
export function createSchema(name, {
|
|
15
|
+
strict = false
|
|
16
|
+
} = {}) {
|
|
17
|
+
return 'CREATE SCHEMA '
|
|
18
|
+
+ (strict ? '' : 'IF NOT EXISTS ')
|
|
19
|
+
+ name;
|
|
20
|
+
}
|
package/src/load/load.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createTable } from './create.js';
|
|
2
2
|
import { sqlFrom } from './sql-from.js';
|
|
3
3
|
|
|
4
4
|
export function load(method, tableName, fileName, options = {}, defaults = {}) {
|
|
@@ -7,7 +7,7 @@ export function load(method, tableName, fileName, options = {}, defaults = {}) {
|
|
|
7
7
|
const read = `${method}('${fileName}'${params ? ', ' + params : ''})`;
|
|
8
8
|
const filter = where ? ` WHERE ${where}` : '';
|
|
9
9
|
const query = `SELECT ${select.join(', ')} FROM ${read}${filter}`;
|
|
10
|
-
return
|
|
10
|
+
return createTable(tableName, query, { view, temp, replace });
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export function loadCSV(tableName, fileName, options) {
|
|
@@ -15,7 +15,7 @@ export function loadCSV(tableName, fileName, options) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function loadJSON(tableName, fileName, options) {
|
|
18
|
-
return load('read_json', tableName, fileName, options, { auto_detect: true,
|
|
18
|
+
return load('read_json', tableName, fileName, options, { auto_detect: true, format: 'auto' });
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function loadParquet(tableName, fileName, options) {
|
|
@@ -51,7 +51,7 @@ export function loadObjects(tableName, data, options = {}) {
|
|
|
51
51
|
const query = select.length === 1 && select[0] === '*'
|
|
52
52
|
? values
|
|
53
53
|
: `SELECT ${select} FROM ${values}`;
|
|
54
|
-
return
|
|
54
|
+
return createTable(tableName, query, opt);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function parameters(options) {
|
package/src/load/sql-from.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { asLiteral } from '../util/ast.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Create a SQL query that embeds the given data for loading.
|
|
5
|
-
* @param {*} data The dataset
|
|
6
|
-
* @param {object} [options] Loading options
|
|
7
|
-
* @param {string[]|object} [options.columns] The columns to include
|
|
8
|
-
*
|
|
5
|
+
* @param {*} data The dataset as an array of objects.
|
|
6
|
+
* @param {object} [options] Loading options.
|
|
7
|
+
* @param {string[]|object} [options.columns] The columns to include.
|
|
8
|
+
* If not specified, the keys of the first data object are used.
|
|
9
|
+
* @returns {string} SQL query string to load data.
|
|
9
10
|
*/
|
|
10
11
|
export function sqlFrom(data, {
|
|
11
12
|
columns = Object.keys(data?.[0] || {})
|
|
@@ -22,7 +23,7 @@ export function sqlFrom(data, {
|
|
|
22
23
|
}
|
|
23
24
|
const subq = [];
|
|
24
25
|
for (const datum of data) {
|
|
25
|
-
const sel = keys.map(k => `${
|
|
26
|
+
const sel = keys.map(k => `${asLiteral(datum[k])} AS "${columns[k]}"`);
|
|
26
27
|
subq.push(`(SELECT ${sel.join(', ')})`);
|
|
27
28
|
}
|
|
28
29
|
return subq.join(' UNION ALL ');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { float64 } from '../functions/cast.js';
|
|
2
|
+
import { mul, sub } from '../functions/operators.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compute binned values over a one-dimensional extent.
|
|
6
|
+
* @param {import('../types.js').ExprValue} x The expression to bin.
|
|
7
|
+
* The expression must return numeric values. For example, to bin
|
|
8
|
+
* datetime values, the input expression might map them to numeric
|
|
9
|
+
* values such as milliseconds since the epoch.
|
|
10
|
+
* @param {number} lo The low value of the bin extent.
|
|
11
|
+
* @param {number} hi The high value of the bin extent.
|
|
12
|
+
* @param {number} bins The integer number of bins to use within the
|
|
13
|
+
* defined binning extent.
|
|
14
|
+
* @param {boolean} [reverse] Flag indicating if bins should be
|
|
15
|
+
* produced in reverse order from *hi* to *lo* (default `false`).
|
|
16
|
+
*/
|
|
17
|
+
export function bin1d(x, lo, hi, bins, reverse) {
|
|
18
|
+
const diff = reverse ? sub(hi, float64(x)) : sub(float64(x), lo);
|
|
19
|
+
const scale = hi === lo ? 0 : bins / (hi - lo);
|
|
20
|
+
return scale ? mul(diff, float64(scale)) : diff;
|
|
21
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SelectQuery } from '../ast/query.js';
|
|
2
|
+
import { int32 } from '../functions/cast.js';
|
|
3
|
+
import { floor } from '../functions/numeric.js';
|
|
4
|
+
import { add, mul } from '../functions/operators.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Perform aggregation over a binned 2D domain. This method takes expressions
|
|
8
|
+
* for the (non-truncated) x and y bin values; these expressions should be
|
|
9
|
+
* in units of grid indices, but can contain fractional components. The
|
|
10
|
+
* resulting query performs grouping and aggregation over the binned domain,
|
|
11
|
+
* and uses a 2D integer bin index of the form (xbin + num_xbins * ybin).
|
|
12
|
+
* @param {SelectQuery} q The input query. The FROM and WHERE clauses should
|
|
13
|
+
* be added to the query separately, either before or after this method.
|
|
14
|
+
* @param {import('../types.js').ExprValue} xp The x bin expression.
|
|
15
|
+
* @param {import('../types.js').ExprValue} yp The y bin expression.
|
|
16
|
+
* @param {Record<string, import('../types.js').ExprValue>} aggs Named
|
|
17
|
+
* aggregate expressions over bins.
|
|
18
|
+
* @param {number} xn The number of bins along the x dimension
|
|
19
|
+
* @param {string[]} groupby Group by expressions.
|
|
20
|
+
* @returns {SelectQuery} The input query, with binning expressions added.
|
|
21
|
+
*/
|
|
22
|
+
export function bin2d(q, xp, yp, aggs, xn, groupby) {
|
|
23
|
+
return q
|
|
24
|
+
.select({
|
|
25
|
+
index: add(int32(floor(xp)), mul(int32(floor(yp)), xn)),
|
|
26
|
+
...aggs
|
|
27
|
+
})
|
|
28
|
+
.groupby('index', groupby);
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Query } from '../ast/query.js';
|
|
2
|
+
import { sum } from '../functions/aggregate.js';
|
|
3
|
+
import { int32 } from '../functions/cast.js';
|
|
4
|
+
import { floor } from '../functions/numeric.js';
|
|
5
|
+
import { add, mul, neq, sub } from '../functions/operators.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Perform linear binning in one dimension.
|
|
9
|
+
* @param {import('../ast/query.js').SelectQuery} query The base query to bin.
|
|
10
|
+
* @param {import('../types.js').ExprValue} x The expression to bin.
|
|
11
|
+
* @param {import('../types.js').ExprValue} [weight] The expression to weight by.
|
|
12
|
+
* @returns {Query}
|
|
13
|
+
*/
|
|
14
|
+
export function binLinear1d(query, x, weight) {
|
|
15
|
+
const w = weight ? (x => mul(x, weight)) : (x => x);
|
|
16
|
+
const p0 = floor(x);
|
|
17
|
+
const p1 = add(p0, 1);
|
|
18
|
+
return Query
|
|
19
|
+
.from(Query.unionAll(
|
|
20
|
+
query.clone().select({ i: int32(p0), w: w(sub(p1, x)) }),
|
|
21
|
+
query.clone().select({ i: int32(p1), w: w(sub(x, p0)) })
|
|
22
|
+
))
|
|
23
|
+
.select({ index: 'i', density: sum('w') })
|
|
24
|
+
.groupby('index')
|
|
25
|
+
.having(neq('density', 0));
|
|
26
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Query, SelectQuery } from '../ast/query.js';
|
|
2
|
+
import { sum } from '../functions/aggregate.js';
|
|
3
|
+
import { int32 } from '../functions/cast.js';
|
|
4
|
+
import { floor } from '../functions/numeric.js';
|
|
5
|
+
import { add, mul, neq, sub } from '../functions/operators.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Identity function.
|
|
9
|
+
* @template T
|
|
10
|
+
* @param {T} x
|
|
11
|
+
* @returns {T}
|
|
12
|
+
*/
|
|
13
|
+
function identity(x) {
|
|
14
|
+
return x;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Compute densities over a 2D domain using linear binning. The weight of
|
|
19
|
+
* each data point is linearly distributed over adjacent bins, providing
|
|
20
|
+
* a better base for subsequent kernel density estimation. This method takes
|
|
21
|
+
* expressions for the (non-truncated) x and y bin values; these expressions
|
|
22
|
+
* should be in units of grid indices, but can contain fractional components.
|
|
23
|
+
* @param {SelectQuery} q The input query. The FROM and WHERE clauses should
|
|
24
|
+
* be added to the query separately, before this method is invoked.
|
|
25
|
+
* @param {import('../types.js').ExprValue} xp The x grid bin expression
|
|
26
|
+
* @param {import('../types.js').ExprValue} yp The y grid bin expression
|
|
27
|
+
* @param {import('../types.js').ExprValue | undefined} weight Point weights.
|
|
28
|
+
* @param {number} xn The number of x grid bins.
|
|
29
|
+
* @param {string[]} groupby Group by expressions.
|
|
30
|
+
* @returns {SelectQuery} A linear binning query for bin `index` and
|
|
31
|
+
* aggregate `density` columns, in addition to any group by expressions.
|
|
32
|
+
*/
|
|
33
|
+
export function binLinear2d(q, xp, yp, weight, xn, groupby) {
|
|
34
|
+
|
|
35
|
+
const w = weight ? x => mul(x, weight) : identity;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {import('../types.js').ExprValue} i
|
|
39
|
+
* @param {import('../types.js').ExprValue} w
|
|
40
|
+
*/
|
|
41
|
+
const subq = (i, w) => q.clone().select({ xp, yp, i, w });
|
|
42
|
+
/**
|
|
43
|
+
* @param {import('../types.js').ExprValue} x
|
|
44
|
+
* @param {import('../types.js').ExprValue} y
|
|
45
|
+
*/
|
|
46
|
+
const index = (x, y) => add(x, mul(y, xn));
|
|
47
|
+
|
|
48
|
+
const xu = int32(floor(xp));
|
|
49
|
+
const yu = int32(floor(yp));
|
|
50
|
+
const xv = add(xu, 1);
|
|
51
|
+
const yv = add(yu, 1);
|
|
52
|
+
const xpu = sub(xp, xu);
|
|
53
|
+
const xvp = sub(xv, xp);
|
|
54
|
+
const ypu = sub(yp, yu);
|
|
55
|
+
const yvp = sub(yv, yp);
|
|
56
|
+
|
|
57
|
+
return Query
|
|
58
|
+
.from(Query.unionAll(
|
|
59
|
+
// grid[xu + yu * xn] += (xv - xp) * (yv - yp) * wi
|
|
60
|
+
subq(index(xu, yu), w(mul(xvp, yvp))),
|
|
61
|
+
// grid[xu + yv * xn] += (xv - xp) * (yp - yu) * wi
|
|
62
|
+
subq(index(xu, yv), w(mul(xvp, ypu))),
|
|
63
|
+
// grid[xv + yu * xn] += (xp - xu) * (yv - yp) * wi
|
|
64
|
+
subq(index(xv, yu), w(mul(xpu, yvp))),
|
|
65
|
+
// grid[xv + yv * xn] += (xp - xu) * (yp - yu) * wi
|
|
66
|
+
subq(index(xv, yv), w(mul(xpu, ypu)))
|
|
67
|
+
))
|
|
68
|
+
.select({ index: 'i', density: sum('w') }, groupby)
|
|
69
|
+
.groupby('index', groupby)
|
|
70
|
+
.having(neq('density', 0));
|
|
71
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Query, SelectQuery } from '../ast/query.js';
|
|
2
|
+
import { count, max, sum } from '../functions/aggregate.js';
|
|
3
|
+
import { int32 } from '../functions/cast.js';
|
|
4
|
+
import { abs, floor, greatest, round, sign } from '../functions/numeric.js';
|
|
5
|
+
import { add, div, gt, isNull, lt, lte, mul, or, sub } from '../functions/operators.js';
|
|
6
|
+
import { asc } from '../functions/order-by.js';
|
|
7
|
+
import { sql } from '../functions/sql-template-tag.js';
|
|
8
|
+
import { lead } from '../functions/window.js';
|
|
9
|
+
import { over } from '../util/ast.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compute line segment densities over a gridded 2D domain. The returned
|
|
13
|
+
* query uses multiple subqueries (CTEs) to identify line segment end point
|
|
14
|
+
* pairs, perform line rasterization in-database, normalize arc lengths,
|
|
15
|
+
* and then sum results for all line series to produce a density map.
|
|
16
|
+
* Based on Moritz and Fisher's work: https://arxiv.org/abs/1808.06019
|
|
17
|
+
* @param {SelectQuery} q The base query over the data.
|
|
18
|
+
* @param {import('../types.js').ExprValue} x Bin expression for x dimension.
|
|
19
|
+
* Provides gridded x coordinates, potentially with a fractional component.
|
|
20
|
+
* @param {import('../types.js').ExprValue} y Bin expression for x dimension.
|
|
21
|
+
* Provides gridded y coordinates, potentially with a fractional component.
|
|
22
|
+
* @param {string[]} z Group by columns that segment data into individual line
|
|
23
|
+
* series. An empty array indicates there is only a single line series.
|
|
24
|
+
* @param {number} xn The number of grid bins for the x dimension.
|
|
25
|
+
* @param {number} yn The number of grid bins for the y dimension.
|
|
26
|
+
* @param {string[]} [groupby] Additional group by expressions. Separate
|
|
27
|
+
* line density maps are created for each of these groups.
|
|
28
|
+
* @param {boolean} [normalize=true] Flag toggling approximate arc-length
|
|
29
|
+
* normalization to improve accuracy and reduce artifacts (default `true`).
|
|
30
|
+
* @returns {SelectQuery}
|
|
31
|
+
*/
|
|
32
|
+
export function lineDensity(
|
|
33
|
+
q, x, y, z, xn, yn,
|
|
34
|
+
groupby = [], normalize = true
|
|
35
|
+
) {
|
|
36
|
+
// select x, y points binned to the grid
|
|
37
|
+
q.select({
|
|
38
|
+
x: int32(floor(x)),
|
|
39
|
+
y: int32(floor(y))
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// select line segment end point pairs
|
|
43
|
+
// retain only segments within the grid region
|
|
44
|
+
const groups = groupby.concat(z);
|
|
45
|
+
const pairs = Query
|
|
46
|
+
.from(q)
|
|
47
|
+
.select(groups, {
|
|
48
|
+
x0: 'x',
|
|
49
|
+
y0: 'y',
|
|
50
|
+
dx: sub(lead('x').over('sw'), 'x'),
|
|
51
|
+
dy: sub(lead('y').over('sw'), 'y')
|
|
52
|
+
})
|
|
53
|
+
.window({
|
|
54
|
+
sw: over().partitionby(groups).orderby(asc('x'))
|
|
55
|
+
})
|
|
56
|
+
.qualify([
|
|
57
|
+
or(lt('x0', xn), lt(add('x0', 'dx'), xn)),
|
|
58
|
+
or(lt('y0', yn), lt(add('y0', 'dy'), yn)),
|
|
59
|
+
or(gt('x0', 0), gt(add('x0', 'dx'), 0)),
|
|
60
|
+
or(gt('y0', 0), gt(add('y0', 'dy'), 0))
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
// create indices to join against for rasterization
|
|
64
|
+
// generate the maximum number of indices needed
|
|
65
|
+
const num = Query
|
|
66
|
+
.select({ x: greatest(max(abs('dx')), max(abs('dy'))) })
|
|
67
|
+
.from('pairs');
|
|
68
|
+
const indices = Query.select({
|
|
69
|
+
i: int32(sql`UNNEST(range((${num})))`)
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// rasterize line segments
|
|
73
|
+
const raster = Query.unionAll(
|
|
74
|
+
Query
|
|
75
|
+
.select(groups, {
|
|
76
|
+
x: add('x0', 'i'),
|
|
77
|
+
y: add('y0', int32(round(div(mul('i', 'dy'), 'dx'))))
|
|
78
|
+
})
|
|
79
|
+
.from('pairs', 'indices')
|
|
80
|
+
.where([lte(abs('dy'), abs('dx')), lt('i', abs('dx'))]),
|
|
81
|
+
Query
|
|
82
|
+
.select(groups, {
|
|
83
|
+
x: add('x0', int32(round(div(mul(mul(sign('dy'), 'i'), 'dx'), 'dy')))),
|
|
84
|
+
y: add('y0', mul(sign('dy'), 'i'))
|
|
85
|
+
})
|
|
86
|
+
.from('pairs', 'indices')
|
|
87
|
+
.where([gt(abs('dy'), abs('dx')), lt('i', abs('dy'))]),
|
|
88
|
+
Query
|
|
89
|
+
.select(groups, { x: 'x0', y: 'y0' })
|
|
90
|
+
.from('pairs')
|
|
91
|
+
.where(isNull('dx'))
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// filter raster, normalize columns for each series
|
|
95
|
+
const points = Query
|
|
96
|
+
.from('raster')
|
|
97
|
+
.select(groups, 'x', 'y',
|
|
98
|
+
normalize
|
|
99
|
+
? { w: div(1, count().partitionby(['x'].concat(groups))) }
|
|
100
|
+
: null
|
|
101
|
+
)
|
|
102
|
+
.where([lte(0, 'x'), lt('x', xn), lte(0, 'y'), lt('y', yn)]);
|
|
103
|
+
|
|
104
|
+
// sum normalized, rasterized series into output grids
|
|
105
|
+
return Query
|
|
106
|
+
.with({ pairs, indices, raster, points })
|
|
107
|
+
.from('points')
|
|
108
|
+
.select(groupby, {
|
|
109
|
+
index: add('x', mul('y', int32(xn))),
|
|
110
|
+
density: normalize ? sum('w') : count()
|
|
111
|
+
})
|
|
112
|
+
.groupby('index', groupby);
|
|
113
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Query } from '../ast/query.js';
|
|
2
|
+
import { argmax, argmin, max, min } from '../functions/aggregate.js';
|
|
3
|
+
import { int32 } from '../functions/cast.js';
|
|
4
|
+
import { floor } from '../functions/numeric.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* M4 is an optimization for value-preserving time-series aggregation
|
|
8
|
+
* (https://www.vldb.org/pvldb/vol7/p797-jugel.pdf). This implementation uses
|
|
9
|
+
* an efficient version with a single scan and the aggregate functions
|
|
10
|
+
* argmin and argmax, following https://arxiv.org/pdf/2306.03714.pdf.
|
|
11
|
+
* This method can bin along either the *x* or *y* dimension, as determined
|
|
12
|
+
* by the caller-provided *bin* expression.
|
|
13
|
+
* @param {import('../types.js').FromExpr} input The base query or table.
|
|
14
|
+
* @param {import('../types.js').ExprValue} bin An expression that maps
|
|
15
|
+
* time-series values to fractional pixel positions.
|
|
16
|
+
* @param {string} x The x dimension column name.
|
|
17
|
+
* @param {string} y The y dimension column name.
|
|
18
|
+
* @param {import('../ast/node.js').ExprNode[]} [groups] Additional
|
|
19
|
+
* groupby columns, for example for faceted charts.
|
|
20
|
+
* @returns {Query} The resulting M4 query.
|
|
21
|
+
*/
|
|
22
|
+
export function m4(input, bin, x, y, groups = []) {
|
|
23
|
+
const pixel = int32(floor(bin));
|
|
24
|
+
|
|
25
|
+
const q = (sel) => Query
|
|
26
|
+
.from(input)
|
|
27
|
+
.select(sel)
|
|
28
|
+
.groupby(pixel, groups);
|
|
29
|
+
|
|
30
|
+
return Query
|
|
31
|
+
.union(
|
|
32
|
+
q([{ [x]: min(x), [y]: argmin(y, x) }, ...groups]),
|
|
33
|
+
q([{ [x]: max(x), [y]: argmax(y, x) }, ...groups]),
|
|
34
|
+
q([{ [x]: argmin(x, y), [y]: min(y) }, ...groups]),
|
|
35
|
+
q([{ [x]: argmax(x, y), [y]: max(y) }, ...groups])
|
|
36
|
+
)
|
|
37
|
+
.orderby(groups, x);
|
|
38
|
+
}
|