mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-29 12:13:01 +00:00
feat(sdk/search): add owner filter (#14649)
Co-authored-by: Mayuri N <mayuri.nehate@datahub.com>
This commit is contained in:
parent
0b75674ab3
commit
8d13b03e85
@ -0,0 +1,6 @@
|
|||||||
|
from datahub.sdk import DataHubClient
|
||||||
|
from datahub.sdk.search_filters import FilterDsl as F
|
||||||
|
|
||||||
|
# search for all assets having user urn:li:corpuser:jdoe as owner
|
||||||
|
client = DataHubClient(server="<your_server>", token="<your_token>")
|
||||||
|
results = client.search.get_urns(filter=F.owner("urn:li:corpuser:jdoe"))
|
||||||
@ -30,7 +30,14 @@ from datahub.ingestion.graph.filters import (
|
|||||||
_get_status_filter,
|
_get_status_filter,
|
||||||
)
|
)
|
||||||
from datahub.metadata.schema_classes import EntityTypeName
|
from datahub.metadata.schema_classes import EntityTypeName
|
||||||
from datahub.metadata.urns import ContainerUrn, DataPlatformUrn, DomainUrn
|
from datahub.metadata.urns import (
|
||||||
|
ContainerUrn,
|
||||||
|
CorpGroupUrn,
|
||||||
|
CorpUserUrn,
|
||||||
|
DataPlatformUrn,
|
||||||
|
DomainUrn,
|
||||||
|
)
|
||||||
|
from datahub.utilities.urns.urn import guess_entity_type
|
||||||
|
|
||||||
_AndSearchFilterRule = TypedDict(
|
_AndSearchFilterRule = TypedDict(
|
||||||
"_AndSearchFilterRule", {"and": List[SearchFilterRule]}
|
"_AndSearchFilterRule", {"and": List[SearchFilterRule]}
|
||||||
@ -235,6 +242,36 @@ class _EnvFilter(_BaseFilter):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class _OwnerFilter(_BaseFilter):
|
||||||
|
"""Filter for entities owned by specific users or groups."""
|
||||||
|
|
||||||
|
owner: List[str] = pydantic.Field(
|
||||||
|
description="The owner to filter on. Should be user or group URNs.",
|
||||||
|
)
|
||||||
|
|
||||||
|
@pydantic.validator("owner", each_item=True)
|
||||||
|
def validate_owner(cls, v: str) -> str:
|
||||||
|
if not v.startswith("urn:li:"):
|
||||||
|
raise ValueError(f"Owner must be a valid User or Group URN, got: {v}")
|
||||||
|
_type = guess_entity_type(v)
|
||||||
|
if _type == CorpUserUrn.ENTITY_TYPE:
|
||||||
|
return str(CorpUserUrn.from_string(v))
|
||||||
|
elif _type == CorpGroupUrn.ENTITY_TYPE:
|
||||||
|
return str(CorpGroupUrn.from_string(v))
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Owner must be a valid User or Group URN, got: {v}")
|
||||||
|
|
||||||
|
def _build_rule(self) -> SearchFilterRule:
|
||||||
|
return SearchFilterRule(
|
||||||
|
field="owners",
|
||||||
|
condition="EQUAL",
|
||||||
|
values=self.owner,
|
||||||
|
)
|
||||||
|
|
||||||
|
def compile(self) -> _OrFilters:
|
||||||
|
return [{"and": [self._build_rule()]}]
|
||||||
|
|
||||||
|
|
||||||
class _CustomCondition(_BaseFilter):
|
class _CustomCondition(_BaseFilter):
|
||||||
"""Represents a single field condition."""
|
"""Represents a single field condition."""
|
||||||
|
|
||||||
@ -407,6 +444,7 @@ if TYPE_CHECKING or not PYDANTIC_SUPPORTS_CALLABLE_DISCRIMINATOR:
|
|||||||
_DomainFilter,
|
_DomainFilter,
|
||||||
_ContainerFilter,
|
_ContainerFilter,
|
||||||
_EnvFilter,
|
_EnvFilter,
|
||||||
|
_OwnerFilter,
|
||||||
_CustomCondition,
|
_CustomCondition,
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -448,6 +486,7 @@ else:
|
|||||||
_ContainerFilter, Tag(_ContainerFilter._field_discriminator())
|
_ContainerFilter, Tag(_ContainerFilter._field_discriminator())
|
||||||
],
|
],
|
||||||
Annotated[_EnvFilter, Tag(_EnvFilter._field_discriminator())],
|
Annotated[_EnvFilter, Tag(_EnvFilter._field_discriminator())],
|
||||||
|
Annotated[_OwnerFilter, Tag(_OwnerFilter._field_discriminator())],
|
||||||
Annotated[
|
Annotated[
|
||||||
_CustomCondition, Tag(_CustomCondition._field_discriminator())
|
_CustomCondition, Tag(_CustomCondition._field_discriminator())
|
||||||
],
|
],
|
||||||
@ -551,6 +590,10 @@ class FilterDsl:
|
|||||||
def env(env: Union[str, Sequence[str]], /) -> _EnvFilter:
|
def env(env: Union[str, Sequence[str]], /) -> _EnvFilter:
|
||||||
return _EnvFilter(env=[env] if isinstance(env, str) else env)
|
return _EnvFilter(env=[env] if isinstance(env, str) else env)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def owner(owner: Union[str, Sequence[str]], /) -> _OwnerFilter:
|
||||||
|
return _OwnerFilter(owner=[owner] if isinstance(owner, str) else owner)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def has_custom_property(key: str, value: str) -> _CustomCondition:
|
def has_custom_property(key: str, value: str) -> _CustomCondition:
|
||||||
return _CustomCondition(
|
return _CustomCondition(
|
||||||
|
|||||||
@ -382,6 +382,41 @@ def test_filter_before_validators() -> None:
|
|||||||
load_filters(filter_str)
|
load_filters(filter_str)
|
||||||
|
|
||||||
|
|
||||||
|
def test_owner_filter() -> None:
|
||||||
|
"""Test basic owner filter functionality."""
|
||||||
|
filter_obj: Filter = load_filters({"owner": ["urn:li:corpuser:john"]})
|
||||||
|
assert filter_obj == F.owner("urn:li:corpuser:john")
|
||||||
|
assert filter_obj.compile() == [
|
||||||
|
{
|
||||||
|
"and": [
|
||||||
|
SearchFilterRule(
|
||||||
|
field="owners",
|
||||||
|
condition="EQUAL",
|
||||||
|
values=["urn:li:corpuser:john"],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_owner_filter_mixed_types() -> None:
|
||||||
|
"""Test owner filter with both user and group URNs."""
|
||||||
|
filter_obj: Filter = load_filters(
|
||||||
|
{"owner": ["urn:li:corpuser:john", "urn:li:corpGroup:engineering"]}
|
||||||
|
)
|
||||||
|
assert filter_obj == F.owner(
|
||||||
|
["urn:li:corpuser:john", "urn:li:corpGroup:engineering"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_owner_filter() -> None:
|
||||||
|
"""Test validation error for invalid owner URN."""
|
||||||
|
with pytest.raises(
|
||||||
|
ValidationError, match="Owner must be a valid User or Group URN"
|
||||||
|
):
|
||||||
|
F.owner("invalid-owner")
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_filter() -> None:
|
def test_invalid_filter() -> None:
|
||||||
with pytest.raises(InvalidUrnError):
|
with pytest.raises(InvalidUrnError):
|
||||||
F.domain("marketing")
|
F.domain("marketing")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user