Source code for dbt_ibis._references
from abc import ABC, abstractproperty
from dataclasses import dataclass
from functools import wraps
from typing import Callable, Final, Union
import ibis
import ibis.expr.datatypes as dt
import ibis.expr.types as ir
_REF_IDENTIFIER_PREFIX: Final = "__ibd_ref__"
_REF_IDENTIFIER_SUFFIX: Final = "__rid__"
_SOURCE_IDENTIFIER_PREFIX: Final = "__ibd_source__"
_SOURCE_IDENTIFIER_SUFFIX: Final = "__sid__"
_SOURCE_IDENTIFIER_SEPARATOR: Final = "__ibd_sep__"
class _Reference(ABC):
@abstractproperty
def _ibis_table_name(self) -> str:
pass
def to_ibis(self, schema: Union[ibis.Schema, dict[str, dt.DataType]]) -> ir.Table:
if schema is None:
raise NotImplementedError
return ibis.table(
schema,
name=self._ibis_table_name,
)
[docs]
@dataclass
class ref(_Reference):
"""A reference to a dbt model."""
name: str
@property
def _ibis_table_name(self) -> str:
return _REF_IDENTIFIER_PREFIX + self.name + _REF_IDENTIFIER_SUFFIX
[docs]
@dataclass
class source(_Reference):
"""A reference to a dbt source."""
source_name: str
table_name: str
@property
def _ibis_table_name(self) -> str:
return (
_SOURCE_IDENTIFIER_PREFIX
+ self.source_name
+ _SOURCE_IDENTIFIER_SEPARATOR
+ self.table_name
+ _SOURCE_IDENTIFIER_SUFFIX
)
# Type hints could be improved here. Could use a typing.Protocol with a typed __call__
# method to indicate that the function that is wrapped by depends_on needs to be
# callable, accept a variadic number of _Reference arguments and needs to
# return an ibis Table
[docs]
def depends_on(*references: _Reference) -> Callable:
"""Decorator to specify the dependencies of an Ibis model. You can pass
either dbt_ibis.ref or dbt_ibis.source objects as arguments.
"""
if not all(isinstance(r, _Reference) for r in references):
raise ValueError(
"All arguments to depends_on need to be either an instance of"
+ " dbt_ibis.ref or dbt_ibis.source"
)
def decorator(
func: Callable[..., ir.Table],
) -> Callable[..., ir.Table]:
@wraps(func)
def wrapper(*args: _Reference, **kwargs: _Reference) -> ir.Table:
return func(*args, **kwargs)
wrapper.depends_on = references # type: ignore[attr-defined]
return wrapper
return decorator