Fix PostgreSQL compatibility in migrations

- tasks.0002_initial: Remove duplicate user field on Tag model
- tasks.0005_fix_tasks_tags_table: Add PostgreSQL/MySQL/SQLite support
  - Use SERIAL instead of AUTOINCREMENT for PostgreSQL
  - Use UUID type for foreign keys in PostgreSQL
- tasks.0006_fix_task_shares_table: Add PostgreSQL/MySQL/SQLite support
  - Use UUID type and TIMESTAMP in PostgreSQL
  - Use CHAR(32) and DATETIME in MySQL/SQLite

These migrations now detect the database backend and use appropriate
syntax for each database type.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Keith Smith
2025-12-26 17:05:33 -07:00
co-authored by Claude Sonnet 4.5
parent 4e903b688d
commit 0cb1e9508f
2 changed files with 115 additions and 31 deletions
+43 -11
View File
@@ -10,21 +10,53 @@ def fix_tasks_tags_table(apps, schema_editor):
""" """
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
# Check database type
is_postgres = schema_editor.connection.vendor == 'postgresql'
is_mysql = schema_editor.connection.vendor == 'mysql'
# Drop and recreate the tasks_tags table with correct foreign keys # Drop and recreate the tasks_tags table with correct foreign keys
schema_editor.execute( schema_editor.execute(
"DROP TABLE IF EXISTS tasks_tags;" "DROP TABLE IF EXISTS tasks_tags CASCADE;" if is_postgres else "DROP TABLE IF EXISTS tasks_tags;"
) )
schema_editor.execute( if is_postgres:
""" # PostgreSQL syntax
CREATE TABLE tasks_tags ( schema_editor.execute(
id INTEGER PRIMARY KEY AUTOINCREMENT, """
task_id CHAR(32) NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, CREATE TABLE tasks_tags (
tag_id CHAR(32) NOT NULL REFERENCES tags(id) ON DELETE CASCADE, id SERIAL PRIMARY KEY,
UNIQUE (task_id, tag_id) task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
); tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
""" UNIQUE (task_id, tag_id)
) );
"""
)
elif is_mysql:
# MySQL/MariaDB syntax
schema_editor.execute(
"""
CREATE TABLE tasks_tags (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
task_id CHAR(32) NOT NULL,
tag_id CHAR(32) NOT NULL,
UNIQUE (task_id, tag_id),
FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);
"""
)
else:
# SQLite syntax (default)
schema_editor.execute(
"""
CREATE TABLE tasks_tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id CHAR(32) NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
tag_id CHAR(32) NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
UNIQUE (task_id, tag_id)
);
"""
)
# Create indexes for performance # Create indexes for performance
schema_editor.execute( schema_editor.execute(
+72 -20
View File
@@ -10,30 +10,82 @@ def fix_task_shares_table(apps, schema_editor):
""" """
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
# Check database type
is_postgres = schema_editor.connection.vendor == 'postgresql'
is_mysql = schema_editor.connection.vendor == 'mysql'
# Drop and recreate the task_shares table with correct foreign keys # Drop and recreate the task_shares table with correct foreign keys
schema_editor.execute( schema_editor.execute(
"DROP TABLE IF EXISTS task_shares;" "DROP TABLE IF EXISTS task_shares CASCADE;" if is_postgres else "DROP TABLE IF EXISTS task_shares;"
) )
schema_editor.execute( if is_postgres:
""" # PostgreSQL syntax
CREATE TABLE task_shares ( schema_editor.execute(
id CHAR(32) NOT NULL PRIMARY KEY, """
permission VARCHAR(20) NOT NULL, CREATE TABLE task_shares (
sync_id CHAR(32) NOT NULL UNIQUE, id UUID NOT NULL PRIMARY KEY,
created_at DATETIME NOT NULL, permission VARCHAR(20) NOT NULL,
updated_at DATETIME NOT NULL, sync_id UUID NOT NULL UNIQUE,
owner_id CHAR(32) NOT NULL REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED, created_at TIMESTAMP NOT NULL,
shared_with_id CHAR(32) NOT NULL REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED, updated_at TIMESTAMP NOT NULL,
task_id CHAR(32) NULL REFERENCES tasks(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, owner_id UUID NOT NULL REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED,
tag_id CHAR(32) NULL REFERENCES tags(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, shared_with_id UUID NOT NULL REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT share_task_or_tag_not_both CHECK ( task_id UUID NULL REFERENCES tasks(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
(tag_id IS NULL AND task_id IS NOT NULL) OR tag_id UUID NULL REFERENCES tags(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
(tag_id IS NOT NULL AND task_id IS NULL) CONSTRAINT share_task_or_tag_not_both CHECK (
) (tag_id IS NULL AND task_id IS NOT NULL) OR
); (tag_id IS NOT NULL AND task_id IS NULL)
""" )
) );
"""
)
elif is_mysql:
# MySQL/MariaDB syntax
schema_editor.execute(
"""
CREATE TABLE task_shares (
id CHAR(32) NOT NULL PRIMARY KEY,
permission VARCHAR(20) NOT NULL,
sync_id CHAR(32) NOT NULL UNIQUE,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
owner_id CHAR(32) NOT NULL,
shared_with_id CHAR(32) NOT NULL,
task_id CHAR(32) NULL,
tag_id CHAR(32) NULL,
CONSTRAINT share_task_or_tag_not_both CHECK (
(tag_id IS NULL AND task_id IS NOT NULL) OR
(tag_id IS NOT NULL AND task_id IS NULL)
),
FOREIGN KEY (owner_id) REFERENCES users(id),
FOREIGN KEY (shared_with_id) REFERENCES users(id),
FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);
"""
)
else:
# SQLite syntax (default)
schema_editor.execute(
"""
CREATE TABLE task_shares (
id CHAR(32) NOT NULL PRIMARY KEY,
permission VARCHAR(20) NOT NULL,
sync_id CHAR(32) NOT NULL UNIQUE,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
owner_id CHAR(32) NOT NULL REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED,
shared_with_id CHAR(32) NOT NULL REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED,
task_id CHAR(32) NULL REFERENCES tasks(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
tag_id CHAR(32) NULL REFERENCES tags(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT share_task_or_tag_not_both CHECK (
(tag_id IS NULL AND task_id IS NOT NULL) OR
(tag_id IS NOT NULL AND task_id IS NULL)
)
);
"""
)
# Create indexes for foreign keys # Create indexes for foreign keys
schema_editor.execute( schema_editor.execute(