Created
September 17, 2011 03:43
-
-
Save taku0/1223605 to your computer and use it in GitHub Desktop.
オレオレJDBCラッパのプロトタイプ Ruby版
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
class RowParser | |
end | |
class BlockParser < RowParser | |
def initialize(*parsers, &block) | |
@block = block | |
@parsers = parsers | |
end | |
def arity | |
@parsers.map(&:arity).inject(0) do |left, right| left + right end | |
end | |
def parse(resultSet, index) | |
elements = @parsers.map do |parser| | |
element = parser.parse(resultSet, index) | |
index += parser.arity | |
element | |
end | |
@block.call(*elements) | |
end | |
end | |
class ParameterSetter | |
def to_setter | |
self | |
end | |
end | |
class TupleSetter < ParameterSetter | |
def initialize(*setters) | |
@setters = setters | |
end | |
def arity | |
@setters.map(&:arity).inject(0) do |left, right| left + right end | |
end | |
def set_to(index, statement) | |
@setters.each do |setter| | |
setter.set_to(index, statement) | |
index += setter.arity | |
end | |
end | |
def set_null(index, statement) | |
@setters.each do |setter| | |
setter.set_null(index, statement) | |
index += setter.arity | |
end | |
end | |
end | |
class RichConnection | |
def initialize(connection) | |
@connection = connection | |
end | |
def query_array(sql, parser, *setters) | |
if not parser.kind_of?(RowParser) | |
parser = parser::ROW_PARSER | |
end | |
statement = @connection.prepareStatement(sql) | |
begin | |
set_parameters(statement, setters) | |
result_set = statement.executeQuery() | |
array = [] | |
while result_set.next() | |
array.push(parser.parse(result_set, 1)) | |
end | |
array | |
ensure | |
statement.close() | |
end | |
end | |
def execute_update(sql, *setters) | |
statement = @connection.prepareStatement(sql) | |
begin | |
set_parameters(statement, setters) | |
statement.executeUpdate() | |
rescue | |
statement.close() | |
end | |
end | |
protected | |
def set_parameters(statement, setters) | |
index = 1 | |
setters.each do |setter| | |
setter = setter.to_setter | |
setter.set_to(index, statement) | |
index += setter.arity | |
end | |
end | |
end | |
class Int | |
ROW_PARSER = RowParser.new | |
class << ROW_PARSER | |
def arity | |
1 | |
end | |
def parse(resultSet, index) | |
resultSet.getInt(index) | |
end | |
end | |
class Setter < ParameterSetter | |
def initialize(value) | |
@value = value | |
end | |
def arity | |
1 | |
end | |
def set_to(index, statement) | |
if @value.nil? | |
set_null(index, statement) | |
else | |
statement.setInt(index, @value) | |
end | |
end | |
def set_null(index, statement) | |
statement.setNull(index, Types::INTEGER) | |
end | |
end | |
def self.to_setter(value) | |
Setter.new(value) | |
end | |
end | |
class Module | |
def case_class(*parameters) | |
parameter_names = parameters.map do |parameter| | |
("@" + parameter[0].to_s).to_sym | |
end | |
define_method(:initialize) do |*args| | |
args.zip(parameter_names).each do |arg, parameter_name| | |
instance_variable_set(parameter_name, arg) | |
end | |
end | |
define_method(:to_a) do | |
parameter_names.map do |parameter_name| | |
instance_variable_get(parameter_name) | |
end | |
end | |
parameter_types = parameters.map do |parameter| | |
parameter[1] | |
end | |
const_set(:ROW_PARSER, BlockParser.new(*(parameter_types.map do |type| type::ROW_PARSER end), &method(:new))) | |
define_singleton_method(:to_setter) do |value| | |
tuple = value.to_a | |
setters = parameter_types.map.with_index do |type, index| | |
type.to_setter(tuple[index]) | |
end | |
TupleSetter.new(*setters) | |
end | |
mod = self | |
define_method(:to_setter) do | |
mod.to_setter(self) | |
end | |
class_name = name | |
define_method(:to_s) do | |
"#{class_name}(#{to_a.join(', ')})" | |
end | |
end | |
end | |
class Foo | |
case_class([:a, Int], | |
[:b, Int]) | |
end | |
class Bar | |
case_class([:a, Foo], | |
[:b, Int]) | |
end | |
class Buz | |
case_class([:a, Int], | |
[:b, Bar]) | |
end | |
# java.sql以下のクラスのデモ用実装 | |
class NullConnection | |
def prepareStatement(sql) | |
puts("prepareStatement(#{sql.inspect})") | |
NullPreparedStatement.new | |
end | |
end | |
class NullPreparedStatement | |
def executeQuery | |
puts("executeQuery()") | |
NullResultSet.new | |
end | |
def executeUpdate | |
puts("executeUpdate()") | |
1 | |
end | |
def setInt(index, value) | |
puts("setInt(#{index}, #{value})") | |
end | |
def setNull(index, type) | |
puts("setNull(#{index}, #{type})") | |
end | |
def close | |
puts("close()") | |
end | |
end | |
class NullResultSet | |
def next | |
puts("next()") | |
@x ||= 0 | |
@x += 1 | |
@x < 3 | |
end | |
def getInt(index) | |
puts("getInt(#{index})") | |
@v ||= 0 | |
@v += 1 | |
@v | |
end | |
end | |
class Types | |
INTEGER = :INTEGER | |
end | |
puts("Buz::ROW_PARSER.arity = #{Buz::ROW_PARSER.arity}") | |
puts("Buz.to_setter(nil).arity = #{Buz.to_setter(nil).arity}") | |
puts | |
connection = NullConnection.new | |
buz_array = RichConnection.new(connection).query_array("SELECT a, b, c, d FROM t WHERE x = ? AND y = ?", Buz, Int.to_setter(1), Int.to_setter(2)) | |
puts | |
puts(buz_array) | |
puts | |
RichConnection.new(connection).execute_update("INSERT INTO s (a, b, c, d) VALUES (?, ?, ?, ?)", buz_array[1]) | |
puts | |
RichConnection.new(connection).execute_update("INSERT INTO s (a, b, c, d) VALUES (?, ?, ?, ?)", Buz.to_setter(nil)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment