Skip to content

Commit de9c6b6

Browse files
committed
add 'rollupJoin pre-aggregation matching with transitive joins' test
1 parent 6992e59 commit de9c6b6

File tree

1 file changed

+261
-0
lines changed

1 file changed

+261
-0
lines changed

packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations.test.ts

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,213 @@ describe('PreAggregations', () => {
925925
]
926926
});
927927
928+
// Models with transitive joins for rollupJoin matching
929+
cube('merchant_dims', {
930+
sql: \`
931+
SELECT 101 AS merchant_sk, 'M1' AS merchant_id
932+
UNION ALL
933+
SELECT 102 AS merchant_sk, 'M2' AS merchant_id
934+
\`,
935+
936+
dimensions: {
937+
merchant_sk: {
938+
sql: 'merchant_sk',
939+
type: 'number',
940+
primary_key: true
941+
},
942+
merchant_id: {
943+
sql: 'merchant_id',
944+
type: 'string'
945+
}
946+
}
947+
});
948+
949+
cube('product_dims', {
950+
sql: \`
951+
SELECT 201 AS product_sk, 'P1' AS product_id
952+
UNION ALL
953+
SELECT 202 AS product_sk, 'P2' AS product_id
954+
\`,
955+
956+
dimensions: {
957+
product_sk: {
958+
sql: 'product_sk',
959+
type: 'number',
960+
primary_key: true
961+
},
962+
product_id: {
963+
sql: 'product_id',
964+
type: 'string'
965+
}
966+
}
967+
});
968+
969+
cube('merchant_and_product_dims', {
970+
sql: \`
971+
SELECT 'M1' AS merchant_id, 'P1' AS product_id, 'Organic' AS acquisition_channel, 'SOLD' AS status
972+
UNION ALL
973+
SELECT 'M1' AS merchant_id, 'P2' AS product_id, 'Paid' AS acquisition_channel, 'PAID' AS status
974+
UNION ALL
975+
SELECT 'M2' AS merchant_id, 'P1' AS product_id, 'Referral' AS acquisition_channel, 'RETURNED' AS status
976+
\`,
977+
978+
dimensions: {
979+
product_id: {
980+
sql: 'product_id',
981+
type: 'string',
982+
primary_key: true
983+
},
984+
merchant_id: {
985+
sql: 'merchant_id',
986+
type: 'string',
987+
primary_key: true
988+
},
989+
status: {
990+
sql: 'status',
991+
type: 'string'
992+
},
993+
acquisition_channel: {
994+
sql: 'acquisition_channel',
995+
type: 'string'
996+
}
997+
},
998+
999+
pre_aggregations: {
1000+
bridge_rollup: {
1001+
dimensions: [
1002+
merchant_id,
1003+
product_id,
1004+
acquisition_channel,
1005+
status
1006+
]
1007+
}
1008+
}
1009+
});
1010+
1011+
cube('other_facts', {
1012+
sql: \`
1013+
SELECT 1 AS id, 1 AS fact_id, 'OF1' AS fact
1014+
UNION ALL
1015+
SELECT 2 AS id, 2 AS fact_id, 'OF2' AS fact
1016+
UNION ALL
1017+
SELECT 3 AS id, 3 AS fact_id, 'OF3' AS fact
1018+
\`,
1019+
1020+
dimensions: {
1021+
other_fact_id: {
1022+
sql: 'id',
1023+
type: 'number',
1024+
primary_key: true
1025+
},
1026+
fact_id: {
1027+
sql: 'fact_id',
1028+
type: 'number'
1029+
},
1030+
fact: {
1031+
sql: 'fact',
1032+
type: 'string'
1033+
}
1034+
},
1035+
1036+
pre_aggregations: {
1037+
bridge_rollup: {
1038+
dimensions: [
1039+
fact_id,
1040+
fact
1041+
]
1042+
}
1043+
}
1044+
1045+
});
1046+
1047+
cube('test_facts', {
1048+
sql: \`
1049+
SELECT 1 AS id, 101 AS merchant_sk, 201 AS product_sk, 100 AS amount
1050+
UNION ALL
1051+
SELECT 2 AS id, 101 AS merchant_sk, 202 AS product_sk, 150 AS amount
1052+
UNION ALL
1053+
SELECT 3 AS id, 102 AS merchant_sk, 201 AS product_sk, 200 AS amount
1054+
\`,
1055+
1056+
joins: {
1057+
merchant_dims: {
1058+
relationship: 'many_to_one',
1059+
sql: \`\${CUBE.merchant_sk} = \${merchant_dims.merchant_sk}\`
1060+
},
1061+
product_dims: {
1062+
relationship: 'many_to_one',
1063+
sql: \`\${CUBE.product_sk} = \${product_dims.product_sk}\`
1064+
},
1065+
// Transitive join - depends on merchant_dims and product_dims
1066+
merchant_and_product_dims: {
1067+
relationship: 'many_to_one',
1068+
sql: \`\${merchant_dims.merchant_id} = \${merchant_and_product_dims.merchant_id} AND \${product_dims.product_id} = \${merchant_and_product_dims.product_id}\`
1069+
},
1070+
other_facts: {
1071+
relationship: 'one_to_many',
1072+
sql: \`\${CUBE.id} = \${other_facts.fact_id}\`
1073+
},
1074+
},
1075+
1076+
dimensions: {
1077+
id: {
1078+
sql: 'id',
1079+
type: 'number',
1080+
primary_key: true
1081+
},
1082+
merchant_sk: {
1083+
sql: 'merchant_sk',
1084+
type: 'number'
1085+
},
1086+
product_sk: {
1087+
sql: 'product_sk',
1088+
type: 'number'
1089+
},
1090+
acquisition_channel: {
1091+
sql: \`\${merchant_and_product_dims.acquisition_channel}\`,
1092+
type: 'string'
1093+
}
1094+
},
1095+
1096+
measures: {
1097+
amount_sum: {
1098+
sql: 'amount',
1099+
type: 'sum'
1100+
}
1101+
},
1102+
1103+
pre_aggregations: {
1104+
facts_rollup: {
1105+
dimensions: [
1106+
id,
1107+
merchant_sk,
1108+
merchant_dims.merchant_sk,
1109+
merchant_dims.merchant_id,
1110+
merchant_and_product_dims.merchant_id,
1111+
product_sk,
1112+
product_dims.product_sk,
1113+
product_dims.product_id,
1114+
merchant_and_product_dims.product_id,
1115+
acquisition_channel,
1116+
merchant_and_product_dims.status
1117+
]
1118+
},
1119+
rollupJoinTransitive: {
1120+
type: 'rollupJoin',
1121+
dimensions: [
1122+
merchant_sk,
1123+
product_sk,
1124+
merchant_and_product_dims.status,
1125+
other_facts.fact
1126+
],
1127+
rollups: [
1128+
facts_rollup,
1129+
other_facts.bridge_rollup
1130+
]
1131+
}
1132+
}
1133+
});
1134+
9281135
`);
9291136

9301137
it('simple pre-aggregation', async () => {
@@ -3234,4 +3441,58 @@ describe('PreAggregations', () => {
32343441
});
32353442
});
32363443
}
3444+
3445+
it('rollupJoin pre-aggregation matching with transitive joins', async () => {
3446+
await compiler.compile();
3447+
3448+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
3449+
dimensions: [
3450+
'test_facts.merchant_sk',
3451+
'test_facts.product_sk',
3452+
'merchant_and_product_dims.status',
3453+
'other_facts.fact'
3454+
],
3455+
timezone: 'America/Los_Angeles',
3456+
preAggregationsSchema: ''
3457+
});
3458+
3459+
const queryAndParams = query.buildSqlAndParams();
3460+
console.log(queryAndParams);
3461+
const preAggregationsDescription: any = query.preAggregations?.preAggregationsDescription();
3462+
console.log(JSON.stringify(preAggregationsDescription, null, 2));
3463+
3464+
// Verify that both rollups are included in the description
3465+
expect(preAggregationsDescription.length).toBe(2);
3466+
const factsRollup = preAggregationsDescription.find(p => p.preAggregationId === 'test_facts.facts_rollup');
3467+
const bridgeRollup = preAggregationsDescription.find(p => p.preAggregationId === 'other_facts.bridge_rollup');
3468+
expect(factsRollup).toBeDefined();
3469+
expect(bridgeRollup).toBeDefined();
3470+
3471+
// Verify that the rollupJoin pre-aggregation can be used for the query
3472+
expect(query.preAggregations?.preAggregationForQuery?.canUsePreAggregation).toEqual(true);
3473+
expect(query.preAggregations?.preAggregationForQuery?.preAggregationName).toEqual('rollupJoinTransitive');
3474+
3475+
return dbRunner.evaluateQueryWithPreAggregations(query).then(res => {
3476+
expect(res).toEqual([
3477+
{
3478+
merchant_and_product_dims__status: 'SOLD',
3479+
other_facts__fact: 'OF1',
3480+
test_facts__merchant_sk: 101,
3481+
test_facts__product_sk: 201,
3482+
},
3483+
{
3484+
merchant_and_product_dims__status: 'PAID',
3485+
other_facts__fact: 'OF2',
3486+
test_facts__merchant_sk: 101,
3487+
test_facts__product_sk: 202,
3488+
},
3489+
{
3490+
merchant_and_product_dims__status: 'RETURNED',
3491+
other_facts__fact: 'OF3',
3492+
test_facts__merchant_sk: 102,
3493+
test_facts__product_sk: 201,
3494+
},
3495+
]);
3496+
});
3497+
});
32373498
});

0 commit comments

Comments
 (0)