diff --git a/spec/std/db/dummy_driver.cr b/spec/std/db/dummy_driver.cr index 0b62db0..12db753 100644 --- a/spec/std/db/dummy_driver.cr +++ b/spec/std/db/dummy_driver.cr @@ -29,7 +29,7 @@ class DummyDriver < DB::Driver 0 end - def perform_close + protected def do_close end end @@ -57,6 +57,9 @@ class DummyDriver < DB::Driver @params[index] = arg end end + + protected def do_close + end end class DummyResultSet < DB::ResultSet @@ -69,6 +72,9 @@ class DummyDriver < DB::Driver @@last_result_set = self end + protected def do_close + end + def self.last_result_set @@last_result_set.not_nil! end diff --git a/src/db/connection.cr b/src/db/connection.cr index 50c62f6..38e1707 100644 --- a/src/db/connection.cr +++ b/src/db/connection.cr @@ -15,30 +15,11 @@ module DB # Also override `#last_insert_id` to allow safe access to the last inserted id through this connection. # abstract class Connection - @closed = false - - # Closes this connection. - def close - return if @closed - @closed = true - perform_close - end - - # Returns `true` if this connection is closed. See `#close`. - def closed? - @closed - end - - # :nodoc: - def finalize - close unless closed? - end + include Disposable # :nodoc: abstract def prepare(query) : Statement include QueryMethods - - protected abstract def perform_close # TODO do_close end end diff --git a/src/db/db.cr b/src/db/db.cr index 0dd4842..a61c3c9 100644 --- a/src/db/db.cr +++ b/src/db/db.cr @@ -99,6 +99,7 @@ module DB end require "./query_methods" +require "./disposable" require "./database" require "./driver" require "./connection" diff --git a/src/db/disposable.cr b/src/db/disposable.cr new file mode 100644 index 0000000..301df9d --- /dev/null +++ b/src/db/disposable.cr @@ -0,0 +1,28 @@ +module DB + # Generic module to encapsulate disposable db resources. + module Disposable + macro included + @closed = false + end + + # Closes this object. + def close + return if @closed + @closed = true + do_close + end + + # Returns `true` if this object is closed. See `#close`. + def closed? + @closed + end + + # :nodoc: + def finalize + close + end + + # Implementors overrides this method to perform resource cleanup + protected abstract def do_close + end +end diff --git a/src/db/result_set.cr b/src/db/result_set.cr index 3015d15..027efa5 100644 --- a/src/db/result_set.cr +++ b/src/db/result_set.cr @@ -13,6 +13,8 @@ module DB # 4. Override `#column_count`, `#column_name`. # 5. Override `#column_type`. It must return a type in `DB::TYPES`. abstract class ResultSet + include Disposable + getter statement def initialize(@statement : Statement) @@ -27,26 +29,6 @@ module DB end end - # Closes this result set. - def close - return if @closed - @closed = true - do_close - end - - # Returns `true` if this result set is closed. See `#close`. - def closed? - @closed - end - - # :nodoc: - def finalize - close - end - - protected def do_close - end - # Move the next row in the result. # Return `false` if no more rows are available. # See `#each` diff --git a/src/db/statement.cr b/src/db/statement.cr index 5af9428..ed39aba 100644 --- a/src/db/statement.cr +++ b/src/db/statement.cr @@ -10,13 +10,13 @@ module DB # 4. `#perform_exec` executes a query that is expected to return an `ExecResult` # 6. `#do_close` is called to release the statement resources. abstract class Statement + include Disposable + getter connection def initialize(@connection) - @closed = false end - # See `QueryMethods#exec` def exec perform_exec(Slice(Any).new(0)) # no overload matches ... with types Slice(NoReturn) @@ -82,27 +82,7 @@ module DB perform_query(args.to_a.to_unsafe.to_slice(args.size)) end - # Closes this statement. - def close - return if @closed - @closed = true - do_close - end - - # Returns `true` if this statement is closed. See `#close`. - def closed? - @closed - end - - # :nodoc: - def finalize - close - end - protected abstract def perform_query(args : Slice(Any)) : ResultSet protected abstract def perform_exec(args : Slice(Any)) : ExecResult - - protected def do_close - end end end