You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# PSQLPy - Async PostgreSQL driver for Python written in Rust.
7
6
8
7
Driver for PostgreSQL written fully in Rust and exposed to Python.
9
8
The project is under active development and _**we cannot confirm that it's ready for production**_. Anyway, We will be grateful for the bugs found and open issues. Stay tuned.
10
-
*Normal documentation is in development.*
9
+
_Normal documentation is in development._
11
10
12
11
## Installation
13
12
14
13
You can install package with `pip` or `poetry`.
15
14
16
15
poetry:
16
+
17
17
```bash
18
18
> poetry add psqlpy
19
19
```
20
+
20
21
pip:
22
+
21
23
```bash
22
24
> pip install psqlpy
23
25
```
24
26
25
27
Or you can build it by yourself. To do it, install stable rust and [maturin](https://github.com/PyO3/maturin).
28
+
26
29
```
27
30
> maturin develop --release
28
31
```
29
32
30
33
## Usage
34
+
31
35
Usage is as easy as possible.
32
36
Create new instance of PSQLPool, startup it and start querying.
37
+
33
38
```python
34
39
from typing import Any
35
40
@@ -57,11 +62,14 @@ async def main() -> None:
57
62
# rust does it instead.
58
63
59
64
```
65
+
60
66
Please take into account that each new execute gets new connection from connection pool.
61
67
62
68
### DSN support
69
+
63
70
You can separate specify `host`, `port`, `username`, etc or specify everything in one `DSN`.
64
71
**Please note that if you specify DSN any other argument doesn't take into account.**
72
+
65
73
```py
66
74
from typing import Any
67
75
@@ -86,31 +94,33 @@ async def main() -> None:
86
94
```
87
95
88
96
### Control connection recycling
97
+
89
98
There are 3 available options to control how a connection is recycled - `Fast`, `Verified` and `Clean`.
90
99
As connection can be closed in different situations on various sides you can select preferable behavior of how a connection is recycled.
91
100
92
101
-`Fast`: Only run `is_closed()` when recycling existing connections.
93
102
-`Verified`: Run `is_closed()` and execute a test query. This is slower, but guarantees that the database connection is ready to
94
-
be used. Normally, `is_closed()` should be enough to filter
95
-
out bad connections, but under some circumstances (i.e. hard-closed
96
-
network connections) it's possible that `is_closed()`
97
-
returns `false` while the connection is dead. You will receive an error
98
-
on your first query then.
103
+
be used. Normally, `is_closed()` should be enough to filter
104
+
out bad connections, but under some circumstances (i.e. hard-closed
105
+
network connections) it's possible that `is_closed()`
106
+
returns `false` while the connection is dead. You will receive an error
107
+
on your first query then.
99
108
-`Clean`: Like [`Verified`] query method, but instead use the following sequence of statements which guarantees a pristine connection:
100
-
```sql
101
-
CLOSE ALL;
102
-
SET SESSION AUTHORIZATION DEFAULT;
103
-
RESET ALL;
104
-
UNLISTEN *;
105
-
SELECT pg_advisory_unlock_all();
106
-
DISCARD TEMP;
107
-
DISCARD SEQUENCES;
108
-
```
109
-
This is similar to calling `DISCARD ALL`. but doesn't call
110
-
`DEALLOCATE ALL` and `DISCARD PLAN`, so that the statement cache is not
111
-
rendered ineffective.
109
+
```sql
110
+
CLOSE ALL;
111
+
SET SESSION AUTHORIZATION DEFAULT;
112
+
RESET ALL;
113
+
UNLISTEN *;
114
+
SELECT pg_advisory_unlock_all();
115
+
DISCARD TEMP;
116
+
DISCARD SEQUENCES;
117
+
```
118
+
This is similar to calling `DISCARD ALL`. but doesn't call
119
+
`DEALLOCATE ALL` and `DISCARD PLAN`, so that the statement cache is not
120
+
rendered ineffective.
112
121
113
122
## Query parameters
123
+
114
124
You can pass parameters into queries.
115
125
Parameters can be passed in any `execute` method as the second parameter, it must be a list.
116
126
Any placeholder must be marked with `$< num>`.
@@ -123,7 +133,9 @@ Any placeholder must be marked with `$< num>`.
123
133
```
124
134
125
135
## Connection
136
+
126
137
You can work with connection instead of DatabasePool.
138
+
127
139
```python
128
140
from typing import Any
129
141
@@ -154,17 +166,22 @@ async def main() -> None:
154
166
```
155
167
156
168
## Transactions
169
+
157
170
Of course it's possible to use transactions with this driver.
158
171
It's as easy as possible and sometimes it copies common functionality from PsycoPG and AsyncPG.
159
172
160
173
### Transaction parameters
174
+
161
175
In process of transaction creation it is possible to specify some arguments to configure transaction.
162
176
163
177
-`isolation_level`: level of the isolation. By default - `None`.
164
178
-`read_variant`: read option. By default - `None`.
179
+
-`deferrable`: deferrable option. By default - `None`.
165
180
166
181
### You can use transactions as async context managers
182
+
167
183
By default async context manager only begins and commits transaction automatically.
184
+
168
185
```python
169
186
from typing import Any
170
187
@@ -188,6 +205,7 @@ async def main() -> None:
188
205
```
189
206
190
207
### Or you can control transaction fully on your own.
208
+
191
209
```python
192
210
from typing import Any
193
211
@@ -217,9 +235,11 @@ async def main() -> None:
217
235
```
218
236
219
237
### Transactions can be rolled back
238
+
220
239
You must understand that rollback can be executed only once per transaction.
221
240
After it's execution transaction state changes to `done`.
222
241
If you want to use `ROLLBACK TO SAVEPOINT`, see below.
242
+
223
243
```python
224
244
from typing import Any
225
245
@@ -245,6 +265,7 @@ async def main() -> None:
245
265
```
246
266
247
267
### Transaction ROLLBACK TO SAVEPOINT
268
+
248
269
You can rollback your transaction to the specified savepoint, but before it you must create it.
249
270
250
271
```python
@@ -278,6 +299,7 @@ async def main() -> None:
278
299
```
279
300
280
301
### Transaction RELEASE SAVEPOINT
302
+
281
303
It's possible to release savepoint
282
304
283
305
```python
@@ -306,12 +328,15 @@ async def main() -> None:
306
328
```
307
329
308
330
## Cursors
331
+
309
332
Library supports PostgreSQL cursors.
310
333
311
334
Cursors can be created only in transaction. In addition, cursor supports async iteration.
312
335
313
336
### Cursor parameters
337
+
314
338
In process of cursor creation you can specify some configuration parameters.
339
+
315
340
-`querystring`: query for the cursor. Required.
316
341
-`parameters`: parameters for the query. Not Required.
317
342
-`fetch_number`: number of records per fetch if cursor is used as an async iterator. If you are using `.fetch()` method you can pass different fetch number. Not required. Default - 10.
@@ -355,7 +380,9 @@ async def main() -> None:
355
380
```
356
381
357
382
### Cursor operations
383
+
358
384
Available cursor operations:
385
+
359
386
- FETCH count - `cursor.fetch(fetch_number=)`
360
387
- FETCH NEXT - `cursor.fetch_next()`
361
388
- FETCH PRIOR - `cursor.fetch_prior()`
@@ -368,15 +395,16 @@ Available cursor operations:
368
395
- FETCH BACKWARD ALL - `cursor.fetch_backward_all()`
369
396
370
397
## Extra Types
398
+
371
399
Sometimes it's impossible to identify which type user tries to pass as a argument. But Rust is a strongly typed programming language so we have to help.
372
400
373
-
| Extra Type in Python | Type in PostgreSQL | Type in Rust |
374
-
| ------------- | ------------- | -------------
375
-
| SmallInt | SmallInt | i16 |
376
-
| Integer | Integer | i32 |
377
-
| BigInt | BigInt | i64 |
378
-
| PyUUID | UUID | Uuid |
379
-
| PyJSON | JSON, JSONB | Value |
401
+
| Extra Type in Python | Type in PostgreSQL | Type in Rust |
3) PostgreSQL v15. Server is located in other part of the world, because we want to simulate network problems.
433
-
4) Grafana (dashboards)
434
-
5) InfluxDB
435
-
6) JMeter (for load testing)
436
-
437
-
The results are very promising! `PSQLPy` is faster than `AsyncPG` at best by 2 times, at worst by 45%. `PsycoPG` is 3.5 times slower than `PSQLPy` in the worst case, 60% in the best case.
3. PostgreSQL v15. Server is located in other part of the world, because we want to simulate network problems.
463
+
4. Grafana (dashboards)
464
+
5. InfluxDB
465
+
6. JMeter (for load testing)
466
+
467
+
The results are very promising! `PSQLPy` is faster than `AsyncPG` at best by 2 times, at worst by 45%. `PsycoPG` is 3.5 times slower than `PSQLPy` in the worst case, 60% in the best case.
0 commit comments