Skip to content

Commit 8d611d6

Browse files
committed
test: add aggregated dataset to testing ldm
risk: nonprod
1 parent 3e7956d commit 8d611d6

File tree

10 files changed

+234
-12
lines changed

10 files changed

+234
-12
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
@@ -42,6 +42,7 @@ class CatalogDeclarativeDataset(Base):
4242
attributes: Optional[list[CatalogDeclarativeAttribute]] = None
4343
facts: Optional[list[CatalogDeclarativeFact]] = None
4444
aggregated_facts: Optional[list[CatalogDeclarativeAggregatedFact]] = None
45+
precedence: Optional[int] = None
4546
data_source_table_id: Optional[CatalogDataSourceTableIdentifier] = None
4647
sql: Optional[CatalogDeclarativeDatasetSql] = None
4748
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: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,6 +2376,70 @@
23762376
],
23772377
"title": "Campaign channels"
23782378
},
2379+
{
2380+
"attributes": [
2381+
{
2382+
"description": "Category Agg",
2383+
"id": "campaign_channels.category_agg",
2384+
"sourceColumn": "category",
2385+
"sourceColumnDataType": "STRING",
2386+
"labels": [],
2387+
"tags": [
2388+
"Campaign channels"
2389+
],
2390+
"title": "Category"
2391+
}
2392+
],
2393+
"description": "Campaign channels per categories",
2394+
"facts": [],
2395+
"aggregatedFacts": [
2396+
{
2397+
"description": "Budget Agg",
2398+
"id": "budget_agg",
2399+
"sourceColumn": "budget",
2400+
"sourceColumnDataType": "INT",
2401+
"tags": [
2402+
"Campaign channels per category"
2403+
],
2404+
"sourceFactReference": {
2405+
"reference": {
2406+
"id": "budget",
2407+
"type": "fact"
2408+
},
2409+
"operation": "SUM"
2410+
}
2411+
}
2412+
],
2413+
"grain": [
2414+
{
2415+
"id": "campaign_channels.category_agg",
2416+
"type": "attribute"
2417+
}
2418+
],
2419+
"id": "campaign_channels_per_category",
2420+
"precedence": 1,
2421+
"references": [
2422+
{
2423+
"identifier": {
2424+
"id": "campaign_channels",
2425+
"type": "dataset"
2426+
},
2427+
"multivalue": false,
2428+
"sourceColumns": [
2429+
"campaign_channel_category"
2430+
],
2431+
"sourceColumnDataTypes": [ "STRING" ]
2432+
}
2433+
],
2434+
"tags": [
2435+
"Campaign channels per category"
2436+
],
2437+
"sql": {
2438+
"statement": "SELECT category, SUM(budget) FROM campaign_channels GROUP BY category",
2439+
"dataSourceId": "demo-test-ds"
2440+
},
2441+
"title": "Campaign channels per category"
2442+
},
23792443
{
23802444
"attributes": [
23812445
{
@@ -2412,6 +2476,7 @@
24122476
},
24132477
"description": "Campaigns",
24142478
"facts": [],
2479+
"aggregatedFacts": [],
24152480
"grain": [
24162481
{
24172482
"id": "campaign_id",
@@ -2494,6 +2559,7 @@
24942559
},
24952560
"description": "Customers",
24962561
"facts": [],
2562+
"aggregatedFacts": [],
24972563
"grain": [
24982564
{
24992565
"id": "customer_id",
@@ -2575,6 +2641,7 @@
25752641
"title": "Quantity"
25762642
}
25772643
],
2644+
"aggregatedFacts": [],
25782645
"grain": [
25792646
{
25802647
"id": "order_line_id",
@@ -2724,6 +2791,7 @@
27242791
},
27252792
"description": "Products",
27262793
"facts": [],
2794+
"aggregatedFacts": [],
27272795
"grain": [
27282796
{
27292797
"id": "product_id",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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: category
10+
dataType: STRING
11+
target:
12+
id: category
13+
type: attribute
14+
- column: budget
15+
dataType: INT
16+
target:
17+
id: budget
18+
type: fact
19+
title: Campaign channels per category
20+
description: Campaign channels per categories
21+
attributes: []
22+
facts: []
23+
grain: []
24+
aggregatedFacts:
25+
- id: budget_agg
26+
sourceColumn: budget
27+
sourceFactReference:
28+
operation: SUM
29+
reference:
30+
id: budget
31+
type: fact
32+
sourceColumnDataType: INT
33+
description: Budget Agg
34+
tags:
35+
- Campaign channels per category
36+
precedence: 1
37+
sql:
38+
dataSourceId: demo-test-ds
39+
statement: SELECT category, SUM(budget) FROM campaign_channels GROUP
40+
BY category
41+
tags:
42+
- Campaign channels per category
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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: category
10+
dataType: STRING
11+
target:
12+
id: category
13+
type: attribute
14+
- column: budget
15+
dataType: INT
16+
target:
17+
id: budget
18+
type: fact
19+
title: Campaign channels per category
20+
description: Campaign channels per categories
21+
attributes: []
22+
facts: []
23+
grain: []
24+
aggregatedFacts:
25+
- id: budget_agg
26+
sourceColumn: budget
27+
sourceFactReference:
28+
operation: SUM
29+
reference:
30+
id: budget
31+
type: fact
32+
sourceColumnDataType: INT
33+
description: Budget Agg
34+
tags:
35+
- Campaign channels per category
36+
precedence: 1
37+
sql:
38+
dataSourceId: demo-test-ds
39+
statement: SELECT category, SUM(budget) FROM campaign_channels GROUP
40+
BY category
41+
tags:
42+
- 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: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2346,6 +2346,54 @@
23462346
],
23472347
"title": "Campaign channels"
23482348
},
2349+
{
2350+
"attributes": [],
2351+
"description": "Campaign channels per categories",
2352+
"facts": [],
2353+
"aggregatedFacts": [
2354+
{
2355+
"description": "Budget Agg",
2356+
"id": "budget_agg",
2357+
"sourceColumn": "budget",
2358+
"sourceColumnDataType": "INT",
2359+
"tags": [
2360+
"Campaign channels per category"
2361+
],
2362+
"sourceFactReference": {
2363+
"reference": {
2364+
"id": "budget",
2365+
"type": "fact"
2366+
},
2367+
"operation": "SUM"
2368+
}
2369+
}
2370+
],
2371+
"grain": [],
2372+
"id": "campaign_channels_per_category",
2373+
"precedence": 1,
2374+
"references": [
2375+
{
2376+
"identifier": {
2377+
"id": "campaign_channels",
2378+
"type": "dataset"
2379+
},
2380+
"multivalue": false,
2381+
"sourceColumns": [
2382+
"category",
2383+
"budget"
2384+
],
2385+
"sourceColumnDataTypes": [ "STRING", "INT" ]
2386+
}
2387+
],
2388+
"tags": [
2389+
"Campaign channels per category"
2390+
],
2391+
"sql": {
2392+
"statement": "SELECT category, SUM(budget) FROM campaign_channels GROUP BY category",
2393+
"dataSourceId": "demo-test-ds"
2394+
},
2395+
"title": "Campaign channels per category"
2396+
},
23492397
{
23502398
"attributes": [
23512399
{
@@ -2672,11 +2720,21 @@
26722720
"dateInstances": [
26732721
{
26742722
"granularities": [
2723+
"MINUTE",
2724+
"HOUR",
26752725
"DAY",
26762726
"MONTH",
26772727
"QUARTER",
26782728
"WEEK",
2679-
"YEAR"
2729+
"YEAR",
2730+
"MINUTE_OF_HOUR",
2731+
"HOUR_OF_DAY",
2732+
"DAY_OF_WEEK",
2733+
"DAY_OF_MONTH",
2734+
"DAY_OF_YEAR",
2735+
"WEEK_OF_YEAR",
2736+
"MONTH_OF_YEAR",
2737+
"QUARTER_OF_YEAR"
26802738
],
26812739
"granularitiesFormatting": {
26822740
"titleBase": "",

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)