Skip to content

Commit

Permalink
Support :connect_opts_proc Database option for late binding options
Browse files Browse the repository at this point in the history
Some modern authentication schemes automatically rotate usernames
and/or passwords on a regular basis without user involvement or
control.  Attempt to support this type of authentication case
with this option, so you can do something like:

  Sequel.connect('postgres://user@host/database',
    connect_opts_proc: lambda do |h|
      h[:password] = SomeAuthLibrary.get_current_password(h[:user])
    end)

The way this is implemented, the :connect_opts_proc is always
called before a new connection is made, so directly before the
connection is made, it will get the current password for
the account.

Note that for the jdbc adapter, because it generally works directly
on JDBC URIs, the :connect_opts_proc should probably set the :uri
key in the hash appropriately.
  • Loading branch information
jeremyevans committed Jun 5, 2024
1 parent 52ccf07 commit 8a18971
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
=== master

* Support :connect_opts_proc Database option for late binding options (jeremyevans) (#2164)

=== 5.81.0 (2024-06-01)

* Fix ignored block warnings in a couple plugin apply methods on Ruby 3.4 (jeremyevans)
Expand Down
3 changes: 3 additions & 0 deletions doc/opening_databases.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ These options are shared by all adapters unless otherwise noted.
or string with extensions separated by columns. These extensions are loaded after
connections are made by the :preconnect option.
:cache_schema :: Whether schema should be cached for this database (true by default)
:connect_opts_proc :: Callable object for modifying options hash used when connecting, designed for
cases where the option values (e.g. password) are automatically rotated on
a regular basis without involvement from the application using Sequel.
:default_string_column_size :: The default size for string columns (255 by default)
:host :: The hostname of the database server to which to connect
:keep_reference :: Whether to keep a reference to the database in Sequel::DATABASES (true by default)
Expand Down
5 changes: 5 additions & 0 deletions lib/sequel/database/connecting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,11 @@ def server_opts(server)
else
@opts.dup
end

if pr = opts[:connect_opts_proc]
pr.call(opts)
end

opts.delete(:servers)
opts
end
Expand Down
3 changes: 3 additions & 0 deletions lib/sequel/database/misc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ def self.uri_to_options(uri)
# :cache_schema :: Whether schema should be cached for this Database instance
# :check_string_typecast_bytesize :: Whether to check the bytesize of strings before typecasting.
# :connect_sqls :: An array of sql strings to execute on each new connection, after :after_connect runs.
# :connect_opts_proc :: Callable object for modifying options hash used when connecting, designed for
# cases where the option values (e.g. password) are automatically rotated on
# a regular basis without involvement from the application using Sequel.
# :default_string_column_size :: The default size of string columns, 255 by default.
# :extensions :: Extensions to load into this Database instance. Can be a symbol, array of symbols,
# or string with extensions separated by columns. These extensions are loaded after
Expand Down
15 changes: 15 additions & 0 deletions spec/core/database_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@
Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).loggers.must_equal [4,3]
end

it "should support :connect_opts_proc option to modify options passed when connecting" do
c = Class.new(Sequel::Database) do
alias connect server_opts
end
opts = {:a => 1, :connect_opts_proc=>lambda{|h| h[:a] += 2; h[:b] = 4}}
c.new(opts).synchronize do |c|
c[:a].must_equal 3
c[:b].must_equal 4
end
c.new(opts.merge(:servers=>{:default=>{:a=>5}})).synchronize do |c|
c[:a].must_equal 7
c[:b].must_equal 4
end
end

it "should support :preconnect option to preconnect to database" do
@db.pool.size.must_equal 0
c = Class.new(Sequel::Database) do
Expand Down

0 comments on commit 8a18971

Please sign in to comment.