Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ services:
GDC_FEATURES_VALUES_ENABLE_SCHEDULING: "true"
GDC_FEATURES_VALUES_ENABLE_ALERTING: "true"
GDC_FEATURES_VALUES_ENABLE_SMTP: "true"
GDC_FEATURES_VALUES_ENABLE_PRE_AGGREGATION_DATASETS: "true"
# In the case of failing tests (HTTP 500), you can increase the memory for the metadata API
# METADATA_API_JAVA_OPTS: "-Xmx1024m -Xms512m"
gooddata-fdw:
Expand Down
1 change: 1 addition & 0 deletions gooddata-sdk/gooddata_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
)
from gooddata_sdk.catalog.workspace.declarative_model.workspace.logical_model.dataset.dataset import (
CatalogDataSourceTableIdentifier,
CatalogDeclarativeAggregatedFact,
CatalogDeclarativeAttribute,
CatalogDeclarativeDataset,
CatalogDeclarativeDatasetSql,
Expand Down
11 changes: 11 additions & 0 deletions gooddata-sdk/gooddata_sdk/catalog/identifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
)
from gooddata_api_client.model.declarative_user_group_identifier import DeclarativeUserGroupIdentifier
from gooddata_api_client.model.declarative_user_identifier import DeclarativeUserIdentifier
from gooddata_api_client.model.fact_identifier import FactIdentifier
from gooddata_api_client.model.grain_identifier import GrainIdentifier
from gooddata_api_client.model.label_identifier import LabelIdentifier
from gooddata_api_client.model.reference_identifier import ReferenceIdentifier
Expand Down Expand Up @@ -82,6 +83,16 @@ def client_class() -> builtins.type[DeclarativeUserIdentifier]:
return DeclarativeUserIdentifier


@attr.s(auto_attribs=True, kw_only=True)
class CatalogFactIdentifier(Base):
id: str
type: str = attr.field(validator=value_in_allowed)

@staticmethod
def client_class() -> builtins.type[FactIdentifier]:
return FactIdentifier


@attr.s(auto_attribs=True, kw_only=True)
class CatalogLabelIdentifier(Base):
id: str
Expand Down
19 changes: 19 additions & 0 deletions gooddata-sdk/gooddata_sdk/catalog/workspace/content_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from gooddata_sdk.catalog.workspace.declarative_model.workspace.logical_model.ldm import CatalogDeclarativeModel
from gooddata_sdk.catalog.workspace.declarative_model.workspace.workspace import LAYOUT_WORKSPACES_DIR
from gooddata_sdk.catalog.workspace.entity_model.content_objects.dataset import (
CatalogAggregatedFact,
CatalogAttribute,
CatalogFact,
CatalogLabel,
Expand Down Expand Up @@ -191,6 +192,24 @@ def get_facts_catalog(self, workspace_id: str) -> list[CatalogFact]:
catalog_facts = [CatalogFact.from_api(fact) for fact in facts.data]
return catalog_facts

def get_aggregated_facts_catalog(self, workspace_id: str) -> list[CatalogAggregatedFact]:
"""Retrieve all aggregated facts in a given workspace.

Args:
workspace_id (str):
Workspace identification string e.g. "demo"

Returns:
list[CatalogAggregatedFact]:
List of all aggregated facts in a given workspace.
"""
get_agg_facts = functools.partial(
self._entities_api.get_all_entities_aggregated_facts, workspace_id, _check_return_type=False
)
agg_facts = load_all_entities(get_agg_facts)
catalog_agg_facts = [CatalogAggregatedFact.from_api(agg_fact) for agg_fact in agg_facts.data]
return catalog_agg_facts

def get_dependent_entities_graph(self, workspace_id: str) -> CatalogDependentEntitiesResponse:
"""There are dependencies among all catalog objects, the chain is the following:
`fact/attribute/label → dataset → metric → visualization → dashboard`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@

import attr
from gooddata_api_client.model.data_source_table_identifier import DataSourceTableIdentifier
from gooddata_api_client.model.declarative_aggregated_fact import DeclarativeAggregatedFact
from gooddata_api_client.model.declarative_attribute import DeclarativeAttribute
from gooddata_api_client.model.declarative_dataset import DeclarativeDataset
from gooddata_api_client.model.declarative_dataset_sql import DeclarativeDatasetSql
from gooddata_api_client.model.declarative_fact import DeclarativeFact
from gooddata_api_client.model.declarative_label import DeclarativeLabel
from gooddata_api_client.model.declarative_reference import DeclarativeReference
from gooddata_api_client.model.declarative_reference_source import DeclarativeReferenceSource
from gooddata_api_client.model.declarative_source_fact_reference import DeclarativeSourceFactReference
from gooddata_api_client.model.declarative_workspace_data_filter_column import DeclarativeWorkspaceDataFilterColumn

from gooddata_sdk.catalog.base import Base
from gooddata_sdk.catalog.identifier import CatalogGrainIdentifier, CatalogLabelIdentifier, CatalogReferenceIdentifier
from gooddata_sdk.catalog.identifier import (
CatalogFactIdentifier,
CatalogGrainIdentifier,
CatalogLabelIdentifier,
CatalogReferenceIdentifier,
)
from gooddata_sdk.catalog.workspace.declarative_model.workspace.logical_model.data_filter_references import (
CatalogDeclarativeWorkspaceDataFilterReferences,
)
Expand All @@ -34,6 +41,7 @@ class CatalogDeclarativeDataset(Base):
description: Optional[str] = None
attributes: Optional[list[CatalogDeclarativeAttribute]] = None
facts: Optional[list[CatalogDeclarativeFact]] = None
aggregated_facts: Optional[list[CatalogDeclarativeAggregatedFact]] = None
data_source_table_id: Optional[CatalogDataSourceTableIdentifier] = None
sql: Optional[CatalogDeclarativeDatasetSql] = None
tags: Optional[list[str]] = None
Expand Down Expand Up @@ -86,6 +94,30 @@ def client_class() -> type[DeclarativeFact]:
return DeclarativeFact


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDeclarativeSourceFactReference(Base):
operation: str
reference: CatalogFactIdentifier

@staticmethod
def client_class() -> type[DeclarativeFact]:
return DeclarativeSourceFactReference


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDeclarativeAggregatedFact(Base):
id: str
source_column: str
source_fact_reference: Optional[CatalogDeclarativeSourceFactReference] = None
source_column_data_type: Optional[str] = None
description: Optional[str] = None
tags: Optional[list[str]] = None

@staticmethod
def client_class() -> type[DeclarativeAggregatedFact]:
return DeclarativeAggregatedFact


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDataSourceTableIdentifier(Base):
id: str
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ def change_tables_columns_case(self, upper_case: Optional[bool] = None) -> Catal
for fact in dataset.facts:
if fact.source_column:
fact.source_column = self._change_case(fact.source_column, upper_case)
if dataset.aggregated_facts:
for aggregated_fact in dataset.aggregated_facts:
if aggregated_fact.source_column:
aggregated_fact.source_column = self._change_case(aggregated_fact.source_column, upper_case)
Copy link
Copy Markdown
Contributor Author

@fiedlr fiedlr Jul 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doublecheck, not sure if this should be done also for agg facts. I took it from facts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ok.

for reference in dataset.references:
if reference.source_columns is not None:
new_columns = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import attr
import attrs
from gooddata_api_client.model.json_api_aggregated_fact_out import JsonApiAggregatedFactOut
from gooddata_api_client.model.json_api_attribute_out import JsonApiAttributeOut
from gooddata_api_client.model.json_api_dataset_out import JsonApiDatasetOut
from gooddata_api_client.model.json_api_fact_out import JsonApiFactOut
Expand Down Expand Up @@ -99,6 +100,18 @@ def as_computable(self) -> Metric:
# TODO - dataset?


@attr.s(auto_attribs=True, kw_only=True)
class CatalogAggregatedFact(AttrCatalogEntity):
@staticmethod
def client_class() -> Any:
return JsonApiAggregatedFactOut

def as_computable(self) -> Metric:
return SimpleMetric(local_id=self.id, item=self.obj_id)

# TODO - dataset?


@attr.s(auto_attribs=True, kw_only=True)
class CatalogDataset(AttrCatalogEntity):
@property
Expand Down
7 changes: 6 additions & 1 deletion gooddata-sdk/gooddata_sdk/catalog/workspace/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,8 @@ def add_title_description_tags(

@staticmethod
def set_title_description(workspace_object: Any, translated: dict[str, str]) -> None:
if workspace_object.title:
# Aggregated facts do not have a title as a property
if hasattr(workspace_object, "title") and workspace_object.title:
workspace_object.title = translated[workspace_object.title]
if workspace_object.description:
workspace_object.description = translated[workspace_object.description]
Expand Down Expand Up @@ -735,6 +736,8 @@ def get_texts_to_translate(
self.add_title_description_tags(to_translate, label.title, label.description, label.tags)
for fact in dataset.facts or []:
self.add_title_description_tags(to_translate, fact.title, fact.description, fact.tags)
for agg_fact in dataset.aggregated_facts or []:
self.add_title_description_tags(to_translate, None, agg_fact.description, agg_fact.tags)
Copy link
Copy Markdown
Contributor Author

@fiedlr fiedlr Jul 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doublecheck, not sure if we should trasnlate also agg facts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ok.

for date_dataset in workspace_content.ldm.date_instances:
self.add_title_description_tags(
to_translate, date_dataset.title, date_dataset.description, date_dataset.tags
Expand Down Expand Up @@ -792,6 +795,8 @@ def set_translated_texts(
self.set_title_description_tags(label, translated)
for fact in dataset.facts or []:
self.set_title_description_tags(fact, translated)
for agg_fact in dataset.aggregated_facts or []:
self.set_title_description_tags(agg_fact, translated)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doublecheck

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ok.

for date_dataset in new_workspace_content.ldm.date_instances:
self.set_title_description_tags(date_dataset, translated)
# ADM
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# (C) 2025 GoodData Corporation
version: 1
interactions:
- request:
method: GET
uri: http://localhost:3000/api/v1/entities/workspaces/demo/aggregatedFacts?page=0&size=500
body: null
headers:
Accept:
- application/vnd.gooddata.api+json
Accept-Encoding:
- br, gzip, deflate
X-GDC-VALIDATE-RELATIONS:
- 'true'
X-Requested-With:
- XMLHttpRequest
response:
status:
code: 200
message: OK
headers:
Cache-Control:
- no-cache, no-store, max-age=0, must-revalidate
Content-Length:
- '211'
Content-Type:
- application/vnd.gooddata.api+json
DATE: &id001
- PLACEHOLDER
Expires:
- '0'
Featurepolicy:
- geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr
'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope
'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none';
Pragma:
- no-cache
Referrer-Policy:
- same-origin
Vary:
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- SAMEORIGIN
X-GDC-TRACE-ID: *id001
X-Xss-Protection:
- 1; mode=block
body:
string:
data: []
links:
self: http://localhost:3000/api/v1/entities/workspaces/demo/aggregatedFacts?page=0&size=500
next: http://localhost:3000/api/v1/entities/workspaces/demo/aggregatedFacts?page=1&size=500
Loading
Loading