@@ -22,8 +22,12 @@ export default class BigQueryQuery {
2222 return res ;
2323 }
2424
25- public static formatDateToString ( inputDate , separator = '' , addtime = false ) {
26- const date = new Date ( inputDate ) ;
25+ public static formatDateToString ( inputDate , convertToUTC = false , separator = '' , addtime = false ) {
26+ let date = new Date ( inputDate ) ;
27+ if ( convertToUTC ) {
28+ // check if should convert string to UTC time (relevant whenever addTime = true)
29+ date = BigQueryQuery . convertToUtc ( date ) ;
30+ }
2731 // 01, 02, 03, ... 29, 30, 31
2832 const DD = ( date . getDate ( ) < 10 ? '0' : '' ) + date . getDate ( ) ;
2933 // 01, 02, 03, ... 10, 11, 12
@@ -89,6 +93,8 @@ export default class BigQueryQuery {
8993 public static replaceTimeShift ( q ) {
9094 return q . replace ( / ( \$ _ _ t i m e S h i f t i n g \( ) .* ?(? = \) ) ./ g, '' ) ;
9195 }
96+
97+ // Note: converts to UTC time BUT - Date object always represented in local time (so probably relevant when handling date/time strings)
9298 static convertToUtc ( d ) {
9399 return new Date ( d . getTime ( ) + d . getTimezoneOffset ( ) * 60000 ) ;
94100 }
@@ -378,22 +384,32 @@ export default class BigQueryQuery {
378384 return query ;
379385 }
380386
387+ // Detects either date or timestamp, only if not comment out
388+ static hasDateFilter ( whereClause ) {
389+ return whereClause . match ( / ( (?< ! - - .* ) ( [ 1 - 2 ] \d { 3 } - [ 0 - 1 ] \d - [ 0 - 3 ] \d ) | ( [ \D ] ( \d { 13 } ) [ \D ] ) .* \n ) / gi) ;
390+ }
391+
381392 public buildWhereClause ( ) {
382- let query = '' ;
393+ let query = '' , hasMacro = false , hasDateFilter = false ;
383394 const conditions = _ . map ( this . target . where , ( tag , index ) => {
384395 switch ( tag . type ) {
385396 case 'macro' :
397+ hasMacro = true ;
386398 return tag . name + '(' + this . target . timeColumn + ')' ;
387399 case 'expression' :
388- return tag . params . join ( ' ' ) ;
400+ const expression = tag . params . join ( ' ' ) ;
401+ hasDateFilter = BigQueryQuery . hasDateFilter ( expression ) ? true : hasDateFilter ;
402+ return expression ;
389403 }
390404 } ) ;
405+ const hasTimeFilter = ! ! ( hasMacro || hasDateFilter ) ;
391406 if ( this . target . partitioned ) {
392407 const partitionedField = this . target . partitionedField ? this . target . partitionedField : '_PARTITIONTIME' ;
393- if ( this . target . timeColumn !== partitionedField ) {
408+ if ( this . target . timeColumn !== partitionedField && ! hasTimeFilter ) {
394409 if ( this . templateSrv . timeRange && this . templateSrv . timeRange . from ) {
395410 const from = `${ partitionedField } >= '${ BigQueryQuery . formatDateToString (
396411 this . templateSrv . timeRange . from . _d ,
412+ this . target . convertToUTC ,
397413 '-' ,
398414 true
399415 ) } '`;
@@ -402,6 +418,7 @@ export default class BigQueryQuery {
402418 if ( this . templateSrv . timeRange && this . templateSrv . timeRange . to ) {
403419 const to = `${ partitionedField } < '${ BigQueryQuery . formatDateToString (
404420 this . templateSrv . timeRange . to . _d ,
421+ this . target . convertToUTC ,
405422 '-' ,
406423 true
407424 ) } '`;
@@ -410,8 +427,8 @@ export default class BigQueryQuery {
410427 }
411428 }
412429 if ( this . target . sharded ) {
413- const from = BigQueryQuery . formatDateToString ( this . templateSrv . timeRange . from . _d ) ;
414- const to = BigQueryQuery . formatDateToString ( this . templateSrv . timeRange . to . _d ) ;
430+ const from = BigQueryQuery . formatDateToString ( this . templateSrv . timeRange . from . _d , this . target . convertToUTC ) ;
431+ const to = BigQueryQuery . formatDateToString ( this . templateSrv . timeRange . to . _d , this . target . convertToUTC ) ;
415432 const sharded = "_TABLE_SUFFIX BETWEEN '" + from + "' AND '" + to + "' " ;
416433 conditions . push ( sharded ) ;
417434 }
@@ -536,24 +553,18 @@ export default class BigQueryQuery {
536553 public expend_macros ( options ) {
537554 if ( this . target . rawSql ) {
538555 let q = this . target . rawSql ;
539- q = BigQueryQuery . replaceTimeShift ( q ) ;
540- q = this . replaceTimeFilters ( q , options ) ;
541- q = this . replacetimeGroupAlias ( q , true , options ) ;
542- q = this . replacetimeGroupAlias ( q , false , options ) ;
543- return q ;
556+ let hasTimeFilter , hasTimeGroup , hasTimeGroupAlias = false ;
557+ q = BigQueryQuery . replaceTimeShift ( q ) ; // should also block additional partition time filtering?
558+ [ q , hasTimeFilter ] = this . replaceTimeFilters ( q , options ) ;
559+ [ q , hasTimeGroup ] = this . replacetimeGroupAlias ( q , true , options ) ;
560+ [ q , hasTimeGroupAlias ] = this . replacetimeGroupAlias ( q , false , options ) ;
561+ return [ q , hasTimeFilter || hasTimeGroup || hasTimeGroupAlias , this . target . convertToUTC ] ;
544562 }
545563 }
546564 public replaceTimeFilters ( q , options ) {
547- let fromD = options . range . from ;
548- let toD = options . range . to ;
549- if ( this . target . convertToUTC === true ) {
550- fromD = BigQueryQuery . convertToUtc ( options . range . from . _d ) ;
551- toD = BigQueryQuery . convertToUtc ( options . range . to . _d ) ;
552- }
553- let to = '' ;
554- let from = '' ;
555- from = this . _getDateRangePart ( fromD ) ;
556- to = this . _getDateRangePart ( toD ) ;
565+ const { from : fromD , to : toD } = options . range ;
566+ const from = this . _getDateRangePart ( fromD , this . target . convertToUTC ) ;
567+ const to = this . _getDateRangePart ( toD , this . target . convertToUTC ) ;
557568 if ( this . target . timeColumn === '-- time --' ) {
558569 const myRegexp = / \$ _ _ t i m e F i l t e r \( ( [ \w _ . ] + ) \) / g;
559570 const tf = myRegexp . exec ( q ) ;
@@ -564,26 +575,27 @@ export default class BigQueryQuery {
564575 const range = BigQueryQuery . quoteFiledName ( this . target . timeColumn ) + ' BETWEEN ' + from + ' AND ' + to ;
565576 const fromRange = BigQueryQuery . quoteFiledName ( this . target . timeColumn ) + ' > ' + from + ' ' ;
566577 const toRange = BigQueryQuery . quoteFiledName ( this . target . timeColumn ) + ' < ' + to + ' ' ;
578+ const hasMacro = q . match ( / ( \b _ _ t i m e F i l t e r \b ) | ( \b _ _ t i m e F r o m \b ) | ( \b _ _ t i m e T o \b ) | ( \b _ _ m i l l i s T i m e T o \b ) | ( \b _ _ m i l l i s T i m e F r o m \b ) / g)
567579 q = q . replace ( / \$ _ _ t i m e F i l t e r \( ( .* ?) \) / g, range ) ;
568580 q = q . replace ( / \$ _ _ t i m e F r o m \( ( [ \w _ . ] + ) \) / g, fromRange ) ;
569581 q = q . replace ( / \$ _ _ t i m e T o \( ( [ \w _ . ] + ) \) / g, toRange ) ;
570582 q = q . replace ( / \$ _ _ m i l l i s T i m e T o \( ( [ \w _ . ] + ) \) / g, to ) ;
571583 q = q . replace ( / \$ _ _ m i l l i s T i m e F r o m \( ( [ \w _ . ] + ) \) / g, from ) ;
572- return q ;
584+ return [ q , hasMacro ] ;
573585 }
574586
575587 public replacetimeGroupAlias ( q , alias : boolean , options ) {
576588 const res = BigQueryQuery . _getInterval ( q , alias ) ;
577589 const interval = res [ 0 ] ;
578590 const mininterval = res [ 1 ] ;
579591 if ( ! interval ) {
580- return q ;
592+ return [ q , false ] ;
581593 }
582594 const intervalStr = this . getIntervalStr ( interval , mininterval , options ) ;
583595 if ( alias ) {
584- return q . replace ( / \$ _ _ t i m e G r o u p A l i a s \( ( [ \w _ . ] + , + [ a - z A - Z 0 - 9 _ ] + .* \) ) / g, intervalStr ) ;
596+ return [ q . replace ( / \$ _ _ t i m e G r o u p A l i a s \( ( [ \w _ . ] + , + [ a - z A - Z 0 - 9 _ ] + .* \) ) / g, intervalStr ) , q . match ( / ( \b _ _ t i m e G r o u p A l i a s \b ) / g ) ] ;
585597 } else {
586- return q . replace ( / \$ _ _ t i m e G r o u p \( ( [ \w _ . ] + , + [ a - z A - Z 0 - 9 _ ] + .* \) ) / g, intervalStr ) ;
598+ return [ q . replace ( / \$ _ _ t i m e G r o u p \( ( [ \w _ . ] + , + [ a - z A - Z 0 - 9 _ ] + .* \) ) / g, intervalStr ) , q . match ( / ( \b _ _ t i m e G r o u p \b ) / g ) ] ;
587599 }
588600 }
589601
@@ -597,13 +609,14 @@ export default class BigQueryQuery {
597609 const seconds = ( this . templateSrv . timeRange . to . _d - this . templateSrv . timeRange . from . _d ) / 1000 ;
598610 return Math . ceil ( seconds / options . maxDataPoints ) + 's' ;
599611 }
600- private _getDateRangePart ( part ) {
612+ private _getDateRangePart ( part , convertToUTC = false ) {
613+ // if its TIMESTAMP no need conversion (same value for utc or local), else - need conversion
601614 if ( this . target . timeColumnType === 'DATE' ) {
602- return "'" + BigQueryQuery . formatDateToString ( part , '-' ) + "'" ;
615+ return "'" + BigQueryQuery . formatDateToString ( part , convertToUTC , '-' ) + "'" ; // "'2021-01-31'"
603616 } else if ( this . target . timeColumnType === 'DATETIME' ) {
604- return "'" + BigQueryQuery . formatDateToString ( part , '-' , true ) + "'" ;
617+ return "'" + BigQueryQuery . formatDateToString ( part , convertToUTC , '-' , true ) + "'" ; // "'2021-01-31 19:41:45'"
605618 } else {
606- return 'TIMESTAMP_MILLIS (' + part . valueOf ( ) . toString ( ) + ')' ;
619+ return 'TIMESTAMP_MILLIS (' + part . valueOf ( ) . toString ( ) + ')' ; // "TIMESTAMP_MILLIS (1612056873199)"
607620 }
608621 }
609622}
0 commit comments