initial commit after split
This commit is contained in:
73
alembic/versions/6a7b8c9d0e1f_file_folder_uniqueness.py
Normal file
73
alembic/versions/6a7b8c9d0e1f_file_folder_uniqueness.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""Prevent duplicate active file-folder paths.
|
||||
|
||||
Revision ID: 6a7b8c9d0e1f
|
||||
Revises: 5f6a7b8c9d0e
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
from sqlalchemy import inspect
|
||||
|
||||
revision = "6a7b8c9d0e1f"
|
||||
down_revision = "5f6a7b8c9d0e"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
USER_INDEX = "uq_file_folders_active_user_path"
|
||||
GROUP_INDEX = "uq_file_folders_active_group_path"
|
||||
|
||||
|
||||
def _deduplicate_active_folders() -> None:
|
||||
bind = op.get_bind()
|
||||
rows = bind.execute(sa.text("""
|
||||
SELECT id, tenant_id, owner_type, owner_user_id, owner_group_id, path, created_at
|
||||
FROM file_folders
|
||||
WHERE deleted_at IS NULL
|
||||
ORDER BY created_at ASC, id ASC
|
||||
""")).mappings().all()
|
||||
grouped: dict[tuple[object, ...], list[str]] = defaultdict(list)
|
||||
for row in rows:
|
||||
owner_id = row["owner_user_id"] if row["owner_type"] == "user" else row["owner_group_id"]
|
||||
grouped[(row["tenant_id"], row["owner_type"], owner_id, row["path"])].append(row["id"])
|
||||
duplicate_ids = [folder_id for ids in grouped.values() for folder_id in ids[1:]]
|
||||
if duplicate_ids:
|
||||
bind.execute(
|
||||
sa.text("UPDATE file_folders SET deleted_at = CURRENT_TIMESTAMP WHERE id IN :ids").bindparams(
|
||||
sa.bindparam("ids", expanding=True)
|
||||
),
|
||||
{"ids": duplicate_ids},
|
||||
)
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
_deduplicate_active_folders()
|
||||
existing = {item["name"] for item in inspect(op.get_bind()).get_indexes("file_folders")}
|
||||
if USER_INDEX not in existing:
|
||||
op.create_index(
|
||||
USER_INDEX,
|
||||
"file_folders",
|
||||
["tenant_id", "owner_user_id", "path"],
|
||||
unique=True,
|
||||
sqlite_where=sa.text("owner_type = 'user' AND deleted_at IS NULL"),
|
||||
postgresql_where=sa.text("owner_type = 'user' AND deleted_at IS NULL"),
|
||||
)
|
||||
if GROUP_INDEX not in existing:
|
||||
op.create_index(
|
||||
GROUP_INDEX,
|
||||
"file_folders",
|
||||
["tenant_id", "owner_group_id", "path"],
|
||||
unique=True,
|
||||
sqlite_where=sa.text("owner_type = 'group' AND deleted_at IS NULL"),
|
||||
postgresql_where=sa.text("owner_type = 'group' AND deleted_at IS NULL"),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
existing = {item["name"] for item in inspect(op.get_bind()).get_indexes("file_folders")}
|
||||
if GROUP_INDEX in existing:
|
||||
op.drop_index(GROUP_INDEX, table_name="file_folders")
|
||||
if USER_INDEX in existing:
|
||||
op.drop_index(USER_INDEX, table_name="file_folders")
|
||||
Reference in New Issue
Block a user