sqlengine-lite 2.2.0__py3-none-any.whl → 2.2.1__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/__init__.py +7 -3
- sqlengine/_internal/__init__.py +4 -0
- sqlengine/{core/connection.py → _internal/connection_manager.py} +17 -6
- sqlengine/{core → _internal}/statements.py +36 -14
- sqlengine/{core → _internal}/types.py +9 -8
- sqlengine/exceptions.py +20 -0
- sqlengine/schema.py +1 -1
- sqlengine/sqltable.py +98 -66
- sqlengine/utils/__init__.py +2 -2
- sqlengine/utils/connection.py +11 -8
- sqlengine/utils/convert.py +114 -9
- {sqlengine_lite-2.2.0.dist-info → sqlengine_lite-2.2.1.dist-info}/METADATA +43 -13
- sqlengine_lite-2.2.1.dist-info/RECORD +18 -0
- sqlengine/core/__init__.py +0 -4
- sqlengine_lite-2.2.0.dist-info/RECORD +0 -17
- /sqlengine/{core → _internal}/repr.py +0 -0
- /sqlengine/{core → _internal}/sqlgen.py +0 -0
- {sqlengine_lite-2.2.0.dist-info → sqlengine_lite-2.2.1.dist-info}/WHEEL +0 -0
- {sqlengine_lite-2.2.0.dist-info → sqlengine_lite-2.2.1.dist-info}/licenses/LICENSE +0 -0
- {sqlengine_lite-2.2.0.dist-info → sqlengine_lite-2.2.1.dist-info}/top_level.txt +0 -0
sqlengine/__init__.py
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
from .
|
|
2
|
-
from .
|
|
1
|
+
from ._internal import sqlgen
|
|
2
|
+
from ._internal import ConnectionManager
|
|
3
|
+
from ._internal.types import Schema, Primary, register_type
|
|
3
4
|
from .sqltable import SqlTableMixin
|
|
4
5
|
|
|
5
6
|
__author__ = "suffermuffin"
|
|
6
7
|
|
|
7
|
-
__all__ = [
|
|
8
|
+
__all__ = [
|
|
9
|
+
"sqlgen", "Schema", "SqlTableMixin",
|
|
10
|
+
"Primary", "ConnectionManager", "register_type"
|
|
11
|
+
]
|
|
@@ -6,6 +6,7 @@ from typing import overload, Literal, Sequence
|
|
|
6
6
|
from contextlib import contextmanager
|
|
7
7
|
|
|
8
8
|
from .types import SqlValue, SqlRow
|
|
9
|
+
from ..exceptions import TransactionError, NestedTransactionError, OutsideTransactionError
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
logger = logging.getLogger("sqlengine")
|
|
@@ -14,6 +15,16 @@ logger.setLevel(os.getenv("SQL_ENGINE_LOG_LEVEL", "WARNING").upper())
|
|
|
14
15
|
|
|
15
16
|
class ConnectionManager:
|
|
16
17
|
|
|
18
|
+
"""
|
|
19
|
+
Connection manager for sqlite3
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
|
|
23
|
+
database (str): database filename to connect to. If `":memory:"` is passed, then database will be set in memory and you will have to
|
|
24
|
+
create table manually with `create_table()` method inside `transaction()` block.
|
|
25
|
+
**connection_params: Params to create connection with. Reference: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
|
|
26
|
+
"""
|
|
27
|
+
|
|
17
28
|
_trans : sqlite3.Connection
|
|
18
29
|
_trans_cursor : sqlite3.Cursor
|
|
19
30
|
|
|
@@ -172,7 +183,7 @@ class ConnectionManager:
|
|
|
172
183
|
def open(self) -> None:
|
|
173
184
|
""" Opens unmanaged transaction """
|
|
174
185
|
if self.in_transaction():
|
|
175
|
-
raise
|
|
186
|
+
raise NestedTransactionError("Can't re-open existing connection")
|
|
176
187
|
|
|
177
188
|
self._trans = self.connect()
|
|
178
189
|
self._trans_cursor = self._trans.cursor()
|
|
@@ -184,7 +195,7 @@ class ConnectionManager:
|
|
|
184
195
|
return
|
|
185
196
|
|
|
186
197
|
if self._is_managed_transaction:
|
|
187
|
-
raise
|
|
198
|
+
raise TransactionError("Can't manually close managed transaction")
|
|
188
199
|
|
|
189
200
|
self._trans_cursor.close()
|
|
190
201
|
self._trans.close()
|
|
@@ -194,14 +205,14 @@ class ConnectionManager:
|
|
|
194
205
|
|
|
195
206
|
def commit(self) -> None:
|
|
196
207
|
if not self.in_transaction():
|
|
197
|
-
raise
|
|
208
|
+
raise OutsideTransactionError("Can't commit outside transaction mode")
|
|
198
209
|
|
|
199
210
|
self._trans.commit()
|
|
200
211
|
|
|
201
212
|
|
|
202
213
|
def rollback(self) -> None:
|
|
203
214
|
if not self.in_transaction():
|
|
204
|
-
raise
|
|
215
|
+
raise OutsideTransactionError("Can't rollback outside transaction mode")
|
|
205
216
|
|
|
206
217
|
self._trans.rollback()
|
|
207
218
|
|
|
@@ -242,7 +253,7 @@ class ConnectionManager:
|
|
|
242
253
|
def tx_conn(self) -> sqlite3.Connection:
|
|
243
254
|
""" Gives access to connection while in transaction """
|
|
244
255
|
if not self.in_transaction():
|
|
245
|
-
raise
|
|
256
|
+
raise OutsideTransactionError("`tx_conn` is not available outside the transaction mode")
|
|
246
257
|
return self._trans
|
|
247
258
|
|
|
248
259
|
|
|
@@ -250,6 +261,6 @@ class ConnectionManager:
|
|
|
250
261
|
def tx_cursor(self) -> sqlite3.Cursor:
|
|
251
262
|
""" Gives access to connection cursor while in transaction """
|
|
252
263
|
if not self.in_transaction():
|
|
253
|
-
raise
|
|
264
|
+
raise OutsideTransactionError("`tx_cursor` is not available outside the transaction mode")
|
|
254
265
|
return self._trans_cursor
|
|
255
266
|
|
|
@@ -2,10 +2,11 @@ from typing import Sequence, Literal, Generator, Self
|
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
|
|
4
4
|
from . import sqlgen as sql
|
|
5
|
-
from .
|
|
5
|
+
from .connection_manager import ConnectionManager
|
|
6
6
|
|
|
7
7
|
from .types import SqlValue, SqlRow, Schema
|
|
8
8
|
from .repr import to_html
|
|
9
|
+
from ..exceptions import SqlEngineError, OutsideTransactionError
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class Where[T : "Statement"]:
|
|
@@ -146,7 +147,7 @@ class Statement(ABC):
|
|
|
146
147
|
|
|
147
148
|
self._tableschema = tableschema
|
|
148
149
|
self._connection = connection
|
|
149
|
-
self._where
|
|
150
|
+
self._where = Where(self)
|
|
150
151
|
|
|
151
152
|
self._custom_query : str | None = None
|
|
152
153
|
self._custom_args : tuple[SqlValue, ...] = ()
|
|
@@ -206,6 +207,7 @@ class Statement(ABC):
|
|
|
206
207
|
class MutationalStatement(Statement, ABC):
|
|
207
208
|
|
|
208
209
|
def execute(self) -> None:
|
|
210
|
+
""" Execute built statement """
|
|
209
211
|
query, args = self.build()
|
|
210
212
|
self._connection.execute(query, *args)
|
|
211
213
|
|
|
@@ -222,46 +224,52 @@ class Select(Statement):
|
|
|
222
224
|
|
|
223
225
|
|
|
224
226
|
def __call__(self, *columns : str) -> Self:
|
|
227
|
+
""" Shortcut to columns selector """
|
|
225
228
|
return self.columns(*columns)
|
|
226
229
|
|
|
227
230
|
|
|
228
231
|
def columns(self, *columns : str) -> Self:
|
|
229
|
-
"""
|
|
232
|
+
""" Columns selector """
|
|
230
233
|
self._columns.extend(columns)
|
|
231
234
|
return self
|
|
232
235
|
|
|
233
236
|
|
|
234
237
|
def aggregate(self, by : Literal['COUNT', 'SUM', 'AVG', 'MIN', 'MAX']) -> Self:
|
|
235
|
-
|
|
238
|
+
""" Aggregate by provided method """
|
|
236
239
|
if self._aggregate:
|
|
237
|
-
raise
|
|
240
|
+
raise SqlEngineError("Can't aggregate columns multiple times")
|
|
238
241
|
|
|
239
242
|
self._aggregate = by
|
|
240
243
|
return self
|
|
241
244
|
|
|
242
245
|
|
|
243
246
|
def order_by(self, column : str, ascending : bool = True) -> Self:
|
|
247
|
+
""" Orders returned rows by provided column """
|
|
244
248
|
order = "ASC" if ascending else "DESC"
|
|
245
249
|
self._order_by.append(f"{column} {order}")
|
|
246
250
|
return self
|
|
247
251
|
|
|
248
252
|
|
|
249
253
|
def limit(self, n : int) -> Self:
|
|
254
|
+
""" Limit number of returned rows """
|
|
250
255
|
self._limit = n
|
|
251
256
|
return self
|
|
252
257
|
|
|
253
258
|
|
|
254
259
|
def fetchone(self) -> SqlRow:
|
|
260
|
+
""" Fetch first row """
|
|
255
261
|
query, args = self.build()
|
|
256
262
|
return self._connection.fetchone(query, *args)
|
|
257
263
|
|
|
258
264
|
|
|
259
265
|
def fetchmany(self, size : int = 1) -> list[SqlRow]:
|
|
266
|
+
""" Fetch first `size` rows """
|
|
260
267
|
query, args = self.build()
|
|
261
268
|
return self._connection.fetchmany(query, *args, size=size)
|
|
262
269
|
|
|
263
270
|
|
|
264
271
|
def fetchall(self) -> list[SqlRow]:
|
|
272
|
+
""" Fetch all rows """
|
|
265
273
|
query, args = self.build()
|
|
266
274
|
return self._connection.fetchall(query, *args)
|
|
267
275
|
|
|
@@ -275,13 +283,15 @@ class Select(Statement):
|
|
|
275
283
|
|
|
276
284
|
Examples:
|
|
277
285
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
286
|
+
```python
|
|
287
|
+
with table.transaction():
|
|
288
|
+
for batch in table.select.where.gt("Age", 30).then.fetchmany_iterator(1000):
|
|
289
|
+
process_batch(batch)
|
|
290
|
+
```
|
|
281
291
|
"""
|
|
282
292
|
if not self._connection.in_transaction():
|
|
283
|
-
raise
|
|
284
|
-
to keep open the transaction of the table
|
|
293
|
+
raise OutsideTransactionError("To use the `fetchall_iterator()` method you have \
|
|
294
|
+
to keep open the transaction of the table")
|
|
285
295
|
|
|
286
296
|
query, exec_args = self.build()
|
|
287
297
|
|
|
@@ -293,11 +303,22 @@ class Select(Statement):
|
|
|
293
303
|
|
|
294
304
|
|
|
295
305
|
def __iter__(self) -> Generator[SqlRow, None, None]:
|
|
296
|
-
"""
|
|
306
|
+
"""
|
|
307
|
+
Select statement rows iterator
|
|
308
|
+
|
|
309
|
+
Examples:
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
with table.transaction():
|
|
313
|
+
# here `then` is used to link back to the `select` instance from `where` object
|
|
314
|
+
for row in table.select.where.gt("Age", 30).then:
|
|
315
|
+
process_row(row)
|
|
316
|
+
```
|
|
317
|
+
"""
|
|
297
318
|
|
|
298
319
|
if not self._connection.in_transaction():
|
|
299
|
-
raise
|
|
300
|
-
to keep open the transaction of the table
|
|
320
|
+
raise OutsideTransactionError("To use the __iter__ method you have \
|
|
321
|
+
to keep open the transaction of the table")
|
|
301
322
|
|
|
302
323
|
query, exec_args = self.build()
|
|
303
324
|
|
|
@@ -360,7 +381,7 @@ class Delete(MutationalStatement):
|
|
|
360
381
|
def _build(self, where_clause : str, *args : SqlValue) -> tuple[str, tuple[SqlValue, ...]]:
|
|
361
382
|
|
|
362
383
|
if not where_clause:
|
|
363
|
-
raise
|
|
384
|
+
raise SqlEngineError("Delete statement must have a where clause")
|
|
364
385
|
|
|
365
386
|
query = sql.delete_rows(self._tableschema["tablename"], where_clause)
|
|
366
387
|
return query, args
|
|
@@ -379,6 +400,7 @@ class Update(MutationalStatement):
|
|
|
379
400
|
|
|
380
401
|
|
|
381
402
|
def __call__(self, column : str, value : SqlValue) -> Self:
|
|
403
|
+
""" Shortcut to set value to a column """
|
|
382
404
|
return self.set(column, value)
|
|
383
405
|
|
|
384
406
|
|
|
@@ -12,15 +12,16 @@ class CustomType(Protocol):
|
|
|
12
12
|
...
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
type SqlValue
|
|
16
|
-
type SqlRow
|
|
17
|
-
type SqlType
|
|
15
|
+
type SqlValue = str | int | float | bytes | None | CustomType
|
|
16
|
+
type SqlRow = tuple[SqlValue, ...]
|
|
17
|
+
type SqlType = type[str | int | float | bytes | CustomType]
|
|
18
|
+
type ColumnType = SqlType | str | UnionType
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class Schema(TypedDict):
|
|
21
22
|
tablename : str
|
|
22
23
|
columns : list[str]
|
|
23
|
-
types : list[
|
|
24
|
+
types : list[ColumnType]
|
|
24
25
|
primary : list[str]
|
|
25
26
|
|
|
26
27
|
|
|
@@ -41,7 +42,7 @@ _TYPES_MAP : dict[type | UnionType, str] = {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
|
|
44
|
-
def is_custom_type(type_: SqlType) -> TypeGuard[type[CustomType]]:
|
|
45
|
+
def is_custom_type(type_: SqlType | UnionType) -> TypeGuard[type[CustomType]]:
|
|
45
46
|
return (
|
|
46
47
|
type_ not in (str, int, float, bytes)
|
|
47
48
|
and isinstance(type_, type)
|
|
@@ -52,7 +53,7 @@ def is_custom_type(type_: SqlType) -> TypeGuard[type[CustomType]]:
|
|
|
52
53
|
|
|
53
54
|
def register_type(cls : type[CustomType], type_name : str | None = None) -> None:
|
|
54
55
|
"""
|
|
55
|
-
Register custom type to be able to store it in tables
|
|
56
|
+
Register custom type into sqlite3 to be able to store it in tables
|
|
56
57
|
|
|
57
58
|
Args:
|
|
58
59
|
cls (CustomType): Class that implements `from_sql(cls, sql : bytes) -> Self` and `
|
|
@@ -65,7 +66,7 @@ def register_type(cls : type[CustomType], type_name : str | None = None) -> None
|
|
|
65
66
|
sqlite3.register_converter(type_name, cls.from_sql)
|
|
66
67
|
|
|
67
68
|
|
|
68
|
-
def pytype_to_sqltype(type_ : type) -> str:
|
|
69
|
+
def pytype_to_sqltype(type_ : type | UnionType) -> str:
|
|
69
70
|
""" Converts python type to sql type """
|
|
70
71
|
if type_ not in _TYPES_MAP:
|
|
71
72
|
raise TypeError(f"{type_} is not natively supported by sqlite3")
|
|
@@ -73,7 +74,7 @@ def pytype_to_sqltype(type_ : type) -> str:
|
|
|
73
74
|
return _TYPES_MAP[type_]
|
|
74
75
|
|
|
75
76
|
|
|
76
|
-
def register_resolve_types(types : list[
|
|
77
|
+
def register_resolve_types(types : list[ColumnType], **connection_params) -> tuple[list[str], dict[str, Any]]:
|
|
77
78
|
""" Converts py types to sql types, registers custom types, resolves type names, updates connection params """
|
|
78
79
|
|
|
79
80
|
resolved : list[str] = []
|
sqlengine/exceptions.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
class SqlEngineError(Exception):
|
|
3
|
+
""" Errors linked to sqlengine module """
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
class TransactionError(SqlEngineError):
|
|
7
|
+
""" Errors within transactions """
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
class OutsideTransactionError(TransactionError):
|
|
11
|
+
""" Errors of prohibited outside tranasctions operations """
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
class NestedTransactionError(TransactionError):
|
|
15
|
+
""" Errors of nested transaction operations """
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
class TableDeclarationError(SqlEngineError):
|
|
19
|
+
""" Errors of table declaration """
|
|
20
|
+
pass
|
sqlengine/schema.py
CHANGED
sqlengine/sqltable.py
CHANGED
|
@@ -5,13 +5,15 @@ import sqlite3
|
|
|
5
5
|
from typing import Sequence, Literal, Any
|
|
6
6
|
from typing import get_origin, get_args, overload, get_type_hints
|
|
7
7
|
|
|
8
|
-
from .
|
|
9
|
-
from .core.repr import to_html
|
|
8
|
+
from .exceptions import TableDeclarationError
|
|
10
9
|
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
13
|
-
|
|
14
|
-
from .
|
|
10
|
+
from ._internal import sqlgen as sql
|
|
11
|
+
from ._internal.repr import to_html
|
|
12
|
+
|
|
13
|
+
from ._internal import ConnectionManager, Select, Update, Delete
|
|
14
|
+
from ._internal.types import SqlRow, SqlValue, ColumnType
|
|
15
|
+
from ._internal.types import Schema, Primary
|
|
16
|
+
from ._internal.types import register_resolve_types
|
|
15
17
|
|
|
16
18
|
logger = logging.getLogger("sqlengine")
|
|
17
19
|
logger.setLevel(os.getenv("SQL_ENGINE_LOG_LEVEL", "WARNING").upper())
|
|
@@ -23,50 +25,44 @@ class SqlTableMixin:
|
|
|
23
25
|
|
|
24
26
|
Args:
|
|
25
27
|
database (str): database filename to connect to. If it not exists - will create new one first.
|
|
26
|
-
If `":memory:"` is passed, then database will be
|
|
28
|
+
If `":memory:"` is passed, then database will be set in memory and you will have to
|
|
27
29
|
create table manually with `create_table()` method inside `transaction()` block.
|
|
28
30
|
force_drop (bool): If `True` - will drop existing table.
|
|
29
|
-
**connection_params
|
|
30
|
-
Reference: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
|
|
31
|
+
**connection_params: Params to create connection with. Reference: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
|
|
31
32
|
|
|
32
33
|
Attributes:
|
|
33
34
|
__tablename__ (Optional[str]): Name of the table that will be used in queries.
|
|
34
35
|
If omitted in inherited class declaration, then it will take the class name.
|
|
35
|
-
__columns__ (list[str]):
|
|
36
|
-
__types__ (list[
|
|
36
|
+
__columns__ (list[str]): Column names of the table
|
|
37
|
+
__types__ (list[ColumnType]): Column types of the table
|
|
37
38
|
__primary__ (list[str]): List of primary keys
|
|
38
39
|
|
|
39
40
|
Examples:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
>>> name : Primary[str]
|
|
53
|
-
>>> surname : str | None
|
|
54
|
-
>>> salary : float | None
|
|
55
|
-
>>> position : str
|
|
56
|
-
>>>
|
|
57
|
-
>>> table = Employees("mydb.sqlite3")
|
|
41
|
+
```python
|
|
42
|
+
from sqlengine import SqlTableMixin, Primary
|
|
43
|
+
|
|
44
|
+
class Employees(SqlTableMixin):
|
|
45
|
+
ID : Primary[int]
|
|
46
|
+
name : Primary[str]
|
|
47
|
+
surname : str | None
|
|
48
|
+
salary : float | None
|
|
49
|
+
position : str
|
|
50
|
+
|
|
51
|
+
table = Employees("mydb.sqlite3")
|
|
52
|
+
```
|
|
58
53
|
"""
|
|
59
54
|
|
|
60
55
|
__tablename__ : str
|
|
61
56
|
__columns__ : list[str]
|
|
62
|
-
__types__ : list[
|
|
57
|
+
__types__ : list[ColumnType]
|
|
63
58
|
__primary__ : list[str]
|
|
64
59
|
|
|
65
60
|
def __init__(self, database: str | Literal[":memory:"], force_drop : bool = False, **connection_params) -> None:
|
|
66
61
|
|
|
62
|
+
self.database = database
|
|
63
|
+
|
|
67
64
|
resolved_types, connection_params = register_resolve_types(self.__types__, **connection_params)
|
|
68
65
|
|
|
69
|
-
self.database = database
|
|
70
66
|
self._connection_manager = ConnectionManager(database, **connection_params)
|
|
71
67
|
self.__types_sql__ = resolved_types
|
|
72
68
|
|
|
@@ -90,7 +86,7 @@ class SqlTableMixin:
|
|
|
90
86
|
continue
|
|
91
87
|
|
|
92
88
|
if name in columns:
|
|
93
|
-
raise
|
|
89
|
+
raise TableDeclarationError(f"Annotated column `{name}` is already in __columns__")
|
|
94
90
|
|
|
95
91
|
columns.append(name)
|
|
96
92
|
|
|
@@ -99,12 +95,13 @@ class SqlTableMixin:
|
|
|
99
95
|
continue
|
|
100
96
|
|
|
101
97
|
if name in primary:
|
|
102
|
-
raise
|
|
98
|
+
raise TableDeclarationError(f"Annotated primary column `{name}` is already in __primary__")
|
|
103
99
|
|
|
104
100
|
primary_type = get_args(type_)[0]
|
|
105
101
|
|
|
106
102
|
if not primary_type:
|
|
107
|
-
raise
|
|
103
|
+
raise TableDeclarationError(("Primary type was declared without the type. "
|
|
104
|
+
"Usage: `my_column : Primary[T]`, where T is desired type"))
|
|
108
105
|
|
|
109
106
|
types.append(primary_type)
|
|
110
107
|
primary.append(name)
|
|
@@ -128,15 +125,15 @@ class SqlTableMixin:
|
|
|
128
125
|
]
|
|
129
126
|
|
|
130
127
|
if missing_attrs:
|
|
131
|
-
raise
|
|
128
|
+
raise TableDeclarationError(f'{cls.__name__} is missing attributes: {missing_attrs}')
|
|
132
129
|
|
|
133
130
|
n_types, n_cols = len(cls.__types__), len(cls.__columns__)
|
|
134
131
|
|
|
135
132
|
if not n_types == n_cols:
|
|
136
|
-
raise
|
|
133
|
+
raise TableDeclarationError((f'`__types__` and `__columns__`: length mismatch: types = {n_types}, columns = {n_cols}'))
|
|
137
134
|
|
|
138
135
|
if len(cls.__primary__) < 1:
|
|
139
|
-
raise
|
|
136
|
+
raise TableDeclarationError(f'`__primary__`: Number of primary keys must be at least 1')
|
|
140
137
|
|
|
141
138
|
wrong_primaries = [
|
|
142
139
|
prim for prim in cls.__primary__ if
|
|
@@ -144,7 +141,7 @@ class SqlTableMixin:
|
|
|
144
141
|
]
|
|
145
142
|
|
|
146
143
|
if wrong_primaries:
|
|
147
|
-
raise
|
|
144
|
+
raise TableDeclarationError(f'`__primary__`: Keys {wrong_primaries} can\'t be primaries as they are not declared in __columns__')
|
|
148
145
|
|
|
149
146
|
|
|
150
147
|
def _write_db(self, force_drop : bool) -> None:
|
|
@@ -193,10 +190,12 @@ class SqlTableMixin:
|
|
|
193
190
|
autocommit (bool): If `True`, will commit changes at the end of transaction
|
|
194
191
|
|
|
195
192
|
Examples:
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
with table.transaction():
|
|
196
|
+
for idx, age in table.select("ID", "Age"):
|
|
197
|
+
table.update("Age", age + 1).where.eq("ID", idx).then.execute()
|
|
198
|
+
```
|
|
200
199
|
"""
|
|
201
200
|
|
|
202
201
|
return self._connection_manager.transaction(autocommit)
|
|
@@ -207,17 +206,22 @@ class SqlTableMixin:
|
|
|
207
206
|
Insert single row
|
|
208
207
|
|
|
209
208
|
Args:
|
|
210
|
-
*args (
|
|
211
|
-
**kwargs (
|
|
209
|
+
*args (SqlValue): Arguments in order of declared __columns__
|
|
210
|
+
**kwargs (SqlValue): Column to value mapping
|
|
212
211
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
212
|
+
Examples:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
table = MyTable("mydb.db")
|
|
216
|
+
table.columns # -> ["ID", "Name", "Age"]
|
|
217
|
+
table.insert(0, "Daniel", 27)
|
|
218
|
+
table.insert(ID=1, name="Boris", age=26)
|
|
219
|
+
```
|
|
218
220
|
"""
|
|
219
|
-
|
|
220
|
-
|
|
221
|
+
columns = self.columns[:len(args)]
|
|
222
|
+
columns.extend(kwargs.keys())
|
|
223
|
+
query = sql.insert_row(self.tablename, columns)
|
|
224
|
+
self._connection_manager.execute(query, *args, *kwargs.values())
|
|
221
225
|
|
|
222
226
|
|
|
223
227
|
def upsert(self, *args, **kwargs) -> None:
|
|
@@ -226,18 +230,22 @@ class SqlTableMixin:
|
|
|
226
230
|
via the declared `primary` key
|
|
227
231
|
|
|
228
232
|
Args:
|
|
229
|
-
|
|
230
|
-
**kwargs (
|
|
233
|
+
**args (SqlValue): Arguments in order of declared __columns__
|
|
234
|
+
**kwargs (SqlValue): Column to value mapping
|
|
231
235
|
|
|
232
236
|
Example:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
table = MyTable("mydb.db")
|
|
240
|
+
table.columns # -> ["ID", "Name", "Age"]
|
|
241
|
+
table.upsert(0, "Daniel", 27)
|
|
242
|
+
table.upsert(ID=0, age=21)
|
|
243
|
+
```
|
|
238
244
|
"""
|
|
239
|
-
|
|
240
|
-
|
|
245
|
+
columns = self.columns[:len(args)]
|
|
246
|
+
columns.extend(kwargs.keys())
|
|
247
|
+
query = sql.upsert(self.tablename, columns, self.primary)
|
|
248
|
+
self._connection_manager.execute(query, *args, *kwargs.values())
|
|
241
249
|
|
|
242
250
|
|
|
243
251
|
def insert_many(self, rows: Sequence[SqlRow]) -> None:
|
|
@@ -386,19 +394,43 @@ class SqlTableMixin:
|
|
|
386
394
|
|
|
387
395
|
@property
|
|
388
396
|
def update(self) -> Update:
|
|
389
|
-
"""
|
|
397
|
+
"""
|
|
398
|
+
UPDATE statement builder and executor
|
|
399
|
+
|
|
400
|
+
Examples:
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
table.update.set("City", "Karaganda").where.eq("Country", "Czech Republic").then.execute()
|
|
404
|
+
```
|
|
405
|
+
"""
|
|
390
406
|
return Update(self.conn, self.schema)
|
|
391
407
|
|
|
392
408
|
|
|
393
409
|
@property
|
|
394
410
|
def delete(self) -> Delete:
|
|
395
|
-
"""
|
|
411
|
+
"""
|
|
412
|
+
DELETE statement builder and executor
|
|
413
|
+
|
|
414
|
+
Examples:
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
table.delete.where.eq("ID", 0).then.execute()
|
|
418
|
+
```
|
|
419
|
+
"""
|
|
396
420
|
return Delete(self.conn, self.schema)
|
|
397
421
|
|
|
398
422
|
|
|
399
423
|
@property
|
|
400
424
|
def select(self) -> Select:
|
|
401
|
-
"""
|
|
425
|
+
"""
|
|
426
|
+
SELECT statement builder and fetcher
|
|
427
|
+
|
|
428
|
+
Examples:
|
|
429
|
+
|
|
430
|
+
```python
|
|
431
|
+
table.select("Email").where.eq("SupportRepId", 3).then.aggregate("COUNT").fetchone()
|
|
432
|
+
```
|
|
433
|
+
"""
|
|
402
434
|
return Select(self.conn, self.schema)
|
|
403
435
|
|
|
404
436
|
|
|
@@ -409,7 +441,7 @@ class SqlTableMixin:
|
|
|
409
441
|
|
|
410
442
|
|
|
411
443
|
@property
|
|
412
|
-
def types(self) -> list[
|
|
444
|
+
def types(self) -> list[ColumnType]:
|
|
413
445
|
""" List of table column dtypes as declared"""
|
|
414
446
|
return self.__types__
|
|
415
447
|
|
|
@@ -452,7 +484,7 @@ class SqlTableMixin:
|
|
|
452
484
|
|
|
453
485
|
@property
|
|
454
486
|
def conn(self) -> ConnectionManager:
|
|
455
|
-
"""
|
|
487
|
+
""" Access connection manager instance """
|
|
456
488
|
return self._connection_manager
|
|
457
489
|
|
|
458
490
|
|
|
@@ -476,4 +508,4 @@ class SqlTableMixin:
|
|
|
476
508
|
|
|
477
509
|
@connection_params.setter
|
|
478
510
|
def connection_params(self, value : dict[str, Any]) -> None:
|
|
479
|
-
self._connection_manager.connection_params = value
|
|
511
|
+
self._connection_manager.connection_params = value
|
sqlengine/utils/__init__.py
CHANGED
sqlengine/utils/connection.py
CHANGED
|
@@ -4,8 +4,9 @@ import sqlite3
|
|
|
4
4
|
|
|
5
5
|
from contextlib import contextmanager
|
|
6
6
|
|
|
7
|
-
from ..sqltable
|
|
8
|
-
from ..
|
|
7
|
+
from ..sqltable import SqlTableMixin
|
|
8
|
+
from .._internal import ConnectionManager
|
|
9
|
+
from ..exceptions import NestedTransactionError
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
logger = logging.getLogger("sqlengine")
|
|
@@ -26,11 +27,13 @@ def shared_connection(*args : SqlTableMixin, autocommit : bool = True, **connect
|
|
|
26
27
|
|
|
27
28
|
Examples:
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
```python
|
|
31
|
+
from sqlengine.utils import shared_connection
|
|
32
|
+
with shared_connection(table1, table2, **table1.connection_params):
|
|
33
|
+
for (id1,), (id2, temp) in zip(table1.select("ID").limit(20), table2.select("ID", "Temperature").limit(20)):
|
|
34
|
+
if id1 == id2:
|
|
35
|
+
table.update.where.eq("ID", id2).then.set("Salary", temp).execute()
|
|
36
|
+
```
|
|
34
37
|
"""
|
|
35
38
|
|
|
36
39
|
tables_in_trans = [
|
|
@@ -38,7 +41,7 @@ def shared_connection(*args : SqlTableMixin, autocommit : bool = True, **connect
|
|
|
38
41
|
]
|
|
39
42
|
|
|
40
43
|
if tables_in_trans:
|
|
41
|
-
raise
|
|
44
|
+
raise NestedTransactionError(f"Tables {tables_in_trans} are already in transaction")
|
|
42
45
|
|
|
43
46
|
unique_databases = set(table.database for table in args)
|
|
44
47
|
database_map : dict[str, list[ConnectionManager]] = {}
|
sqlengine/utils/convert.py
CHANGED
|
@@ -1,24 +1,129 @@
|
|
|
1
1
|
import csv
|
|
2
|
+
from typing import Generator
|
|
2
3
|
|
|
3
4
|
from ..sqltable import SqlTableMixin
|
|
4
|
-
from ..
|
|
5
|
+
from .._internal.statements import Where, Select
|
|
6
|
+
from .._internal.types import SqlValue
|
|
5
7
|
|
|
6
8
|
|
|
7
|
-
def
|
|
9
|
+
def _get_select(builder : Select | Where[Select] | SqlTableMixin) -> Select:
|
|
8
10
|
|
|
9
11
|
match builder:
|
|
10
12
|
case Where():
|
|
11
|
-
|
|
13
|
+
return builder.then
|
|
12
14
|
case SqlTableMixin():
|
|
13
|
-
|
|
15
|
+
return builder.select
|
|
16
|
+
case Select():
|
|
17
|
+
return builder
|
|
18
|
+
case _:
|
|
19
|
+
raise TypeError(f"Unexpected builder type {type(builder)}")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def to_csv(
|
|
23
|
+
builder : Select | Where[Select] | SqlTableMixin,
|
|
24
|
+
filename : str,
|
|
25
|
+
stream_batch_size : int | None = None
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Writes query or whole table to a csv file
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
builder (Select | Where[Select] | SqlTableMixin): Object to convert to csv
|
|
32
|
+
filename (str): Path to write to
|
|
33
|
+
stream_bach_size (int | None): If not None or 0, will stream all rows to csv in batches of provided size
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
builder = _get_select(builder)
|
|
14
37
|
|
|
15
38
|
if builder._aggregate:
|
|
16
39
|
raise AssertionError("Aggregated queries are not supported")
|
|
17
40
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
if stream_batch_size and not builder._connection.in_transaction():
|
|
42
|
+
raise RuntimeError("To stream to csv you have to keep open the `transaction`")
|
|
43
|
+
|
|
44
|
+
columns = builder._resolve_columns()
|
|
45
|
+
|
|
46
|
+
with open(filename, 'w', newline='') as file:
|
|
22
47
|
writer = csv.writer(file)
|
|
23
48
|
writer.writerow(columns)
|
|
24
|
-
|
|
49
|
+
|
|
50
|
+
if not stream_batch_size:
|
|
51
|
+
repr_rows = builder.fetchall()
|
|
52
|
+
writer.writerows(repr_rows)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
for rows in builder.fetchmany_iterator(stream_batch_size):
|
|
56
|
+
writer.writerows(rows)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def to_dicts(builder : Select | Where[Select] | SqlTableMixin) -> list[dict[str, SqlValue]]:
|
|
60
|
+
"""
|
|
61
|
+
Converts query or whole table to pandas friendly format
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
builder (Select | Where[Select] | SqlTableMixin): Object to convert to list of dicts
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
out (list[dict[str, SqlValue]]): list of rows mappings
|
|
68
|
+
|
|
69
|
+
Examples:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import pandas as pd
|
|
73
|
+
|
|
74
|
+
df = pd.DataFrame(to_dict(table))
|
|
75
|
+
```
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
builder = _get_select(builder)
|
|
79
|
+
|
|
80
|
+
if builder._aggregate:
|
|
81
|
+
raise AssertionError("Aggregated queries are not supported")
|
|
82
|
+
|
|
83
|
+
columns = builder._resolve_columns()
|
|
84
|
+
rows = builder.fetchall()
|
|
85
|
+
|
|
86
|
+
return [dict(zip(columns, row)) for row in rows]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def to_dicts_stream(
|
|
90
|
+
builder : Select | Where[Select] | SqlTableMixin,
|
|
91
|
+
batch_size : int
|
|
92
|
+
) -> Generator[list[dict[str, SqlValue]], None, None]:
|
|
93
|
+
"""
|
|
94
|
+
Converts query or whole table to pandas friendly format and yields it in batches
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
builder (Select | Where[Select] | SqlTableMixin): Object to convert to list of dicts
|
|
98
|
+
batch_size (int): Size of each yiedled batch
|
|
99
|
+
|
|
100
|
+
Yields:
|
|
101
|
+
batch (list[dict[str, SqlValue]]): list of rows mappings
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
import pandas as pd
|
|
107
|
+
|
|
108
|
+
df = pd.DataFrame(columns=table.columns)
|
|
109
|
+
|
|
110
|
+
with table.transaction():
|
|
111
|
+
for batch in to_dict_stream(table, 100):
|
|
112
|
+
df = pd.concat([df, pd.DataFrame(batch)], axis=0)
|
|
113
|
+
|
|
114
|
+
df.set_index("ID", inplace=True)
|
|
115
|
+
```
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
builder = _get_select(builder)
|
|
119
|
+
|
|
120
|
+
if builder._aggregate:
|
|
121
|
+
raise AssertionError("Aggregated queries are not supported")
|
|
122
|
+
|
|
123
|
+
if not builder._connection.in_transaction():
|
|
124
|
+
raise RuntimeError("To stream to csv you have to keep open the `transaction`")
|
|
125
|
+
|
|
126
|
+
columns = builder._resolve_columns()
|
|
127
|
+
|
|
128
|
+
for rows in builder.fetchmany_iterator(batch_size):
|
|
129
|
+
yield [dict(zip(columns, row)) for row in rows]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlengine-lite
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.1
|
|
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
|
|
@@ -27,6 +27,7 @@ Dynamic: license-file
|
|
|
27
27
|
- [Get Item](#get-item)
|
|
28
28
|
- [Custom Types](#custom-types)
|
|
29
29
|
- [Csv Converter](#csv-converter)
|
|
30
|
+
- [Pandas-like Converter](#pandas-like-converter)
|
|
30
31
|
- [Full Documentation](#full-documentation)
|
|
31
32
|
|
|
32
33
|
|
|
@@ -127,25 +128,19 @@ More details at [Declaration](https://github.com/suffermuffin/SQL-Engine/blob/ma
|
|
|
127
128
|
from sqlengine import SqlTableMixin, Primary
|
|
128
129
|
|
|
129
130
|
# Helper constants for column names
|
|
130
|
-
ID
|
|
131
|
-
Name
|
|
131
|
+
ID = "ID"
|
|
132
|
+
Name = "Name"
|
|
132
133
|
Occupation = "Occupation"
|
|
133
|
-
Salary
|
|
134
|
+
Salary = "Salary"
|
|
134
135
|
|
|
135
136
|
|
|
136
137
|
class Employees(SqlTableMixin):
|
|
137
138
|
|
|
138
139
|
ID : Primary[int]
|
|
139
|
-
Name : str
|
|
140
|
+
Name : str | None
|
|
140
141
|
Occupation : str
|
|
141
142
|
Salary : float
|
|
142
143
|
|
|
143
|
-
# You may overwrite your insert methods for type consistency
|
|
144
|
-
def insert(self, id : int, name : str, occupation : str, salary : float) -> None:
|
|
145
|
-
return super().insert(id, name, occupation, salary)
|
|
146
|
-
|
|
147
|
-
def upsert(self, id : int, name : str, occupation : str, salary : float) -> None:
|
|
148
|
-
return super().upsert(id, name, occupation, salary)
|
|
149
144
|
```
|
|
150
145
|
|
|
151
146
|
## Instantiation
|
|
@@ -168,11 +163,16 @@ table = Employees("temp/data.db", force_drop=True)
|
|
|
168
163
|
table.insert(1, "John Doe", "Software Engineer", 75000.0)
|
|
169
164
|
```
|
|
170
165
|
|
|
166
|
+
```py
|
|
167
|
+
# Use kwargs mapping to insert/upsert one row
|
|
168
|
+
|
|
169
|
+
table.insert(2, salary=80000.0, name="Jane Smith", occupation="Data Scientist")
|
|
170
|
+
```
|
|
171
|
+
|
|
171
172
|
```py
|
|
172
173
|
# Bulk insert multiple rows
|
|
173
174
|
|
|
174
175
|
employees_data = [
|
|
175
|
-
(2, "Jane Smith", "Data Scientist", 80000.0),
|
|
176
176
|
(3, "Alice Johnson", "Product Manager", 90000.0),
|
|
177
177
|
(4, "Bob Brown", "Project Manager", 78000.0),
|
|
178
178
|
(5, "Charlie Davis", "UI/UX Designer", 65000.0),
|
|
@@ -322,10 +322,40 @@ to_csv(table, "temp/table.csv")
|
|
|
322
322
|
|
|
323
323
|
```py
|
|
324
324
|
# Save query result to csv
|
|
325
|
-
|
|
326
325
|
to_csv(table.select.where.gt(Salary, 70_000), "temp/query.csv")
|
|
327
326
|
```
|
|
328
327
|
|
|
328
|
+
```py
|
|
329
|
+
# Stream to csv
|
|
330
|
+
with table.transaction():
|
|
331
|
+
to_csv(table, "temp/query.csv", stream_batch_size=1000)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Pandas-like Converter
|
|
335
|
+
|
|
336
|
+
```py
|
|
337
|
+
# via one shot
|
|
338
|
+
import pandas as pd
|
|
339
|
+
from sqlengine.utils import to_dicts
|
|
340
|
+
|
|
341
|
+
df = pd.DataFrame(to_dicts(table))
|
|
342
|
+
df.set_index("ID", inplace=True)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```py
|
|
346
|
+
# via generator
|
|
347
|
+
import pandas as pd
|
|
348
|
+
from sqlengine.utils import to_dicts_stream
|
|
349
|
+
|
|
350
|
+
df = pd.DataFrame(columns=table.columns)
|
|
351
|
+
|
|
352
|
+
with table.transaction():
|
|
353
|
+
for batch in to_dicts_stream(table, batch_size=1000):
|
|
354
|
+
df = pd.concat([df, pd.DataFrame(batch)], axis=0)
|
|
355
|
+
|
|
356
|
+
df.set_index("ID", inplace=True)
|
|
357
|
+
```
|
|
358
|
+
|
|
329
359
|
# Full Documentation
|
|
330
360
|
|
|
331
361
|
For detailed usage, API reference, and advanced examples, see the [full documentation](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/index.md).
|
|
@@ -0,0 +1,18 @@
|
|
|
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,,
|
sqlengine/core/__init__.py
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
sqlengine/__init__.py,sha256=CxA4Z-rx9RfDNBntCbY7wQ7IQGxKc9bcBjHY9g7T8YQ,207
|
|
2
|
-
sqlengine/schema.py,sha256=2PW1RsBgZejozS3xIz63Mu80tSKpJ7pcKyWt8mgWgKA,3687
|
|
3
|
-
sqlengine/sqltable.py,sha256=Oa0CPqBbYZT5TsMK53gRrxIo4vFfhsbLnOYEDgsTUXQ,15652
|
|
4
|
-
sqlengine/core/__init__.py,sha256=1HPCmL4ca9WLFVsgZVtEEirYUF7PwoEGm4G9yrBIiX4,151
|
|
5
|
-
sqlengine/core/connection.py,sha256=Fz9_P8-xKggAEOSk-7Dlqm2so-qXXHyi8yIiCjGBNI8,7876
|
|
6
|
-
sqlengine/core/repr.py,sha256=PEwC3MdOoTE8ORvcVXTCmY502boJfr5V2LU5jJ6qWG0,1478
|
|
7
|
-
sqlengine/core/sqlgen.py,sha256=b8usEqBAX5JDEdMR6Xeaona0ZuOi7vtptl858qXhD78,3473
|
|
8
|
-
sqlengine/core/statements.py,sha256=mAvaM3poFDEWl6cu8FemeCLpRDFGwqM-QKGQym446xM,11683
|
|
9
|
-
sqlengine/core/types.py,sha256=o-P9o4KRjWeubrwDdkEKsSaU7KVEBxazHY6BGaNG2Xw,3185
|
|
10
|
-
sqlengine/utils/__init__.py,sha256=2D55vx-Gzlz0Yjl09zVn3S0tPh3NjbTHbrqw3BZbGL4,115
|
|
11
|
-
sqlengine/utils/connection.py,sha256=bNGMN360FUoxscWv_-YuJA2UEQ0ZQLwjrSwBINXhFmw,3082
|
|
12
|
-
sqlengine/utils/convert.py,sha256=aVpGy0ZC25ZTdeu36gbHxwzdP6je-N8bPVcFrq6HZms,654
|
|
13
|
-
sqlengine_lite-2.2.0.dist-info/licenses/LICENSE,sha256=aepvve4t1ho5uHMQG88dErp5L5CgoNAXctIjMdoceqY,1069
|
|
14
|
-
sqlengine_lite-2.2.0.dist-info/METADATA,sha256=i77esz2My03c_7zqcNYnqvR7CEa9zhQJOrzQjCZUfcs,20190
|
|
15
|
-
sqlengine_lite-2.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
16
|
-
sqlengine_lite-2.2.0.dist-info/top_level.txt,sha256=KG_FG0LCB_mIEu2qJ5LGLQMpan4QmF5d8xLEcqTghCE,10
|
|
17
|
-
sqlengine_lite-2.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|