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

Support non prepared statements #25

Merged
merged 8 commits into from
Dec 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions spec/custom_drivers_types_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ class FooDriver < DB::Driver
end

class FooConnection < DB::Connection
def build_statement(query)
def build_prepared_statement(query)
FooStatement.new(self)
end

def build_unprepared_statement(query)
raise "not implemented"
end
end

class FooStatement < DB::Statement
Expand Down Expand Up @@ -107,9 +111,13 @@ class BarDriver < DB::Driver
end

class BarConnection < DB::Connection
def build_statement(query)
def build_prepared_statement(query)
BarStatement.new(self)
end

def build_unprepared_statement(query)
raise "not implemented"
end
end

class BarStatement < DB::Statement
Expand Down
96 changes: 89 additions & 7 deletions spec/database_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,24 @@ describe DB::Database do

it "should allow creation of more statements than pool connections" do
DB.open "dummy://localhost:1027?initial_pool_size=1&max_pool_size=2" do |db|
db.prepare("query1").should be_a(DB::PoolStatement)
db.prepare("query2").should be_a(DB::PoolStatement)
db.prepare("query3").should be_a(DB::PoolStatement)
db.build("query1").should be_a(DB::PoolPreparedStatement)
db.build("query2").should be_a(DB::PoolPreparedStatement)
db.build("query3").should be_a(DB::PoolPreparedStatement)
end
end

it "should return same statement in pool per query" do
with_dummy do |db|
stmt = db.prepare("query1")
db.prepare("query2").should_not eq(stmt)
db.prepare("query1").should eq(stmt)
stmt = db.build("query1")
db.build("query2").should_not eq(stmt)
db.build("query1").should eq(stmt)
end
end

it "should close pool statements when closing db" do
stmt = uninitialized DB::PoolStatement
with_dummy do |db|
stmt = db.prepare("query1")
stmt = db.build("query1")
end
stmt.closed?.should be_true
end
Expand Down Expand Up @@ -97,4 +97,86 @@ describe DB::Database do
DummyDriver::DummyConnection.connections.size.should eq(2)
end
end

describe "prepared_statements connection option" do
it "defaults to true" do
with_dummy "dummy://localhost:1027" do |db|
db.prepared_statements?.should be_true
end
end

it "can be set to false" do
with_dummy "dummy://localhost:1027?prepared_statements=false" do |db|
db.prepared_statements?.should be_false
end
end

it "is copied to connections (false)" do
with_dummy "dummy://localhost:1027?prepared_statements=false&initial_pool_size=1" do |db|
connection = DummyDriver::DummyConnection.connections.first
connection.prepared_statements?.should be_false
end
end

it "is copied to connections (true)" do
with_dummy "dummy://localhost:1027?prepared_statements=true&initial_pool_size=1" do |db|
connection = DummyDriver::DummyConnection.connections.first
connection.prepared_statements?.should be_true
end
end

it "should build prepared statements if true" do
with_dummy "dummy://localhost:1027?prepared_statements=true" do |db|
db.build("the query").should be_a(DB::PoolPreparedStatement)
end
end

it "should build unprepared statements if false" do
with_dummy "dummy://localhost:1027?prepared_statements=false" do |db|
db.build("the query").should be_a(DB::PoolUnpreparedStatement)
end
end

it "should be overrided by dsl" do
with_dummy "dummy://localhost:1027?prepared_statements=true" do |db|
stmt = db.unprepared.query("the query").statement.as(DummyDriver::DummyStatement)
stmt.prepared?.should be_false
end

with_dummy "dummy://localhost:1027?prepared_statements=false" do |db|
stmt = db.prepared.query("the query").statement.as(DummyDriver::DummyStatement)
stmt.prepared?.should be_true
end
end
end

describe "unprepared statements in pool" do
it "creating statements should not create new connections" do
with_dummy "dummy://localhost:1027?initial_pool_size=1" do |db|
stmt1 = db.unprepared.build("query1")
stmt2 = db.unprepared.build("query2")
DummyDriver::DummyConnection.connections.size.should eq(1)
end
end

it "simultaneous statements should go to different connections" do
with_dummy "dummy://localhost:1027?initial_pool_size=1" do |db|
rs1 = db.unprepared.query("query1")
rs2 = db.unprepared.query("query2")
rs1.statement.connection.should_not eq(rs2.statement.connection)
DummyDriver::DummyConnection.connections.size.should eq(2)
end
end

it "sequential statements should go to different connections" do
with_dummy "dummy://localhost:1027?initial_pool_size=1" do |db|
rs1 = db.unprepared.query("query1")
rs1.close
rs2 = db.unprepared.query("query2")
rs2.close
rs1.statement.connection.should eq(rs2.statement.connection)
DummyDriver::DummyConnection.connections.size.should eq(1)
end
end
end
end
15 changes: 15 additions & 0 deletions spec/db_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,19 @@ describe DB do
DB.open "foobar://baz"
end
end

it "should parse boolean query string params" do
DB.fetch_bool(HTTP::Params.parse("foo=true"), "foo", false).should be_true
DB.fetch_bool(HTTP::Params.parse("foo=True"), "foo", false).should be_true

DB.fetch_bool(HTTP::Params.parse("foo=false"), "foo", true).should be_false
DB.fetch_bool(HTTP::Params.parse("foo=False"), "foo", true).should be_false

DB.fetch_bool(HTTP::Params.parse("bar=true"), "foo", false).should be_false
DB.fetch_bool(HTTP::Params.parse("bar=true"), "foo", true).should be_true

expect_raises(ArgumentError, %(invalid "other" value for option "foo")) do
DB.fetch_bool(HTTP::Params.parse("foo=other"), "foo", true)
end
end
end
18 changes: 13 additions & 5 deletions spec/dummy_driver.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ class DummyDriver < DB::Driver
@@connections.try &.clear
end

def build_statement(query)
DummyStatement.new(self, query)
def build_prepared_statement(query)
DummyStatement.new(self, query, true)
end

def build_unprepared_statement(query)
DummyStatement.new(self, query, false)
end

def last_insert_id : Int64
Expand All @@ -46,7 +50,7 @@ class DummyDriver < DB::Driver
class DummyStatement < DB::Statement
property params

def initialize(connection, @query : String)
def initialize(connection, @query : String, @prepared : Bool)
@params = Hash(Int32 | String, DB::Any).new
super(connection)
end
Expand Down Expand Up @@ -79,6 +83,10 @@ class DummyDriver < DB::Driver
raise "not implemented for #{value.class}"
end

def prepared?
@prepared
end

protected def do_close
super
end
Expand Down Expand Up @@ -204,8 +212,8 @@ def with_dummy(uri : String = "dummy://host?checkout_timeout=0.5")
end
end

def with_dummy_connection
with_dummy do |db|
def with_dummy_connection(options = "")
with_dummy("dummy://host?checkout_timeout=0.5&#{options}") do |db|
db.using_connection do |cnn|
yield cnn.as(DummyDriver::DummyConnection)
end
Expand Down
56 changes: 41 additions & 15 deletions spec/statement_spec.cr
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
require "./spec_helper"

describe DB::Statement do
it "should prepare statements" do
it "should build prepared statements" do
with_dummy_connection do |cnn|
cnn.prepare("the query").should be_a(DB::Statement)
prepared = cnn.prepared("the query")
prepared.should be_a(DB::Statement)
prepared.as(DummyDriver::DummyStatement).prepared?.should be_true
end
end

it "should build unprepared statements" do
with_dummy_connection("prepared_statements=false") do |cnn|
prepared = cnn.unprepared("the query")
prepared.should be_a(DB::Statement)
prepared.as(DummyDriver::DummyStatement).prepared?.should be_false
end
end

describe "prepared_statements flag" do
it "should build prepared statements if true" do
with_dummy_connection("prepared_statements=true") do |cnn|
stmt = cnn.query("the query").statement
stmt.as(DummyDriver::DummyStatement).prepared?.should be_true
end
end

it "should build unprepared statements if false" do
with_dummy_connection("prepared_statements=false") do |cnn|
stmt = cnn.query("the query").statement
stmt.as(DummyDriver::DummyStatement).prepared?.should be_false
end
end
end

it "should initialize positional params in query" do
with_dummy_connection do |cnn|
stmt = cnn.prepare("the query").as(DummyDriver::DummyStatement)
stmt = cnn.prepared("the query").as(DummyDriver::DummyStatement)
stmt.query "a", 1, nil
stmt.params[0].should eq("a")
stmt.params[1].should eq(1)
Expand All @@ -19,7 +45,7 @@ describe DB::Statement do

it "should initialize positional params in query with array" do
with_dummy_connection do |cnn|
stmt = cnn.prepare("the query").as(DummyDriver::DummyStatement)
stmt = cnn.prepared("the query").as(DummyDriver::DummyStatement)
stmt.query ["a", 1, nil]
stmt.params[0].should eq("a")
stmt.params[1].should eq(1)
Expand All @@ -29,7 +55,7 @@ describe DB::Statement do

it "should initialize positional params in exec" do
with_dummy_connection do |cnn|
stmt = cnn.prepare("the query").as(DummyDriver::DummyStatement)
stmt = cnn.prepared("the query").as(DummyDriver::DummyStatement)
stmt.exec "a", 1, nil
stmt.params[0].should eq("a")
stmt.params[1].should eq(1)
Expand All @@ -39,7 +65,7 @@ describe DB::Statement do

it "should initialize positional params in exec with array" do
with_dummy_connection do |cnn|
stmt = cnn.prepare("the query").as(DummyDriver::DummyStatement)
stmt = cnn.prepared("the query").as(DummyDriver::DummyStatement)
stmt.exec ["a", 1, nil]
stmt.params[0].should eq("a")
stmt.params[1].should eq(1)
Expand All @@ -49,7 +75,7 @@ describe DB::Statement do

it "should initialize positional params in scalar" do
with_dummy_connection do |cnn|
stmt = cnn.prepare("the query").as(DummyDriver::DummyStatement)
stmt = cnn.prepared("the query").as(DummyDriver::DummyStatement)
stmt.scalar "a", 1, nil
stmt.params[0].should eq("a")
stmt.params[1].should eq(1)
Expand All @@ -59,7 +85,7 @@ describe DB::Statement do

it "query with block should not close statement" do
with_dummy_connection do |cnn|
stmt = cnn.prepare "3,4 1,2"
stmt = cnn.prepared "3,4 1,2"
stmt.query
stmt.closed?.should be_false
end
Expand All @@ -68,15 +94,15 @@ describe DB::Statement do
it "closing connection should close statement" do
stmt = uninitialized DB::Statement
with_dummy_connection do |cnn|
stmt = cnn.prepare "3,4 1,2"
stmt = cnn.prepared "3,4 1,2"
stmt.query
end
stmt.closed?.should be_true
end

it "query with block should not close statement" do
with_dummy_connection do |cnn|
stmt = cnn.prepare "3,4 1,2"
stmt = cnn.prepared "3,4 1,2"
stmt.query do |rs|
end
stmt.closed?.should be_false
Expand All @@ -85,7 +111,7 @@ describe DB::Statement do

it "query should not close statement" do
with_dummy_connection do |cnn|
stmt = cnn.prepare "3,4 1,2"
stmt = cnn.prepared "3,4 1,2"
stmt.query do |rs|
end
stmt.closed?.should be_false
Expand All @@ -94,27 +120,27 @@ describe DB::Statement do

it "scalar should not close statement" do
with_dummy_connection do |cnn|
stmt = cnn.prepare "3,4 1,2"
stmt = cnn.prepared "3,4 1,2"
stmt.scalar
stmt.closed?.should be_false
end
end

it "exec should not close statement" do
with_dummy_connection do |cnn|
stmt = cnn.prepare "3,4 1,2"
stmt = cnn.prepared "3,4 1,2"
stmt.exec
stmt.closed?.should be_false
end
end

it "connection should cache statements by query" do
with_dummy_connection do |cnn|
rs = cnn.query "1, ?", 2
rs = cnn.prepared.query "1, ?", 2
stmt = rs.statement
rs.close

rs = cnn.query "1, ?", 4
rs = cnn.prepared.query "1, ?", 4
rs.statement.should be(stmt)
end
end
Expand Down
Loading