@@ -197,8 +197,14 @@ pub fn get_members(
197197 . any ( |dim| * dim == MemberOrMemberExpression :: Member ( calc_member. clone ( ) ) )
198198 } )
199199 {
200- members_map. insert ( calc_member. clone ( ) , column. clone ( ) ) ;
201- members_arr. push ( calc_member) ;
200+ // For cases when the same dimension with few different granularities is present
201+ // we should not duplicate the dimension without granularity
202+ if members_map
203+ . insert ( calc_member. clone ( ) , column. clone ( ) )
204+ . is_none ( )
205+ {
206+ members_arr. push ( calc_member) ;
207+ }
202208 }
203209 }
204210
@@ -290,6 +296,21 @@ pub fn get_vanilla_row(
290296) -> Result < HashMap < String , DBResponsePrimitive > > {
291297 let mut row = HashMap :: new ( ) ;
292298
299+ // FIXME: For now custom granularities are not supported, only common ones.
300+ // There is no granularity type/class implementation in rust yet.
301+ let granularity_levels: HashMap < & str , u8 > = HashMap :: from ( [
302+ ( "second" , 1 ) ,
303+ ( "minute" , 2 ) ,
304+ ( "hour" , 3 ) ,
305+ ( "day" , 4 ) ,
306+ ( "week" , 5 ) ,
307+ ( "month" , 6 ) ,
308+ ( "quarter" , 7 ) ,
309+ ( "year" , 8 ) ,
310+ ] ) ;
311+ let default_level_for_unknown = 10 ;
312+ let mut minimal_granularities: HashMap < String , ( u8 , DBResponsePrimitive ) > = HashMap :: new ( ) ;
313+
293314 for ( alias, & index) in columns_pos {
294315 if let Some ( value) = db_row. get ( index) {
295316 let member_name = match alias_to_member_name_map. get ( alias) {
@@ -324,23 +345,46 @@ pub fn get_vanilla_row(
324345 row. insert ( member_name. clone ( ) , transformed_value. clone ( ) ) ;
325346
326347 // Handle deprecated time dimensions without granularity
348+ // Try to collect minimal granularity value for time dimensions without granularity
349+ // as there might be more than one granularity column for the same dimension
327350 let path: Vec < & str > = member_name. split ( MEMBER_SEPARATOR ) . collect ( ) ;
328- let member_name_without_granularity =
329- format ! ( "{}{}{}" , path[ 0 ] , MEMBER_SEPARATOR , path[ 1 ] ) ;
330- if path. len ( ) == 3
331- && query. dimensions . as_ref ( ) . map_or ( true , |dims| {
351+ if path. len ( ) == 3 {
352+ let granularity = path[ 2 ] ;
353+ let member_name_without_granularity =
354+ format ! ( "{}{}{}" , path[ 0 ] , MEMBER_SEPARATOR , path[ 1 ] ) ;
355+
356+ // Check that a member without granularity is absent in the query
357+ if query. dimensions . as_ref ( ) . map_or ( true , |dims| {
332358 !dims. iter ( ) . any ( |dim| {
333359 * dim == MemberOrMemberExpression :: Member (
334360 member_name_without_granularity. clone ( ) ,
335361 )
336362 } )
337- } )
338- {
339- row. insert ( member_name_without_granularity, transformed_value) ;
363+ } ) {
364+ let level = granularity_levels
365+ . get ( granularity)
366+ . cloned ( )
367+ . unwrap_or ( default_level_for_unknown) ;
368+
369+ match minimal_granularities. get ( & member_name_without_granularity) {
370+ Some ( ( existing_level, _) ) if * existing_level < level => { }
371+ _ => {
372+ minimal_granularities. insert (
373+ member_name_without_granularity,
374+ ( level, transformed_value) ,
375+ ) ;
376+ }
377+ }
378+ }
340379 }
341380 }
342381 }
343382
383+ // Handle deprecated time dimensions without granularity
384+ for ( member, ( _, value) ) in minimal_granularities {
385+ row. insert ( member, value) ;
386+ }
387+
344388 match query_type {
345389 QueryType :: CompareDateRangeQuery => {
346390 let date_range_value = get_date_range_value ( query. time_dimensions . as_ref ( ) ) ?;
@@ -1271,6 +1315,133 @@ mod tests {
12711315 ]
12721316 ]
12731317 }
1318+ },
1319+ "blending_query_multiple_granularities": {
1320+ "request": {
1321+ "aliasToMemberNameMap": {
1322+ "e_commerce_records_us2021__avg_discount": "ECommerceRecordsUs2021.avg_discount",
1323+ "e_commerce_records_us2021__order_date_month": "ECommerceRecordsUs2021.orderDate.month",
1324+ "e_commerce_records_us2021__order_date_week": "ECommerceRecordsUs2021.orderDate.week"
1325+ },
1326+ "annotation": {
1327+ "ECommerceRecordsUs2021.avg_discount": {
1328+ "title": "E Commerce Records Us2021 Avg Discount",
1329+ "shortTitle": "Avg Discount",
1330+ "type": "number",
1331+ "drillMembers": [],
1332+ "drillMembersGrouped": {
1333+ "measures": [],
1334+ "dimensions": []
1335+ }
1336+ },
1337+ "ECommerceRecordsUs2021.orderDate.month": {
1338+ "title": "E Commerce Records Us2021 Order Date",
1339+ "shortTitle": "Order Date",
1340+ "type": "time"
1341+ },
1342+ "ECommerceRecordsUs2021.orderDate.week": {
1343+ "title": "E Commerce Records Us2021 Order Date",
1344+ "shortTitle": "Order Date",
1345+ "type": "time"
1346+ },
1347+ "ECommerceRecordsUs2021.orderDate": {
1348+ "title": "E Commerce Records Us2021 Order Date",
1349+ "shortTitle": "Order Date",
1350+ "type": "time"
1351+ }
1352+ },
1353+ "query": {
1354+ "measures": [
1355+ "ECommerceRecordsUs2021.avg_discount"
1356+ ],
1357+ "timeDimensions": [
1358+ {
1359+ "dimension": "ECommerceRecordsUs2021.orderDate",
1360+ "granularity": "month",
1361+ "dateRange": [
1362+ "2020-01-01T00:00:00.000",
1363+ "2020-12-30T23:59:59.999"
1364+ ]
1365+ },
1366+ {
1367+ "dimension": "ECommerceRecordsUs2021.orderDate",
1368+ "granularity": "week",
1369+ "dateRange": [
1370+ "2020-01-01T00:00:00.000",
1371+ "2020-12-30T23:59:59.999"
1372+ ]
1373+ }
1374+ ],
1375+ "filters": [
1376+ {
1377+ "operator": "equals",
1378+ "values": [
1379+ "First Class"
1380+ ],
1381+ "member": "ECommerceRecordsUs2021.shipMode"
1382+ }
1383+ ],
1384+ "limit": 2,
1385+ "rowLimit": 2,
1386+ "timezone": "UTC",
1387+ "order": [],
1388+ "dimensions": []
1389+ },
1390+ "queryType": "blendingQuery"
1391+ },
1392+ "queryResult": [
1393+ {
1394+ "e_commerce_records_us2021__order_date_month": "2020-01-01T00:00:00.000",
1395+ "e_commerce_records_us2021__order_date_week": "2019-12-30T00:00:00.000",
1396+ "e_commerce_records_us2021__avg_discount": "0.28571428571428571429"
1397+ },
1398+ {
1399+ "e_commerce_records_us2021__order_date_month": "2020-02-01T00:00:00.000",
1400+ "e_commerce_records_us2021__order_date_week": "2020-01-27T00:00:00.000",
1401+ "e_commerce_records_us2021__avg_discount": "0.21777777777777777778"
1402+ }
1403+ ],
1404+ "finalResultDefault": [
1405+ {
1406+ "ECommerceRecordsUs2021.orderDate.month": "2020-01-01T00:00:00.000",
1407+ "ECommerceRecordsUs2021.orderDate.week": "2019-12-30T00:00:00.000",
1408+ "ECommerceRecordsUs2021.orderDate": "2019-12-30T00:00:00.000",
1409+ "ECommerceRecordsUs2021.avg_discount": "0.28571428571428571429",
1410+ "time.month": "2020-01-01T00:00:00.000"
1411+ },
1412+ {
1413+ "ECommerceRecordsUs2021.orderDate.month": "2020-02-01T00:00:00.000",
1414+ "ECommerceRecordsUs2021.orderDate.week": "2020-01-27T00:00:00.000",
1415+ "ECommerceRecordsUs2021.orderDate": "2020-01-27T00:00:00.000",
1416+ "ECommerceRecordsUs2021.avg_discount": "0.21777777777777777778",
1417+ "time.month": "2020-02-01T00:00:00.000"
1418+ }
1419+ ],
1420+ "finalResultCompact": {
1421+ "members": [
1422+ "ECommerceRecordsUs2021.orderDate.month",
1423+ "ECommerceRecordsUs2021.orderDate.week",
1424+ "ECommerceRecordsUs2021.orderDate",
1425+ "ECommerceRecordsUs2021.avg_discount",
1426+ "time.month"
1427+ ],
1428+ "dataset": [
1429+ [
1430+ "2020-01-01T00:00:00.000",
1431+ "2019-12-30T00:00:00.000",
1432+ "2019-12-30T00:00:00.000",
1433+ "0.28571428571428571429",
1434+ "2020-01-01T00:00:00.000"
1435+ ],
1436+ [
1437+ "2020-02-01T00:00:00.000",
1438+ "2020-01-27T00:00:00.000",
1439+ "2020-01-27T00:00:00.000",
1440+ "0.21777777777777777778",
1441+ "2020-02-01T00:00:00.000"
1442+ ]
1443+ ]
1444+ }
12741445 }
12751446}
12761447 "# ;
@@ -1919,6 +2090,32 @@ mod tests {
19192090 Ok ( ( ) )
19202091 }
19212092
2093+ #[ test]
2094+ fn test_blending_query_multiple_granularities_default ( ) -> Result < ( ) > {
2095+ let mut test_data = TEST_SUITE_DATA
2096+ . get ( & "blending_query_multiple_granularities" . to_string ( ) )
2097+ . unwrap ( )
2098+ . clone ( ) ;
2099+ test_data. request . res_type = Some ( ResultType :: Default ) ;
2100+ let raw_data = QueryResult :: from_js_raw_data ( test_data. query_result . clone ( ) ) ?;
2101+ let transformed = TransformedData :: transform ( & test_data. request , & raw_data) ?;
2102+ compare_transformed_data ( & transformed, & test_data. final_result_default . unwrap ( ) ) ?;
2103+ Ok ( ( ) )
2104+ }
2105+
2106+ #[ test]
2107+ fn test_blending_query_multiple_granularities_compact ( ) -> Result < ( ) > {
2108+ let mut test_data = TEST_SUITE_DATA
2109+ . get ( & "blending_query_multiple_granularities" . to_string ( ) )
2110+ . unwrap ( )
2111+ . clone ( ) ;
2112+ test_data. request . res_type = Some ( ResultType :: Compact ) ;
2113+ let raw_data = QueryResult :: from_js_raw_data ( test_data. query_result . clone ( ) ) ?;
2114+ let transformed = TransformedData :: transform ( & test_data. request , & raw_data) ?;
2115+ compare_transformed_data ( & transformed, & test_data. final_result_compact . unwrap ( ) ) ?;
2116+ Ok ( ( ) )
2117+ }
2118+
19222119 #[ test]
19232120 fn test_get_members_no_alias_to_member_name_map ( ) -> Result < ( ) > {
19242121 let mut test_data = TEST_SUITE_DATA
0 commit comments