Skip to content

Commit 134dc7c

Browse files
committed
test: add aggregated dataset to testing ldm
risk: nonprod
1 parent 82a1c2d commit 134dc7c

File tree

10 files changed

+207
-13
lines changed

10 files changed

+207
-13
lines changed

gooddata-sdk/gooddata_sdk/catalog/workspace/declarative_model/workspace/logical_model/dataset/dataset.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class CatalogDeclarativeDataset(Base):
4343
attributes: Optional[list[CatalogDeclarativeAttribute]] = None
4444
facts: Optional[list[CatalogDeclarativeFact]] = None
4545
aggregated_facts: Optional[list[CatalogDeclarativeAggregatedFact]] = attrs.field(factory=list)
46+
precedence: Optional[int] = None
4647
data_source_table_id: Optional[CatalogDataSourceTableIdentifier] = None
4748
sql: Optional[CatalogDeclarativeDatasetSql] = None
4849
tags: Optional[list[str]] = None

gooddata-sdk/gooddata_sdk/catalog/workspace/entity_model/content_objects/dataset.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ def generate_facts_from_api(self) -> list[CatalogFact]:
145145
default=attr.Factory(lambda self: self.generate_facts_from_api(), takes_self=True),
146146
)
147147

148+
# TODO: Doublecheck if we shouldn't do something like for facts
149+
aggregated_facts: Optional[list[CatalogAggregatedFact]] = attr.field(
150+
default=attr.Factory(lambda self: self.json_api_attributes.get("aggregatedFacts"), takes_self=True),
151+
)
152+
precedence: Optional[int] = attr.field(
153+
default=attr.Factory(lambda self: self.json_api_attributes.get("precedence"), takes_self=True)
154+
)
155+
148156
grain: Optional[list] = attr.field(
149157
default=attr.Factory(lambda self: self.json_api_attributes.get("grain"), takes_self=True)
150158
)

gooddata-sdk/gooddata_sdk/catalog/workspace/model_container.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from gooddata_sdk.catalog.types import ValidObjects
88
from gooddata_sdk.catalog.workspace.entity_model.content_objects.dataset import (
9+
CatalogAggregatedFact,
910
CatalogAttribute,
1011
CatalogDataset,
1112
CatalogFact,
@@ -46,6 +47,10 @@ def datasets(self) -> list[CatalogDataset]:
4647
def facts(self) -> list[CatalogFact]:
4748
return [f for d in self._datasets for f in d.facts]
4849

50+
@property
51+
def aggregated_facts(self) -> list[CatalogAggregatedFact]:
52+
return [f for d in self._datasets for f in d.aggregated_facts]
53+
4954
@property
5055
def attributes(self) -> list[CatalogAttribute]:
5156
return [a for d in self._datasets for a in d.attributes]

gooddata-sdk/tests/catalog/expected/declarative_workspaces.json

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2450,7 +2450,59 @@
24502450
"title": "Campaign channels"
24512451
},
24522452
{
2453-
"aggregatedFacts": [],
2453+
"attributes": [],
2454+
"description": "Campaign channels per categories",
2455+
"facts": [],
2456+
"aggregatedFacts": [
2457+
{
2458+
"description": "Budget Agg",
2459+
"id": "budget_agg",
2460+
"sourceColumn": "budget",
2461+
"sourceColumnDataType": "INT",
2462+
"tags": [
2463+
"Campaign channels per category"
2464+
],
2465+
"sourceFactReference": {
2466+
"reference": {
2467+
"id": "budget",
2468+
"type": "fact"
2469+
},
2470+
"operation": "SUM"
2471+
}
2472+
}
2473+
],
2474+
"grain": [],
2475+
"id": "campaign_channels_per_category",
2476+
"precedence": 1,
2477+
"references": [
2478+
{
2479+
"identifier": {
2480+
"id": "campaign_channels",
2481+
"type": "dataset"
2482+
},
2483+
"multivalue": false,
2484+
"sources": [
2485+
{
2486+
"column": "campaign_channel_id",
2487+
"dataType": "STRING",
2488+
"target": {
2489+
"id": "campaign_channel_id",
2490+
"type": "attribute"
2491+
}
2492+
}
2493+
]
2494+
}
2495+
],
2496+
"tags": [
2497+
"Campaign channels per category"
2498+
],
2499+
"sql": {
2500+
"statement": "SELECT category, SUM(budget) FROM campaign_channels GROUP BY category",
2501+
"dataSourceId": "demo-test-ds"
2502+
},
2503+
"title": "Campaign channels per category"
2504+
},
2505+
{
24542506
"attributes": [
24552507
{
24562508
"description": "Campaign id",
@@ -2486,6 +2538,7 @@
24862538
},
24872539
"description": "Campaigns",
24882540
"facts": [],
2541+
"aggregatedFacts": [],
24892542
"grain": [
24902543
{
24912544
"id": "campaign_id",
@@ -2570,6 +2623,7 @@
25702623
},
25712624
"description": "Customers",
25722625
"facts": [],
2626+
"aggregatedFacts": [],
25732627
"grain": [
25742628
{
25752629
"id": "customer_id",
@@ -2652,6 +2706,7 @@
26522706
"title": "Quantity"
26532707
}
26542708
],
2709+
"aggregatedFacts": [],
26552710
"grain": [
26562711
{
26572712
"id": "order_line_id",
@@ -2802,6 +2857,7 @@
28022857
},
28032858
"description": "Products",
28042859
"facts": [],
2860+
"aggregatedFacts": [],
28052861
"grain": [
28062862
{
28072863
"id": "product_id",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# (C) 2025 GoodData Corporation
2+
id: campaign_channels_per_category
3+
references:
4+
- identifier:
5+
id: campaign_channels
6+
type: dataset
7+
multivalue: false
8+
sources:
9+
- column: campaign_channel_id
10+
dataType: NUMERIC
11+
target:
12+
id: campaign_channel_id
13+
type: attribute
14+
title: Campaign channels per category
15+
description: Campaign channels per categories
16+
attributes: []
17+
facts: []
18+
grain: []
19+
aggregatedFacts:
20+
- id: budget_agg
21+
sourceColumn: budget
22+
sourceFactReference:
23+
operation: SUM
24+
reference:
25+
id: budget
26+
type: fact
27+
sourceColumnDataType: INT
28+
description: Budget Agg
29+
tags:
30+
- Campaign channels per category
31+
precedence: 1
32+
sql:
33+
dataSourceId: demo-test-ds
34+
statement: SELECT category, SUM(budget) FROM campaign_channels GROUP
35+
BY category
36+
tags:
37+
- Campaign channels per category
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# (C) 2025 GoodData Corporation
2+
id: campaign_channels_per_category
3+
references:
4+
- identifier:
5+
id: campaign_channels
6+
type: dataset
7+
multivalue: false
8+
sources:
9+
- column: campaign_channel_id
10+
dataType: NUMERIC
11+
target:
12+
id: campaign_channel_id
13+
type: attribute
14+
title: Campaign channels per category
15+
description: Campaign channels per categories
16+
attributes: []
17+
facts: []
18+
grain: []
19+
aggregatedFacts:
20+
- id: budget_agg
21+
sourceColumn: budget
22+
sourceFactReference:
23+
operation: SUM
24+
reference:
25+
id: budget
26+
type: fact
27+
sourceColumnDataType: INT
28+
description: Budget Agg
29+
tags:
30+
- Campaign channels per category
31+
precedence: 1
32+
sql:
33+
dataSourceId: demo-test-ds
34+
statement: SELECT category, SUM(budget) FROM campaign_channels GROUP
35+
BY category
36+
tags:
37+
- Campaign channels per category

gooddata-sdk/tests/catalog/test_catalog_workspace.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,8 +701,7 @@ def test_clone_workspace(test_config):
701701
default_cloned_decl_ws = sdk.catalog_workspace.get_declarative_workspace(default_cloned_ws_id)
702702
assert default_cloned_decl_ws.ldm.datasets[0].data_source_table_id.data_source_id == test_config["data_source2"]
703703
assert default_cloned_decl_ws.ldm.datasets[0].facts[0].source_column == "BUDGET"
704-
# TODO: Add a nontrivial test for agg facts here
705-
assert default_cloned_decl_ws.ldm.datasets[0].aggregated_facts == []
704+
assert default_cloned_decl_ws.ldm.datasets[1].aggregated_facts[0].source_column == "BUDGET"
706705

707706
sdk.catalog_workspace.clone_workspace(
708707
source_ws_id, target_workspace_id=custom_cloned_ws_id, target_workspace_name=custom_cloned_ws_name
@@ -756,7 +755,7 @@ def test_translate_workspace(test_config):
756755
for fact in dataset.facts:
757756
if fact.id == "budget":
758757
assert fact.title == "Rozpočet"
759-
# TODO: Add agg facts here for descriptions?
758+
# TODO: Do for aggregated facts descriptions
760759

761760
# Run second time without translation function. Previous execution created translation file, which is used.
762761
sdk.catalog_workspace.generate_localized_workspaces(

gooddata-sdk/tests/catalog/test_catalog_workspace_content.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ def test_catalog_list_facts(test_config):
6363
def test_catalog_list_aggregated_facts(test_config):
6464
sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"])
6565
agg_facts_list = sdk.catalog_workspace_content.get_aggregated_facts_catalog(test_config["workspace"])
66-
# TODO: Add a non-trivial test
67-
assert len(agg_facts_list) == 0
66+
assert len(agg_facts_list) == 1
6867

6968

7069
@gd_vcr.use_cassette(str(_fixtures_dir / "demo_catalog_list_attributes.yaml"))
@@ -129,7 +128,7 @@ def test_load_and_modify_ds_and_put_declarative_ldm(test_config):
129128
sdk.catalog_workspace.create_or_update(workspace)
130129

131130
ldm_e = sdk.catalog_workspace_content.get_declarative_ldm(workspace_id)
132-
ds_e = list(set([d.data_source_table_id.data_source_id for d in ldm_e.ldm.datasets]))
131+
ds_e = list(set([d.data_source_table_id.data_source_id for d in ldm_e.ldm.datasets if d.data_source_table_id]))
133132
assert ds_e == [test_config["data_source"]]
134133

135134
try:
@@ -147,7 +146,7 @@ def test_load_and_modify_ds_and_put_declarative_ldm(test_config):
147146
ldm_e.ldm.modify_mapped_data_source(data_source_mapping=reverse_data_source_mapping)
148147
sdk.catalog_workspace_content.put_declarative_ldm(identifier, ldm_e, validator, standalone_copy=True)
149148
ldm_o = sdk.catalog_workspace_content.get_declarative_ldm(identifier)
150-
ds_o = list(set([d.data_source_table_id.data_source_id for d in ldm_o.ldm.datasets]))
149+
ds_o = list(set([d.data_source_table_id.data_source_id for d in ldm_o.ldm.datasets if d.data_source_table_id]))
151150
assert ds_o == [test_config["data_source"]]
152151
finally:
153152
_refresh_workspaces(sdk)
@@ -166,7 +165,7 @@ def test_load_ldm_and_modify_tables_columns_case(test_config):
166165
assert ldm_e.ldm.datasets[0].data_source_table_id.id == table_id.upper()
167166
assert ldm_e.ldm.datasets[0].attributes[0].source_column == attribute_column.upper()
168167
assert ldm_e.ldm.datasets[0].facts[0].source_column == fact_column.upper()
169-
# TODO: Add agg facts here
168+
assert ldm_e.ldm.datasets[1].aggregated_facts[0].source_column == fact_column.upper()
170169
assert ldm_e.ldm.datasets[0].references[0].source_columns is None
171170
assert ldm_e.ldm.datasets[0].references[0].sources[0].column == reference_column.upper()
172171
# Test chaining approach as well
@@ -178,7 +177,7 @@ def test_load_ldm_and_modify_tables_columns_case(test_config):
178177
assert ldm_o.ldm.datasets[0].data_source_table_id.id == table_id
179178
assert ldm_o.ldm.datasets[0].attributes[0].source_column == attribute_column
180179
assert ldm_o.ldm.datasets[0].facts[0].source_column == fact_column
181-
# TODO: Add agg facts here
180+
assert ldm_o.ldm.datasets[1].aggregated_facts[0].source_column == fact_column
182181
assert ldm_o.ldm.datasets[0].references[0].source_columns is None
183182
assert ldm_e.ldm.datasets[0].references[0].sources[0].column == reference_column
184183

@@ -313,7 +312,7 @@ def test_catalog_load(test_config):
313312

314313
# rough initial smoke-test; just do a quick 'rub'
315314
assert len(catalog.metrics) == 24
316-
assert len(catalog.datasets) == 6
315+
assert len(catalog.datasets) == 7
317316

318317
assert catalog.get_metric("order_amount") is not None
319318
assert catalog.get_metric("revenue") is not None

tests-support/fixtures/demo_declarative_hierarchy.json

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2611,7 +2611,59 @@
26112611
"title": "Campaign channels"
26122612
},
26132613
{
2614-
"aggregatedFacts": [],
2614+
"attributes": [],
2615+
"description": "Campaign channels per categories",
2616+
"facts": [],
2617+
"aggregatedFacts": [
2618+
{
2619+
"description": "Budget Agg",
2620+
"id": "budget_agg",
2621+
"sourceColumn": "budget",
2622+
"sourceColumnDataType": "INT",
2623+
"tags": [
2624+
"Campaign channels per category"
2625+
],
2626+
"sourceFactReference": {
2627+
"reference": {
2628+
"id": "budget",
2629+
"type": "fact"
2630+
},
2631+
"operation": "SUM"
2632+
}
2633+
}
2634+
],
2635+
"grain": [],
2636+
"id": "campaign_channels_per_category",
2637+
"precedence": 1,
2638+
"references": [
2639+
{
2640+
"identifier": {
2641+
"id": "campaign_channels",
2642+
"type": "dataset"
2643+
},
2644+
"multivalue": false,
2645+
"sources": [
2646+
{
2647+
"column": "campaign_channel_id",
2648+
"dataType": "STRING",
2649+
"target": {
2650+
"id": "campaign_channel_id",
2651+
"type": "attribute"
2652+
}
2653+
}
2654+
]
2655+
}
2656+
],
2657+
"tags": [
2658+
"Campaign channels per category"
2659+
],
2660+
"sql": {
2661+
"statement": "SELECT category, SUM(budget) FROM campaign_channels GROUP BY category",
2662+
"dataSourceId": "demo-test-ds"
2663+
},
2664+
"title": "Campaign channels per category"
2665+
},
2666+
{
26152667
"attributes": [
26162668
{
26172669
"description": "Campaign id",

tests-support/upload_demo_layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def rest_op(op, url_path, data=None, raise_ex=True):
3535

3636
if response.status_code < 200 or response.status_code > 299:
3737
if raise_ex:
38-
raise Exception(f"Call to {url} failed - {str(response)}")
38+
raise Exception(f"Call to {url} failed - {str(response.text)}")
3939
else:
4040
return None
4141

0 commit comments

Comments
 (0)