| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -12,38 +12,33 @@ class Quantity < ApplicationRecord
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  scope :defaults, ->{ where(user: nil) }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  scope :ordered, ->{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cte = Arel::Table.new('cte')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    numbered = Arel::Table.new('numbered')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Quantity.with(numbered: numbered(:parent_id, :name)).with_recursive(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      cte:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        Arel::SelectManager.new.project(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          numbered[Arel.star],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          numbered.cast(numbered[:child_number], 'BINARY').as('path')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ).from(numbered).where(numbered[:parent_id].eq(nil)),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        Arel::SelectManager.new.project(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          numbered[Arel.star],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          cte[:path].concat(numbered[:child_number])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ).from(numbered).join(cte).on(numbered[:parent_id].eq(cte[:id]))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ).select(cte[Arel.star]).from(cte).order(cte[:path])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Quantity.with(numbered: numbered(:parent_id, :name)).with_recursive(quantities: [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      Arel::SelectManager.new.project(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        numbered[Arel.star],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        numbered.cast(numbered[:child_number], 'BINARY').as('path'),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        Arel::Nodes.build_quoted(0).as('depth')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ).from(numbered).where(numbered[:parent_id].eq(nil)),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      Arel::SelectManager.new.project(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        numbered[Arel.star],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        arel_table[:path].concat(numbered[:child_number]),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        arel_table[:depth] + 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ).from(numbered).join(arel_table).on(numbered[:parent_id].eq(arel_table[:id]))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ]).select(arel_table[Arel.star]).from(arel_table).order(arel_table[:path])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  # TODO: extract named functions to custom Arel extension
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  # https://gist.github.com/ProGM/c6df08da14708dcc28b5ca325df37ceb#extending-arel
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  scope :numbered, ->(parent_column, order_column){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    select(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      arel_table[Arel.star],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      Arel::Nodes::NamedFunction.new(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'LPAD',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          Arel::Nodes::NamedFunction.new(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            'ROW_NUMBER', []
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          ).over(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Arel::Nodes::Window.new.partition(parent_column).order(order_column)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          ),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          Arel::Nodes::NamedFunction.new('ROW_NUMBER', [])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .over(Arel::Nodes::Window.new.partition(parent_column).order(order_column)),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          Arel::SelectManager.new.project(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Arel::Nodes::NamedFunction.new(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              'LENGTH', [Arel::Nodes::NamedFunction.new('COUNT', [Arel.star])]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            )
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Arel::Nodes::NamedFunction.new('LENGTH', [Arel.star.count])])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          ),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          Arel::Nodes.build_quoted('0')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ],
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -62,4 +57,24 @@ class Quantity < ApplicationRecord
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  def default?
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    parent_id.nil?
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  end
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  # Return: record, its ancestors and succesive record in order of appearance,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  # including :depth attribute. Used for table view reload.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  def successive
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    quantities = Quantity.arel_table
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ancestors = Arel::Table.new('ancestors')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Quantity.with(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ancestors: user.quantities.ordered.select(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        Arel::Nodes::NamedFunction.new('LAG', [quantities[:id]]).over.as('lag_id')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      )
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    )
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    .with_recursive(quantities: [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      Arel::SelectManager.new.project(ancestors[Arel.star]).from(ancestors)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .where(ancestors[:id].eq(id).or(ancestors[:lag_id].eq(id))),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      Arel::SelectManager.new.project(ancestors[Arel.star]).from(ancestors)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .join(quantities).on(quantities[:parent_id].eq(ancestors[:id]))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .where(quantities[:lag_id].not_eq(id))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ]).order(quantities[:path])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    # return: .first == self ? nul, ancestors : ancestors.pop, ancestors
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  end
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				end
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				
 
 |