127 lines
3.6 KiB
Ruby
127 lines
3.6 KiB
Ruby
def match_sql_command(sql)
|
|
options_pattern = %q{
|
|
(?:\s+OPTIONS\s*\((?<options>
|
|
(?:
|
|
\s*
|
|
(?:\"(?:[^\"]+)\"|(?:[^\s]+))
|
|
\s+
|
|
(?:\'(?:[^\']*)\'|(?:[^\'].+))
|
|
)*
|
|
\s*
|
|
)\))?
|
|
}
|
|
patterns = {
|
|
create_server: %r{
|
|
CREATE\s+SERVER\s+(?<server_name>[^\s]+)
|
|
\s+
|
|
FOREIGN\s+DATA\s+WRAPPER\s+(?<fdw_name>[^\s]+)
|
|
#{options_pattern}
|
|
}xi,
|
|
create_user_mapping: %r{
|
|
CREATE\s+USER\s+MAPPING\s+FOR\s+\"?(?<user_name>[^\s\"]+)\"?
|
|
\s+
|
|
SERVER\s+(?<server_name>[^\s]+)
|
|
#{options_pattern}
|
|
}xi,
|
|
import_foreign_schema: %r{
|
|
IMPORT\s+FOREIGN\s+SCHEMA\s+\"?(?<remote_schema_name>[^\s\"]+)\"?
|
|
\s+
|
|
FROM\s+SERVER\s+(?<server_name>[^\s]+)
|
|
\s+
|
|
INTO\s+\"?(?<schema_name>[^\s\"]+)\"?
|
|
#{options_pattern}
|
|
}xi,
|
|
import_foreign_schema_limited: %r{
|
|
IMPORT\s+FOREIGN\s+SCHEMA\s+\"?(?<remote_schema_name>[^\s\"]+)\"?
|
|
\s+
|
|
LIMIT\s+TO\s+\((?<limited_to>.+)\)
|
|
\s+
|
|
FROM\s+SERVER\s+(?<server_name>[^\s]+)
|
|
\s+
|
|
INTO\s+\"?(?<schema_name>[^\s\"]+)\"?
|
|
#{options_pattern}
|
|
}xi,
|
|
create_foreign_table: %r{
|
|
CREATE\+FOREIGN\+TABLE\s+(?<table_name>.+)\s*\((?<columns>.+)\)
|
|
\s+
|
|
SERVER\s+(?<server_name>[^\s]+)
|
|
#{options_pattern}
|
|
}xi,
|
|
grant_select: %r{
|
|
GRANT\s+SELECT\s+ON\s+(?<table_name>[^\s]+)\s+TO\s+\"?(?<user_name>[^\s\"]+)\"?
|
|
}xi,
|
|
create_table_as_select: %r{
|
|
CREATE\s+TABLE\s+(?<table_name>[^\s]+)\s+AS\s+SELECT\s+(?<select>.+)(?:\s+LIMIT\s+(?<limit>\d+))?
|
|
}xi,
|
|
drop_foreign_table_if_exists: %r{
|
|
DROP\s+FOREIGN\s+TABLE\s+IF\s+EXISTS\s+(?<table_name>[^\s]+)(?:\s+(?<cascade>CASCADE))?
|
|
}xi,
|
|
drop_server_if_exists: %r{
|
|
DROP\s+SERVER\s+IF\s+EXISTS\s+(?<server_name>[^\s]+)(?:\s+(?<cascade>CASCADE))?
|
|
}xi,
|
|
drop_usermapping_if_exists: %r{
|
|
DROP\s+USER\s+MAPPING\s+IF\s+EXISTS\s+FOR\s+\"?(?<user_name>[^\s\"]+)\"?\s+SERVER\s+(?<server_name>[^\s]+)
|
|
}xi,
|
|
rename_foreign_table: %r{
|
|
ALTER\s+FOREIGN\s+TABLE\s+(?<table_name>.+)\s+RENAME\s+TO\s+(?<new_name>.+)
|
|
}xi,
|
|
select_all: %r{
|
|
SELECT\s+\*\s+FROM\s+(?<from>.+)
|
|
}xi
|
|
}
|
|
option_pair = %r{
|
|
\A\s*
|
|
(?:\"(?<quoted_name>[^\"]+)\"|(?<name>[^\s]+))
|
|
\s+
|
|
(?:\'(?<quoted_value>[^\']*)\'|(?<value>[^\'].+))
|
|
}x
|
|
|
|
result = nil
|
|
patterns.each do |command, regexp|
|
|
match = regexp.match(sql)
|
|
if match
|
|
result = {
|
|
command: command
|
|
}
|
|
match.names.each do |name|
|
|
value = match[name]
|
|
if value
|
|
if name.in? ['options', 'columns']
|
|
value = Hash[
|
|
value.split(',').map { |opt|
|
|
match = opt.match(option_pair)
|
|
[match[:name] || match[:quoted_name], match[:value] || match[:quoted_value]] if match
|
|
}.compact
|
|
]
|
|
end
|
|
result[name.to_sym] = value
|
|
end
|
|
end
|
|
break
|
|
end
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
def match_sql(sql)
|
|
sql.scan(/(?:'[^']*'|[^;])+/).map { |command| match_sql_command(command) }.compact
|
|
end
|
|
|
|
def expect_sql(sql, expectactions = [])
|
|
match_sql(sql).zip(expectactions).each do |parsed_sql, sql_expectactions|
|
|
sql_expectactions.each do |key, expected_value|
|
|
if expected_value.nil?
|
|
parsed_sql[key].should be_nil, "#{key.inspect} wasn't expected in SQL"
|
|
else
|
|
parsed_sql[key].should_not be_nil, "#{key.inspect} was expected in SQL"
|
|
if expected_value.is_a?(Regexp)
|
|
parsed_sql[key].should match expected_value
|
|
else
|
|
parsed_sql[key].should eq expected_value
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|