diff --git a/spec/avram/queryable_spec.cr b/spec/avram/queryable_spec.cr index 57c6d664b..012cfb4b7 100644 --- a/spec/avram/queryable_spec.cr +++ b/spec/avram/queryable_spec.cr @@ -62,6 +62,12 @@ describe Avram::Queryable do query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE users.age >= $1 AND users.name = $2" end + it "releases connection if no open transaction", tags: Avram::SpecHelper::TRUNCATE do + UserQuery.new.first? + + TestDatabase.connections.should be_empty + end + describe "#distinct" do it "selects distinct" do query = UserQuery.new.distinct.query diff --git a/src/avram/database.cr b/src/avram/database.cr index 85d564b2a..c408a4e26 100644 --- a/src/avram/database.cr +++ b/src/avram/database.cr @@ -153,7 +153,9 @@ abstract class Avram::Database # :nodoc: def run - yield current_connection || db + with_connection do |conn| + yield conn + end end # :nodoc: @@ -173,16 +175,31 @@ abstract class Avram::Database end end - private def current_connection : DB::Connection - connections[object_id] ||= db.checkout + # singular place to retrieve a DB::Connection + # must be passed a block and we + # try to release the connection back to the pool + # once the block is finished + private def with_connection + key = object_id + connections[key] ||= db.checkout + connection = connections[key] + + begin + yield connection + ensure + if !connection._avram_in_transaction? + connection.release + connections.delete(key) + end + end end private def object_id : UInt64 self.class.lock_id || Fiber.current.object_id end - private def current_transaction : DB::Transaction? - current_connection._avram_stack.last? + private def current_transaction(connection : DB::Connection) : DB::Transaction? + connection._avram_stack.last? end protected def truncate @@ -199,12 +216,14 @@ abstract class Avram::Database # :nodoc: def transaction : Bool - if current_transaction.try(&._avram_joinable?) - yield - true - else - wrap_in_transaction do + with_connection do |conn| + if current_transaction(conn).try(&._avram_joinable?) yield + true + else + wrap_in_transaction(conn) do + yield + end end end end @@ -213,18 +232,13 @@ abstract class Avram::Database self.class.connections end - private def wrap_in_transaction - (current_transaction || current_connection).transaction do + private def wrap_in_transaction(conn) + (current_transaction(conn) || conn).transaction do yield end true rescue e : Avram::Rollback false - ensure - if !current_connection._avram_in_transaction? - current_connection.release - connections.delete(object_id) - end end class DatabaseCleaner