maleo-database 0.0.2__tar.gz → 0.0.3__tar.gz

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.
Files changed (38) hide show
  1. {maleo_database-0.0.2 → maleo_database-0.0.3}/PKG-INFO +19 -2
  2. {maleo_database-0.0.2 → maleo_database-0.0.3}/maleo_database.egg-info/PKG-INFO +19 -2
  3. {maleo_database-0.0.2 → maleo_database-0.0.3}/maleo_database.egg-info/requires.txt +18 -1
  4. {maleo_database-0.0.2 → maleo_database-0.0.3}/pyproject.toml +19 -2
  5. maleo_database-0.0.3/src/managers/session.py +256 -0
  6. maleo_database-0.0.2/src/managers/session.py +0 -103
  7. {maleo_database-0.0.2 → maleo_database-0.0.3}/LICENSE +0 -0
  8. {maleo_database-0.0.2 → maleo_database-0.0.3}/README.md +0 -0
  9. {maleo_database-0.0.2 → maleo_database-0.0.3}/maleo_database.egg-info/SOURCES.txt +0 -0
  10. {maleo_database-0.0.2 → maleo_database-0.0.3}/maleo_database.egg-info/dependency_links.txt +0 -0
  11. {maleo_database-0.0.2 → maleo_database-0.0.3}/maleo_database.egg-info/top_level.txt +0 -0
  12. {maleo_database-0.0.2 → maleo_database-0.0.3}/setup.cfg +0 -0
  13. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/__init__.py +0 -0
  14. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/config/__init__.py +0 -0
  15. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/config/additional.py +0 -0
  16. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/config/connection.py +0 -0
  17. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/config/identifier.py +0 -0
  18. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/config/pooling.py +0 -0
  19. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/enums.py +0 -0
  20. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/__init__.py +0 -0
  21. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/clients/__init__.py +0 -0
  22. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/clients/elasticsearch.py +0 -0
  23. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/clients/mongodb.py +0 -0
  24. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/clients/redis.py +0 -0
  25. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/engines/__init__.py +0 -0
  26. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/engines/mysql.py +0 -0
  27. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/engines/postgresql.py +0 -0
  28. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/engines/sqlite.py +0 -0
  29. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/managers/engines/sqlserver.py +0 -0
  30. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/__init__.py +0 -0
  31. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/base.py +0 -0
  32. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/models/__init__.py +0 -0
  33. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/models/mixins/__init__.py +0 -0
  34. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/models/mixins/identifier.py +0 -0
  35. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/models/mixins/status.py +0 -0
  36. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/models/mixins/timestamp.py +0 -0
  37. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/models/table.py +0 -0
  38. {maleo_database-0.0.2 → maleo_database-0.0.3}/src/orm/queries.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo-database
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Database package for MaleoSuite
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: Proprietary
@@ -16,6 +16,7 @@ Requires-Dist: cachetools>=5.5.2
16
16
  Requires-Dist: certifi>=2025.8.3
17
17
  Requires-Dist: cffi>=1.17.1
18
18
  Requires-Dist: cfgv>=3.4.0
19
+ Requires-Dist: charset-normalizer>=3.4.3
19
20
  Requires-Dist: click>=8.2.1
20
21
  Requires-Dist: cryptography>=45.0.6
21
22
  Requires-Dist: distlib>=0.4.0
@@ -24,23 +25,37 @@ Requires-Dist: elastic-transport>=9.1.0
24
25
  Requires-Dist: elasticsearch>=9.1.0
25
26
  Requires-Dist: fastapi>=0.116.1
26
27
  Requires-Dist: filelock>=3.19.1
28
+ Requires-Dist: google-api-core>=2.25.1
27
29
  Requires-Dist: google-auth>=2.40.3
30
+ Requires-Dist: google-cloud-appengine-logging>=1.6.2
31
+ Requires-Dist: google-cloud-audit-log>=0.3.2
32
+ Requires-Dist: google-cloud-core>=2.4.3
33
+ Requires-Dist: google-cloud-logging>=3.12.1
34
+ Requires-Dist: googleapis-common-protos>=1.70.0
28
35
  Requires-Dist: greenlet>=3.2.4
36
+ Requires-Dist: grpc-google-iam-v1>=0.14.2
37
+ Requires-Dist: grpcio>=1.74.0
38
+ Requires-Dist: grpcio-status>=1.74.0
29
39
  Requires-Dist: identify>=2.6.13
30
40
  Requires-Dist: idna>=3.10
41
+ Requires-Dist: importlib_metadata>=8.7.0
31
42
  Requires-Dist: maleo-constants>=0.0.2
32
43
  Requires-Dist: maleo-enums>=0.0.2
33
- Requires-Dist: maleo-mixins>=0.0.2
44
+ Requires-Dist: maleo-logging>=0.0.1
45
+ Requires-Dist: maleo-mixins>=0.0.5
34
46
  Requires-Dist: maleo-types-base>=0.0.2
35
47
  Requires-Dist: maleo-types-enums>=0.0.2
36
48
  Requires-Dist: maleo-utils>=0.0.3
37
49
  Requires-Dist: motor>=3.7.1
38
50
  Requires-Dist: mypy_extensions>=1.1.0
39
51
  Requires-Dist: nodeenv>=1.9.1
52
+ Requires-Dist: opentelemetry-api>=1.36.0
40
53
  Requires-Dist: packaging>=25.0
41
54
  Requires-Dist: pathspec>=0.12.1
42
55
  Requires-Dist: platformdirs>=4.4.0
43
56
  Requires-Dist: pre_commit>=4.3.0
57
+ Requires-Dist: proto-plus>=1.26.1
58
+ Requires-Dist: protobuf>=6.32.0
44
59
  Requires-Dist: pyasn1>=0.6.1
45
60
  Requires-Dist: pyasn1_modules>=0.4.2
46
61
  Requires-Dist: pycparser>=2.22
@@ -51,6 +66,7 @@ Requires-Dist: pymongo>=4.14.1
51
66
  Requires-Dist: python-dateutil>=2.9.0.post0
52
67
  Requires-Dist: PyYAML>=6.0.2
53
68
  Requires-Dist: redis>=6.4.0
69
+ Requires-Dist: requests>=2.32.5
54
70
  Requires-Dist: rsa>=4.9.1
55
71
  Requires-Dist: six>=1.17.0
56
72
  Requires-Dist: sniffio>=1.3.1
@@ -60,6 +76,7 @@ Requires-Dist: typing-inspection>=0.4.1
60
76
  Requires-Dist: typing_extensions>=4.15.0
61
77
  Requires-Dist: urllib3>=2.5.0
62
78
  Requires-Dist: virtualenv>=20.34.0
79
+ Requires-Dist: zipp>=3.23.0
63
80
  Dynamic: license-file
64
81
 
65
82
  # README #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo-database
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Database package for MaleoSuite
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: Proprietary
@@ -16,6 +16,7 @@ Requires-Dist: cachetools>=5.5.2
16
16
  Requires-Dist: certifi>=2025.8.3
17
17
  Requires-Dist: cffi>=1.17.1
18
18
  Requires-Dist: cfgv>=3.4.0
19
+ Requires-Dist: charset-normalizer>=3.4.3
19
20
  Requires-Dist: click>=8.2.1
20
21
  Requires-Dist: cryptography>=45.0.6
21
22
  Requires-Dist: distlib>=0.4.0
@@ -24,23 +25,37 @@ Requires-Dist: elastic-transport>=9.1.0
24
25
  Requires-Dist: elasticsearch>=9.1.0
25
26
  Requires-Dist: fastapi>=0.116.1
26
27
  Requires-Dist: filelock>=3.19.1
28
+ Requires-Dist: google-api-core>=2.25.1
27
29
  Requires-Dist: google-auth>=2.40.3
30
+ Requires-Dist: google-cloud-appengine-logging>=1.6.2
31
+ Requires-Dist: google-cloud-audit-log>=0.3.2
32
+ Requires-Dist: google-cloud-core>=2.4.3
33
+ Requires-Dist: google-cloud-logging>=3.12.1
34
+ Requires-Dist: googleapis-common-protos>=1.70.0
28
35
  Requires-Dist: greenlet>=3.2.4
36
+ Requires-Dist: grpc-google-iam-v1>=0.14.2
37
+ Requires-Dist: grpcio>=1.74.0
38
+ Requires-Dist: grpcio-status>=1.74.0
29
39
  Requires-Dist: identify>=2.6.13
30
40
  Requires-Dist: idna>=3.10
41
+ Requires-Dist: importlib_metadata>=8.7.0
31
42
  Requires-Dist: maleo-constants>=0.0.2
32
43
  Requires-Dist: maleo-enums>=0.0.2
33
- Requires-Dist: maleo-mixins>=0.0.2
44
+ Requires-Dist: maleo-logging>=0.0.1
45
+ Requires-Dist: maleo-mixins>=0.0.5
34
46
  Requires-Dist: maleo-types-base>=0.0.2
35
47
  Requires-Dist: maleo-types-enums>=0.0.2
36
48
  Requires-Dist: maleo-utils>=0.0.3
37
49
  Requires-Dist: motor>=3.7.1
38
50
  Requires-Dist: mypy_extensions>=1.1.0
39
51
  Requires-Dist: nodeenv>=1.9.1
52
+ Requires-Dist: opentelemetry-api>=1.36.0
40
53
  Requires-Dist: packaging>=25.0
41
54
  Requires-Dist: pathspec>=0.12.1
42
55
  Requires-Dist: platformdirs>=4.4.0
43
56
  Requires-Dist: pre_commit>=4.3.0
57
+ Requires-Dist: proto-plus>=1.26.1
58
+ Requires-Dist: protobuf>=6.32.0
44
59
  Requires-Dist: pyasn1>=0.6.1
45
60
  Requires-Dist: pyasn1_modules>=0.4.2
46
61
  Requires-Dist: pycparser>=2.22
@@ -51,6 +66,7 @@ Requires-Dist: pymongo>=4.14.1
51
66
  Requires-Dist: python-dateutil>=2.9.0.post0
52
67
  Requires-Dist: PyYAML>=6.0.2
53
68
  Requires-Dist: redis>=6.4.0
69
+ Requires-Dist: requests>=2.32.5
54
70
  Requires-Dist: rsa>=4.9.1
55
71
  Requires-Dist: six>=1.17.0
56
72
  Requires-Dist: sniffio>=1.3.1
@@ -60,6 +76,7 @@ Requires-Dist: typing-inspection>=0.4.1
60
76
  Requires-Dist: typing_extensions>=4.15.0
61
77
  Requires-Dist: urllib3>=2.5.0
62
78
  Requires-Dist: virtualenv>=20.34.0
79
+ Requires-Dist: zipp>=3.23.0
63
80
  Dynamic: license-file
64
81
 
65
82
  # README #
@@ -7,6 +7,7 @@ cachetools>=5.5.2
7
7
  certifi>=2025.8.3
8
8
  cffi>=1.17.1
9
9
  cfgv>=3.4.0
10
+ charset-normalizer>=3.4.3
10
11
  click>=8.2.1
11
12
  cryptography>=45.0.6
12
13
  distlib>=0.4.0
@@ -15,23 +16,37 @@ elastic-transport>=9.1.0
15
16
  elasticsearch>=9.1.0
16
17
  fastapi>=0.116.1
17
18
  filelock>=3.19.1
19
+ google-api-core>=2.25.1
18
20
  google-auth>=2.40.3
21
+ google-cloud-appengine-logging>=1.6.2
22
+ google-cloud-audit-log>=0.3.2
23
+ google-cloud-core>=2.4.3
24
+ google-cloud-logging>=3.12.1
25
+ googleapis-common-protos>=1.70.0
19
26
  greenlet>=3.2.4
27
+ grpc-google-iam-v1>=0.14.2
28
+ grpcio>=1.74.0
29
+ grpcio-status>=1.74.0
20
30
  identify>=2.6.13
21
31
  idna>=3.10
32
+ importlib_metadata>=8.7.0
22
33
  maleo-constants>=0.0.2
23
34
  maleo-enums>=0.0.2
24
- maleo-mixins>=0.0.2
35
+ maleo-logging>=0.0.1
36
+ maleo-mixins>=0.0.5
25
37
  maleo-types-base>=0.0.2
26
38
  maleo-types-enums>=0.0.2
27
39
  maleo-utils>=0.0.3
28
40
  motor>=3.7.1
29
41
  mypy_extensions>=1.1.0
30
42
  nodeenv>=1.9.1
43
+ opentelemetry-api>=1.36.0
31
44
  packaging>=25.0
32
45
  pathspec>=0.12.1
33
46
  platformdirs>=4.4.0
34
47
  pre_commit>=4.3.0
48
+ proto-plus>=1.26.1
49
+ protobuf>=6.32.0
35
50
  pyasn1>=0.6.1
36
51
  pyasn1_modules>=0.4.2
37
52
  pycparser>=2.22
@@ -42,6 +57,7 @@ pymongo>=4.14.1
42
57
  python-dateutil>=2.9.0.post0
43
58
  PyYAML>=6.0.2
44
59
  redis>=6.4.0
60
+ requests>=2.32.5
45
61
  rsa>=4.9.1
46
62
  six>=1.17.0
47
63
  sniffio>=1.3.1
@@ -51,3 +67,4 @@ typing-inspection>=0.4.1
51
67
  typing_extensions>=4.15.0
52
68
  urllib3>=2.5.0
53
69
  virtualenv>=20.34.0
70
+ zipp>=3.23.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maleo-database"
7
- version = "0.0.2"
7
+ version = "0.0.3"
8
8
  description = "Database package for MaleoSuite"
9
9
  authors = [
10
10
  { name = "Agra Bima Yuda", email = "agra@nexmedis.com" }
@@ -22,6 +22,7 @@ dependencies = [
22
22
  "certifi>=2025.8.3",
23
23
  "cffi>=1.17.1",
24
24
  "cfgv>=3.4.0",
25
+ "charset-normalizer>=3.4.3",
25
26
  "click>=8.2.1",
26
27
  "cryptography>=45.0.6",
27
28
  "distlib>=0.4.0",
@@ -30,23 +31,37 @@ dependencies = [
30
31
  "elasticsearch>=9.1.0",
31
32
  "fastapi>=0.116.1",
32
33
  "filelock>=3.19.1",
34
+ "google-api-core>=2.25.1",
33
35
  "google-auth>=2.40.3",
36
+ "google-cloud-appengine-logging>=1.6.2",
37
+ "google-cloud-audit-log>=0.3.2",
38
+ "google-cloud-core>=2.4.3",
39
+ "google-cloud-logging>=3.12.1",
40
+ "googleapis-common-protos>=1.70.0",
34
41
  "greenlet>=3.2.4",
42
+ "grpc-google-iam-v1>=0.14.2",
43
+ "grpcio>=1.74.0",
44
+ "grpcio-status>=1.74.0",
35
45
  "identify>=2.6.13",
36
46
  "idna>=3.10",
47
+ "importlib_metadata>=8.7.0",
37
48
  "maleo-constants>=0.0.2",
38
49
  "maleo-enums>=0.0.2",
39
- "maleo-mixins>=0.0.2",
50
+ "maleo-logging>=0.0.1",
51
+ "maleo-mixins>=0.0.5",
40
52
  "maleo-types-base>=0.0.2",
41
53
  "maleo-types-enums>=0.0.2",
42
54
  "maleo-utils>=0.0.3",
43
55
  "motor>=3.7.1",
44
56
  "mypy_extensions>=1.1.0",
45
57
  "nodeenv>=1.9.1",
58
+ "opentelemetry-api>=1.36.0",
46
59
  "packaging>=25.0",
47
60
  "pathspec>=0.12.1",
48
61
  "platformdirs>=4.4.0",
49
62
  "pre_commit>=4.3.0",
63
+ "proto-plus>=1.26.1",
64
+ "protobuf>=6.32.0",
50
65
  "pyasn1>=0.6.1",
51
66
  "pyasn1_modules>=0.4.2",
52
67
  "pycparser>=2.22",
@@ -57,6 +72,7 @@ dependencies = [
57
72
  "python-dateutil>=2.9.0.post0",
58
73
  "PyYAML>=6.0.2",
59
74
  "redis>=6.4.0",
75
+ "requests>=2.32.5",
60
76
  "rsa>=4.9.1",
61
77
  "six>=1.17.0",
62
78
  "sniffio>=1.3.1",
@@ -66,6 +82,7 @@ dependencies = [
66
82
  "typing_extensions>=4.15.0",
67
83
  "urllib3>=2.5.0",
68
84
  "virtualenv>=20.34.0",
85
+ "zipp>=3.23.0",
69
86
  ]
70
87
 
71
88
  [tool.setuptools]
@@ -0,0 +1,256 @@
1
+ from contextlib import (
2
+ AbstractAsyncContextManager,
3
+ AbstractContextManager,
4
+ asynccontextmanager,
5
+ contextmanager,
6
+ )
7
+ from datetime import datetime, timezone
8
+ from pydantic import ValidationError
9
+ from sqlalchemy.engine import Engine
10
+ from sqlalchemy.exc import SQLAlchemyError
11
+ from sqlalchemy.ext.asyncio import AsyncEngine, async_sessionmaker, AsyncSession
12
+ from sqlalchemy.orm import sessionmaker, Session
13
+ from typing import AsyncGenerator, Generator, Literal, Tuple, Union, overload
14
+ from uuid import UUID, uuid4
15
+ from maleo.mixins.timestamp import OperationTimestamp
16
+ from maleo.types.base.uuid import OptionalUUID
17
+ from maleo.logging.logger import Database
18
+ from ..enums import Connection
19
+ from ..config import (
20
+ PostgreSQLDatabaseConfig,
21
+ MySQLDatabaseConfig,
22
+ SQLiteDatabaseConfig,
23
+ SQLServerDatabaseConfig,
24
+ )
25
+
26
+
27
+ class SessionManager:
28
+ def __init__(
29
+ self,
30
+ config: Union[
31
+ PostgreSQLDatabaseConfig,
32
+ MySQLDatabaseConfig,
33
+ SQLiteDatabaseConfig,
34
+ SQLServerDatabaseConfig,
35
+ ],
36
+ engines: Tuple[AsyncEngine, Engine],
37
+ logger: Database,
38
+ ) -> None:
39
+ self._config = config
40
+ self._async_engine, self._sync_engine = engines
41
+ self._logger = logger
42
+ self._async_sessionmaker: async_sessionmaker[AsyncSession] = async_sessionmaker[
43
+ AsyncSession
44
+ ](bind=self._async_engine, expire_on_commit=True)
45
+ self._sync_sessionmaker: sessionmaker[Session] = sessionmaker[Session](
46
+ bind=self._sync_engine, expire_on_commit=True
47
+ )
48
+
49
+ async def _async_session_handler(
50
+ self, operation_id: UUID
51
+ ) -> AsyncGenerator[AsyncSession, None]:
52
+ """Async session handler with proper error handling."""
53
+ executed_at = datetime.now(tz=timezone.utc)
54
+ session = self._async_sessionmaker()
55
+ try:
56
+ yield session
57
+ await session.commit()
58
+ completed_at = datetime.now(tz=timezone.utc)
59
+ self._logger.info(
60
+ f"Operation {operation_id} - success - Committed async database transaction",
61
+ extra={
62
+ "json_fields": {
63
+ "config": self._config.model_dump(mode="json"),
64
+ "operation_id": operation_id,
65
+ "success": True,
66
+ "timestamp": OperationTimestamp(
67
+ executed_at=executed_at,
68
+ completed_at=completed_at,
69
+ duration=(completed_at - executed_at).total_seconds(),
70
+ ).model_dump(mode="json"),
71
+ },
72
+ },
73
+ )
74
+ except (SQLAlchemyError, ValidationError, Exception):
75
+ await session.rollback()
76
+ completed_at = datetime.now(tz=timezone.utc)
77
+ self._logger.error(
78
+ f"Operation {operation_id} - failed - Error handling async database session",
79
+ exc_info=True,
80
+ extra={
81
+ "json_fields": {
82
+ "config": self._config.model_dump(mode="json"),
83
+ "operation_id": operation_id,
84
+ "success": False,
85
+ "timestamp": OperationTimestamp(
86
+ executed_at=executed_at,
87
+ completed_at=completed_at,
88
+ duration=(completed_at - executed_at).total_seconds(),
89
+ ).model_dump(mode="json"),
90
+ },
91
+ },
92
+ )
93
+ raise
94
+ finally:
95
+ await session.close()
96
+ completed_at = datetime.now(tz=timezone.utc)
97
+ self._logger.info(
98
+ f"Operation {operation_id} - success - Closed async database session",
99
+ extra={
100
+ "json_fields": {
101
+ "config": self._config.model_dump(mode="json"),
102
+ "operation_id": operation_id,
103
+ "success": True,
104
+ "timestamp": OperationTimestamp(
105
+ executed_at=executed_at,
106
+ completed_at=completed_at,
107
+ duration=(completed_at - executed_at).total_seconds(),
108
+ ).model_dump(mode="json"),
109
+ },
110
+ },
111
+ )
112
+
113
+ def _sync_session_handler(
114
+ self, operation_id: UUID
115
+ ) -> Generator[Session, None, None]:
116
+ """Sync session handler with proper error handling."""
117
+ executed_at = datetime.now(tz=timezone.utc)
118
+ session = self._sync_sessionmaker()
119
+ try:
120
+ yield session
121
+ session.commit()
122
+ completed_at = datetime.now(tz=timezone.utc)
123
+ self._logger.info(
124
+ f"Operation {operation_id} - success - Committed sync database transaction",
125
+ extra={
126
+ "json_fields": {
127
+ "config": self._config.model_dump(mode="json"),
128
+ "operation_id": operation_id,
129
+ "success": True,
130
+ "timestamp": OperationTimestamp(
131
+ executed_at=executed_at,
132
+ completed_at=completed_at,
133
+ duration=(completed_at - executed_at).total_seconds(),
134
+ ).model_dump(mode="json"),
135
+ },
136
+ },
137
+ )
138
+ except (SQLAlchemyError, ValidationError, Exception):
139
+ session.rollback()
140
+ completed_at = datetime.now(tz=timezone.utc)
141
+ self._logger.error(
142
+ f"Operation {operation_id} - failed - Error handling sync database session",
143
+ exc_info=True,
144
+ extra={
145
+ "json_fields": {
146
+ "config": self._config.model_dump(mode="json"),
147
+ "operation_id": operation_id,
148
+ "success": False,
149
+ "timestamp": OperationTimestamp(
150
+ executed_at=executed_at,
151
+ completed_at=completed_at,
152
+ duration=(completed_at - executed_at).total_seconds(),
153
+ ).model_dump(mode="json"),
154
+ },
155
+ },
156
+ )
157
+ raise
158
+ finally:
159
+ session.close()
160
+ completed_at = datetime.now(tz=timezone.utc)
161
+ self._logger.info(
162
+ f"Operation {operation_id} - success - Closed sync database session",
163
+ extra={
164
+ "json_fields": {
165
+ "config": self._config.model_dump(mode="json"),
166
+ "operation_id": operation_id,
167
+ "success": True,
168
+ "timestamp": OperationTimestamp(
169
+ executed_at=executed_at,
170
+ completed_at=completed_at,
171
+ duration=(completed_at - executed_at).total_seconds(),
172
+ ).model_dump(mode="json"),
173
+ },
174
+ },
175
+ )
176
+
177
+ @asynccontextmanager
178
+ async def _async_context_manager(
179
+ self, operation_id: UUID
180
+ ) -> AsyncGenerator[AsyncSession, None]:
181
+ """Async context manager implementation."""
182
+ async for session in self._async_session_handler(operation_id):
183
+ yield session
184
+
185
+ @contextmanager
186
+ def _sync_context_manager(
187
+ self, operation_id: UUID
188
+ ) -> Generator[Session, None, None]:
189
+ """Sync context manager implementation."""
190
+ yield from self._sync_session_handler(operation_id)
191
+
192
+ # Overloaded context manager methods
193
+ @overload
194
+ def get(
195
+ self, connection: Literal[Connection.ASYNC], operation_id: OptionalUUID = None
196
+ ) -> AbstractAsyncContextManager[AsyncSession]: ...
197
+
198
+ @overload
199
+ def get(
200
+ self, connection: Literal[Connection.SYNC], operation_id: OptionalUUID = None
201
+ ) -> AbstractContextManager[Session]: ...
202
+
203
+ def get(
204
+ self,
205
+ connection: Connection = Connection.ASYNC,
206
+ operation_id: OptionalUUID = None,
207
+ ) -> Union[
208
+ AbstractAsyncContextManager[AsyncSession], AbstractContextManager[Session]
209
+ ]:
210
+ """Context manager for manual session handling."""
211
+ if operation_id is None:
212
+ operation_id = uuid4()
213
+ if connection is Connection.ASYNC:
214
+ return self._async_context_manager(operation_id)
215
+ else:
216
+ return self._sync_context_manager(operation_id)
217
+
218
+ # Alternative: More explicit methods
219
+ @asynccontextmanager
220
+ async def get_async(
221
+ self, operation_id: OptionalUUID = None
222
+ ) -> AsyncGenerator[AsyncSession, None]:
223
+ """Explicit async context manager."""
224
+ if operation_id is None:
225
+ operation_id = uuid4()
226
+ async for session in self._async_session_handler(operation_id):
227
+ yield session
228
+
229
+ @contextmanager
230
+ def get_sync(
231
+ self, operation_id: OptionalUUID = None
232
+ ) -> Generator[Session, None, None]:
233
+ """Explicit sync context manager."""
234
+ if operation_id is None:
235
+ operation_id = uuid4()
236
+ yield from self._sync_session_handler(operation_id)
237
+
238
+ def as_async_dependency(self, operation_id: OptionalUUID = None):
239
+ """Explicit async dependency injection."""
240
+ if operation_id is None:
241
+ operation_id = uuid4()
242
+
243
+ def dependency() -> AsyncGenerator[AsyncSession, None]:
244
+ return self._async_session_handler(operation_id)
245
+
246
+ return dependency
247
+
248
+ def as_sync_dependency(self, operation_id: OptionalUUID = None):
249
+ """Explicit sync dependency injection."""
250
+ if operation_id is None:
251
+ operation_id = uuid4()
252
+
253
+ def dependency() -> AsyncGenerator[AsyncSession, None]:
254
+ return self._async_session_handler(operation_id)
255
+
256
+ return dependency
@@ -1,103 +0,0 @@
1
- from contextlib import (
2
- AbstractAsyncContextManager,
3
- AbstractContextManager,
4
- asynccontextmanager,
5
- contextmanager,
6
- )
7
- from pydantic import ValidationError
8
- from sqlalchemy.engine import Engine
9
- from sqlalchemy.exc import SQLAlchemyError
10
- from sqlalchemy.ext.asyncio import AsyncEngine, async_sessionmaker, AsyncSession
11
- from sqlalchemy.orm import sessionmaker, Session
12
- from typing import AsyncGenerator, Generator, Literal, Tuple, Union, overload
13
- from ..enums import Connection
14
-
15
-
16
- class SessionManager:
17
- def __init__(self, engines: Tuple[AsyncEngine, Engine]) -> None:
18
- self._async_engine, self._sync_engine = engines
19
- self._async_sessionmaker: async_sessionmaker[AsyncSession] = async_sessionmaker[
20
- AsyncSession
21
- ](bind=self._async_engine, expire_on_commit=True)
22
- self._sync_sessionmaker: sessionmaker[Session] = sessionmaker[Session](
23
- bind=self._sync_engine, expire_on_commit=True
24
- )
25
-
26
- async def _async_session_handler(self) -> AsyncGenerator[AsyncSession, None]:
27
- """Async session handler with proper error handling."""
28
- session = self._async_sessionmaker()
29
- try:
30
- yield session
31
- await session.commit()
32
- except (SQLAlchemyError, ValidationError, Exception):
33
- await session.rollback()
34
- raise
35
- finally:
36
- await session.close()
37
-
38
- def _sync_session_handler(self) -> Generator[Session, None, None]:
39
- """Sync session handler with proper error handling."""
40
- session = self._sync_sessionmaker()
41
- try:
42
- yield session
43
- session.commit()
44
- except (SQLAlchemyError, ValidationError, Exception):
45
- session.rollback()
46
- raise
47
- finally:
48
- session.close()
49
-
50
- # Overloaded context manager methods
51
- @overload
52
- def get(
53
- self, connection: Literal[Connection.ASYNC]
54
- ) -> AbstractAsyncContextManager[AsyncSession]: ...
55
-
56
- @overload
57
- def get(
58
- self, connection: Literal[Connection.SYNC]
59
- ) -> AbstractContextManager[Session]: ...
60
-
61
- def get(
62
- self, connection: Connection = Connection.ASYNC
63
- ) -> Union[
64
- AbstractAsyncContextManager[AsyncSession], AbstractContextManager[Session]
65
- ]:
66
- """Context manager for manual session handling."""
67
- if connection is Connection.ASYNC:
68
- return self._async_context_manager()
69
- else:
70
- return self._sync_context_manager()
71
-
72
- @asynccontextmanager
73
- async def _async_context_manager(self) -> AsyncGenerator[AsyncSession, None]:
74
- """Async context manager implementation."""
75
- async for session in self._async_session_handler():
76
- yield session
77
-
78
- @contextmanager
79
- def _sync_context_manager(self) -> Generator[Session, None, None]:
80
- """Sync context manager implementation."""
81
- yield from self._sync_session_handler()
82
-
83
- # Alternative: More explicit methods
84
- @asynccontextmanager
85
- async def get_async(self) -> AsyncGenerator[AsyncSession, None]:
86
- """Explicit async context manager."""
87
- async for session in self._async_session_handler():
88
- yield session
89
-
90
- @contextmanager
91
- def get_sync(self) -> Generator[Session, None, None]:
92
- """Explicit sync context manager."""
93
- yield from self._sync_session_handler()
94
- # with self._sync_session_handler() as session:
95
- # yield session
96
-
97
- def inject_async(self) -> AsyncGenerator[AsyncSession, None]:
98
- """Explicit async dependency injection."""
99
- return self._async_session_handler()
100
-
101
- def inject_sync(self) -> Generator[Session, None, None]:
102
- """Explicit sync dependency injection."""
103
- return self._sync_session_handler()
File without changes
File without changes
File without changes