database-postgresql-local 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- database_postgresql_local/__init__.py +1 -0
- database_postgresql_local/connector.py +156 -0
- database_postgresql_local/constants_src.py +36 -0
- database_postgresql_local/cursor.py +142 -0
- database_postgresql_local/generic_crud_postgresql.py +967 -0
- database_postgresql_local/table_columns.py +4 -0
- database_postgresql_local/table_definition.py +4 -0
- database_postgresql_local/utils.py +263 -0
- database_postgresql_local-0.1.0.dist-info/METADATA +24 -0
- database_postgresql_local-0.1.0.dist-info/RECORD +12 -0
- database_postgresql_local-0.1.0.dist-info/WHEEL +5 -0
- database_postgresql_local-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import inspect
|
|
3
|
+
import os
|
|
4
|
+
from functools import lru_cache
|
|
5
|
+
from typing import Any, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
from logger_local.LoggerLocal import Logger
|
|
8
|
+
from logger_local.MetaLogger import module_wrapper
|
|
9
|
+
from python_sdk_remote.utilities import get_environment_name
|
|
10
|
+
from python_sdk_remote.utilities import our_get_env
|
|
11
|
+
from url_remote.environment_name_enum import EnvironmentName
|
|
12
|
+
|
|
13
|
+
from .constants_src import LOGGER_CONNECTOR_CODE_OBJECT
|
|
14
|
+
from .table_columns import table_columns
|
|
15
|
+
from .table_definition import table_definition
|
|
16
|
+
# from .to_sql_interface import ToSQLInterface
|
|
17
|
+
from database_infrastructure_local.to_sql_interface import ToSQLInterface
|
|
18
|
+
|
|
19
|
+
logger = Logger.create_logger(object=LOGGER_CONNECTOR_CODE_OBJECT)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# TODO Convert those methods to class with overloading methods
|
|
23
|
+
def get_sql_hostname() -> str:
|
|
24
|
+
sql_hostname = our_get_env("POSTGRESQL_HOSTNAME")
|
|
25
|
+
return sql_hostname
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_sql_username() -> str:
|
|
29
|
+
sql_username = our_get_env("POSTGRESQL_USERNAME")
|
|
30
|
+
return sql_username
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_sql_password() -> str:
|
|
34
|
+
sql_password = our_get_env("POSTGRESQL_PASSWORD")
|
|
35
|
+
return sql_password
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_sql_port() -> str:
|
|
39
|
+
sql_port = our_get_env("POSTGRES_PORT", default="5432")
|
|
40
|
+
return sql_port
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_ssh_hostname() -> str:
|
|
44
|
+
return our_get_env("SSH_HOSTNAME", raise_if_not_found=False)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_ssh_username() -> str:
|
|
48
|
+
ssh_username = our_get_env("SSH_USERNAME", raise_if_empty=True)
|
|
49
|
+
return ssh_username
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Placeholder for table_columns and table_definition
|
|
53
|
+
# These will be populated from the database schema
|
|
54
|
+
table_columns = {}
|
|
55
|
+
table_definition = {}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def detect_if_is_test_data() -> bool:
|
|
59
|
+
"""Detects if the current environment is a test environment."""
|
|
60
|
+
environment_name = get_environment_name()
|
|
61
|
+
return environment_name != EnvironmentName.PROD1.value
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def generate_id_column_name(table_name: str) -> str:
|
|
65
|
+
"""Generates the ID column name for a table."""
|
|
66
|
+
if table_name.endswith('_table'):
|
|
67
|
+
table_name = table_name[:-6]
|
|
68
|
+
elif table_name.endswith('_view'):
|
|
69
|
+
table_name = table_name[:-5]
|
|
70
|
+
return f"{table_name}_id"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def generate_table_name(schema_name: str) -> str:
|
|
74
|
+
"""Generates the table name for a schema."""
|
|
75
|
+
return f"{schema_name}_table"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def generate_view_name(table_name: str) -> str:
|
|
79
|
+
"""Generates the view name for a table."""
|
|
80
|
+
if table_name.endswith('_table'):
|
|
81
|
+
table_name = table_name[:-6]
|
|
82
|
+
return f"{table_name}_view"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_entity_type_by_table_name(table_name: str) -> int:
|
|
86
|
+
"""Gets the entity type ID for a table."""
|
|
87
|
+
# This would be implemented based on your entity type mapping
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_where_params(column_name: str, column_value: Any) -> tuple:
|
|
92
|
+
"""Generates a WHERE clause and parameters for a column and value."""
|
|
93
|
+
if isinstance(column_value, (list, tuple)):
|
|
94
|
+
placeholders = ', '.join(['%s'] * len(column_value))
|
|
95
|
+
where = f"{column_name} IN ({placeholders})"
|
|
96
|
+
params = tuple(column_value)
|
|
97
|
+
else:
|
|
98
|
+
where = f"{column_name} = %s"
|
|
99
|
+
params = (column_value,)
|
|
100
|
+
return where, params
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def process_insert_data_dict(data_dict: dict) -> tuple:
|
|
104
|
+
"""Processes a dictionary for an INSERT statement."""
|
|
105
|
+
columns = ", ".join(f"\"{key}\"" for key in data_dict)
|
|
106
|
+
values = ", ".join(["%s"] * len(data_dict))
|
|
107
|
+
params = tuple(data_dict.values())
|
|
108
|
+
return columns, values, params
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def process_update_data_dict(data_dict: dict) -> tuple:
|
|
112
|
+
"""Processes a dictionary for an UPDATE statement."""
|
|
113
|
+
set_values = ", ".join(f"\"{key}\" = %s" for key in data_dict)
|
|
114
|
+
params = tuple(data_dict.values())
|
|
115
|
+
return set_values, params
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def process_upsert_data_dict(data_dict: dict, compare_with_or: bool = False,
|
|
119
|
+
where_compare: str = None, params_compare: tuple = None) -> tuple:
|
|
120
|
+
"""Processes a dictionary for an UPSERT statement."""
|
|
121
|
+
if where_compare:
|
|
122
|
+
where = where_compare
|
|
123
|
+
params = params_compare
|
|
124
|
+
else:
|
|
125
|
+
where_parts = []
|
|
126
|
+
params = []
|
|
127
|
+
for key, value in data_dict.items():
|
|
128
|
+
if value is None:
|
|
129
|
+
where_parts.append(f"\"{key}\" IS NULL")
|
|
130
|
+
else:
|
|
131
|
+
where_parts.append(f"\"{key}\" = %s")
|
|
132
|
+
params.append(value)
|
|
133
|
+
connector = " OR " if compare_with_or else " AND "
|
|
134
|
+
where = connector.join(where_parts)
|
|
135
|
+
params = tuple(params)
|
|
136
|
+
return where, params
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def replace_view_with_table(view_table_name: str, select_clause_value: str = None) -> str:
|
|
140
|
+
"""Replaces a view name with a table name."""
|
|
141
|
+
if view_table_name.endswith('_view'):
|
|
142
|
+
return view_table_name[:-5] + '_table'
|
|
143
|
+
return view_table_name
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def validate_none_select_table_name(table_name: str) -> None:
|
|
147
|
+
"""Validates a table name for non-select operations."""
|
|
148
|
+
if not table_name:
|
|
149
|
+
raise ValueError("Table name cannot be empty")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def validate_select_table_name(view_table_name: str, is_ignore_duplicate: bool = False) -> None:
|
|
153
|
+
"""Validates a table name for select operations."""
|
|
154
|
+
if not view_table_name:
|
|
155
|
+
raise ValueError("View table name cannot be empty")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def validate_single_clause_value(select_clause_value: str) -> None:
|
|
159
|
+
"""Validates that a SELECT clause has only one value."""
|
|
160
|
+
if ',' in select_clause_value:
|
|
161
|
+
raise ValueError(f"Expected a single column, got: {select_clause_value}")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def where_skip_null_values(where: str, select_clause_value: str, skip_null_values: bool) -> str:
|
|
165
|
+
"""Adds a condition to skip NULL values in a WHERE clause."""
|
|
166
|
+
if skip_null_values:
|
|
167
|
+
null_condition = f"{select_clause_value} IS NOT NULL"
|
|
168
|
+
if where:
|
|
169
|
+
where = f"({where}) AND {null_condition}"
|
|
170
|
+
else:
|
|
171
|
+
where = null_condition
|
|
172
|
+
return where
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def insert_is_undelete(table_name: str) -> bool:
|
|
176
|
+
"""Checks if an insert operation should undelete a record."""
|
|
177
|
+
# This would be implemented based on your table configuration
|
|
178
|
+
return False
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def is_column_in_table(table_name: str, column_name: str) -> bool:
|
|
182
|
+
"""Checks if a column exists in a table."""
|
|
183
|
+
if table_name in table_columns:
|
|
184
|
+
return column_name in table_columns[table_name]
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def is_end_timestamp_in_table(table_name: str) -> bool:
|
|
189
|
+
"""Checks if a table has an end_timestamp column."""
|
|
190
|
+
return is_column_in_table(table_name, "end_timestamp")
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_table_columns(table_name: str) -> list:
|
|
194
|
+
"""Gets the columns for a table."""
|
|
195
|
+
if table_name in table_columns:
|
|
196
|
+
return table_columns[table_name]
|
|
197
|
+
return []
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def group_list_by_columns(list_of_dicts: list, group_by: str) -> dict:
|
|
201
|
+
"""Groups a list of dictionaries by specified columns."""
|
|
202
|
+
result = {}
|
|
203
|
+
group_by_columns = [col.strip() for col in group_by.split(',')]
|
|
204
|
+
|
|
205
|
+
for item in list_of_dicts:
|
|
206
|
+
key = tuple(item.get(col) for col in group_by_columns)
|
|
207
|
+
if len(group_by_columns) == 1:
|
|
208
|
+
key = key[0] # If only one column, use the value directly as key
|
|
209
|
+
|
|
210
|
+
if key not in result:
|
|
211
|
+
result[key] = []
|
|
212
|
+
result[key].append(item)
|
|
213
|
+
|
|
214
|
+
return result
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def process_select_data_dict(data_dict: dict) -> tuple:
|
|
218
|
+
"""Processes a dictionary for a SELECT statement."""
|
|
219
|
+
where_parts = []
|
|
220
|
+
params = []
|
|
221
|
+
for key, value in data_dict.items():
|
|
222
|
+
if value is None:
|
|
223
|
+
where_parts.append(f"\"{key}\" IS NULL")
|
|
224
|
+
else:
|
|
225
|
+
where_parts.append(f"\"{key}\" = %s")
|
|
226
|
+
params.append(value)
|
|
227
|
+
where = " AND ".join(where_parts)
|
|
228
|
+
params = tuple(params)
|
|
229
|
+
return where, params
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def generate_where_clause_for_ignore_duplicate(data_dict: dict, constraint_columns: list) -> tuple:
|
|
233
|
+
"""Generates a WHERE clause for checking duplicates."""
|
|
234
|
+
for columns in constraint_columns:
|
|
235
|
+
where_parts = []
|
|
236
|
+
params = []
|
|
237
|
+
valid = True
|
|
238
|
+
for column in columns:
|
|
239
|
+
if column in data_dict:
|
|
240
|
+
value = data_dict[column]
|
|
241
|
+
if value is None:
|
|
242
|
+
where_parts.append(f"\"{column}\" IS NULL")
|
|
243
|
+
else:
|
|
244
|
+
where_parts.append(f"\"{column}\" = %s")
|
|
245
|
+
params.append(value)
|
|
246
|
+
else:
|
|
247
|
+
valid = False
|
|
248
|
+
break
|
|
249
|
+
if valid and where_parts:
|
|
250
|
+
where = " AND ".join(where_parts)
|
|
251
|
+
params = tuple(params)
|
|
252
|
+
return where, params
|
|
253
|
+
return None, None
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def fix_select_clause_value(select_clause_value: str) -> str:
|
|
257
|
+
"""Fixes a SELECT clause value."""
|
|
258
|
+
return select_clause_value
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def fix_where_clause_value(where_clause_value: str) -> str:
|
|
262
|
+
"""Fixes a WHERE clause value."""
|
|
263
|
+
return where_clause_value
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: database-postgresql-local
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: PyPI Package for Circles database-postgresql-local Python
|
|
5
|
+
Home-page: https://github.com/circles-zone/database-postgresql-local-python-package
|
|
6
|
+
Author: Circles
|
|
7
|
+
Author-email: info@circlez.ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: logger-local
|
|
12
|
+
Requires-Dist: database-sql-local
|
|
13
|
+
Requires-Dist: python-sdk-remote
|
|
14
|
+
Requires-Dist: psycopg2
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: requires-dist
|
|
22
|
+
Dynamic: summary
|
|
23
|
+
|
|
24
|
+
PyPI Package for Circles database-postgresql-local Python
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
database_postgresql_local/__init__.py,sha256=zoclCN8mUJrL26mZ4J-xYIJUpU85MxDq5Eq8E4LcJ-8,35
|
|
2
|
+
database_postgresql_local/connector.py,sha256=p3Iu0-3TQXg8OQCO5_D_tEc4fthfwsmgFebSCnwhUE0,6416
|
|
3
|
+
database_postgresql_local/constants_src.py,sha256=oa2RK1CG7bFE0Lt5USVfSR_4OAF33vdYtNu6EoWQmlg,1619
|
|
4
|
+
database_postgresql_local/cursor.py,sha256=po4GPXo4V4zGjLFrp00psPQ45wAiXfo0gYSt4IatMYo,5152
|
|
5
|
+
database_postgresql_local/generic_crud_postgresql.py,sha256=M7k7FFNa6j43OfbfQ2BzDDrjkpvz4vKDLT338L1URoU,52319
|
|
6
|
+
database_postgresql_local/table_columns.py,sha256=wOedYTaOU3mPDP-8ooVbsFJbad_QDyi8x4HdHTSryDs,101
|
|
7
|
+
database_postgresql_local/table_definition.py,sha256=i_sEO31Ataj5KcfFAHoEc1oplPX_KYpIEX5qdg0OJ0I,108
|
|
8
|
+
database_postgresql_local/utils.py,sha256=By9b24rP7sFws8m7A4JY-WsjiE6jJGQ8QIeusrmAR9k,8629
|
|
9
|
+
database_postgresql_local-0.1.0.dist-info/METADATA,sha256=-38dZDA3-zY0XkyFZZ6TZQ4AWhDrGzK-fchuUSWMaYs,751
|
|
10
|
+
database_postgresql_local-0.1.0.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
|
11
|
+
database_postgresql_local-0.1.0.dist-info/top_level.txt,sha256=-fQwEAJMMDqJZ5-k9liyhoNXbj52QwRiB02paws2fu4,26
|
|
12
|
+
database_postgresql_local-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
database_postgresql_local
|