sqlengine-lite 2.2.1__py3-none-any.whl → 2.2.2__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.
- sqlengine/_internal/connection_manager.py +10 -7
- sqlengine/_internal/statements.py +24 -15
- sqlengine/schema.py +2 -8
- sqlengine/sqltable.py +7 -7
- sqlengine/utils/connection.py +1 -1
- sqlengine/utils/convert.py +12 -11
- {sqlengine_lite-2.2.1.dist-info → sqlengine_lite-2.2.2.dist-info}/METADATA +149 -96
- sqlengine_lite-2.2.2.dist-info/RECORD +18 -0
- sqlengine_lite-2.2.1.dist-info/RECORD +0 -18
- {sqlengine_lite-2.2.1.dist-info → sqlengine_lite-2.2.2.dist-info}/WHEEL +0 -0
- {sqlengine_lite-2.2.1.dist-info → sqlengine_lite-2.2.2.dist-info}/licenses/LICENSE +0 -0
- {sqlengine_lite-2.2.1.dist-info → sqlengine_lite-2.2.2.dist-info}/top_level.txt +0 -0
|
@@ -20,8 +20,7 @@ class ConnectionManager:
|
|
|
20
20
|
|
|
21
21
|
Args:
|
|
22
22
|
|
|
23
|
-
database (str): database filename to connect to. If `":memory:"` is passed, then database will be set in memory
|
|
24
|
-
create table manually with `create_table()` method inside `transaction()` block.
|
|
23
|
+
database (str): database filename to connect to. If `":memory:"` is passed, then database will be set in memory.
|
|
25
24
|
**connection_params: Params to create connection with. Reference: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
|
|
26
25
|
"""
|
|
27
26
|
|
|
@@ -139,7 +138,7 @@ class ConnectionManager:
|
|
|
139
138
|
Args:
|
|
140
139
|
query (str): SQL query
|
|
141
140
|
*args (tuple[SqlValue, ...]): Arguments to the execution
|
|
142
|
-
size (
|
|
141
|
+
size (int): Number of rows to return
|
|
143
142
|
|
|
144
143
|
Returns:
|
|
145
144
|
rows (list[SqlRow]): list of `size` rows
|
|
@@ -197,10 +196,14 @@ class ConnectionManager:
|
|
|
197
196
|
if self._is_managed_transaction:
|
|
198
197
|
raise TransactionError("Can't manually close managed transaction")
|
|
199
198
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
try:
|
|
200
|
+
self._trans_cursor.close()
|
|
201
|
+
self._trans.close()
|
|
202
|
+
except sqlite3.ProgrammingError as e:
|
|
203
|
+
raise TransactionError("Can't close connection properly") from e
|
|
204
|
+
finally:
|
|
205
|
+
del(self._trans_cursor)
|
|
206
|
+
del(self._trans)
|
|
204
207
|
|
|
205
208
|
|
|
206
209
|
def commit(self) -> None:
|
|
@@ -32,39 +32,46 @@ class Where[T : "Statement"]:
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def op(self, column : str, value : SqlValue, operator : str) -> Self:
|
|
35
|
+
""" Adds operator to the where clause """
|
|
35
36
|
self._clause.append(f"{column} {operator} ?")
|
|
36
37
|
self._args.append(value)
|
|
37
38
|
return self
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
def join(self, lop : str = "AND") -> Self:
|
|
41
|
-
"""
|
|
42
|
+
""" Join previous expression via logical operator `lop` """
|
|
42
43
|
joined = f" {lop} ".join(self._clause)
|
|
43
44
|
self._clause = [f"({joined})"]
|
|
44
45
|
return self
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
def eq(self, column : str, value : SqlValue) -> Self:
|
|
49
|
+
""" Add `column = value` to the where clause """
|
|
48
50
|
return self.op(column, value, "=")
|
|
49
51
|
|
|
50
52
|
|
|
51
53
|
def neq(self, column : str, value : SqlValue) -> Self:
|
|
54
|
+
""" Add `column != value` to the where clause """
|
|
52
55
|
return self.op(column, value, "!=")
|
|
53
56
|
|
|
54
57
|
|
|
55
58
|
def gt(self, column : str, value : SqlValue) -> Self:
|
|
59
|
+
""" Add `column > value` to the where clause """
|
|
56
60
|
return self.op(column, value, ">")
|
|
57
61
|
|
|
58
62
|
|
|
59
63
|
def gte(self, column : str, value : SqlValue) -> Self:
|
|
64
|
+
""" Add `column >= value` to the where clause """
|
|
60
65
|
return self.op(column, value, ">=")
|
|
61
66
|
|
|
62
67
|
|
|
63
68
|
def lt(self, column : str, value : SqlValue) -> Self:
|
|
69
|
+
""" Add `column < value` to the where clause """
|
|
64
70
|
return self.op(column, value, "<")
|
|
65
71
|
|
|
66
72
|
|
|
67
73
|
def lte(self, column : str, value : SqlValue) -> Self:
|
|
74
|
+
""" Add `column <= value` to the where clause """
|
|
68
75
|
return self.op(column, value, "<=")
|
|
69
76
|
|
|
70
77
|
|
|
@@ -77,12 +84,13 @@ class Where[T : "Statement"]:
|
|
|
77
84
|
|
|
78
85
|
|
|
79
86
|
def is_null(self, column : str) -> Self:
|
|
87
|
+
""" Add `column IS NULL` to the where clause """
|
|
80
88
|
self._clause.append(f"{column} IS NULL")
|
|
81
89
|
return self
|
|
82
90
|
|
|
83
91
|
|
|
84
92
|
def inverted(self) -> Self:
|
|
85
|
-
""" Invert
|
|
93
|
+
""" Invert previous where clauses with `NOT` """
|
|
86
94
|
self._clause[-1] = f"NOT ({self._clause[-1]})"
|
|
87
95
|
return self
|
|
88
96
|
|
|
@@ -128,14 +136,16 @@ class Where[T : "Statement"]:
|
|
|
128
136
|
return self._statement.__repr__()
|
|
129
137
|
|
|
130
138
|
|
|
139
|
+
def __iter__(self):
|
|
140
|
+
if not isinstance(self._statement, Select):
|
|
141
|
+
raise SqlEngineError("Can iterate only over `Select` statements")
|
|
142
|
+
return iter(self._statement)
|
|
143
|
+
|
|
144
|
+
|
|
131
145
|
def _repr_html_(self) -> str | None:
|
|
132
146
|
if isinstance(self._statement, Select):
|
|
133
147
|
return self._statement._repr_html_()
|
|
134
148
|
return None
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def __len__(self) -> int:
|
|
138
|
-
return len(self._args)
|
|
139
149
|
|
|
140
150
|
|
|
141
151
|
class Statement(ABC):
|
|
@@ -276,12 +286,12 @@ class Select(Statement):
|
|
|
276
286
|
|
|
277
287
|
def fetchmany_iterator(self, batch_size: int) -> Generator[list[SqlRow], None, None]:
|
|
278
288
|
"""
|
|
279
|
-
Yields all rows in batches
|
|
289
|
+
Yields all rows in batches within a single transaction.
|
|
280
290
|
|
|
281
291
|
Args:
|
|
282
292
|
batch_size (int): Size of each batch
|
|
283
293
|
|
|
284
|
-
|
|
294
|
+
Example:
|
|
285
295
|
|
|
286
296
|
```python
|
|
287
297
|
with table.transaction():
|
|
@@ -290,8 +300,8 @@ class Select(Statement):
|
|
|
290
300
|
```
|
|
291
301
|
"""
|
|
292
302
|
if not self._connection.in_transaction():
|
|
293
|
-
raise OutsideTransactionError("To use the `fetchall_iterator()` method you have
|
|
294
|
-
to keep open the transaction of the table")
|
|
303
|
+
raise OutsideTransactionError("To use the `fetchall_iterator()` method you have "
|
|
304
|
+
"to keep open the transaction of the table")
|
|
295
305
|
|
|
296
306
|
query, exec_args = self.build()
|
|
297
307
|
|
|
@@ -306,19 +316,18 @@ class Select(Statement):
|
|
|
306
316
|
"""
|
|
307
317
|
Select statement rows iterator
|
|
308
318
|
|
|
309
|
-
|
|
319
|
+
Example:
|
|
310
320
|
|
|
311
321
|
```python
|
|
312
322
|
with table.transaction():
|
|
313
|
-
|
|
314
|
-
for row in table.select.where.gt("Age", 30).then:
|
|
323
|
+
for row in table.select.where.gt("Age", 30):
|
|
315
324
|
process_row(row)
|
|
316
325
|
```
|
|
317
326
|
"""
|
|
318
327
|
|
|
319
328
|
if not self._connection.in_transaction():
|
|
320
|
-
raise OutsideTransactionError("To use the __iter__ method you have
|
|
321
|
-
to keep open the transaction of the table")
|
|
329
|
+
raise OutsideTransactionError("To use the `__iter__` method you have "
|
|
330
|
+
"to keep open the transaction of the table")
|
|
322
331
|
|
|
323
332
|
query, exec_args = self.build()
|
|
324
333
|
|
sqlengine/schema.py
CHANGED
|
@@ -62,15 +62,9 @@ def get_database_schemas(database : str) -> list[Schema]:
|
|
|
62
62
|
cursor = conn.cursor()
|
|
63
63
|
names = get_database_tablenames(database, cursor)
|
|
64
64
|
|
|
65
|
-
schemas
|
|
65
|
+
schemas = (get_table_schema(database, table_name, cursor) for table_name in names)
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
schema = get_table_schema(database, tablename, cursor)
|
|
69
|
-
|
|
70
|
-
if schema:
|
|
71
|
-
schemas.append(schema)
|
|
72
|
-
|
|
73
|
-
return schemas
|
|
67
|
+
return [sh for sh in schemas if sh]
|
|
74
68
|
|
|
75
69
|
|
|
76
70
|
def table_from_schema(database : str, schema : Schema, **kwargs) -> SqlTableMixin:
|
sqlengine/sqltable.py
CHANGED
|
@@ -24,7 +24,7 @@ class SqlTableMixin:
|
|
|
24
24
|
Lightweight wrapper for SQLite3 tables
|
|
25
25
|
|
|
26
26
|
Args:
|
|
27
|
-
database (str): database filename to connect to. If it not exists - will create new one first.
|
|
27
|
+
database (str): database filename to connect to. If it does not exists - will create new one first.
|
|
28
28
|
If `":memory:"` is passed, then database will be set in memory and you will have to
|
|
29
29
|
create table manually with `create_table()` method inside `transaction()` block.
|
|
30
30
|
force_drop (bool): If `True` - will drop existing table.
|
|
@@ -37,7 +37,7 @@ class SqlTableMixin:
|
|
|
37
37
|
__types__ (list[ColumnType]): Column types of the table
|
|
38
38
|
__primary__ (list[str]): List of primary keys
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Example:
|
|
41
41
|
```python
|
|
42
42
|
from sqlengine import SqlTableMixin, Primary
|
|
43
43
|
|
|
@@ -189,7 +189,7 @@ class SqlTableMixin:
|
|
|
189
189
|
Args:
|
|
190
190
|
autocommit (bool): If `True`, will commit changes at the end of transaction
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
Example:
|
|
193
193
|
|
|
194
194
|
```python
|
|
195
195
|
with table.transaction():
|
|
@@ -209,7 +209,7 @@ class SqlTableMixin:
|
|
|
209
209
|
*args (SqlValue): Arguments in order of declared __columns__
|
|
210
210
|
**kwargs (SqlValue): Column to value mapping
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
Example:
|
|
213
213
|
|
|
214
214
|
```python
|
|
215
215
|
table = MyTable("mydb.db")
|
|
@@ -397,7 +397,7 @@ class SqlTableMixin:
|
|
|
397
397
|
"""
|
|
398
398
|
UPDATE statement builder and executor
|
|
399
399
|
|
|
400
|
-
|
|
400
|
+
Example:
|
|
401
401
|
|
|
402
402
|
```python
|
|
403
403
|
table.update.set("City", "Karaganda").where.eq("Country", "Czech Republic").then.execute()
|
|
@@ -411,7 +411,7 @@ class SqlTableMixin:
|
|
|
411
411
|
"""
|
|
412
412
|
DELETE statement builder and executor
|
|
413
413
|
|
|
414
|
-
|
|
414
|
+
Example:
|
|
415
415
|
|
|
416
416
|
```python
|
|
417
417
|
table.delete.where.eq("ID", 0).then.execute()
|
|
@@ -425,7 +425,7 @@ class SqlTableMixin:
|
|
|
425
425
|
"""
|
|
426
426
|
SELECT statement builder and fetcher
|
|
427
427
|
|
|
428
|
-
|
|
428
|
+
Example:
|
|
429
429
|
|
|
430
430
|
```python
|
|
431
431
|
table.select("Email").where.eq("SupportRepId", 3).then.aggregate("COUNT").fetchone()
|
sqlengine/utils/connection.py
CHANGED
|
@@ -25,7 +25,7 @@ def shared_connection(*args : SqlTableMixin, autocommit : bool = True, **connect
|
|
|
25
25
|
**connection_params (dict): Params to create connections with. This argument will be shared
|
|
26
26
|
across different connections. Reference: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Example:
|
|
29
29
|
|
|
30
30
|
```python
|
|
31
31
|
from sqlengine.utils import shared_connection
|
sqlengine/utils/convert.py
CHANGED
|
@@ -4,6 +4,7 @@ from typing import Generator
|
|
|
4
4
|
from ..sqltable import SqlTableMixin
|
|
5
5
|
from .._internal.statements import Where, Select
|
|
6
6
|
from .._internal.types import SqlValue
|
|
7
|
+
from ..exceptions import OutsideTransactionError, SqlEngineError
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def _get_select(builder : Select | Where[Select] | SqlTableMixin) -> Select:
|
|
@@ -30,16 +31,16 @@ def to_csv(
|
|
|
30
31
|
Args:
|
|
31
32
|
builder (Select | Where[Select] | SqlTableMixin): Object to convert to csv
|
|
32
33
|
filename (str): Path to write to
|
|
33
|
-
|
|
34
|
+
stream_batch_size (int | None): If not None or 0, will stream all rows to csv in batches of provided size
|
|
34
35
|
"""
|
|
35
36
|
|
|
36
37
|
builder = _get_select(builder)
|
|
37
38
|
|
|
38
39
|
if builder._aggregate:
|
|
39
|
-
raise
|
|
40
|
+
raise SqlEngineError("Aggregated queries are not supported")
|
|
40
41
|
|
|
41
42
|
if stream_batch_size and not builder._connection.in_transaction():
|
|
42
|
-
raise
|
|
43
|
+
raise OutsideTransactionError("To stream to csv you have to keep open the `transaction`")
|
|
43
44
|
|
|
44
45
|
columns = builder._resolve_columns()
|
|
45
46
|
|
|
@@ -66,19 +67,19 @@ def to_dicts(builder : Select | Where[Select] | SqlTableMixin) -> list[dict[str,
|
|
|
66
67
|
Returns:
|
|
67
68
|
out (list[dict[str, SqlValue]]): list of rows mappings
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
Example:
|
|
70
71
|
|
|
71
72
|
```python
|
|
72
73
|
import pandas as pd
|
|
73
74
|
|
|
74
|
-
df = pd.DataFrame(
|
|
75
|
+
df = pd.DataFrame(to_dicts(table))
|
|
75
76
|
```
|
|
76
77
|
"""
|
|
77
78
|
|
|
78
79
|
builder = _get_select(builder)
|
|
79
80
|
|
|
80
81
|
if builder._aggregate:
|
|
81
|
-
raise
|
|
82
|
+
raise SqlEngineError("Aggregated queries are not supported")
|
|
82
83
|
|
|
83
84
|
columns = builder._resolve_columns()
|
|
84
85
|
rows = builder.fetchall()
|
|
@@ -95,12 +96,12 @@ def to_dicts_stream(
|
|
|
95
96
|
|
|
96
97
|
Args:
|
|
97
98
|
builder (Select | Where[Select] | SqlTableMixin): Object to convert to list of dicts
|
|
98
|
-
batch_size (int): Size of each
|
|
99
|
+
batch_size (int): Size of each yielded batch
|
|
99
100
|
|
|
100
101
|
Yields:
|
|
101
102
|
batch (list[dict[str, SqlValue]]): list of rows mappings
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
Example:
|
|
104
105
|
|
|
105
106
|
```python
|
|
106
107
|
import pandas as pd
|
|
@@ -108,7 +109,7 @@ def to_dicts_stream(
|
|
|
108
109
|
df = pd.DataFrame(columns=table.columns)
|
|
109
110
|
|
|
110
111
|
with table.transaction():
|
|
111
|
-
for batch in
|
|
112
|
+
for batch in to_dicts_stream(table, 100):
|
|
112
113
|
df = pd.concat([df, pd.DataFrame(batch)], axis=0)
|
|
113
114
|
|
|
114
115
|
df.set_index("ID", inplace=True)
|
|
@@ -118,10 +119,10 @@ def to_dicts_stream(
|
|
|
118
119
|
builder = _get_select(builder)
|
|
119
120
|
|
|
120
121
|
if builder._aggregate:
|
|
121
|
-
raise
|
|
122
|
+
raise SqlEngineError("Aggregated queries are not supported")
|
|
122
123
|
|
|
123
124
|
if not builder._connection.in_transaction():
|
|
124
|
-
raise
|
|
125
|
+
raise OutsideTransactionError("To stream to csv you have to keep open the `transaction`")
|
|
125
126
|
|
|
126
127
|
columns = builder._resolve_columns()
|
|
127
128
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlengine-lite
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Cute sqlite3 wrapper for sql tables
|
|
5
5
|
Project-URL: Homepage, https://github.com/suffermuffin/SQL-Engine
|
|
6
6
|
Project-URL: Repository, https://github.com/suffermuffin/SQL-Engine.git
|
|
@@ -10,38 +10,33 @@ Description-Content-Type: text/markdown
|
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Dynamic: license-file
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- [Update Query](#update-query)
|
|
25
|
-
- [Delete Query](#delete-query)
|
|
26
|
-
- [Transaction](#transaction)
|
|
27
|
-
- [Get Item](#get-item)
|
|
28
|
-
- [Custom Types](#custom-types)
|
|
29
|
-
- [Csv Converter](#csv-converter)
|
|
30
|
-
- [Pandas-like Converter](#pandas-like-converter)
|
|
31
|
-
- [Full Documentation](#full-documentation)
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://github.com/suffermuffin/SQL-Engine/actions/workflows/test.yml?query=event%3Apush">
|
|
15
|
+
<img src="https://github.com/suffermuffin/SQL-Engine/actions/workflows/test.yml/badge.svg?event=push&branch=main" alt="Tests">
|
|
16
|
+
</a>
|
|
17
|
+
<a href="https://github.com/suffermuffin/SQL-Engine/actions?query=workflow%3APublish">
|
|
18
|
+
<img src="https://github.com/suffermuffin/SQL-Engine/actions/workflows/publish.yml/badge.svg" alt="Publishing">
|
|
19
|
+
</a>
|
|
20
|
+
<a href="https://pypi.org/project/sqlengine-lite/">
|
|
21
|
+
<img alt="PyPI" src="https://img.shields.io/pypi/v/sqlengine-lite?logoSize=amd&labelColor=black&color=royalblue">
|
|
22
|
+
</a>
|
|
23
|
+
</p>
|
|
32
24
|
|
|
33
25
|
|
|
34
|
-
#
|
|
26
|
+
# SqlEngine
|
|
35
27
|
|
|
36
|
-
My
|
|
28
|
+
My SqlEngine is a cute little wrapper for `sqlite3` table manipulations without any third party dependencies.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
[**Home Page**](https://github.com/suffermuffin/SQL-Engine) | [**Installation**](#installation) | [**Quick Start**](#quick-start) | [**Documentation**](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/index.md)
|
|
37
32
|
|
|
38
33
|
|
|
39
34
|
## Features
|
|
40
35
|
|
|
41
|
-
|
|
36
|
+
SqlEngine abstracts SQL queries into tiny little methods like `insert`, `insert_many`, `upsert`, and not so tiny (but still cute and little) query builders like `select`, `delete` and `update`. SqlEngine also provides bulk insertion with `insert_many` and transaction operations like `select.fetchmany_iterator`. Methods can be executed either in transaction mode (thanks to `transaction` context manager) or right on the spot.
|
|
42
37
|
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
SqlEngine implements Jupyter integration and dynamic schema building. You can easily instantiate existing database table and view it in a cute little html representation.
|
|
45
40
|
|
|
46
41
|
```py
|
|
47
42
|
from sqlengine import schema
|
|
@@ -74,66 +69,40 @@ table.select("InvoiceId", "CustomerId", "BillingAddress", "BillingCountry", "Tot
|
|
|
74
69
|
|
|
75
70
|
## Purpose
|
|
76
71
|
|
|
77
|
-
It's a tiny little modern ORM-like that lets you prototype your databases locally with great flexibility. Also, it can be used in production apps to store and retrieve data, because all select, update, delete queries are parametrized. But it does not restrict you from using your own queries which might not be
|
|
72
|
+
It's a tiny little modern ORM-like that lets you prototype your databases locally with great flexibility. Also, it can be used in production apps to store and retrieve data, because all select, update, delete queries are parametrized. But it does not restrict you from using your own queries which might not be parameterized with methods like `select.custom()` and `where.custom()`. Flexibility is a go to for this library.
|
|
78
73
|
|
|
79
|
-
And last (but not least) is data inspection. If you need to quickly inspect existing .db file but don't want to install yet another heavy ORM with a lot of unused dependencies, you might look into
|
|
74
|
+
And last (but not least) is data inspection. If you need to quickly inspect existing .db file but don't want to install yet another heavy ORM with a lot of unused dependencies and features, you might look into SqlEngine, as it uses only native python modules, implements dynamic schema builder and has a good synergy with Jupyter Notebook.
|
|
80
75
|
|
|
81
76
|
|
|
82
77
|
## Installation
|
|
83
78
|
|
|
84
|
-
To install
|
|
79
|
+
To install SqlEngine, you can use `pip`:
|
|
85
80
|
|
|
86
|
-
```
|
|
81
|
+
```bash
|
|
87
82
|
pip install sqlengine-lite
|
|
88
83
|
```
|
|
89
84
|
|
|
90
85
|
## Env
|
|
91
86
|
|
|
92
|
-
You
|
|
87
|
+
You can set environment variable for logging. By default it's `WARNING`.
|
|
93
88
|
|
|
94
89
|
```console
|
|
95
90
|
SQL_ENGINE_LOG_LEVEL=INFO
|
|
96
91
|
```
|
|
97
92
|
|
|
98
|
-
# Quick Start
|
|
99
|
-
|
|
100
|
-
All you have to do to create your own cute little table is to [inherit](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#class-declaration) `SqlTableMixin` class or to create your own [schema](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#schema-declaration) and declare desired properties of your table's columns. They are:
|
|
101
93
|
|
|
94
|
+
# Quick Start
|
|
102
95
|
|
|
103
|
-
|
|
104
|
-
```py
|
|
105
|
-
__tablename__ : Optional[str]
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
_Column names of the table_
|
|
109
|
-
```py
|
|
110
|
-
__columns__ : list[str]
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
_Column types of the table_
|
|
114
|
-
```py
|
|
115
|
-
__types__ : list[SqlType | str]
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
_List of primary keys_
|
|
119
|
-
```py
|
|
120
|
-
__primary__ : list[str]
|
|
121
|
-
```
|
|
96
|
+
Here lays everything you need to know to start working with SqlEngine. For detailed usage, API reference, and advanced examples, see the [full documentation](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/index.md).
|
|
122
97
|
|
|
123
98
|
## Table Declaration
|
|
124
99
|
|
|
125
|
-
|
|
100
|
+
All you have to do to create your own cute little table is to [inherit](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#class-declaration) `SqlTableMixin` class or to create your own [schema](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#schema-declaration) and declare desired types of your table's columns.
|
|
101
|
+
|
|
126
102
|
|
|
127
103
|
```py
|
|
128
104
|
from sqlengine import SqlTableMixin, Primary
|
|
129
105
|
|
|
130
|
-
# Helper constants for column names
|
|
131
|
-
ID = "ID"
|
|
132
|
-
Name = "Name"
|
|
133
|
-
Occupation = "Occupation"
|
|
134
|
-
Salary = "Salary"
|
|
135
|
-
|
|
136
|
-
|
|
137
106
|
class Employees(SqlTableMixin):
|
|
138
107
|
|
|
139
108
|
ID : Primary[int]
|
|
@@ -143,35 +112,35 @@ class Employees(SqlTableMixin):
|
|
|
143
112
|
|
|
144
113
|
```
|
|
145
114
|
|
|
115
|
+
More details at [Declaration](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#table-declaration).
|
|
116
|
+
|
|
146
117
|
## Instantiation
|
|
147
118
|
|
|
148
|
-
|
|
119
|
+
Create an instance of the table class with provided path to create or connect to. `force_drop=True` to overwrite existing table if it exists.
|
|
149
120
|
|
|
150
121
|
```py
|
|
151
|
-
# Create an instance of the table class
|
|
152
|
-
# with provided path to create or connect to
|
|
153
|
-
# `force_drop=True` to overwrite existing table if exists
|
|
154
|
-
|
|
155
122
|
table = Employees("temp/data.db", force_drop=True)
|
|
156
123
|
```
|
|
157
124
|
|
|
125
|
+
More details at [Instantiation](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#table-instantiation).
|
|
126
|
+
|
|
158
127
|
## Row insertion
|
|
159
128
|
|
|
160
|
-
|
|
161
|
-
# Insert one row
|
|
129
|
+
Insert one row in a `*args` style.
|
|
162
130
|
|
|
131
|
+
```py
|
|
163
132
|
table.insert(1, "John Doe", "Software Engineer", 75000.0)
|
|
164
133
|
```
|
|
165
134
|
|
|
166
|
-
|
|
167
|
-
# Use kwargs mapping to insert/upsert one row
|
|
135
|
+
Use **kwargs mapping** to insert/upsert one row
|
|
168
136
|
|
|
137
|
+
```py
|
|
169
138
|
table.insert(2, salary=80000.0, name="Jane Smith", occupation="Data Scientist")
|
|
170
139
|
```
|
|
171
140
|
|
|
172
|
-
|
|
173
|
-
# Bulk insert multiple rows
|
|
141
|
+
Bulk insert multiple rows.
|
|
174
142
|
|
|
143
|
+
```py
|
|
175
144
|
employees_data = [
|
|
176
145
|
(3, "Alice Johnson", "Product Manager", 90000.0),
|
|
177
146
|
(4, "Bob Brown", "Project Manager", 78000.0),
|
|
@@ -187,17 +156,17 @@ table.insert_many(employees_data)
|
|
|
187
156
|
```
|
|
188
157
|
|
|
189
158
|
|
|
190
|
-
|
|
191
|
-
# Upsert one row
|
|
159
|
+
Upsert one row.
|
|
192
160
|
|
|
161
|
+
```py
|
|
193
162
|
table.upsert(1, "Jane Doe", "Data Scientist", 80000.0)
|
|
194
163
|
```
|
|
195
164
|
|
|
196
165
|
## Jupyter view
|
|
197
166
|
|
|
198
|
-
|
|
199
|
-
# Inspect tables in Jupyter Notebook
|
|
167
|
+
Inspect table in Jupyter Notebook.
|
|
200
168
|
|
|
169
|
+
```py
|
|
201
170
|
table
|
|
202
171
|
```
|
|
203
172
|
|
|
@@ -205,11 +174,18 @@ table
|
|
|
205
174
|
|
|
206
175
|
## Select Query
|
|
207
176
|
|
|
208
|
-
|
|
177
|
+
Helper constants for column names.
|
|
209
178
|
|
|
210
179
|
```py
|
|
211
|
-
|
|
180
|
+
ID = "ID"
|
|
181
|
+
Name = "Name"
|
|
182
|
+
Occupation = "Occupation"
|
|
183
|
+
Salary = "Salary"
|
|
184
|
+
```
|
|
212
185
|
|
|
186
|
+
Query **select** and **fetch** in one go.
|
|
187
|
+
|
|
188
|
+
```py
|
|
213
189
|
table.select.where.between(ID, 3, 5).then.fetchall()
|
|
214
190
|
|
|
215
191
|
# ->
|
|
@@ -218,9 +194,24 @@ table.select.where.between(ID, 3, 5).then.fetchall()
|
|
|
218
194
|
# (5, 'Charlie Davis', 'UI/UX Designer', 65000.0)]
|
|
219
195
|
```
|
|
220
196
|
|
|
197
|
+
**Iterate** over select statements.
|
|
198
|
+
|
|
221
199
|
```py
|
|
222
|
-
|
|
200
|
+
with table.transaction():
|
|
201
|
+
for id, occupation in table.select(ID, Occupation).where.gt(Salary, 70_000):
|
|
202
|
+
print(id, occupation)
|
|
203
|
+
```
|
|
223
204
|
|
|
205
|
+
```console
|
|
206
|
+
1 Data Scientist
|
|
207
|
+
3 Product Manager
|
|
208
|
+
4 Project Manager
|
|
209
|
+
6 DevOps Engineer
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Inspect select query in Jupyter.
|
|
213
|
+
|
|
214
|
+
```py
|
|
224
215
|
table.select(Name, Salary).where.lt(Salary, 70_000)
|
|
225
216
|
```
|
|
226
217
|
|
|
@@ -239,33 +230,32 @@ table.update(Salary, 50_000).where.eq(Name, "Eve Taylor").then.execute()
|
|
|
239
230
|
table.delete.where.eq(ID, 5).then.execute()
|
|
240
231
|
```
|
|
241
232
|
|
|
233
|
+
More details at [Statements](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/statements.md).
|
|
234
|
+
|
|
242
235
|
## Transaction
|
|
243
236
|
|
|
244
|
-
|
|
237
|
+
Operate within a transaction
|
|
245
238
|
|
|
246
239
|
```py
|
|
247
|
-
# Operate within a transaction
|
|
248
240
|
|
|
249
241
|
with table.transaction():
|
|
250
242
|
for row in employees_data:
|
|
251
243
|
table.upsert(*row)
|
|
252
244
|
```
|
|
253
245
|
|
|
246
|
+
More details at [Transaction](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/transactions.md).
|
|
247
|
+
|
|
254
248
|
## Get Item
|
|
255
249
|
|
|
256
|
-
|
|
250
|
+
Fetch row by primary key.
|
|
257
251
|
|
|
258
252
|
```py
|
|
259
|
-
#
|
|
260
|
-
|
|
261
|
-
table[9]
|
|
262
|
-
|
|
263
|
-
# -> (9, 'Grace Hall', 'Marketing Manager', 68000.0)
|
|
253
|
+
table[9] # -> (9, 'Grace Hall', 'Marketing Manager', 68000.0)
|
|
264
254
|
```
|
|
265
255
|
|
|
266
|
-
|
|
267
|
-
# Fetch slice by integer primary key
|
|
256
|
+
Fetch slice by integer primary key.
|
|
268
257
|
|
|
258
|
+
```py
|
|
269
259
|
table[4:10:2]
|
|
270
260
|
|
|
271
261
|
# ->
|
|
@@ -274,9 +264,11 @@ table[4:10:2]
|
|
|
274
264
|
# (8, 'Frank White', 'Quality Assurance', 53000.0)]
|
|
275
265
|
```
|
|
276
266
|
|
|
267
|
+
More details at [Syntax Sugar](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/syntax_sugar.md).
|
|
268
|
+
|
|
277
269
|
## Custom Types
|
|
278
270
|
|
|
279
|
-
|
|
271
|
+
Declare your own non-native SQL type to be compatible with sqlite3.
|
|
280
272
|
|
|
281
273
|
```py
|
|
282
274
|
from datetime import datetime
|
|
@@ -305,36 +297,68 @@ class ReservationIndex(SqlTableMixin):
|
|
|
305
297
|
|
|
306
298
|
table = ReservationIndex("temp/data.db")
|
|
307
299
|
|
|
308
|
-
table.insert(
|
|
300
|
+
table.insert(
|
|
301
|
+
user_id=1,
|
|
302
|
+
room_id="loft_1",
|
|
303
|
+
time_at=DateTime.now()
|
|
304
|
+
)
|
|
309
305
|
table
|
|
310
306
|
```
|
|
311
307
|
|
|
312
308
|
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">ReservationIndex</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">user_id</td><td style="border: 1px solid #555; text-align: center;">room_id</td><td style="border: 1px solid #555; text-align: center;">time_at</td><td style="border: 1px solid #555; text-align: center;">user_name</td></tr></thead><tbody><tr><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">loft_1</td><td style="border: 1px solid #000; text-align: center;">2026-05-29 21:29:00</td><td style="border: 1px solid #000; text-align: center;">None</td></tr></tbody></table>
|
|
313
309
|
|
|
310
|
+
More details at [Custom Types](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/custom_types.md).
|
|
311
|
+
|
|
312
|
+
## Pure SQL
|
|
313
|
+
|
|
314
|
+
Use SQL queries directly.
|
|
315
|
+
|
|
316
|
+
```py
|
|
317
|
+
with table.transaction(autocommit=False):
|
|
318
|
+
table.conn.execute("DELETE FROM ReservationIndex WHERE user_id = 1;")
|
|
319
|
+
table.commit()
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Same as:
|
|
323
|
+
|
|
324
|
+
```py
|
|
325
|
+
table.conn.execute("DELETE FROM ReservationIndex WHERE user_id = 1;")
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
```py
|
|
329
|
+
table
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">ReservationIndex</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">user_id</td><td style="border: 1px solid #555; text-align: center;">room_id</td><td style="border: 1px solid #555; text-align: center;">time_at</td><td style="border: 1px solid #555; text-align: center;">user_name</td></tr></thead><tbody></tbody></table>
|
|
333
|
+
|
|
314
334
|
## Csv Converter
|
|
315
335
|
|
|
336
|
+
Save table to csv.
|
|
337
|
+
|
|
316
338
|
```py
|
|
317
|
-
# Save table to csv
|
|
318
339
|
from sqlengine.utils import to_csv
|
|
319
340
|
|
|
320
341
|
to_csv(table, "temp/table.csv")
|
|
321
342
|
```
|
|
322
343
|
|
|
344
|
+
Save query result to csv.
|
|
345
|
+
|
|
323
346
|
```py
|
|
324
|
-
# Save query result to csv
|
|
325
347
|
to_csv(table.select.where.gt(Salary, 70_000), "temp/query.csv")
|
|
326
348
|
```
|
|
327
349
|
|
|
350
|
+
Stream big tables or query results to csv.
|
|
351
|
+
|
|
328
352
|
```py
|
|
329
|
-
# Stream to csv
|
|
330
353
|
with table.transaction():
|
|
331
354
|
to_csv(table, "temp/query.csv", stream_batch_size=1000)
|
|
332
355
|
```
|
|
333
356
|
|
|
334
357
|
## Pandas-like Converter
|
|
335
358
|
|
|
359
|
+
Convert tables or query results to pandas **DataFrame** in one shot.
|
|
360
|
+
|
|
336
361
|
```py
|
|
337
|
-
# via one shot
|
|
338
362
|
import pandas as pd
|
|
339
363
|
from sqlengine.utils import to_dicts
|
|
340
364
|
|
|
@@ -342,8 +366,9 @@ df = pd.DataFrame(to_dicts(table))
|
|
|
342
366
|
df.set_index("ID", inplace=True)
|
|
343
367
|
```
|
|
344
368
|
|
|
369
|
+
Or stream them via generator.
|
|
370
|
+
|
|
345
371
|
```py
|
|
346
|
-
# via generator
|
|
347
372
|
import pandas as pd
|
|
348
373
|
from sqlengine.utils import to_dicts_stream
|
|
349
374
|
|
|
@@ -356,6 +381,34 @@ with table.transaction():
|
|
|
356
381
|
df.set_index("ID", inplace=True)
|
|
357
382
|
```
|
|
358
383
|
|
|
359
|
-
#
|
|
384
|
+
# Contributions
|
|
385
|
+
|
|
386
|
+
Your impact is welcome. Install module from source if you want to contribute:
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
git clone https://github.com/suffermuffin/SQL-Engine.git
|
|
390
|
+
cd SQL-Engine
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Use `uv` to sync dependencies and checkout to your new branch:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
uv sync
|
|
397
|
+
git checkout -b "<your_feature_or_fix_name>"
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Don't forget to run tests after the implementation:
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
uv run python -m unittest discover -s tests
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
And update api documentation with your docstrings:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
pydoc-markdown
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
# License
|
|
360
413
|
|
|
361
|
-
|
|
414
|
+
This project is licensed under the terms of the [MIT license](https://github.com/suffermuffin/SQL-Engine/blob/main/LICENSE).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
sqlengine/__init__.py,sha256=_t3mutixVp60g1MwD6BZ6WcvXZPFz7JkV29nXXl1bOw,305
|
|
2
|
+
sqlengine/exceptions.py,sha256=Sd12r8dHgtKr6RKUaiHNhaEpdJr3Jr-JXePwrBQojC4,506
|
|
3
|
+
sqlengine/schema.py,sha256=SL-7eXib56wIVHSgykqMJKZGRPJuOffpwA0GJEgChSc,3593
|
|
4
|
+
sqlengine/sqltable.py,sha256=ZgkPQi5L1IGHauamTSjqyKVGNMKHCKmt3tEGTI-pCnY,16197
|
|
5
|
+
sqlengine/_internal/__init__.py,sha256=9cQIPDgLssRJNeROpuDYA0rJzY9B_N9VsY4rJbgzBnk,159
|
|
6
|
+
sqlengine/_internal/connection_manager.py,sha256=j4H7BiPu7iUxqOSRMmApgGnCY9dRBdL4javwMwAi_BU,8522
|
|
7
|
+
sqlengine/_internal/repr.py,sha256=PEwC3MdOoTE8ORvcVXTCmY502boJfr5V2LU5jJ6qWG0,1478
|
|
8
|
+
sqlengine/_internal/sqlgen.py,sha256=b8usEqBAX5JDEdMR6Xeaona0ZuOi7vtptl858qXhD78,3473
|
|
9
|
+
sqlengine/_internal/statements.py,sha256=8D6uZCwm4iMwfq0Lzg5-Z91x68xN874xQbHyZyFPBKE,12876
|
|
10
|
+
sqlengine/_internal/types.py,sha256=bA-tsS8r13pvRB3M13wFNsd3Fc9KAaqGW47aXhkKkDQ,3265
|
|
11
|
+
sqlengine/utils/__init__.py,sha256=EGg576qs61VsXlXd1bxF0oDytlmpcgqouVLdPxwqTrI,173
|
|
12
|
+
sqlengine/utils/connection.py,sha256=wnA21QCUd7meRHL114ZzghchNIgvmq-cEmIJ-8L_ozQ,3118
|
|
13
|
+
sqlengine/utils/convert.py,sha256=8bUNdxNNNkBnUIcTNkLGqA9h_X-D8BHtssHhe0UMPx0,3782
|
|
14
|
+
sqlengine_lite-2.2.2.dist-info/licenses/LICENSE,sha256=aepvve4t1ho5uHMQG88dErp5L5CgoNAXctIjMdoceqY,1069
|
|
15
|
+
sqlengine_lite-2.2.2.dist-info/METADATA,sha256=2WfgmOiu-lq7b6fBamCTtVhuVmYNHwCDuujYz1H9WL0,22586
|
|
16
|
+
sqlengine_lite-2.2.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
17
|
+
sqlengine_lite-2.2.2.dist-info/top_level.txt,sha256=KG_FG0LCB_mIEu2qJ5LGLQMpan4QmF5d8xLEcqTghCE,10
|
|
18
|
+
sqlengine_lite-2.2.2.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
sqlengine/__init__.py,sha256=_t3mutixVp60g1MwD6BZ6WcvXZPFz7JkV29nXXl1bOw,305
|
|
2
|
-
sqlengine/exceptions.py,sha256=Sd12r8dHgtKr6RKUaiHNhaEpdJr3Jr-JXePwrBQojC4,506
|
|
3
|
-
sqlengine/schema.py,sha256=HUk11gqOSzQTdiKBYU65EEQ52iCbUj3fxv3jigi1tG8,3692
|
|
4
|
-
sqlengine/sqltable.py,sha256=FOwXyTghcIxF8vhxMgzFeF6wAZNRjVt6r7Ebhqs-iJ0,16198
|
|
5
|
-
sqlengine/_internal/__init__.py,sha256=9cQIPDgLssRJNeROpuDYA0rJzY9B_N9VsY4rJbgzBnk,159
|
|
6
|
-
sqlengine/_internal/connection_manager.py,sha256=2ooDsAUvSfXTBpUJtNDS2GIO96tJo1GnE_R7dRBVflY,8466
|
|
7
|
-
sqlengine/_internal/repr.py,sha256=PEwC3MdOoTE8ORvcVXTCmY502boJfr5V2LU5jJ6qWG0,1478
|
|
8
|
-
sqlengine/_internal/sqlgen.py,sha256=b8usEqBAX5JDEdMR6Xeaona0ZuOi7vtptl858qXhD78,3473
|
|
9
|
-
sqlengine/_internal/statements.py,sha256=ntJrOeomPW15KowXUbnma9_ah-H5_ZmWKjemCIsf3Rw,12395
|
|
10
|
-
sqlengine/_internal/types.py,sha256=bA-tsS8r13pvRB3M13wFNsd3Fc9KAaqGW47aXhkKkDQ,3265
|
|
11
|
-
sqlengine/utils/__init__.py,sha256=EGg576qs61VsXlXd1bxF0oDytlmpcgqouVLdPxwqTrI,173
|
|
12
|
-
sqlengine/utils/connection.py,sha256=H86Y2PUJcTIc9iD398MJoRR-IyMYSVjOSfu_bk9UuoM,3119
|
|
13
|
-
sqlengine/utils/convert.py,sha256=Il5KAbc0Mbe2SIxBWyvj9rJ68XTJmpDFboJc1vifaaI,3694
|
|
14
|
-
sqlengine_lite-2.2.1.dist-info/licenses/LICENSE,sha256=aepvve4t1ho5uHMQG88dErp5L5CgoNAXctIjMdoceqY,1069
|
|
15
|
-
sqlengine_lite-2.2.1.dist-info/METADATA,sha256=XAAXT6IKmRIUkYtVkqij11U1W5UMZNwjfGg9sgbT81w,20593
|
|
16
|
-
sqlengine_lite-2.2.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
17
|
-
sqlengine_lite-2.2.1.dist-info/top_level.txt,sha256=KG_FG0LCB_mIEu2qJ5LGLQMpan4QmF5d8xLEcqTghCE,10
|
|
18
|
-
sqlengine_lite-2.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|