src.offers.postgresql_offers_repository_adapter

PostgreSQL adapter for the offers repository.

 1"""PostgreSQL adapter for the offers repository."""
 2
 3from typing import cast, override
 4
 5import psycopg2
 6from psycopg2.extensions import connection as _connection
 7
 8from src.offers.models import Offer
 9from src.offers.offers_repository_port import OffersRepositoryPort
10
11class PostgreSQLOffersRepositoryAdapter(OffersRepositoryPort):
12    """Adapter that stores offers in a PostgreSQL database."""
13
14    _conn: _connection
15    _connection_string: str
16
17    def __init__(self, connection_string: str) -> None:
18        """Initialise with a PostgreSQL connection string.
19
20        Args:
21            connection_string: PostgreSQL connection string.
22        """
23        self._connection_string = connection_string
24        self._conn = psycopg2.connect(connection_string)
25        self._init_db()
26
27    def close_db(self) -> None:
28        """Close the database connection."""
29        self._conn.close()
30
31    def _init_db(self) -> None:
32        """Initialize the database table for offers."""
33        with self._conn.cursor() as cursor:
34            cursor.execute(
35                """
36                CREATE TABLE IF NOT EXISTS offers (
37                    offer_id TEXT PRIMARY KEY,
38                    award_id TEXT NOT NULL
39                )
40                """
41                # TODO add indexes for offer_id and award_id
42            )
43            self._conn.commit()
44
45    @override
46    def store(self, offer: Offer) -> None:
47        """Persist an offer in PostgreSQL.
48
49        Args:
50            offer: The offer to store.
51        """
52        with self._conn.cursor() as cursor:
53            cursor.execute(
54                """
55                INSERT INTO offers (offer_id, award_id)
56                VALUES (%s, %s)
57                ON CONFLICT (offer_id) DO UPDATE
58                SET award_id = EXCLUDED.award_id
59                """,
60                (
61                    offer.offer_id,
62                    offer.award_id,
63                ),
64            )
65            self._conn.commit()
66
67    @override
68    def get(self, offer_id: str) -> Offer:
69        """Retrieve an offer by its identifier.
70
71        Args:
72            offer_id: The unique offer identifier.
73
74        Returns:
75            The matching Offer.
76
77        Raises:
78            KeyError: When no offer with the given id exists.
79        """
80        with self._conn.cursor() as cursor:
81            cursor.execute(
82                """
83                SELECT offer_id, award_id
84                FROM offers
85                WHERE offer_id = %s
86                """,
87                (offer_id,),
88            )
89            row = cursor.fetchone()
90        self._conn.commit()
91
92        if row is None:
93            raise KeyError(f"Offer with id {offer_id} not found")
94        return Offer(
95            offer_id=cast(str, row[0]),
96            award_id=cast(str, row[1]),
97            uri=None
98        )
class PostgreSQLOffersRepositoryAdapter(src.offers.offers_repository_port.OffersRepositoryPort):
12class PostgreSQLOffersRepositoryAdapter(OffersRepositoryPort):
13    """Adapter that stores offers in a PostgreSQL database."""
14
15    _conn: _connection
16    _connection_string: str
17
18    def __init__(self, connection_string: str) -> None:
19        """Initialise with a PostgreSQL connection string.
20
21        Args:
22            connection_string: PostgreSQL connection string.
23        """
24        self._connection_string = connection_string
25        self._conn = psycopg2.connect(connection_string)
26        self._init_db()
27
28    def close_db(self) -> None:
29        """Close the database connection."""
30        self._conn.close()
31
32    def _init_db(self) -> None:
33        """Initialize the database table for offers."""
34        with self._conn.cursor() as cursor:
35            cursor.execute(
36                """
37                CREATE TABLE IF NOT EXISTS offers (
38                    offer_id TEXT PRIMARY KEY,
39                    award_id TEXT NOT NULL
40                )
41                """
42                # TODO add indexes for offer_id and award_id
43            )
44            self._conn.commit()
45
46    @override
47    def store(self, offer: Offer) -> None:
48        """Persist an offer in PostgreSQL.
49
50        Args:
51            offer: The offer to store.
52        """
53        with self._conn.cursor() as cursor:
54            cursor.execute(
55                """
56                INSERT INTO offers (offer_id, award_id)
57                VALUES (%s, %s)
58                ON CONFLICT (offer_id) DO UPDATE
59                SET award_id = EXCLUDED.award_id
60                """,
61                (
62                    offer.offer_id,
63                    offer.award_id,
64                ),
65            )
66            self._conn.commit()
67
68    @override
69    def get(self, offer_id: str) -> Offer:
70        """Retrieve an offer by its identifier.
71
72        Args:
73            offer_id: The unique offer identifier.
74
75        Returns:
76            The matching Offer.
77
78        Raises:
79            KeyError: When no offer with the given id exists.
80        """
81        with self._conn.cursor() as cursor:
82            cursor.execute(
83                """
84                SELECT offer_id, award_id
85                FROM offers
86                WHERE offer_id = %s
87                """,
88                (offer_id,),
89            )
90            row = cursor.fetchone()
91        self._conn.commit()
92
93        if row is None:
94            raise KeyError(f"Offer with id {offer_id} not found")
95        return Offer(
96            offer_id=cast(str, row[0]),
97            award_id=cast(str, row[1]),
98            uri=None
99        )

Adapter that stores offers in a PostgreSQL database.

PostgreSQLOffersRepositoryAdapter(connection_string: str)
18    def __init__(self, connection_string: str) -> None:
19        """Initialise with a PostgreSQL connection string.
20
21        Args:
22            connection_string: PostgreSQL connection string.
23        """
24        self._connection_string = connection_string
25        self._conn = psycopg2.connect(connection_string)
26        self._init_db()

Initialise with a PostgreSQL connection string.

Args: connection_string: PostgreSQL connection string.

def close_db(self) -> None:
28    def close_db(self) -> None:
29        """Close the database connection."""
30        self._conn.close()

Close the database connection.

@override
def store(self, offer: src.offers.models.Offer) -> None:
46    @override
47    def store(self, offer: Offer) -> None:
48        """Persist an offer in PostgreSQL.
49
50        Args:
51            offer: The offer to store.
52        """
53        with self._conn.cursor() as cursor:
54            cursor.execute(
55                """
56                INSERT INTO offers (offer_id, award_id)
57                VALUES (%s, %s)
58                ON CONFLICT (offer_id) DO UPDATE
59                SET award_id = EXCLUDED.award_id
60                """,
61                (
62                    offer.offer_id,
63                    offer.award_id,
64                ),
65            )
66            self._conn.commit()

Persist an offer in PostgreSQL.

Args: offer: The offer to store.

@override
def get(self, offer_id: str) -> src.offers.models.Offer:
68    @override
69    def get(self, offer_id: str) -> Offer:
70        """Retrieve an offer by its identifier.
71
72        Args:
73            offer_id: The unique offer identifier.
74
75        Returns:
76            The matching Offer.
77
78        Raises:
79            KeyError: When no offer with the given id exists.
80        """
81        with self._conn.cursor() as cursor:
82            cursor.execute(
83                """
84                SELECT offer_id, award_id
85                FROM offers
86                WHERE offer_id = %s
87                """,
88                (offer_id,),
89            )
90            row = cursor.fetchone()
91        self._conn.commit()
92
93        if row is None:
94            raise KeyError(f"Offer with id {offer_id} not found")
95        return Offer(
96            offer_id=cast(str, row[0]),
97            award_id=cast(str, row[1]),
98            uri=None
99        )

Retrieve an offer by its identifier.

Args: offer_id: The unique offer identifier.

Returns: The matching Offer.

Raises: KeyError: When no offer with the given id exists.