mirror of
https://gitea.invidious.io/iv-org/shard-crystal-db.git
synced 2024-08-15 00:53:32 +00:00
Introduce DB::ConnectionContext (#44)
* make Database a ConnectionContext. * introduce SingleConnectionContext for independant connections. * add `DB#connect` to create non pooled connections.
This commit is contained in:
parent
c63ea48748
commit
385cf70a8a
8 changed files with 115 additions and 23 deletions
|
@ -43,8 +43,8 @@ class FooDriver < DB::Driver
|
||||||
@@row
|
@@row
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_connection(db : DB::Database) : DB::Connection
|
def build_connection(context : DB::ConnectionContext) : DB::Connection
|
||||||
FooConnection.new(db)
|
FooConnection.new(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
class FooConnection < DB::Connection
|
class FooConnection < DB::Connection
|
||||||
|
@ -106,8 +106,8 @@ class BarDriver < DB::Driver
|
||||||
@@row
|
@@row
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_connection(db : DB::Database) : DB::Connection
|
def build_connection(context : DB::ConnectionContext) : DB::Connection
|
||||||
BarConnection.new(db)
|
BarConnection.new(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
class BarConnection < DB::Connection
|
class BarConnection < DB::Connection
|
||||||
|
|
|
@ -25,6 +25,25 @@ describe DB do
|
||||||
connections.first.closed?.should be_true
|
connections.first.closed?.should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should create a connection and close it" do
|
||||||
|
DummyDriver::DummyConnection.clear_connections
|
||||||
|
DB.connect "dummy://localhost" do |cnn|
|
||||||
|
cnn.should be_a(DummyDriver::DummyConnection)
|
||||||
|
end
|
||||||
|
connections.size.should eq(1)
|
||||||
|
connections.first.closed?.should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should create a connection and wait for explicit closing" do
|
||||||
|
DummyDriver::DummyConnection.clear_connections
|
||||||
|
cnn = DB.connect "dummy://localhost"
|
||||||
|
cnn.should be_a(DummyDriver::DummyConnection)
|
||||||
|
connections.size.should eq(1)
|
||||||
|
connections.first.closed?.should be_false
|
||||||
|
cnn.close
|
||||||
|
connections.first.closed?.should be_true
|
||||||
|
end
|
||||||
|
|
||||||
it "query should close result_set" do
|
it "query should close result_set" do
|
||||||
with_witness do |w|
|
with_witness do |w|
|
||||||
with_dummy do |db|
|
with_dummy do |db|
|
||||||
|
|
|
@ -2,13 +2,13 @@ require "spec"
|
||||||
require "../src/db"
|
require "../src/db"
|
||||||
|
|
||||||
class DummyDriver < DB::Driver
|
class DummyDriver < DB::Driver
|
||||||
def build_connection(db : DB::Database) : DB::Connection
|
def build_connection(context : DB::ConnectionContext) : DB::Connection
|
||||||
DummyConnection.new(db)
|
DummyConnection.new(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
class DummyConnection < DB::Connection
|
class DummyConnection < DB::Connection
|
||||||
def initialize(db)
|
def initialize(context)
|
||||||
super(db)
|
super(context)
|
||||||
@connected = true
|
@connected = true
|
||||||
@@connections ||= [] of DummyConnection
|
@@connections ||= [] of DummyConnection
|
||||||
@@connections.not_nil! << self
|
@@connections.not_nil! << self
|
||||||
|
|
33
src/db.cr
33
src/db.cr
|
@ -113,12 +113,42 @@ module DB
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Opens a connection using the specified *uri*.
|
||||||
|
# The scheme of the *uri* determines the driver to use.
|
||||||
|
# Returned connection must be closed by `Connection#close`.
|
||||||
|
# If a block is used the connection is yielded and closed automatically.
|
||||||
|
def self.connect(uri : URI | String)
|
||||||
|
build_connection(uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
# ditto
|
||||||
|
def self.connect(uri : URI | String, &block)
|
||||||
|
cnn = build_connection(uri)
|
||||||
|
begin
|
||||||
|
yield cnn
|
||||||
|
ensure
|
||||||
|
cnn.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def self.build_database(connection_string : String)
|
private def self.build_database(connection_string : String)
|
||||||
build_database(URI.parse(connection_string))
|
build_database(URI.parse(connection_string))
|
||||||
end
|
end
|
||||||
|
|
||||||
private def self.build_database(uri : URI)
|
private def self.build_database(uri : URI)
|
||||||
Database.new(driver_class(uri.scheme).new, uri)
|
Database.new(build_driver(uri), uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def self.build_connection(connection_string : String)
|
||||||
|
build_connection(URI.parse(connection_string))
|
||||||
|
end
|
||||||
|
|
||||||
|
private def self.build_connection(uri : URI)
|
||||||
|
build_driver(uri).build_connection(SingleConnectionContext.new(uri)).as(Connection)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def self.build_driver(uri : URI)
|
||||||
|
driver_class(uri.scheme).new
|
||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
|
@ -144,6 +174,7 @@ require "./db/disposable"
|
||||||
require "./db/driver"
|
require "./db/driver"
|
||||||
require "./db/statement"
|
require "./db/statement"
|
||||||
require "./db/begin_transaction"
|
require "./db/begin_transaction"
|
||||||
|
require "./db/connection_context"
|
||||||
require "./db/connection"
|
require "./db/connection"
|
||||||
require "./db/transaction"
|
require "./db/transaction"
|
||||||
require "./db/statement"
|
require "./db/statement"
|
||||||
|
|
|
@ -24,15 +24,15 @@ module DB
|
||||||
include BeginTransaction
|
include BeginTransaction
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
getter database
|
getter context
|
||||||
@statements_cache = StringKeyCache(Statement).new
|
@statements_cache = StringKeyCache(Statement).new
|
||||||
@transaction = false
|
@transaction = false
|
||||||
getter? prepared_statements : Bool
|
getter? prepared_statements : Bool
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
property auto_release : Bool = true
|
property auto_release : Bool = true
|
||||||
|
|
||||||
def initialize(@database : Database)
|
def initialize(@context : ConnectionContext)
|
||||||
@prepared_statements = @database.prepared_statements?
|
@prepared_statements = @context.prepared_statements?
|
||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
|
@ -59,7 +59,7 @@ module DB
|
||||||
protected def do_close
|
protected def do_close
|
||||||
@statements_cache.each_value &.close
|
@statements_cache.each_value &.close
|
||||||
@statements_cache.clear
|
@statements_cache.clear
|
||||||
@database.pool.delete self
|
@context.discard self
|
||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
|
@ -75,7 +75,7 @@ module DB
|
||||||
# managed by the database. Should be used
|
# managed by the database. Should be used
|
||||||
# only if the connection was obtained by `Database#checkout`.
|
# only if the connection was obtained by `Database#checkout`.
|
||||||
def release
|
def release
|
||||||
@database.return_to_pool(self)
|
@context.release(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
|
|
36
src/db/connection_context.cr
Normal file
36
src/db/connection_context.cr
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
module DB
|
||||||
|
module ConnectionContext
|
||||||
|
# Returns the uri with the connection settings to the database
|
||||||
|
abstract def uri : URI
|
||||||
|
|
||||||
|
# Return whether the statements should be prepared by default
|
||||||
|
abstract def prepared_statements? : Bool
|
||||||
|
|
||||||
|
# Indicates that the *connection* was permanently closed
|
||||||
|
# and should not be used in the future.
|
||||||
|
abstract def discard(connection : Connection)
|
||||||
|
|
||||||
|
# Indicates that the *connection* is no longer needed
|
||||||
|
# and can be reused in the future.
|
||||||
|
abstract def release(connection : Connection)
|
||||||
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
|
class SingleConnectionContext
|
||||||
|
include ConnectionContext
|
||||||
|
|
||||||
|
getter uri : URI
|
||||||
|
getter? prepared_statements : Bool
|
||||||
|
|
||||||
|
def initialize(@uri : URI)
|
||||||
|
params = HTTP::Params.parse(uri.query || "")
|
||||||
|
@prepared_statements = DB.fetch_bool(params, "prepared_statements", true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def discard(connection : Connection)
|
||||||
|
end
|
||||||
|
|
||||||
|
def release(connection : Connection)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -23,6 +23,7 @@ module DB
|
||||||
# Refer to `QueryMethods` and `SessionMethods` for documentation about querying the database.
|
# Refer to `QueryMethods` and `SessionMethods` for documentation about querying the database.
|
||||||
class Database
|
class Database
|
||||||
include SessionMethods(Database, PoolStatement)
|
include SessionMethods(Database, PoolStatement)
|
||||||
|
include ConnectionContext
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
getter driver
|
getter driver
|
||||||
|
@ -68,6 +69,16 @@ module DB
|
||||||
@pool.close
|
@pool.close
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
|
def discard(connection : Connection)
|
||||||
|
@pool.delete connection
|
||||||
|
end
|
||||||
|
|
||||||
|
# :nodoc:
|
||||||
|
def release(connection : Connection)
|
||||||
|
@pool.release connection
|
||||||
|
end
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
def fetch_or_build_prepared_statement(query)
|
def fetch_or_build_prepared_statement(query)
|
||||||
@statements_cache.fetch(query) { build_prepared_statement(query) }
|
@statements_cache.fetch(query) { build_prepared_statement(query) }
|
||||||
|
@ -88,11 +99,6 @@ module DB
|
||||||
@pool.checkout_some candidates
|
@pool.checkout_some candidates
|
||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc:
|
|
||||||
def return_to_pool(connection)
|
|
||||||
@pool.release connection
|
|
||||||
end
|
|
||||||
|
|
||||||
# yields a connection from the pool
|
# yields a connection from the pool
|
||||||
# the connection is returned to the pool
|
# the connection is returned to the pool
|
||||||
# when the block ends
|
# when the block ends
|
||||||
|
|
|
@ -6,9 +6,9 @@ module DB
|
||||||
# ```
|
# ```
|
||||||
# require "db"
|
# require "db"
|
||||||
#
|
#
|
||||||
# class FakeDriver < Driver
|
# class FakeDriver < DB::Driver
|
||||||
# def build_connection(db)
|
# def build_connection(context : DB::ConnectionContext)
|
||||||
# FakeConnection.new db
|
# FakeConnection.new context
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
|
@ -26,7 +26,7 @@ module DB
|
||||||
# Refer to `Connection`, `Statement` and `ResultSet` for further
|
# Refer to `Connection`, `Statement` and `ResultSet` for further
|
||||||
# driver implementation instructions.
|
# driver implementation instructions.
|
||||||
abstract class Driver
|
abstract class Driver
|
||||||
abstract def build_connection(db : Database) : Connection
|
abstract def build_connection(context : ConnectionContext) : Connection
|
||||||
|
|
||||||
def connection_pool_options(params : HTTP::Params)
|
def connection_pool_options(params : HTTP::Params)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue