-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsqlite_python.py
More file actions
173 lines (145 loc) · 4.59 KB
/
sqlite_python.py
File metadata and controls
173 lines (145 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
from builtins import RuntimeError
import sqlite3
USER_ID = 100000
def db_connect(database_name: str) -> sqlite3.Connection:
"""
Helper function to connect to sqlite3 from python
This function mostly exists to set the `row_factory` option to
allow 'string' or index based access of row elements and also
to set the important PRAGMA foreign_keys to ON, which means
the database will enforce foreign key constraints (an important
data integrity measure across tables)
"""
db = sqlite3.connect(
database_name,
detect_types=sqlite3.PARSE_DECLTYPES,
uri=database_name.startswith("file:"),
)
db.row_factory = sqlite3.Row
db.execute("PRAGMA foreign_keys = ON;")
return db
# connect to the database
conn = db_connect("books.db")
# Show there are no python books :(
cur = conn.execute(
"""
SELECT
book_id, title, authors, original_publication_year
FROM books
WHERE title like '%' || :title || '%' -- this allows safe, parameterised, wildcard queries
ORDER BY original_publication_year
LIMIT :limit
""",
{"title": "python", "limit": 10},
)
for row in cur:
print(f"{row['book_id']} {row['title']}")
print(
"== Inserting book (Architecture in Python) =============================================="
)
# insert a python book successfully
# Also, insert this to our to_read pile
with conn:
cur = conn.execute(
"""INSERT INTO books(authors, title, original_publication_year, isbn13)
VALUES (:authors, :title, :original_publication_year, :isbn13)
returning book_id""",
{
"authors": "Harry J.W. Percival, Bob Gregory",
"title": "Architecture Patterns With Python",
"original_publication_year": 2020,
"isbn13": "9781492052203",
},
)
book_id = cur.fetchone()[0]
print(f"New book id: {book_id}")
cur = conn.execute(
"""INSERT INTO to_read(book_id, user_id)
VALUES (:book_id, :user_id)
""",
{
"book_id": book_id,
"user_id": USER_ID,
},
)
cur = conn.execute(
"""
SELECT * FROM to_read WHERE user_id = :user_id
""",
{"user_id": USER_ID},
)
print("to_read table (after the first insert):")
for row in cur:
print(f"{row['book_id']=} {row['user_id']=}")
print(
"== Inserting book with an error (Fluent Python) ========================================"
)
# insert a python book
# Also, insert this to our to_read pile
# but then we fail due to a RuntimeError :(
try:
with conn:
cur = conn.execute(
"""
INSERT INTO books(authors, title, original_publication_year)
VALUES (:authors, :title, :original_publication_year)
returning book_id
""",
{
"authors": "Luciano Ramalho",
"title": "Fluent Python",
"original_publication_year": 2015,
},
)
book_id = cur.fetchone()[0]
print(f"New book id: {book_id}")
# use this in our to_read insert statement
cur = conn.execute(
"""INSERT INTO to_read(book_id, user_id)
VALUES (:book_id, :user_id)
""",
{
"book_id": book_id,
"user_id": USER_ID,
},
)
cur = conn.execute(
"""
SELECT * FROM to_read WHERE user_id = :user_id
""",
{"user_id": USER_ID},
)
print("to_read table (just before the error, still in the transaction):")
for row in cur:
print(f"{row['book_id']=} {row['user_id']=}")
print("Both our books are in the to read pile")
raise RuntimeError("Stop transaction")
except Exception:
print("Ooops, we failed!")
print("== Querying after the error, outside the transaction =======================")
# Onlyone row in the to_read table
cur = conn.execute(
"""
SELECT * FROM to_read WHERE user_id = :user_id
""",
{"user_id": USER_ID},
)
print("to_read table (just after the error):")
for row in cur:
print(f"{row['book_id']=} {row['user_id']=}")
# Show there is a python book!
cur = conn.execute(
"""
SELECT
book_id, title, authors, original_publication_year
FROM books
WHERE title like '%' || :title || '%' -- this allows safe, parameterised, wildcard queries
ORDER BY original_publication_year
LIMIT :limit
""",
{"title": "python", "limit": 10},
)
print("books results (just after the error)")
for row in cur:
print(f"{row['book_id']} {row['title']} {row['authors']}")
conn.close()