Skip to content

Commit 8f7acc7

Browse files
committed
add 'rollupJoin pre-aggregation matching with transitive joins' test
1 parent 35f6368 commit 8f7acc7

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
@@ -967,6 +967,213 @@ describe('PreAggregations', () => {
967967
]
968968
});
969969
970+
// Models with transitive joins for rollupJoin matching
971+
cube('merchant_dims', {
972+
sql: \`
973+
SELECT 101 AS merchant_sk, 'M1' AS merchant_id
974+
UNION ALL
975+
SELECT 102 AS merchant_sk, 'M2' AS merchant_id
976+
\`,
977+
978+
dimensions: {
979+
merchant_sk: {
980+
sql: 'merchant_sk',
981+
type: 'number',
982+
primary_key: true
983+
},
984+
merchant_id: {
985+
sql: 'merchant_id',
986+
type: 'string'
987+
}
988+
}
989+
});
990+
991+
cube('product_dims', {
992+
sql: \`
993+
SELECT 201 AS product_sk, 'P1' AS product_id
994+
UNION ALL
995+
SELECT 202 AS product_sk, 'P2' AS product_id
996+
\`,
997+
998+
dimensions: {
999+
product_sk: {
1000+
sql: 'product_sk',
1001+
type: 'number',
1002+
primary_key: true
1003+
},
1004+
product_id: {
1005+
sql: 'product_id',
1006+
type: 'string'
1007+
}
1008+
}
1009+
});
1010+
1011+
cube('merchant_and_product_dims', {
1012+
sql: \`
1013+
SELECT 'M1' AS merchant_id, 'P1' AS product_id, 'Organic' AS acquisition_channel, 'SOLD' AS status
1014+
UNION ALL
1015+
SELECT 'M1' AS merchant_id, 'P2' AS product_id, 'Paid' AS acquisition_channel, 'PAID' AS status
1016+
UNION ALL
1017+
SELECT 'M2' AS merchant_id, 'P1' AS product_id, 'Referral' AS acquisition_channel, 'RETURNED' AS status
1018+
\`,
1019+
1020+
dimensions: {
1021+
product_id: {
1022+
sql: 'product_id',
1023+
type: 'string',
1024+
primary_key: true
1025+
},
1026+
merchant_id: {
1027+
sql: 'merchant_id',
1028+
type: 'string',
1029+
primary_key: true
1030+
},
1031+
status: {
1032+
sql: 'status',
1033+
type: 'string'
1034+
},
1035+
acquisition_channel: {
1036+
sql: 'acquisition_channel',
1037+
type: 'string'
1038+
}
1039+
},
1040+
1041+
pre_aggregations: {
1042+
bridge_rollup: {
1043+
dimensions: [
1044+
merchant_id,
1045+
product_id,
1046+
acquisition_channel,
1047+
status
1048+
]
1049+
}
1050+
}
1051+
});
1052+
1053+
cube('other_facts', {
1054+
sql: \`
1055+
SELECT 1 AS id, 1 AS fact_id, 'OF1' AS fact
1056+
UNION ALL
1057+
SELECT 2 AS id, 2 AS fact_id, 'OF2' AS fact
1058+
UNION ALL
1059+
SELECT 3 AS id, 3 AS fact_id, 'OF3' AS fact
1060+
\`,
1061+
1062+
dimensions: {
1063+
other_fact_id: {
1064+
sql: 'id',
1065+
type: 'number',
1066+
primary_key: true
1067+
},
1068+
fact_id: {
1069+
sql: 'fact_id',
1070+
type: 'number'
1071+
},
1072+
fact: {
1073+
sql: 'fact',
1074+
type: 'string'
1075+
}
1076+
},
1077+
1078+
pre_aggregations: {
1079+
bridge_rollup: {
1080+
dimensions: [
1081+
fact_id,
1082+
fact
1083+
]
1084+
}
1085+
}
1086+
1087+
});
1088+
1089+
cube('test_facts', {
1090+
sql: \`
1091+
SELECT 1 AS id, 101 AS merchant_sk, 201 AS product_sk, 100 AS amount
1092+
UNION ALL
1093+
SELECT 2 AS id, 101 AS merchant_sk, 202 AS product_sk, 150 AS amount
1094+
UNION ALL
1095+
SELECT 3 AS id, 102 AS merchant_sk, 201 AS product_sk, 200 AS amount
1096+
\`,
1097+
1098+
joins: {
1099+
merchant_dims: {
1100+
relationship: 'many_to_one',
1101+
sql: \`\${CUBE.merchant_sk} = \${merchant_dims.merchant_sk}\`
1102+
},
1103+
product_dims: {
1104+
relationship: 'many_to_one',
1105+
sql: \`\${CUBE.product_sk} = \${product_dims.product_sk}\`
1106+
},
1107+
// Transitive join - depends on merchant_dims and product_dims
1108+
merchant_and_product_dims: {
1109+
relationship: 'many_to_one',
1110+
sql: \`\${merchant_dims.merchant_id} = \${merchant_and_product_dims.merchant_id} AND \${product_dims.product_id} = \${merchant_and_product_dims.product_id}\`
1111+
},
1112+
other_facts: {
1113+
relationship: 'one_to_many',
1114+
sql: \`\${CUBE.id} = \${other_facts.fact_id}\`
1115+
},
1116+
},
1117+
1118+
dimensions: {
1119+
id: {
1120+
sql: 'id',
1121+
type: 'number',
1122+
primary_key: true
1123+
},
1124+
merchant_sk: {
1125+
sql: 'merchant_sk',
1126+
type: 'number'
1127+
},
1128+
product_sk: {
1129+
sql: 'product_sk',
1130+
type: 'number'
1131+
},
1132+
acquisition_channel: {
1133+
sql: \`\${merchant_and_product_dims.acquisition_channel}\`,
1134+
type: 'string'
1135+
}
1136+
},
1137+
1138+
measures: {
1139+
amount_sum: {
1140+
sql: 'amount',
1141+
type: 'sum'
1142+
}
1143+
},
1144+
1145+
pre_aggregations: {
1146+
facts_rollup: {
1147+
dimensions: [
1148+
id,
1149+
merchant_sk,
1150+
merchant_dims.merchant_sk,
1151+
merchant_dims.merchant_id,
1152+
merchant_and_product_dims.merchant_id,
1153+
product_sk,
1154+
product_dims.product_sk,
1155+
product_dims.product_id,
1156+
merchant_and_product_dims.product_id,
1157+
acquisition_channel,
1158+
merchant_and_product_dims.status
1159+
]
1160+
},
1161+
rollupJoinTransitive: {
1162+
type: 'rollupJoin',
1163+
dimensions: [
1164+
merchant_sk,
1165+
product_sk,
1166+
merchant_and_product_dims.status,
1167+
other_facts.fact
1168+
],
1169+
rollups: [
1170+
facts_rollup,
1171+
other_facts.bridge_rollup
1172+
]
1173+
}
1174+
}
1175+
});
1176+
9701177
`);
9711178

9721179
it('simple pre-aggregation', async () => {
@@ -3276,4 +3483,58 @@ describe('PreAggregations', () => {
32763483
});
32773484
});
32783485
}
3486+
3487+
it('rollupJoin pre-aggregation matching with transitive joins', async () => {
3488+
await compiler.compile();
3489+
3490+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
3491+
dimensions: [
3492+
'test_facts.merchant_sk',
3493+
'test_facts.product_sk',
3494+
'merchant_and_product_dims.status',
3495+
'other_facts.fact'
3496+
],
3497+
timezone: 'America/Los_Angeles',
3498+
preAggregationsSchema: ''
3499+
});
3500+
3501+
const queryAndParams = query.buildSqlAndParams();
3502+
console.log(queryAndParams);
3503+
const preAggregationsDescription: any = query.preAggregations?.preAggregationsDescription();
3504+
console.log(JSON.stringify(preAggregationsDescription, null, 2));
3505+
3506+
// Verify that both rollups are included in the description
3507+
expect(preAggregationsDescription.length).toBe(2);
3508+
const factsRollup = preAggregationsDescription.find(p => p.preAggregationId === 'test_facts.facts_rollup');
3509+
const bridgeRollup = preAggregationsDescription.find(p => p.preAggregationId === 'other_facts.bridge_rollup');
3510+
expect(factsRollup).toBeDefined();
3511+
expect(bridgeRollup).toBeDefined();
3512+
3513+
// Verify that the rollupJoin pre-aggregation can be used for the query
3514+
expect(query.preAggregations?.preAggregationForQuery?.canUsePreAggregation).toEqual(true);
3515+
expect(query.preAggregations?.preAggregationForQuery?.preAggregationName).toEqual('rollupJoinTransitive');
3516+
3517+
return dbRunner.evaluateQueryWithPreAggregations(query).then(res => {
3518+
expect(res).toEqual([
3519+
{
3520+
merchant_and_product_dims__status: 'SOLD',
3521+
other_facts__fact: 'OF1',
3522+
test_facts__merchant_sk: 101,
3523+
test_facts__product_sk: 201,
3524+
},
3525+
{
3526+
merchant_and_product_dims__status: 'PAID',
3527+
other_facts__fact: 'OF2',
3528+
test_facts__merchant_sk: 101,
3529+
test_facts__product_sk: 202,
3530+
},
3531+
{
3532+
merchant_and_product_dims__status: 'RETURNED',
3533+
other_facts__fact: 'OF3',
3534+
test_facts__merchant_sk: 102,
3535+
test_facts__product_sk: 201,
3536+
},
3537+
]);
3538+
});
3539+
});
32793540
});

0 commit comments

Comments
 (0)