Turn #ancestors into #with_ancestors scope

This commit is contained in:
cryptogopher 2025-01-14 23:27:32 +01:00
parent 27038a74d0
commit 2c0ae1530a

View File

@ -93,28 +93,28 @@ class Quantity < ApplicationRecord
user.quantities.progenies(self).to_a user.quantities.progenies(self).to_a
end end
# Return: ancestors of (possibly destroyed) self; include depths, also on # Return: record `of` with its ancestors, sorted by `depth`
# self (unless destroyed) scope :with_ancestors, ->(of) {
def ancestors selected = Arel::Table.new('selected')
quantities = Quantity.arel_table
ancestors = Arel::Table.new('ancestors')
model.with(selected: self).with_recursive(arel_table.name => [
selected.project(selected[Arel.star], Arel::Nodes.build_quoted(0).as('depth'))
.where(selected[:id].eq(of&.id)),
# Ancestors are listed bottom up, so it's impossible to know depth at the # Ancestors are listed bottom up, so it's impossible to know depth at the
# start. Start with depth = 0 and count downwards, then adjust by the # start. Start with depth = 0 and count downwards, then adjust by the
# amount needed to set biggest negative depth to 0. # amount needed to set biggest negative depth to 0.
Quantity.with_recursive(ancestors: [ selected.project(selected[Arel.star], arel_table[:depth] - 1)
user.quantities.select(quantities[Arel.star], Arel::Nodes.build_quoted(0).as('depth')) .join(arel_table).on(selected[:id].eq(arel_table[:parent_id]))
.where(id: parent_id), ]).select(
user.quantities.select(quantities[Arel.star], ancestors[:depth] - 1) arel_table[Arel.star],
.joins(quantities.create_join( (arel_table[:depth] + Arel::SelectManager.new.project(Arel.star.count).from(arel_table) - 1)
ancestors, quantities.create_on(quantities[:id].eq(ancestors[:parent_id])) .as('depth')
)) ).order(arel_table[:depth])
]).select(ancestors[Arel.star]).from(ancestors).to_a.then do |records| }
records.map(&:depth).min&.abs.then do |maxdepth|
self.depth = maxdepth&.succ || 0 unless frozen? # Return: ancestors of (possibly destroyed) self
records.each { |r| r.depth += maxdepth } def ancestors
end user.quantities.with_ancestors(parent)
end
end end
def ancestor_of?(descendant) def ancestor_of?(descendant)