database-postgresql-local 0.1.2.1234__tar.gz → 0.1.3b4665__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.2.1234 → database_postgresql_local-0.1.3b4665}/PKG-INFO +2 -2
- database_postgresql_local-0.1.3b4665/README.md +10 -0
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/connector.py +13 -10
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/cursor.py +12 -8
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/generic_crud_postgresql.py +96 -186
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/table_columns.py +1 -1
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/table_definition.py +1 -1
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/utils.py +15 -15
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local.egg-info/PKG-INFO +2 -2
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local.egg-info/requires.txt +1 -1
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/pyproject.toml +1 -1
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/setup.py +2 -2
- database_postgresql_local-0.1.2.1234/README.md +0 -1
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/__init__.py +0 -0
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local/src/constants_src.py +0 -0
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local.egg-info/SOURCES.txt +0 -0
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local.egg-info/dependency_links.txt +0 -0
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/database_postgresql_local.egg-info/top_level.txt +0 -0
- {database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/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.3b4665
|
|
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
|
|
@@ -10,7 +10,7 @@ Classifier: Operating System :: OS Independent
|
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
Requires-Dist: python-sdk-remote
|
|
12
12
|
Requires-Dist: logger-local
|
|
13
|
-
Requires-Dist: psycopg2
|
|
13
|
+
Requires-Dist: psycopg2-binary
|
|
14
14
|
Dynamic: author
|
|
15
15
|
Dynamic: author-email
|
|
16
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,13 +10,13 @@ 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,
|
|
19
|
-
|
|
19
|
+
get_entity_type_by_table_name, get_where_params,
|
|
20
20
|
process_insert_data_dict, process_update_data_dict,
|
|
21
21
|
process_upsert_data_dict,
|
|
22
22
|
replace_view_with_table, validate_none_select_table_name,
|
|
@@ -31,41 +31,38 @@ from .utils import (detect_if_is_test_data, generate_id_column_name,
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
34
|
-
|
|
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
|
-
self.default_view_table_name = default_view_table_name
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
self.
|
|
58
|
-
or generate_id_column_name(self.default_table_name)
|
|
59
|
-
self.default_view_with_deleted_and_test_data = \
|
|
60
|
-
default_view_with_deleted_and_test_data
|
|
54
|
+
self.default_view_table_name = default_view_table_name or generate_view_name(
|
|
55
|
+
self.default_table_name)
|
|
56
|
+
self.default_column_name = default_column_name or generate_id_column_name(self.default_table_name)
|
|
57
|
+
self.default_view_with_deleted_and_test_data = default_view_with_deleted_and_test_data
|
|
61
58
|
self.default_select_clause_value = default_select_clause_value
|
|
62
59
|
self.default_where = default_where
|
|
63
60
|
self.is_test_data = is_test_data or detect_if_is_test_data()
|
|
64
61
|
self.is_ignore_duplicate = False
|
|
65
62
|
self.user_context = UserContext()
|
|
66
63
|
|
|
67
|
-
def insert(self, *, schema_name: str = None, table_name: str = None, data_dict: dict = None,
|
|
68
|
-
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]:
|
|
69
66
|
"""Inserts a new row into the table and returns the id of the new row or -1 if an error occurred.
|
|
70
67
|
ignore_duplicate should be False as default, because for example if a user register with existing name,
|
|
71
68
|
he should get an error and not existing id
|
|
@@ -78,8 +75,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
78
75
|
object={"data_dict": data_dict})
|
|
79
76
|
|
|
80
77
|
data_dict = self.__add_create_updated_user_profile_ids(
|
|
81
|
-
data_dict=data_dict, add_created_user_id=True,
|
|
82
|
-
schema_name=schema_name, table_name=table_name)
|
|
78
|
+
data_dict=data_dict, add_created_user_id=True, schema_name=schema_name, table_name=table_name)
|
|
83
79
|
|
|
84
80
|
columns, values, params = process_insert_data_dict(data_dict=data_dict)
|
|
85
81
|
|
|
@@ -131,9 +127,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
131
127
|
def __get_existing_duplicate_id_with_undelete(
|
|
132
128
|
self, schema_name: str, table_name: str, data_dict: dict) -> int | None:
|
|
133
129
|
column_name = generate_id_column_name(table_name)
|
|
134
|
-
where, params = self.get_constraint_where_clause(
|
|
135
|
-
|
|
136
|
-
data_dict=data_dict)
|
|
130
|
+
where, params = self.get_constraint_where_clause(schema_name=schema_name, table_name=table_name,
|
|
131
|
+
data_dict=data_dict)
|
|
137
132
|
row = self.select_one_tuple_by_where(
|
|
138
133
|
schema_name=schema_name, view_table_name=table_name,
|
|
139
134
|
select_clause_value=f"{column_name}, end_timestamp",
|
|
@@ -175,16 +170,14 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
175
170
|
existing_duplicate_id = None
|
|
176
171
|
else:
|
|
177
172
|
existing_duplicate_id = self.select_one_value_by_where(
|
|
178
|
-
schema_name=schema_name, view_table_name=table_name,
|
|
179
|
-
select_clause_value=column_name,
|
|
173
|
+
schema_name=schema_name, view_table_name=table_name, select_clause_value=column_name,
|
|
180
174
|
where=where, params=params)
|
|
181
175
|
return existing_duplicate_id
|
|
182
|
-
|
|
183
176
|
def update_by_column_and_value(
|
|
184
|
-
self, *, schema_name: str = None, table_name: str = None,
|
|
185
|
-
column_name: str = None, column_value: Any,
|
|
186
|
-
data_dict: dict = None,
|
|
187
|
-
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,
|
|
188
181
|
commit_changes: bool = True) -> int:
|
|
189
182
|
"""Updates data in the table by ID."""
|
|
190
183
|
|
|
@@ -201,96 +194,11 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
201
194
|
else:
|
|
202
195
|
raise Exception("Update by id requires an column_name")
|
|
203
196
|
|
|
204
|
-
def update_by_where(self, *, schema_name: str = None,
|
|
205
|
-
table_name: str = None, where: str = None,
|
|
206
|
-
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,
|
|
207
200
|
limit: int = DEFAULT_SQL_SELECT_LIMIT,
|
|
208
|
-
order_by: str = None,
|
|
209
|
-
commit_changes: bool = True) -> int:
|
|
210
|
-
"""Updates data in the table by WHERE.
|
|
211
|
-
Example:
|
|
212
|
-
"UPDATE table_name SET A=A_val, B=B_val WHERE C=C_val AND D=D_val"
|
|
213
|
-
translates into:
|
|
214
|
-
update_by_where(table_name="table_name",
|
|
215
|
-
data_dict={"A": A_val, "B": B_val},
|
|
216
|
-
where="C=%s AND D=%s",
|
|
217
|
-
params=(C_val, D_val)"
|
|
218
|
-
"""
|
|
219
|
-
|
|
220
|
-
table_name = table_name or self.default_table_name
|
|
221
|
-
schema_name = schema_name or self.default_schema_name
|
|
222
|
-
self._validate_args(args=locals())
|
|
223
|
-
|
|
224
|
-
data_dict = self.__add_create_updated_user_profile_ids(data_dict=data_dict, add_created_user_id=False,
|
|
225
|
-
schema_name=schema_name, table_name=table_name)
|
|
226
|
-
|
|
227
|
-
set_values, data_dict_params = process_update_data_dict(data_dict)
|
|
228
|
-
if not where:
|
|
229
|
-
raise Exception("update_by_where requires a 'where'")
|
|
230
|
-
|
|
231
|
-
# PostgreSQL doesn't support LIMIT in UPDATE without a subquery
|
|
232
|
-
# We'll handle this differently based on whether limit and order_by are provided
|
|
233
|
-
if limit != DEFAULT_SQL_SELECT_LIMIT or order_by:
|
|
234
|
-
# For PostgreSQL, we need to use a subquery with LIMIT and ORDER BY
|
|
235
|
-
id_column = generate_id_column_name(table_name)
|
|
236
|
-
|
|
237
|
-
# First, get the IDs of rows to update
|
|
238
|
-
select_query = f'SELECT "{id_column}" FROM "{schema_name}"."{table_name}" WHERE {where}'
|
|
239
|
-
if order_by:
|
|
240
|
-
select_query += f' ORDER BY {order_by}'
|
|
241
|
-
if limit != DEFAULT_SQL_SELECT_LIMIT:
|
|
242
|
-
select_query += f' LIMIT {limit}'
|
|
243
|
-
|
|
244
|
-
# Then update only those rows
|
|
245
|
-
if 'mapping' in self.default_table_name:
|
|
246
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values} ' \
|
|
247
|
-
f'WHERE "{id_column}" IN ({select_query});'
|
|
248
|
-
else:
|
|
249
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values}, ' \
|
|
250
|
-
f'updated_timestamp=CURRENT_TIMESTAMP ' \
|
|
251
|
-
f'WHERE "{id_column}" IN ({select_query});'
|
|
252
|
-
else:
|
|
253
|
-
# Simple update without LIMIT or ORDER BY
|
|
254
|
-
if 'mapping' in self.default_table_name:
|
|
255
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values} WHERE {where};'
|
|
256
|
-
else:
|
|
257
|
-
update_query = f'UPDATE "{schema_name}"."{table_name}" SET {set_values}, ' \
|
|
258
|
-
f'updated_timestamp=CURRENT_TIMESTAMP WHERE {where};'
|
|
259
|
-
|
|
260
|
-
where_params = params or tuple()
|
|
261
|
-
|
|
262
|
-
self.cursor.execute(update_query, data_dict_params + where_params)
|
|
263
|
-
if commit_changes:
|
|
264
|
-
self.connection.commit()
|
|
265
|
-
updated_rows = self.cursor.get_affected_row_count()
|
|
266
|
-
return updated_rows
|
|
267
|
-
|
|
268
|
-
def update_by_column_and_value(
|
|
269
|
-
self, *, schema_name: str = None, table_name: str = None,
|
|
270
|
-
column_name: str = None, column_value: Any,
|
|
271
|
-
data_dict: dict = None,
|
|
272
|
-
limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: str = None,
|
|
273
|
-
commit_changes: bool = True) -> int:
|
|
274
|
-
"""Updates data in the table by ID."""
|
|
275
|
-
|
|
276
|
-
table_name = table_name or self.default_table_name
|
|
277
|
-
column_name = column_name or self.default_column_name
|
|
278
|
-
|
|
279
|
-
if column_name:
|
|
280
|
-
where, params = get_where_params(column_name, column_value)
|
|
281
|
-
updated_rows = self.update_by_where(
|
|
282
|
-
schema_name=schema_name, table_name=table_name, where=where, data_dict=data_dict,
|
|
283
|
-
params=params, limit=limit, order_by=order_by, commit_changes=commit_changes)
|
|
284
|
-
return updated_rows
|
|
285
|
-
|
|
286
|
-
else:
|
|
287
|
-
raise Exception("Update by id requires an column_name")
|
|
288
|
-
|
|
289
|
-
def update_by_where(self, *, schema_name: str = None,
|
|
290
|
-
table_name: str = None, where: str = None,
|
|
291
|
-
params: tuple = None, data_dict: dict = None,
|
|
292
|
-
limit: int = DEFAULT_SQL_SELECT_LIMIT,
|
|
293
|
-
order_by: str = None,
|
|
201
|
+
order_by: Optional[str] = None,
|
|
294
202
|
commit_changes: bool = True) -> int:
|
|
295
203
|
"""Updates data in the table by WHERE.
|
|
296
204
|
Example:
|
|
@@ -350,8 +258,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
350
258
|
updated_rows = self.cursor.get_affected_row_count()
|
|
351
259
|
return updated_rows
|
|
352
260
|
|
|
353
|
-
def delete_by_column_and_value(self, *, schema_name: str = None, table_name: str = None,
|
|
354
|
-
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:
|
|
355
263
|
"""Deletes data from the table by id.
|
|
356
264
|
Returns the number of deleted rows."""
|
|
357
265
|
# checks are done inside delete_by_where
|
|
@@ -365,8 +273,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
365
273
|
else:
|
|
366
274
|
raise Exception("Delete by id requires an column_name and column_value.")
|
|
367
275
|
|
|
368
|
-
def delete_by_where(self, *, schema_name: str = None, table_name: str = None, where: str = None,
|
|
369
|
-
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:
|
|
370
278
|
"""Deletes data from the table by WHERE.
|
|
371
279
|
Returns the number of deleted rows."""
|
|
372
280
|
|
|
@@ -388,8 +296,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
388
296
|
deleted_rows = self.cursor.get_affected_row_count()
|
|
389
297
|
return deleted_rows
|
|
390
298
|
|
|
391
|
-
def undelete_by_column_and_value(self, *, schema_name: str = None, table_name: str = None,
|
|
392
|
-
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:
|
|
393
301
|
"""Undeletes a row by setting the end_timestamp to NULL."""
|
|
394
302
|
schema_name = schema_name or self.default_schema_name
|
|
395
303
|
table_name = table_name or self.default_table_name
|
|
@@ -401,9 +309,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
401
309
|
data_dict={"end_timestamp": None})
|
|
402
310
|
# Main select function
|
|
403
311
|
def select_multi_tuple_by_where(
|
|
404
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
405
|
-
where: str = None, params: tuple = None, distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT,
|
|
406
|
-
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:
|
|
407
315
|
"""Selects multiple rows from the table based on a WHERE clause and returns them as a list of tuples."""
|
|
408
316
|
|
|
409
317
|
schema_name = schema_name or self.default_schema_name
|
|
@@ -448,21 +356,22 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
448
356
|
return result
|
|
449
357
|
|
|
450
358
|
def select_multi_dict_by_where(
|
|
451
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
452
|
-
where: str = None, params: tuple = None, distinct: bool = False, group_by: str = None,
|
|
453
|
-
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]:
|
|
454
362
|
"""Selects multiple rows from the table based on a WHERE clause and returns them as a list of dictionaries."""
|
|
455
363
|
result = self.select_multi_tuple_by_where(
|
|
456
364
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
457
365
|
where=where, params=params, distinct=distinct, limit=limit, order_by=order_by)
|
|
458
366
|
result_as_dicts = self.convert_multi_to_dict(result, select_clause_value)
|
|
459
367
|
if group_by:
|
|
460
|
-
|
|
368
|
+
grouped_result = group_list_by_columns(list_of_dicts=result_as_dicts, group_by=group_by)
|
|
369
|
+
return grouped_result
|
|
461
370
|
return result_as_dicts
|
|
462
371
|
|
|
463
372
|
def select_one_tuple_by_where(
|
|
464
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
465
|
-
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:
|
|
466
375
|
"""Selects one row from the table based on a WHERE clause and returns it as a tuple."""
|
|
467
376
|
result = self.select_multi_tuple_by_where(
|
|
468
377
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
@@ -474,18 +383,18 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
474
383
|
return tuple_result
|
|
475
384
|
|
|
476
385
|
def select_one_dict_by_where(
|
|
477
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
478
|
-
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:
|
|
479
388
|
"""Selects one row from the table based on a WHERE clause and returns it as a dictionary."""
|
|
480
|
-
|
|
389
|
+
row = self.select_one_tuple_by_where(
|
|
481
390
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
482
391
|
where=where, params=params, distinct=distinct, order_by=order_by)
|
|
483
|
-
result = self.convert_to_dict(row=
|
|
392
|
+
result = self.convert_to_dict(row=row, select_clause_value=select_clause_value)
|
|
484
393
|
return result
|
|
485
394
|
|
|
486
395
|
def select_one_value_by_where(
|
|
487
|
-
self, *, select_clause_value: str, schema_name: str = None, view_table_name: str = None,
|
|
488
|
-
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,
|
|
489
398
|
skip_null_values: bool = True) -> Any:
|
|
490
399
|
"""Selects one value from the table based on a WHERE clause and returns it."""
|
|
491
400
|
select_clause_value = select_clause_value or self.default_select_clause_value
|
|
@@ -500,9 +409,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
500
409
|
value = None
|
|
501
410
|
return value
|
|
502
411
|
def select_one_tuple_by_column_and_value(
|
|
503
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
504
|
-
column_name: str = None, column_value: Any,
|
|
505
|
-
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:
|
|
506
415
|
"""Selects one row from the table by ID and returns it as a tuple."""
|
|
507
416
|
result = self.select_multi_tuple_by_column_and_value(
|
|
508
417
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
@@ -514,20 +423,20 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
514
423
|
return one_tuple_result
|
|
515
424
|
|
|
516
425
|
def select_one_dict_by_column_and_value(
|
|
517
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
518
|
-
column_name: str = None, column_value: Any,
|
|
519
|
-
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:
|
|
520
429
|
"""Selects one row from the table by ID and returns it as a dictionary (column_name: value)"""
|
|
521
|
-
|
|
430
|
+
row = self.select_one_tuple_by_column_and_value(
|
|
522
431
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
523
432
|
column_name=column_name, column_value=column_value, distinct=distinct, order_by=order_by)
|
|
524
|
-
result = self.convert_to_dict(row=
|
|
433
|
+
result = self.convert_to_dict(row=row, select_clause_value=select_clause_value)
|
|
525
434
|
return result
|
|
526
435
|
|
|
527
436
|
def select_one_value_by_column_and_value(
|
|
528
|
-
self, *, select_clause_value: str = None, schema_name: str = None, view_table_name: str = None,
|
|
529
|
-
column_name: str = None, column_value: Any,
|
|
530
|
-
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:
|
|
531
440
|
"""Selects one value from the table by ID and returns it."""
|
|
532
441
|
|
|
533
442
|
column_name = column_name or self.default_column_name
|
|
@@ -545,9 +454,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
545
454
|
return value
|
|
546
455
|
|
|
547
456
|
def select_multi_tuple_by_column_and_value(
|
|
548
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
549
|
-
column_name: str = None, column_value: Any,
|
|
550
|
-
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:
|
|
551
460
|
"""Selects multiple rows from the table by ID and returns them as a list of tuples.
|
|
552
461
|
If column_value is list / tuple, it will be used as multiple values for the column_name (SQL IN)."""
|
|
553
462
|
|
|
@@ -560,20 +469,21 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
560
469
|
return result
|
|
561
470
|
|
|
562
471
|
def select_multi_dict_by_column_and_value(
|
|
563
|
-
self, *, schema_name: str = None, view_table_name: str = None, select_clause_value: str = None,
|
|
564
|
-
column_name: str = None, column_value: Any,
|
|
565
|
-
distinct: bool = False, limit: int = DEFAULT_SQL_SELECT_LIMIT, order_by: str = None,
|
|
566
|
-
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]:
|
|
567
476
|
"""Selects multiple rows from the table by ID and returns them as a list of dictionaries."""
|
|
568
477
|
result = self.select_multi_tuple_by_column_and_value(
|
|
569
478
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value=select_clause_value,
|
|
570
479
|
column_name=column_name, column_value=column_value, distinct=distinct, limit=limit, order_by=order_by)
|
|
571
480
|
result_as_dicts = self.convert_multi_to_dict(result, select_clause_value)
|
|
572
481
|
if group_by:
|
|
573
|
-
|
|
482
|
+
grouped_result = group_list_by_columns(list_of_dicts=result_as_dicts, group_by=group_by)
|
|
483
|
+
return grouped_result
|
|
574
484
|
return result_as_dicts
|
|
575
|
-
def insert_if_not_exists(self, *, schema_name: str = None, table_name: str = None, data_dict: dict = None,
|
|
576
|
-
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,
|
|
577
487
|
commit_changes: bool = True, compare_with_or: bool = False) -> int:
|
|
578
488
|
"""Inserts a new row into the table if a row with the same values does not exist,
|
|
579
489
|
and returns the id of the new row | None if an error occurred."""
|
|
@@ -584,7 +494,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
584
494
|
self._validate_args(args=locals())
|
|
585
495
|
|
|
586
496
|
# Try to select
|
|
587
|
-
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)
|
|
588
498
|
row_tuple = self.select_one_tuple_by_where(
|
|
589
499
|
schema_name=schema_name, view_table_name=view_table_name, select_clause_value="*",
|
|
590
500
|
where=where_clause, params=params)
|
|
@@ -599,7 +509,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
599
509
|
object={"id": entity_id})
|
|
600
510
|
return entity_id
|
|
601
511
|
|
|
602
|
-
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],
|
|
603
513
|
commit_changes: bool = True) -> int:
|
|
604
514
|
"""Inserts multiple rows into the table.
|
|
605
515
|
data_dicts should be in the following format: [{col1: val1, col2: val2}, {col1: val3, col2: val4}, ...]
|
|
@@ -609,13 +519,13 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
609
519
|
self.logger.warning("GenericCrudPostgresql.insert_many_dicts: data_dicts is empty")
|
|
610
520
|
inserted_rows = 0
|
|
611
521
|
else:
|
|
612
|
-
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]}
|
|
613
523
|
inserted_rows = self.insert_many(schema_name=schema_name, table_name=table_name,
|
|
614
524
|
data_dict=converted_data_dicts, commit_changes=commit_changes)
|
|
615
525
|
|
|
616
526
|
return inserted_rows
|
|
617
527
|
|
|
618
|
-
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],
|
|
619
529
|
commit_changes: bool = True) -> int:
|
|
620
530
|
"""Inserts multiple rows into the table.
|
|
621
531
|
data_dict should be in the following format: {col1: [val1, val2], col2: [val3, val4], ...}
|
|
@@ -648,9 +558,9 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
648
558
|
self.connection.commit()
|
|
649
559
|
inserted_rows = self.cursor.get_affected_row_count()
|
|
650
560
|
return inserted_rows
|
|
651
|
-
def upsert_with_select_clause(self, *, schema_name: str = None, table_name: str = None, view_table_name: str = None,
|
|
652
|
-
data_dict: dict = None, where_compare: str = None, params_compare: tuple = None,
|
|
653
|
-
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,
|
|
654
564
|
select_clause_value: str = "*") -> dict:
|
|
655
565
|
"""
|
|
656
566
|
Inserts a new row into the table if a row with the same values does not exist,
|
|
@@ -667,7 +577,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
667
577
|
view_table_name = view_table_name or self.default_view_table_name
|
|
668
578
|
column_name = generate_id_column_name(table_name)
|
|
669
579
|
self._validate_args(args=locals())
|
|
670
|
-
result_dict = {}
|
|
580
|
+
result_dict: dict = {}
|
|
671
581
|
if not data_dict:
|
|
672
582
|
self.logger.warning(log_message="GenericCrudPostgresql.upsert_with_select_clause: data_dict is empty")
|
|
673
583
|
return result_dict
|
|
@@ -678,7 +588,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
678
588
|
result_dict = data_dict
|
|
679
589
|
return result_dict
|
|
680
590
|
|
|
681
|
-
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,
|
|
682
592
|
where_compare=where_compare, params_compare=params_compare)
|
|
683
593
|
# Add table_id if it's not in select_clause_value
|
|
684
594
|
if select_clause_value != "*" and column_name not in select_clause_value:
|
|
@@ -714,10 +624,10 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
714
624
|
return result_dict
|
|
715
625
|
|
|
716
626
|
# We want upsert to call upsert_with_select_clause, and return only the id
|
|
717
|
-
def upsert(self, *, schema_name: str = None, table_name: str = None, view_table_name: str = None,
|
|
718
|
-
data_dict: dict = None, where_compare: str = None,
|
|
719
|
-
params_compare: tuple = None, data_dict_compare: dict = None,
|
|
720
|
-
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]:
|
|
721
631
|
"""
|
|
722
632
|
Inserts a new row into the table if a row with the same values does not exist,
|
|
723
633
|
the "same values" are extracted from data_dict_compare.
|
|
@@ -736,18 +646,18 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
736
646
|
inserted_id = inserted_id_per_column_dict[column_name]
|
|
737
647
|
return inserted_id
|
|
738
648
|
# Helper methods
|
|
739
|
-
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:
|
|
740
650
|
"""Returns a dictionary of the column names and their values."""
|
|
741
651
|
select_clause_value = select_clause_value or self.default_select_clause_value
|
|
742
652
|
if select_clause_value == "*":
|
|
743
|
-
column_names = self.cursor.column_names()
|
|
653
|
+
column_names: Sequence[str] = self.cursor.column_names()
|
|
744
654
|
else:
|
|
745
655
|
column_names = [x.strip() for x in select_clause_value.split(",")]
|
|
746
656
|
dict_result = dict(zip(column_names, row or tuple()))
|
|
747
657
|
self.logger.debug(object=locals())
|
|
748
658
|
return dict_result
|
|
749
659
|
|
|
750
|
-
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]:
|
|
751
661
|
"""Converts multiple rows to dictionaries."""
|
|
752
662
|
multiple_dict_result = [self.convert_to_dict(row=row, select_clause_value=select_clause_value)
|
|
753
663
|
for row in rows]
|
|
@@ -777,7 +687,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
777
687
|
if message:
|
|
778
688
|
raise Exception(message)
|
|
779
689
|
|
|
780
|
-
def __where_security(self, where: str, view_name: str) -> str:
|
|
690
|
+
def __where_security(self, where: Optional[str], view_name: str) -> Optional[str]:
|
|
781
691
|
"""Adds security to the where clause."""
|
|
782
692
|
if view_name in table_definition:
|
|
783
693
|
if table_definition[view_name].get("is_visibility"):
|
|
@@ -788,8 +698,8 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
788
698
|
return where_security
|
|
789
699
|
return where
|
|
790
700
|
|
|
791
|
-
def __add_create_updated_user_profile_ids(self, data_dict: dict, add_created_user_id: bool = False,
|
|
792
|
-
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:
|
|
793
703
|
"""Adds created_user_id and updated_user_id to data_dict."""
|
|
794
704
|
data_dict = data_dict or {}
|
|
795
705
|
schema_name = schema_name or self.default_schema_name
|
|
@@ -859,7 +769,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
859
769
|
|
|
860
770
|
def __add_identifier(self, data_dict: dict, table_name: str) -> None:
|
|
861
771
|
# If there's an "identifier" column in the table, we want to insert a random identifier
|
|
862
|
-
identifier_entity_type_id =
|
|
772
|
+
identifier_entity_type_id = get_entity_type_by_table_name(table_name)
|
|
863
773
|
if not identifier_entity_type_id:
|
|
864
774
|
return
|
|
865
775
|
identifier = NumberGenerator.get_random_identifier(
|
|
@@ -871,7 +781,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
871
781
|
self.connection.commit()
|
|
872
782
|
|
|
873
783
|
@lru_cache
|
|
874
|
-
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:
|
|
875
785
|
schema_name = schema_name or self.default_schema_name
|
|
876
786
|
table_name = table_name or self.default_table_name
|
|
877
787
|
query = """
|
|
@@ -929,7 +839,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
929
839
|
return where, params
|
|
930
840
|
|
|
931
841
|
@property
|
|
932
|
-
def cursor(self) -> Cursor:
|
|
842
|
+
def cursor(self) -> cursor_module.Cursor:
|
|
933
843
|
"""Get a new cursor"""
|
|
934
844
|
if self._cursor.is_closed():
|
|
935
845
|
self._cursor = self.connection.cursor()
|
|
@@ -937,7 +847,7 @@ class GenericCrudPostgresql(GenericCrudAbstract, metaclass=ABCMetaLogger,
|
|
|
937
847
|
return cursor
|
|
938
848
|
|
|
939
849
|
@cursor.setter
|
|
940
|
-
def cursor(self, value: Cursor) -> None:
|
|
850
|
+
def cursor(self, value: cursor_module.Cursor) -> None:
|
|
941
851
|
"""Set the cursor"""
|
|
942
852
|
self._cursor = value
|
|
943
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
|
|
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.3b4665
|
|
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
|
|
@@ -10,7 +10,7 @@ Classifier: Operating System :: OS Independent
|
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
Requires-Dist: python-sdk-remote
|
|
12
12
|
Requires-Dist: logger-local
|
|
13
|
-
Requires-Dist: psycopg2
|
|
13
|
+
Requires-Dist: psycopg2-binary
|
|
14
14
|
Dynamic: author
|
|
15
15
|
Dynamic: author-email
|
|
16
16
|
Dynamic: classifier
|
{database_postgresql_local-0.1.2.1234 → database_postgresql_local-0.1.3b4665}/pyproject.toml
RENAMED
|
@@ -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.3b4665" # 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.3b4665', # 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",
|
|
@@ -58,6 +58,6 @@ setuptools.setup(
|
|
|
58
58
|
# TODO: in -remote package please use logger-remote instead.
|
|
59
59
|
'logger-local',
|
|
60
60
|
# TODO: In -remote package please delete this line.
|
|
61
|
-
'psycopg2'
|
|
61
|
+
'psycopg2-binary'
|
|
62
62
|
]
|
|
63
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
|