def get_annotation(self, cte): ancestor_condition = self.build_ancestor_condition(cte) return ArrayAgg(Case(When(condition=WhenQ(*ancestor_condition), then=cte.col.pk), default=Value(None)), output_field=CharField())
def get_annotation(self, cte): resource_condition = self.build_topic_condition(F('kind_id'), '!=') topic_condition = self.build_child_condition(cte) return Coalesce( Max( Case( # when selected node is not a topic, use its sort_order When(condition=WhenQ(*resource_condition), then=F('sort_order')), # when selected node is a topic, then find max of children When(condition=WhenQ(*topic_condition), then=cte.col.sort_order), default=Value(None))), Value(1), output_field=IntegerField())
def get_annotation(self, cte): resource_condition = self.build_topic_condition(F('kind_id'), '!=') topic_condition = self.build_topic_condition(cte.col.kind_id, '!=') topic_condition += self.build_descendant_condition(cte) return Count( Case( # when selected node is not a topic, then count = 1 When(condition=WhenQ(*resource_condition), then=F('content_id')), # when it is a topic, then count descendants When(condition=WhenQ(*topic_condition), then=cte.col.content_id), default=Value(None)), distinct=True)
def get_annotation(self, cte): topic_condition = self.build_topic_condition(F('kind_id')) topic_condition += self.build_descendant_condition(cte) topic_condition += self.build_coach_condition(cte.col.role_visibility) resource_condition = self.build_topic_condition(F('kind_id'), '!=') resource_condition += self.build_coach_condition(F('role_visibility')) return Count( Case( # when selected node is a coach topic, then count descendent content_id's When(condition=WhenQ(*topic_condition), then=cte.col.content_id), # when selected node is not a topic, count its content_id When(condition=WhenQ(*resource_condition), then=F('content_id')), default=Value(None)), distinct=True)
def get_annotation(self, cte): resource_condition = self.build_topic_condition(F('kind_id'), '!=') whens = [ # when selected node is not a topic, just use its changed status When(condition=WhenQ(*resource_condition), then=F('changed')), ] if self.include_self: # when selected node is a topic and it's changed and including self, then return that whens.append( When(condition=WhenQ(*[F('changed')]), then=F('changed'))) return Coalesce( Case( *whens, # fallback to aggregating descendant changed status when a unchanged topic default=BoolOr(cte.col.changed)), Value(False), output_field=BooleanField())
def get_annotation(self, cte=None): """ @see MPTTModel.get_descendant_count() """ return Max( Case( # when selected node is topic, use algorithm to get descendant count When( condition=WhenQ(*self.build_topic_condition(F('kind_id'))), then=(F('rght') - F('lft') - Value(1)) / Value(2)), # integer division floors the result in postgres default=Value(1)))
def build(self): """ Creates special nested CTE since all other metadata works of nodes, and joining on multiple file records would produce incorrect result for resource sizes due to summing. """ files_cte = FileMetadataCTE(self.query) files_cte.add_columns(('file_size', 'checksum')) resource_condition = BooleanComparison(F('kind_id'), '!=', Value(content_kinds.TOPIC)) q = files_cte.join(self.query).annotate(resource_size=Sum( Case( # aggregate file_size when selected node is not a topic When( condition=WhenQ(resource_condition), then=Coalesce(files_cte.col.file_size, Value(0)), ), default=Value(0)), output_field=IntegerField())) return With(q.values(*set(self.columns)), name='resource_size_cte')