module SQLTree::Node
# The SQLTree::Node::Base class is the superclass for all node
# types that are used to represent SQL queries.
#
# This class implements some helper methods, and enables the
# SQLTree::Node::NodeType['SQL fragment'] construct to parse SQL
# queries.
class Base
def initialize(attributes = {}) # :nodoc:
attributes.each { |key, value| send(:"#{key}=", value) }
end
# Pretty prints this instance for inspection
def inspect
"#{self.class.name}[#{self.to_sql}]"
end
# Quotes a variable name so that it can be safely used within
# SQL queries.
# name:: The name of the variable to quote.
def quote_var(name)
"#{SQLTree.identifier_quote_char}#{name}#{SQLTree.identifier_quote_char}" # TODO: MySQL style variable quoting
end
# Quotes a string so that it can be used safey within an SQL query.
# str:: The string to quote.
def quote_str(str)
"'#{str.gsub("'", "''")}'"
end
# Registers the children and leafs attributes in the subclass
def self.inherited(subclass)
class << subclass; attr_accessor :children, :leafs; end
subclass.children = []
subclass.leafs = []
end
# Adds another leaf to this node class.
def self.leaf(name)
self.leafs << name
self.send(:attr_accessor, name)
end
# Adds another child to this node class.
def self.child(name)
self.children << name
self.send(:attr_accessor, name)
end
# Compares this node with another node, returns true if the nodes are equal.
def ==(other)
other.kind_of?(self.class) && equal_children?(other) && equal_leafs?(other)
end
# Returns true if all children of the current object and the other object are equal.
def equal_children?(other)
self.class.children.all? { |child| send(child) == other.send(child) }
end
# Returns true if all leaf values of the current object and the other object are equal.
def equal_leafs?(other)
self.class.leafs.all? { |leaf| send(leaf) == other.send(leaf) }
end
# Parses an SQL fragment tree from a stream of tokens.
#
# This method should be implemented by each subclass.
# This method should not be called directly, but the
# SQLTree::Node::Subclass#[] should be called to
# parse an SQL fragment provided as a string.
#
# tokens:: the token stream to use for parsing.
def self.parse(tokens)
raise 'Only implemented in subclasses!'
end
def self.parse_list(tokens, item_class = SQLTree::Node::Expression)
items = [item_class.parse(tokens)]
while SQLTree::Token::COMMA === tokens.peek
tokens.consume(SQLTree::Token::COMMA)
items << item_class.parse(tokens)
end
return items
end
# Parses a string, expecting it to be parsable to an instance of
# the current class.
#
# This method will construct a new parser that will tokenize the
# string, and will then present the stream of tokens to the
# self.parse method of the current class.
#
# sql:: The SQL string to parse
# options:: A Hash of options to send to the parser.
def self.[](sql, options = {})
parser = SQLTree::Parser.new(sql, options)
self.parse(parser)
end
end
end
require 'sql_tree/node/expression'
require 'sql_tree/node/select_query'
require 'sql_tree/node/select_declaration'
require 'sql_tree/node/table_reference'
require 'sql_tree/node/source'
require 'sql_tree/node/join'
require 'sql_tree/node/ordering'
require 'sql_tree/node/insert_query'
require 'sql_tree/node/update_query'
require 'sql_tree/node/delete_query'
require 'sql_tree/node/set_query'
require 'sql_tree/node/begin_statement'
require 'sql_tree/node/commit_statement'
require 'sql_tree/node/rollback_statement'