cartodb/services/importer/spec/unit/sql_helper.rb
2020-06-15 10:58:47 +08:00

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