database-postgresql-local 0.1.0__tar.gz → 0.1.2b4627__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.
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/PKG-INFO +3 -4
- database_postgresql_local-0.1.2b4627/README.md +10 -0
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/connector.py +13 -10
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/cursor.py +12 -8
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/generic_crud_postgresql.py +86 -168
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/table_columns.py +1 -1
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/table_definition.py +1 -1
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/utils.py +15 -15
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local.egg-info/PKG-INFO +3 -4
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local.egg-info/requires.txt +2 -3
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/pyproject.toml +1 -1
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/setup.py +5 -4
- database_postgresql_local-0.1.0/README.md +0 -1
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/__init__.py +0 -0
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local/src/constants_src.py +0 -0
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local.egg-info/SOURCES.txt +0 -0
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local.egg-info/dependency_links.txt +0 -0
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/database_postgresql_local.egg-info/top_level.txt +0 -0
- {database_postgresql_local-0.1.0 → database_postgresql_local-0.1.2b4627}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: database-postgresql-local
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2b4627
|
|
4
4
|
Summary: PyPI Package for Circles database-postgresql-local Python
|
|
5
5
|
Home-page: https://github.com/circles-zone/database-postgresql-local-python-package
|
|
6
6
|
Author: Circles
|
|
@@ -8,10 +8,9 @@ Author-email: info@circlez.ai
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
|
-
Requires-Dist: logger-local
|
|
12
|
-
Requires-Dist: database-sql-local
|
|
13
11
|
Requires-Dist: python-sdk-remote
|
|
14
|
-
Requires-Dist:
|
|
12
|
+
Requires-Dist: logger-local
|
|
13
|
+
Requires-Dist: psycopg2-binary
|
|
15
14
|
Dynamic: author
|
|
16
15
|
Dynamic: author-email
|
|
17
16
|
Dynamic: classifier
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Database PostgreSQL Local Python Package
|
|
2
|
+
|
|
3
|
+
TODO Please update the README of the package.<br>
|
|
4
|
+
|
|
5
|
+
## TODOs
|
|
6
|
+
|
|
7
|
+
TODO dynamic permission to certain columns to certain users.<br>
|
|
8
|
+
|
|
9
|
+
TODO Enforce the GenericCrud interface on GenericCrudPostgres<br>
|
|
10
|
+
TODO Enforce the GenericCrudMl interface on GenericCrudMlPostgres<br>
|
|
@@ -2,21 +2,24 @@ from __future__ import annotations # Required for type hinting in class methods
|
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
4
|
from os.path import expanduser
|
|
5
|
-
from typing import Optional
|
|
5
|
+
from typing import Any, Optional
|
|
6
6
|
|
|
7
7
|
import psycopg2
|
|
8
8
|
from psycopg2 import pool
|
|
9
|
+
from logger_local import Logger
|
|
9
10
|
from logger_local.MetaLogger import MetaLogger
|
|
10
11
|
|
|
11
12
|
from .constants_src import LOGGER_CONNECTOR_CODE_OBJECT
|
|
12
|
-
from .
|
|
13
|
+
from . import cursor as cursor_module
|
|
13
14
|
from .utils import (get_sql_hostname, get_sql_password, get_sql_username, get_sql_port)
|
|
14
15
|
|
|
15
|
-
connections_pool = defaultdict(dict)
|
|
16
|
+
connections_pool: defaultdict[str, dict] = defaultdict(dict)
|
|
16
17
|
home = expanduser('~')
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
class Connector(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
20
|
+
class Connector(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT): # type: ignore[call-arg] # MetaLogger takes `object`
|
|
21
|
+
logger: Logger # Set by MetaLogger
|
|
22
|
+
|
|
20
23
|
@staticmethod
|
|
21
24
|
def connect(schema_name: str, *, user: str = get_sql_username(), ignore_cache: bool = False) -> Connector:
|
|
22
25
|
if ignore_cache and schema_name in connections_pool[user]:
|
|
@@ -59,8 +62,8 @@ class Connector(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
|
59
62
|
if not (self.host.endswith("circ.zone") or self.host.endswith("circlez.ai")):
|
|
60
63
|
self.logger.warning(
|
|
61
64
|
f"Your POSTGRESQL_HOSTNAME={self.host} which is not what is expected")
|
|
62
|
-
self.connection = None
|
|
63
|
-
self._cursor = None
|
|
65
|
+
self.connection: Any = None
|
|
66
|
+
self._cursor: Any = None
|
|
64
67
|
self._connect_to_db()
|
|
65
68
|
connections_pool[user][schema_name] = self
|
|
66
69
|
|
|
@@ -108,12 +111,12 @@ class Connector(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
|
108
111
|
except:
|
|
109
112
|
pass
|
|
110
113
|
|
|
111
|
-
def cursor(self, *, close_previous: bool = True, cache_previous: bool = False, dictionary: bool = None,
|
|
112
|
-
buffered: bool = None, raw: bool = None,
|
|
113
|
-
prepared: bool = None, named_tuple: bool = None, cursor_class=None) -> Cursor:
|
|
114
|
+
def cursor(self, *, close_previous: bool = True, cache_previous: bool = False, dictionary: Optional[bool] = None,
|
|
115
|
+
buffered: Optional[bool] = None, raw: Optional[bool] = None,
|
|
116
|
+
prepared: Optional[bool] = None, named_tuple: Optional[bool] = None, cursor_class=None) -> cursor_module.Cursor:
|
|
114
117
|
# PostgreSQL doesn't support all the same cursor options as MySQL
|
|
115
118
|
# We'll create a basic cursor and wrap it in our Cursor class
|
|
116
|
-
cursor_instance = Cursor(self.connection.cursor())
|
|
119
|
+
cursor_instance = cursor_module.Cursor(self.connection.cursor())
|
|
117
120
|
return cursor_instance
|
|
118
121
|
|
|
119
122
|
def commit(self) -> None:
|
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any, Optional
|
|
2
2
|
|
|
3
|
+
from logger_local import Logger
|
|
3
4
|
from logger_local.MetaLogger import MetaLogger
|
|
4
5
|
from psycopg2.extensions import cursor as PostgreSQLCursor
|
|
5
6
|
import psycopg2
|
|
6
7
|
from .constants_src import LOGGER_CONNECTOR_CODE_OBJECT
|
|
7
8
|
|
|
8
9
|
# PostgreSQL version
|
|
9
|
-
POSTGRESQL_VERSION = psycopg2.__version__
|
|
10
|
+
POSTGRESQL_VERSION = psycopg2.__version__ # type: ignore[attr-defined] # Not in the psycopg2 type stubs
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def version_tuple(version):
|
|
13
14
|
return tuple(map(int, version.split("."))) # Converts "2.9.5" → (2, 9, 5)
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
class Cursor(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
17
|
+
class Cursor(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT): # type: ignore[call-arg] # MetaLogger takes `object`
|
|
18
|
+
logger: Logger # Set by MetaLogger
|
|
19
|
+
|
|
17
20
|
def __init__(self, cursor: PostgreSQLCursor) -> None:
|
|
18
21
|
self.cursor = cursor
|
|
19
22
|
self.__is_closed = False
|
|
20
23
|
|
|
21
|
-
def execute(self, sql_statement: str, sql_parameters: tuple | list = None, multi: bool = False) -> None:
|
|
24
|
+
def execute(self, sql_statement: str, sql_parameters: Optional[tuple | list] = None, multi: bool = False) -> None:
|
|
22
25
|
# PostgreSQL doesn't support the multi parameter
|
|
23
26
|
# Convert MySQL-style backtick quotes to PostgreSQL double quotes
|
|
24
27
|
sql_statement = sql_statement.replace('`', '"')
|
|
@@ -43,7 +46,7 @@ class Cursor(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
|
43
46
|
self.logger.error(f"Error executing SQL: {e}")
|
|
44
47
|
raise
|
|
45
48
|
|
|
46
|
-
def executemany(self, sql_statement: str, sql_parameters: tuple | list = None) -> None:
|
|
49
|
+
def executemany(self, sql_statement: str, sql_parameters: Optional[tuple | list] = None) -> None:
|
|
47
50
|
try:
|
|
48
51
|
# Convert MySQL-style backtick quotes to PostgreSQL double quotes
|
|
49
52
|
sql_statement = sql_statement.replace('`', '"')
|
|
@@ -61,7 +64,7 @@ class Cursor(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
|
61
64
|
"sql_statement": sql_statement.replace("\n", " ")
|
|
62
65
|
})
|
|
63
66
|
|
|
64
|
-
self.cursor.executemany(sql_statement, sql_parameters)
|
|
67
|
+
self.cursor.executemany(sql_statement, sql_parameters or [])
|
|
65
68
|
except Exception as e:
|
|
66
69
|
self.logger.warning('Unable to execute statement', object={
|
|
67
70
|
"sql_statement": sql_statement,
|
|
@@ -82,7 +85,7 @@ class Cursor(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
|
82
85
|
result = self.cursor.fetchone()
|
|
83
86
|
return result
|
|
84
87
|
|
|
85
|
-
def description(self) ->
|
|
88
|
+
def description(self) -> Optional[tuple]:
|
|
86
89
|
"""Returns description of columns in a result
|
|
87
90
|
|
|
88
91
|
This property returns a list of tuples describing the columns
|
|
@@ -112,7 +115,8 @@ class Cursor(metaclass=MetaLogger, object=LOGGER_CONNECTOR_CODE_OBJECT):
|
|
|
112
115
|
# This is a simplified implementation that may need to be adjusted based on actual usage
|
|
113
116
|
try:
|
|
114
117
|
self.cursor.execute("SELECT lastval()")
|
|
115
|
-
|
|
118
|
+
row = self.cursor.fetchone()
|
|
119
|
+
result = row[0] if row else None
|
|
116
120
|
return result
|
|
117
121
|
except Exception as e:
|
|
118
122
|
self.logger.warning(f"Error getting lastrowid: {e}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime, timezone
|
|
2
2
|
from functools import lru_cache
|
|
3
|
-
from typing import Any, Optional
|
|
3
|
+
from typing import Any, Optional, Sequence
|
|
4
4
|
|
|
5
5
|
import psycopg2
|
|
6
6
|
from database_infrastructure_local.number_generator import NumberGenerator
|
|
@@ -10,9 +10,9 @@ from logger_local.MetaLogger import ABCMetaLogger
|
|
|
10
10
|
from user_context_remote.user_context import UserContext
|
|
11
11
|
from python_sdk_remote.our_object import OurObject
|
|
12
12
|
|
|
13
|
-
from .
|
|
13
|
+
from . import connector as connector_module
|
|
14
14
|
from .constants_src import CRUD_POSTGRESQL_CODE_LOGGER_OBJECT
|
|
15
|
-
from .
|
|
15
|
+
from . import cursor as cursor_module
|
|
16
16
|
from .table_definition import table_definition
|
|
17
17
|
from .utils import (detect_if_is_test_data, generate_id_column_name,
|
|
18
18
|
generate_table_name, generate_view_name,
|
|
@@ -31,24 +31,24 @@ from .utils import (detect_if_is_test_data, generate_id_column_name,
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
34
|
-
object=CRUD_POSTGRESQL_CODE_LOGGER_OBJECT):
|
|
34
|
+
object=CRUD_POSTGRESQL_CODE_LOGGER_OBJECT): # type: ignore[call-arg] # MetaLogger takes `object`
|
|
35
35
|
"""A class that provides generic CRUD functionality for PostgreSQL databases.
|
|
36
36
|
There are 4 main functions to create, read, update, and delete data from the database.
|
|
37
37
|
The rest of the functions are helper functions or wrappers around the main functions."""
|
|
38
38
|
|
|
39
39
|
def __init__(self, *, default_schema_name: str,
|
|
40
|
-
default_table_name: str = None,
|
|
41
|
-
default_view_table_name: str = None,
|
|
42
|
-
default_view_with_deleted_and_test_data: str = None,
|
|
43
|
-
default_column_name: str = None,
|
|
40
|
+
default_table_name: Optional[str] = None,
|
|
41
|
+
default_view_table_name: Optional[str] = None,
|
|
42
|
+
default_view_with_deleted_and_test_data: Optional[str] = None,
|
|
43
|
+
default_column_name: Optional[str] = None,
|
|
44
44
|
default_select_clause_value: str = "*",
|
|
45
|
-
default_where: str = None,
|
|
45
|
+
default_where: Optional[str] = None,
|
|
46
46
|
is_test_data: bool = False) -> None:
|
|
47
47
|
"""Initializes the GenericCrudPostgresql class. If a connection is not provided, a new connection will be created."""
|
|
48
48
|
self.default_schema_name = default_schema_name
|
|
49
49
|
# We do not need a connection per schema, and it makes terrible performance.
|
|
50
50
|
# In special cases, you can always use set_schema.
|
|
51
|
-
self.connection = Connector.connect(schema_name=default_schema_name)
|
|
51
|
+
self.connection = connector_module.Connector.connect(schema_name=default_schema_name)
|
|
52
52
|
self._cursor = self.connection.cursor()
|
|
53
53
|
self.default_table_name = default_table_name or generate_table_name(default_schema_name)
|
|
54
54
|
self.default_view_table_name = default_view_table_name or generate_view_name(
|
|
@@ -61,8 +61,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
61
61
|
self.is_ignore_duplicate = False
|
|
62
62
|
self.user_context = UserContext()
|
|
63
63
|
|
|
64
|
-
def insert(self, *, schema_name: str = None, table_name: str = None, data_dict: dict = None,
|
|
65
|
-
ignore_duplicate: bool = False, commit_changes: bool = True) -> int:
|
|
64
|
+
def insert(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None, data_dict: Optional[dict] = None,
|
|
65
|
+
ignore_duplicate: bool = False, commit_changes: bool = True) -> Optional[int]:
|
|
66
66
|
"""Inserts a new row into the table and returns the id of the new row or -1 if an error occurred.
|
|
67
67
|
ignore_duplicate should be False as default, because for example if a user register with existing name,
|
|
68
68
|
he should get an error and not existing id
|
|
@@ -174,10 +174,10 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
174
174
|
where=where, params=params)
|
|
175
175
|
return existing_duplicate_id
|
|
176
176
|
def update_by_column_and_value(
|
|
177
|
-
self, *, schema_name: str = None, table_name: str = None,
|
|
178
|
-
column_name: str = None, column_value: Any,
|
|
179
|
-
data_dict: dict = None,
|
|
180
|
-
limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: str = None,
|
|
177
|
+
self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None,
|
|
178
|
+
column_name: Optional[str] = None, column_value: Any,
|
|
179
|
+
data_dict: Optional[dict] = None,
|
|
180
|
+
limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: Optional[str] = None,
|
|
181
181
|
commit_changes: bool = True) -> int:
|
|
182
182
|
"""Updates data in the table by ID."""
|
|
183
183
|
|
|
@@ -194,95 +194,11 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
194
194
|
else:
|
|
195
195
|
raise Exception("Update by id requires an column_name")
|
|
196
196
|
|
|
197
|
-
def update_by_where(self, *, schema_name: str = None,
|
|
198
|
-
table_name: str = None, where: str = None,
|
|
199
|
-
params: tuple = None, data_dict: dict = None,
|
|
197
|
+
def update_by_where(self, *, schema_name: Optional[str] = None,
|
|
198
|
+
table_name: Optional[str] = None, where: Optional[str] = None,
|
|
199
|
+
params: Optional[tuple] = None, data_dict: Optional[dict] = None,
|
|
200
200
|
limit: int = DEFAULT_SQL_SELECT_LIMIT,
|
|
201
|
-
order_by: str = None,
|
|
202
|
-
commit_changes: bool = True) -> int:
|
|
203
|
-
"""Updates data in the table by WHERE.
|
|
204
|
-
Example:
|
|
205
|
-
"UPDATE table_name SET A=A_val, B=B_val WHERE C=C_val AND D=D_val"
|
|
206
|
-
translates into:
|
|
207
|
-
update_by_where(table_name="table_name",
|
|
208
|
-
data_dict={"A": A_val, "B": B_val},
|
|
209
|
-
where="C=%s AND D=%s",
|
|
210
|
-
params=(C_val, D_val)"
|
|
211
|
-
"""
|
|
212
|
-
|
|
213
|
-
table_name = table_name or self.default_table_name
|
|
214
|
-
schema_name = schema_name or self.default_schema_name
|
|
215
|
-
self._validate_args(args=locals())
|
|
216
|
-
|
|
217
|
-
data_dict = self.__add_create_updated_user_profile_ids(data_dict=data_dict, add_created_user_id=False,
|
|
218
|
-
schema_name=schema_name, table_name=table_name)
|
|
219
|
-
|
|
220
|
-
set_values, data_dict_params = process_update_data_dict(data_dict)
|
|
221
|
-
if not where:
|
|
222
|
-
raise Exception("update_by_where requires a 'where'")
|
|
223
|
-
|
|
224
|
-
# PostgreSQL doesn't support LIMIT in UPDATE without a subquery
|
|
225
|
-
# We'll handle this differently based on whether limit and order_by are provided
|
|
226
|
-
if limit != DEFAULT_SQL_SELECT_LIMIT or order_by:
|
|
227
|
-
# For PostgreSQL, we need to use a subquery with LIMIT and ORDER BY
|
|
228
|
-
id_column = generate_id_column_name(table_name)
|
|
229
|
-
|
|
230
|
-
# First, get the IDs of rows to update
|
|
231
|
-
select_query = f'SELECT "{id_column}" FROM "{schema_name}"."{table_name}" WHERE {where}'
|
|
232
|
-
if order_by:
|
|
233
|
-
select_query += f' ORDER BY {order_by}'
|
|
234
|
-
if limit != DEFAULT_SQL_SELECT_LIMIT:
|
|
235
|
-
select_query += f' LIMIT {limit}'
|
|
236
|
-
|
|
237
|
-
# Then update only those rows
|
|
238
|
-
if 'mapping' in self.default_table_name:
|
|
239
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values} ' \
|
|
240
|
-
f'WHERE "{id_column}" IN ({select_query});'
|
|
241
|
-
else:
|
|
242
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values}, ' \
|
|
243
|
-
f'updated_timestamp=CURRENT_TIMESTAMP ' \
|
|
244
|
-
f'WHERE "{id_column}" IN ({select_query});'
|
|
245
|
-
else:
|
|
246
|
-
# Simple update without LIMIT or ORDER BY
|
|
247
|
-
if 'mapping' in self.default_table_name:
|
|
248
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values} WHERE {where};'
|
|
249
|
-
else:
|
|
250
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values}, ' \
|
|
251
|
-
f'updated_timestamp=CURRENT_TIMESTAMP WHERE {where};'
|
|
252
|
-
|
|
253
|
-
where_params = params or tuple()
|
|
254
|
-
|
|
255
|
-
self.cursor.execute(update_query, data_dict_params + where_params)
|
|
256
|
-
if commit_changes:
|
|
257
|
-
self.connection.commit()
|
|
258
|
-
updated_rows = self.cursor.get_affected_row_count()
|
|
259
|
-
return updated_rows
|
|
260
|
-
def update_by_column_and_value(
|
|
261
|
-
self, *, schema_name: str = None, table_name: str = None,
|
|
262
|
-
column_name: str = None, column_value: Any,
|
|
263
|
-
data_dict: dict = None,
|
|
264
|
-
limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: str = None,
|
|
265
|
-
commit_changes: bool = True) -> int:
|
|
266
|
-
"""Updates data in the table by ID."""
|
|
267
|
-
|
|
268
|
-
table_name = table_name or self.default_table_name
|
|
269
|
-
column_name = column_name or self.default_column_name
|
|
270
|
-
|
|
271
|
-
if column_name:
|
|
272
|
-
where, params = get_where_params(column_name, column_value)
|
|
273
|
-
updated_rows = self.update_by_where(
|
|
274
|
-
schema_name=schema_name, table_name=table_name, where=where, data_dict=data_dict,
|
|
275
|
-
params=params, limit=limit, order_by=order_by, commit_changes=commit_changes)
|
|
276
|
-
return updated_rows
|
|
277
|
-
|
|
278
|
-
else:
|
|
279
|
-
raise Exception("Update by id requires an column_name")
|
|
280
|
-
|
|
281
|
-
def update_by_where(self, *, schema_name: str = None,
|
|
282
|
-
table_name: str = None, where: str = None,
|
|
283
|
-
params: tuple = None, data_dict: dict = None,
|
|
284
|
-
limit: int = DEFAULT_SQL_SELECT_LIMIT,
|
|
285
|
-
order_by: str = None,
|
|
201
|
+
order_by: Optional[str] = None,
|
|
286
202
|
commit_changes: bool = True) -> int:
|
|
287
203
|
"""Updates data in the table by WHERE.
|
|
288
204
|
Example:
|
|
@@ -342,8 +258,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
342
258
|
updated_rows = self.cursor.get_affected_row_count()
|
|
343
259
|
return updated_rows
|
|
344
260
|
|
|
345
|
-
def delete_by_column_and_value(self, *, schema_name: str = None, table_name: str = None,
|
|
346
|
-
column_name: str = None, column_value: Any) -> int:
|
|
261
|
+
def delete_by_column_and_value(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None,
|
|
262
|
+
column_name: Optional[str] = None, column_value: Any) -> int:
|
|
347
263
|
"""Deletes data from the table by id.
|
|
348
264
|
Returns the number of deleted rows."""
|
|
349
265
|
# checks are done inside delete_by_where
|
|
@@ -357,8 +273,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
357
273
|
else:
|
|
358
274
|
raise Exception("Delete by id requires an column_name and column_value.")
|
|
359
275
|
|
|
360
|
-
def delete_by_where(self, *, schema_name: str = None, table_name: str = None, where: str = None,
|
|
361
|
-
params: tuple = None) -> int:
|
|
276
|
+
def delete_by_where(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None, where: Optional[str] = None,
|
|
277
|
+
params: Optional[tuple] = None) -> int:
|
|
362
278
|
"""Deletes data from the table by WHERE.
|
|
363
279
|
Returns the number of deleted rows."""
|
|
364
280
|
|
|
@@ -380,8 +296,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
380
296
|
deleted_rows = self.cursor.get_affected_row_count()
|
|
381
297
|
return deleted_rows
|
|
382
298
|
|
|
383
|
-
def undelete_by_column_and_value(self, *, schema_name: str = None, table_name: str = None,
|
|
384
|
-
column_name: str = None, column_value: Any) -> None:
|
|
299
|
+
def undelete_by_column_and_value(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None,
|
|
300
|
+
column_name: Optional[str] = None, column_value: Any) -> None:
|
|
385
301
|
"""Undeletes a row by setting the end_timestamp to NULL."""
|
|
386
302
|
schema_name = schema_name or self.default_schema_name
|
|
387
303
|
table_name = table_name or self.default_table_name
|
|
@@ -393,9 +309,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
393
309
|
data_dict={"end_timestamp": None})
|
|
394
310
|
# Main select function
|
|
395
311
|
def select_multi_tuple_by_where(
|
|
396
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
397
|
-
where: str = None, params: tuple = None, distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT,
|
|
398
|
-
order_by: str = None) -> list:
|
|
312
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
313
|
+
where: Optional[str] = None, params: Optional[tuple] = None, distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT,
|
|
314
|
+
order_by: Optional[str] = None) -> list:
|
|
399
315
|
"""Selects multiple rows from the table based on a WHERE clause and returns them as a list of tuples."""
|
|
400
316
|
|
|
401
317
|
schema_name = schema_name or self.default_schema_name
|
|
@@ -440,21 +356,22 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
440
356
|
return result
|
|
441
357
|
|
|
442
358
|
def select_multi_dict_by_where(
|
|
443
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
444
|
-
where: str = None, params: tuple = None, distinct: bool = False, group_by: str = None,
|
|
445
|
-
limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: str = None) -> list | dict[tuple | str, list]:
|
|
359
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
360
|
+
where: Optional[str] = None, params: Optional[tuple] = None, distinct: bool = False, group_by: Optional[str] = None,
|
|
361
|
+
limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: Optional[str] = None) -> list | dict[tuple | str, list]:
|
|
446
362
|
"""Selects multiple rows from the table based on a WHERE clause and returns them as a list of dictionaries."""
|
|
447
363
|
result = self.select_multi_tuple_by_where(
|
|
448
364
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
449
365
|
where=where, params=params, distinct=distinct, limit=limit, order_by=order_by)
|
|
450
366
|
result_as_dicts = self.convert_multi_to_dict(result, select_clause_value)
|
|
451
367
|
if group_by:
|
|
452
|
-
|
|
368
|
+
grouped_result = group_list_by_columns(list_of_dicts=result_as_dicts, group_by=group_by)
|
|
369
|
+
return grouped_result
|
|
453
370
|
return result_as_dicts
|
|
454
371
|
|
|
455
372
|
def select_one_tuple_by_where(
|
|
456
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
457
|
-
where: str = None, params: tuple = None, distinct: bool = False, order_by: str = None) -> tuple:
|
|
373
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
374
|
+
where: Optional[str] = None, params: Optional[tuple] = None, distinct: bool = False, order_by: Optional[str] = None) -> tuple:
|
|
458
375
|
"""Selects one row from the table based on a WHERE clause and returns it as a tuple."""
|
|
459
376
|
result = self.select_multi_tuple_by_where(
|
|
460
377
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
@@ -466,18 +383,18 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
466
383
|
return tuple_result
|
|
467
384
|
|
|
468
385
|
def select_one_dict_by_where(
|
|
469
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
470
|
-
where: str = None, params: tuple = None, distinct: bool = False, order_by: str = None) -> dict:
|
|
386
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
387
|
+
where: Optional[str] = None, params: Optional[tuple] = None, distinct: bool = False, order_by: Optional[str] = None) -> dict:
|
|
471
388
|
"""Selects one row from the table based on a WHERE clause and returns it as a dictionary."""
|
|
472
|
-
|
|
389
|
+
row = self.select_one_tuple_by_where(
|
|
473
390
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
474
391
|
where=where, params=params, distinct=distinct, order_by=order_by)
|
|
475
|
-
result = self.convert_to_dict(row=
|
|
392
|
+
result = self.convert_to_dict(row=row, select_clause_value=select_clause_value)
|
|
476
393
|
return result
|
|
477
394
|
|
|
478
395
|
def select_one_value_by_where(
|
|
479
|
-
self, *, select_clause_value: str, schema_name: str = None, view_table_name: str = None,
|
|
480
|
-
where: str = None, params: tuple = None, distinct: bool = False, order_by: str = None,
|
|
396
|
+
self, *, select_clause_value: str, schema_name: Optional[str] = None, view_table_name: Optional[str] = None,
|
|
397
|
+
where: Optional[str] = None, params: Optional[tuple] = None, distinct: bool = False, order_by: Optional[str] = None,
|
|
481
398
|
skip_null_values: bool = True) -> Any:
|
|
482
399
|
"""Selects one value from the table based on a WHERE clause and returns it."""
|
|
483
400
|
select_clause_value = select_clause_value or self.default_select_clause_value
|
|
@@ -492,9 +409,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
492
409
|
value = None
|
|
493
410
|
return value
|
|
494
411
|
def select_one_tuple_by_column_and_value(
|
|
495
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
496
|
-
column_name: str = None, column_value: Any,
|
|
497
|
-
distinct: bool = False, order_by: str = None) -> tuple:
|
|
412
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
413
|
+
column_name: Optional[str] = None, column_value: Any,
|
|
414
|
+
distinct: bool = False, order_by: Optional[str] = None) -> tuple:
|
|
498
415
|
"""Selects one row from the table by ID and returns it as a tuple."""
|
|
499
416
|
result = self.select_multi_tuple_by_column_and_value(
|
|
500
417
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
@@ -506,20 +423,20 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
506
423
|
return one_tuple_result
|
|
507
424
|
|
|
508
425
|
def select_one_dict_by_column_and_value(
|
|
509
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
510
|
-
column_name: str = None, column_value: Any,
|
|
511
|
-
distinct: bool = False, order_by: str = None) -> dict:
|
|
426
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
427
|
+
column_name: Optional[str] = None, column_value: Any,
|
|
428
|
+
distinct: bool = False, order_by: Optional[str] = None) -> dict:
|
|
512
429
|
"""Selects one row from the table by ID and returns it as a dictionary (column_name: value)"""
|
|
513
|
-
|
|
430
|
+
row = self.select_one_tuple_by_column_and_value(
|
|
514
431
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
515
432
|
column_name=column_name, column_value=column_value, distinct=distinct, order_by=order_by)
|
|
516
|
-
result = self.convert_to_dict(row=
|
|
433
|
+
result = self.convert_to_dict(row=row, select_clause_value=select_clause_value)
|
|
517
434
|
return result
|
|
518
435
|
|
|
519
436
|
def select_one_value_by_column_and_value(
|
|
520
|
-
self, *, select_clause_value: str = None, schema_name: str = None, view_table_name: str = None,
|
|
521
|
-
column_name: str = None, column_value: Any,
|
|
522
|
-
distinct: bool = False, order_by: str = None, skip_null_values: bool = True) -> Any:
|
|
437
|
+
self, *, select_clause_value: Optional[str] = None, schema_name: Optional[str] = None, view_table_name: Optional[str] = None,
|
|
438
|
+
column_name: Optional[str] = None, column_value: Any,
|
|
439
|
+
distinct: bool = False, order_by: Optional[str] = None, skip_null_values: bool = True) -> Any:
|
|
523
440
|
"""Selects one value from the table by ID and returns it."""
|
|
524
441
|
|
|
525
442
|
column_name = column_name or self.default_column_name
|
|
@@ -537,9 +454,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
537
454
|
return value
|
|
538
455
|
|
|
539
456
|
def select_multi_tuple_by_column_and_value(
|
|
540
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
541
|
-
column_name: str = None, column_value: Any,
|
|
542
|
-
distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: str = None) -> list:
|
|
457
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
458
|
+
column_name: Optional[str] = None, column_value: Any,
|
|
459
|
+
distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: Optional[str] = None) -> list:
|
|
543
460
|
"""Selects multiple rows from the table by ID and returns them as a list of tuples.
|
|
544
461
|
If column_value is list / tuple, it will be used as multiple values for the column_name (SQL IN)."""
|
|
545
462
|
|
|
@@ -552,20 +469,21 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
552
469
|
return result
|
|
553
470
|
|
|
554
471
|
def select_multi_dict_by_column_and_value(
|
|
555
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
556
|
-
column_name: str = None, column_value: Any,
|
|
557
|
-
distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: str = None,
|
|
558
|
-
group_by: str = None) -> list | dict[tuple | str, list]:
|
|
472
|
+
self, *, schema_name: Optional[str] = None, view_table_name: Optional[str] = None, select_clause_value: Optional[str] = None,
|
|
473
|
+
column_name: Optional[str] = None, column_value: Any,
|
|
474
|
+
distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: Optional[str] = None,
|
|
475
|
+
group_by: Optional[str] = None) -> list | dict[tuple | str, list]:
|
|
559
476
|
"""Selects multiple rows from the table by ID and returns them as a list of dictionaries."""
|
|
560
477
|
result = self.select_multi_tuple_by_column_and_value(
|
|
561
478
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
562
479
|
column_name=column_name, column_value=column_value, distinct=distinct, limit=limit, order_by=order_by)
|
|
563
480
|
result_as_dicts = self.convert_multi_to_dict(result, select_clause_value)
|
|
564
481
|
if group_by:
|
|
565
|
-
|
|
482
|
+
grouped_result = group_list_by_columns(list_of_dicts=result_as_dicts, group_by=group_by)
|
|
483
|
+
return grouped_result
|
|
566
484
|
return result_as_dicts
|
|
567
|
-
def insert_if_not_exists(self, *, schema_name: str = None, table_name: str = None, data_dict: dict = None,
|
|
568
|
-
data_dict_compare: dict = None, view_table_name: str = None,
|
|
485
|
+
def insert_if_not_exists(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None, data_dict: Optional[dict] = None,
|
|
486
|
+
data_dict_compare: Optional[dict] = None, view_table_name: Optional[str] = None,
|
|
569
487
|
commit_changes: bool = True, compare_with_or: bool = False) -> int:
|
|
570
488
|
"""Inserts a new row into the table if a row with the same values does not exist,
|
|
571
489
|
and returns the id of the new row | None if an error occurred."""
|
|
@@ -576,7 +494,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
576
494
|
self._validate_args(args=locals())
|
|
577
495
|
|
|
578
496
|
# Try to select
|
|
579
|
-
where_clause, params = process_upsert_data_dict(data_dict=data_dict_compare, compare_with_or=compare_with_or)
|
|
497
|
+
where_clause, params = process_upsert_data_dict(data_dict=data_dict_compare or {}, compare_with_or=compare_with_or)
|
|
580
498
|
row_tuple = self.select_one_tuple_by_where(
|
|
581
499
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value="*",
|
|
582
500
|
where=where_clause, params=params)
|
|
@@ -591,7 +509,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
591
509
|
object={"id": entity_id})
|
|
592
510
|
return entity_id
|
|
593
511
|
|
|
594
|
-
def insert_many_dicts(self, *, schema_name: str = None, table_name: str = None, data_dicts: list[dict],
|
|
512
|
+
def insert_many_dicts(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None, data_dicts: list[dict],
|
|
595
513
|
commit_changes: bool = True) -> int:
|
|
596
514
|
"""Inserts multiple rows into the table.
|
|
597
515
|
data_dicts should be in the following format: [{col1: val1, col2: val2}, {col1: val3, col2: val4}, ...]
|
|
@@ -601,13 +519,13 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
601
519
|
self.logger.warning("GenericCrudPostgresql.insert_many_dicts: data_dicts is empty")
|
|
602
520
|
inserted_rows = 0
|
|
603
521
|
else:
|
|
604
|
-
converted_data_dicts = {col: [row[col] for row in data_dicts] for col in data_dicts[0]}
|
|
522
|
+
converted_data_dicts: dict[str, list[Any] | tuple[Any, ...]] = {col: [row[col] for row in data_dicts] for col in data_dicts[0]}
|
|
605
523
|
inserted_rows = self.insert_many(schema_name=schema_name, table_name=table_name,
|
|
606
524
|
data_dict=converted_data_dicts, commit_changes=commit_changes)
|
|
607
525
|
|
|
608
526
|
return inserted_rows
|
|
609
527
|
|
|
610
|
-
def insert_many(self, *, schema_name: str = None, table_name: str = None, data_dict: dict[str, list | tuple],
|
|
528
|
+
def insert_many(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None, data_dict: dict[str, list | tuple],
|
|
611
529
|
commit_changes: bool = True) -> int:
|
|
612
530
|
"""Inserts multiple rows into the table.
|
|
613
531
|
data_dict should be in the following format: {col1: [val1, val2], col2: [val3, val4], ...}
|
|
@@ -640,9 +558,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
640
558
|
self.connection.commit()
|
|
641
559
|
inserted_rows = self.cursor.get_affected_row_count()
|
|
642
560
|
return inserted_rows
|
|
643
|
-
def upsert_with_select_clause(self, *, schema_name: str = None, table_name: str = None, view_table_name: str = None,
|
|
644
|
-
data_dict: dict = None, where_compare: str = None, params_compare: tuple = None,
|
|
645
|
-
data_dict_compare: dict = None, order_by: str = None, compare_with_or: bool = False,
|
|
561
|
+
def upsert_with_select_clause(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None, view_table_name: Optional[str] = None,
|
|
562
|
+
data_dict: Optional[dict] = None, where_compare: Optional[str] = None, params_compare: Optional[tuple] = None,
|
|
563
|
+
data_dict_compare: Optional[dict] = None, order_by: Optional[str] = None, compare_with_or: bool = False,
|
|
646
564
|
select_clause_value: str = "*") -> dict:
|
|
647
565
|
"""
|
|
648
566
|
Inserts a new row into the table if a row with the same values does not exist,
|
|
@@ -659,7 +577,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
659
577
|
view_table_name = view_table_name or self.default_view_table_name
|
|
660
578
|
column_name = generate_id_column_name(table_name)
|
|
661
579
|
self._validate_args(args=locals())
|
|
662
|
-
result_dict = {}
|
|
580
|
+
result_dict: dict = {}
|
|
663
581
|
if not data_dict:
|
|
664
582
|
self.logger.warning(log_message="GenericCrudPostgresql.upsert_with_select_clause: data_dict is empty")
|
|
665
583
|
return result_dict
|
|
@@ -670,7 +588,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
670
588
|
result_dict = data_dict
|
|
671
589
|
return result_dict
|
|
672
590
|
|
|
673
|
-
where_clause, params = process_upsert_data_dict(data_dict=data_dict_compare, compare_with_or=compare_with_or,
|
|
591
|
+
where_clause, params = process_upsert_data_dict(data_dict=data_dict_compare or {}, compare_with_or=compare_with_or,
|
|
674
592
|
where_compare=where_compare, params_compare=params_compare)
|
|
675
593
|
# Add table_id if it's not in select_clause_value
|
|
676
594
|
if select_clause_value != "*" and column_name not in select_clause_value:
|
|
@@ -706,10 +624,10 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
706
624
|
return result_dict
|
|
707
625
|
|
|
708
626
|
# We want upsert to call upsert_with_select_clause, and return only the id
|
|
709
|
-
def upsert(self, *, schema_name: str = None, table_name: str = None, view_table_name: str = None,
|
|
710
|
-
data_dict: dict = None, where_compare: str = None,
|
|
711
|
-
params_compare: tuple = None, data_dict_compare: dict = None,
|
|
712
|
-
order_by: str = None, compare_with_or: bool = False) -> Optional[int]:
|
|
627
|
+
def upsert(self, *, schema_name: Optional[str] = None, table_name: Optional[str] = None, view_table_name: Optional[str] = None,
|
|
628
|
+
data_dict: Optional[dict] = None, where_compare: Optional[str] = None,
|
|
629
|
+
params_compare: Optional[tuple] = None, data_dict_compare: Optional[dict] = None,
|
|
630
|
+
order_by: Optional[str] = None, compare_with_or: bool = False) -> Optional[int]:
|
|
713
631
|
"""
|
|
714
632
|
Inserts a new row into the table if a row with the same values does not exist,
|
|
715
633
|
the "same values" are extracted from data_dict_compare.
|
|
@@ -728,18 +646,18 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
728
646
|
inserted_id = inserted_id_per_column_dict[column_name]
|
|
729
647
|
return inserted_id
|
|
730
648
|
# Helper methods
|
|
731
|
-
def convert_to_dict(self, row: tuple, select_clause_value: str = None) -> dict:
|
|
649
|
+
def convert_to_dict(self, row: tuple, select_clause_value: Optional[str] = None) -> dict:
|
|
732
650
|
"""Returns a dictionary of the column names and their values."""
|
|
733
651
|
select_clause_value = select_clause_value or self.default_select_clause_value
|
|
734
652
|
if select_clause_value == "*":
|
|
735
|
-
column_names = self.cursor.column_names()
|
|
653
|
+
column_names: Sequence[str] = self.cursor.column_names()
|
|
736
654
|
else:
|
|
737
655
|
column_names = [x.strip() for x in select_clause_value.split(",")]
|
|
738
656
|
dict_result = dict(zip(column_names, row or tuple()))
|
|
739
657
|
self.logger.debug(object=locals())
|
|
740
658
|
return dict_result
|
|
741
659
|
|
|
742
|
-
def convert_multi_to_dict(self, rows: list[tuple], select_clause_value: str = None) -> list[dict]:
|
|
660
|
+
def convert_multi_to_dict(self, rows: list[tuple], select_clause_value: Optional[str] = None) -> list[dict]:
|
|
743
661
|
"""Converts multiple rows to dictionaries."""
|
|
744
662
|
multiple_dict_result = [self.convert_to_dict(row=row, select_clause_value=select_clause_value)
|
|
745
663
|
for row in rows]
|
|
@@ -769,7 +687,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
769
687
|
if message:
|
|
770
688
|
raise Exception(message)
|
|
771
689
|
|
|
772
|
-
def __where_security(self, where: str, view_name: str) -> str:
|
|
690
|
+
def __where_security(self, where: Optional[str], view_name: str) -> Optional[str]:
|
|
773
691
|
"""Adds security to the where clause."""
|
|
774
692
|
if view_name in table_definition:
|
|
775
693
|
if table_definition[view_name].get("is_visibility"):
|
|
@@ -780,8 +698,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
780
698
|
return where_security
|
|
781
699
|
return where
|
|
782
700
|
|
|
783
|
-
def __add_create_updated_user_profile_ids(self, data_dict: dict, add_created_user_id: bool = False,
|
|
784
|
-
schema_name: str = None, table_name: str = None) -> dict:
|
|
701
|
+
def __add_create_updated_user_profile_ids(self, data_dict: Optional[dict], add_created_user_id: bool = False,
|
|
702
|
+
schema_name: Optional[str] = None, table_name: Optional[str] = None) -> dict:
|
|
785
703
|
"""Adds created_user_id and updated_user_id to data_dict."""
|
|
786
704
|
data_dict = data_dict or {}
|
|
787
705
|
schema_name = schema_name or self.default_schema_name
|
|
@@ -863,7 +781,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
863
781
|
self.connection.commit()
|
|
864
782
|
|
|
865
783
|
@lru_cache
|
|
866
|
-
def get_primary_key(self, schema_name: str = None, table_name: str = None) -> str | None:
|
|
784
|
+
def get_primary_key(self, schema_name: Optional[str] = None, table_name: Optional[str] = None) -> str | None:
|
|
867
785
|
schema_name = schema_name or self.default_schema_name
|
|
868
786
|
table_name = table_name or self.default_table_name
|
|
869
787
|
query = """
|
|
@@ -921,7 +839,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
921
839
|
return where, params
|
|
922
840
|
|
|
923
841
|
@property
|
|
924
|
-
def cursor(self) -> Cursor:
|
|
842
|
+
def cursor(self) -> cursor_module.Cursor:
|
|
925
843
|
"""Get a new cursor"""
|
|
926
844
|
if self._cursor.is_closed():
|
|
927
845
|
self._cursor = self.connection.cursor()
|
|
@@ -929,7 +847,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
929
847
|
return cursor
|
|
930
848
|
|
|
931
849
|
@cursor.setter
|
|
932
|
-
def cursor(self, value: Cursor) -> None:
|
|
850
|
+
def cursor(self, value: cursor_module.Cursor) -> None:
|
|
933
851
|
"""Set the cursor"""
|
|
934
852
|
self._cursor = value
|
|
935
853
|
|
|
@@ -82,7 +82,7 @@ def generate_view_name(table_name: str) -> str:
|
|
|
82
82
|
return f"{table_name}_view"
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
def get_entity_type_by_table_name(table_name: str) -> int:
|
|
85
|
+
def get_entity_type_by_table_name(table_name: str) -> Optional[int]:
|
|
86
86
|
"""Gets the entity type ID for a table."""
|
|
87
87
|
# This would be implemented based on your entity type mapping
|
|
88
88
|
return None
|
|
@@ -116,27 +116,27 @@ def process_update_data_dict(data_dict: dict) -> tuple:
|
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
def process_upsert_data_dict(data_dict: dict, compare_with_or: bool = False,
|
|
119
|
-
where_compare: str = None, params_compare: tuple = None) -> tuple:
|
|
119
|
+
where_compare: Optional[str] = None, params_compare: Optional[tuple] = None) -> tuple:
|
|
120
120
|
"""Processes a dictionary for an UPSERT statement."""
|
|
121
121
|
if where_compare:
|
|
122
122
|
where = where_compare
|
|
123
123
|
params = params_compare
|
|
124
124
|
else:
|
|
125
125
|
where_parts = []
|
|
126
|
-
|
|
126
|
+
params_list = []
|
|
127
127
|
for key, value in data_dict.items():
|
|
128
128
|
if value is None:
|
|
129
129
|
where_parts.append(f"\"{key}\" IS NULL")
|
|
130
130
|
else:
|
|
131
131
|
where_parts.append(f"\"{key}\" = %s")
|
|
132
|
-
|
|
132
|
+
params_list.append(value)
|
|
133
133
|
connector = " OR " if compare_with_or else " AND "
|
|
134
134
|
where = connector.join(where_parts)
|
|
135
|
-
params = tuple(
|
|
135
|
+
params = tuple(params_list)
|
|
136
136
|
return where, params
|
|
137
137
|
|
|
138
138
|
|
|
139
|
-
def replace_view_with_table(view_table_name: str, select_clause_value: str = None) -> str:
|
|
139
|
+
def replace_view_with_table(view_table_name: str, select_clause_value: Optional[str] = None) -> str:
|
|
140
140
|
"""Replaces a view name with a table name."""
|
|
141
141
|
if view_table_name.endswith('_view'):
|
|
142
142
|
return view_table_name[:-5] + '_table'
|
|
@@ -161,7 +161,7 @@ def validate_single_clause_value(select_clause_value: str) -> None:
|
|
|
161
161
|
raise ValueError(f"Expected a single column, got: {select_clause_value}")
|
|
162
162
|
|
|
163
163
|
|
|
164
|
-
def where_skip_null_values(where: str, select_clause_value: str, skip_null_values: bool) -> str:
|
|
164
|
+
def where_skip_null_values(where: Optional[str], select_clause_value: str, skip_null_values: bool) -> Optional[str]:
|
|
165
165
|
"""Adds a condition to skip NULL values in a WHERE clause."""
|
|
166
166
|
if skip_null_values:
|
|
167
167
|
null_condition = f"{select_clause_value} IS NOT NULL"
|
|
@@ -199,7 +199,7 @@ def get_table_columns(table_name: str) -> list:
|
|
|
199
199
|
|
|
200
200
|
def group_list_by_columns(list_of_dicts: list, group_by: str) -> dict:
|
|
201
201
|
"""Groups a list of dictionaries by specified columns."""
|
|
202
|
-
result = {}
|
|
202
|
+
result: dict = {}
|
|
203
203
|
group_by_columns = [col.strip() for col in group_by.split(',')]
|
|
204
204
|
|
|
205
205
|
for item in list_of_dicts:
|
|
@@ -217,15 +217,15 @@ def group_list_by_columns(list_of_dicts: list, group_by: str) -> dict:
|
|
|
217
217
|
def process_select_data_dict(data_dict: dict) -> tuple:
|
|
218
218
|
"""Processes a dictionary for a SELECT statement."""
|
|
219
219
|
where_parts = []
|
|
220
|
-
|
|
220
|
+
params_list = []
|
|
221
221
|
for key, value in data_dict.items():
|
|
222
222
|
if value is None:
|
|
223
223
|
where_parts.append(f"\"{key}\" IS NULL")
|
|
224
224
|
else:
|
|
225
225
|
where_parts.append(f"\"{key}\" = %s")
|
|
226
|
-
|
|
226
|
+
params_list.append(value)
|
|
227
227
|
where = " AND ".join(where_parts)
|
|
228
|
-
params = tuple(
|
|
228
|
+
params = tuple(params_list)
|
|
229
229
|
return where, params
|
|
230
230
|
|
|
231
231
|
|
|
@@ -233,7 +233,7 @@ def generate_where_clause_for_ignore_duplicate(data_dict: dict, constraint_colum
|
|
|
233
233
|
"""Generates a WHERE clause for checking duplicates."""
|
|
234
234
|
for columns in constraint_columns:
|
|
235
235
|
where_parts = []
|
|
236
|
-
|
|
236
|
+
params_list = []
|
|
237
237
|
valid = True
|
|
238
238
|
for column in columns:
|
|
239
239
|
if column in data_dict:
|
|
@@ -242,13 +242,13 @@ def generate_where_clause_for_ignore_duplicate(data_dict: dict, constraint_colum
|
|
|
242
242
|
where_parts.append(f"\"{column}\" IS NULL")
|
|
243
243
|
else:
|
|
244
244
|
where_parts.append(f"\"{column}\" = %s")
|
|
245
|
-
|
|
245
|
+
params_list.append(value)
|
|
246
246
|
else:
|
|
247
247
|
valid = False
|
|
248
248
|
break
|
|
249
249
|
if valid and where_parts:
|
|
250
250
|
where = " AND ".join(where_parts)
|
|
251
|
-
params = tuple(
|
|
251
|
+
params = tuple(params_list)
|
|
252
252
|
return where, params
|
|
253
253
|
return None, None
|
|
254
254
|
|
|
@@ -258,6 +258,6 @@ def fix_select_clause_value(select_clause_value: str) -> str:
|
|
|
258
258
|
return select_clause_value
|
|
259
259
|
|
|
260
260
|
|
|
261
|
-
def fix_where_clause_value(where_clause_value: str) -> str:
|
|
261
|
+
def fix_where_clause_value(where_clause_value: Optional[str]) -> Optional[str]:
|
|
262
262
|
"""Fixes a WHERE clause value."""
|
|
263
263
|
return where_clause_value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: database-postgresql-local
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2b4627
|
|
4
4
|
Summary: PyPI Package for Circles database-postgresql-local Python
|
|
5
5
|
Home-page: https://github.com/circles-zone/database-postgresql-local-python-package
|
|
6
6
|
Author: Circles
|
|
@@ -8,10 +8,9 @@ Author-email: info@circlez.ai
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
|
-
Requires-Dist: logger-local
|
|
12
|
-
Requires-Dist: database-sql-local
|
|
13
11
|
Requires-Dist: python-sdk-remote
|
|
14
|
-
Requires-Dist:
|
|
12
|
+
Requires-Dist: logger-local
|
|
13
|
+
Requires-Dist: psycopg2-binary
|
|
15
14
|
Dynamic: author
|
|
16
15
|
Dynamic: author-email
|
|
17
16
|
Dynamic: classifier
|
|
@@ -14,7 +14,7 @@ build-backend = "setuptools.build_meta"
|
|
|
14
14
|
# TODO: Please update the name, similar to storage-local (suffix -local)
|
|
15
15
|
name = "<project-name>"
|
|
16
16
|
# I believe we are still using the version from setup.py and not from here until Potery will work
|
|
17
|
-
version = "0.
|
|
17
|
+
version = "0.1.2b4627" # https://pypi.org/project/<project-name> i.e. https://pypi.org/project/storage-local/
|
|
18
18
|
description = "<project-name> Python Package"
|
|
19
19
|
readme = "README.md"
|
|
20
20
|
authors = [
|
|
@@ -24,7 +24,7 @@ setuptools.setup(
|
|
|
24
24
|
name=PACKAGE_NAME,
|
|
25
25
|
# Increase this number every time you make a change you
|
|
26
26
|
# want to publish. After 0.0.9 switch to 0.0.10 and not 0.1.0
|
|
27
|
-
version='0.1.
|
|
27
|
+
version='0.1.2b4627', # https://pypi.org/project/database-postgresql-local/
|
|
28
28
|
author="Circles",
|
|
29
29
|
author_email="info@circlez.ai",
|
|
30
30
|
description=f"PyPI Package for Circles {PACKAGE_NAME} Python",
|
|
@@ -51,12 +51,13 @@ setuptools.setup(
|
|
|
51
51
|
],
|
|
52
52
|
# TODO: Update which packages to include with this package in production
|
|
53
53
|
# (dependencies) - Not for development/testing
|
|
54
|
+
# When another package/code imports from this package, the packages
|
|
55
|
+
# in install_requires will be installed automatically
|
|
54
56
|
install_requires=[
|
|
57
|
+
'python-sdk-remote',
|
|
55
58
|
# TODO: in -remote package please use logger-remote instead.
|
|
56
59
|
'logger-local',
|
|
57
60
|
# TODO: In -remote package please delete this line.
|
|
58
|
-
'
|
|
59
|
-
'python-sdk-remote',
|
|
60
|
-
'psycopg2'
|
|
61
|
+
'psycopg2-binary'
|
|
61
62
|
]
|
|
62
63
|
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
TODO Please update the README of the package
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|