use djangos method of wiping sqlite3 tables

Django uses a reference graph to determine the order
in table deletions that occur. Do the same here.

This commit also adds in the `REGEXP` sqlite function,
exactly how Django uses it in its reference graphing.

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2021-06-10 14:18:39 -07:00
parent 5de7ff64df
commit d18cfad63e
3 changed files with 62 additions and 1 deletions

View file

@ -1,6 +1,28 @@
from itertools import chain
import aurweb.db
def references_graph(table):
""" Taken from Django's sqlite3/operations.py. """
query = """
WITH tables AS (
SELECT :table name
UNION
SELECT sqlite_master.name
FROM sqlite_master
JOIN tables ON (sql REGEXP :regexp_1 || tables.name || :regexp_2)
) SELECT name FROM tables;
"""
params = {
"table": table,
"regexp_1": r'(?i)\s+references\s+("|\')?',
"regexp_2": r'("|\')?\s*\(',
}
cursor = aurweb.db.session.execute(query, params=params)
return [row[0] for row in cursor.fetchall()]
def setup_test_db(*args):
""" This function is to be used to setup a test database before
using it. It takes a variable number of table strings, and for
@ -25,8 +47,22 @@ def setup_test_db(*args):
aurweb.db.get_engine()
tables = list(args)
db_backend = aurweb.config.get("database", "backend")
if db_backend != "sqlite":
aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 0")
else:
# We're using sqlite, setup tables to be deleted without violating
# foreign key constraints by graphing references.
tables = set(chain.from_iterable(
references_graph(table) for table in tables))
for table in tables:
aurweb.db.session.execute(f"DELETE FROM {table}")
if db_backend != "sqlite":
aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 1")
# Expunge all objects from SQLAlchemy's IdentityMap.
aurweb.db.session.expunge_all()