Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from collections.abc import Callable
from datetime import datetime
from typing import Any
from typing import Any, TypeVar, overload

from adcp.reporting.service import (
ReliableReportingService,
Expand All @@ -15,6 +15,34 @@

__all__ = ["postgres_reliable_reporting_service"]

_ServiceT = TypeVar("_ServiceT", bound=ReliableReportingService)


@overload
def postgres_reliable_reporting_service(
*,
pool: Any,
account_context: ReportingContextResolver,
caller_resolver: ReportingCallerResolver | None = ...,
clock: Callable[[], datetime] | None = ...,
production: ReportingProductionOptions | None = ...,
service_class: None = ...,
**kwargs: Any,
) -> ReliableReportingService: ...


@overload
def postgres_reliable_reporting_service(
*,
pool: Any,
account_context: ReportingContextResolver,
caller_resolver: ReportingCallerResolver | None = ...,
clock: Callable[[], datetime] | None = ...,
production: ReportingProductionOptions | None = ...,
service_class: type[_ServiceT],
**kwargs: Any,
) -> _ServiceT: ...


def postgres_reliable_reporting_service(
*,
Expand All @@ -23,6 +51,7 @@ def postgres_reliable_reporting_service(
caller_resolver: ReportingCallerResolver | None = None,
clock: Callable[[], datetime] | None = None,
production: ReportingProductionOptions | None = None,
service_class: type[ReliableReportingService] | None = None,
**kwargs: Any,
) -> ReliableReportingService:
"""Create durable ledger, staging and seal stores over a borrowed pool.
Expand All @@ -32,6 +61,10 @@ def postgres_reliable_reporting_service(
Startup installs all SDK-owned schemas. Explicit source-store overrides
remain the adopter's responsibility. No pool is opened or closed here.

``service_class`` builds an adopter's ``ReliableReportingService``
subclass, as ``SubClass.memory(...)`` does, so a host can override the
installed tool methods without copying this composition.

This is what ``ReliableReportingService.postgres(...)`` was before the
storage implementations moved to this distribution.
"""
Expand All @@ -45,7 +78,8 @@ def postgres_reliable_reporting_service(
else PgReportingLedgerStore(pool=pool, clock=clock)
)
staging = PgReportingStagingStore(pool=pool)
return ReliableReportingService(
cls = ReliableReportingService if service_class is None else service_class
return cls(
store=store,
account_context=account_context,
caller_resolver=caller_resolver,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_reporting_storage_service_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""``postgres_reliable_reporting_service`` builds an adopter's service subclass (#1588)."""

from __future__ import annotations

import pytest

pytest.importorskip("psycopg_pool")

from adcp_reporting_storage import postgres_reliable_reporting_service # noqa: E402
from psycopg_pool import AsyncConnectionPool # noqa: E402

from adcp.reporting import ReliableReportingService # noqa: E402
from tests.test_reliable_reporting_service import _account_context # noqa: E402


class HostReportingService(ReliableReportingService):
"""A host subclass overriding an installed tool method."""


def _pool() -> AsyncConnectionPool:
return AsyncConnectionPool("postgresql://unused", open=False)


def test_default_builds_the_base_service() -> None:
service = postgres_reliable_reporting_service(pool=_pool(), account_context=_account_context)
assert type(service) is ReliableReportingService


def test_service_class_builds_the_subclass_like_memory() -> None:
pg = postgres_reliable_reporting_service(
pool=_pool(), account_context=_account_context, service_class=HostReportingService
)
memory = HostReportingService.memory(account_context=_account_context)
assert type(pg) is HostReportingService
assert type(memory) is HostReportingService
21 changes: 21 additions & 0 deletions tests/type_checks/reporting_storage_service_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Adopter-facing type contract: the Postgres factory returns the requested subclass."""

from typing import Any

from adcp_reporting_storage import postgres_reliable_reporting_service

from adcp.reporting import ReliableReportingService


class HostReportingService(ReliableReportingService):
pass


def build(pool: Any, account_context: Any) -> HostReportingService:
return postgres_reliable_reporting_service(
pool=pool, account_context=account_context, service_class=HostReportingService
)


def build_default(pool: Any, account_context: Any) -> ReliableReportingService:
return postgres_reliable_reporting_service(pool=pool, account_context=account_context)
Loading