2016-04-14 17:24:11 +00:00
|
|
|
require "./spec_helper"
|
|
|
|
|
2016-06-21 15:10:09 +00:00
|
|
|
module GenericResultSet
|
|
|
|
@index = 0
|
2016-04-14 17:24:11 +00:00
|
|
|
|
2019-08-02 14:54:52 +00:00
|
|
|
def move_next : Bool
|
2016-04-14 17:24:11 +00:00
|
|
|
@index = 0
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def column_count : Int32
|
|
|
|
@row.size
|
|
|
|
end
|
|
|
|
|
|
|
|
def column_name(index : Int32) : String
|
|
|
|
index.to_s
|
|
|
|
end
|
|
|
|
|
2016-06-28 17:02:08 +00:00
|
|
|
def read
|
2016-04-14 18:18:09 +00:00
|
|
|
@index += 1
|
|
|
|
@row[@index - 1]
|
|
|
|
end
|
2021-10-12 23:49:26 +00:00
|
|
|
|
|
|
|
def next_column_index : Int32
|
|
|
|
@index
|
|
|
|
end
|
2016-04-14 18:18:09 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class FooValue
|
|
|
|
def initialize(@value : Int32)
|
|
|
|
end
|
|
|
|
|
|
|
|
def value
|
|
|
|
@value
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class FooDriver < DB::Driver
|
2023-06-20 14:10:58 +00:00
|
|
|
class FooConnectionBuilder < DB::ConnectionBuilder
|
|
|
|
def initialize(@options : DB::Connection::Options)
|
|
|
|
end
|
|
|
|
|
|
|
|
def build : DB::Connection
|
|
|
|
FooConnection.new(@options)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-14 18:18:09 +00:00
|
|
|
alias Any = DB::Any | FooValue
|
|
|
|
@@row = [] of Any
|
2016-04-14 17:24:11 +00:00
|
|
|
|
2016-04-14 18:18:09 +00:00
|
|
|
def self.fake_row=(row : Array(Any))
|
2016-04-14 17:24:11 +00:00
|
|
|
@@row = row
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.fake_row
|
|
|
|
@@row
|
|
|
|
end
|
|
|
|
|
2023-06-20 14:10:58 +00:00
|
|
|
def connection_builder(uri : URI) : DB::ConnectionBuilder
|
2023-05-29 01:58:55 +00:00
|
|
|
params = HTTP::Params.parse(uri.query || "")
|
2023-06-20 14:10:58 +00:00
|
|
|
FooConnectionBuilder.new(connection_options(params))
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class FooConnection < DB::Connection
|
2022-10-20 18:48:21 +00:00
|
|
|
def build_prepared_statement(query) : DB::Statement
|
|
|
|
FooStatement.new(self, query)
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
2016-11-29 23:14:07 +00:00
|
|
|
|
2022-10-20 18:48:21 +00:00
|
|
|
def build_unprepared_statement(query) : DB::Statement
|
2016-11-29 23:14:07 +00:00
|
|
|
raise "not implemented"
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class FooStatement < DB::Statement
|
2016-04-14 20:33:39 +00:00
|
|
|
protected def perform_query(args : Enumerable) : DB::ResultSet
|
2016-06-22 03:44:16 +00:00
|
|
|
args.each { |arg| process_arg arg }
|
2016-06-21 15:10:09 +00:00
|
|
|
FooResultSet.new(self, FooDriver.fake_row)
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
2016-04-15 04:40:27 +00:00
|
|
|
protected def perform_exec(args : Enumerable) : DB::ExecResult
|
2016-06-22 03:44:16 +00:00
|
|
|
args.each { |arg| process_arg arg }
|
2016-06-21 21:31:13 +00:00
|
|
|
DB::ExecResult.new 0i64, 0i64
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
2016-06-22 03:44:16 +00:00
|
|
|
|
|
|
|
private def process_arg(value : FooDriver::Any)
|
|
|
|
end
|
|
|
|
|
|
|
|
private def process_arg(value)
|
|
|
|
raise "#{self.class} does not support #{value.class} params"
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
2016-06-21 15:10:09 +00:00
|
|
|
|
|
|
|
class FooResultSet < DB::ResultSet
|
|
|
|
include GenericResultSet
|
|
|
|
|
|
|
|
def initialize(statement, @row : Array(FooDriver::Any))
|
|
|
|
super(statement)
|
|
|
|
end
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
DB.register_driver "foo", FooDriver
|
|
|
|
|
2016-04-14 18:18:09 +00:00
|
|
|
class BarValue
|
|
|
|
getter value
|
|
|
|
|
|
|
|
def initialize(@value : Int32)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-14 17:24:11 +00:00
|
|
|
class BarDriver < DB::Driver
|
2023-06-20 14:10:58 +00:00
|
|
|
class BarConnectionBuilder < DB::ConnectionBuilder
|
|
|
|
def initialize(@options : DB::Connection::Options)
|
|
|
|
end
|
|
|
|
|
|
|
|
def build : DB::Connection
|
|
|
|
BarConnection.new(@options)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-14 18:18:09 +00:00
|
|
|
alias Any = DB::Any | BarValue
|
|
|
|
@@row = [] of Any
|
2016-04-14 17:24:11 +00:00
|
|
|
|
2016-04-14 18:18:09 +00:00
|
|
|
def self.fake_row=(row : Array(Any))
|
2016-04-14 17:24:11 +00:00
|
|
|
@@row = row
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.fake_row
|
|
|
|
@@row
|
|
|
|
end
|
|
|
|
|
2023-06-20 14:10:58 +00:00
|
|
|
def connection_builder(uri : URI) : DB::ConnectionBuilder
|
2023-05-29 01:58:55 +00:00
|
|
|
params = HTTP::Params.parse(uri.query || "")
|
2023-06-20 14:10:58 +00:00
|
|
|
BarConnectionBuilder.new(connection_options(params))
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class BarConnection < DB::Connection
|
2019-08-02 14:54:52 +00:00
|
|
|
def build_prepared_statement(query) : DB::Statement
|
2020-09-25 17:49:50 +00:00
|
|
|
BarStatement.new(self, query)
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
2016-11-29 23:14:07 +00:00
|
|
|
|
2019-08-02 14:54:52 +00:00
|
|
|
def build_unprepared_statement(query) : DB::Statement
|
2016-11-29 23:14:07 +00:00
|
|
|
raise "not implemented"
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class BarStatement < DB::Statement
|
2016-04-14 20:33:39 +00:00
|
|
|
protected def perform_query(args : Enumerable) : DB::ResultSet
|
2016-06-22 03:44:16 +00:00
|
|
|
args.each { |arg| process_arg arg }
|
2016-06-21 15:10:09 +00:00
|
|
|
BarResultSet.new(self, BarDriver.fake_row)
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
2016-04-15 04:40:27 +00:00
|
|
|
protected def perform_exec(args : Enumerable) : DB::ExecResult
|
2016-06-22 03:44:16 +00:00
|
|
|
args.each { |arg| process_arg arg }
|
2016-06-21 21:31:13 +00:00
|
|
|
DB::ExecResult.new 0i64, 0i64
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
2016-06-22 03:44:16 +00:00
|
|
|
|
|
|
|
private def process_arg(value : BarDriver::Any)
|
|
|
|
end
|
|
|
|
|
|
|
|
private def process_arg(value)
|
|
|
|
raise "#{self.class} does not support #{value.class} params"
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
2016-06-21 15:10:09 +00:00
|
|
|
|
|
|
|
class BarResultSet < DB::ResultSet
|
|
|
|
include GenericResultSet
|
|
|
|
|
|
|
|
def initialize(statement, @row : Array(BarDriver::Any))
|
|
|
|
super(statement)
|
|
|
|
end
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
DB.register_driver "bar", BarDriver
|
|
|
|
|
|
|
|
describe DB do
|
|
|
|
it "should be able to register multiple drivers" do
|
2023-05-29 16:40:58 +00:00
|
|
|
DB.open("foo://host").checkout.should be_a(FooDriver::FooConnection)
|
|
|
|
DB.open("bar://host").checkout.should be_a(BarDriver::BarConnection)
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it "Foo and Bar drivers should return fake_row" do
|
|
|
|
with_witness do |w|
|
|
|
|
DB.open("foo://host") do |db|
|
2016-06-24 01:36:34 +00:00
|
|
|
FooDriver.fake_row = [1, "string", FooValue.new(3)] of FooDriver::Any
|
2016-04-14 17:24:11 +00:00
|
|
|
db.query "query" do |rs|
|
|
|
|
w.check
|
|
|
|
rs.move_next
|
2016-06-28 17:02:08 +00:00
|
|
|
rs.read(Int32).should eq(1)
|
|
|
|
rs.read(String).should eq("string")
|
2016-06-21 15:10:09 +00:00
|
|
|
rs.read(FooValue).value.should eq(3)
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
with_witness do |w|
|
|
|
|
DB.open("bar://host") do |db|
|
2016-06-24 01:36:34 +00:00
|
|
|
BarDriver.fake_row = [BarValue.new(4), "lorem", 1.0] of BarDriver::Any
|
2016-04-14 17:24:11 +00:00
|
|
|
db.query "query" do |rs|
|
|
|
|
w.check
|
|
|
|
rs.move_next
|
2016-06-21 15:10:09 +00:00
|
|
|
rs.read(BarValue).value.should eq(4)
|
2016-06-28 17:02:08 +00:00
|
|
|
rs.read(String).should eq("lorem")
|
|
|
|
rs.read(Float64).should eq(1.0)
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-04-14 20:33:39 +00:00
|
|
|
|
2016-06-24 01:19:53 +00:00
|
|
|
it "drivers should return custom values as scalar" do
|
|
|
|
DB.open("foo://host") do |db|
|
2016-06-24 01:36:34 +00:00
|
|
|
FooDriver.fake_row = [FooValue.new(3)] of FooDriver::Any
|
2016-06-24 01:19:53 +00:00
|
|
|
db.scalar("query").as(FooValue).value.should eq(3)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-21 15:10:09 +00:00
|
|
|
it "Foo and Bar drivers should not implement each other read" do
|
|
|
|
with_witness do |w|
|
|
|
|
DB.open("foo://host") do |db|
|
|
|
|
FooDriver.fake_row = [1] of FooDriver::Any
|
|
|
|
db.query "query" do |rs|
|
|
|
|
rs.move_next
|
2021-10-12 23:49:26 +00:00
|
|
|
expect_raises(DB::ColumnTypeMismatchError, "In FooDriver::FooResultSet#read the column 0 returned a Int32 but a BarValue was expected.") do
|
2016-06-21 15:10:09 +00:00
|
|
|
w.check
|
|
|
|
rs.read(BarValue)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
with_witness do |w|
|
|
|
|
DB.open("bar://host") do |db|
|
|
|
|
BarDriver.fake_row = [1] of BarDriver::Any
|
|
|
|
db.query "query" do |rs|
|
|
|
|
rs.move_next
|
2021-10-12 23:49:26 +00:00
|
|
|
expect_raises(DB::ColumnTypeMismatchError, "In BarDriver::BarResultSet#read the column 0 returned a Int32 but a FooValue was expected.") do
|
2016-06-21 15:10:09 +00:00
|
|
|
w.check
|
|
|
|
rs.read(FooValue)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-14 20:33:39 +00:00
|
|
|
it "allow custom types to be used as arguments for query" do
|
|
|
|
DB.open("foo://host") do |db|
|
|
|
|
FooDriver.fake_row = [1, "string"] of FooDriver::Any
|
|
|
|
db.query "query" { }
|
|
|
|
db.query "query", 1 { }
|
|
|
|
db.query "query", 1, "string" { }
|
2016-06-22 17:10:09 +00:00
|
|
|
db.query("query", Bytes.new(4)) { }
|
2016-04-14 20:33:39 +00:00
|
|
|
db.query("query", 1, "string", FooValue.new(5)) { }
|
2019-09-20 20:23:09 +00:00
|
|
|
db.query "query", args: [1, "string", FooValue.new(5)] { }
|
2016-04-14 21:50:44 +00:00
|
|
|
|
|
|
|
db.query("query").close
|
|
|
|
db.query("query", 1).close
|
|
|
|
db.query("query", 1, "string").close
|
2016-06-22 17:10:09 +00:00
|
|
|
db.query("query", Bytes.new(4)).close
|
2016-04-14 21:50:44 +00:00
|
|
|
db.query("query", 1, "string", FooValue.new(5)).close
|
2019-09-20 20:23:09 +00:00
|
|
|
db.query("query", args: [1, "string", FooValue.new(5)]).close
|
2016-04-14 20:33:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
DB.open("bar://host") do |db|
|
|
|
|
BarDriver.fake_row = [1, "string"] of BarDriver::Any
|
|
|
|
db.query "query" { }
|
|
|
|
db.query "query", 1 { }
|
|
|
|
db.query "query", 1, "string" { }
|
2016-06-22 17:10:09 +00:00
|
|
|
db.query("query", Bytes.new(4)) { }
|
2016-04-14 20:33:39 +00:00
|
|
|
db.query("query", 1, "string", BarValue.new(5)) { }
|
2019-09-20 20:23:09 +00:00
|
|
|
db.query "query", args: [1, "string", BarValue.new(5)] { }
|
2016-04-14 21:50:44 +00:00
|
|
|
|
|
|
|
db.query("query").close
|
|
|
|
db.query("query", 1).close
|
|
|
|
db.query("query", 1, "string").close
|
2016-06-22 17:10:09 +00:00
|
|
|
db.query("query", Bytes.new(4)).close
|
2016-04-14 21:50:44 +00:00
|
|
|
db.query("query", 1, "string", BarValue.new(5)).close
|
2019-09-20 20:23:09 +00:00
|
|
|
db.query("query", args: [1, "string", BarValue.new(5)]).close
|
2016-04-14 20:33:39 +00:00
|
|
|
end
|
|
|
|
end
|
2016-04-15 04:40:27 +00:00
|
|
|
|
|
|
|
it "allow custom types to be used as arguments for exec" do
|
|
|
|
DB.open("foo://host") do |db|
|
|
|
|
FooDriver.fake_row = [1, "string"] of FooDriver::Any
|
|
|
|
db.exec("query")
|
|
|
|
db.exec("query", 1)
|
|
|
|
db.exec("query", 1, "string")
|
2016-06-22 17:10:09 +00:00
|
|
|
db.exec("query", Bytes.new(4))
|
2016-04-15 04:40:27 +00:00
|
|
|
db.exec("query", 1, "string", FooValue.new(5))
|
2019-09-20 20:23:09 +00:00
|
|
|
db.exec("query", args: [1, "string", FooValue.new(5)])
|
2016-04-15 04:40:27 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
DB.open("bar://host") do |db|
|
|
|
|
BarDriver.fake_row = [1, "string"] of BarDriver::Any
|
|
|
|
db.exec("query")
|
|
|
|
db.exec("query", 1)
|
|
|
|
db.exec("query", 1, "string")
|
2016-06-22 17:10:09 +00:00
|
|
|
db.exec("query", Bytes.new(4))
|
2016-04-15 04:40:27 +00:00
|
|
|
db.exec("query", 1, "string", BarValue.new(5))
|
2019-09-20 20:23:09 +00:00
|
|
|
db.exec("query", args: [1, "string", BarValue.new(5)])
|
2016-04-15 04:40:27 +00:00
|
|
|
end
|
|
|
|
end
|
2016-06-22 03:44:16 +00:00
|
|
|
|
|
|
|
it "Foo and Bar drivers should not implement each other params" do
|
|
|
|
DB.open("foo://host") do |db|
|
|
|
|
expect_raises Exception, "FooDriver::FooStatement does not support BarValue params" do
|
2019-09-20 20:23:09 +00:00
|
|
|
db.exec("query", args: [BarValue.new(5)])
|
2016-06-22 03:44:16 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
DB.open("bar://host") do |db|
|
|
|
|
expect_raises Exception, "BarDriver::BarStatement does not support FooValue params" do
|
2019-09-20 20:23:09 +00:00
|
|
|
db.exec("query", args: [FooValue.new(5)])
|
2016-06-22 03:44:16 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-04-14 17:24:11 +00:00
|
|
|
end
|