rb-commons 0.1.0__tar.gz → 0.1.2__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.
- {rb_commons-0.1.0 → rb_commons-0.1.2}/PKG-INFO +9 -23
- rb_commons-0.1.2/rb_commons/__init__.py +0 -0
- rb_commons-0.1.2/rb_commons/configs/__init__.py +0 -0
- rb_commons-0.1.2/rb_commons/configs/config.py +47 -0
- rb_commons-0.1.2/rb_commons/orm/__init__.py +0 -0
- rb_commons-0.1.2/rb_commons/orm/exceptions.py +11 -0
- rb_commons-0.1.2/rb_commons/orm/managers.py +178 -0
- {rb_commons-0.1.0 → rb_commons-0.1.2}/rb_commons.egg-info/PKG-INFO +9 -23
- rb_commons-0.1.2/rb_commons.egg-info/SOURCES.txt +12 -0
- rb_commons-0.1.2/rb_commons.egg-info/requires.txt +6 -0
- rb_commons-0.1.2/rb_commons.egg-info/top_level.txt +1 -0
- rb_commons-0.1.2/setup.py +30 -0
- rb_commons-0.1.0/rb_commons.egg-info/SOURCES.txt +0 -6
- rb_commons-0.1.0/rb_commons.egg-info/requires.txt +0 -21
- rb_commons-0.1.0/rb_commons.egg-info/top_level.txt +0 -1
- rb_commons-0.1.0/setup.py +0 -46
- {rb_commons-0.1.0 → rb_commons-0.1.2}/rb_commons.egg-info/dependency_links.txt +0 -0
- {rb_commons-0.1.0 → rb_commons-0.1.2}/setup.cfg +0 -0
@@ -1,35 +1,21 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: rb-commons
|
3
|
-
Version: 0.1.
|
4
|
-
Summary:
|
3
|
+
Version: 0.1.2
|
4
|
+
Summary: Commons of project and simplified orm based on sqlalchemy.
|
5
5
|
Home-page: https://github.com/Abdulvoris101/rb-commons
|
6
6
|
Author: Abdulvoris
|
7
7
|
Author-email: erkinovabdulvoris101@gmail.com
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
9
10
|
Classifier: Operating System :: OS Independent
|
10
11
|
Requires-Python: >=3.11
|
11
12
|
Description-Content-Type: text/markdown
|
12
|
-
Requires-Dist: annotated-types
|
13
|
-
Requires-Dist:
|
14
|
-
Requires-Dist:
|
15
|
-
Requires-Dist:
|
16
|
-
Requires-Dist:
|
17
|
-
Requires-Dist:
|
18
|
-
Requires-Dist: h11~=0.14.0
|
19
|
-
Requires-Dist: httptools~=0.6.4
|
20
|
-
Requires-Dist: idna~=3.10
|
21
|
-
Requires-Dist: pydantic~=2.10.4
|
22
|
-
Requires-Dist: pydantic-settings~=2.7.1
|
23
|
-
Requires-Dist: pydantic_core~=2.27.2
|
24
|
-
Requires-Dist: python-dotenv~=1.0.1
|
25
|
-
Requires-Dist: PyYAML~=6.0.2
|
26
|
-
Requires-Dist: sniffio~=1.3.1
|
27
|
-
Requires-Dist: SQLAlchemy~=2.0.36
|
28
|
-
Requires-Dist: starlette~=0.41.3
|
29
|
-
Requires-Dist: typing_extensions~=4.12.2
|
30
|
-
Requires-Dist: uvicorn~=0.34.0
|
31
|
-
Requires-Dist: watchfiles~=1.0.3
|
32
|
-
Requires-Dist: websockets~=14.1
|
13
|
+
Requires-Dist: annotated-types==0.7.0
|
14
|
+
Requires-Dist: greenlet==3.1.1
|
15
|
+
Requires-Dist: pydantic==2.10.4
|
16
|
+
Requires-Dist: PyJWT==2.10.1
|
17
|
+
Requires-Dist: python-dotenv==1.0.1
|
18
|
+
Requires-Dist: SQLAlchemy==2.0.36
|
33
19
|
|
34
20
|
# RB-Commons
|
35
21
|
|
File without changes
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from pydantic_settings import BaseSettings
|
4
|
+
|
5
|
+
class CommonConfigs(BaseSettings):
|
6
|
+
service_name: str = None
|
7
|
+
service_port: int = None
|
8
|
+
service_id: str = None
|
9
|
+
service_hostname: str = '127.0.0.1'
|
10
|
+
service_host: str = None
|
11
|
+
|
12
|
+
consul_host: str = '127.0.0.1'
|
13
|
+
consul_port: int = 8888
|
14
|
+
|
15
|
+
# db
|
16
|
+
POSTGRES_HOST: str = None
|
17
|
+
POSTGRES_USER: str = None
|
18
|
+
POSTGRES_PORT: int = None
|
19
|
+
POSTGRES_PASSWORD: str = None
|
20
|
+
POSTGRES_DB: str = None
|
21
|
+
DB_ALEMBIC_URL: str = None
|
22
|
+
|
23
|
+
@property
|
24
|
+
def database_url(self) -> Optional[str]:
|
25
|
+
"""Construct the database URL if all required fields are present."""
|
26
|
+
required_fields = [
|
27
|
+
self.POSTGRES_USER,
|
28
|
+
self.POSTGRES_PASSWORD,
|
29
|
+
self.POSTGRES_HOST,
|
30
|
+
self.POSTGRES_PORT,
|
31
|
+
self.POSTGRES_DB
|
32
|
+
]
|
33
|
+
if all(required_fields):
|
34
|
+
return (
|
35
|
+
f"postgresql+asyncpg://{self.POSTGRES_USER}:"
|
36
|
+
f"{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:"
|
37
|
+
f"{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
|
38
|
+
)
|
39
|
+
return None
|
40
|
+
|
41
|
+
class Config:
|
42
|
+
env_file = ".env"
|
43
|
+
env_file_encoding = "utf-8"
|
44
|
+
extra = "ignore"
|
45
|
+
|
46
|
+
|
47
|
+
configs = CommonConfigs()
|
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class DatabaseException(Exception):
|
2
|
+
def __init__(self, text: str, user_id: int | None = None , original_exception=None):
|
3
|
+
self.user_id = user_id
|
4
|
+
self.text = text
|
5
|
+
self.original_exception = original_exception
|
6
|
+
|
7
|
+
class InternalException(Exception):
|
8
|
+
def __init__(self, text: str, user_id: int | None = None, telegram_id: int | None = None, original_exception=None):
|
9
|
+
self.user_id = user_id
|
10
|
+
self.text = text
|
11
|
+
self.original_exception = original_exception
|
@@ -0,0 +1,178 @@
|
|
1
|
+
from typing import TypeVar, Type, Generic, Optional, List, Dict
|
2
|
+
from sqlalchemy import select, delete, update
|
3
|
+
from sqlalchemy.exc import IntegrityError, SQLAlchemyError, NoResultFound
|
4
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
5
|
+
from sqlalchemy.orm import declarative_base
|
6
|
+
from rb_commons.orm.exceptions import DatabaseException, InternalException
|
7
|
+
|
8
|
+
ModelType = TypeVar('ModelType', bound=declarative_base())
|
9
|
+
|
10
|
+
class BaseManager(Generic[ModelType]):
|
11
|
+
model: Type[ModelType]
|
12
|
+
|
13
|
+
def __init__(self, session: AsyncSession) -> None:
|
14
|
+
self.session = session
|
15
|
+
|
16
|
+
async def get(self, **kwargs) -> Optional[ModelType]:
|
17
|
+
"""
|
18
|
+
get object based on conditions
|
19
|
+
"""
|
20
|
+
query = select(self.model).filter_by(**kwargs)
|
21
|
+
result = await self.session.execute(query)
|
22
|
+
return result.scalar_one_or_none()
|
23
|
+
|
24
|
+
async def filter(self, **kwargs) -> List[ModelType]:
|
25
|
+
"""
|
26
|
+
Filter objects based on conditions
|
27
|
+
"""
|
28
|
+
query = select(self.model).filter_by(**kwargs)
|
29
|
+
result = await self.session.execute(query)
|
30
|
+
return list(result.scalars().all())
|
31
|
+
|
32
|
+
async def create(self, **kwargs) -> ModelType:
|
33
|
+
"""
|
34
|
+
Create a new object
|
35
|
+
"""
|
36
|
+
obj = self.model(**kwargs)
|
37
|
+
|
38
|
+
try:
|
39
|
+
self.session.add(obj)
|
40
|
+
await self.session.flush()
|
41
|
+
await self.session.commit()
|
42
|
+
await self.session.refresh(obj)
|
43
|
+
return obj
|
44
|
+
except IntegrityError as e:
|
45
|
+
await self.session.rollback()
|
46
|
+
raise DatabaseException(f"Constraint violation: {str(e)}") from e
|
47
|
+
except SQLAlchemyError as e:
|
48
|
+
await self.session.rollback()
|
49
|
+
raise DatabaseException(f"Database error occurred: {str(e)}") from e
|
50
|
+
except Exception as e:
|
51
|
+
await self.session.rollback()
|
52
|
+
raise InternalException(f"Unexpected error during creation: {str(e)}") from e
|
53
|
+
|
54
|
+
|
55
|
+
async def delete(self, id: Optional[int] = None, **filters) -> bool | None:
|
56
|
+
"""
|
57
|
+
Delete object(s) with flexible filtering options
|
58
|
+
|
59
|
+
:param id: Specific ID to delete
|
60
|
+
:param filters: Additional filter conditions
|
61
|
+
:return: Number of deleted records or None
|
62
|
+
"""
|
63
|
+
try:
|
64
|
+
if id is not None:
|
65
|
+
filters['id'] = id
|
66
|
+
|
67
|
+
delete_stmt = delete(self.model).filter_by(**filters)
|
68
|
+
result = await self.session.execute(delete_stmt)
|
69
|
+
await self.session.commit()
|
70
|
+
return result.rowcount() > 0
|
71
|
+
except NoResultFound:
|
72
|
+
return False
|
73
|
+
except SQLAlchemyError as e:
|
74
|
+
await self.session.rollback()
|
75
|
+
raise DatabaseException(f"Delete operation failed: {str(e)}") from e
|
76
|
+
|
77
|
+
async def bulk_delete(self, **filters) -> int:
|
78
|
+
"""
|
79
|
+
Bulk delete with flexible filtering
|
80
|
+
|
81
|
+
:param filters: Conditions for bulk deletion
|
82
|
+
:return: Number of deleted records
|
83
|
+
"""
|
84
|
+
try:
|
85
|
+
delete_stmt = delete(self.model).filter_by(**filters)
|
86
|
+
result = await self.session.execute(delete_stmt)
|
87
|
+
await self.session.commit()
|
88
|
+
return result.rowcount()
|
89
|
+
except SQLAlchemyError as e:
|
90
|
+
await self.session.rollback()
|
91
|
+
raise DatabaseException(f"Bulk delete failed: {str(e)}") from e
|
92
|
+
|
93
|
+
async def update_by_filters(self, filters: Dict, **update_fields) -> Optional[ModelType]:
|
94
|
+
"""
|
95
|
+
Update object(s) with flexible filtering options
|
96
|
+
|
97
|
+
:param filters: Conditions for selecting records to update
|
98
|
+
:param update_fields: Fields and values to update
|
99
|
+
:return: Number of updated records
|
100
|
+
"""
|
101
|
+
if not update_fields:
|
102
|
+
raise InternalException("No fields provided for update")
|
103
|
+
|
104
|
+
try:
|
105
|
+
update_stmt = update(self.model).filter_by(**filters).values(**update_fields)
|
106
|
+
await self.session.execute(update_stmt)
|
107
|
+
await self.session.commit()
|
108
|
+
updated_instance = await self.get(**filters)
|
109
|
+
return updated_instance
|
110
|
+
except IntegrityError as e:
|
111
|
+
await self.session.rollback()
|
112
|
+
raise InternalException(f"Constraint violation: {str(e)}") from e
|
113
|
+
except SQLAlchemyError as e:
|
114
|
+
await self.session.rollback()
|
115
|
+
raise DatabaseException(f"Update operation failed: {str(e)}") from e
|
116
|
+
|
117
|
+
async def update(self, instance: ModelType, **update_fields) -> Optional[ModelType]:
|
118
|
+
"""
|
119
|
+
Update an existing database instance with new fields
|
120
|
+
|
121
|
+
:param instance: The database model instance to update
|
122
|
+
:param update_fields: Keyword arguments of fields to update
|
123
|
+
:return: The updated instance
|
124
|
+
|
125
|
+
:raises ValueError: If no update fields are provided
|
126
|
+
:raises RuntimeError: For database-related errors
|
127
|
+
"""
|
128
|
+
# Validate update fields
|
129
|
+
if not update_fields:
|
130
|
+
raise InternalException("No fields provided for update")
|
131
|
+
|
132
|
+
try:
|
133
|
+
# Apply updates directly to the instance
|
134
|
+
for key, value in update_fields.items():
|
135
|
+
setattr(instance, key, value)
|
136
|
+
|
137
|
+
self.session.add(instance)
|
138
|
+
await self.session.commit()
|
139
|
+
await self.session.refresh(instance)
|
140
|
+
|
141
|
+
return instance
|
142
|
+
|
143
|
+
except IntegrityError as e:
|
144
|
+
await self.session.rollback()
|
145
|
+
raise InternalException(f"Constraint violation: {str(e)}") from e
|
146
|
+
|
147
|
+
except SQLAlchemyError as e:
|
148
|
+
await self.session.rollback()
|
149
|
+
raise DatabaseException(f"Update operation failed: {str(e)}") from e
|
150
|
+
|
151
|
+
async def save(self, instance: ModelType) -> Optional[ModelType]:
|
152
|
+
"""
|
153
|
+
Save instance
|
154
|
+
|
155
|
+
:param instance: The database model instance to save
|
156
|
+
:return: The saved instance
|
157
|
+
|
158
|
+
:raises ValueError: If no update fields are provided
|
159
|
+
:raises RuntimeError: For database-related errors
|
160
|
+
"""
|
161
|
+
try:
|
162
|
+
self.session.add(instance)
|
163
|
+
await self.session.commit()
|
164
|
+
await self.session.refresh(instance)
|
165
|
+
return instance
|
166
|
+
|
167
|
+
except IntegrityError as e:
|
168
|
+
await self.session.rollback()
|
169
|
+
raise InternalException(f"Constraint violation: {str(e)}") from e
|
170
|
+
|
171
|
+
except SQLAlchemyError as e:
|
172
|
+
await self.session.rollback()
|
173
|
+
raise DatabaseException(f"Update operation failed: {str(e)}") from e
|
174
|
+
|
175
|
+
|
176
|
+
async def is_exists(self, **kwargs) -> bool:
|
177
|
+
return await self.get(**kwargs) is not None
|
178
|
+
|
@@ -1,35 +1,21 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: rb-commons
|
3
|
-
Version: 0.1.
|
4
|
-
Summary:
|
3
|
+
Version: 0.1.2
|
4
|
+
Summary: Commons of project and simplified orm based on sqlalchemy.
|
5
5
|
Home-page: https://github.com/Abdulvoris101/rb-commons
|
6
6
|
Author: Abdulvoris
|
7
7
|
Author-email: erkinovabdulvoris101@gmail.com
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
9
10
|
Classifier: Operating System :: OS Independent
|
10
11
|
Requires-Python: >=3.11
|
11
12
|
Description-Content-Type: text/markdown
|
12
|
-
Requires-Dist: annotated-types
|
13
|
-
Requires-Dist:
|
14
|
-
Requires-Dist:
|
15
|
-
Requires-Dist:
|
16
|
-
Requires-Dist:
|
17
|
-
Requires-Dist:
|
18
|
-
Requires-Dist: h11~=0.14.0
|
19
|
-
Requires-Dist: httptools~=0.6.4
|
20
|
-
Requires-Dist: idna~=3.10
|
21
|
-
Requires-Dist: pydantic~=2.10.4
|
22
|
-
Requires-Dist: pydantic-settings~=2.7.1
|
23
|
-
Requires-Dist: pydantic_core~=2.27.2
|
24
|
-
Requires-Dist: python-dotenv~=1.0.1
|
25
|
-
Requires-Dist: PyYAML~=6.0.2
|
26
|
-
Requires-Dist: sniffio~=1.3.1
|
27
|
-
Requires-Dist: SQLAlchemy~=2.0.36
|
28
|
-
Requires-Dist: starlette~=0.41.3
|
29
|
-
Requires-Dist: typing_extensions~=4.12.2
|
30
|
-
Requires-Dist: uvicorn~=0.34.0
|
31
|
-
Requires-Dist: watchfiles~=1.0.3
|
32
|
-
Requires-Dist: websockets~=14.1
|
13
|
+
Requires-Dist: annotated-types==0.7.0
|
14
|
+
Requires-Dist: greenlet==3.1.1
|
15
|
+
Requires-Dist: pydantic==2.10.4
|
16
|
+
Requires-Dist: PyJWT==2.10.1
|
17
|
+
Requires-Dist: python-dotenv==1.0.1
|
18
|
+
Requires-Dist: SQLAlchemy==2.0.36
|
33
19
|
|
34
20
|
# RB-Commons
|
35
21
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
setup.py
|
2
|
+
rb_commons/__init__.py
|
3
|
+
rb_commons.egg-info/PKG-INFO
|
4
|
+
rb_commons.egg-info/SOURCES.txt
|
5
|
+
rb_commons.egg-info/dependency_links.txt
|
6
|
+
rb_commons.egg-info/requires.txt
|
7
|
+
rb_commons.egg-info/top_level.txt
|
8
|
+
rb_commons/configs/__init__.py
|
9
|
+
rb_commons/configs/config.py
|
10
|
+
rb_commons/orm/__init__.py
|
11
|
+
rb_commons/orm/exceptions.py
|
12
|
+
rb_commons/orm/managers.py
|
@@ -0,0 +1 @@
|
|
1
|
+
rb_commons
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from setuptools import setup, find_packages
|
2
|
+
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
4
|
+
long_description = fh.read()
|
5
|
+
|
6
|
+
setup(
|
7
|
+
name="rb-commons",
|
8
|
+
version="0.1.2",
|
9
|
+
author="Abdulvoris",
|
10
|
+
author_email="erkinovabdulvoris101@gmail.com",
|
11
|
+
description="Commons of project and simplified orm based on sqlalchemy.",
|
12
|
+
long_description=long_description,
|
13
|
+
long_description_content_type="text/markdown",
|
14
|
+
url="https://github.com/Abdulvoris101/rb-commons", # Replace with your repo URL
|
15
|
+
packages=find_packages(),
|
16
|
+
classifiers=[
|
17
|
+
"Programming Language :: Python :: 3",
|
18
|
+
"License :: OSI Approved :: MIT License",
|
19
|
+
"Operating System :: OS Independent",
|
20
|
+
],
|
21
|
+
python_requires='>=3.11',
|
22
|
+
install_requires=[
|
23
|
+
"annotated-types==0.7.0",
|
24
|
+
"greenlet==3.1.1",
|
25
|
+
"pydantic==2.10.4",
|
26
|
+
"PyJWT==2.10.1",
|
27
|
+
"python-dotenv==1.0.1",
|
28
|
+
"SQLAlchemy==2.0.36",
|
29
|
+
],
|
30
|
+
)
|
@@ -1,21 +0,0 @@
|
|
1
|
-
annotated-types~=0.7.0
|
2
|
-
anyio~=4.7.0
|
3
|
-
click~=8.1.8
|
4
|
-
colorama~=0.4.6
|
5
|
-
fastapi~=0.115.6
|
6
|
-
greenlet~=3.1.1
|
7
|
-
h11~=0.14.0
|
8
|
-
httptools~=0.6.4
|
9
|
-
idna~=3.10
|
10
|
-
pydantic~=2.10.4
|
11
|
-
pydantic-settings~=2.7.1
|
12
|
-
pydantic_core~=2.27.2
|
13
|
-
python-dotenv~=1.0.1
|
14
|
-
PyYAML~=6.0.2
|
15
|
-
sniffio~=1.3.1
|
16
|
-
SQLAlchemy~=2.0.36
|
17
|
-
starlette~=0.41.3
|
18
|
-
typing_extensions~=4.12.2
|
19
|
-
uvicorn~=0.34.0
|
20
|
-
watchfiles~=1.0.3
|
21
|
-
websockets~=14.1
|
@@ -1 +0,0 @@
|
|
1
|
-
|
rb_commons-0.1.0/setup.py
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# setup.py
|
2
|
-
from setuptools import setup, find_packages
|
3
|
-
|
4
|
-
with open("README.md", "r", encoding="utf-8") as fh:
|
5
|
-
long_description = fh.read()
|
6
|
-
|
7
|
-
|
8
|
-
setup(
|
9
|
-
name="rb-commons",
|
10
|
-
version="0.1.0",
|
11
|
-
author="Abdulvoris",
|
12
|
-
author_email="erkinovabdulvoris101@gmail.com",
|
13
|
-
description="Orm commons for sqlalchemy based projects",
|
14
|
-
long_description=long_description,
|
15
|
-
long_description_content_type="text/markdown",
|
16
|
-
url="https://github.com/Abdulvoris101/rb-commons",
|
17
|
-
packages=find_packages(include=['your_package', 'your_package.*']),
|
18
|
-
install_requires=[
|
19
|
-
"annotated-types~=0.7.0",
|
20
|
-
"anyio~=4.7.0",
|
21
|
-
"click~=8.1.8",
|
22
|
-
"colorama~=0.4.6",
|
23
|
-
"fastapi~=0.115.6",
|
24
|
-
"greenlet~=3.1.1",
|
25
|
-
"h11~=0.14.0",
|
26
|
-
"httptools~=0.6.4",
|
27
|
-
"idna~=3.10",
|
28
|
-
"pydantic~=2.10.4",
|
29
|
-
"pydantic-settings~=2.7.1",
|
30
|
-
"pydantic_core~=2.27.2",
|
31
|
-
"python-dotenv~=1.0.1",
|
32
|
-
"PyYAML~=6.0.2",
|
33
|
-
"sniffio~=1.3.1",
|
34
|
-
"SQLAlchemy~=2.0.36",
|
35
|
-
"starlette~=0.41.3",
|
36
|
-
"typing_extensions~=4.12.2",
|
37
|
-
"uvicorn~=0.34.0",
|
38
|
-
"watchfiles~=1.0.3",
|
39
|
-
"websockets~=14.1",
|
40
|
-
],
|
41
|
-
classifiers=[
|
42
|
-
"Programming Language :: Python :: 3",
|
43
|
-
"Operating System :: OS Independent",
|
44
|
-
],
|
45
|
-
python_requires='>=3.11',
|
46
|
-
)
|
File without changes
|
File without changes
|