datajunction 0.0.1-a85 → 0.0.1-a87

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datajunction",
3
- "version": "0.0.1a85",
3
+ "version": "0.0.1a87",
4
4
  "description": "A Javascript client for interacting with a DataJunction server",
5
5
  "module": "src/index.js",
6
6
  "scripts": {
package/src/httpclient.js CHANGED
@@ -1,27 +1,66 @@
1
1
  export default class HttpClient {
2
2
  constructor(options = {}) {
3
- this._baseURL = options.baseURL || ''
4
- this._headers = options.headers || {}
3
+ this._baseURL = options.baseURL || '';
4
+ this._headers = options.headers || {};
5
+ this._cookie = '';
5
6
  }
6
7
 
7
8
  async _fetchJSON(endpoint, options = {}) {
8
9
  const res = await fetch(this._baseURL + endpoint, {
9
10
  ...options,
10
- headers: this._headers,
11
- })
11
+ headers: {
12
+ ...this._headers,
13
+ 'Cookie': this._cookie,
14
+ },
15
+ credentials: 'include',
16
+ });
17
+
18
+ const setCookieHeader = res.headers.get('Set-Cookie');
19
+ if (setCookieHeader) {
20
+ this._cookie = setCookieHeader;
21
+ this._headers['Cookie'] = this._cookie;
22
+ }
12
23
 
13
- if (!res.ok)
14
- throw new Error(
15
- res.statusText + ` (${endpoint}, ${JSON.stringify(options)})`
16
- )
24
+ if (!res.ok) {
25
+ const errorText = await res.text();
26
+ throw new Error(`Request failed: ${res.status} ${errorText}`);
27
+ }
17
28
 
18
29
  if (options.parseResponse !== false && res.status !== 204) {
19
- return res.json()
30
+ return res.json();
20
31
  }
21
32
 
22
- return undefined
33
+ return undefined;
23
34
  }
24
35
 
36
+ async login(username, password) {
37
+ const body = new URLSearchParams({
38
+ grant_type: 'password',
39
+ username: username,
40
+ password: password,
41
+ });
42
+
43
+ const response = await fetch(this._baseURL + '/basic/login', {
44
+ method: 'POST',
45
+ headers: {
46
+ 'Content-Type': 'application/x-www-form-urlencoded',
47
+ ...this._headers,
48
+ },
49
+ body: body.toString(),
50
+ credentials: 'include',
51
+ });
52
+
53
+ if (!response.ok) {
54
+ const errorText = await response.text();
55
+ throw new Error(`Login failed: ${response.status} ${errorText}`);
56
+ }
57
+
58
+ const setCookieHeader = response.headers.get('Set-Cookie');
59
+ if (setCookieHeader) {
60
+ this._cookie = setCookieHeader;
61
+ this._headers['Cookie'] = this._cookie;
62
+ }
63
+ }
25
64
  setHeader(key, value) {
26
65
  this._headers[key] = value
27
66
  return this
package/src/index.js CHANGED
@@ -6,7 +6,7 @@ export class DJClient extends HttpClient {
6
6
  namespace,
7
7
  engineName = null,
8
8
  engineVersion = null,
9
- httpAgent = null
9
+ httpAgent = null,
10
10
  ) {
11
11
  super(
12
12
  {
@@ -295,4 +295,20 @@ export class DJClient extends HttpClient {
295
295
  },
296
296
  }
297
297
  }
298
+
299
+ get register() {
300
+ return {
301
+ table: (catalog, schema, table) =>
302
+ this.setHeader('Content-Type', 'application/json').post(
303
+ `/register/table/${catalog}/${schema}/${table}`
304
+ ),
305
+ view: (catalog, schema, view, query, replace = false) => {
306
+ const replaceQuery = replace ? `?replace=${replace}` : '';
307
+ return this.setHeader('Content-Type', 'application/json').post(
308
+ `/register/view/${catalog}/${schema}/${view}${replaceQuery}`,
309
+ { query }
310
+ );
311
+ }
312
+ }
313
+ }
298
314
  }
package/src/index.test.js CHANGED
@@ -2,591 +2,79 @@ const { DJClient } = require('./index')
2
2
  var dockerNames = require('docker-names')
3
3
 
4
4
  test('should return something', async () => {
5
- const randomName = dockerNames.getRandomName(true)
6
- const namespace = `integration.javascript.${randomName}`
7
- const dj = new DJClient('http://localhost:8000')
8
-
9
- // Create a namespace
10
- const namespace_created = await dj.namespaces.create(namespace)
11
- expect(namespace_created).toEqual({
12
- message: `Node namespace \`${namespace}\` has been successfully created`,
13
- })
14
-
15
- // List namespaces
16
- const existing_namespaces = await dj.namespaces.list()
17
- expect(existing_namespaces).toContainEqual({ namespace: namespace })
18
-
19
- // Create a source
20
- await dj.sources.create({
21
- name: `${namespace}.repair_orders`,
22
- description: 'Repair orders',
23
- catalog: 'warehouse',
24
- schema_: 'roads',
25
- table: 'repair_orders',
26
- mode: 'published',
5
+ const dj = new DJClient('http://localhost:8000', 'integration.tests', 'dj', 'dj');
6
+ await dj.login("dj", "dj")
7
+
8
+ await dj.catalogs.create({ name: 'tpch' });
9
+ await dj.engines.create({ name: 'trino', version: '451' });
10
+ await dj.catalogs.addEngine('tpch', 'trino', '451');
11
+
12
+ await dj.namespaces.create('integration.tests');
13
+ await dj.namespaces.create('integration.tests.trino');
14
+
15
+ const source = await dj.sources.create({
16
+ name: 'integration.tests.source1',
17
+ catalog: 'unknown',
18
+ schema_: 'db',
19
+ table: 'tbl',
20
+ display_name: 'Test Source with Columns',
21
+ description: 'A test source node with columns',
27
22
  columns: [
28
- { name: 'repair_order_id', type: 'int' },
29
- { name: 'municipality_id', type: 'string' },
30
- { name: 'hard_hat_id', type: 'int' },
31
- { name: 'order_date', type: 'timestamp' },
32
- { name: 'required_date', type: 'timestamp' },
33
- { name: 'dispatched_date', type: 'timestamp' },
34
- { name: 'dispatcher_id', type: 'int' },
23
+ { name: 'id', type: 'int' },
24
+ { name: 'name', type: 'string' },
25
+ { name: 'price', type: 'double' },
26
+ { name: 'created_at', type: 'timestamp' },
35
27
  ],
36
- })
37
-
38
- // Get source
39
- const source1 = await dj.nodes.get(`${namespace}.repair_orders`)
40
- expect(source1.name).toBe(`${namespace}.repair_orders`)
41
- expect(source1.status).toBe('valid')
42
- expect(source1.mode).toBe('published')
43
-
44
- // Create a transform
45
- await dj.transforms.create({
46
- name: `${namespace}.repair_orders_w_dispatchers`,
47
- description: 'Repair orders that have a dispatcher',
28
+ primary_key: ['id'],
48
29
  mode: 'published',
49
- query: `SELECT
50
- repair_order_id,
51
- municipality_id,
52
- hard_hat_id,
53
- dispatcher_id
54
- FROM ${namespace}.repair_orders
55
- WHERE dispatcher_id IS NOT NULL`,
56
- })
30
+ update_if_exists: true,
31
+ });
57
32
 
58
- // Get transform
59
- const transform1 = await dj.nodes.get(
60
- `${namespace}.repair_orders_w_dispatchers`
61
- )
62
- expect(transform1.name).toBe(`${namespace}.repair_orders_w_dispatchers`)
63
- expect(transform1.status).toBe('valid')
64
- expect(transform1.mode).toBe('published')
33
+ await dj.register.table('tpch', 'sf1', 'orders');
65
34
 
66
- // Create a source and dimension node
67
- const source2 = await dj.sources.create({
68
- name: `${namespace}.dispatchers`,
69
- description:
70
- 'Different third party dispatcher companies that coordinate repairs',
71
- catalog: 'warehouse',
72
- schema_: 'roads',
73
- table: 'dispatchers',
35
+ const transform = await dj.transforms.create({
36
+ name: 'integration.tests.trino.transform1',
37
+ display_name: 'Filter to last 1000 records',
38
+ description: 'The last 1000 purchases',
74
39
  mode: 'published',
75
- columns: [
76
- { name: 'dispatcher_id', type: 'int' },
77
- { name: 'company_name', type: 'string' },
78
- { name: 'phone', type: 'string' },
79
- ],
80
- })
81
- expect(source2.name).toBe(`${namespace}.dispatchers`)
82
- expect(source2.status).toBe('valid')
83
- expect(source2.mode).toBe('published')
84
- await dj.dimensions.create({
85
- name: `${namespace}.all_dispatchers`,
86
- description: 'All dispatchers',
87
- primary_key: ['dispatcher_id'],
40
+ query: 'select custkey, totalprice, orderdate from source.tpch.sf1.orders order by orderdate desc limit 1000',
41
+ update_if_exists: true,
42
+ });
43
+
44
+ const dimension = await dj.dimensions.create({
45
+ name: 'integration.tests.trino.dimension1',
46
+ display_name: 'Customer keys',
47
+ description: 'All custkey values in the source table',
88
48
  mode: 'published',
89
- query: `SELECT
90
- dispatcher_id,
91
- company_name,
92
- phone
93
- FROM ${namespace}.dispatchers`,
94
- })
95
- const dimension1 = await dj.nodes.get(`${namespace}.all_dispatchers`)
96
- expect(dimension1.name).toBe(`${namespace}.all_dispatchers`)
97
- expect(dimension1.status).toBe('valid')
98
- expect(dimension1.mode).toBe('published')
99
-
100
- // Create metrics
101
- await dj.metrics.create({
102
- name: `${namespace}.num_repair_orders`,
103
- description: 'Number of repair orders',
49
+ primary_key: ['id'],
50
+ tags: [],
51
+ query: "select custkey as id, 'attribute' as foo from source.tpch.sf1.orders",
52
+ update_if_exists: true,
53
+ });
54
+
55
+ await dj.dimensions.link(
56
+ 'integration.tests.trino.transform1',
57
+ 'custkey',
58
+ 'integration.tests.trino.dimension1',
59
+ 'id',
60
+ );
61
+
62
+ const metric = await dj.metrics.create({
63
+ name: 'integration.tests.trino.metric1',
64
+ display_name: 'Total of last 1000 purchases',
65
+ description: 'This is the total amount from the last 1000 purchases',
104
66
  mode: 'published',
105
- query: `SELECT
106
- count(repair_order_id)
107
- FROM ${namespace}.repair_orders`,
108
- })
109
- const metric1 = await dj.nodes.get(`${namespace}.num_repair_orders`)
110
- expect(metric1.name).toBe(`${namespace}.num_repair_orders`)
111
- expect(metric1.status).toBe('valid')
112
- expect(metric1.mode).toBe('published')
113
-
114
- // List metrics
115
- const list_of_metrics = await dj.metrics.all()
116
- expect(list_of_metrics).toContain(`${namespace}.num_repair_orders`)
117
-
118
- // Create a dimension link
119
- const dimension_linked_message = await dj.dimensions.link(
120
- `${namespace}.repair_orders`,
121
- 'dispatcher_id',
122
- `${namespace}.all_dispatchers`,
123
- 'dispatcher_id'
124
- )
125
- expect(dimension_linked_message).toEqual({
126
- message: `Dimension node ${namespace}.all_dispatchers has been successfully linked to column dispatcher_id on node ${namespace}.repair_orders`,
127
- })
67
+ query: 'select sum(totalprice) from integration.tests.trino.transform1',
68
+ update_if_exists: true,
69
+ });
128
70
 
129
- const common_dimensions = await dj.commonDimensions.list([
130
- 'default.num_repair_orders',
131
- 'default.avg_repair_price',
132
- 'default.total_repair_cost',
133
- ])
134
-
135
- expect(common_dimensions).toEqual([
136
- {
137
- name: 'default.dispatcher.company_name',
138
- type: 'string',
139
- path: [
140
- 'default.repair_orders.repair_order_id',
141
- 'default.repair_order.dispatcher_id',
142
- ],
143
- },
144
- {
145
- name: 'default.dispatcher.dispatcher_id',
146
- type: 'int',
147
- path: [
148
- 'default.repair_orders.repair_order_id',
149
- 'default.repair_order.dispatcher_id',
150
- ],
151
- },
152
- {
153
- name: 'default.dispatcher.phone',
154
- type: 'string',
155
- path: [
156
- 'default.repair_orders.repair_order_id',
157
- 'default.repair_order.dispatcher_id',
158
- ],
159
- },
160
- {
161
- name: 'default.hard_hat.address',
162
- type: 'string',
163
- path: [
164
- 'default.repair_orders.repair_order_id',
165
- 'default.repair_order.hard_hat_id',
166
- ],
167
- },
168
- {
169
- name: 'default.hard_hat.birth_date',
170
- type: 'date',
171
- path: [
172
- 'default.repair_orders.repair_order_id',
173
- 'default.repair_order.hard_hat_id',
174
- ],
175
- },
176
- {
177
- name: 'default.hard_hat.city',
178
- type: 'string',
179
- path: [
180
- 'default.repair_orders.repair_order_id',
181
- 'default.repair_order.hard_hat_id',
182
- ],
183
- },
184
- {
185
- name: 'default.hard_hat.contractor_id',
186
- type: 'int',
187
- path: [
188
- 'default.repair_orders.repair_order_id',
189
- 'default.repair_order.hard_hat_id',
190
- ],
191
- },
192
- {
193
- name: 'default.hard_hat.country',
194
- type: 'string',
195
- path: [
196
- 'default.repair_orders.repair_order_id',
197
- 'default.repair_order.hard_hat_id',
198
- ],
199
- },
200
- {
201
- name: 'default.hard_hat.first_name',
202
- type: 'string',
203
- path: [
204
- 'default.repair_orders.repair_order_id',
205
- 'default.repair_order.hard_hat_id',
206
- ],
207
- },
208
- {
209
- name: 'default.hard_hat.hard_hat_id',
210
- type: 'int',
211
- path: [
212
- 'default.repair_orders.repair_order_id',
213
- 'default.repair_order.hard_hat_id',
214
- ],
215
- },
216
- {
217
- name: 'default.hard_hat.hire_date',
218
- type: 'date',
219
- path: [
220
- 'default.repair_orders.repair_order_id',
221
- 'default.repair_order.hard_hat_id',
222
- ],
223
- },
224
- {
225
- name: 'default.hard_hat.last_name',
226
- type: 'string',
227
- path: [
228
- 'default.repair_orders.repair_order_id',
229
- 'default.repair_order.hard_hat_id',
230
- ],
231
- },
232
- {
233
- name: 'default.hard_hat.manager',
234
- type: 'int',
235
- path: [
236
- 'default.repair_orders.repair_order_id',
237
- 'default.repair_order.hard_hat_id',
238
- ],
239
- },
240
- {
241
- name: 'default.hard_hat.postal_code',
242
- type: 'string',
243
- path: [
244
- 'default.repair_orders.repair_order_id',
245
- 'default.repair_order.hard_hat_id',
246
- ],
247
- },
248
- {
249
- name: 'default.hard_hat.state',
250
- type: 'string',
251
- path: [
252
- 'default.repair_orders.repair_order_id',
253
- 'default.repair_order.hard_hat_id',
254
- ],
255
- },
256
- {
257
- name: 'default.hard_hat.title',
258
- type: 'string',
259
- path: [
260
- 'default.repair_orders.repair_order_id',
261
- 'default.repair_order.hard_hat_id',
262
- ],
263
- },
264
- {
265
- name: 'default.municipality_dim.contact_name',
266
- type: 'string',
267
- path: [
268
- 'default.repair_orders.repair_order_id',
269
- 'default.repair_order.municipality_id',
270
- ],
271
- },
272
- {
273
- name: 'default.municipality_dim.contact_title',
274
- type: 'string',
275
- path: [
276
- 'default.repair_orders.repair_order_id',
277
- 'default.repair_order.municipality_id',
278
- ],
279
- },
280
- {
281
- name: 'default.municipality_dim.local_region',
282
- type: 'string',
283
- path: [
284
- 'default.repair_orders.repair_order_id',
285
- 'default.repair_order.municipality_id',
286
- ],
287
- },
288
- {
289
- name: 'default.municipality_dim.municipality_id',
290
- type: 'string',
291
- path: [
292
- 'default.repair_orders.repair_order_id',
293
- 'default.repair_order.municipality_id',
294
- ],
295
- },
296
- {
297
- name: 'default.municipality_dim.municipality_type_desc',
298
- type: 'string',
299
- path: [
300
- 'default.repair_orders.repair_order_id',
301
- 'default.repair_order.municipality_id',
302
- ],
303
- },
304
- {
305
- name: 'default.municipality_dim.municipality_type_id',
306
- type: 'string',
307
- path: [
308
- 'default.repair_orders.repair_order_id',
309
- 'default.repair_order.municipality_id',
310
- ],
311
- },
312
- {
313
- name: 'default.municipality_dim.state_id',
314
- type: 'int',
315
- path: [
316
- 'default.repair_orders.repair_order_id',
317
- 'default.repair_order.municipality_id',
318
- ],
319
- },
320
- {
321
- name: 'default.repair_orders.repair_order_id',
322
- type: 'int',
323
- path: [],
324
- },
325
- {
326
- name: 'default.us_state.state_abbr',
327
- type: 'string',
328
- path: [
329
- 'default.repair_orders.repair_order_id',
330
- 'default.repair_order.hard_hat_id',
331
- 'default.hard_hat.state',
332
- ],
333
- },
334
- {
335
- name: 'default.us_state.state_id',
336
- type: 'int',
337
- path: [
338
- 'default.repair_orders.repair_order_id',
339
- 'default.repair_order.hard_hat_id',
340
- 'default.hard_hat.state',
341
- ],
342
- },
343
- {
344
- name: 'default.us_state.state_name',
345
- type: 'string',
346
- path: [
347
- 'default.repair_orders.repair_order_id',
348
- 'default.repair_order.hard_hat_id',
349
- 'default.hard_hat.state',
350
- ],
351
- },
352
- {
353
- name: 'default.us_state.state_region',
354
- type: 'int',
355
- path: [
356
- 'default.repair_orders.repair_order_id',
357
- 'default.repair_order.hard_hat_id',
358
- 'default.hard_hat.state',
359
- ],
360
- },
361
- {
362
- name: 'default.us_state.state_region_description',
363
- type: 'string',
364
- path: [
365
- 'default.repair_orders.repair_order_id',
366
- 'default.repair_order.hard_hat_id',
367
- 'default.hard_hat.state',
368
- ],
369
- },
370
- ])
71
+ await dj.commonDimensions.list(['integration.tests.trino.metric1']);
371
72
 
372
73
  const query = await dj.sql.get(
373
- [
374
- 'default.num_repair_orders',
375
- 'default.avg_repair_price',
376
- 'default.total_repair_cost',
377
- ],
378
- [
379
- 'default.us_state.state_abbr',
380
- 'default.us_state.state_id',
381
- 'default.us_state.state_name',
382
- ],
74
+ ['integration.tests.trino.metric1'],
75
+ ['integration.tests.trino.dimension1.id'],
383
76
  []
384
- )
385
- const trimmedQuery = query.sql.replace(/\s+/g, '')
386
- expect(trimmedQuery).toBe(
387
- `WITH
388
- m0_default_DOT_num_repair_orders AS (SELECT default_DOT_us_state.state_abbr,
389
- default_DOT_us_state.state_id,
390
- default_DOT_us_state.state_name,
391
- count(default_DOT_repair_orders.repair_order_id) default_DOT_num_repair_orders
392
- FROM roads.repair_orders AS default_DOT_repair_orders LEFT OUTER JOIN (SELECT default_DOT_repair_orders.dispatcher_id,
393
- default_DOT_repair_orders.hard_hat_id,
394
- default_DOT_repair_orders.municipality_id,
395
- default_DOT_repair_orders.repair_order_id
396
- FROM roads.repair_orders AS default_DOT_repair_orders)
397
- AS default_DOT_repair_order ON default_DOT_repair_orders.repair_order_id = default_DOT_repair_order.repair_order_id
398
- LEFT OUTER JOIN (SELECT default_DOT_hard_hats.birth_date,
399
- default_DOT_hard_hats.hard_hat_id,
400
- default_DOT_hard_hats.hire_date,
401
- default_DOT_hard_hats.state
402
- FROM roads.hard_hats AS default_DOT_hard_hats)
403
- AS default_DOT_hard_hat ON default_DOT_repair_order.hard_hat_id = default_DOT_hard_hat.hard_hat_id
404
- LEFT OUTER JOIN (SELECT default_DOT_us_states.state_abbr,
405
- default_DOT_us_states.state_id,
406
- default_DOT_us_states.state_name
407
- FROM roads.us_states AS default_DOT_us_states LEFT JOIN roads.us_region AS default_DOT_us_region ON default_DOT_us_states.state_region = default_DOT_us_region.us_region_description)
408
- AS default_DOT_us_state ON default_DOT_hard_hat.state = default_DOT_us_state.state_abbr
409
- GROUP BY default_DOT_us_state.state_abbr, default_DOT_us_state.state_id, default_DOT_us_state.state_name
410
- ),
411
- m1_default_DOT_avg_repair_price AS (SELECT default_DOT_us_state.state_abbr,
412
- default_DOT_us_state.state_id,
413
- default_DOT_us_state.state_name,
414
- avg(default_DOT_repair_order_details.price) default_DOT_avg_repair_price
415
- FROM roads.repair_order_details AS default_DOT_repair_order_details LEFT OUTER JOIN (SELECT default_DOT_repair_orders.dispatcher_id,
416
- default_DOT_repair_orders.hard_hat_id,
417
- default_DOT_repair_orders.municipality_id,
418
- default_DOT_repair_orders.repair_order_id
419
- FROM roads.repair_orders AS default_DOT_repair_orders)
420
- AS default_DOT_repair_order ON default_DOT_repair_order_details.repair_order_id = default_DOT_repair_order.repair_order_id
421
- LEFT OUTER JOIN (SELECT default_DOT_hard_hats.birth_date,
422
- default_DOT_hard_hats.hard_hat_id,
423
- default_DOT_hard_hats.hire_date,
424
- default_DOT_hard_hats.state
425
- FROM roads.hard_hats AS default_DOT_hard_hats)
426
- AS default_DOT_hard_hat ON default_DOT_repair_order.hard_hat_id = default_DOT_hard_hat.hard_hat_id
427
- LEFT OUTER JOIN (SELECT default_DOT_us_states.state_abbr,
428
- default_DOT_us_states.state_id,
429
- default_DOT_us_states.state_name
430
- FROM roads.us_states AS default_DOT_us_states LEFT JOIN roads.us_region AS default_DOT_us_region ON default_DOT_us_states.state_region = default_DOT_us_region.us_region_description)
431
- AS default_DOT_us_state ON default_DOT_hard_hat.state = default_DOT_us_state.state_abbr
432
- GROUP BY default_DOT_us_state.state_abbr, default_DOT_us_state.state_id, default_DOT_us_state.state_name
433
- ),
434
- m2_default_DOT_total_repair_cost AS (SELECT default_DOT_us_state.state_abbr,
435
- default_DOT_us_state.state_id,
436
- default_DOT_us_state.state_name,
437
- sum(default_DOT_repair_order_details.price) default_DOT_total_repair_cost
438
- FROM roads.repair_order_details AS default_DOT_repair_order_details LEFT OUTER JOIN (SELECT default_DOT_repair_orders.dispatcher_id,
439
- default_DOT_repair_orders.hard_hat_id,
440
- default_DOT_repair_orders.municipality_id,
441
- default_DOT_repair_orders.repair_order_id
442
- FROM roads.repair_orders AS default_DOT_repair_orders)
443
- AS default_DOT_repair_order ON default_DOT_repair_order_details.repair_order_id = default_DOT_repair_order.repair_order_id
444
- LEFT OUTER JOIN (SELECT default_DOT_hard_hats.birth_date,
445
- default_DOT_hard_hats.hard_hat_id,
446
- default_DOT_hard_hats.hire_date,
447
- default_DOT_hard_hats.state
448
- FROM roads.hard_hats AS default_DOT_hard_hats)
449
- AS default_DOT_hard_hat ON default_DOT_repair_order.hard_hat_id = default_DOT_hard_hat.hard_hat_id
450
- LEFT OUTER JOIN (SELECT default_DOT_us_states.state_abbr,
451
- default_DOT_us_states.state_id,
452
- default_DOT_us_states.state_name
453
- FROM roads.us_states AS default_DOT_us_states LEFT JOIN roads.us_region AS default_DOT_us_region ON default_DOT_us_states.state_region = default_DOT_us_region.us_region_description)
454
- AS default_DOT_us_state ON default_DOT_hard_hat.state = default_DOT_us_state.state_abbr
455
- GROUP BY default_DOT_us_state.state_abbr, default_DOT_us_state.state_id, default_DOT_us_state.state_name
456
- )SELECT m0_default_DOT_num_repair_orders.default_DOT_num_repair_orders,
457
- m1_default_DOT_avg_repair_price.default_DOT_avg_repair_price,
458
- m2_default_DOT_total_repair_cost.default_DOT_total_repair_cost,
459
- COALESCE(m0_default_DOT_num_repair_orders.state_abbr, m1_default_DOT_avg_repair_price.state_abbr, m2_default_DOT_total_repair_cost.state_abbr) state_abbr,
460
- COALESCE(m0_default_DOT_num_repair_orders.state_id, m1_default_DOT_avg_repair_price.state_id, m2_default_DOT_total_repair_cost.state_id) state_id,
461
- COALESCE(m0_default_DOT_num_repair_orders.state_name, m1_default_DOT_avg_repair_price.state_name, m2_default_DOT_total_repair_cost.state_name) state_name
462
- FROM m0_default_DOT_num_repair_orders FULL OUTER JOIN m1_default_DOT_avg_repair_price ON m0_default_DOT_num_repair_orders.state_abbr = m1_default_DOT_avg_repair_price.state_abbr AND m0_default_DOT_num_repair_orders.state_id = m1_default_DOT_avg_repair_price.state_id AND m0_default_DOT_num_repair_orders.state_name = m1_default_DOT_avg_repair_price.state_name
463
- FULL OUTER JOIN m2_default_DOT_total_repair_cost ON m0_default_DOT_num_repair_orders.state_abbr = m2_default_DOT_total_repair_cost.state_abbr AND m0_default_DOT_num_repair_orders.state_id = m2_default_DOT_total_repair_cost.state_id AND m0_default_DOT_num_repair_orders.state_name = m2_default_DOT_total_repair_cost.state_name
464
- `.replace(/\s+/g, '')
465
- )
466
-
467
- const data = await dj.data.get(
468
- [
469
- 'default.num_repair_orders',
470
- 'default.avg_repair_price',
471
- 'default.total_repair_cost',
472
- ],
473
- [
474
- 'default.us_state.state_abbr',
475
- 'default.us_state.state_id',
476
- 'default.us_state.state_name',
477
- ],
478
- []
479
- )
480
-
481
- expect(data).toEqual({
482
- columns: [
483
- {
484
- name: 'default_DOT_num_repair_orders',
485
- type: 'bigint',
486
- },
487
- {
488
- name: 'default_DOT_avg_repair_price',
489
- type: 'double',
490
- },
491
- {
492
- name: 'default_DOT_total_repair_cost',
493
- type: 'double',
494
- },
495
- {
496
- name: 'state_abbr',
497
- type: 'string',
498
- },
499
- {
500
- name: 'state_id',
501
- type: 'int',
502
- },
503
- {
504
- name: 'state_name',
505
- type: 'string',
506
- },
507
- ],
508
- data: [
509
- [486, 65682.0, 31921452.0, 'AZ', 3, 'Arizona'],
510
- [486, 39301.5, 19100529.0, 'CT', 7, 'Connecticut'],
511
- [729, 65595.66666666667, 47819241.0, 'GA', 11, 'Georgia'],
512
- [729, 76555.33333333333, 55808838.0, 'MA', 22, 'Massachusetts'],
513
- [1215, 64190.6, 77991579.0, 'MI', 23, 'Michigan'],
514
- [972, 54672.75, 53141913.0, 'NJ', 31, 'New Jersey'],
515
- [243, 53374.0, 12969882.0, 'NY', 33, 'New York'],
516
- [243, 70418.0, 17111574.0, 'OK', 37, 'Oklahoma'],
517
- [972, 54083.5, 52569162.0, 'PA', 39, 'Pennsylvania'],
518
- ],
519
- })
520
-
521
- // Create a transform 2 downstream from a transform 1
522
- await dj.transforms.create({
523
- name: `${namespace}.repair_orders_w_hard_hats`,
524
- description: 'Repair orders that have a hard hat assigned',
525
- mode: 'published',
526
- query: `SELECT
527
- repair_order_id,
528
- municipality_id,
529
- hard_hat_id,
530
- dispatcher_id
531
- FROM ${namespace}.repair_orders_w_dispatchers
532
- WHERE hard_hat_id IS NOT NULL`,
533
- })
534
-
535
- // Get transform 2 that's downstream from transform 1 and make sure it's valid
536
- const transform2 = await dj.nodes.get(
537
- `${namespace}.repair_orders_w_hard_hats`
538
- )
539
- expect(transform2.name).toBe(`${namespace}.repair_orders_w_hard_hats`)
540
- expect(transform2.status).toBe('valid')
541
- expect(transform2.mode).toBe('published')
542
-
543
- // Create a draft transform 4 that's downstream from a not yet created transform 3
544
- await dj.transforms.create({
545
- name: `${namespace}.repair_orders_w_repair_order_id`,
546
- description: 'Repair orders without a null ID',
547
- mode: 'draft',
548
- query: `SELECT
549
- repair_order_id,
550
- municipality_id,
551
- hard_hat_id,
552
- dispatcher_id
553
- FROM ${namespace}.repair_orders_w_municipalities
554
- WHERE repair_order_id IS NOT NULL`,
555
- })
556
- const transform4 = await dj.nodes.get(
557
- `${namespace}.repair_orders_w_repair_order_id`
558
- )
559
- // Check that transform 4 is invalid because transform 3 does not exist
560
- expect(transform4.name).toBe(`${namespace}.repair_orders_w_repair_order_id`)
561
- expect(transform4.status).toBe('invalid')
562
- expect(transform4.mode).toBe('draft')
563
-
564
- // Create a draft transform 3 that's downstream from transform 2
565
- await dj.transforms.create({
566
- name: `${namespace}.repair_orders_w_municipalities`,
567
- description: 'Repair orders that have a municipality listed',
568
- mode: 'draft',
569
- query: `SELECT
570
- repair_order_id,
571
- municipality_id,
572
- hard_hat_id,
573
- dispatcher_id
574
- FROM ${namespace}.repair_orders_w_hard_hats
575
- WHERE municipality_id IS NOT NULL`,
576
- })
577
- const transform3 = await dj.nodes.get(
578
- `${namespace}.repair_orders_w_municipalities`
579
- )
580
- expect(transform3.name).toBe(`${namespace}.repair_orders_w_municipalities`)
581
- expect(transform3.status).toBe('valid')
582
- expect(transform3.mode).toBe('draft')
583
-
584
- // Check that transform 4 is now valid after transform 3 was created
585
- const transform4_now_valid = await dj.nodes.get(
586
- `${namespace}.repair_orders_w_repair_order_id`
587
- )
588
- expect(transform4_now_valid.status).toBe('valid')
77
+ );
589
78
 
590
- // Check that publishing transform 3 works
591
- await dj.nodes.publish(transform3.name)
79
+ expect(query.sql).toContain('SELECT');
592
80
  }, 60000)