Improving history migration 0011

remotes/origin/issue/4795/notification_even_they_are_disabled
Alejandro Alonso 2016-09-20 11:21:43 +02:00 committed by David Barragán Merino
parent aa0095ba58
commit dc623f5c5c
2 changed files with 144 additions and 13 deletions

View File

@ -17,6 +17,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
('userstories', '0012_auto_20160614_1201'), ('userstories', '0012_auto_20160614_1201'),
('projects', '0049_auto_20160629_1443'), ('projects', '0049_auto_20160629_1443'),
('history', '0012_auto_20160629_1036'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
] ]

View File

@ -2,30 +2,160 @@
# Generated by Django 1.9.2 on 2016-06-29 10:36 # Generated by Django 1.9.2 on 2016-06-29 10:36
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations from django.db import migrations, connection
from taiga.projects.history.services import get_instance_from_key from taiga.projects.history.services import get_instance_from_key
def forward_func(apps, schema_editor): GENERATE_CORRECT_HISTORY_ENTRIES_TABLE = """
HistoryEntry = apps.get_model("history", "HistoryEntry") -- Creating a table containing all the existing object keys and the project ids
db_alias = schema_editor.connection.alias DROP TABLE IF EXISTS project_keys;
for entry in HistoryEntry.objects.using(db_alias).all().iterator(): CREATE TABLE project_keys (
instance = get_instance_from_key(entry.key) key VARCHAR,
if type(instance) == apps.get_model("projects", "Project"): project_id INTEGER
entry.project_id = instance.id );
else:
entry.project_id = getattr(instance, 'project_id', None)
entry.save()
HistoryEntry.objects.using(db_alias).filter(project_id__isnull=True).delete() DROP INDEX IF EXISTS project_keys_index;
CREATE INDEX project_keys_index
ON project_keys
USING btree
(key);
INSERT INTO project_keys
SELECT 'milestones.milestone:' || id, project_id
FROM milestones_milestone;
INSERT INTO project_keys
SELECT 'userstories.userstory:' || id, project_id
FROM userstories_userstory;
INSERT INTO project_keys
SELECT 'tasks.task:' || id, project_id
FROM tasks_task;
INSERT INTO project_keys
SELECT 'issues.issue:' || id, project_id
FROM issues_issue;
INSERT INTO project_keys
SELECT 'wiki.wikipage:' || id, project_id
FROM wiki_wikipage;
INSERT INTO project_keys
SELECT 'projects.project:' || id, id
FROM projects_project;
-- Create a table where we will insert all the history_historyentry content with its correct project_id
-- Elements without project_id won't be inserted
DROP TABLE IF EXISTS history_historyentry_correct;
CREATE TABLE history_historyentry_correct AS
SELECT
history_historyentry.id ,
history_historyentry.user,
history_historyentry.created_at,
history_historyentry.type,
history_historyentry.is_snapshot,
history_historyentry.key,
history_historyentry.diff,
history_historyentry.snapshot,
history_historyentry.values,
history_historyentry.comment,
history_historyentry.comment_html,
history_historyentry.delete_comment_date,
history_historyentry.delete_comment_user,
history_historyentry.is_hidden,
history_historyentry.comment_versions,
history_historyentry.edit_comment_date,
project_keys.project_id
FROM history_historyentry
INNER JOIN project_keys
ON project_keys.key = history_historyentry.key;
-- Delete aux table
DROP TABLE IF EXISTS project_keys;
"""
def get_constraints_def_sql(table_name):
cursor = connection.cursor()
query = """
SELECT 'ALTER TABLE "'||nspname||'"."'||relname||'" ADD CONSTRAINT "'||conname||'" '||
pg_get_constraintdef(pg_constraint.oid)||';'
FROM pg_constraint
INNER JOIN pg_class ON conrelid=pg_class.oid
INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace
WHERE relname='{}'
ORDER BY CASE WHEN contype='f' THEN 0 ELSE 1 END DESC,contype DESC,nspname DESC,relname DESC,conname DESC;
""".format(table_name)
cursor.execute(query)
return [row[0] for row in cursor.fetchall()]
def get_indexes_def_sql(table_name):
cursor = connection.cursor()
query = """
SELECT pg_get_indexdef(idx.oid)||';'
FROM pg_index ind
JOIN pg_class idx ON idx.oid = ind.indexrelid
JOIN pg_class tbl ON tbl.oid = ind.indrelid
LEFT JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
WHERE
tbl.relname = '{}' AND
indisprimary=FALSE;
""".format(table_name)
cursor.execute(query)
return [row[0] for row in cursor.fetchall()]
def drop_constraints(table_name):
# This query returns all the ALTER sentences needed to drop the constraints
cursor = connection.cursor()
alter_sentences_query = """
SELECT 'ALTER TABLE "'||nspname||'"."'||relname||'" DROP CONSTRAINT "'||conname||'" '||';'
FROM pg_constraint
INNER JOIN pg_class ON conrelid=pg_class.oid
INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace
WHERE relname='{}'
ORDER BY CASE WHEN contype='f' THEN 0 ELSE 1 END DESC,contype DESC,nspname DESC,relname DESC,conname DESC;
""".format(table_name)
cursor.execute(alter_sentences_query)
alter_sentences = [row[0] for row in cursor.fetchall()]
#Now we execute those sentences
for alter_sentence in alter_sentences:
cursor.execute(alter_sentence)
def toggle_history_entries_tables(apps, schema_editor):
history_entry_sql_def_contraints = get_constraints_def_sql("history_historyentry")
history_entry_sql_def_indexes = get_indexes_def_sql("history_historyentry")
history_change_notifications_sql_def_contraints = get_constraints_def_sql("notifications_historychangenotification_history_entries")
drop_constraints("notifications_historychangenotification_history_entries")
cursor = connection.cursor()
cursor.execute("""
DELETE FROM notifications_historychangenotification_history_entries;
DROP TABLE history_historyentry;
ALTER TABLE "history_historyentry_correct" RENAME to "history_historyentry";
""")
for history_entry_sql_def_contraint in history_entry_sql_def_contraints:
cursor.execute(history_entry_sql_def_contraint)
for history_entry_sql_def_index in history_entry_sql_def_indexes:
cursor.execute(history_entry_sql_def_index)
# Restoring the dropped constraints and indexes
for history_change_notifications_sql_def_contraint in history_change_notifications_sql_def_contraints:
cursor.execute(history_change_notifications_sql_def_contraint)
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('history', '0010_historyentry_project'), ('history', '0010_historyentry_project'),
('wiki', '0003_auto_20160615_0721'),
('users', '0022_auto_20160629_1443')
] ]
operations = [ operations = [
migrations.RunPython(forward_func, atomic=False), migrations.RunSQL(GENERATE_CORRECT_HISTORY_ENTRIES_TABLE),
migrations.RunPython(toggle_history_entries_tables)
] ]