"""
refactor: drop 'group_id' from 'resources' table.
"""
import sqlite3
from yoyo import step
__depends__ = {'20230907_02_Enicg-refactor-add-system-and-group-resource-categories'}
def drop_group_id_from_group_user_roles_on_resources(conn):
conn.execute(
"ALTER TABLE group_user_roles_on_resources "
"RENAME TO group_user_roles_on_resources_bkp")
conn.execute(
"""
CREATE TABLE group_user_roles_on_resources (
group_id TEXT NOT NULL,
user_id TEXT NOT NULL,
role_id TEXT NOT NULL,
resource_id TEXT NOT NULL,
PRIMARY KEY (group_id, user_id, role_id, resource_id),
FOREIGN KEY (user_id)
REFERENCES users(user_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (group_id, role_id)
REFERENCES group_roles(group_id, role_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (resource_id)
REFERENCES resources(resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
conn.execute(
"INSERT INTO group_user_roles_on_resources "
"(group_id, user_id, role_id, resource_id)"
"SELECT group_id, user_id, role_id, resource_id "
"FROM group_user_roles_on_resources_bkp")
conn.execute("DROP TABLE IF EXISTS group_user_roles_on_resources_bkp")
def drop_group_id_from_mrna_resources(conn):
conn.execute("ALTER TABLE mrna_resources RENAME TO mrna_resources_bkp")
conn.execute(
"""
CREATE TABLE IF NOT EXISTS mrna_resources
-- Link mRNA data to specific resource
(
resource_id TEXT NOT NULL, -- A resource can have multiple items
data_link_id TEXT NOT NULL,
PRIMARY KEY (resource_id, data_link_id),
UNIQUE (data_link_id) -- ensure data is linked to single resource
FOREIGN KEY (resource_id)
REFERENCES resources(resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id) REFERENCES linked_mrna_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
conn.execute(
"INSERT INTO mrna_resources "
"SELECT resource_id, data_link_id FROM mrna_resources_bkp")
conn.execute("DROP TABLE IF EXISTS mrna_resources_bkp")
def drop_group_id_from_genotype_resources(conn):
conn.execute(
"ALTER TABLE genotype_resources RENAME TO genotype_resources_bkp")
conn.execute(
"""
CREATE TABLE IF NOT EXISTS genotype_resources
-- Link genotype data to specific resource
(
resource_id TEXT NOT NULL, -- A resource can have multiple items
data_link_id TEXT NOT NULL,
PRIMARY KEY (resource_id, data_link_id),
UNIQUE (data_link_id) -- ensure data is linked to single resource
FOREIGN KEY (resource_id)
REFERENCES resources(resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id)
REFERENCES linked_genotype_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
conn.execute(
"INSERT INTO genotype_resources "
"SELECT resource_id, data_link_id FROM genotype_resources_bkp")
conn.execute("DROP TABLE IF EXISTS genotype_resources_bkp")
def drop_group_id_from_phenotype_resources(conn):
conn.execute(
"ALTER TABLE phenotype_resources RENAME TO phenotype_resources_bkp")
conn.execute(
"""
CREATE TABLE IF NOT EXISTS phenotype_resources
-- Link phenotype data to specific resources
(
resource_id TEXT NOT NULL, -- A resource can have multiple data items
data_link_id TEXT NOT NULL,
PRIMARY KEY(resource_id, data_link_id),
UNIQUE (data_link_id), -- ensure data is linked to only one resource
FOREIGN KEY (resource_id)
REFERENCES resources(resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id)
REFERENCES linked_phenotype_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
conn.execute(
"INSERT INTO phenotype_resources "
"SELECT resource_id, data_link_id FROM phenotype_resources_bkp")
conn.execute("DROP TABLE IF EXISTS phenotype_resources_bkp")
def drop_group_id_from_resources_table(conn):
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = OFF")
conn.execute(
"""
CREATE TABLE IF NOT EXISTS resources_new(
resource_id TEXT NOT NULL,
resource_name TEXT NOT NULL UNIQUE,
resource_category_id TEXT NOT NULL,
public INTEGER NOT NULL DEFAULT 0 CHECK (public=0 or public=1),
PRIMARY KEY(resource_id),
FOREIGN KEY(resource_category_id)
REFERENCES resource_categories(resource_category_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
conn.execute(
"INSERT INTO resources_new "
"SELECT resource_id, resource_name, resource_category_id, public "
"FROM resources")
conn.execute("DROP TABLE IF EXISTS resources")
conn.execute("ALTER TABLE resources_new RENAME TO resources")
drop_group_id_from_mrna_resources(conn)
drop_group_id_from_genotype_resources(conn)
drop_group_id_from_phenotype_resources(conn)
drop_group_id_from_group_user_roles_on_resources(conn)
conn.execute("PRAGMA foreign_key_check")
conn.execute("PRAGMA foreign_keys = ON")
def restore_group_id_from_group_user_roles_on_resources(conn):
conn.execute(
"ALTER TABLE group_user_roles_on_resources "
"RENAME TO group_user_roles_on_resources_bkp")
conn.execute(
"""
CREATE TABLE group_user_roles_on_resources (
group_id TEXT NOT NULL,
user_id TEXT NOT NULL,
role_id TEXT NOT NULL,
resource_id TEXT NOT NULL,
PRIMARY KEY (group_id, user_id, role_id, resource_id),
FOREIGN KEY (user_id)
REFERENCES users(user_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (group_id, role_id)
REFERENCES group_roles(group_id, role_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (group_id, resource_id)
REFERENCES resources(group_id, resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
conn.execute(
"INSERT INTO group_user_roles_on_resources "
"(group_id, user_id, role_id, resource_id)"
"SELECT group_id, user_id, role_id, resource_id "
"FROM group_user_roles_on_resources_bkp")
conn.execute("DROP TABLE IF EXISTS group_user_roles_on_resources_bkp")
def restore_group_id_from_mrna_resources(conn, resource_group_map):
conn.execute("ALTER TABLE mrna_resources RENAME TO mrna_resources_bkp")
conn.execute(
"""
CREATE TABLE IF NOT EXISTS mrna_resources
-- Link mRNA data to specific resource
(
group_id TEXT NOT NULL,
resource_id TEXT NOT NULL, -- A resource can have multiple items
data_link_id TEXT NOT NULL,
PRIMARY KEY (resource_id, data_link_id),
UNIQUE (data_link_id) -- ensure data is linked to single resource
FOREIGN KEY (group_id, resource_id)
REFERENCES resources(group_id, resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id) REFERENCES linked_mrna_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
cursor = conn.cursor()
cursor.execute("SELECT * FROM mrna_resources_bkp")
resources = tuple({
"group_id": resource_group_map[row["resource_id"]],
**dict(row)
} for row in cursor.fetchall())
cursor.executemany(
"INSERT INTO mrna_resources(group_id, resource_id, data_link_id) "
"VALUES(:group_id, :resource_id, :data_link_id)",
resources)
conn.execute("DROP TABLE IF EXISTS mrna_resources_bkp")
def restore_group_id_from_genotype_resources(conn, resource_group_map):
conn.execute(
"ALTER TABLE genotype_resources RENAME TO genotype_resources_bkp")
conn.execute(
"""
CREATE TABLE IF NOT EXISTS genotype_resources
-- Link genotype data to specific resource
(
group_id TEXT NOT NULL,
resource_id TEXT NOT NULL, -- A resource can have multiple items
data_link_id TEXT NOT NULL,
PRIMARY KEY (group_id, resource_id, data_link_id),
UNIQUE (data_link_id) -- ensure data is linked to single resource
FOREIGN KEY (group_id, resource_id)
REFERENCES resources(group_id, resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id)
REFERENCES linked_genotype_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
cursor = conn.cursor()
cursor.execute("SELECT * FROM genotype_resources_bkp")
resources = tuple({
"group_id": resource_group_map[row["resource_id"]],
**dict(row)
} for row in cursor.fetchall())
cursor.executemany(
"INSERT INTO genotype_resources(group_id, resource_id, data_link_id) "
"VALUES(:group_id, :resource_id, :data_link_id)",
resources)
conn.execute("DROP TABLE IF EXISTS genotype_resources_bkp")
def restore_group_id_from_phenotype_resources(conn, resource_group_map):
conn.execute(
"ALTER TABLE phenotype_resources RENAME TO phenotype_resources_bkp")
conn.execute(
"""
CREATE TABLE IF NOT EXISTS phenotype_resources
-- Link phenotype data to specific resources
(
group_id TEXT NOT NULL,
resource_id TEXT NOT NULL, -- A resource can have multiple data items
data_link_id TEXT NOT NULL,
PRIMARY KEY(group_id, resource_id, data_link_id),
UNIQUE (data_link_id), -- ensure data is linked to only one resource
FOREIGN KEY (group_id, resource_id)
REFERENCES resources(group_id, resource_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id)
REFERENCES linked_phenotype_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
cursor = conn.cursor()
cursor.execute("SELECT * FROM phenotype_resources_bkp")
resources = tuple({
"group_id": resource_group_map[row["resource_id"]],
**dict(row)
} for row in cursor.fetchall())
cursor.executemany(
"INSERT INTO phenotype_resources(group_id, resource_id, data_link_id) "
"VALUES(:group_id, :resource_id, :data_link_id)",
resources)
conn.execute("DROP TABLE IF EXISTS phenotype_resources_bkp")
def restore_group_id_to_resources_table(conn):
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = OFF")
cursor = conn.cursor()
cursor.execute("ALTER TABLE resources RENAME TO resources_bkp")
cursor.execute(
"SELECT r.*, ro.group_id FROM resources_bkp AS r "
"INNER JOIN resource_ownership AS ro "
"ON r.resource_id=ro.resource_id")
group_resources = tuple(dict(row) for row in cursor.fetchall())
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS resources(
group_id TEXT NOT NULL,
resource_id TEXT NOT NULL,
resource_name TEXT NOT NULL UNIQUE,
resource_category_id TEXT NOT NULL,
public INTEGER NOT NULL DEFAULT 0 CHECK (public=0 or public=1),
PRIMARY KEY(group_id, resource_id),
FOREIGN KEY(group_id)
REFERENCES groups(group_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY(resource_category_id)
REFERENCES resource_categories(resource_category_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID
""")
cursor.executemany(
"INSERT INTO resources"
"(group_id, resource_id, resource_name, resource_category_id)"
"VALUES "
"(:group_id, :resource_id, :resource_name, :resource_category_id)",
group_resources)
cursor.execute("DROP TABLE IF EXISTS resources_bkp")
resource_group_map = {
res["resource_id"]: res["group_id"]
for res in group_resources
}
restore_group_id_from_group_user_roles_on_resources(conn)
restore_group_id_from_mrna_resources(conn, resource_group_map)
restore_group_id_from_genotype_resources(conn, resource_group_map)
restore_group_id_from_phenotype_resources(conn, resource_group_map)
conn.execute("PRAGMA foreign_key_check")
conn.execute("PRAGMA foreign_keys = ON")
steps = [
step(
drop_group_id_from_resources_table, restore_group_id_to_resources_table)
]