@@ -5,7 +5,7 @@ import { PostgresQuery } from '../../../src/adapter/PostgresQuery';
55import { prepareYamlCompiler } from '../../unit/PrepareCompiler' ;
66import { dbRunner } from './PostgresDBRunner' ;
77
8- describe ( 'Member Expression' , ( ) => {
8+ describe ( 'Member Expression Multistage ' , ( ) => {
99 jest . setTimeout ( 200000 ) ;
1010
1111 const { compiler, joinGraph, cubeEvaluator } = prepareYamlCompiler ( `
@@ -37,6 +37,170 @@ cubes:
3737 - name: count
3838 type: count
3939
40+ - name: orders
41+ sql: >
42+ select 10 AS ID, 'complited' AS STATUS, '2021-01-05 00:00:00'::timestamp AS CREATED_AT, 100 AS CUSTOMER_ID, 50.0 as revenue
43+ UNION ALL
44+ select 11 AS ID, 'complited' AS STATUS, '2021-05-01 00:00:00'::timestamp AS CREATED_AT, 100 AS CUSTOMER_ID, 150.0 as revenue
45+ UNION ALL
46+ select 12 AS ID, 'complited' AS STATUS, '2021-06-01 00:00:00'::timestamp AS CREATED_AT, 100 AS CUSTOMER_ID, 200.0 as revenue
47+ UNION ALL
48+ select 13 AS ID, 'complited' AS STATUS, '2022-01-04 00:00:00'::timestamp AS CREATED_AT, 100 AS CUSTOMER_ID, 10.0 as revenue
49+ UNION ALL
50+ select 14 AS ID, 'complited' AS STATUS, '2022-05-04 00:00:00'::timestamp AS CREATED_AT, 100 AS CUSTOMER_ID, 30.0 as revenue
51+ public: false
52+
53+ joins:
54+ - name: line_items
55+ sql: "{CUBE}.ID = {line_items}.order_id"
56+ relationship: many_to_one
57+
58+ - name: customers
59+ sql: "{CUBE}.CUSTOMER_ID = {customers}.ID"
60+ relationship: many_to_one
61+
62+ dimensions:
63+ - name: id
64+ sql: ID
65+ type: number
66+ primary_key: true
67+
68+ - name: status
69+ sql: STATUS
70+ type: string
71+
72+ - name: date
73+ sql: CREATED_AT
74+ type: time
75+
76+ - name: amount
77+ sql: '{line_items.total_amount}'
78+ type: number
79+ sub_query: true
80+
81+ measures:
82+ - name: count
83+ type: count
84+
85+ - name: completed_count
86+ type: count
87+ filters:
88+ - sql: "{CUBE}.STATUS = 'completed'"
89+
90+ - name: returned_count
91+ type: count
92+ filters:
93+ - sql: "{CUBE}.STATUS = 'returned'"
94+
95+ - name: return_rate
96+ type: number
97+ sql: "({returned_count} / NULLIF({completed_count}, 0)) * 100.0"
98+ description: "Percentage of returned orders out of completed, exclude just placed orders."
99+ format: percent
100+
101+ - name: total_amount
102+ sql: '{CUBE.amount}'
103+ type: sum
104+
105+ - name: revenue
106+ sql: "revenue"
107+ type: sum
108+ format: currency
109+
110+ - name: average_order_value
111+ sql: '{CUBE.amount}'
112+ type: avg
113+
114+ - name: revenue_1_y_ago
115+ sql: "{revenue}"
116+ multi_stage: true
117+ type: number
118+ format: currency
119+ time_shift:
120+ - time_dimension: date
121+ interval: 1 year
122+ type: prior
123+ - time_dimension: orders_view.date
124+ interval: 1 year
125+ type: prior
126+
127+ - name: cagr_1_y
128+ sql: "(({revenue} / {revenue_1_y_ago}) - 1)"
129+ type: number
130+ format: percent
131+ description: "Annual CAGR, year over year growth in revenue"
132+
133+ - name: line_items
134+ sql: >
135+ SELECT 10 AS ID, 10 AS PRODUCT_ID, '2021-01-01 00:00:00'::timestamp AS CREATED_AT, 10 as order_id
136+ UNION ALL
137+ SELECT 11 AS ID, 10 AS PRODUCT_ID, '2021-01-01 00:00:00'::timestamp AS CREATED_AT, 11 as order_id
138+ UNION ALL
139+ SELECT 12 AS ID, 10 AS PRODUCT_ID, '2021-01-01 00:00:00'::timestamp AS CREATED_AT, 11 as order_id
140+ UNION ALL
141+ SELECT 13 AS ID, 10 AS PRODUCT_ID, '2021-01-01 00:00:00'::timestamp AS CREATED_AT, 12 as order_id
142+ public: false
143+
144+ joins:
145+ - name: products
146+ sql: "{CUBE}.PRODUCT_ID = {products}.ID"
147+ relationship: many_to_one
148+
149+ dimensions:
150+ - name: id
151+ sql: ID
152+ type: number
153+ primary_key: true
154+
155+ - name: created_at
156+ sql: CREATED_AT
157+ type: time
158+
159+ - name: price
160+ sql: "{products.price}"
161+ type: number
162+
163+ measures:
164+ - name: count
165+ type: count
166+
167+ - name: total_amount
168+ sql: "{price}"
169+ type: sum
170+ - name: products
171+ sql: >
172+ SELECT 10 AS ID, 'Clothes' AS PRODUCT_CATEGORY, 'Shirt' AS NAME, 10 AS PRICE
173+ UNION ALL
174+ SELECT 11 AS ID, 'Clothes' AS PRODUCT_CATEGORY, 'Shirt' AS NAME, 20 AS PRICE
175+ public: false
176+ description: >
177+ Products and categories in our e-commerce store.
178+
179+ dimensions:
180+ - name: id
181+ sql: ID
182+ type: number
183+ primary_key: true
184+
185+ - name: product_category
186+ sql: PRODUCT_CATEGORY
187+ type: string
188+
189+ - name: name
190+ sql: NAME
191+ type: string
192+
193+ - name: price
194+ sql: PRICE
195+ type: number
196+
197+ measures:
198+ - name: count
199+ type: count
200+
201+
202+
203+
40204views:
41205 - name: customers_view
42206
@@ -47,6 +211,29 @@ views:
47211
48212 - city
49213
214+ - name: orders_view
215+ cubes:
216+ - join_path: orders
217+ includes:
218+ - count
219+ - date
220+ - revenue
221+ - cagr_1_y
222+ - return_rate
223+
224+ - join_path: line_items.products
225+ prefix: true
226+ includes:
227+ - product_category
228+
229+ - join_path: orders.customers
230+ prefix: true
231+ includes:
232+ - city
233+ - count
234+ - id
235+
236+
50237 ` ) ;
51238
52239 async function runQueryTest ( q , expectedResult ) {
@@ -124,4 +311,77 @@ views:
124311 } ,
125312
126313 [ { count : 1 , city : 'New York' , cubejoinfield : 'NULL' } , { count : 1 , city : 'New York' , cubejoinfield : 'NULL' } ] ) ) ;
314+ if ( getEnv ( 'nativeSqlPlanner' ) ) {
315+ it ( 'member expression multi stage' , async ( ) => runQueryTest ( {
316+ measures : [
317+ {
318+ // eslint-disable-next-line no-new-func
319+ expression : new Function (
320+ 'orders' ,
321+ // eslint-disable-next-line no-template-curly-in-string
322+ 'return `${orders.cagr_1_y}`'
323+ ) ,
324+ // eslint-disable-next-line no-template-curly-in-string
325+ definition : '${orders.cagr_1_y}' ,
326+ expressionName : 'orders__cagr_2023' ,
327+ cubeName : 'orders' ,
328+ } ,
329+ ] ,
330+ timeDimensions : [
331+ {
332+ dimension : 'orders.date' ,
333+ dateRange : [ '2022-01-01' , '2022-10-31' ] ,
334+ } ,
335+ ] ,
336+ timezone : 'America/Los_Angeles'
337+ } ,
338+
339+ [ { orders__cagr_2023 : '-0.90000000000000000000' } ] ) ) ;
340+ } else {
341+ it . skip ( 'member expression multi stage' , ( ) => {
342+ // Skipping because it works only in Tesseract
343+ } ) ;
344+ }
345+
346+ if ( getEnv ( 'nativeSqlPlanner' ) ) {
347+ it ( 'member expression multi stage with time dimension segment' , async ( ) => runQueryTest ( {
348+ measures : [
349+ {
350+ // eslint-disable-next-line no-new-func
351+ expression : new Function (
352+ 'orders' ,
353+ // eslint-disable-next-line no-template-curly-in-string
354+ 'return `${orders.cagr_1_y}`'
355+ ) ,
356+ // eslint-disable-next-line no-template-curly-in-string
357+ definition : '${orders.cagr_1_y}' ,
358+ expressionName : 'orders__cagr_2023' ,
359+ cubeName : 'orders' ,
360+ } ,
361+ ] ,
362+ segments : [
363+ {
364+ cubeName : 'orders' ,
365+ name : 'orders_date____c' ,
366+ expressionName : 'orders_date____c' ,
367+ // eslint-disable-next-line no-new-func
368+ expression : new Function (
369+ 'orders' ,
370+ // eslint-disable-next-line no-template-curly-in-string
371+ 'return `((${orders.date} >= CAST(\'2022-01-01\' AS TIMESTAMP)) AND (${orders.date} < CAST(\'2022-10-31\' AS TIMESTAMP)))`'
372+ ) ,
373+ // eslint-disable-next-line no-template-curly-in-string
374+ definition : '{"cube_name":"orders","alias":"orders_date____c","cube_params":["orders"],"expr":"((${orders.date} >= CAST($0$ AS TIMESTAMP)) AND (${orders.date} < CAST($1$ AS TIMESTAMP)))","grouping_set":null}' ,
375+ }
376+ ] ,
377+
378+ timezone : 'America/Los_Angeles'
379+ } ,
380+
381+ [ { orders__cagr_2023 : '-0.90000000000000000000' } ] ) ) ;
382+ } else {
383+ it . skip ( 'member expression multi stage with time dimension segment' , ( ) => {
384+ // Skipping because it works only in Tesseract
385+ } ) ;
386+ }
127387} ) ;
0 commit comments