dbhydra 2.2.6__tar.gz → 2.2.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {dbhydra-2.2.6 → dbhydra-2.2.9}/PKG-INFO +1 -1
  2. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/dbhydra_core.py +3 -0
  3. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/abstract_db.py +1 -0
  4. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/abstract_table.py +14 -16
  5. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/mysql_db.py +2 -1
  6. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/tables.py +15 -3
  7. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/xlsx_db.py +2 -1
  8. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra.egg-info/PKG-INFO +1 -1
  9. {dbhydra-2.2.6 → dbhydra-2.2.9}/setup.py +1 -1
  10. {dbhydra-2.2.6 → dbhydra-2.2.9}/LICENSE +0 -0
  11. {dbhydra-2.2.6 → dbhydra-2.2.9}/README.md +0 -0
  12. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/__init__.py +0 -0
  13. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/__init__.py +0 -0
  14. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/bigquery_db.py +0 -0
  15. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/errors/__init__.py +0 -0
  16. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/errors/exceptions.py +0 -0
  17. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/migrator.py +0 -0
  18. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/mongo_db.py +0 -0
  19. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/postgres_db.py +0 -0
  20. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/src/sqlserver_db.py +0 -0
  21. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/test_migrator.py +0 -0
  22. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/tests/__init__.py +0 -0
  23. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/tests/test_cases.py +0 -0
  24. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/tests/test_mongo.py +0 -0
  25. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra/tests/test_sql.py +0 -0
  26. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra.egg-info/SOURCES.txt +0 -0
  27. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra.egg-info/dependency_links.txt +0 -0
  28. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra.egg-info/requires.txt +0 -0
  29. {dbhydra-2.2.6 → dbhydra-2.2.9}/dbhydra.egg-info/top_level.txt +0 -0
  30. {dbhydra-2.2.6 → dbhydra-2.2.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbhydra
3
- Version: 2.2.6
3
+ Version: 2.2.9
4
4
  Summary: Data science friendly ORM combining Python
5
5
  Home-page: https://github.com/DovaX/dbhydra
6
6
  Author: DovaX
@@ -22,6 +22,9 @@ class Jsonable(str):
22
22
  """Is used as type in python_database_type_mapping"""
23
23
  pass
24
24
 
25
+ class Blob(str):
26
+ """Store BLOBs up to 16MB."""
27
+ pass
25
28
 
26
29
 
27
30
  # dataframe - dictionary auxiliary functions
@@ -58,6 +58,7 @@ class AbstractDb(abc.ABC):
58
58
  'Union': 'object',
59
59
  'Optional': 'object',
60
60
  'Jsonable': 'Jsonable',
61
+ 'Blob': 'Blob',
61
62
  # 'FrozenSet': frozenset,
62
63
  # 'Deque': list,
63
64
  # 'Any': object,
@@ -259,16 +259,19 @@ class AbstractTable(AbstractJoinable, abc.ABC):
259
259
 
260
260
 
261
261
  def drop(self, debug_mode = False):
262
- query = "DROP TABLE " + self.name
262
+ quote = self.db1.identifier_quote
263
+ query = f"DROP TABLE {quote}{self.name}{quote}"
263
264
  if debug_mode:
264
265
  print(query)
265
266
  self.execute(query)
266
267
 
267
268
  def update(self, variable_assign, where=None, debug_mode = False):
269
+ quote = self.db1.identifier_quote
268
270
  if where is None:
269
- query = "UPDATE " + self.name + " SET " + variable_assign
271
+ query = f"UPDATE {quote}{self.name}{quote} SET {quote}{variable_assign}{quote}"
270
272
  else:
271
- query = "UPDATE " + self.name + " SET " + variable_assign + " WHERE " + where
273
+ query = f"UPDATE {quote}{self.name}{quote} SET {quote}{variable_assign}{quote} WHERE {quote}{where}{quote}"
274
+
272
275
  if debug_mode:
273
276
  print(query)
274
277
  return self.execute(query)
@@ -303,25 +306,25 @@ class AbstractTable(AbstractJoinable, abc.ABC):
303
306
  for column_name, column_type in types_without_id_column
304
307
  ]
305
308
 
309
+ quote = self.db1.identifier_quote
306
310
  column_value_string = ""
307
311
  for column_name, cell_value, column_type in update_df_row_list:
308
312
  if cell_value is None:
309
- column_value_string += f"{column_name} = NULL, "
313
+ column_value_string += f"{quote}{column_name}{quote} = NULL, "
310
314
  elif column_type in ["double", "int", "tinyint"]:
311
- column_value_string += f"{column_name} = {cell_value}, "
315
+ column_value_string += f"{quote}{column_name}{quote} = {cell_value}, "
312
316
  elif "varchar" in column_type:
313
- column_value_string += f"{column_name} = '{cell_value}', "
317
+ column_value_string += f"{quote}{column_name}{quote} = '{cell_value}', "
314
318
  elif column_type in ["json", "text", "mediumtext", "longtext", "datetime"]:
315
- column_value_string += f"{column_name} = '{cell_value}', "
319
+ column_value_string += f"{quote}{column_name}{quote} = '{cell_value}', "
316
320
  else:
317
321
  raise AttributeError(f"Unknown column type '{column_type}'")
318
322
 
319
323
  column_value_string = column_value_string.rstrip(", ")
320
- quote = self.db1.identifier_quote
321
324
  sql_query = f"UPDATE {quote}{self.name}{quote} SET {column_value_string}"
322
325
 
323
326
  if where_column is not None and where_value is not None:
324
- sql_query += f" WHERE {where_column} = {where_value};"
327
+ sql_query += f" WHERE {quote}{where_column}{quote} = {where_value};"
325
328
  else:
326
329
  sql_query += ";"
327
330
  if debug_mode:
@@ -382,7 +385,7 @@ class AbstractTable(AbstractJoinable, abc.ABC):
382
385
  inserted_columns=list(dict.fromkeys(self.columns)) #DEDUPLICATION preserving order -> better than inserted_columns = set(self.columns)
383
386
  id_index=inserted_columns.index(self.id_column_name)
384
387
  inserted_columns.pop(id_index)
385
- print(inserted_columns,df.columns)
388
+ # print(inserted_columns,df.columns)
386
389
 
387
390
  assert set(df.columns) == set(inserted_columns) #elements are matchin
388
391
  #df = df[inserted_columns]
@@ -429,12 +432,7 @@ class AbstractTable(AbstractJoinable, abc.ABC):
429
432
  quote = self.db1.identifier_quote
430
433
 
431
434
  if where is None:
432
- query = "DELETE FROM {quote}{self.name}{quote}"
435
+ query = f"DELETE FROM {quote}{self.name}{quote}"
433
436
  else:
434
437
  query = f"DELETE FROM {quote}{self.name}{quote} WHERE {where}"
435
438
  return self.execute(query)
436
-
437
-
438
-
439
-
440
-
@@ -19,7 +19,8 @@ class MysqlDb(AbstractDb):
19
19
  'dict': "nvarchar(2047)",
20
20
  'bool': "tinyint",
21
21
  'datetime': "datetime",
22
- 'Jsonable': "json"
22
+ 'Jsonable': "json",
23
+ 'Blob': "mediumblob",
23
24
  }
24
25
 
25
26
  def __init__(self, *args, **kwargs):
@@ -5,9 +5,8 @@ import abc
5
5
  import time
6
6
  #xlsx imports
7
7
  import pathlib
8
-
9
8
  from dbhydra.src.abstract_table import AbstractTable, AbstractSelectable, AbstractJoinable
10
-
9
+ import binascii
11
10
 
12
11
  MONGO_OPERATOR_DICT = {"=": "$eq", ">": "$gt", ">=": "$gte", " IN ": "$in", "<": "$lt", "<=": "$lte", "<>": "$ne"}
13
12
 
@@ -807,7 +806,10 @@ class MysqlTable(AbstractTable):
807
806
  query += "'" + str(rows[k][j]) + "',"
808
807
  elif "json" in self.types[j + start_index]:
809
808
  query += f"'{rows[k][j]}', "
810
-
809
+ elif 'blob' in self.types[j + start_index]:
810
+ # Convert to hex to allow insertion into SQL query
811
+ hex_data = binascii.hexlify(rows[k][j]).decode('ascii')
812
+ query += f"UNHEX('{hex_data}'), "
811
813
 
812
814
  else:
813
815
  query += str(rows[k][j]) + ","
@@ -903,6 +905,11 @@ class XlsxTable(AbstractTable):
903
905
  self.table_directory_path: pathlib.Path = self.db1.db_directory_path / table_filename
904
906
 
905
907
  def _save_table(self, df: pd.DataFrame):
908
+ blob_columns = [
909
+ column for column, type_ in self.column_type_dict.items() if type_ == "Blob"
910
+ ]
911
+ df[blob_columns] = df[blob_columns].map(lambda x: x.hex() if x is not None else None)
912
+
906
913
  if self.db1.is_csv:
907
914
  df.to_csv(self.table_directory_path, index=False)
908
915
  else:
@@ -960,6 +967,9 @@ class XlsxTable(AbstractTable):
960
967
  date_columns = [
961
968
  column for column, type_ in self.column_type_dict.items() if type_ == "datetime"
962
969
  ]
970
+ blob_columns = [
971
+ column for column, type_ in self.column_type_dict.items() if type_ == "Blob"
972
+ ]
963
973
 
964
974
  # BUG: If XlsxTable is being accessed by multiple threads, read operation
965
975
  # might fail due to race conditions. Add retry mechanism to handle these cases.
@@ -974,6 +984,8 @@ class XlsxTable(AbstractTable):
974
984
  else:
975
985
  print(f"Failed to read data from {self.table_directory_path}, returning empty DataFrame")
976
986
  df = pd.DataFrame(columns=self.columns)
987
+
988
+ df[blob_columns] = df[blob_columns].map(lambda x: bytes.fromhex(x) if x else None)
977
989
  return df
978
990
 
979
991
  def _select(self, column_type_map, date_columns):
@@ -41,7 +41,8 @@ class XlsxDb(AbstractDb):
41
41
  'dict': "str",
42
42
  'bool': "bool",
43
43
  'datetime': "datetime",
44
- 'Jsonable': "str"
44
+ 'Jsonable': "str",
45
+ 'Blob': "Blob"
45
46
  }
46
47
 
47
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbhydra
3
- Version: 2.2.6
3
+ Version: 2.2.9
4
4
  Summary: Data science friendly ORM combining Python
5
5
  Home-page: https://github.com/DovaX/dbhydra
6
6
  Author: DovaX
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name='dbhydra',
8
- version='2.2.6',
8
+ version='2.2.9',
9
9
  author='DovaX',
10
10
  author_email='dovax.ai@gmail.com',
11
11
  description='Data science friendly ORM combining Python',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes