Compare commits

...

5 Commits

4 changed files with 41 additions and 25 deletions

View File

@ -379,7 +379,8 @@ table.items td {
} }
/* For <a> to fill <td> completely, we use an ::after pseudoelement. */ /* For <a> to fill <td> completely, we use an ::after pseudoelement. */
table.items td.link { table.items td.link {
padding: 0 0 0 1em; padding: 0;
padding-inline-start: calc(1em + var(--depth) * 0.8em);
position: relative; position: relative;
} }
table.items td.link a { table.items td.link a {

View File

@ -12,38 +12,33 @@ class Quantity < ApplicationRecord
scope :defaults, ->{ where(user: nil) } scope :defaults, ->{ where(user: nil) }
scope :ordered, ->{ scope :ordered, ->{
cte = Arel::Table.new('cte')
numbered = Arel::Table.new('numbered') numbered = Arel::Table.new('numbered')
Quantity.with(numbered: numbered(:parent_id, :name)).with_recursive( Quantity.with(numbered: numbered(:parent_id, :name)).with_recursive(quantities: [
cte:
[
Arel::SelectManager.new.project( Arel::SelectManager.new.project(
numbered[Arel.star], numbered[Arel.star],
numbered.cast(numbered[:child_number], 'BINARY').as('path') numbered.cast(numbered[:child_number], 'BINARY').as('path'),
Arel::Nodes.build_quoted(0).as('depth')
).from(numbered).where(numbered[:parent_id].eq(nil)), ).from(numbered).where(numbered[:parent_id].eq(nil)),
Arel::SelectManager.new.project( Arel::SelectManager.new.project(
numbered[Arel.star], numbered[Arel.star],
cte[:path].concat(numbered[:child_number]) arel_table[:path].concat(numbered[:child_number]),
).from(numbered).join(cte).on(numbered[:parent_id].eq(cte[:id])) arel_table[:depth] + 1
] ).from(numbered).join(arel_table).on(numbered[:parent_id].eq(arel_table[:id]))
).select(cte[Arel.star]).from(cte).order(cte[:path]) ]).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){ scope :numbered, ->(parent_column, order_column){
select( select(
arel_table[Arel.star], arel_table[Arel.star],
Arel::Nodes::NamedFunction.new( Arel::Nodes::NamedFunction.new(
'LPAD', 'LPAD',
[ [
Arel::Nodes::NamedFunction.new( Arel::Nodes::NamedFunction.new('ROW_NUMBER', [])
'ROW_NUMBER', [] .over(Arel::Nodes::Window.new.partition(parent_column).order(order_column)),
).over(
Arel::Nodes::Window.new.partition(parent_column).order(order_column)
),
Arel::SelectManager.new.project( Arel::SelectManager.new.project(
Arel::Nodes::NamedFunction.new( Arel::Nodes::NamedFunction.new('LENGTH', [Arel.star.count])])
'LENGTH', [Arel::Nodes::NamedFunction.new('COUNT', [Arel.star])]
)
), ),
Arel::Nodes.build_quoted('0') Arel::Nodes.build_quoted('0')
], ],
@ -62,4 +57,24 @@ class Quantity < ApplicationRecord
def default? def default?
parent_id.nil? parent_id.nil?
end 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 end

View File

@ -10,7 +10,6 @@
</td> </td>
<td class="number"> <td class="number">
<% unless @unit.base.nil? %> <% unless @unit.base.nil? %>
<%= form.hidden_field :base_id %>
<%= form.number_field :multiplier, required: true, size: 10, min: :step %> <%= form.number_field :multiplier, required: true, size: 10, min: :step %>
<% end %> <% end %>
</td> </td>

View File

@ -7,7 +7,8 @@
<%= turbo_stream.disable ids[:link] -%> <%= turbo_stream.disable ids[:link] -%>
<%= turbo_stream.append :unit_form do %> <%= turbo_stream.append :unit_form do %>
<%- tabular_form_with model: @unit, html: {id: ids[:form_tag]} do %> <%- tabular_form_with model: @unit, html: {id: ids[:form_tag]} do |form| %>
<%= form.hidden_field :base_id unless @unit.base.nil? %>
<% end %> <% end %>
<% end %> <% end %>