module Arel
module Enhance
module ContextEnhancer
class ArelTable
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/AbcSize
def self.call(node)
context = node.context.merge!(
range_variable: false, column_reference: false, alias: false,
)
parent_object = node.parent.object
# Using Arel::Table as SELECT ... FROM
if parent_object.is_a?(Arel::Nodes::JoinSource)
context[:range_variable] = true
# NOTE: only applies to ActiveRecord generated Arel
# which does not use Arel::Table#alias but Arel::TableAlias instead
# Using Arel::Table as SELECT ... FROM AS alias
elsif parent_object.is_a?(Arel::Nodes::TableAlias) &&
node.parent.parent.object.is_a?(Arel::Nodes::JoinSource)
context[:range_variable] = true
# Using Arel::Table as SELECT ... FROM []
elsif parent_object.is_a?(Array) &&
node.parent.parent.object.is_a?(Arel::Nodes::JoinSource)
context[:range_variable] = true
# NOTE: only applies to ActiveRecord generated Arel
# which does not use Arel::Table#alias but Arel::TableAlias instead
# Using Arel::Table as SELECT ... FROM [ AS alias]
elsif parent_object.is_a?(Arel::Nodes::TableAlias) &&
node.parent.parent.object.is_a?(Array) &&
node.parent.parent.parent.object.is_a?(Arel::Nodes::JoinSource)
context[:range_variable] = true
# Using Arel::Table as SELECT ... INNER JOIN ON TRUE
elsif parent_object.is_a?(Arel::Nodes::Join)
context[:range_variable] = true
# Using Arel::Table as an attribute SELECT .id ...
elsif parent_object.is_a?(Arel::Attributes::Attribute)
context[:column_reference] = true
# Using Arel::Table in an INSERT INTO
elsif parent_object.is_a?(Arel::Nodes::InsertStatement)
context[:range_variable] = true
# Using Arel::Table in an UPDATE ...
elsif parent_object.is_a?(Arel::Nodes::UpdateStatement)
context[:range_variable] = true
# Arel::Table in UPDATE ... FROM []
elsif parent_object.is_a?(Array) &&
node.parent.parent.object.is_a?(Arel::Nodes::UpdateStatement)
context[:range_variable] = true
# Using Arel::Table in an DELETE FROM
elsif parent_object.is_a?(Arel::Nodes::DeleteStatement)
context[:range_variable] = true
# Arel::Table in DELETE ... USING []
elsif parent_object.is_a?(Array) &&
node.parent.parent.object.is_a?(Arel::Nodes::DeleteStatement)
context[:range_variable] = true
# Using Arel::Table as an "alias" for WITH AS (SELECT 1) SELECT 1
elsif parent_object.is_a?(Arel::Nodes::As) &&
node.parent.parent.parent.object.is_a?(Arel::Nodes::With)
context[:alias] = true
# Using Arel::Table as an "alias" for WITH RECURSIVE AS (SELECT 1) SELECT 1
elsif parent_object.is_a?(Arel::Nodes::As) &&
node.parent.parent.parent.object.is_a?(Arel::Nodes::WithRecursive)
context[:alias] = true
# Using Arel::Table as an "alias" for SELECT INTO ...
elsif parent_object.is_a?(Arel::Nodes::Into)
context[:alias] = true
else
raise "Unknown AST location for table #{node.inspect}, #{node.root_node.to_sql}"
end
end
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/AbcSize
end
end
end
end