@@ -49,7 +49,7 @@ import {
4949} from './types/auth' ;
5050import {
5151 Query ,
52- NormalizedQuery ,
52+ NormalizedQuery , MemberExpression ,
5353} from './types/query' ;
5454import {
5555 UserBackgroundContext ,
@@ -89,6 +89,8 @@ import {
8989 transformPreAggregations ,
9090} from './helpers/transformMetaExtended' ;
9191
92+ const memberExpressionRegex = / ^ ( [ a - z A - Z 0 - 9 _ ] + ) .( [ a - z A - Z 0 - 9 _ ] + ) : \( ( [ a - z A - Z 0 - 9 _ , ] + ) \) : ( .* ) $ / ;
93+
9294/**
9395 * API gateway server class.
9496 */
@@ -1170,18 +1172,23 @@ class ApiGateway {
11701172 return [ queryType , normalizedQueries ] ;
11711173 }
11721174
1173- public async sql ( { query, context, res, memberToAlias, exportAnnotatedSql } : QueryRequest ) {
1175+ public async sql ( { query, context, res, memberToAlias, exportAnnotatedSql, memberExpressions , expressionParams } : QueryRequest ) {
11741176 const requestStarted = new Date ( ) ;
11751177
11761178 try {
11771179 await this . assertApiScope ( 'data' , context . securityContext ) ;
11781180
11791181 query = this . parseQueryParam ( query ) ;
1182+
1183+ if ( memberExpressions ) {
1184+ query = this . parseMemberExpressionsInQueries ( query ) ;
1185+ }
1186+
11801187 const [ queryType , normalizedQueries ] = await this . getNormalizedQueries ( query , context ) ;
11811188
11821189 const sqlQueries = await Promise . all < any > (
11831190 normalizedQueries . map ( async ( normalizedQuery ) => ( await this . getCompilerApi ( context ) ) . getSql (
1184- this . coerceForSqlQuery ( { ...normalizedQuery , memberToAlias } , context ) ,
1191+ this . coerceForSqlQuery ( { ...normalizedQuery , memberToAlias, expressionParams } , context ) ,
11851192 {
11861193 includeDebugInfo : getEnv ( 'devMode' ) || context . signedWithPlaygroundAuthSecret ,
11871194 exportAnnotatedSql,
@@ -1204,6 +1211,39 @@ class ApiGateway {
12041211 }
12051212 }
12061213
1214+ private parseMemberExpressionsInQueries ( query : Record < string , any > | Record < string , any > [ ] ) : Query | Query [ ] {
1215+ if ( Array . isArray ( query ) ) {
1216+ return query . map ( q => this . parseMemberExpressionsInQuery ( < Query > q ) ) ;
1217+ } else {
1218+ return this . parseMemberExpressionsInQuery ( < Query > query ) ;
1219+ }
1220+ }
1221+
1222+ private parseMemberExpressionsInQuery ( query : Query ) : Query {
1223+ return {
1224+ ...query ,
1225+ measures : ( query . measures || [ ] ) . map ( m => ( typeof m === 'string' ? this . parseMemberExpression ( m ) : m ) ) ,
1226+ dimensions : ( query . dimensions || [ ] ) . map ( m => ( typeof m === 'string' ? this . parseMemberExpression ( m ) : m ) ) ,
1227+ } ;
1228+ }
1229+
1230+ private parseMemberExpression ( memberExpression : string ) : string | MemberExpression {
1231+ const match = memberExpression . match ( memberExpressionRegex ) ;
1232+ if ( match ) {
1233+ const args = match [ 3 ] . split ( ',' ) ;
1234+ args . push ( `return \`${ match [ 4 ] } \`` ) ;
1235+ return {
1236+ cubeName : match [ 1 ] ,
1237+ name : match [ 2 ] ,
1238+ expressionName : match [ 2 ] ,
1239+ expression : Function . constructor . apply ( null , args ) ,
1240+ definition : memberExpression ,
1241+ } ;
1242+ } else {
1243+ return memberExpression ;
1244+ }
1245+ }
1246+
12071247 public async sqlGenerators ( { context, res } : { context : RequestContext , res : ResponseResultFn } ) {
12081248 const requestStarted = new Date ( ) ;
12091249
@@ -1651,6 +1691,8 @@ class ApiGateway {
16511691 query = this . parseQueryParam ( request . query ) ;
16521692 let resType : ResultType = ResultType . DEFAULT ;
16531693
1694+ query = this . parseMemberExpressionsInQueries ( query ) ;
1695+
16541696 if ( ! Array . isArray ( query ) && query . responseFormat ) {
16551697 resType = query . responseFormat ;
16561698 }
0 commit comments