Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQL in ruby #91

Merged
merged 14 commits into from
Oct 22, 2023
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ You will get output like so:
```bash
$ invoke test python any

docker run ...
⏱ ./src/python/sort_builtin.py on ./data/sort_input_0.txt ran for 0.5 seconds
docker run ... python ./src/python/sort_builtin.py
⏱ ./src/python/sort_builtin.py on ./data/sort_input_0.txt ran for 0.52 seconds
🟢 ./src/python/sort_builtin.py on ./data/sort_input_0.txt succeeded
docker run ...
⏱ ./src/python/sort_bubble_sort.py on ./data/sort_input_0.txt ran for 0.51 seconds
🟢 ./src/python/sort_bubble_sort.py on ./data/sort_input_0.txt succeeded
docker run ...
⏱ ./src/python/sort_selection_sort.py on ./data/sort_input_0.txt ran for 0.58 seconds
🟢 ./src/python/sort_selection_sort.py on ./data/sort_input_0.txt succeeded
docker run ...
⏱ ./src/python/sort_insertion_sort.py on ./data/sort_input_0.txt ran for 0.52 seconds
🟢 ./src/python/sort_insertion_sort.py on ./data/sort_input_0.txt succeeded
docker run ... python ./src/python/sql_test.py
⏱ ./src/python/sql_test.py on ./data/sql_input_2.sql ran for 0.75 seconds
🟢 ./src/python/sql_test.py on ./data/sql_input_2.sql succeeded
docker run ... python ./src/python/sql_test.py
⏱ ./src/python/sql_test.py on ./data/sql_input_3.sql ran for 0.75 seconds
🟢 ./src/python/sql_test.py on ./data/sql_input_3.sql succeeded
docker run ... python ./src/python/sql_test.py
⏱ ./src/python/sql_test.py on ./data/sql_input_1.sql ran for 0.74 seconds
🟢 ./src/python/sql_test.py on ./data/sql_input_1.sql succeeded

✨ script run success ✨
```
Expand Down
144 changes: 144 additions & 0 deletions snippets/ruby/sql_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
class SQLState
attr_reader :state

def initialize(state = {})
@state = state
end

def read_table_meta(table_name)
@state[table_name] ? @state[table_name]['metadata'] || {} : {}
end

def read_table_rows(table_name)
@state[table_name] ? @state[table_name]['rows'] || [] : []
end

def read_information_schema
@state.values.map { |data| data['metadata'] }
end

def write_table_meta(table_name, data)
@state[table_name] ||= {}
@state[table_name]['metadata'] ||= {}
@state[table_name]['metadata'].merge!(data)
self.class.new(@state)
end

def write_table_rows(table_name, data)
@state[table_name] ||= {}
@state[table_name]['rows'] ||= []
@state[table_name]['rows'] << data
self.class.new(@state)
end
end

module SQLType
def self.varchar(data)
data.to_s.strip.sub(/^['"]/, '').sub(/['"]$/, '')
end

def self.int(data)
data.to_i
end
end

module SQLFunctions
def self.create_table(state, *args, table_schema: 'public')
output = []
table_name = args[2]

columns = {}
columns_str = args[3..].join(' ').gsub(/[()]/, '').strip
unless columns_str.empty?
columns = Hash[columns_str.split(',').map { |column| column.strip.split(' ') }]
end

if state.read_table_meta(table_name).empty?
metadata = {
'table_name' => table_name,
'table_schema' => table_schema,
'columns' => columns
}
state = state.write_table_meta(table_name, metadata)
end

[output, state]
end

def self.insert_into(state, *args)
output = []
table_name = args[2]

sql_type_map = {
'VARCHAR' => SQLType.method(:varchar),
'INT' => SQLType.method(:int)
}

values_index = args.index('VALUES')
raise 'VALUES not found' if values_index.nil?

keys = args[3...values_index].join(' ').gsub(/[()]/, '').split(',').map(&:strip)
values = args[values_index + 1..].join(' ').gsub(/[()]/, '').split(',').map(&:strip)
key_value_map = Hash[keys.zip(values)]

metadata = state.read_table_meta(table_name)
row = {}
key_value_map.each do |key, value|
row[key] = sql_type_map[metadata['columns'][key]].call(value)
end
state = state.write_table_rows(table_name, row)

[output, state]
end

def self.select(state, *args)
output = []

from_index = args.index('FROM')
# where_index = args.index('WHERE')

raise 'FROM not found' if from_index.nil?

select_keys = args[1...from_index].join(' ').split(',').map(&:strip)
from_value = args[from_index + 1]

data = if from_value == 'information_schema.tables'
state.read_information_schema
else
state.read_table_rows(from_value)
end

data.each do |datum|
output << select_keys.map { |key| [key, datum[key]] }.to_h
end

[output, state]
end
end

def run_sql(input_sql)
output = []
state = SQLState.new

input_sql = input_sql.map(&:strip).reject { |line| line.start_with?('--') }
input_sql = input_sql.join(' ').split(';')

sql_function_map = {
'CREATE TABLE' => SQLFunctions.method(:create_table),
'SELECT' => SQLFunctions.method(:select),
'INSERT INTO' => SQLFunctions.method(:insert_into)
}

input_sql.each do |line|
words = line.split(' ')
words.each_index do |i|
key = words[0..i].join(' ').strip
if sql_function_map.key?(key)
output, state = sql_function_map[key].call(state, *words.reject(&:empty?))
break
end
end
end

[output.to_json]
end
14 changes: 7 additions & 7 deletions src/ruby/sort_bubble_sort.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ def do_sorting_round(input_list)
# business logic end #
######################

# 👇🏽 copy pasted helpers
if __FILE__ == $PROGRAM_NAME
input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)

input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)
sorted_data = do_sorting(input_file)

sorted_data = do_sorting(input_file)

output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
end
14 changes: 7 additions & 7 deletions src/ruby/sort_builtin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ def do_sorting(input_list)
# business logic end #
######################

# 👇🏽 copy pasted helpers
if __FILE__ == $PROGRAM_NAME
input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)

input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)
sorted_data = do_sorting(input_file)

sorted_data = do_sorting(input_file)

output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
end
14 changes: 7 additions & 7 deletions src/ruby/sort_insertion_sort.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ def swap(idx)
# business logic end #
######################

# 👇🏽 copy pasted helpers
if __FILE__ == $PROGRAM_NAME
input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)

input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)
sorted_data = do_sorting(input_file)

sorted_data = do_sorting(input_file)

output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
end
14 changes: 7 additions & 7 deletions src/ruby/sort_selection_sort.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ def find_smallest_index(input_list)
# business logic end #
######################

# 👇🏽 copy pasted helpers
if __FILE__ == $PROGRAM_NAME
input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)

input_file_path = ENV['INPUT_PATH']
input_file = File.readlines(input_file_path)
sorted_data = do_sorting(input_file)

sorted_data = do_sorting(input_file)

output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
output_file_path = ENV['OUTPUT_PATH']
File.open(output_file_path, 'wb') { |f| f.write(sorted_data.join('')) }
end
Loading