@@ -10,9 +10,7 @@ import {
10
10
SASProtocol ,
11
11
generateBlobSASQueryParameters ,
12
12
} from '@azure/storage-blob' ;
13
- import {
14
- DownloadTableCSVData ,
15
- } from '@cubejs-backend/base-driver' ;
13
+ import { DriverCapabilities , UnloadOptions , } from '@cubejs-backend/base-driver' ;
16
14
import {
17
15
JDBCDriver ,
18
16
JDBCDriverConfiguration ,
@@ -194,6 +192,23 @@ export class DatabricksDriver extends JDBCDriver {
194
192
return result ;
195
193
}
196
194
195
+ private async queryColumnTypes ( sql : string , params : unknown [ ] ) {
196
+ const result = [ ] ;
197
+ // eslint-disable-next-line camelcase
198
+ const response = await this . query < { col_name : string ; data_type : string } > ( `DESCRIBE QUERY ${ sql } ` , params ) ;
199
+
200
+ for ( const column of response ) {
201
+ // Databricks describe additional info by default after empty line.
202
+ if ( column . col_name === '' ) {
203
+ break ;
204
+ }
205
+
206
+ result . push ( { name : column . col_name , type : this . toGenericType ( column . data_type ) } ) ;
207
+ }
208
+
209
+ return result ;
210
+ }
211
+
197
212
public async getTablesQuery ( schemaName : string ) {
198
213
const response = await this . query ( `SHOW TABLES IN ${ this . quoteIdentifier ( schemaName ) } ` , [ ] ) ;
199
214
@@ -248,21 +263,22 @@ export class DatabricksDriver extends JDBCDriver {
248
263
return this . config . exportBucket !== undefined ;
249
264
}
250
265
251
- /**
252
- * Saves pre-aggs table to the bucket and returns links to download
253
- * results.
254
- */
255
- public async unload (
256
- tableName : string ,
257
- ) : Promise < DownloadTableCSVData > {
258
- const types = await this . tableColumnTypes ( tableName ) ;
259
- const columns = types . map ( t => t . name ) . join ( ', ' ) ;
266
+ public async unload ( tableName : string , options : UnloadOptions ) {
267
+ if ( ! [ 'azure' , 's3' ] . includes ( this . config . bucketType as string ) ) {
268
+ throw new Error ( `Unsupported export bucket type: ${
269
+ this . config . bucketType
270
+ } `) ;
271
+ }
272
+
273
+ const types = options . query ?
274
+ await this . unloadWithSql ( tableName , options . query . sql , options . query . params ) :
275
+ await this . unloadWithTable ( tableName ) ;
276
+
260
277
const pathname = `${ this . config . exportBucket } /${ tableName } .csv` ;
261
278
const csvFile = await this . getCsvFiles (
262
- tableName ,
263
- columns ,
264
279
pathname ,
265
280
) ;
281
+
266
282
return {
267
283
csvFile,
268
284
types,
@@ -271,21 +287,41 @@ export class DatabricksDriver extends JDBCDriver {
271
287
}
272
288
273
289
/**
274
- * Unload table to bucket using Databricks JDBC query and returns (async)
275
- * csv files signed URLs array.
290
+ * Create table with query and unload it to bucket
291
+ */
292
+ private async unloadWithSql ( tableName : string , sql : string , params : unknown [ ] ) {
293
+ const types = await this . queryColumnTypes ( sql , params ) ;
294
+
295
+ await this . createExternalTableFromSql ( tableName , sql , params ) ;
296
+
297
+ return types ;
298
+ }
299
+
300
+ /**
301
+ * Create table from preaggregation table with location and unload it to bucket
302
+ */
303
+ private async unloadWithTable ( tableName : string ) {
304
+ const types = await this . tableColumnTypes ( tableName ) ;
305
+ const columns = types . map ( t => t . name ) . join ( ', ' ) ;
306
+
307
+ await this . createExternalTableFromTable ( tableName , columns ) ;
308
+
309
+ return types ;
310
+ }
311
+
312
+ /**
313
+ * return csv files signed URLs array.
276
314
*/
277
315
private async getCsvFiles (
278
- table : string ,
279
- columns : string ,
280
316
pathname : string ,
281
317
) : Promise < string [ ] > {
282
318
let res ;
283
319
switch ( this . config . bucketType ) {
284
320
case 'azure' :
285
- res = await this . getAzureCsvFiles ( table , columns , pathname ) ;
321
+ res = await this . getSignedAzureUrls ( pathname ) ;
286
322
break ;
287
323
case 's3' :
288
- res = await this . getS3CsvFiles ( table , columns , pathname ) ;
324
+ res = await this . getSignedS3Urls ( pathname ) ;
289
325
break ;
290
326
default :
291
327
throw new Error ( `Unsupported export bucket type: ${
@@ -295,19 +331,6 @@ export class DatabricksDriver extends JDBCDriver {
295
331
return res ;
296
332
}
297
333
298
- /**
299
- * Saves specified table to the Azure blob storage and returns (async)
300
- * csv files signed URLs array.
301
- */
302
- private async getAzureCsvFiles (
303
- table : string ,
304
- columns : string ,
305
- pathname : string ,
306
- ) : Promise < string [ ] > {
307
- await this . createExternalTable ( table , columns ) ;
308
- return this . getSignedAzureUrls ( pathname ) ;
309
- }
310
-
311
334
/**
312
335
* Returns Azure signed URLs of unloaded scv files.
313
336
*/
@@ -360,19 +383,6 @@ export class DatabricksDriver extends JDBCDriver {
360
383
return csvFile ;
361
384
}
362
385
363
- /**
364
- * Saves specified table to the S3 bucket and returns (async) csv files
365
- * signed URLs array.
366
- */
367
- private async getS3CsvFiles (
368
- table : string ,
369
- columns : string ,
370
- pathname : string ,
371
- ) : Promise < string [ ] > {
372
- await this . createExternalTable ( table , columns ) ;
373
- return this . getSignedS3Urls ( pathname ) ;
374
- }
375
-
376
386
/**
377
387
* Returns S3 signed URLs of unloaded scv files.
378
388
*/
@@ -429,7 +439,19 @@ export class DatabricksDriver extends JDBCDriver {
429
439
* `fs.s3a.access.key <aws-access-key>`
430
440
* `fs.s3a.secret.key <aws-secret-key>`
431
441
*/
432
- private async createExternalTable ( table : string , columns : string , ) {
442
+ private async createExternalTableFromSql ( table : string , sql : string , params : unknown [ ] ) {
443
+ await this . query (
444
+ `
445
+ CREATE TABLE ${ table } _csv_export
446
+ USING CSV LOCATION '${ this . config . exportBucketMountDir || this . config . exportBucket } /${ table } .csv'
447
+ OPTIONS (escape = '"')
448
+ AS (${ sql } )
449
+ ` ,
450
+ params ,
451
+ ) ;
452
+ }
453
+
454
+ private async createExternalTableFromTable ( table : string , columns : string ) {
433
455
await this . query (
434
456
`
435
457
CREATE TABLE ${ table } _csv_export
@@ -440,4 +462,8 @@ export class DatabricksDriver extends JDBCDriver {
440
462
[ ] ,
441
463
) ;
442
464
}
465
+
466
+ public capabilities ( ) : DriverCapabilities {
467
+ return { unloadWithoutTempTable : true } ;
468
+ }
443
469
}
0 commit comments