@@ -3,14 +3,22 @@ import { QueryOrchestrator } from '../../src/orchestrator/QueryOrchestrator';
33
44class MockDriver {
55 constructor ( { csvImport } = { } ) {
6- this . tables = [ ] ;
6+ this . tablesObj = [ ] ;
77 this . tablesReady = [ ] ;
88 this . executedQueries = [ ] ;
99 this . cancelledQueries = [ ] ;
1010 this . csvImport = csvImport ;
1111 this . now = new Date ( ) . getTime ( ) ;
1212 }
1313
14+ get tables ( ) {
15+ return this . tablesObj . map ( t => t . tableName || t ) ;
16+ }
17+
18+ resetTables ( ) {
19+ this . tablesObj = [ ] ;
20+ }
21+
1422 query ( query ) {
1523 this . executedQueries . push ( query ) ;
1624 let promise = Promise . resolve ( [ query ] ) ;
@@ -26,6 +34,10 @@ class MockDriver {
2634 promise = promise . then ( ( ) => [ { now : new Date ( ) . toJSON ( ) } ] ) ;
2735 }
2836
37+ if ( query . match ( / ^ S E L E C T ' ( \d + - \d + - \d + ) ' / ) ) {
38+ promise = promise . then ( ( ) => [ { date : new Date ( `${ query . match ( / ^ S E L E C T ' ( \d + - \d + - \d + ) ' / ) [ 1 ] } T00:00:00.000Z` ) . toJSON ( ) } ] ) ;
39+ }
40+
2941 if ( query . match ( / ^ S E L E C T M A X \( t i m e s t a m p \) / ) ) {
3042 promise = promise . then ( ( ) => [ { max : new Date ( '2021-06-01T00:00:00.000Z' ) . toJSON ( ) } ] ) ;
3143 }
@@ -56,7 +68,11 @@ class MockDriver {
5668 if ( this . tablesQueryDelay ) {
5769 await this . delay ( this . tablesQueryDelay ) ;
5870 }
59- return this . tables . filter ( t => t . split ( '.' ) [ 0 ] === schema ) . map ( t => ( { table_name : t . replace ( `${ schema } .` , '' ) } ) ) ;
71+ return this . tablesObj . filter ( t => ( t . tableName || t ) . split ( '.' ) [ 0 ] === schema )
72+ . map ( t => ( {
73+ table_name : ( t . tableName || t ) . replace ( `${ schema } .` , '' ) ,
74+ build_range_end : t . buildRangeEnd
75+ } ) ) ;
6076 }
6177
6278 delay ( timeout ) {
@@ -69,15 +85,15 @@ class MockDriver {
6985 }
7086
7187 loadPreAggregationIntoTable ( preAggregationTableName , loadSql ) {
72- this . tables . push ( preAggregationTableName . substring ( 0 , 100 ) ) ;
88+ this . tablesObj . push ( { tableName : preAggregationTableName . substring ( 0 , 100 ) } ) ;
7389 const promise = this . query ( loadSql ) ;
7490 const resPromise = promise . then ( ( ) => this . tablesReady . push ( preAggregationTableName . substring ( 0 , 100 ) ) ) ;
7591 resPromise . cancel = promise . cancel ;
7692 return resPromise ;
7793 }
7894
7995 async dropTable ( tableName ) {
80- this . tables = this . tables . filter ( t => t !== tableName ) ;
96+ this . tablesObj = this . tablesObj . filter ( t => ( t . tableName || t ) !== tableName ) ;
8197 return this . query ( `DROP TABLE ${ tableName } ` ) ;
8298 }
8399
@@ -109,12 +125,12 @@ class ExternalMockDriver extends MockDriver {
109125 }
110126
111127 async uploadTable ( table ) {
112- this . tables . push ( table . substring ( 0 , 100 ) ) ;
128+ this . tablesObj . push ( { tableName : table . substring ( 0 , 100 ) } ) ;
113129 throw new Error ( 'uploadTable has been called instead of uploadTableWithIndexes' ) ;
114130 }
115131
116- async uploadTableWithIndexes ( table , columns , tableData , indexesSql ) {
117- this . tables . push ( table . substring ( 0 , 100 ) ) ;
132+ async uploadTableWithIndexes ( table , columns , tableData , indexesSql , uniqueKeyColumns , queryTracingObj , externalOptions ) {
133+ this . tablesObj . push ( { tableName : table . substring ( 0 , 100 ) , buildRangeEnd : queryTracingObj ?. buildRangeEnd } ) ;
118134 if ( tableData . csvFile ) {
119135 this . csvFiles . push ( tableData . csvFile ) ;
120136 }
@@ -209,7 +225,7 @@ describe('QueryOrchestrator', () => {
209225 } ) ,
210226 } ,
211227 preAggregationsOptions : {
212- maxPartitions : 32 ,
228+ maxPartitions : 100 ,
213229 queueOptions : ( ) => ( {
214230 executionTimeout : 2 ,
215231 concurrency : 2 ,
@@ -535,7 +551,7 @@ describe('QueryOrchestrator', () => {
535551 } ) ;
536552
537553 test ( 'save structure versions' , async ( ) => {
538- mockDriver . tables = [ ] ;
554+ mockDriver . resetTables ( ) ;
539555 await queryOrchestrator . fetchQuery ( {
540556 query : 'SELECT * FROM stb_pre_aggregations.orders' ,
541557 values : [ ] ,
@@ -1017,7 +1033,7 @@ describe('QueryOrchestrator', () => {
10171033 await expect ( async ( ) => {
10181034 await queryOrchestrator . fetchQuery ( query ) ;
10191035 } ) . rejects . toThrow (
1020- 'The maximum number of partitions (32) was reached for the pre-aggregation'
1036+ 'Pre-aggregation \'stb_pre_aggregations.orders_d\' requested to build 745 partitions which exceeds the maximum number of partitions per pre-aggregation of 100 '
10211037 ) ;
10221038 } ) ;
10231039
@@ -1137,6 +1153,73 @@ describe('QueryOrchestrator', () => {
11371153 expect ( result . data [ 0 ] ) . toMatch ( / o r d e r s _ d 2 0 2 1 0 6 0 1 / ) ;
11381154 } ) ;
11391155
1156+ test ( 'lambda partitions' , async ( ) => {
1157+ const query = ( matchedTimeDimensionDateRange ) => ( {
1158+ query : 'SELECT * FROM stb_pre_aggregations.orders_d UNION ALL SELECT * FROM stb_pre_aggregations.orders_h' ,
1159+ values : [ ] ,
1160+ cacheKeyQueries : {
1161+ queries : [ ]
1162+ } ,
1163+ preAggregations : [ {
1164+ preAggregationsSchema : 'stb_pre_aggregations' ,
1165+ tableName : 'stb_pre_aggregations.orders_d' ,
1166+ loadSql : [
1167+ 'CREATE TABLE stb_pre_aggregations.orders_d AS SELECT * FROM public.orders WHERE timestamp >= ? AND timestamp <= ?' ,
1168+ [ '__FROM_PARTITION_RANGE' , '__TO_PARTITION_RANGE' ]
1169+ ] ,
1170+ invalidateKeyQueries : [ [ 'SELECT CASE WHEN NOW() > ? THEN NOW() END as now' , [ '__TO_PARTITION_RANGE' ] , {
1171+ renewalThreshold : 1 ,
1172+ updateWindowSeconds : 86400 ,
1173+ renewalThresholdOutsideUpdateWindow : 86400 ,
1174+ incremental : true
1175+ } ] ] ,
1176+ preAggregationStartEndQueries : [
1177+ [ 'SELECT MIN(timestamp) FROM orders' , [ ] ] ,
1178+ [ 'SELECT \'2021-05-31\'' , [ ] ] ,
1179+ ] ,
1180+ external : true ,
1181+ partitionGranularity : 'day' ,
1182+ timezone : 'UTC' ,
1183+ rollupLambdaId : 'orders.d_lambda' ,
1184+ matchedTimeDimensionDateRange
1185+ } , {
1186+ preAggregationsSchema : 'stb_pre_aggregations' ,
1187+ tableName : 'stb_pre_aggregations.orders_h' ,
1188+ loadSql : [
1189+ 'CREATE TABLE stb_pre_aggregations.orders_h AS SELECT * FROM public.orders WHERE timestamp >= ? AND timestamp <= ?' ,
1190+ [ '__FROM_PARTITION_RANGE' , '__TO_PARTITION_RANGE' ]
1191+ ] ,
1192+ invalidateKeyQueries : [ [ 'SELECT CASE WHEN NOW() > ? THEN NOW() END as now' , [ '__TO_PARTITION_RANGE' ] , {
1193+ renewalThreshold : 1 ,
1194+ updateWindowSeconds : 86400 ,
1195+ renewalThresholdOutsideUpdateWindow : 86400 ,
1196+ incremental : true
1197+ } ] ] ,
1198+ preAggregationStartEndQueries : [
1199+ [ 'SELECT \'2021-05-30\'' , [ ] ] ,
1200+ [ 'SELECT MAX(timestamp) FROM orders' , [ ] ] ,
1201+ ] ,
1202+ external : true ,
1203+ partitionGranularity : 'hour' ,
1204+ timezone : 'UTC' ,
1205+ rollupLambdaId : 'orders.d_lambda' ,
1206+ lastRollupLambda : true ,
1207+ matchedTimeDimensionDateRange
1208+ } ] ,
1209+ requestId : 'lambda partitions' ,
1210+ external : true ,
1211+ } ) ;
1212+ let result = await queryOrchestrator . fetchQuery ( query ( ) ) ;
1213+ console . log ( JSON . stringify ( result , null , 2 ) ) ;
1214+ expect ( result . data [ 0 ] ) . toMatch ( / o r d e r s _ d 2 0 2 1 0 5 0 1 / ) ;
1215+ expect ( result . data [ 0 ] ) . not . toMatch ( / o r d e r s _ h 2 0 2 1 0 5 3 0 0 0 / ) ;
1216+ expect ( result . data [ 0 ] ) . toMatch ( / o r d e r s _ h 2 0 2 1 0 5 3 1 0 0 / ) ;
1217+
1218+ result = await queryOrchestrator . fetchQuery ( query ( [ '2021-05-31T00:00:00.000' , '2021-05-31T23:59:59.999' ] ) ) ;
1219+ console . log ( JSON . stringify ( result , null , 2 ) ) ;
1220+ expect ( result . data [ 0 ] ) . toMatch ( / o r d e r s _ h 2 0 2 1 0 5 3 1 0 0 / ) ;
1221+ } ) ;
1222+
11401223 test ( 'loadRefreshKeys' , async ( ) => {
11411224 const preAggregationsLoadCacheByDataSource = { } ;
11421225 const preAggregationExternalRefreshKey = {
0 commit comments