@@ -33,6 +33,8 @@ import sqlstring from 'sqlstring';
3333
3434import { transformRow , transformStreamRow } from './HydrationStream' ;
3535
36+ const SUPPORTED_BUCKET_TYPES = [ 's3' ] ;
37+
3638const ClickhouseTypeToGeneric : Record < string , string > = {
3739 enum : 'text' ,
3840 string : 'text' ,
@@ -489,11 +491,9 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
489491 protected getExportBucket (
490492 dataSource : string ,
491493 ) : ClickhouseDriverExportAWS | null {
492- const supportedBucketTypes = [ 's3' ] ;
493-
494494 const requiredExportBucket : ClickhouseDriverExportRequiredAWS = {
495495 bucketType : getEnv ( 'dbExportBucketType' , {
496- supported : supportedBucketTypes ,
496+ supported : SUPPORTED_BUCKET_TYPES ,
497497 dataSource,
498498 } ) ,
499499 bucketName : getEnv ( 'dbExportBucket' , { dataSource } ) ,
@@ -507,9 +507,9 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
507507 } ;
508508
509509 if ( exportBucket . bucketType ) {
510- if ( ! supportedBucketTypes . includes ( exportBucket . bucketType ) ) {
510+ if ( ! SUPPORTED_BUCKET_TYPES . includes ( exportBucket . bucketType ) ) {
511511 throw new Error (
512- `Unsupported EXPORT_BUCKET_TYPE, supported: ${ supportedBucketTypes . join ( ',' ) } `
512+ `Unsupported EXPORT_BUCKET_TYPE, supported: ${ SUPPORTED_BUCKET_TYPES . join ( ',' ) } `
513513 ) ;
514514 }
515515
@@ -529,11 +529,7 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
529529 }
530530
531531 public async isUnloadSupported ( ) {
532- if ( this . config . exportBucket ) {
533- return true ;
534- }
535-
536- return false ;
532+ return ! ! this . config . exportBucket ;
537533 }
538534
539535 /**
@@ -588,18 +584,33 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
588584 ) ;
589585 }
590586
591- public async unloadFromQuery ( sql : string , params : unknown [ ] , options : UnloadOptions ) : Promise < DownloadTableCSVData > {
587+ /**
588+ * Returns clean S3 bucket name and prefix path ending with / (if set)
589+ */
590+ private parseS3Path ( input : string ) : { bucket : string ; prefix : string | null } {
591+ let trimmed = input . startsWith ( 's3://' ) ? input . slice ( 5 ) : input ;
592+ trimmed = trimmed . endsWith ( '/' ) ? trimmed . slice ( 0 , - 1 ) : trimmed ;
593+ const parts = trimmed . split ( '/' ) ;
594+ const bucket = parts [ 0 ] ;
595+ const prefixParts = parts . slice ( 1 ) ;
596+ const prefix = prefixParts . length > 0 ? `${ prefixParts . join ( '/' ) } /` : null ;
597+
598+ return { bucket, prefix } ;
599+ }
600+
601+ public async unloadFromQuery ( sql : string , params : unknown [ ] , _options : UnloadOptions ) : Promise < DownloadTableCSVData > {
592602 if ( ! this . config . exportBucket ) {
593603 throw new Error ( 'Unload is not configured' ) ;
594604 }
595605
596606 const types = await this . queryColumnTypes ( `(${ sql } )` , params ) ;
597- const exportPrefix = uuidv4 ( ) ;
607+ const { bucket, prefix } = this . parseS3Path ( this . config . exportBucket . bucketName ) ;
608+ const exportPrefix = prefix ? `${ prefix } ${ uuidv4 ( ) } ` : uuidv4 ( ) ;
598609
599610 const formattedQuery = sqlstring . format ( `
600611 INSERT INTO FUNCTION
601612 s3(
602- 'https://${ this . config . exportBucket . bucketName } .s3.${ this . config . exportBucket . region } .amazonaws.com/${ exportPrefix } /export.csv.gz',
613+ 'https://${ bucket } .s3.${ this . config . exportBucket . region } .amazonaws.com/${ exportPrefix } /export.csv.gz',
603614 '${ this . config . exportBucket . keyId } ',
604615 '${ this . config . exportBucket . secretKey } ',
605616 'CSV'
@@ -617,7 +628,7 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
617628 } ,
618629 region : this . config . exportBucket . region ,
619630 } ,
620- this . config . exportBucket . bucketName ,
631+ bucket ,
621632 exportPrefix ,
622633 ) ;
623634
0 commit comments