Adds support for the unified endpoint, for when you want to mix inserts and queries in the same transaction, usually as an easier way to determine why an update failed.
For example, given the following schema:
sql
CREATE TABLE users (
id INTEGER PRIMARY KEY,
uid TEXT UNIQUE NOT NULL,
);
CREATE TABLE projects (
id INTEGER PRIMARY KEY,
uid TEXT UNIQUE NOT NULL,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name TEXT NOT NULL
);
CREATE INDEX projects_user_idx ON projects(user_id);
Then a query to set a projects name by uid, but only if it's owned by the user with the given name, for which you want to distinguish between the project not existing and it being owned by a different user, might be accomplished as follows:
py
import rqdb
import rqdb.connection
import dataclasses
class ProjectDoesNotExistError(Exception):
def __init__(self, uid: str) -> None:
super().__init__(f"there is no project with {uid=}")
self.uid = uid
class ProjectHasDifferentOwnerError(Exception):
def __init__(self, uid: str, required_owner: str, actual_owner: str) -> None:
super().__init__(f"project {uid=} is owned by {actual_owner=} but was requested by {required_owner=}")
self.uid = uid
self.required_owner = required_owner
self.actual_owner = actual_owner
def set_project_name(conn: rqdb.connection.Connection, uid: str, name: str, user: str) -> None:
cursor = conn.cursor()
response = cursor.executeunified3(
[
(
"""
UPDATE projects
SET name = ?
WHERE
projects.uid = ?
AND EXISTS (
SELECT 1 FROM users
WHERE
users.id = projects.user_id
AND users.uid = ?
)
""",
(name, uid, user)
),
(
"""
SELECT
users.uid
FROM projects, users
WHERE
projects.uid = ?
AND users.id = projects.user_id
""",
(uid,)
)
]
)
if response[0].rows_affected is not None and response[0].rows_affected > 0:
return
if not response[1].results:
raise ProjectDoesNotExistError(uid)
raise ProjectHasDifferentOwnerError(uid, user, response[1].results[0][0])