module ActiveRecordExtended::QueryMethods::Unionize
Constants
- UNIONIZE_METHODS
- UNION_RELATION_METHODS
Public Instance Methods
to_nice_union_sql(color = true)
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 136 def to_nice_union_sql(color = true) return to_union_sql unless defined?(::Niceql) ::Niceql::Prettifier.prettify_sql(to_union_sql, color) end
to_union_sql()
click to toggle source
Will construct Just the union SQL statement that was been built thus far
# File lib/active_record_extended/query_methods/unionize.rb, line 130 def to_union_sql return unless union_values? apply_union_ordering(build_union_nodes!(false)).to_sql end
union(opts = :chain, *args)
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 109 def union(opts = :chain, *args) return UnionChain.new(spawn) if opts == :chain opts.nil? ? self : spawn.union!(opts, *args, chain_method: __callee__) end
union!(opts = :chain, *args, chain_method: :union)
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 121 def union!(opts = :chain, *args, chain_method: :union) union_chain = UnionChain.new(self) chain_method ||= :union return union_chain if opts == :chain union_chain.public_send(chain_method, *([opts] + args)) end
unionize_storage()
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 75 def unionize_storage @values.fetch(:unionize, {}) end
unionize_storage!()
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 79 def unionize_storage! @values[:unionize] ||= { union_values: [], union_operations: [], union_ordering_values: [], unionized_name: nil } end
Protected Instance Methods
apply_union_ordering(union_nodes)
click to toggle source
Apply's the allowed ORDER BY to the end of the final union statement
Note: This will only apply at the very end of the union statements. Not nested ones.
(I guess you could double nest a union and apply it, but that would be dumb)
Example:
User.union(User.select(:id).where(id: 8)) .union(User.select(:id).where(id: 50)) .union.order(id: :desc) #=> [<#User id: 50>, <#User id: 8>] ```sql SELECT users.* FROM( (SELECT users.id FROM users WHERE id = 8) UNION (SELECT users.id FROM users WHERE id = 50) ORDER BY id DESC ) users; ```
# File lib/active_record_extended/query_methods/unionize.rb, line 221 def apply_union_ordering(union_nodes) return union_nodes unless union_ordering_values? UnionChain.new(self).inline_order_by(union_nodes, union_ordering_values) end
build_union_nodes!(raise_error = true)
click to toggle source
Builds a set of nested nodes that union each other's results
Note: Order of chained unions DOES matter
Example:
User.union(User.select(:id).where(id: 8)) .union(User.select(:id).where(id: 50)) .union.except(User.select(:id).where(id: 8)) #=> [<#User id: 50]] ```sql SELECT users.* FROM( ( (SELECT users.id FROM users WHERE id = 8) UNION (SELECT users.id FROM users WHERE id = 50) ) EXCEPT (SELECT users.id FROM users WHERE id = 8) ) users; ```
# File lib/active_record_extended/query_methods/unionize.rb, line 178 def build_union_nodes!(raise_error = true) unionize_error_or_warn!(raise_error) union_values.each_with_index.reduce(nil) do |union_node, (relation_node, index)| next resolve_relation_node(relation_node) if union_node.nil? operation = union_operations.fetch(index - 1, :union) left = union_node right = resolve_relation_node(relation_node) case operation when :union_all Arel::Nodes::UnionAll.new(left, right) when :except Arel::Nodes::Except.new(left, right) when :intersect Arel::Nodes::Intersect.new(left, right) else Arel::Nodes::Union.new(left, right) end end end
build_unions(arel = @klass.arel_table)
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 144 def build_unions(arel = @klass.arel_table) return unless union_values? union_nodes = apply_union_ordering(build_union_nodes!) table_name = Arel.sql(unionized_name) table_alias = arel.create_table_alias(arel.grouping(union_nodes), table_name) arel.from(table_alias) end
Private Instance Methods
resolve_relation_node(relation_node)
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 237 def resolve_relation_node(relation_node) case relation_node when String Arel::Nodes::Grouping.new(Arel.sql(relation_node)) else relation_node.arel end end
unionize_error_or_warn!(raise_error = true)
click to toggle source
# File lib/active_record_extended/query_methods/unionize.rb, line 229 def unionize_error_or_warn!(raise_error = true) if raise_error && union_values.size <= 1 raise ArgumentError.new("You are required to provide 2 or more unions to join!") elsif !raise_error && union_values.size <= 1 warn("Warning: You are required to provide 2 or more unions to join.") end end