apppy-db 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
apppy/db/__init__.py ADDED
File without changes
apppy/db/migrations.py ADDED
@@ -0,0 +1,12 @@
1
+ import abc
2
+
3
+
4
+ class Migrations(abc.ABC):
5
+ @abc.abstractmethod
6
+ async def head(self) -> str | None:
7
+ pass
8
+
9
+
10
+ class DefaultMigrations(Migrations):
11
+ async def head(self) -> str | None:
12
+ return None
apppy/db/postgres.py ADDED
@@ -0,0 +1,73 @@
1
+ import psycopg
2
+ from fastapi_lifespan_manager import LifespanManager
3
+ from psycopg.rows import DictRow, dict_row
4
+ from psycopg_pool.pool_async import AsyncConnectionPool as DBConnAsyncPool
5
+ from pydantic import Field
6
+
7
+ from apppy.env import EnvSettings
8
+ from apppy.logger import WithLogger
9
+
10
+
11
+ class PostgresClientSettings(EnvSettings):
12
+ db_conn: str = Field(alias="APP_POSTGRES_DB_CONN")
13
+ db_host: str = Field(alias="APP_POSTGRES_DB_HOST")
14
+ db_password: str = Field(alias="APP_POSTGRES_DB_PASSWORD", exclude=True)
15
+
16
+ db_pool_min_size: int = Field(alias="APP_POSTGRES_DB_POOL_MIN_SIZE", default=4)
17
+ db_pool_max_size: int | None = Field(alias="APP_POSTGRES_DB_POOL_MAX_SIZE", default=None)
18
+ db_pool_timeout: float = Field(alias="APP_POSTGRES_DB_POOL_TIMEOUT", default=30)
19
+
20
+
21
+ class PostgresClient(WithLogger):
22
+ def __init__(self, settings: PostgresClientSettings, lifespan: LifespanManager) -> None:
23
+ self._settings = settings
24
+
25
+ self._conninfo: str = (
26
+ f"host={settings.db_host} password={settings.db_password} {settings.db_conn}"
27
+ )
28
+ self._db_pool_async: DBConnAsyncPool | None = None
29
+ lifespan.add(self.__open_db_pool_async)
30
+
31
+ async def __open_db_pool_async(self):
32
+ self._logger.info("Opening Postgres psycopg_pool_async")
33
+ if not self._db_pool_async or self._db_pool_async.closed:
34
+ self._db_pool_async = DBConnAsyncPool(
35
+ conninfo=self._conninfo,
36
+ open=False,
37
+ min_size=self._settings.db_pool_min_size,
38
+ max_size=self._settings.db_pool_max_size,
39
+ timeout=self._settings.db_pool_timeout,
40
+ )
41
+ self._logger.info(
42
+ "Opened Postgres psycopg_pool_async",
43
+ extra={
44
+ "min_size": self._settings.db_pool_min_size,
45
+ "max_size": self._settings.db_pool_max_size,
46
+ },
47
+ )
48
+
49
+ await self._db_pool_async.open(wait=True)
50
+ yield {"db_pool_async": self._db_pool_async}
51
+
52
+ self._logger.info("Closing Postgres psycopg_pool_async")
53
+ try:
54
+ await self._db_pool_async.close()
55
+ except Exception:
56
+ self._logger.exception("Error while closing Postgres psycopg_pool_async")
57
+
58
+ @property
59
+ def db_pool_async(self) -> DBConnAsyncPool:
60
+ if self._db_pool_async is None:
61
+ raise Exception("Postgres db_pool_async is uninitialized")
62
+
63
+ return self._db_pool_async
64
+
65
+ async def db_query_async(self, query: str, params: dict | None = None) -> list[DictRow]:
66
+ async with (
67
+ self.db_pool_async.connection() as db_conn,
68
+ psycopg.AsyncClientCursor(db_conn, row_factory=dict_row) as db_cursor_async,
69
+ ):
70
+ await db_cursor_async.execute(query=query, params=params)
71
+ result_set = await db_cursor_async.fetchall()
72
+
73
+ return result_set
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.4
2
+ Name: apppy-db
3
+ Version: 0.1.0
4
+ Summary: Python database definitions for server development
5
+ Project-URL: Homepage, https://github.com/spals/apppy
6
+ Author: Tim Kral
7
+ License: MIT
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: apppy-env>=0.1.0
12
+ Requires-Dist: apppy-logger>=0.1.0
13
+ Requires-Dist: fastapi-lifespan-manager==0.1.4
14
+ Requires-Dist: psycopg-pool==3.2.2
15
+ Requires-Dist: psycopg[binary]==3.1.19
@@ -0,0 +1,6 @@
1
+ apppy/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ apppy/db/migrations.py,sha256=_1Ah4wZBzxgcXAe4lNjt3ewASwy13hJGWwvANYimCjA,216
3
+ apppy/db/postgres.py,sha256=hbFAS1-r9L8FPx94FM3bYk-NpRnJpfvKSOfkRfjzRgg,2916
4
+ apppy_db-0.1.0.dist-info/METADATA,sha256=MRJG7Qeba4-xex7WoOMTR-P-MYyC79vjHPz4n5rUGJs,507
5
+ apppy_db-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ apppy_db-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any