Skip to content

Commit 07d03a0

Browse files
committed
feat: add api to gooddata-sdk for agg fact
risk: low
1 parent 1b17638 commit 07d03a0

File tree

13 files changed

+979
-1755
lines changed

13 files changed

+979
-1755
lines changed

docker-compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ services:
2424
GDC_FEATURES_VALUES_ENABLE_SCHEDULING: "true"
2525
GDC_FEATURES_VALUES_ENABLE_ALERTING: "true"
2626
GDC_FEATURES_VALUES_ENABLE_SMTP: "true"
27+
GDC_FEATURES_VALUES_ENABLE_PRE_AGGREGATION_DATASETS: "true"
2728
# In the case of failing tests (HTTP 500), you can increase the memory for the metadata API
2829
# METADATA_API_JAVA_OPTS: "-Xmx1024m -Xms512m"
2930
gooddata-fdw:

gooddata-sdk/gooddata_sdk/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
)
179179
from gooddata_sdk.catalog.workspace.declarative_model.workspace.logical_model.dataset.dataset import (
180180
CatalogDataSourceTableIdentifier,
181+
CatalogDeclarativeAggregatedFact,
181182
CatalogDeclarativeAttribute,
182183
CatalogDeclarativeDataset,
183184
CatalogDeclarativeDatasetSql,

gooddata-sdk/gooddata_sdk/catalog/identifier.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
)
1717
from gooddata_api_client.model.declarative_user_group_identifier import DeclarativeUserGroupIdentifier
1818
from gooddata_api_client.model.declarative_user_identifier import DeclarativeUserIdentifier
19+
from gooddata_api_client.model.fact_identifier import FactIdentifier
1920
from gooddata_api_client.model.grain_identifier import GrainIdentifier
2021
from gooddata_api_client.model.label_identifier import LabelIdentifier
2122
from gooddata_api_client.model.reference_identifier import ReferenceIdentifier
@@ -82,6 +83,16 @@ def client_class() -> builtins.type[DeclarativeUserIdentifier]:
8283
return DeclarativeUserIdentifier
8384

8485

86+
@attr.s(auto_attribs=True, kw_only=True)
87+
class CatalogFactIdentifier(Base):
88+
id: str
89+
type: str = attr.field(validator=value_in_allowed)
90+
91+
@staticmethod
92+
def client_class() -> builtins.type[FactIdentifier]:
93+
return FactIdentifier
94+
95+
8596
@attr.s(auto_attribs=True, kw_only=True)
8697
class CatalogLabelIdentifier(Base):
8798
id: str

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from gooddata_sdk.catalog.workspace.declarative_model.workspace.logical_model.ldm import CatalogDeclarativeModel
2222
from gooddata_sdk.catalog.workspace.declarative_model.workspace.workspace import LAYOUT_WORKSPACES_DIR
2323
from gooddata_sdk.catalog.workspace.entity_model.content_objects.dataset import (
24+
CatalogAggregatedFact,
2425
CatalogAttribute,
2526
CatalogFact,
2627
CatalogLabel,
@@ -191,6 +192,24 @@ def get_facts_catalog(self, workspace_id: str) -> list[CatalogFact]:
191192
catalog_facts = [CatalogFact.from_api(fact) for fact in facts.data]
192193
return catalog_facts
193194

195+
def get_aggregated_facts_catalog(self, workspace_id: str) -> list[CatalogAggregatedFact]:
196+
"""Retrieve all aggregated facts in a given workspace.
197+
198+
Args:
199+
workspace_id (str):
200+
Workspace identification string e.g. "demo"
201+
202+
Returns:
203+
list[CatalogAggregatedFact]:
204+
List of all aggregated facts in a given workspace.
205+
"""
206+
get_agg_facts = functools.partial(
207+
self._entities_api.get_all_entities_aggregated_facts, workspace_id, _check_return_type=False
208+
)
209+
agg_facts = load_all_entities(get_agg_facts)
210+
catalog_agg_facts = [CatalogAggregatedFact.from_api(agg_fact) for agg_fact in agg_facts.data]
211+
return catalog_agg_facts
212+
194213
def get_dependent_entities_graph(self, workspace_id: str) -> CatalogDependentEntitiesResponse:
195214
"""There are dependencies among all catalog objects, the chain is the following:
196215
`fact/attribute/label → dataset → metric → visualization → dashboard`

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,24 @@
66

77
import attr
88
from gooddata_api_client.model.data_source_table_identifier import DataSourceTableIdentifier
9+
from gooddata_api_client.model.declarative_aggregated_fact import DeclarativeAggregatedFact
910
from gooddata_api_client.model.declarative_attribute import DeclarativeAttribute
1011
from gooddata_api_client.model.declarative_dataset import DeclarativeDataset
1112
from gooddata_api_client.model.declarative_dataset_sql import DeclarativeDatasetSql
1213
from gooddata_api_client.model.declarative_fact import DeclarativeFact
1314
from gooddata_api_client.model.declarative_label import DeclarativeLabel
1415
from gooddata_api_client.model.declarative_reference import DeclarativeReference
1516
from gooddata_api_client.model.declarative_reference_source import DeclarativeReferenceSource
17+
from gooddata_api_client.model.declarative_source_fact_reference import DeclarativeSourceFactReference
1618
from gooddata_api_client.model.declarative_workspace_data_filter_column import DeclarativeWorkspaceDataFilterColumn
1719

1820
from gooddata_sdk.catalog.base import Base
19-
from gooddata_sdk.catalog.identifier import CatalogGrainIdentifier, CatalogLabelIdentifier, CatalogReferenceIdentifier
21+
from gooddata_sdk.catalog.identifier import (
22+
CatalogFactIdentifier,
23+
CatalogGrainIdentifier,
24+
CatalogLabelIdentifier,
25+
CatalogReferenceIdentifier,
26+
)
2027
from gooddata_sdk.catalog.workspace.declarative_model.workspace.logical_model.data_filter_references import (
2128
CatalogDeclarativeWorkspaceDataFilterReferences,
2229
)
@@ -34,6 +41,7 @@ class CatalogDeclarativeDataset(Base):
3441
description: Optional[str] = None
3542
attributes: Optional[list[CatalogDeclarativeAttribute]] = None
3643
facts: Optional[list[CatalogDeclarativeFact]] = None
44+
aggregated_facts: Optional[list[CatalogDeclarativeAggregatedFact]] = None
3745
data_source_table_id: Optional[CatalogDataSourceTableIdentifier] = None
3846
sql: Optional[CatalogDeclarativeDatasetSql] = None
3947
tags: Optional[list[str]] = None
@@ -86,6 +94,30 @@ def client_class() -> type[DeclarativeFact]:
8694
return DeclarativeFact
8795

8896

97+
@attr.s(auto_attribs=True, kw_only=True)
98+
class CatalogDeclarativeSourceFactReference(Base):
99+
operation: str
100+
reference: CatalogFactIdentifier
101+
102+
@staticmethod
103+
def client_class() -> type[DeclarativeFact]:
104+
return DeclarativeSourceFactReference
105+
106+
107+
@attr.s(auto_attribs=True, kw_only=True)
108+
class CatalogDeclarativeAggregatedFact(Base):
109+
id: str
110+
source_column: str
111+
source_fact_reference: Optional[CatalogDeclarativeSourceFactReference] = None
112+
source_column_data_type: Optional[str] = None
113+
description: Optional[str] = None
114+
tags: Optional[list[str]] = None
115+
116+
@staticmethod
117+
def client_class() -> type[DeclarativeAggregatedFact]:
118+
return DeclarativeAggregatedFact
119+
120+
89121
@attr.s(auto_attribs=True, kw_only=True)
90122
class CatalogDataSourceTableIdentifier(Base):
91123
id: str

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@ def change_tables_columns_case(self, upper_case: Optional[bool] = None) -> Catal
241241
for fact in dataset.facts:
242242
if fact.source_column:
243243
fact.source_column = self._change_case(fact.source_column, upper_case)
244+
if dataset.aggregated_facts:
245+
for aggregated_fact in dataset.aggregated_facts:
246+
if aggregated_fact.source_column:
247+
aggregated_fact.source_column = self._change_case(aggregated_fact.source_column, upper_case)
244248
for reference in dataset.references:
245249
if reference.source_columns is not None:
246250
new_columns = [

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

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

66
import attr
77
import attrs
8+
from gooddata_api_client.model.json_api_aggregated_fact_out import JsonApiAggregatedFactOut
89
from gooddata_api_client.model.json_api_attribute_out import JsonApiAttributeOut
910
from gooddata_api_client.model.json_api_dataset_out import JsonApiDatasetOut
1011
from gooddata_api_client.model.json_api_fact_out import JsonApiFactOut
@@ -99,6 +100,18 @@ def as_computable(self) -> Metric:
99100
# TODO - dataset?
100101

101102

103+
@attr.s(auto_attribs=True, kw_only=True)
104+
class CatalogAggregatedFact(AttrCatalogEntity):
105+
@staticmethod
106+
def client_class() -> Any:
107+
return JsonApiAggregatedFactOut
108+
109+
def as_computable(self) -> Metric:
110+
return SimpleMetric(local_id=self.id, item=self.obj_id)
111+
112+
# TODO - dataset?
113+
114+
102115
@attr.s(auto_attribs=True, kw_only=True)
103116
class CatalogDataset(AttrCatalogEntity):
104117
@property

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,8 @@ def add_title_description_tags(
705705

706706
@staticmethod
707707
def set_title_description(workspace_object: Any, translated: dict[str, str]) -> None:
708-
if workspace_object.title:
708+
# Aggregated facts do not have a title as a property
709+
if hasattr(workspace_object, "title") and workspace_object.title:
709710
workspace_object.title = translated[workspace_object.title]
710711
if workspace_object.description:
711712
workspace_object.description = translated[workspace_object.description]
@@ -735,6 +736,8 @@ def get_texts_to_translate(
735736
self.add_title_description_tags(to_translate, label.title, label.description, label.tags)
736737
for fact in dataset.facts or []:
737738
self.add_title_description_tags(to_translate, fact.title, fact.description, fact.tags)
739+
for agg_fact in dataset.aggregated_facts or []:
740+
self.add_title_description_tags(to_translate, None, agg_fact.description, agg_fact.tags)
738741
for date_dataset in workspace_content.ldm.date_instances:
739742
self.add_title_description_tags(
740743
to_translate, date_dataset.title, date_dataset.description, date_dataset.tags
@@ -792,6 +795,8 @@ def set_translated_texts(
792795
self.set_title_description_tags(label, translated)
793796
for fact in dataset.facts or []:
794797
self.set_title_description_tags(fact, translated)
798+
for agg_fact in dataset.aggregated_facts or []:
799+
self.set_title_description_tags(agg_fact, translated)
795800
for date_dataset in new_workspace_content.ldm.date_instances:
796801
self.set_title_description_tags(date_dataset, translated)
797802
# ADM
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# (C) 2025 GoodData Corporation
2+
version: 1
3+
interactions:
4+
- request:
5+
method: GET
6+
uri: http://localhost:3000/api/v1/entities/workspaces/demo/aggregatedFacts?page=0&size=500
7+
body: null
8+
headers:
9+
Accept:
10+
- application/vnd.gooddata.api+json
11+
Accept-Encoding:
12+
- br, gzip, deflate
13+
X-GDC-VALIDATE-RELATIONS:
14+
- 'true'
15+
X-Requested-With:
16+
- XMLHttpRequest
17+
response:
18+
status:
19+
code: 200
20+
message: OK
21+
headers:
22+
Cache-Control:
23+
- no-cache, no-store, max-age=0, must-revalidate
24+
Content-Length:
25+
- '211'
26+
Content-Type:
27+
- application/vnd.gooddata.api+json
28+
DATE: &id001
29+
- PLACEHOLDER
30+
Expires:
31+
- '0'
32+
Featurepolicy:
33+
- geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr
34+
'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope
35+
'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none';
36+
Pragma:
37+
- no-cache
38+
Referrer-Policy:
39+
- same-origin
40+
Vary:
41+
- Origin
42+
- Access-Control-Request-Method
43+
- Access-Control-Request-Headers
44+
X-Content-Type-Options:
45+
- nosniff
46+
X-Frame-Options:
47+
- SAMEORIGIN
48+
X-GDC-TRACE-ID: *id001
49+
X-Xss-Protection:
50+
- 1; mode=block
51+
body:
52+
string:
53+
data: []
54+
links:
55+
self: http://localhost:3000/api/v1/entities/workspaces/demo/aggregatedFacts?page=0&size=500
56+
next: http://localhost:3000/api/v1/entities/workspaces/demo/aggregatedFacts?page=1&size=500

0 commit comments

Comments
 (0)