database-wrapper-sqlite 0.2.16__py3-none-any.whl → 0.2.23__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.
@@ -9,7 +9,8 @@ Part of the database_wrapper package
9
9
  import logging
10
10
 
11
11
  # from .db_wrapper_sqlite import DBWrapperSqlite
12
- from .connector import Sqlite, SqliteConfig
12
+ from .connector import Sqlite, SqliteConfig, SqliteTypedDictCursor
13
+ from .db_wrapper_sqlite import DBWrapperSqlite
13
14
 
14
15
  # Set the logger to a quiet default, can be enabled if needed
15
16
  logger = logging.getLogger("database_wrapper_sqlite")
@@ -18,7 +19,12 @@ if logger.level == logging.NOTSET:
18
19
 
19
20
 
20
21
  __all__ = [
21
- # "DBWrapperSqlite",
22
- "SqliteConfig",
23
- "Sqlite",
22
+ # Wrappers
23
+ DBWrapperSqlite,
24
+ # Connectors
25
+ Sqlite,
26
+ # Connection and Cursor types
27
+ SqliteTypedDictCursor,
28
+ # Helpers
29
+ SqliteConfig,
24
30
  ]
@@ -1,48 +1,99 @@
1
- from typing import Any, NotRequired, TypedDict
1
+ import sqlite3
2
+ from typing import Any, NotRequired, TypedDict, cast
2
3
 
3
4
  from database_wrapper import DatabaseBackend
4
5
 
5
6
 
7
+ def dict_factory(cursor: sqlite3.Cursor, row: tuple) -> dict[str, Any]:
8
+ fields = [col[0] for col in cursor.description]
9
+ return dict(zip(fields, row, strict=False))
10
+
11
+
6
12
  class SqliteConfig(TypedDict):
7
13
  database: str
14
+ timeout: NotRequired[float]
15
+ isolation_level: NotRequired[str | None]
8
16
  kwargs: NotRequired[dict[str, Any]]
9
17
 
10
18
 
11
- # TODO: Needs to finish the implementation
12
- class Sqlite(DatabaseBackend):
19
+ class SqliteTypedDictCursor(sqlite3.Cursor):
13
20
  """
14
- Sqlite database backend
21
+ Type hint wrapper only. At runtime, this is just a sqlite3.Cursor
22
+ that happens to produce dicts because of the row_factory.
23
+ """
24
+
25
+ def fetchone(self) -> dict[str, Any] | None:
26
+ return super().fetchone() # type: ignore
15
27
 
16
- :param config: Configuration for Sqlite
17
- :type config: MyConfig
28
+ def fetchall(self) -> list[dict[str, Any]]:
29
+ return super().fetchall() # type: ignore
18
30
 
19
- Defaults:
20
- _no defaults_
31
+ def __iter__(self) -> "SqliteTypedDictCursor":
32
+ return self
33
+
34
+ def __next__(self) -> dict[str, Any]:
35
+ return super().__next__() # type: ignore
36
+
37
+
38
+ class Sqlite(DatabaseBackend):
39
+ """
40
+ SQLite database backend
41
+
42
+ :param config: Configuration for SQLite
43
+ :type config: SqliteConfig
21
44
  """
22
45
 
23
46
  config: SqliteConfig
47
+ connection: sqlite3.Connection
48
+ cursor: SqliteTypedDictCursor
24
49
 
25
- connection: Any
26
- cursor: Any
50
+ ##################
51
+ ### Connection ###
52
+ ##################
27
53
 
28
54
  def open(self) -> None:
29
- # Free resources
30
- if hasattr(self, "connection") and self.connection:
31
- self.close()
55
+ self.logger.debug("Connecting to DB")
32
56
 
33
- # Set defaults
34
- if "kwargs" not in self.config or not self.config["kwargs"]:
57
+ if "kwargs" not in self.config:
35
58
  self.config["kwargs"] = {}
36
59
 
37
- self.logger.debug("Connecting to DB")
60
+ # Default timeout to 5.0 seconds if not specified
61
+ timeout = self.config.get("timeout", 5.0)
38
62
 
39
- raise NotImplementedError(
40
- "Sqlite is not yet implemented. See here: https://github.com/gintsmurans/py_database_wrapper/"
63
+ # Default isolation_level to None (autocommit mode via library, though SQLite is tricky with this)
64
+ # or leave as default. Let's respect config or default to standard.
65
+ isolation_level = self.config.get("isolation_level", None)
66
+
67
+ self.connection = sqlite3.connect(
68
+ self.config["database"],
69
+ timeout=timeout,
70
+ isolation_level=isolation_level,
71
+ **self.config["kwargs"],
41
72
  )
42
73
 
74
+ # Set row factory to return dicts
75
+ self.connection.row_factory = dict_factory
76
+
77
+ # Create cursor
78
+ self.cursor = cast(SqliteTypedDictCursor, self.connection.cursor())
79
+
80
+ def ping(self) -> bool:
81
+ try:
82
+ self.cursor.execute("SELECT 1")
83
+ self.cursor.fetchone()
84
+ except Exception as e:
85
+ self.logger.debug(f"Error while pinging the database: {e}")
86
+ return False
87
+
88
+ return True
89
+
90
+ ############
91
+ ### Data ###
92
+ ############
93
+
43
94
  def last_insert_id(self) -> int:
44
95
  assert self.cursor, "Cursor is not initialized"
45
- return self.cursor.lastrowid
96
+ return self.cursor.lastrowid or 0
46
97
 
47
98
  def affected_rows(self) -> int:
48
99
  assert self.cursor, "Cursor is not initialized"
@@ -52,12 +103,12 @@ class Sqlite(DatabaseBackend):
52
103
  """Commit DB queries"""
53
104
  assert self.connection, "Connection is not initialized"
54
105
 
55
- self.logger.debug("Commit DB queries..")
106
+ self.logger.debug("Commit DB queries")
56
107
  self.connection.commit()
57
108
 
58
109
  def rollback(self) -> None:
59
110
  """Rollback DB queries"""
60
111
  assert self.connection, "Connection is not initialized"
61
112
 
62
- self.logger.debug("Rollback DB queries..")
113
+ self.logger.debug("Rollback DB queries")
63
114
  self.connection.rollback()
@@ -0,0 +1,76 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ from database_wrapper import DBWrapper
5
+
6
+ from .connector import SqliteTypedDictCursor
7
+
8
+
9
+ class DBWrapperSqlite(DBWrapper):
10
+ """Wrapper for SQLite database"""
11
+
12
+ db_cursor: SqliteTypedDictCursor | None
13
+ """ SQLite cursor object """
14
+
15
+ #######################
16
+ ### Class lifecycle ###
17
+ #######################
18
+
19
+ # Meta methods
20
+ # We are overriding the __init__ method for the type hinting
21
+ def __init__(
22
+ self,
23
+ db_cursor: SqliteTypedDictCursor | None = None,
24
+ logger: logging.Logger | None = None,
25
+ ):
26
+ """
27
+ Initializes a new instance of the DBWrapper class.
28
+
29
+ Args:
30
+ db_cursor (SqliteTypedDictCursor): The SQLite database cursor object.
31
+ logger (logging.Logger, optional): The logger object. Defaults to None.
32
+ """
33
+ super().__init__(db_cursor, logger)
34
+
35
+ ###############
36
+ ### Setters ###
37
+ ###############
38
+
39
+ def set_db_cursor(self, db_cursor: SqliteTypedDictCursor | None) -> None:
40
+ """
41
+ Updates the database cursor object.
42
+
43
+ Args:
44
+ db_cursor (SqliteTypedDictCursor): The new database cursor object.
45
+ """
46
+ super().set_db_cursor(db_cursor)
47
+
48
+ ######################
49
+ ### Helper methods ###
50
+ ######################
51
+
52
+ def log_query(
53
+ self,
54
+ cursor: SqliteTypedDictCursor,
55
+ query: Any,
56
+ params: tuple[Any, ...],
57
+ ) -> None:
58
+ """
59
+ Logs the given query and parameters.
60
+
61
+ Args:
62
+ cursor (SqliteTypedDictCursor): The cursor used to execute the query.
63
+ query (Any): The query to log.
64
+ params (tuple[Any, ...]): The parameters to log.
65
+ """
66
+ # sqlite3 does not support mogrify, so we just log query and params
67
+ logging.getLogger().debug(f"Query: {query} with params: {params}")
68
+
69
+ #####################
70
+ ### Query methods ###
71
+ #####################
72
+
73
+ def limit_query(self, offset: int = 0, limit: int = 100) -> str | None:
74
+ if limit == 0:
75
+ return None
76
+ return f"LIMIT {limit} OFFSET {offset}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: database_wrapper_sqlite
3
- Version: 0.2.16
3
+ Version: 0.2.23
4
4
  Summary: database_wrapper for PostgreSQL database
5
5
  Author-email: Gints Murans <gm@gm.lv>
6
6
  License: GNU General Public License v3.0 (GPL-3.0)
@@ -32,7 +32,7 @@ Classifier: Topic :: Software Development
32
32
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
33
33
  Requires-Python: >=3.8
34
34
  Description-Content-Type: text/markdown
35
- Requires-Dist: database_wrapper==0.2.16
35
+ Requires-Dist: database_wrapper==0.2.23
36
36
 
37
37
  # database_wrapper_sqlite
38
38
 
@@ -0,0 +1,8 @@
1
+ database_wrapper_sqlite/__init__.py,sha256=YzrxZ4CaMD_OQqQMYjMtMZzzC7MR5D9MXmahTMjTVhI,678
2
+ database_wrapper_sqlite/connector.py,sha256=pZX3vYO1HLjAYAjxdy1PJb0zFa8vQN5tnT1NAP3ZEXM,3256
3
+ database_wrapper_sqlite/db_wrapper_sqlite.py,sha256=CvB-qZYTGr2r6cIbDtbH-tiUrM5U6Vw6mFI5IU57okU,2133
4
+ database_wrapper_sqlite/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ database_wrapper_sqlite-0.2.23.dist-info/METADATA,sha256=eAb2vMdKTk6-wJzTK6ZOq_w9CHQ70PWfieRJnKrpOqQ,2823
6
+ database_wrapper_sqlite-0.2.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ database_wrapper_sqlite-0.2.23.dist-info/top_level.txt,sha256=53mm8n6modSF012UMCHllRLbCLajpC0uDwHE0WU1Lxo,24
8
+ database_wrapper_sqlite-0.2.23.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- database_wrapper_sqlite/__init__.py,sha256=MNI7MORv3RmKZ-W3keehfa2fw_WpGrCOb2tZ99KNrJ4,509
2
- database_wrapper_sqlite/connector.py,sha256=kZtVpBLtdCof5Pjj8fS8EMp0R_z-NQo_EV2kH_crRa0,1635
3
- database_wrapper_sqlite/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- database_wrapper_sqlite-0.2.16.dist-info/METADATA,sha256=YlpAZYkQ8-_OAZ4Zs__PaBEbrTzCHC1Xiw6lROJ9J7k,2823
5
- database_wrapper_sqlite-0.2.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
- database_wrapper_sqlite-0.2.16.dist-info/top_level.txt,sha256=53mm8n6modSF012UMCHllRLbCLajpC0uDwHE0WU1Lxo,24
7
- database_wrapper_sqlite-0.2.16.dist-info/RECORD,,