diff options
Diffstat (limited to 'activerecord/lib/arel/nodes')
43 files changed, 1198 insertions, 0 deletions
diff --git a/activerecord/lib/arel/nodes/and.rb b/activerecord/lib/arel/nodes/and.rb new file mode 100644 index 0000000000..1e2f61cf43 --- /dev/null +++ b/activerecord/lib/arel/nodes/and.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +module Arel + module Nodes + class And < Arel::Nodes::Node + attr_reader :children + + def initialize children + super() + @children = children + end + + def left + children.first + end + + def right + children[1] + end + + def hash + children.hash + end + + def eql? other + self.class == other.class && + self.children == other.children + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/ascending.rb b/activerecord/lib/arel/nodes/ascending.rb new file mode 100644 index 0000000000..adadab55e4 --- /dev/null +++ b/activerecord/lib/arel/nodes/ascending.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Ascending < Ordering + + def reverse + Descending.new(expr) + end + + def direction + :asc + end + + def ascending? + true + end + + def descending? + false + end + + end + end +end diff --git a/activerecord/lib/arel/nodes/binary.rb b/activerecord/lib/arel/nodes/binary.rb new file mode 100644 index 0000000000..a86d4e4696 --- /dev/null +++ b/activerecord/lib/arel/nodes/binary.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Binary < Arel::Nodes::NodeExpression + attr_accessor :left, :right + + def initialize left, right + super() + @left = left + @right = right + end + + def initialize_copy other + super + @left = @left.clone if @left + @right = @right.clone if @right + end + + def hash + [self.class, @left, @right].hash + end + + def eql? other + self.class == other.class && + self.left == other.left && + self.right == other.right + end + alias :== :eql? + end + + %w{ + As + Assignment + Between + GreaterThan + GreaterThanOrEqual + Join + LessThan + LessThanOrEqual + NotEqual + NotIn + Or + Union + UnionAll + Intersect + Except + }.each do |name| + const_set name, Class.new(Binary) + end + end +end diff --git a/activerecord/lib/arel/nodes/bind_param.rb b/activerecord/lib/arel/nodes/bind_param.rb new file mode 100644 index 0000000000..efa4f452d4 --- /dev/null +++ b/activerecord/lib/arel/nodes/bind_param.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +module Arel + module Nodes + class BindParam < Node + attr_accessor :value + + def initialize(value) + @value = value + super() + end + + def hash + [self.class, self.value].hash + end + + def eql?(other) + other.is_a?(BindParam) && + value == other.value + end + alias :== :eql? + + def nil? + value.nil? + end + end + end +end diff --git a/activerecord/lib/arel/nodes/case.rb b/activerecord/lib/arel/nodes/case.rb new file mode 100644 index 0000000000..50ea1e0be2 --- /dev/null +++ b/activerecord/lib/arel/nodes/case.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Case < Arel::Nodes::Node + attr_accessor :case, :conditions, :default + + def initialize expression = nil, default = nil + @case = expression + @conditions = [] + @default = default + end + + def when condition, expression = nil + @conditions << When.new(Nodes.build_quoted(condition), expression) + self + end + + def then expression + @conditions.last.right = Nodes.build_quoted(expression) + self + end + + def else expression + @default = Else.new Nodes.build_quoted(expression) + self + end + + def initialize_copy other + super + @case = @case.clone if @case + @conditions = @conditions.map { |x| x.clone } + @default = @default.clone if @default + end + + def hash + [@case, @conditions, @default].hash + end + + def eql? other + self.class == other.class && + self.case == other.case && + self.conditions == other.conditions && + self.default == other.default + end + alias :== :eql? + end + + class When < Binary # :nodoc: + end + + class Else < Unary # :nodoc: + end + end +end diff --git a/activerecord/lib/arel/nodes/casted.rb b/activerecord/lib/arel/nodes/casted.rb new file mode 100644 index 0000000000..f945063dd2 --- /dev/null +++ b/activerecord/lib/arel/nodes/casted.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Casted < Arel::Nodes::NodeExpression # :nodoc: + attr_reader :val, :attribute + def initialize val, attribute + @val = val + @attribute = attribute + super() + end + + def nil?; @val.nil?; end + + def hash + [self.class, val, attribute].hash + end + + def eql? other + self.class == other.class && + self.val == other.val && + self.attribute == other.attribute + end + alias :== :eql? + end + + class Quoted < Arel::Nodes::Unary # :nodoc: + alias :val :value + def nil?; val.nil?; end + end + + def self.build_quoted other, attribute = nil + case other + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted, Arel::Nodes::SqlLiteral + other + else + case attribute + when Arel::Attributes::Attribute + Casted.new other, attribute + else + Quoted.new other + end + end + end + end +end diff --git a/activerecord/lib/arel/nodes/count.rb b/activerecord/lib/arel/nodes/count.rb new file mode 100644 index 0000000000..4dd9be453f --- /dev/null +++ b/activerecord/lib/arel/nodes/count.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Count < Arel::Nodes::Function + include Math + + def initialize expr, distinct = false, aliaz = nil + super(expr, aliaz) + @distinct = distinct + end + end + end +end diff --git a/activerecord/lib/arel/nodes/delete_statement.rb b/activerecord/lib/arel/nodes/delete_statement.rb new file mode 100644 index 0000000000..063a5341e5 --- /dev/null +++ b/activerecord/lib/arel/nodes/delete_statement.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +module Arel + module Nodes + class DeleteStatement < Arel::Nodes::Node + attr_accessor :left, :right + attr_accessor :limit + + alias :relation :left + alias :relation= :left= + alias :wheres :right + alias :wheres= :right= + + def initialize relation = nil, wheres = [] + super() + @left = relation + @right = wheres + end + + def initialize_copy other + super + @left = @left.clone if @left + @right = @right.clone if @right + end + + def hash + [self.class, @left, @right].hash + end + + def eql? other + self.class == other.class && + self.left == other.left && + self.right == other.right + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/descending.rb b/activerecord/lib/arel/nodes/descending.rb new file mode 100644 index 0000000000..d7261ab583 --- /dev/null +++ b/activerecord/lib/arel/nodes/descending.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Descending < Ordering + + def reverse + Ascending.new(expr) + end + + def direction + :desc + end + + def ascending? + false + end + + def descending? + true + end + + end + end +end diff --git a/activerecord/lib/arel/nodes/equality.rb b/activerecord/lib/arel/nodes/equality.rb new file mode 100644 index 0000000000..ef44725e24 --- /dev/null +++ b/activerecord/lib/arel/nodes/equality.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Equality < Arel::Nodes::Binary + def operator; :== end + alias :operand1 :left + alias :operand2 :right + end + end +end diff --git a/activerecord/lib/arel/nodes/extract.rb b/activerecord/lib/arel/nodes/extract.rb new file mode 100644 index 0000000000..fdf3004c6a --- /dev/null +++ b/activerecord/lib/arel/nodes/extract.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Extract < Arel::Nodes::Unary + attr_accessor :field + + def initialize expr, field + super(expr) + @field = field + end + + def hash + super ^ @field.hash + end + + def eql? other + super && + self.field == other.field + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/false.rb b/activerecord/lib/arel/nodes/false.rb new file mode 100644 index 0000000000..58132a2f90 --- /dev/null +++ b/activerecord/lib/arel/nodes/false.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Arel + module Nodes + class False < Arel::Nodes::NodeExpression + def hash + self.class.hash + end + + def eql? other + self.class == other.class + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/full_outer_join.rb b/activerecord/lib/arel/nodes/full_outer_join.rb new file mode 100644 index 0000000000..12a02d8cd9 --- /dev/null +++ b/activerecord/lib/arel/nodes/full_outer_join.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +module Arel + module Nodes + class FullOuterJoin < Arel::Nodes::Join + end + end +end diff --git a/activerecord/lib/arel/nodes/function.rb b/activerecord/lib/arel/nodes/function.rb new file mode 100644 index 0000000000..b3bf8f3e51 --- /dev/null +++ b/activerecord/lib/arel/nodes/function.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Function < Arel::Nodes::NodeExpression + include Arel::WindowPredications + attr_accessor :expressions, :alias, :distinct + + def initialize expr, aliaz = nil + super() + @expressions = expr + @alias = aliaz && SqlLiteral.new(aliaz) + @distinct = false + end + + def as aliaz + self.alias = SqlLiteral.new(aliaz) + self + end + + def hash + [@expressions, @alias, @distinct].hash + end + + def eql? other + self.class == other.class && + self.expressions == other.expressions && + self.alias == other.alias && + self.distinct == other.distinct + end + alias :== :eql? + + end + + %w{ + Sum + Exists + Max + Min + Avg + }.each do |name| + const_set(name, Class.new(Function)) + end + end +end diff --git a/activerecord/lib/arel/nodes/grouping.rb b/activerecord/lib/arel/nodes/grouping.rb new file mode 100644 index 0000000000..ffe66654ce --- /dev/null +++ b/activerecord/lib/arel/nodes/grouping.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Grouping < Unary + end + end +end diff --git a/activerecord/lib/arel/nodes/in.rb b/activerecord/lib/arel/nodes/in.rb new file mode 100644 index 0000000000..30cd771c40 --- /dev/null +++ b/activerecord/lib/arel/nodes/in.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +module Arel + module Nodes + class In < Equality + end + end +end diff --git a/activerecord/lib/arel/nodes/infix_operation.rb b/activerecord/lib/arel/nodes/infix_operation.rb new file mode 100644 index 0000000000..4eb7c5356f --- /dev/null +++ b/activerecord/lib/arel/nodes/infix_operation.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true +module Arel + module Nodes + + class InfixOperation < Binary + include Arel::Expressions + include Arel::Predications + include Arel::OrderPredications + include Arel::AliasPredication + include Arel::Math + + attr_reader :operator + + def initialize operator, left, right + super(left, right) + @operator = operator + end + end + + class Multiplication < InfixOperation + def initialize left, right + super(:*, left, right) + end + end + + class Division < InfixOperation + def initialize left, right + super(:/, left, right) + end + end + + class Addition < InfixOperation + def initialize left, right + super(:+, left, right) + end + end + + class Subtraction < InfixOperation + def initialize left, right + super(:-, left, right) + end + end + + class Concat < InfixOperation + def initialize left, right + super('||', left, right) + end + end + + class BitwiseAnd < InfixOperation + def initialize left, right + super(:&, left, right) + end + end + + class BitwiseOr < InfixOperation + def initialize left, right + super(:|, left, right) + end + end + + class BitwiseXor < InfixOperation + def initialize left, right + super(:^, left, right) + end + end + + class BitwiseShiftLeft < InfixOperation + def initialize left, right + super(:<<, left, right) + end + end + + class BitwiseShiftRight < InfixOperation + def initialize left, right + super(:>>, left, right) + end + end + end +end diff --git a/activerecord/lib/arel/nodes/inner_join.rb b/activerecord/lib/arel/nodes/inner_join.rb new file mode 100644 index 0000000000..4e398267c3 --- /dev/null +++ b/activerecord/lib/arel/nodes/inner_join.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +module Arel + module Nodes + class InnerJoin < Arel::Nodes::Join + end + end +end diff --git a/activerecord/lib/arel/nodes/insert_statement.rb b/activerecord/lib/arel/nodes/insert_statement.rb new file mode 100644 index 0000000000..72793bc1ad --- /dev/null +++ b/activerecord/lib/arel/nodes/insert_statement.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +module Arel + module Nodes + class InsertStatement < Arel::Nodes::Node + attr_accessor :relation, :columns, :values, :select + + def initialize + super() + @relation = nil + @columns = [] + @values = nil + @select = nil + end + + def initialize_copy other + super + @columns = @columns.clone + @values = @values.clone if @values + @select = @select.clone if @select + end + + def hash + [@relation, @columns, @values, @select].hash + end + + def eql? other + self.class == other.class && + self.relation == other.relation && + self.columns == other.columns && + self.select == other.select && + self.values == other.values + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/join_source.rb b/activerecord/lib/arel/nodes/join_source.rb new file mode 100644 index 0000000000..428ce8183e --- /dev/null +++ b/activerecord/lib/arel/nodes/join_source.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +module Arel + module Nodes + ### + # Class that represents a join source + # + # http://www.sqlite.org/syntaxdiagrams.html#join-source + + class JoinSource < Arel::Nodes::Binary + def initialize single_source, joinop = [] + super + end + + def empty? + !left && right.empty? + end + end + end +end diff --git a/activerecord/lib/arel/nodes/matches.rb b/activerecord/lib/arel/nodes/matches.rb new file mode 100644 index 0000000000..3ad3850a8e --- /dev/null +++ b/activerecord/lib/arel/nodes/matches.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Matches < Binary + attr_reader :escape + attr_accessor :case_sensitive + + def initialize(left, right, escape = nil, case_sensitive = false) + super(left, right) + @escape = escape && Nodes.build_quoted(escape) + @case_sensitive = case_sensitive + end + end + + class DoesNotMatch < Matches; end + end +end diff --git a/activerecord/lib/arel/nodes/named_function.rb b/activerecord/lib/arel/nodes/named_function.rb new file mode 100644 index 0000000000..173838a7fd --- /dev/null +++ b/activerecord/lib/arel/nodes/named_function.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +module Arel + module Nodes + class NamedFunction < Arel::Nodes::Function + attr_accessor :name + + def initialize name, expr, aliaz = nil + super(expr, aliaz) + @name = name + end + + def hash + super ^ @name.hash + end + + def eql? other + super && self.name == other.name + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/node.rb b/activerecord/lib/arel/nodes/node.rb new file mode 100644 index 0000000000..d2e6313dda --- /dev/null +++ b/activerecord/lib/arel/nodes/node.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true +module Arel + module Nodes + ### + # Abstract base class for all AST nodes + class Node + include Arel::FactoryMethods + include Enumerable + + if $DEBUG + def _caller + @caller + end + + def initialize + @caller = caller.dup + end + end + + ### + # Factory method to create a Nodes::Not node that has the recipient of + # the caller as a child. + def not + Nodes::Not.new self + end + + ### + # Factory method to create a Nodes::Grouping node that has an Nodes::Or + # node as a child. + def or right + Nodes::Grouping.new Nodes::Or.new(self, right) + end + + ### + # Factory method to create an Nodes::And node. + def and right + Nodes::And.new [self, right] + end + + # FIXME: this method should go away. I don't like people calling + # to_sql on non-head nodes. This forces us to walk the AST until we + # can find a node that has a "relation" member. + # + # Maybe we should just use `Table.engine`? :'( + def to_sql engine = Table.engine + collector = Arel::Collectors::SQLString.new + collector = engine.connection.visitor.accept self, collector + collector.value + end + + # Iterate through AST, nodes will be yielded depth-first + def each &block + return enum_for(:each) unless block_given? + + ::Arel::Visitors::DepthFirst.new(block).accept self + end + end + end +end diff --git a/activerecord/lib/arel/nodes/node_expression.rb b/activerecord/lib/arel/nodes/node_expression.rb new file mode 100644 index 0000000000..c4d4c8f428 --- /dev/null +++ b/activerecord/lib/arel/nodes/node_expression.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class NodeExpression < Arel::Nodes::Node + include Arel::Expressions + include Arel::Predications + include Arel::AliasPredication + include Arel::OrderPredications + include Arel::Math + end + end +end diff --git a/activerecord/lib/arel/nodes/outer_join.rb b/activerecord/lib/arel/nodes/outer_join.rb new file mode 100644 index 0000000000..c568655fe6 --- /dev/null +++ b/activerecord/lib/arel/nodes/outer_join.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +module Arel + module Nodes + class OuterJoin < Arel::Nodes::Join + end + end +end diff --git a/activerecord/lib/arel/nodes/over.rb b/activerecord/lib/arel/nodes/over.rb new file mode 100644 index 0000000000..47a34e69ea --- /dev/null +++ b/activerecord/lib/arel/nodes/over.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +module Arel + module Nodes + + class Over < Binary + include Arel::AliasPredication + + def initialize(left, right = nil) + super(left, right) + end + + def operator; 'OVER' end + end + + end +end
\ No newline at end of file diff --git a/activerecord/lib/arel/nodes/regexp.rb b/activerecord/lib/arel/nodes/regexp.rb new file mode 100644 index 0000000000..8a76185ef0 --- /dev/null +++ b/activerecord/lib/arel/nodes/regexp.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Regexp < Binary + attr_accessor :case_sensitive + + def initialize(left, right, case_sensitive = true) + super(left, right) + @case_sensitive = case_sensitive + end + end + + class NotRegexp < Regexp; end + end +end diff --git a/activerecord/lib/arel/nodes/right_outer_join.rb b/activerecord/lib/arel/nodes/right_outer_join.rb new file mode 100644 index 0000000000..04ab31ebf0 --- /dev/null +++ b/activerecord/lib/arel/nodes/right_outer_join.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +module Arel + module Nodes + class RightOuterJoin < Arel::Nodes::Join + end + end +end diff --git a/activerecord/lib/arel/nodes/select_core.rb b/activerecord/lib/arel/nodes/select_core.rb new file mode 100644 index 0000000000..fa1c026107 --- /dev/null +++ b/activerecord/lib/arel/nodes/select_core.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true +module Arel + module Nodes + class SelectCore < Arel::Nodes::Node + attr_accessor :top, :projections, :wheres, :groups, :windows + attr_accessor :havings, :source, :set_quantifier + + def initialize + super() + @source = JoinSource.new nil + @top = nil + + # https://ronsavage.github.io/SQL/sql-92.bnf.html#set%20quantifier + @set_quantifier = nil + @projections = [] + @wheres = [] + @groups = [] + @havings = [] + @windows = [] + end + + def from + @source.left + end + + def from= value + @source.left = value + end + + alias :froms= :from= + alias :froms :from + + def initialize_copy other + super + @source = @source.clone if @source + @projections = @projections.clone + @wheres = @wheres.clone + @groups = @groups.clone + @havings = @havings.clone + @windows = @windows.clone + end + + def hash + [ + @source, @top, @set_quantifier, @projections, + @wheres, @groups, @havings, @windows + ].hash + end + + def eql? other + self.class == other.class && + self.source == other.source && + self.top == other.top && + self.set_quantifier == other.set_quantifier && + self.projections == other.projections && + self.wheres == other.wheres && + self.groups == other.groups && + self.havings == other.havings && + self.windows == other.windows + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/select_statement.rb b/activerecord/lib/arel/nodes/select_statement.rb new file mode 100644 index 0000000000..79176d4be5 --- /dev/null +++ b/activerecord/lib/arel/nodes/select_statement.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +module Arel + module Nodes + class SelectStatement < Arel::Nodes::NodeExpression + attr_reader :cores + attr_accessor :limit, :orders, :lock, :offset, :with + + def initialize cores = [SelectCore.new] + super() + @cores = cores + @orders = [] + @limit = nil + @lock = nil + @offset = nil + @with = nil + end + + def initialize_copy other + super + @cores = @cores.map { |x| x.clone } + @orders = @orders.map { |x| x.clone } + end + + def hash + [@cores, @orders, @limit, @lock, @offset, @with].hash + end + + def eql? other + self.class == other.class && + self.cores == other.cores && + self.orders == other.orders && + self.limit == other.limit && + self.lock == other.lock && + self.offset == other.offset && + self.with == other.with + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/sql_literal.rb b/activerecord/lib/arel/nodes/sql_literal.rb new file mode 100644 index 0000000000..73575a7d49 --- /dev/null +++ b/activerecord/lib/arel/nodes/sql_literal.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Arel + module Nodes + class SqlLiteral < String + include Arel::Expressions + include Arel::Predications + include Arel::AliasPredication + include Arel::OrderPredications + + def encode_with(coder) + coder.scalar = self.to_s + end + end + end +end diff --git a/activerecord/lib/arel/nodes/string_join.rb b/activerecord/lib/arel/nodes/string_join.rb new file mode 100644 index 0000000000..21d6845c45 --- /dev/null +++ b/activerecord/lib/arel/nodes/string_join.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Arel + module Nodes + class StringJoin < Arel::Nodes::Join + def initialize left, right = nil + super + end + end + end +end diff --git a/activerecord/lib/arel/nodes/table_alias.rb b/activerecord/lib/arel/nodes/table_alias.rb new file mode 100644 index 0000000000..78deb175b6 --- /dev/null +++ b/activerecord/lib/arel/nodes/table_alias.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +module Arel + module Nodes + class TableAlias < Arel::Nodes::Binary + alias :name :right + alias :relation :left + alias :table_alias :name + + def [] name + Attribute.new(self, name) + end + + def table_name + relation.respond_to?(:name) ? relation.name : name + end + + def type_cast_for_database(*args) + relation.type_cast_for_database(*args) + end + + def able_to_type_cast? + relation.respond_to?(:able_to_type_cast?) && relation.able_to_type_cast? + end + end + end +end diff --git a/activerecord/lib/arel/nodes/terminal.rb b/activerecord/lib/arel/nodes/terminal.rb new file mode 100644 index 0000000000..3a1cd7f0e1 --- /dev/null +++ b/activerecord/lib/arel/nodes/terminal.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Distinct < Arel::Nodes::NodeExpression + def hash + self.class.hash + end + + def eql? other + self.class == other.class + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/true.rb b/activerecord/lib/arel/nodes/true.rb new file mode 100644 index 0000000000..fdb8ed2095 --- /dev/null +++ b/activerecord/lib/arel/nodes/true.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Arel + module Nodes + class True < Arel::Nodes::NodeExpression + def hash + self.class.hash + end + + def eql? other + self.class == other.class + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/unary.rb b/activerecord/lib/arel/nodes/unary.rb new file mode 100644 index 0000000000..e458d87ab3 --- /dev/null +++ b/activerecord/lib/arel/nodes/unary.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Unary < Arel::Nodes::NodeExpression + attr_accessor :expr + alias :value :expr + + def initialize expr + super() + @expr = expr + end + + def hash + @expr.hash + end + + def eql? other + self.class == other.class && + self.expr == other.expr + end + alias :== :eql? + end + + %w{ + Bin + Cube + DistinctOn + Group + GroupingElement + GroupingSet + Lateral + Limit + Lock + Not + Offset + On + Ordering + RollUp + Top + }.each do |name| + const_set(name, Class.new(Unary)) + end + end +end diff --git a/activerecord/lib/arel/nodes/unary_operation.rb b/activerecord/lib/arel/nodes/unary_operation.rb new file mode 100644 index 0000000000..be4e270e76 --- /dev/null +++ b/activerecord/lib/arel/nodes/unary_operation.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +module Arel + module Nodes + + class UnaryOperation < Unary + attr_reader :operator + + def initialize operator, operand + super(operand) + @operator = operator + end + end + + class BitwiseNot < UnaryOperation + def initialize operand + super(:~, operand) + end + end + end +end diff --git a/activerecord/lib/arel/nodes/unqualified_column.rb b/activerecord/lib/arel/nodes/unqualified_column.rb new file mode 100644 index 0000000000..f9017238c8 --- /dev/null +++ b/activerecord/lib/arel/nodes/unqualified_column.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +module Arel + module Nodes + class UnqualifiedColumn < Arel::Nodes::Unary + alias :attribute :expr + alias :attribute= :expr= + + def relation + @expr.relation + end + + def column + @expr.column + end + + def name + @expr.name + end + end + end +end diff --git a/activerecord/lib/arel/nodes/update_statement.rb b/activerecord/lib/arel/nodes/update_statement.rb new file mode 100644 index 0000000000..286f0bd3ce --- /dev/null +++ b/activerecord/lib/arel/nodes/update_statement.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +module Arel + module Nodes + class UpdateStatement < Arel::Nodes::Node + attr_accessor :relation, :wheres, :values, :orders, :limit + attr_accessor :key + + def initialize + @relation = nil + @wheres = [] + @values = [] + @orders = [] + @limit = nil + @key = nil + end + + def initialize_copy other + super + @wheres = @wheres.clone + @values = @values.clone + end + + def hash + [@relation, @wheres, @values, @orders, @limit, @key].hash + end + + def eql? other + self.class == other.class && + self.relation == other.relation && + self.wheres == other.wheres && + self.values == other.values && + self.orders == other.orders && + self.limit == other.limit && + self.key == other.key + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/values.rb b/activerecord/lib/arel/nodes/values.rb new file mode 100644 index 0000000000..b32d5063a2 --- /dev/null +++ b/activerecord/lib/arel/nodes/values.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Values < Arel::Nodes::Binary + alias :expressions :left + alias :expressions= :left= + alias :columns :right + alias :columns= :right= + + def initialize exprs, columns = [] + super + end + end + end +end diff --git a/activerecord/lib/arel/nodes/values_list.rb b/activerecord/lib/arel/nodes/values_list.rb new file mode 100644 index 0000000000..89cea1790d --- /dev/null +++ b/activerecord/lib/arel/nodes/values_list.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +module Arel + module Nodes + class ValuesList < Node + attr_reader :rows + + def initialize(rows) + @rows = rows + super() + end + + def hash + @rows.hash + end + + def eql? other + self.class == other.class && + self.rows == other.rows + end + alias :== :eql? + end + end +end diff --git a/activerecord/lib/arel/nodes/window.rb b/activerecord/lib/arel/nodes/window.rb new file mode 100644 index 0000000000..23a005daba --- /dev/null +++ b/activerecord/lib/arel/nodes/window.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Window < Arel::Nodes::Node + attr_accessor :orders, :framing, :partitions + + def initialize + @orders = [] + @partitions = [] + @framing = nil + end + + def order *expr + # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically + @orders.concat expr.map { |x| + String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x + } + self + end + + def partition *expr + # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically + @partitions.concat expr.map { |x| + String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x + } + self + end + + def frame(expr) + @framing = expr + end + + def rows(expr = nil) + if @framing + Rows.new(expr) + else + frame(Rows.new(expr)) + end + end + + def range(expr = nil) + if @framing + Range.new(expr) + else + frame(Range.new(expr)) + end + end + + def initialize_copy other + super + @orders = @orders.map { |x| x.clone } + end + + def hash + [@orders, @framing].hash + end + + def eql? other + self.class == other.class && + self.orders == other.orders && + self.framing == other.framing && + self.partitions == other.partitions + end + alias :== :eql? + end + + class NamedWindow < Window + attr_accessor :name + + def initialize name + super() + @name = name + end + + def initialize_copy other + super + @name = other.name.clone + end + + def hash + super ^ @name.hash + end + + def eql? other + super && self.name == other.name + end + alias :== :eql? + end + + class Rows < Unary + def initialize(expr = nil) + super(expr) + end + end + + class Range < Unary + def initialize(expr = nil) + super(expr) + end + end + + class CurrentRow < Node + def hash + self.class.hash + end + + def eql? other + self.class == other.class + end + alias :== :eql? + end + + class Preceding < Unary + def initialize(expr = nil) + super(expr) + end + end + + class Following < Unary + def initialize(expr = nil) + super(expr) + end + end + end +end diff --git a/activerecord/lib/arel/nodes/with.rb b/activerecord/lib/arel/nodes/with.rb new file mode 100644 index 0000000000..def7840ea3 --- /dev/null +++ b/activerecord/lib/arel/nodes/with.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true +module Arel + module Nodes + class With < Arel::Nodes::Unary + alias children expr + end + + class WithRecursive < With; end + end +end + |