diff --git a/app/models/quantity.rb b/app/models/quantity.rb index ed81124..e8d36d3 100644 --- a/app/models/quantity.rb +++ b/app/models/quantity.rb @@ -15,8 +15,8 @@ class Quantity < ApplicationRecord errors.add(:parent, :descendant_reference) if ancestor_of?(parent) end validates :name, presence: true, uniqueness: {scope: [:user_id, :parent_id]}, - length: {maximum: type_for_attribute(:name).limit} - validates :description, length: {maximum: type_for_attribute(:description).limit} + length: {maximum: type_for_attribute(:name).limit || Float::INFINITY} + validates :description, length: {maximum: type_for_attribute(:description).limit || Float::INFINITY} # Update :depths of progenies after parent change before_save if: :parent_changed? do @@ -61,18 +61,26 @@ class Quantity < ApplicationRecord # Return: ordered [sub]hierarchy scope :ordered, ->(root: nil, include_root: true) { - numbered = Arel::Table.new('numbered') - - self.model.with(numbered: numbered(:parent_id, :name)).with_recursive(arel_table.name => [ - numbered.project( - numbered[Arel.star], - numbered.cast(numbered[:child_number], 'BINARY').as('path') - ).where(numbered[root && include_root ? :id : :parent_id].eq(root)), - numbered.project( - numbered[Arel.star], - arel_table[:path].concat(numbered[:child_number]) - ).join(arel_table).on(numbered[:parent_id].eq(arel_table[:id])) - ]).order(arel_table[:path]) + if connection.adapter_name =~ /mysql/i + numbered = Arel::Table.new('numbered') + self.model.with(numbered: numbered(:parent_id, :name)).with_recursive(arel_table.name => [ + numbered.project( + numbered[Arel.star], + numbered.cast(numbered[:child_number], 'BINARY').as('path') + ).where(numbered[root && include_root ? :id : :parent_id].eq(root)), + numbered.project( + numbered[Arel.star], + arel_table[:path].concat(numbered[:child_number]) + ).join(arel_table).on(numbered[:parent_id].eq(arel_table[:id])) + ]).order(arel_table[:path]) + elsif root.nil? + # SQLite: pathname column already stores the full hierarchical path + order(:pathname) + else + root_pathname = unscoped.where(id: root).pick(:pathname) + scope = order(:pathname).where("pathname LIKE ?", "#{root_pathname}#{PATHNAME_DELIMITER}%") + include_root ? scope.or(where(id: root)) : scope + end } # TODO: extract named functions to custom Arel extension