sqlengine-lite 2.1.0__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.
- sqlengine_lite-2.1.0/LICENSE +21 -0
- sqlengine_lite-2.1.0/PKG-INFO +287 -0
- sqlengine_lite-2.1.0/README.md +275 -0
- sqlengine_lite-2.1.0/pyproject.toml +22 -0
- sqlengine_lite-2.1.0/setup.cfg +4 -0
- sqlengine_lite-2.1.0/src/sqlengine/__init__.py +7 -0
- sqlengine_lite-2.1.0/src/sqlengine/schema.py +114 -0
- sqlengine_lite-2.1.0/src/sqlengine/sqltable.py +593 -0
- sqlengine_lite-2.1.0/src/sqlengine_lite.egg-info/PKG-INFO +287 -0
- sqlengine_lite-2.1.0/src/sqlengine_lite.egg-info/SOURCES.txt +11 -0
- sqlengine_lite-2.1.0/src/sqlengine_lite.egg-info/dependency_links.txt +1 -0
- sqlengine_lite-2.1.0/src/sqlengine_lite.egg-info/top_level.txt +1 -0
- sqlengine_lite-2.1.0/tests/test.py +848 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 suffermuffin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqlengine-lite
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: Cute sqlite3 wrapper for sql tables
|
|
5
|
+
Project-URL: Homepage, https://github.com/suffermuffin/SQL-Engine
|
|
6
|
+
Project-URL: Repository, https://github.com/suffermuffin/SQL-Engine.git
|
|
7
|
+
Project-URL: Documentation, https://github.com/suffermuffin/SQL-Engine/blob/main/docs/index.md
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
- [Sql-Engine](#sql-engine)
|
|
14
|
+
- [Features](#features)
|
|
15
|
+
- [Purpose](#purpose)
|
|
16
|
+
- [Installation](#installation)
|
|
17
|
+
- [Env](#env)
|
|
18
|
+
- [Quick Start](#quick-start)
|
|
19
|
+
- [Table Declaration](#table-declaration)
|
|
20
|
+
- [Instantiation](#instantiation)
|
|
21
|
+
- [Row insertion](#row-insertion)
|
|
22
|
+
- [Jupyter view](#jupyter-view)
|
|
23
|
+
- [Select Query](#select-query)
|
|
24
|
+
- [Update Query](#update-query)
|
|
25
|
+
- [Delete Query](#delete-query)
|
|
26
|
+
- [Transaction](#transaction)
|
|
27
|
+
- [Get Item](#get-item)
|
|
28
|
+
- [Csv Converter](#csv-converter)
|
|
29
|
+
- [Full Documentation](#full-documentation)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Sql-Engine
|
|
33
|
+
|
|
34
|
+
My Sql-Engine is a cute little wrapper for `sqlite3` table manipulations without any third party dependencies.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
Abstracts SQL queries into tiny little methods like, `insert`, `insert_many`, `upsert`, and not so little and tiny query builders a-la `select`, `delete`, `update`, etc. Sql-Engine also provides bulk insertion and transaction methods, like `insert_many` and `select.fetchmany_iterator`. Methods can be executed in transaction mode thanks to `transaction` context manager.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
Sql-Engine implements Jupyter integration and dynamic schema building. You can easily instantiate existing database table and view it in cute little html representation.
|
|
43
|
+
|
|
44
|
+
```py
|
|
45
|
+
from sqlengine import schema
|
|
46
|
+
|
|
47
|
+
table = schema.table_from_database("temp/chinook.db", "Invoice")
|
|
48
|
+
table
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Invoice</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">InvoiceId</td><td style="border: 1px solid #555; text-align: center;">CustomerId</td><td style="border: 1px solid #555; text-align: center;">InvoiceDate</td><td style="border: 1px solid #555; text-align: center;">BillingAddress</td><td style="border: 1px solid #555; text-align: center;">BillingCity</td><td style="border: 1px solid #555; text-align: center;">BillingState</td><td style="border: 1px solid #555; text-align: center;">BillingCountry</td><td style="border: 1px solid #555; text-align: center;">BillingPostalCode</td><td style="border: 1px solid #555; text-align: center;">Total</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;">2</td><td style="border: 1px solid #000; text-align: center;">2021-01-01 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Stuttgart</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">70174</td><td style="border: 1px solid #000; text-align: center;">1.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">4</td><td style="border: 1px solid #000; text-align: center;">2021-01-02 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Ullevålsveien 14</td><td style="border: 1px solid #000; text-align: center;">Oslo</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Norway</td><td style="border: 1px solid #000; text-align: center;">0171</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">3</td><td style="border: 1px solid #000; text-align: center;">8</td><td style="border: 1px solid #000; text-align: center;">2021-01-03 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Grétrystraat 63</td><td style="border: 1px solid #000; text-align: center;">Brussels</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Belgium</td><td style="border: 1px solid #000; text-align: center;">1000</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td style="border: 1px solid #000; text-align: center;">4</td><td style="border: 1px solid #000; text-align: center;">14</td><td style="border: 1px solid #000; text-align: center;">2021-01-06 00:00:00</td><td style="border: 1px solid #000; text-align: center;">8210 111 ST NW</td><td style="border: 1px solid #000; text-align: center;">Edmonton</td><td style="border: 1px solid #000; text-align: center;">AB</td><td style="border: 1px solid #000; text-align: center;">Canada</td><td style="border: 1px solid #000; text-align: center;">T6G 2C7</td><td style="border: 1px solid #000; text-align: center;">8.91</td></tr><tr><td style="border: 1px solid #000; text-align: center;">5</td><td style="border: 1px solid #000; text-align: center;">23</td><td style="border: 1px solid #000; text-align: center;">2021-01-11 00:00:00</td><td style="border: 1px solid #000; text-align: center;">69 Salem Street</td><td style="border: 1px solid #000; text-align: center;">Boston</td><td style="border: 1px solid #000; text-align: center;">MA</td><td style="border: 1px solid #000; text-align: center;">USA</td><td style="border: 1px solid #000; text-align: center;">2113</td><td style="border: 1px solid #000; text-align: center;">13.86</td></tr><tr><td style="border: 1px solid #000; text-align: center;">6</td><td style="border: 1px solid #000; text-align: center;">37</td><td style="border: 1px solid #000; text-align: center;">2021-01-19 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Berger Straße 10</td><td style="border: 1px solid #000; text-align: center;">Frankfurt</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">60316</td><td style="border: 1px solid #000; text-align: center;">0.99</td></tr><tr><td style="border: 1px solid #000; text-align: center;">7</td><td style="border: 1px solid #000; text-align: center;">38</td><td style="border: 1px solid #000; text-align: center;">2021-02-01 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Barbarossastraße 19</td><td style="border: 1px solid #000; text-align: center;">Berlin</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">10779</td><td style="border: 1px solid #000; text-align: center;">1.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">8</td><td style="border: 1px solid #000; text-align: center;">40</td><td style="border: 1px solid #000; text-align: center;">2021-02-01 00:00:00</td><td style="border: 1px solid #000; text-align: center;">8, Rue Hanovre</td><td style="border: 1px solid #000; text-align: center;">Paris</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">France</td><td style="border: 1px solid #000; text-align: center;">75002</td><td style="border: 1px solid #000; text-align: center;">1.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">9</td><td style="border: 1px solid #000; text-align: center;">42</td><td style="border: 1px solid #000; text-align: center;">2021-02-02 00:00:00</td><td style="border: 1px solid #000; text-align: center;">9, Place Louis Barthou</td><td style="border: 1px solid #000; text-align: center;">Bordeaux</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">France</td><td style="border: 1px solid #000; text-align: center;">33000</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">10</td><td style="border: 1px solid #000; text-align: center;">46</td><td style="border: 1px solid #000; text-align: center;">2021-02-03 00:00:00</td><td style="border: 1px solid #000; text-align: center;">3 Chatham Street</td><td style="border: 1px solid #000; text-align: center;">Dublin</td><td style="border: 1px solid #000; text-align: center;">Dublin</td><td style="border: 1px solid #000; text-align: center;">Ireland</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td colspan="9" style="text-align:center;color:#888;font-style:italic;padding:8px;">... more rows ...</td></tr></tbody></table>
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
You can preview select statements before fetching data to your variables.
|
|
56
|
+
|
|
57
|
+
```py
|
|
58
|
+
table.select("InvoiceId", "CustomerId", "BillingAddress", "BillingCountry", "Total")\
|
|
59
|
+
.where\
|
|
60
|
+
.gte("Total", 2.0)\
|
|
61
|
+
.then\
|
|
62
|
+
.order_by("CustomerId")\
|
|
63
|
+
.limit(10)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Invoice</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">InvoiceId</td><td style="border: 1px solid #555; text-align: center;">CustomerId</td><td style="border: 1px solid #555; text-align: center;">BillingAddress</td><td style="border: 1px solid #555; text-align: center;">BillingCountry</td><td style="border: 1px solid #555; text-align: center;">Total</td></tr></thead><tbody><tr><td style="border: 1px solid #000; text-align: center;">98</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">3.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">121</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">143</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td style="border: 1px solid #000; text-align: center;">327</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">13.86</td></tr><tr><td style="border: 1px solid #000; text-align: center;">382</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">8.91</td></tr><tr><td style="border: 1px solid #000; text-align: center;">12</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">13.86</td></tr><tr><td style="border: 1px solid #000; text-align: center;">67</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">8.91</td></tr><tr><td style="border: 1px solid #000; text-align: center;">219</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">241</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td style="border: 1px solid #000; text-align: center;">99</td><td style="border: 1px solid #000; text-align: center;">3</td><td style="border: 1px solid #000; text-align: center;">1498 rue Bélanger</td><td style="border: 1px solid #000; text-align: center;">Canada</td><td style="border: 1px solid #000; text-align: center;">3.98</td></tr></tbody></table>
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## Purpose
|
|
70
|
+
|
|
71
|
+
It's a tiny little modern ORM 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 paramerized with methods like `select.custom()` and `where.custom()`.
|
|
72
|
+
|
|
73
|
+
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 Sql-Engine, as it uses only native python modules.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
To install `sqlengine`, you can use `pip`:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
pip install sqlengine-lite
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Env
|
|
85
|
+
|
|
86
|
+
You may set environment variable for logging. By default it's `WARNING`.
|
|
87
|
+
|
|
88
|
+
```console
|
|
89
|
+
SQL_ENGINE_LOG_LEVEL=INFO
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
# Quick Start
|
|
93
|
+
|
|
94
|
+
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:
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
_Name of the table that will be used in queries. If omitted in inherited class declaration, then it will take the class name._
|
|
98
|
+
```py
|
|
99
|
+
__tablename__ : Optional[str]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
_Column names of the table_
|
|
103
|
+
```py
|
|
104
|
+
__columns__ : list[str]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
_Column types of the table_
|
|
108
|
+
```py
|
|
109
|
+
__types__ : list[SqlType | str]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
_List of primary keys_
|
|
113
|
+
```py
|
|
114
|
+
__primary__ : list[str]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Table Declaration
|
|
118
|
+
|
|
119
|
+
More details at [Declaration](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#table-declaration).
|
|
120
|
+
|
|
121
|
+
```py
|
|
122
|
+
from sqlengine import SqlTableMixin
|
|
123
|
+
|
|
124
|
+
# Helper constants for column names
|
|
125
|
+
ID = "ID"
|
|
126
|
+
Name = "Name"
|
|
127
|
+
Occupation = "Occupation"
|
|
128
|
+
Salary = "Salary"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class Employees(SqlTableMixin):
|
|
132
|
+
|
|
133
|
+
__columns__ = [ID, Name, Occupation, Salary]
|
|
134
|
+
__types__ = [int, str, str, float]
|
|
135
|
+
__primary__ = [ID]
|
|
136
|
+
|
|
137
|
+
# You may overwrite your insert methods for type consistency
|
|
138
|
+
def insert(self, id : int, name : str, occupation : str, salary : float) -> None:
|
|
139
|
+
return super().insert(id, name, occupation, salary)
|
|
140
|
+
|
|
141
|
+
def upsert(self, id : int, name : str, occupation : str, salary : float) -> None:
|
|
142
|
+
return super().upsert(id, name, occupation, salary)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Instantiation
|
|
146
|
+
|
|
147
|
+
More details at [Instantiation](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#table-instantiation).
|
|
148
|
+
|
|
149
|
+
```py
|
|
150
|
+
# Create an instance of the table class
|
|
151
|
+
# with provided path to create or connect to
|
|
152
|
+
|
|
153
|
+
table = Employees("temp/data.db")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Row insertion
|
|
157
|
+
|
|
158
|
+
```py
|
|
159
|
+
# Insert one row
|
|
160
|
+
|
|
161
|
+
table.insert(1, "John Doe", "Software Engineer", 75000.0)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```py
|
|
165
|
+
# Bulk insert multiple rows
|
|
166
|
+
|
|
167
|
+
employees_data = [
|
|
168
|
+
(2, "Jane Smith", "Data Scientist", 80000.0),
|
|
169
|
+
(3, "Alice Johnson", "Product Manager", 90000.0),
|
|
170
|
+
(4, "Bob Brown", "Project Manager", 78000.0),
|
|
171
|
+
(5, "Charlie Davis", "UI/UX Designer", 65000.0),
|
|
172
|
+
(6, "David Wilson", "DevOps Engineer", 82000.0),
|
|
173
|
+
(7, "Eve Taylor", "Customer Support", 45000.0),
|
|
174
|
+
(8, "Frank White", "Quality Assurance", 53000.0),
|
|
175
|
+
(9, "Grace Hall", "Marketing Manager", 68000.0),
|
|
176
|
+
(10, "Henry Lee", "Technical Writer", 52000.0)
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
table.insert_many(employees_data)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
```py
|
|
184
|
+
# Upsert one row
|
|
185
|
+
|
|
186
|
+
table.upsert(1, "Jane Doe", "Data Scientist", 80000.0)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Jupyter view
|
|
190
|
+
|
|
191
|
+
```py
|
|
192
|
+
# Inspect tables in Jupyter Notebook
|
|
193
|
+
|
|
194
|
+
table
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Employees</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">ID</td><td style="border: 1px solid #555; text-align: center;">Name</td><td style="border: 1px solid #555; text-align: center;">Occupation</td><td style="border: 1px solid #555; text-align: center;">Salary</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;">Jane Doe</td><td style="border: 1px solid #000; text-align: center;">Data Scientist</td><td style="border: 1px solid #000; text-align: center;">80000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Jane Smith</td><td style="border: 1px solid #000; text-align: center;">Data Scientist</td><td style="border: 1px solid #000; text-align: center;">80000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">3</td><td style="border: 1px solid #000; text-align: center;">Alice Johnson</td><td style="border: 1px solid #000; text-align: center;">Product Manager</td><td style="border: 1px solid #000; text-align: center;">90000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">4</td><td style="border: 1px solid #000; text-align: center;">Bob Brown</td><td style="border: 1px solid #000; text-align: center;">Project Manager</td><td style="border: 1px solid #000; text-align: center;">78000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">5</td><td style="border: 1px solid #000; text-align: center;">Charlie Davis</td><td style="border: 1px solid #000; text-align: center;">UI/UX Designer</td><td style="border: 1px solid #000; text-align: center;">65000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">6</td><td style="border: 1px solid #000; text-align: center;">David Wilson</td><td style="border: 1px solid #000; text-align: center;">DevOps Engineer</td><td style="border: 1px solid #000; text-align: center;">82000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">7</td><td style="border: 1px solid #000; text-align: center;">Eve Taylor</td><td style="border: 1px solid #000; text-align: center;">Customer Support</td><td style="border: 1px solid #000; text-align: center;">45000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">8</td><td style="border: 1px solid #000; text-align: center;">Frank White</td><td style="border: 1px solid #000; text-align: center;">Quality Assurance</td><td style="border: 1px solid #000; text-align: center;">53000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">9</td><td style="border: 1px solid #000; text-align: center;">Grace Hall</td><td style="border: 1px solid #000; text-align: center;">Marketing Manager</td><td style="border: 1px solid #000; text-align: center;">68000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">10</td><td style="border: 1px solid #000; text-align: center;">Henry Lee</td><td style="border: 1px solid #000; text-align: center;">Technical Writer</td><td style="border: 1px solid #000; text-align: center;">52000.0</td></tr></tbody></table>
|
|
198
|
+
|
|
199
|
+
## Select Query
|
|
200
|
+
|
|
201
|
+
More details at [Statements](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/statements.md).
|
|
202
|
+
|
|
203
|
+
```py
|
|
204
|
+
# Query select and fetch
|
|
205
|
+
|
|
206
|
+
table.select.where.between(ID, 3, 5).then.fetchall()
|
|
207
|
+
|
|
208
|
+
# ->
|
|
209
|
+
# [(3, 'Alice Johnson', 'Product Manager', 90000.0),
|
|
210
|
+
# (4, 'Bob Brown', 'Project Manager', 78000.0),
|
|
211
|
+
# (5, 'Charlie Davis', 'UI/UX Designer', 65000.0)]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```py
|
|
215
|
+
# Inspect query select in Jupyter
|
|
216
|
+
|
|
217
|
+
table.select(Name, Salary).where.lt(Salary, 70_000)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Employees</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">Name</td><td style="border: 1px solid #555; text-align: center;">Salary</td></tr></thead><tbody><tr><td style="border: 1px solid #000; text-align: center;">Charlie Davis</td><td style="border: 1px solid #000; text-align: center;">65000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Eve Taylor</td><td style="border: 1px solid #000; text-align: center;">45000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Frank White</td><td style="border: 1px solid #000; text-align: center;">53000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Grace Hall</td><td style="border: 1px solid #000; text-align: center;">68000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Henry Lee</td><td style="border: 1px solid #000; text-align: center;">52000.0</td></tr></tbody></table>
|
|
221
|
+
|
|
222
|
+
## Update Query
|
|
223
|
+
|
|
224
|
+
```py
|
|
225
|
+
# equal to ...update.set(Salary, 50_000)...
|
|
226
|
+
table.update(Salary, 50_000).where.eq(Name, "Eve Taylor").then.execute()
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Delete Query
|
|
230
|
+
|
|
231
|
+
```py
|
|
232
|
+
table.delete.where.eq(ID, 5).then.execute()
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Transaction
|
|
236
|
+
|
|
237
|
+
More details at [Transaction](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/transactions.md).
|
|
238
|
+
|
|
239
|
+
```py
|
|
240
|
+
# Operate within a transaction
|
|
241
|
+
|
|
242
|
+
with table.transaction():
|
|
243
|
+
for row in employees_data:
|
|
244
|
+
table.upsert(*row)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Get Item
|
|
248
|
+
|
|
249
|
+
More details at [Syntax Sugar](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/syntax_sugar.md).
|
|
250
|
+
|
|
251
|
+
```py
|
|
252
|
+
# Fetch row by primary key
|
|
253
|
+
|
|
254
|
+
table[9]
|
|
255
|
+
|
|
256
|
+
# -> (9, 'Grace Hall', 'Marketing Manager', 68000.0)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```py
|
|
260
|
+
# Fetch slice by integer primary key
|
|
261
|
+
|
|
262
|
+
table[4:10:2]
|
|
263
|
+
|
|
264
|
+
# ->
|
|
265
|
+
# [(4, 'Bob Brown', 'Project Manager', 78000.0),
|
|
266
|
+
# (6, 'David Wilson', 'DevOps Engineer', 82000.0),
|
|
267
|
+
# (8, 'Frank White', 'Quality Assurance', 53000.0)]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Csv Converter
|
|
271
|
+
|
|
272
|
+
```py
|
|
273
|
+
# Save table to csv
|
|
274
|
+
from sqlengine.utils import to_csv
|
|
275
|
+
|
|
276
|
+
to_csv(table, "temp/table.csv")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```py
|
|
280
|
+
# Save query result to csv
|
|
281
|
+
|
|
282
|
+
to_csv(table.select.where.gt(Salary, 70_000), "temp/query.csv")
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
# Full Documentation
|
|
286
|
+
|
|
287
|
+
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,275 @@
|
|
|
1
|
+
- [Sql-Engine](#sql-engine)
|
|
2
|
+
- [Features](#features)
|
|
3
|
+
- [Purpose](#purpose)
|
|
4
|
+
- [Installation](#installation)
|
|
5
|
+
- [Env](#env)
|
|
6
|
+
- [Quick Start](#quick-start)
|
|
7
|
+
- [Table Declaration](#table-declaration)
|
|
8
|
+
- [Instantiation](#instantiation)
|
|
9
|
+
- [Row insertion](#row-insertion)
|
|
10
|
+
- [Jupyter view](#jupyter-view)
|
|
11
|
+
- [Select Query](#select-query)
|
|
12
|
+
- [Update Query](#update-query)
|
|
13
|
+
- [Delete Query](#delete-query)
|
|
14
|
+
- [Transaction](#transaction)
|
|
15
|
+
- [Get Item](#get-item)
|
|
16
|
+
- [Csv Converter](#csv-converter)
|
|
17
|
+
- [Full Documentation](#full-documentation)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Sql-Engine
|
|
21
|
+
|
|
22
|
+
My Sql-Engine is a cute little wrapper for `sqlite3` table manipulations without any third party dependencies.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
Abstracts SQL queries into tiny little methods like, `insert`, `insert_many`, `upsert`, and not so little and tiny query builders a-la `select`, `delete`, `update`, etc. Sql-Engine also provides bulk insertion and transaction methods, like `insert_many` and `select.fetchmany_iterator`. Methods can be executed in transaction mode thanks to `transaction` context manager.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
Sql-Engine implements Jupyter integration and dynamic schema building. You can easily instantiate existing database table and view it in cute little html representation.
|
|
31
|
+
|
|
32
|
+
```py
|
|
33
|
+
from sqlengine import schema
|
|
34
|
+
|
|
35
|
+
table = schema.table_from_database("temp/chinook.db", "Invoice")
|
|
36
|
+
table
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Invoice</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">InvoiceId</td><td style="border: 1px solid #555; text-align: center;">CustomerId</td><td style="border: 1px solid #555; text-align: center;">InvoiceDate</td><td style="border: 1px solid #555; text-align: center;">BillingAddress</td><td style="border: 1px solid #555; text-align: center;">BillingCity</td><td style="border: 1px solid #555; text-align: center;">BillingState</td><td style="border: 1px solid #555; text-align: center;">BillingCountry</td><td style="border: 1px solid #555; text-align: center;">BillingPostalCode</td><td style="border: 1px solid #555; text-align: center;">Total</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;">2</td><td style="border: 1px solid #000; text-align: center;">2021-01-01 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Stuttgart</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">70174</td><td style="border: 1px solid #000; text-align: center;">1.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">4</td><td style="border: 1px solid #000; text-align: center;">2021-01-02 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Ullevålsveien 14</td><td style="border: 1px solid #000; text-align: center;">Oslo</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Norway</td><td style="border: 1px solid #000; text-align: center;">0171</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">3</td><td style="border: 1px solid #000; text-align: center;">8</td><td style="border: 1px solid #000; text-align: center;">2021-01-03 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Grétrystraat 63</td><td style="border: 1px solid #000; text-align: center;">Brussels</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Belgium</td><td style="border: 1px solid #000; text-align: center;">1000</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td style="border: 1px solid #000; text-align: center;">4</td><td style="border: 1px solid #000; text-align: center;">14</td><td style="border: 1px solid #000; text-align: center;">2021-01-06 00:00:00</td><td style="border: 1px solid #000; text-align: center;">8210 111 ST NW</td><td style="border: 1px solid #000; text-align: center;">Edmonton</td><td style="border: 1px solid #000; text-align: center;">AB</td><td style="border: 1px solid #000; text-align: center;">Canada</td><td style="border: 1px solid #000; text-align: center;">T6G 2C7</td><td style="border: 1px solid #000; text-align: center;">8.91</td></tr><tr><td style="border: 1px solid #000; text-align: center;">5</td><td style="border: 1px solid #000; text-align: center;">23</td><td style="border: 1px solid #000; text-align: center;">2021-01-11 00:00:00</td><td style="border: 1px solid #000; text-align: center;">69 Salem Street</td><td style="border: 1px solid #000; text-align: center;">Boston</td><td style="border: 1px solid #000; text-align: center;">MA</td><td style="border: 1px solid #000; text-align: center;">USA</td><td style="border: 1px solid #000; text-align: center;">2113</td><td style="border: 1px solid #000; text-align: center;">13.86</td></tr><tr><td style="border: 1px solid #000; text-align: center;">6</td><td style="border: 1px solid #000; text-align: center;">37</td><td style="border: 1px solid #000; text-align: center;">2021-01-19 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Berger Straße 10</td><td style="border: 1px solid #000; text-align: center;">Frankfurt</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">60316</td><td style="border: 1px solid #000; text-align: center;">0.99</td></tr><tr><td style="border: 1px solid #000; text-align: center;">7</td><td style="border: 1px solid #000; text-align: center;">38</td><td style="border: 1px solid #000; text-align: center;">2021-02-01 00:00:00</td><td style="border: 1px solid #000; text-align: center;">Barbarossastraße 19</td><td style="border: 1px solid #000; text-align: center;">Berlin</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">10779</td><td style="border: 1px solid #000; text-align: center;">1.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">8</td><td style="border: 1px solid #000; text-align: center;">40</td><td style="border: 1px solid #000; text-align: center;">2021-02-01 00:00:00</td><td style="border: 1px solid #000; text-align: center;">8, Rue Hanovre</td><td style="border: 1px solid #000; text-align: center;">Paris</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">France</td><td style="border: 1px solid #000; text-align: center;">75002</td><td style="border: 1px solid #000; text-align: center;">1.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">9</td><td style="border: 1px solid #000; text-align: center;">42</td><td style="border: 1px solid #000; text-align: center;">2021-02-02 00:00:00</td><td style="border: 1px solid #000; text-align: center;">9, Place Louis Barthou</td><td style="border: 1px solid #000; text-align: center;">Bordeaux</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">France</td><td style="border: 1px solid #000; text-align: center;">33000</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">10</td><td style="border: 1px solid #000; text-align: center;">46</td><td style="border: 1px solid #000; text-align: center;">2021-02-03 00:00:00</td><td style="border: 1px solid #000; text-align: center;">3 Chatham Street</td><td style="border: 1px solid #000; text-align: center;">Dublin</td><td style="border: 1px solid #000; text-align: center;">Dublin</td><td style="border: 1px solid #000; text-align: center;">Ireland</td><td style="border: 1px solid #000; text-align: center;">None</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td colspan="9" style="text-align:center;color:#888;font-style:italic;padding:8px;">... more rows ...</td></tr></tbody></table>
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
You can preview select statements before fetching data to your variables.
|
|
44
|
+
|
|
45
|
+
```py
|
|
46
|
+
table.select("InvoiceId", "CustomerId", "BillingAddress", "BillingCountry", "Total")\
|
|
47
|
+
.where\
|
|
48
|
+
.gte("Total", 2.0)\
|
|
49
|
+
.then\
|
|
50
|
+
.order_by("CustomerId")\
|
|
51
|
+
.limit(10)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Invoice</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">InvoiceId</td><td style="border: 1px solid #555; text-align: center;">CustomerId</td><td style="border: 1px solid #555; text-align: center;">BillingAddress</td><td style="border: 1px solid #555; text-align: center;">BillingCountry</td><td style="border: 1px solid #555; text-align: center;">Total</td></tr></thead><tbody><tr><td style="border: 1px solid #000; text-align: center;">98</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">3.98</td></tr><tr><td style="border: 1px solid #000; text-align: center;">121</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">143</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td style="border: 1px solid #000; text-align: center;">327</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">13.86</td></tr><tr><td style="border: 1px solid #000; text-align: center;">382</td><td style="border: 1px solid #000; text-align: center;">1</td><td style="border: 1px solid #000; text-align: center;">Av. Brigadeiro Faria Lima, 2170</td><td style="border: 1px solid #000; text-align: center;">Brazil</td><td style="border: 1px solid #000; text-align: center;">8.91</td></tr><tr><td style="border: 1px solid #000; text-align: center;">12</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">13.86</td></tr><tr><td style="border: 1px solid #000; text-align: center;">67</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">8.91</td></tr><tr><td style="border: 1px solid #000; text-align: center;">219</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">3.96</td></tr><tr><td style="border: 1px solid #000; text-align: center;">241</td><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Theodor-Heuss-Straße 34</td><td style="border: 1px solid #000; text-align: center;">Germany</td><td style="border: 1px solid #000; text-align: center;">5.94</td></tr><tr><td style="border: 1px solid #000; text-align: center;">99</td><td style="border: 1px solid #000; text-align: center;">3</td><td style="border: 1px solid #000; text-align: center;">1498 rue Bélanger</td><td style="border: 1px solid #000; text-align: center;">Canada</td><td style="border: 1px solid #000; text-align: center;">3.98</td></tr></tbody></table>
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
## Purpose
|
|
58
|
+
|
|
59
|
+
It's a tiny little modern ORM 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 paramerized with methods like `select.custom()` and `where.custom()`.
|
|
60
|
+
|
|
61
|
+
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 Sql-Engine, as it uses only native python modules.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
To install `sqlengine`, you can use `pip`:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
pip install sqlengine-lite
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Env
|
|
73
|
+
|
|
74
|
+
You may set environment variable for logging. By default it's `WARNING`.
|
|
75
|
+
|
|
76
|
+
```console
|
|
77
|
+
SQL_ENGINE_LOG_LEVEL=INFO
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
# Quick Start
|
|
81
|
+
|
|
82
|
+
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:
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_Name of the table that will be used in queries. If omitted in inherited class declaration, then it will take the class name._
|
|
86
|
+
```py
|
|
87
|
+
__tablename__ : Optional[str]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
_Column names of the table_
|
|
91
|
+
```py
|
|
92
|
+
__columns__ : list[str]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
_Column types of the table_
|
|
96
|
+
```py
|
|
97
|
+
__types__ : list[SqlType | str]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
_List of primary keys_
|
|
101
|
+
```py
|
|
102
|
+
__primary__ : list[str]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Table Declaration
|
|
106
|
+
|
|
107
|
+
More details at [Declaration](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#table-declaration).
|
|
108
|
+
|
|
109
|
+
```py
|
|
110
|
+
from sqlengine import SqlTableMixin
|
|
111
|
+
|
|
112
|
+
# Helper constants for column names
|
|
113
|
+
ID = "ID"
|
|
114
|
+
Name = "Name"
|
|
115
|
+
Occupation = "Occupation"
|
|
116
|
+
Salary = "Salary"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Employees(SqlTableMixin):
|
|
120
|
+
|
|
121
|
+
__columns__ = [ID, Name, Occupation, Salary]
|
|
122
|
+
__types__ = [int, str, str, float]
|
|
123
|
+
__primary__ = [ID]
|
|
124
|
+
|
|
125
|
+
# You may overwrite your insert methods for type consistency
|
|
126
|
+
def insert(self, id : int, name : str, occupation : str, salary : float) -> None:
|
|
127
|
+
return super().insert(id, name, occupation, salary)
|
|
128
|
+
|
|
129
|
+
def upsert(self, id : int, name : str, occupation : str, salary : float) -> None:
|
|
130
|
+
return super().upsert(id, name, occupation, salary)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Instantiation
|
|
134
|
+
|
|
135
|
+
More details at [Instantiation](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/table_declaration.md#table-instantiation).
|
|
136
|
+
|
|
137
|
+
```py
|
|
138
|
+
# Create an instance of the table class
|
|
139
|
+
# with provided path to create or connect to
|
|
140
|
+
|
|
141
|
+
table = Employees("temp/data.db")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Row insertion
|
|
145
|
+
|
|
146
|
+
```py
|
|
147
|
+
# Insert one row
|
|
148
|
+
|
|
149
|
+
table.insert(1, "John Doe", "Software Engineer", 75000.0)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```py
|
|
153
|
+
# Bulk insert multiple rows
|
|
154
|
+
|
|
155
|
+
employees_data = [
|
|
156
|
+
(2, "Jane Smith", "Data Scientist", 80000.0),
|
|
157
|
+
(3, "Alice Johnson", "Product Manager", 90000.0),
|
|
158
|
+
(4, "Bob Brown", "Project Manager", 78000.0),
|
|
159
|
+
(5, "Charlie Davis", "UI/UX Designer", 65000.0),
|
|
160
|
+
(6, "David Wilson", "DevOps Engineer", 82000.0),
|
|
161
|
+
(7, "Eve Taylor", "Customer Support", 45000.0),
|
|
162
|
+
(8, "Frank White", "Quality Assurance", 53000.0),
|
|
163
|
+
(9, "Grace Hall", "Marketing Manager", 68000.0),
|
|
164
|
+
(10, "Henry Lee", "Technical Writer", 52000.0)
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
table.insert_many(employees_data)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
```py
|
|
172
|
+
# Upsert one row
|
|
173
|
+
|
|
174
|
+
table.upsert(1, "Jane Doe", "Data Scientist", 80000.0)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Jupyter view
|
|
178
|
+
|
|
179
|
+
```py
|
|
180
|
+
# Inspect tables in Jupyter Notebook
|
|
181
|
+
|
|
182
|
+
table
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Employees</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">ID</td><td style="border: 1px solid #555; text-align: center;">Name</td><td style="border: 1px solid #555; text-align: center;">Occupation</td><td style="border: 1px solid #555; text-align: center;">Salary</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;">Jane Doe</td><td style="border: 1px solid #000; text-align: center;">Data Scientist</td><td style="border: 1px solid #000; text-align: center;">80000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">2</td><td style="border: 1px solid #000; text-align: center;">Jane Smith</td><td style="border: 1px solid #000; text-align: center;">Data Scientist</td><td style="border: 1px solid #000; text-align: center;">80000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">3</td><td style="border: 1px solid #000; text-align: center;">Alice Johnson</td><td style="border: 1px solid #000; text-align: center;">Product Manager</td><td style="border: 1px solid #000; text-align: center;">90000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">4</td><td style="border: 1px solid #000; text-align: center;">Bob Brown</td><td style="border: 1px solid #000; text-align: center;">Project Manager</td><td style="border: 1px solid #000; text-align: center;">78000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">5</td><td style="border: 1px solid #000; text-align: center;">Charlie Davis</td><td style="border: 1px solid #000; text-align: center;">UI/UX Designer</td><td style="border: 1px solid #000; text-align: center;">65000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">6</td><td style="border: 1px solid #000; text-align: center;">David Wilson</td><td style="border: 1px solid #000; text-align: center;">DevOps Engineer</td><td style="border: 1px solid #000; text-align: center;">82000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">7</td><td style="border: 1px solid #000; text-align: center;">Eve Taylor</td><td style="border: 1px solid #000; text-align: center;">Customer Support</td><td style="border: 1px solid #000; text-align: center;">45000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">8</td><td style="border: 1px solid #000; text-align: center;">Frank White</td><td style="border: 1px solid #000; text-align: center;">Quality Assurance</td><td style="border: 1px solid #000; text-align: center;">53000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">9</td><td style="border: 1px solid #000; text-align: center;">Grace Hall</td><td style="border: 1px solid #000; text-align: center;">Marketing Manager</td><td style="border: 1px solid #000; text-align: center;">68000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">10</td><td style="border: 1px solid #000; text-align: center;">Henry Lee</td><td style="border: 1px solid #000; text-align: center;">Technical Writer</td><td style="border: 1px solid #000; text-align: center;">52000.0</td></tr></tbody></table>
|
|
186
|
+
|
|
187
|
+
## Select Query
|
|
188
|
+
|
|
189
|
+
More details at [Statements](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/statements.md).
|
|
190
|
+
|
|
191
|
+
```py
|
|
192
|
+
# Query select and fetch
|
|
193
|
+
|
|
194
|
+
table.select.where.between(ID, 3, 5).then.fetchall()
|
|
195
|
+
|
|
196
|
+
# ->
|
|
197
|
+
# [(3, 'Alice Johnson', 'Product Manager', 90000.0),
|
|
198
|
+
# (4, 'Bob Brown', 'Project Manager', 78000.0),
|
|
199
|
+
# (5, 'Charlie Davis', 'UI/UX Designer', 65000.0)]
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```py
|
|
203
|
+
# Inspect query select in Jupyter
|
|
204
|
+
|
|
205
|
+
table.select(Name, Salary).where.lt(Salary, 70_000)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
<table style="border-collapse: collapse; font-size: 14px;"><caption style="font-size: 18px; font-weight: bold;">Employees</caption><thead><tr><td style="border: 1px solid #555; text-align: center;">Name</td><td style="border: 1px solid #555; text-align: center;">Salary</td></tr></thead><tbody><tr><td style="border: 1px solid #000; text-align: center;">Charlie Davis</td><td style="border: 1px solid #000; text-align: center;">65000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Eve Taylor</td><td style="border: 1px solid #000; text-align: center;">45000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Frank White</td><td style="border: 1px solid #000; text-align: center;">53000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Grace Hall</td><td style="border: 1px solid #000; text-align: center;">68000.0</td></tr><tr><td style="border: 1px solid #000; text-align: center;">Henry Lee</td><td style="border: 1px solid #000; text-align: center;">52000.0</td></tr></tbody></table>
|
|
209
|
+
|
|
210
|
+
## Update Query
|
|
211
|
+
|
|
212
|
+
```py
|
|
213
|
+
# equal to ...update.set(Salary, 50_000)...
|
|
214
|
+
table.update(Salary, 50_000).where.eq(Name, "Eve Taylor").then.execute()
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Delete Query
|
|
218
|
+
|
|
219
|
+
```py
|
|
220
|
+
table.delete.where.eq(ID, 5).then.execute()
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Transaction
|
|
224
|
+
|
|
225
|
+
More details at [Transaction](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/transactions.md).
|
|
226
|
+
|
|
227
|
+
```py
|
|
228
|
+
# Operate within a transaction
|
|
229
|
+
|
|
230
|
+
with table.transaction():
|
|
231
|
+
for row in employees_data:
|
|
232
|
+
table.upsert(*row)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Get Item
|
|
236
|
+
|
|
237
|
+
More details at [Syntax Sugar](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/syntax_sugar.md).
|
|
238
|
+
|
|
239
|
+
```py
|
|
240
|
+
# Fetch row by primary key
|
|
241
|
+
|
|
242
|
+
table[9]
|
|
243
|
+
|
|
244
|
+
# -> (9, 'Grace Hall', 'Marketing Manager', 68000.0)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```py
|
|
248
|
+
# Fetch slice by integer primary key
|
|
249
|
+
|
|
250
|
+
table[4:10:2]
|
|
251
|
+
|
|
252
|
+
# ->
|
|
253
|
+
# [(4, 'Bob Brown', 'Project Manager', 78000.0),
|
|
254
|
+
# (6, 'David Wilson', 'DevOps Engineer', 82000.0),
|
|
255
|
+
# (8, 'Frank White', 'Quality Assurance', 53000.0)]
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Csv Converter
|
|
259
|
+
|
|
260
|
+
```py
|
|
261
|
+
# Save table to csv
|
|
262
|
+
from sqlengine.utils import to_csv
|
|
263
|
+
|
|
264
|
+
to_csv(table, "temp/table.csv")
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
```py
|
|
268
|
+
# Save query result to csv
|
|
269
|
+
|
|
270
|
+
to_csv(table.select.where.gt(Salary, 70_000), "temp/query.csv")
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
# Full Documentation
|
|
274
|
+
|
|
275
|
+
For detailed usage, API reference, and advanced examples, see the [full documentation](https://github.com/suffermuffin/SQL-Engine/blob/main/docs/index.md).
|