- def fix_tree_tags(self):
- """Fixes the l-tags on the book's subtree.
-
- Makes sure that:
- * the book has its parents book-tags,
- * its fragments have the book's and its parents book-tags,
- * runs those for every child book too,
- * touches all relevant tags,
- * resets tag and theme counter on the book and its ancestry.
- """
- def fix_subtree(book, parent_tags):
- affected_tags = set(book.tags)
- book.tags = list(book.tags.exclude(category='book')) + parent_tags
- sub_parent_tags = parent_tags + [book.book_tag()]
- for frag in book.fragments.all():
- affected_tags.update(frag.tags)
- frag.tags = list(frag.tags.exclude(category='book')
- ) + sub_parent_tags
- for child in book.children.all():
- affected_tags.update(fix_subtree(child, sub_parent_tags))
- return affected_tags
-
- parent_tags = []
- parent = self.parent
- while parent is not None:
- parent_tags.append(parent.book_tag())
- parent = parent.parent
-
- affected_tags = fix_subtree(self, parent_tags)
- for tag in affected_tags:
- tasks.touch_tag(tag)
-
- book = self
- while book is not None:
- book.reset_tag_counter()
- book.reset_theme_counter()
- book = book.parent
+ @classmethod
+ def fix_tree_tags(cls):
+ """Fixes the ancestry cache."""
+ # TODO: table names
+ with transaction.atomic():
+ cursor = connection.cursor()
+ if connection.vendor == 'postgres':
+ cursor.execute("TRUNCATE catalogue_book_ancestor")
+ cursor.execute("""
+ WITH RECURSIVE ancestry AS (
+ SELECT book.id, book.parent_id
+ FROM catalogue_book AS book
+ WHERE book.parent_id IS NOT NULL
+ UNION
+ SELECT ancestor.id, book.parent_id
+ FROM ancestry AS ancestor, catalogue_book AS book
+ WHERE ancestor.parent_id = book.id
+ AND book.parent_id IS NOT NULL
+ )
+ INSERT INTO catalogue_book_ancestor
+ (from_book_id, to_book_id)
+ SELECT id, parent_id
+ FROM ancestry
+ ORDER BY id;
+ """)
+ else:
+ cursor.execute("DELETE FROM catalogue_book_ancestor")
+ for b in cls.objects.exclude(parent=None):
+ parent = b.parent
+ while parent is not None:
+ b.ancestor.add(parent)
+ parent = parent.parent