sqliter-py 0.1.1__py3-none-any.whl → 0.3.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.
sqliter/sqliter.py CHANGED
@@ -27,9 +27,24 @@ if TYPE_CHECKING: # pragma: no cover
27
27
  class SqliterDB:
28
28
  """Class to manage SQLite database interactions."""
29
29
 
30
- def __init__(self, db_filename: str, *, auto_commit: bool = False) -> None:
30
+ def __init__(
31
+ self,
32
+ db_filename: Optional[str] = None,
33
+ *,
34
+ memory: bool = False,
35
+ auto_commit: bool = True,
36
+ ) -> None:
31
37
  """Initialize the class and options."""
32
- self.db_filename = db_filename
38
+ if memory:
39
+ self.db_filename = ":memory:"
40
+ elif db_filename:
41
+ self.db_filename = db_filename
42
+ else:
43
+ err = (
44
+ "Database name must be provided if not using an in-memory "
45
+ "database."
46
+ )
47
+ raise ValueError(err)
33
48
  self.auto_commit = auto_commit
34
49
  self.conn: Optional[sqlite3.Connection] = None
35
50
 
@@ -42,17 +57,29 @@ class SqliterDB:
42
57
  raise DatabaseConnectionError(self.db_filename) from exc
43
58
  return self.conn
44
59
 
60
+ def close(self) -> None:
61
+ """Close the connection to the SQLite database."""
62
+ if self.conn:
63
+ self._maybe_commit()
64
+ self.conn.close()
65
+ self.conn = None
66
+
67
+ def commit(self) -> None:
68
+ """Commit any pending transactions."""
69
+ if self.conn:
70
+ self.conn.commit()
71
+
45
72
  def create_table(self, model_class: type[BaseDBModel]) -> None:
46
73
  """Create a table based on the Pydantic model."""
47
74
  table_name = model_class.get_table_name()
48
75
  primary_key = model_class.get_primary_key()
49
- create_id = model_class.should_create_id()
76
+ create_pk = model_class.should_create_pk()
50
77
 
51
78
  fields = ", ".join(
52
79
  f"{field_name} TEXT" for field_name in model_class.model_fields
53
80
  )
54
81
 
55
- if create_id:
82
+ if create_pk:
56
83
  create_table_sql = f"""
57
84
  CREATE TABLE IF NOT EXISTS {table_name} (
58
85
  {primary_key} INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -75,32 +102,33 @@ class SqliterDB:
75
102
  except sqlite3.Error as exc:
76
103
  raise TableCreationError(table_name) from exc
77
104
 
78
- def _maybe_commit(self, conn: sqlite3.Connection) -> None:
105
+ def _maybe_commit(self) -> None:
79
106
  """Commit changes if auto_commit is True."""
80
- if self.auto_commit:
81
- conn.commit()
107
+ if self.auto_commit and self.conn:
108
+ self.conn.commit()
82
109
 
83
110
  def insert(self, model_instance: BaseDBModel) -> None:
84
111
  """Insert a new record into the table defined by the Pydantic model."""
85
112
  model_class = type(model_instance)
86
113
  table_name = model_class.get_table_name()
87
114
 
88
- fields = ", ".join(model_class.model_fields)
89
- placeholders = ", ".join(["?"] * len(model_class.model_fields))
90
- values = tuple(
91
- getattr(model_instance, field) for field in model_class.model_fields
115
+ data = model_instance.model_dump()
116
+ fields = ", ".join(data.keys())
117
+ placeholders = ", ".join(
118
+ ["?" if value is not None else "NULL" for value in data.values()]
92
119
  )
120
+ values = tuple(value for value in data.values() if value is not None)
93
121
 
94
122
  insert_sql = f"""
95
123
  INSERT INTO {table_name} ({fields})
96
124
  VALUES ({placeholders})
97
- """ # noqa: S608
125
+ """ # noqa: S608
98
126
 
99
127
  try:
100
128
  with self.connect() as conn:
101
129
  cursor = conn.cursor()
102
130
  cursor.execute(insert_sql, values)
103
- self._maybe_commit(conn)
131
+ self._maybe_commit()
104
132
  except sqlite3.Error as exc:
105
133
  raise RecordInsertionError(table_name) from exc
106
134
 
@@ -167,7 +195,7 @@ class SqliterDB:
167
195
  if cursor.rowcount == 0:
168
196
  raise RecordNotFoundError(primary_key_value)
169
197
 
170
- self._maybe_commit(conn)
198
+ self._maybe_commit()
171
199
 
172
200
  except sqlite3.Error as exc:
173
201
  raise RecordUpdateError(table_name) from exc
@@ -190,13 +218,36 @@ class SqliterDB:
190
218
 
191
219
  if cursor.rowcount == 0:
192
220
  raise RecordNotFoundError(primary_key_value)
193
- self._maybe_commit(conn)
221
+ self._maybe_commit()
194
222
  except sqlite3.Error as exc:
195
223
  raise RecordDeletionError(table_name) from exc
196
224
 
197
- def select(self, model_class: type[BaseDBModel]) -> QueryBuilder:
198
- """Start a query for the given model."""
199
- return QueryBuilder(self, model_class)
225
+ def select(
226
+ self,
227
+ model_class: type[BaseDBModel],
228
+ fields: Optional[list[str]] = None,
229
+ exclude: Optional[list[str]] = None,
230
+ ) -> QueryBuilder:
231
+ """Start a query for the given model.
232
+
233
+ Args:
234
+ model_class: The model class to query.
235
+ fields: Optional list of field names to select. If None, all fields
236
+ are selected.
237
+ exclude: Optional list of field names to exclude from the query
238
+ output.
239
+
240
+ Returns:
241
+ QueryBuilder: An instance of QueryBuilder for the given model and
242
+ fields.
243
+ """
244
+ query_builder = QueryBuilder(self, model_class, fields)
245
+
246
+ # If exclude is provided, apply the exclude method
247
+ if exclude:
248
+ query_builder.exclude(exclude)
249
+
250
+ return query_builder
200
251
 
201
252
  # --- Context manager methods ---
202
253
  def __enter__(self) -> Self:
@@ -216,7 +267,8 @@ class SqliterDB:
216
267
  if exc_type:
217
268
  # Roll back the transaction if there was an exception
218
269
  self.conn.rollback()
219
- self._maybe_commit(self.conn)
270
+ else:
271
+ self.conn.commit()
220
272
  finally:
221
273
  # Close the connection and reset the instance variable
222
274
  self.conn.close()