Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 11 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
import logging

from gooddata_sdk._version import __version__
from gooddata_sdk.catalog.ai_lake.model import (
CatalogDatabaseInstance,
CatalogFailedOperation,
CatalogOperation,
CatalogOperationError,
CatalogPendingOperation,
CatalogProvisionDatabaseInstanceRequest,
CatalogSucceededOperation,
OperationKind,
)
from gooddata_sdk.catalog.ai_lake.service import AiLakeService
from gooddata_sdk.catalog.data_source.action_model.requests.ldm_request import (
CatalogGenerateLdmRequest,
CatalogPdmLdmRequest,
Expand Down
11 changes: 11 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/catalog/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
# (C) 2022 GoodData Corporation
from gooddata_sdk.catalog.ai_lake.model import (
CatalogDatabaseInstance,
CatalogFailedOperation,
CatalogOperation,
CatalogOperationError,
CatalogPendingOperation,
CatalogProvisionDatabaseInstanceRequest,
CatalogSucceededOperation,
OperationKind,
)
from gooddata_sdk.catalog.ai_lake.service import AiLakeService
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# (C) 2025 GoodData Corporation
from gooddata_sdk.catalog.ai_lake.model import (
CatalogDatabaseInstance,
CatalogFailedOperation,
CatalogOperation,
CatalogOperationError,
CatalogPendingOperation,
CatalogProvisionDatabaseInstanceRequest,
CatalogSucceededOperation,
OperationKind,
)
from gooddata_sdk.catalog.ai_lake.service import AiLakeService

__all__ = [
"AiLakeService",
"CatalogDatabaseInstance",
"CatalogFailedOperation",
"CatalogOperation",
"CatalogOperationError",
"CatalogPendingOperation",
"CatalogProvisionDatabaseInstanceRequest",
"CatalogSucceededOperation",
"OperationKind",
]
105 changes: 105 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/catalog/ai_lake/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# (C) 2025 GoodData Corporation
from __future__ import annotations

from typing import Any, Dict, List, Literal, Optional, Set

from attr import define
from gooddata_api_client.model.provision_database_instance_request import ProvisionDatabaseInstanceRequest

# TypeAlias for OperationKind values matching the API's allowed_values
OperationKind = Literal["provision-database", "deprovision-database"]


@define(kw_only=True)
class CatalogOperationError:
title: str
status: int
detail: str

@classmethod
def from_api(cls, api_obj: Any) -> "CatalogOperationError":
return cls(
title=api_obj.title,
status=api_obj.status,
detail=api_obj.detail,
)


@define(kw_only=True)
class CatalogOperation:
id: str
kind: str
status: str


@define(kw_only=True)
class CatalogPendingOperation(CatalogOperation):
status: str = "pending"

@classmethod
def from_api(cls, api_obj: Any) -> "CatalogPendingOperation":
return cls(
id=api_obj.id,
kind=api_obj.kind,
status="pending",
)


@define(kw_only=True)
class CatalogSucceededOperation(CatalogOperation):
status: str = "succeeded"
result: Optional[Dict[str, Any]] = None

@classmethod
def from_api(cls, api_obj: Any) -> "CatalogSucceededOperation":
result = None
if hasattr(api_obj, "result"):
result = api_obj.result
return cls(
id=api_obj.id,
kind=api_obj.kind,
status="succeeded",
result=result,
)


@define(kw_only=True)
class CatalogFailedOperation(CatalogOperation):
status: str = "failed"
error: CatalogOperationError = None # type: ignore[assignment]

@classmethod
def from_api(cls, api_obj: Any) -> "CatalogFailedOperation":
return cls(
id=api_obj.id,
kind=api_obj.kind,
status="failed",
error=CatalogOperationError.from_api(api_obj.error),
)


@define(kw_only=True)
class CatalogProvisionDatabaseInstanceRequest:
name: str
storage_ids: Set[str]

def as_api_model(self) -> ProvisionDatabaseInstanceRequest:
return ProvisionDatabaseInstanceRequest(
name=self.name,
storage_ids=list(self.storage_ids),
)


@define(kw_only=True)
class CatalogDatabaseInstance:
id: str
name: str
storage_ids: List[str]

@classmethod
def from_api(cls, api_obj: Any) -> "CatalogDatabaseInstance":
return cls(
id=api_obj.id,
name=api_obj.name,
storage_ids=list(api_obj.storage_ids),
)
113 changes: 113 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/catalog/ai_lake/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# (C) 2025 GoodData Corporation
from __future__ import annotations

from typing import Optional, Union

from gooddata_api_client.api.ai_lake_api import AILakeApi
from gooddata_api_client.model.failed_operation import FailedOperation as ApiFailedOperation
from gooddata_api_client.model.pending_operation import PendingOperation as ApiPendingOperation
from gooddata_api_client.model.succeeded_operation import SucceededOperation as ApiSucceededOperation

from gooddata_sdk.catalog.ai_lake.model import (
CatalogDatabaseInstance,
CatalogFailedOperation,
CatalogOperation,
CatalogPendingOperation,
CatalogProvisionDatabaseInstanceRequest,
CatalogSucceededOperation,
)
from gooddata_sdk.client import GoodDataApiClient


def _convert_operation(
api_op: Union[ApiPendingOperation, ApiSucceededOperation, ApiFailedOperation],
) -> CatalogOperation:
if isinstance(api_op, ApiSucceededOperation):
return CatalogSucceededOperation.from_api(api_op)
elif isinstance(api_op, ApiFailedOperation):
return CatalogFailedOperation.from_api(api_op)
elif isinstance(api_op, ApiPendingOperation):
return CatalogPendingOperation.from_api(api_op)
else:
raise ValueError(f"Unknown operation type: {type(api_op)}")


class AiLakeService:
def __init__(self, api_client: GoodDataApiClient) -> None:
self._client = api_client
self._api = AILakeApi(api_client._api_client)

def provision_database_instance(
self,
request: CatalogProvisionDatabaseInstanceRequest,
operation_id: Optional[str] = None,
) -> None:
"""(BETA) Provision a new AI Lake database instance.

Args:
request (CatalogProvisionDatabaseInstanceRequest):
Request containing name and storage IDs for the new database instance.
operation_id (Optional[str]):
Optional idempotency key for the operation.

Returns:
None
"""
kwargs: dict = {"provision_database_instance_request": request.as_api_model()}
if operation_id is not None:
kwargs["operation_id"] = operation_id
self._api.provision_ai_lake_database_instance(**kwargs)

def deprovision_database_instance(
self,
instance_id: str,
operation_id: Optional[str] = None,
) -> None:
"""(BETA) Delete an existing AI Lake database instance.

Args:
instance_id (str):
ID of the database instance to delete.
operation_id (Optional[str]):
Optional idempotency key for the operation.

Returns:
None
"""
kwargs: dict = {}
if operation_id is not None:
kwargs["operation_id"] = operation_id
self._api.deprovision_ai_lake_database_instance(instance_id, **kwargs)

def get_database_instance(
self,
instance_id: str,
) -> CatalogDatabaseInstance:
"""(BETA) Get details of an AI Lake database instance.

Args:
instance_id (str):
ID of the database instance to retrieve.

Returns:
CatalogDatabaseInstance: Details of the database instance.
"""
result = self._api.get_ai_lake_database_instance(instance_id)
return CatalogDatabaseInstance.from_api(result)

def get_operation(
self,
operation_id: str,
) -> CatalogOperation:
"""(BETA) Get the status of a long-running AI Lake operation.

Args:
operation_id (str):
ID of the operation to retrieve.

Returns:
CatalogOperation: The operation status, one of CatalogPendingOperation,
CatalogSucceededOperation, or CatalogFailedOperation.
"""
result = self._api.get_ai_lake_operation(operation_id)
return _convert_operation(result)
6 changes: 6 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pathlib import Path
from typing import Optional

from gooddata_sdk.catalog.ai_lake.service import AiLakeService
from gooddata_sdk.catalog.data_source.service import CatalogDataSourceService
from gooddata_sdk.catalog.export.service import ExportService
from gooddata_sdk.catalog.organization.service import CatalogOrganizationService
Expand Down Expand Up @@ -77,6 +78,7 @@ def __init__(self, client: GoodDataApiClient) -> None:
"""
self._client = client

self._ai_lake = AiLakeService(self._client)
self._catalog_workspace = CatalogWorkspaceService(self._client)
self._catalog_workspace_content = CatalogWorkspaceContentService(self._client)
self._catalog_data_source = CatalogDataSourceService(self._client)
Expand All @@ -89,6 +91,10 @@ def __init__(self, client: GoodDataApiClient) -> None:
self._catalog_permission = CatalogPermissionService(self._client)
self._export = ExportService(self._client)

@property
def ai_lake(self) -> AiLakeService:
return self._ai_lake

@property
def catalog_workspace(self) -> CatalogWorkspaceService:
return self._catalog_workspace
Expand Down
Loading
Loading