Skip to content

Commit bfdaa12

Browse files
authored
Merge pull request from co0lc0der/dev 0.3.6 -> 0.4
release v0.4
2 parents 5c82e48 + 7418c5f commit bfdaa12

25 files changed

+1506
-407
lines changed

README.md

+23-318
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Latest Version](https://img.shields.io/github/release/co0lc0der/simple-query-builder-python?color=orange&style=flat-square)](https://github.com/co0lc0der/simple-query-builder-python/release)
44
![GitHub repo size](https://img.shields.io/github/repo-size/co0lc0der/simple-query-builder-python?label=size&style=flat-square)
55
[![GitHub license](https://img.shields.io/github/license/co0lc0der/simple-query-builder-python?style=flat-square)](https://github.com/co0lc0der/simple-query-builder-python/blob/main/LICENSE.md)
6-
![Python 3.7, 3.8, 3.9, 3.10](https://img.shields.io/pypi/pyversions/simple-query-builder?color=blueviolet&style=flat-square)
6+
![Python 3.7, 3.8, 3.9, 3.10, 3.11, 3.12](https://img.shields.io/pypi/pyversions/simple-query-builder?color=blueviolet&style=flat-square)
77
![PyPI](https://img.shields.io/pypi/v/simple-query-builder?color=yellow&style=flat-square)
88
![PyPI - Downloads](https://img.shields.io/pypi/dm/simple-query-builder?color=darkgreen&style=flat-square)
99

@@ -30,278 +30,33 @@ Or from Github:
3030
pip install https://github.com/co0lc0der/simple-query-builder-python/archive/main.zip
3131
```
3232
## How to use
33-
### Main public methods
34-
- `get_sql()` returns SQL query string which will be executed
35-
- `get_params()` returns a tuple of parameters for a query
36-
- `get_result()` returns query's result
37-
- `get_count()` returns result's rows count
38-
- `get_error()` returns `True` if an error is had
39-
- `get_error_message()` returns an error message if an error is had
40-
- `set_error(message)` sets `_error` to `True` and `_error_message`
41-
- `get_first()` returns the first item of results
42-
- `get_last()` returns the last item of results
43-
- `reset()` resets state to default values
44-
- `all()` executes SQL query and returns all rows of result (`fetchall()`)
45-
- `one()` executes SQL query and returns the first row of result (`fetchone()`)
46-
- `column(col)` executes SQL query and returns the needed column of result by its index or name, `col` is `0` by default
47-
- `pluck(key, col)` executes SQL query and returns a list of tuples/dicts (the key (usually ID) and the needed column of result) by its indexes or names, `key` is `0` and `col` is `1` by default
48-
- `go()` this method is for non `SELECT` queries. it executes SQL query and returns nothing (but returns the last inserted row ID for `INSERT` method)
49-
- `exists()` returns `True` if SQL query has a row and `False` if it hasn't
50-
- `count()` prepares a query with SQL `COUNT(*)` function and executes it
51-
- `query(sql, params, fetch_type, col_index)` executes prepared `sql` with `params`, it can be used for custom queries
52-
- 'SQL' methods are presented in [Usage section](#usage-examples)
53-
5433
### Import the module and init `QueryBuilder` with `Database()`
5534
```python
5635
from simple_query_builder import *
5736

58-
# if you want to get results as a list of dictionaries (by default since 0.3.5)
59-
qb = QueryBuilder(DataBase(), 'my_db.db') # result_dict=True, print_errors=False
60-
61-
# or if you want to get results as a list of tuples (since 0.3.5)
62-
qb = QueryBuilder(DataBase(), 'my_db.db', result_dict=False)
37+
qb = QueryBuilder(DataBase(), 'my_db.db')
6338

64-
# for printing errors into terminal (since 0.3.5)
65-
qb = QueryBuilder(DataBase(), 'my_db.db', print_errors=True)
39+
# or DB in memory
40+
qb = QueryBuilder(DataBase(), ':memory:')
6641
```
6742
### Usage examples
68-
- Select all rows from a table
43+
#### Select all rows from a table
6944
```python
7045
results = qb.select('users').all()
7146
```
47+
Result query
7248
```sql
7349
SELECT * FROM `users`;
7450
```
75-
- Select a row with a condition
76-
```python
77-
results = qb.select('users').where([['id', '=', 10]]).one()
78-
# or since 0.3.4
79-
results = qb.select('users').where([['id', 10]]).one()
80-
```
81-
```sql
82-
SELECT * FROM `users` WHERE `id` = 10;
83-
```
84-
- Select rows with two conditions
51+
#### Select rows with two conditions
8552
```python
8653
results = qb.select('users').where([['id', '>', 1], 'and', ['group_id', '=', 2]]).all()
87-
# or since 0.3.4
88-
results = qb.select('users').where([['id', '>', 1], 'and', ['group_id', 2]]).all()
8954
```
55+
Result query
9056
```sql
9157
SELECT * FROM `users` WHERE (`id` > 1) AND (`group_id` = 2);
9258
```
93-
- Select a row with a `LIKE` and `NOT LIKE` condition
94-
```python
95-
results = qb.select('users').like(['name', '%John%']).all()
96-
# or
97-
results = qb.select('users').where([['name', 'LIKE', '%John%']]).all()
98-
# or since 0.3.5
99-
results = qb.select('users').like('name', '%John%').all()
100-
```
101-
```sql
102-
SELECT * FROM `users` WHERE (`name` LIKE '%John%');
103-
```
104-
```python
105-
results = qb.select('users').not_like(['name', '%John%']).all()
106-
# or
107-
results = qb.select('users').where([['name', 'NOT LIKE', '%John%']]).all()
108-
# or since 0.3.5
109-
results = qb.select('users').not_like('name', '%John%').all()
110-
```
111-
```sql
112-
SELECT * FROM `users` WHERE (`name` NOT LIKE '%John%');
113-
```
114-
- Select a row with a `IS NULL` and `IS NOT NULL` condition (since 0.3.5)
115-
```python
116-
results = qb.select('users').is_null('phone').all()
117-
# or
118-
results = qb.select('users').where([['phone', 'is null']]).all()
119-
```
120-
```sql
121-
SELECT * FROM `users` WHERE (`phone` IS NULL);
122-
```
123-
```python
124-
results = qb.select('customers').is_not_null('address').all()
125-
# or
126-
results = qb.select('customers').not_null('address').all()
127-
# or
128-
results = qb.select('customers').where([['address', 'is not null']]).all()
129-
```
130-
```sql
131-
SELECT * FROM `customers` WHERE (`address` IS NOT NULL);
132-
```
133-
- Select rows with `OFFSET` and `LIMIT`
134-
```python
135-
results = qb.select('posts')\
136-
.where([['user_id', '=', 3]])\
137-
.offset(14)\
138-
.limit(7)\
139-
.all()
140-
# or since 0.3.4
141-
results = qb.select('posts')\
142-
.where([['user_id', 3]])\
143-
.offset(14)\
144-
.limit(7)\
145-
.all()
146-
```
147-
```sql
148-
SELECT * FROM `posts` WHERE (`user_id` = 3) OFFSET 14 LIMIT 7;
149-
```
150-
- Select custom fields with additional SQL
151-
1. `COUNT()`
152-
```python
153-
results = qb.select('users', {'counter': 'COUNT(*)'}).one()
154-
# or
155-
results = qb.count('users').one()
156-
```
157-
```sql
158-
SELECT COUNT(*) AS `counter` FROM `users`;
159-
```
160-
2. `ORDER BY`
161-
```python
162-
results = qb.select({'b': 'branches'}, ['b.id', 'b.name'])\
163-
.where([['b.id', '>', 1], 'and', ['b.parent_id', 1]])\
164-
.order_by('b.id', 'desc')\
165-
.all()
166-
# or since 0.3.4
167-
results = qb.select({'b': 'branches'}, ['b.id', 'b.name'])\
168-
.where([['b.id', '>', 1], 'and', ['b.parent_id', 1]])\
169-
.order_by('b.id desc')\
170-
.all()
171-
```
172-
```sql
173-
SELECT `b`.`id`, `b`.`name` FROM `branches` AS `b`
174-
WHERE (`b`.`id` > 1) AND (`b`.`parent_id` = 1)
175-
ORDER BY `b`.`id` DESC;
176-
```
177-
3. `GROUP BY` and `HAVING`
178-
```python
179-
results = qb.select('posts', ['id', 'category', 'title'])\
180-
.where([['views', '>=', 1000]])\
181-
.group_by('category')\
182-
.all()
183-
```
184-
```sql
185-
SELECT `id`, `category`, `title` FROM `posts`
186-
WHERE (`views` >= 1000) GROUP BY `category`;
187-
```
188-
```python
189-
groups = qb.select('orders', {'month_num': 'MONTH(`created_at`)', 'total': 'SUM(`total`)'})\
190-
.where([['YEAR(`created_at`)', '=', 2020]])\
191-
.group_by('month_num')\
192-
.having([['total', '=', 20000]])\
193-
.all()
194-
# or since 0.3.4
195-
groups = qb.select('orders', {'month_num': 'MONTH(`created_at`)', 'total': 'SUM(`total`)'})\
196-
.where([['YEAR(`created_at`)', 2020]])\
197-
.group_by('month_num')\
198-
.having([['total', 20000]])\
199-
.all()
200-
```
201-
```sql
202-
SELECT MONTH(`created_at`) AS `month_num`, SUM(`total`) AS `total`
203-
FROM `orders` WHERE (YEAR(`created_at`) = 2020)
204-
GROUP BY `month_num` HAVING (`total` = 20000);
205-
```
206-
4. `JOIN`. Supports `INNER`, `LEFT OUTER`, `RIGHT OUTER`, `FULL OUTER` and `CROSS` joins (`INNER` is by default)
207-
```python
208-
results = qb.select({'u': 'users'}, [
209-
'u.id',
210-
'u.email',
211-
'u.username',
212-
{'perms': 'groups.permissions'}
213-
])\
214-
.join('groups', ['u.group_id', 'groups.id'])\
215-
.limit(5)\
216-
.all()
217-
```
218-
```sql
219-
SELECT `u`.`id`, `u`.`email`, `u`.`username`, `groups`.`permissions` AS `perms`
220-
FROM `users` AS `u`
221-
INNER JOIN `groups` ON `u`.`group_id` = `groups`.`id`
222-
LIMIT 5;
223-
```
224-
```python
225-
results = qb.select({'cp': 'cabs_printers'}, [
226-
'cp.id',
227-
'cp.cab_id',
228-
{'cab_name': 'cb.name'},
229-
'cp.printer_id',
230-
{'printer_name': 'p.name'},
231-
{'cartridge_type': 'c.name'},
232-
'cp.comment'
233-
])\
234-
.join({'cb': 'cabs'}, ['cp.cab_id', 'cb.id'])\
235-
.join({'p': 'printer_models'}, ['cp.printer_id', 'p.id'])\
236-
.join({'c': 'cartridge_types'}, 'p.cartridge_id=c.id')\
237-
.where([['cp.cab_id', 'in', [11, 12, 13]], 'or', ['cp.cab_id', '=', 5], 'and', ['p.id', '>', 'c.id']])\
238-
.all()
239-
```
240-
```sql
241-
SELECT `cp`.`id`, `cp`.`cab_id`, `cb`.`name` AS `cab_name`, `cp`.`printer_id`,
242-
`p`.`name` AS `printer_name`, `c`.`name` AS `cartridge_type`, `cp`.`comment`
243-
FROM `cabs_printers` AS `cp`
244-
INNER JOIN `cabs` AS `cb` ON `cp`.`cab_id` = `cb`.`id`
245-
INNER JOIN `printer_models` AS `p` ON `cp`.`printer_id` = `p`.`id`
246-
INNER JOIN `cartridge_types` AS `c` ON p.cartridge_id=c.id
247-
WHERE (`cp`.`cab_id` IN (11, 12, 13)) OR (`cp`.`cab_id` = 5) AND (`p`.`id` > `c`.`id`);
248-
```
249-
```python
250-
# since 0.3.4
251-
results = qb.select({'cp': 'cabs_printers'}, [
252-
'cp.id',
253-
'cp.cab_id',
254-
{'cab_name': 'cb.name'},
255-
'cp.printer_id',
256-
{'cartridge_id': 'c.id'},
257-
{'printer_name': 'p.name'},
258-
{'cartridge_type': 'c.name'},
259-
'cp.comment'
260-
])\
261-
.join({'cb': 'cabs'}, ['cp.cab_id', 'cb.id'])\
262-
.join({'p': 'printer_models'}, ['cp.printer_id', 'p.id'])\
263-
.join({'c': 'cartridge_types'}, ['p.cartridge_id', 'c.id'])\
264-
.group_by(['cp.printer_id', 'cartridge_id'])\
265-
.order_by(['cp.cab_id', 'cp.printer_id desc'])\
266-
.all()
267-
```
268-
```sql
269-
SELECT `cp`.`id`, `cp`.`cab_id`, `cb`.`name` AS `cab_name`, `cp`.`printer_id`, `c`.`id` AS `cartridge_id`,
270-
`p`.`name` AS `printer_name`, `c`.`name` AS `cartridge_type`, `cp`.`comment`
271-
FROM `cabs_printers` AS `cp`
272-
INNER JOIN `cabs` AS `cb` ON `cp`.`cab_id` = `cb`.`id`
273-
INNER JOIN `printer_models` AS `p` ON `cp`.`printer_id` = `p`.`id`
274-
INNER JOIN `cartridge_types` AS `c` ON `p`.`cartridge_id` = `c`.`id`
275-
GROUP BY `cp`.`printer_id`, `cartridge_id`
276-
ORDER BY `cp`.`cab_id` ASC, `cp`.`printer_id` DESC;
277-
```
278-
- Insert a row
279-
```python
280-
new_id = qb.insert('groups', {
281-
'name': 'Moderator',
282-
'permissions': 'moderator'
283-
}).go()
284-
```
285-
```sql
286-
INSERT INTO `groups` (`name`, `permissions`) VALUES ('Moderator', 'moderator');
287-
```
288-
- Insert many rows
289-
```python
290-
qb.insert('groups', [['name', 'role'],
291-
['Moderator', 'moderator'],
292-
['Moderator2', 'moderator'],
293-
['User', 'user'],
294-
['User2', 'user']
295-
]).go()
296-
```
297-
```sql
298-
INSERT INTO `groups` (`name`, `role`)
299-
VALUES ('Moderator', 'moderator'),
300-
('Moderator2', 'moderator'),
301-
('User', 'user'),
302-
('User2', 'user');
303-
```
304-
- Update a row
59+
#### Update a row
30560
```python
30661
qb.update('users', {
30762
'username': 'John Doe',
@@ -310,72 +65,22 @@ qb.update('users', {
31065
.where([['id', '=', 7]])\
31166
.limit()\
31267
.go()
313-
# or since 0.3.4
314-
qb.update('users', {
315-
'username': 'John Doe',
316-
'status': 'new status'
317-
})\
318-
.where([['id', 7]])\
319-
.limit()\
320-
.go()
32168
```
69+
Result query
32270
```sql
32371
UPDATE `users` SET `username` = 'John Doe', `status` = 'new status'
32472
WHERE `id` = 7 LIMIT 1;
32573
```
326-
- Update rows
327-
```python
328-
qb.update('posts', {'status': 'published'})\
329-
.where([['YEAR(`updated_at`)', '>', 2020]])\
330-
.go()
331-
```
332-
```sql
333-
UPDATE `posts` SET `status` = 'published'
334-
WHERE (YEAR(`updated_at`) > 2020);
335-
```
336-
- Delete a row
337-
```python
338-
qb.delete('users')\
339-
.where([['name', '=', 'John']])\
340-
.limit()\
341-
.go()
342-
# or since 0.3.4
343-
qb.delete('users')\
344-
.where([['name', 'John']])\
345-
.limit()\
346-
.go()
347-
```
348-
```sql
349-
DELETE FROM `users` WHERE `name` = 'John' LIMIT 1;
350-
```
351-
- Delete rows
352-
```python
353-
qb.delete('comments')\
354-
.where([['user_id', '=', 10]])\
355-
.go()
356-
# or since 0.3.4
357-
qb.delete('comments')\
358-
.where([['user_id', 10]])\
359-
.go()
360-
```
361-
```sql
362-
DELETE FROM `comments` WHERE `user_id` = 10;
363-
```
364-
- Truncate a table
365-
366-
This method will be moved to another class
367-
```python
368-
qb.truncate('users').go()
369-
```
370-
```sql
371-
TRUNCATE TABLE `users`;
372-
```
373-
- Drop a table
374-
375-
This method will be moved to another class
376-
```python
377-
qb.drop('temporary').go()
378-
```
379-
```sql
380-
DROP TABLE IF EXISTS `temporary`;
381-
```
74+
More examples you can find in [documentation](https://github.com/co0lc0der/simple-query-builder-python/blob/main/docs/index.md)
75+
76+
## ToDo
77+
I'm going to add the next features into future versions
78+
- write more unit testes
79+
- add subqueries for QueryBuilder
80+
- add `BETWEEN`
81+
- add `WHERE EXISTS`
82+
- add TableBuilder class (for beginning `CREATE TABLE`, move `qb.drop()` and `qb.truncate()` into it)
83+
- add MySQL support
84+
- add PostgreSQL support
85+
- add `WITH`
86+
- and probably something more

0 commit comments

Comments
 (0)