@malloydata/malloy-tests 0.0.202 → 0.0.203-dev241021171612
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/package.json +8 -8
- package/src/databases/all/join.spec.ts +204 -169
package/package.json
CHANGED
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@jest/globals": "^29.4.3",
|
|
24
|
-
"@malloydata/db-bigquery": "^0.0.
|
|
25
|
-
"@malloydata/db-duckdb": "^0.0.
|
|
26
|
-
"@malloydata/db-postgres": "^0.0.
|
|
27
|
-
"@malloydata/db-snowflake": "^0.0.
|
|
28
|
-
"@malloydata/db-trino": "^0.0.
|
|
29
|
-
"@malloydata/malloy": "^0.0.
|
|
30
|
-
"@malloydata/render": "^0.0.
|
|
24
|
+
"@malloydata/db-bigquery": "^0.0.203-dev241021171612",
|
|
25
|
+
"@malloydata/db-duckdb": "^0.0.203-dev241021171612",
|
|
26
|
+
"@malloydata/db-postgres": "^0.0.203-dev241021171612",
|
|
27
|
+
"@malloydata/db-snowflake": "^0.0.203-dev241021171612",
|
|
28
|
+
"@malloydata/db-trino": "^0.0.203-dev241021171612",
|
|
29
|
+
"@malloydata/malloy": "^0.0.203-dev241021171612",
|
|
30
|
+
"@malloydata/render": "^0.0.203-dev241021171612",
|
|
31
31
|
"events": "^3.3.0",
|
|
32
32
|
"jsdom": "^22.1.0",
|
|
33
33
|
"luxon": "^2.4.0",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"@types/jsdom": "^21.1.1",
|
|
38
38
|
"@types/luxon": "^2.4.0"
|
|
39
39
|
},
|
|
40
|
-
"version": "0.0.
|
|
40
|
+
"version": "0.0.203-dev241021171612"
|
|
41
41
|
}
|
|
@@ -59,212 +59,247 @@ afterAll(async () => {
|
|
|
59
59
|
await runtimes.closeAll();
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
describe('
|
|
63
|
-
|
|
64
|
-
const joinModelText = modelText(database);
|
|
65
|
-
const joinModel = runtime.loadModel(joinModelText);
|
|
66
|
-
it(`model source refine join - ${database}`, async () => {
|
|
67
|
-
await expect(`
|
|
68
|
-
source: a2 is aircraft extend {
|
|
69
|
-
join_one: aircraft_models with aircraft_model_code
|
|
70
|
-
}
|
|
71
|
-
run: a2 -> {
|
|
72
|
-
aggregate:
|
|
73
|
-
aircraft_count
|
|
74
|
-
aircraft_models.model_count
|
|
75
|
-
}
|
|
76
|
-
`).malloyResultMatches(joinModel, {model_count: 1416});
|
|
77
|
-
});
|
|
62
|
+
describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
63
|
+
const joinModel = runtime.loadModel(modelText(databaseName));
|
|
78
64
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
});
|
|
65
|
+
it('model source refine join', async () => {
|
|
66
|
+
await expect(`
|
|
67
|
+
source: a2 is aircraft extend {
|
|
68
|
+
join_one: aircraft_models with aircraft_model_code
|
|
69
|
+
}
|
|
70
|
+
run: a2 -> {
|
|
71
|
+
aggregate:
|
|
72
|
+
aircraft_count
|
|
73
|
+
aircraft_models.model_count
|
|
74
|
+
}
|
|
75
|
+
`).malloyResultMatches(joinModel, {model_count: 1416});
|
|
76
|
+
});
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
am_facts.num_models
|
|
103
|
-
order_by: 2 desc
|
|
104
|
-
limit: 1
|
|
105
|
-
}
|
|
106
|
-
`).malloyResultMatches(joinModel, {num_models: 1147});
|
|
107
|
-
});
|
|
78
|
+
it('model source refine in query join', async () => {
|
|
79
|
+
await expect(`
|
|
80
|
+
run: aircraft extend {
|
|
81
|
+
join_one: aircraft_models with aircraft_model_code
|
|
82
|
+
} -> {
|
|
83
|
+
aggregate:
|
|
84
|
+
aircraft_count
|
|
85
|
+
aircraft_models.model_count
|
|
86
|
+
}
|
|
87
|
+
`).malloyResultMatches(joinModel, {model_count: 1416});
|
|
88
|
+
});
|
|
108
89
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
90
|
+
it('model: join fact table query', async () => {
|
|
91
|
+
await expect(`
|
|
92
|
+
run: aircraft_models extend {
|
|
93
|
+
join_one: am_facts is
|
|
94
|
+
aircraft_models->{
|
|
113
95
|
group_by: m is manufacturer
|
|
114
96
|
aggregate: num_models is count()
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
});
|
|
97
|
+
} with manufacturer
|
|
98
|
+
} -> {
|
|
99
|
+
select:
|
|
100
|
+
manufacturer
|
|
101
|
+
am_facts.num_models
|
|
102
|
+
order_by: 2 desc
|
|
103
|
+
limit: 1
|
|
104
|
+
}
|
|
105
|
+
`).malloyResultMatches(joinModel, {num_models: 1147});
|
|
106
|
+
});
|
|
124
107
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
108
|
+
it('model: source based on query', async () => {
|
|
109
|
+
await expect(`
|
|
110
|
+
run: aircraft_models
|
|
111
|
+
-> {
|
|
128
112
|
group_by: m is manufacturer
|
|
129
113
|
aggregate: num_models is count()
|
|
130
|
-
} extend {
|
|
131
|
-
join_one: seats is
|
|
132
|
-
aircraft_models->{
|
|
133
|
-
group_by: m is manufacturer
|
|
134
|
-
aggregate: total_seats is seats.sum()
|
|
135
|
-
} with m
|
|
136
|
-
} -> {
|
|
137
|
-
select:
|
|
138
|
-
m
|
|
139
|
-
num_models
|
|
140
|
-
seats.total_seats
|
|
141
|
-
order_by: 2 desc
|
|
142
|
-
limit: 1
|
|
143
|
-
}
|
|
144
|
-
`).malloyResultMatches(joinModel, {
|
|
145
|
-
num_models: 1147,
|
|
146
|
-
total_seats: 252771,
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it(`model: modeled funnel - ${database}`, async () => {
|
|
151
|
-
await expect(`
|
|
152
|
-
run: aircraft_models-> manufacturer_models extend {
|
|
153
|
-
join_one: seats is aircraft_models->manufacturer_seats with manufacturer
|
|
154
114
|
} -> {
|
|
155
115
|
select:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
seats.total_seats
|
|
116
|
+
m
|
|
117
|
+
num_models
|
|
159
118
|
order_by: 2 desc
|
|
160
119
|
limit: 1
|
|
161
120
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
total_seats: 252771,
|
|
165
|
-
});
|
|
166
|
-
});
|
|
121
|
+
`).malloyResultMatches(joinModel, {num_models: 1147});
|
|
122
|
+
});
|
|
167
123
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
124
|
+
it('model: funnel - merge two queries', async () => {
|
|
125
|
+
await expect(`
|
|
126
|
+
run: aircraft_models->{
|
|
127
|
+
group_by: m is manufacturer
|
|
128
|
+
aggregate: num_models is count()
|
|
129
|
+
} extend {
|
|
130
|
+
join_one: seats is
|
|
131
|
+
aircraft_models->{
|
|
132
|
+
group_by: m is manufacturer
|
|
133
|
+
aggregate: total_seats is seats.sum()
|
|
134
|
+
} with m
|
|
135
|
+
} -> {
|
|
171
136
|
select:
|
|
172
|
-
|
|
137
|
+
m
|
|
173
138
|
num_models
|
|
174
139
|
seats.total_seats
|
|
175
140
|
order_by: 2 desc
|
|
176
141
|
limit: 1
|
|
177
142
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
});
|
|
143
|
+
`).malloyResultMatches(joinModel, {
|
|
144
|
+
num_models: 1147,
|
|
145
|
+
total_seats: 252771,
|
|
182
146
|
});
|
|
147
|
+
});
|
|
183
148
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
149
|
+
it('model: modeled funnel', async () => {
|
|
150
|
+
await expect(`
|
|
151
|
+
run: aircraft_models-> manufacturer_models extend {
|
|
152
|
+
join_one: seats is aircraft_models->manufacturer_seats with manufacturer
|
|
153
|
+
} -> {
|
|
154
|
+
select:
|
|
155
|
+
manufacturer,
|
|
156
|
+
num_models,
|
|
157
|
+
seats.total_seats
|
|
158
|
+
order_by: 2 desc
|
|
159
|
+
limit: 1
|
|
160
|
+
}
|
|
161
|
+
`).malloyResultMatches(joinModel, {
|
|
162
|
+
num_models: 1147,
|
|
163
|
+
total_seats: 252771,
|
|
195
164
|
});
|
|
165
|
+
});
|
|
196
166
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
// If the unnest is an inner join, we'll get back just 4 rows.
|
|
211
|
-
run: ${database}.table('malloytest.state_facts') extend {
|
|
212
|
-
join_one: a_states is a_states with state
|
|
213
|
-
}
|
|
214
|
-
-> {
|
|
215
|
-
group_by: state
|
|
216
|
-
aggregate: c is count()
|
|
217
|
-
nest: a is {
|
|
218
|
-
group_by: a_states.somthing.state
|
|
219
|
-
}
|
|
220
|
-
limit: 5
|
|
221
|
-
}
|
|
222
|
-
`).malloyResultMatches(joinModel, [{}, {}, {}, {}, {}]);
|
|
167
|
+
it('model: modeled funnel2', async () => {
|
|
168
|
+
await expect(`
|
|
169
|
+
run: funnel->{
|
|
170
|
+
select:
|
|
171
|
+
manufacturer
|
|
172
|
+
num_models
|
|
173
|
+
seats.total_seats
|
|
174
|
+
order_by: 2 desc
|
|
175
|
+
limit: 1
|
|
176
|
+
}
|
|
177
|
+
`).malloyResultMatches(joinModel, {
|
|
178
|
+
num_models: 1147,
|
|
179
|
+
total_seats: 252771,
|
|
223
180
|
});
|
|
181
|
+
});
|
|
224
182
|
|
|
225
|
-
|
|
226
|
-
|
|
183
|
+
it('model: double_pipe', async () => {
|
|
184
|
+
await expect(`
|
|
185
|
+
run: aircraft_models->{
|
|
186
|
+
group_by: manufacturer
|
|
187
|
+
aggregate: f is count()
|
|
188
|
+
}->{
|
|
189
|
+
aggregate: f_sum is f.sum()
|
|
190
|
+
}->{
|
|
191
|
+
select: f_sum2 is f_sum+1
|
|
192
|
+
}
|
|
193
|
+
`).malloyResultMatches(joinModel, {f_sum2: 60462});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test.when(runtime.supportsNesting && runtime.dialect.supportsLeftJoinUnnest)(
|
|
197
|
+
'model: unnest is left join',
|
|
198
|
+
async () => {
|
|
227
199
|
await expect(`
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
200
|
+
// produce a table with 4 rows that has a nested element
|
|
201
|
+
query: a_states is ${databaseName}.table('malloytest.state_facts')-> {
|
|
202
|
+
where: state ? ~ 'A%'
|
|
203
|
+
group_by: state
|
|
204
|
+
nest: somthing is {group_by: state}
|
|
233
205
|
}
|
|
234
206
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
207
|
+
// join the 4 rows and reference the
|
|
208
|
+
// nested column. should return all the rows.
|
|
209
|
+
// If the unnest is an inner join, we'll get back just 4 rows.
|
|
210
|
+
run: ${databaseName}.table('malloytest.state_facts') extend {
|
|
211
|
+
join_one: a_states is a_states with state
|
|
212
|
+
}
|
|
213
|
+
-> {
|
|
214
|
+
group_by: state
|
|
215
|
+
aggregate: c is count()
|
|
216
|
+
nest: a is {
|
|
217
|
+
group_by: a_states.somthing.state
|
|
218
|
+
}
|
|
238
219
|
limit: 5
|
|
239
220
|
}
|
|
240
221
|
`).malloyResultMatches(joinModel, [{}, {}, {}, {}, {}]);
|
|
241
|
-
}
|
|
222
|
+
}
|
|
223
|
+
);
|
|
242
224
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
225
|
+
// not sure how to solve this one yet, just check for > 4 rows
|
|
226
|
+
it('All joins at the same level', async () => {
|
|
227
|
+
await expect(`
|
|
228
|
+
source: flights is ${databaseName}.table('malloytest.flights') extend {
|
|
229
|
+
join_one: aircraft is ${databaseName}.table('malloytest.aircraft')
|
|
230
|
+
on tail_num = aircraft.tail_num
|
|
231
|
+
join_one: aircraft_models is ${databaseName}.table('malloytest.aircraft_models')
|
|
232
|
+
on aircraft.aircraft_model_code = aircraft_models.aircraft_model_code
|
|
233
|
+
}
|
|
246
234
|
|
|
247
|
-
|
|
235
|
+
run: flights -> {
|
|
236
|
+
group_by: aircraft_models.seats
|
|
237
|
+
aggregate: flight_count is count()
|
|
238
|
+
limit: 5
|
|
239
|
+
}
|
|
240
|
+
`).malloyResultMatches(joinModel, [{}, {}, {}, {}, {}]);
|
|
241
|
+
});
|
|
248
242
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
243
|
+
it('join issue440', async () => {
|
|
244
|
+
await expect(`
|
|
245
|
+
source: aircraft_models is ${databaseName}.table('malloytest.aircraft_models')
|
|
253
246
|
|
|
254
|
-
|
|
255
|
-
group_by: testingtwo is aircraft_models.model
|
|
256
|
-
limit: 5
|
|
257
|
-
}
|
|
258
|
-
`).malloyResultMatches(runtime, [{}, {}, {}, {}, {}]);
|
|
259
|
-
});
|
|
247
|
+
source: aircraft is ${databaseName}.table('malloytest.aircraft')
|
|
260
248
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
249
|
+
source: flights is ${databaseName}.table('malloytest.flights') extend {
|
|
250
|
+
join_one: aircraft on aircraft.tail_num = tail_num
|
|
251
|
+
join_one: aircraft_models on aircraft_models.aircraft_model_code = aircraft.aircraft_model_code
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
run: flights-> {
|
|
255
|
+
group_by: testingtwo is aircraft_models.model
|
|
256
|
+
limit: 5
|
|
257
|
+
}
|
|
258
|
+
`).malloyResultMatches(runtime, [{}, {}, {}, {}, {}]);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('join issue1092', async () => {
|
|
262
|
+
await expect(`
|
|
263
|
+
run: ${databaseName}.table('malloytest.state_facts') -> {
|
|
264
|
+
extend: {join_one: sf is ${databaseName}.table('malloytest.state_facts') on sf.state = state}
|
|
265
|
+
aggregate: x is sf.births.sum() { where: state = 'CA' }
|
|
266
|
+
}
|
|
267
|
+
`).malloyResultMatches(runtime, [{}]);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('always join in query', async () => {
|
|
271
|
+
await expect(`
|
|
272
|
+
run: ${databaseName}.table('malloytest.state_facts') -> {
|
|
273
|
+
join_cross: x is ${databaseName}.table('malloytest.state_facts') on true
|
|
274
|
+
select: x is 1
|
|
275
|
+
} -> {
|
|
276
|
+
aggregate: c is count()
|
|
277
|
+
}
|
|
278
|
+
`).malloyResultMatches(joinModel, {c: 51 * 51});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('not always join in extend', async () => {
|
|
282
|
+
await expect(`
|
|
283
|
+
run: ${databaseName}.table('malloytest.state_facts') -> {
|
|
284
|
+
extend: {
|
|
285
|
+
join_cross: x is ${databaseName}.table('malloytest.state_facts') on true
|
|
266
286
|
}
|
|
267
|
-
|
|
268
|
-
|
|
287
|
+
select: x is 1
|
|
288
|
+
} -> {
|
|
289
|
+
aggregate: c is count()
|
|
290
|
+
}
|
|
291
|
+
`).malloyResultMatches(joinModel, {c: 51});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('always inner join has side effects (in group_by)', async () => {
|
|
295
|
+
await expect(`
|
|
296
|
+
##! experimental.join_types
|
|
297
|
+
run: ${databaseName}.table('malloytest.state_facts') -> {
|
|
298
|
+
join_cross: x is ${databaseName}.table('malloytest.state_facts') inner on false
|
|
299
|
+
group_by: x is 1
|
|
300
|
+
} -> {
|
|
301
|
+
aggregate: c is count()
|
|
302
|
+
}
|
|
303
|
+
`).malloyResultMatches(joinModel, {c: 0});
|
|
269
304
|
});
|
|
270
305
|
});
|