hanami 2.2.0.beta2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d6bd309aaaf86dce283f25dbdf786db6da76567ae8b00aed92c34de637f8909
4
- data.tar.gz: 3b6430d47afb052bdc4df9ce200ceb3b2888b733b040bdb4de056052a8e99db2
3
+ metadata.gz: 7ebc4cbb51db37137a558abeeb3c4aa509d2a6d4db521458b465a427e503b098
4
+ data.tar.gz: fdd74d2e280be11ba0db6852a0dcfcd15df7629a1edb6e6b7067f623103d9fdd
5
5
  SHA512:
6
- metadata.gz: a73cfea60952ba798fe2d04b2cf430996f8b81960959054251e4277b9f0a53aadfdad23850d389fcedcdb3f77a0855acd2e128e5d8aa3cc8a82df485ae11d592
7
- data.tar.gz: 05a033e21dd6b9499b125583de931a39f128828ef5f8d730c7ef1522db765ffef35eb1938013b8f58d1199d68aa8564d5183a726bb733e4d1c5b1aaae9f79f7f
6
+ metadata.gz: 5c7fbba4c66f89f8426a675c88005b1c67a544f7051aec5835108a075631b253fde376b8a6b993a78257fb329e398dad45349f8380716ff0ca1d812b79624619
7
+ data.tar.gz: c5e66a40feaee584b0d6cc9d22aa31b01abcc4d8ec06a3fe09a9aca294f2cdf5d41c3bfa92a6da291a5c9015fac96f4986ac9535f8b85b3681b81708dd69dcdf
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  The web, with simplicity.
4
4
 
5
+ ## v2.2.0 - 2024-11-05
6
+
7
+ ### Changed
8
+
9
+ - [Tim Riley] Depend on dry-system v1.1, the stable release featuring the changes supporting the provider improvements introduced in beta1 and beta2 (#1467)
10
+ - [Tim Riley] Added specific "json" gem dependency to gemspec in order to suppress bundled gem deprecation warnings appearing in Ruby 3.3.5 (#1469)
11
+
12
+ ## v2.2.0.rc1 - 2024-10-29
13
+
14
+ ### Added
15
+
16
+ - [Adam Lassek] Add `#connection_options` to db gateways. These are a hash of options that will be passed to the lower-level driver when the gateway connects. For SQL databases, this means [Sequel's connection options](https://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html) (#1450)
17
+ - [Adam Lassek] Automatically configure `Dry::Operation` subclasses within Hanami apps for `transaction` support using the app's ROM container. (#1456)
18
+
19
+ ### Changed
20
+
21
+ - [Tim Riley] Apply config from matching gateways in parent slices (#1459)
22
+ - [Tim Riley] Remove `config.any_adapter` from DB provider (#1459)
23
+
5
24
  ## v2.2.0.beta2 - 2024-09-26
6
25
 
7
26
  ### Added
data/hanami.gemspec CHANGED
@@ -36,10 +36,11 @@ Gem::Specification.new do |spec|
36
36
  spec.add_dependency "dry-core", "~> 1.0", "< 2"
37
37
  spec.add_dependency "dry-inflector", "~> 1.0", ">= 1.1.0", "< 2"
38
38
  spec.add_dependency "dry-monitor", "~> 1.0", ">= 1.0.1", "< 2"
39
- spec.add_dependency "dry-system", "= 1.1.0.beta2"
39
+ spec.add_dependency "dry-system", "~> 1.1"
40
40
  spec.add_dependency "dry-logger", "~> 1.0", "< 2"
41
- spec.add_dependency "hanami-cli", "= 2.2.0.beta2"
42
- spec.add_dependency "hanami-utils", "~> 2.2.beta"
41
+ spec.add_dependency "hanami-cli", "~> 2.2"
42
+ spec.add_dependency "hanami-utils", "~> 2.2"
43
+ spec.add_dependency "json", ">= 2.7.2"
43
44
  spec.add_dependency "zeitwerk", "~> 2.6"
44
45
 
45
46
  spec.add_development_dependency "rspec", "~> 3.8"
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/operation"
4
+ require "dry/operation/extensions/rom"
5
+
6
+ module Hanami
7
+ module Extensions
8
+ # Integrated behavior for `Dry::Operation` classes within Hanami apps.
9
+ #
10
+ # @see https://github.com/dry-rb/dry-operation
11
+ #
12
+ # @api public
13
+ # @since 2.2.0
14
+ module Operation
15
+ # @api private
16
+ # @since 2.2.0
17
+ def self.included(operation_class)
18
+ super
19
+
20
+ operation_class.extend(Hanami::SliceConfigurable)
21
+ operation_class.extend(ClassMethods)
22
+ end
23
+
24
+ # @api private
25
+ # @since 2.2.0
26
+ module ClassMethods
27
+ # @api private
28
+ # @since 2.2.0
29
+ def configure_for_slice(slice)
30
+ include slice.namespace::Deps["db.rom"]
31
+ end
32
+
33
+ # @api private
34
+ # @since 2.2.0
35
+ def inherited(subclass)
36
+ super
37
+
38
+ return unless subclass.superclass == self
39
+ return unless Hanami.bundled?("hanami-db")
40
+
41
+ subclass.include Dry::Operation::Extensions::ROM
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ Dry::Operation.include(Hanami::Extensions::Operation)
@@ -19,3 +19,7 @@ end
19
19
  if Hanami.bundled?("hanami-router")
20
20
  require_relative "extensions/router/errors"
21
21
  end
22
+
23
+ if Hanami.bundled?("dry-operation")
24
+ require_relative "extensions/operation"
25
+ end
@@ -30,9 +30,7 @@ module Hanami
30
30
  # @api private
31
31
  # @since 2.2.0
32
32
  def initialize
33
- @adapters = Hash.new do |hsh, key|
34
- hsh[key] = self.class.new_adapter(key)
35
- end
33
+ @adapters = {}
36
34
  end
37
35
 
38
36
  # @api private
@@ -44,6 +42,24 @@ module Hanami
44
42
  @adapters[key] = val.dup
45
43
  end
46
44
  end
45
+
46
+ # @api private
47
+ # @since 2.2.0
48
+ def adapter(key)
49
+ adapters[key] ||= new(key)
50
+ end
51
+
52
+ # @api private
53
+ # @since 2.2.0
54
+ def find(key)
55
+ adapters.fetch(key) { new(key) }
56
+ end
57
+
58
+ # @api private
59
+ # @since 2.2.0
60
+ def new(key)
61
+ self.class.new_adapter(key)
62
+ end
47
63
  end
48
64
  end
49
65
  end
@@ -20,24 +20,8 @@ module Hanami
20
20
 
21
21
  # @api public
22
22
  # @since 2.2.0
23
- def adapter_name
24
- self[:adapter]
25
- end
26
-
27
- # @api public
28
- # @since 2.2.0
29
- def adapter(name = Undefined)
30
- return adapter_name if name.eql?(Undefined)
31
-
32
- adapter = (adapters[name] ||= Adapter.new)
33
- yield adapter if block_given?
34
- adapter
35
- end
36
-
37
- # @api public
38
- # @since 2.2.0
39
- def any_adapter
40
- adapter = (adapters[nil] ||= Adapter.new)
23
+ def adapter(name)
24
+ adapter = adapters.adapter(name)
41
25
  yield adapter if block_given?
42
26
  adapter
43
27
  end
@@ -46,12 +30,10 @@ module Hanami
46
30
  def each_plugin
47
31
  return to_enum(__method__) unless block_given?
48
32
 
49
- universal_plugins = adapters[nil].plugins
50
-
51
33
  gateways.values.group_by(&:adapter_name).each do |adapter_name, adapter_gateways|
52
- per_adapter_plugins = adapter_gateways.map { _1.adapter.plugins }.flatten(1)
34
+ per_adapter_plugins = adapter_gateways.map { _1.adapter.plugins }.flatten(1).uniq
53
35
 
54
- (universal_plugins + per_adapter_plugins).uniq.each do |plugin_spec, config_block|
36
+ per_adapter_plugins.each do |plugin_spec, config_block|
55
37
  yield adapter_name, plugin_spec, config_block
56
38
  end
57
39
  end
@@ -15,6 +15,7 @@ module Hanami
15
15
  setting :database_url
16
16
  setting :adapter_name, default: :sql
17
17
  setting :adapter, mutable: true
18
+ setting :connection_options, default: {}
18
19
 
19
20
  # @api public
20
21
  # @since 2.2.0
@@ -34,13 +35,29 @@ module Hanami
34
35
  end
35
36
  end
36
37
 
38
+ # @api public
39
+ # @since 2.2.0
40
+ def connection_options(**options)
41
+ if options.any?
42
+ config.connection_options.merge!(options)
43
+ end
44
+
45
+ config.connection_options
46
+ end
47
+
48
+ # @api public
49
+ # @since 2.2.0
50
+ def options
51
+ {**connection_options, **config.adapter.gateway_options}
52
+ end
53
+
37
54
  # @api private
38
55
  def configure_adapter(default_adapters)
39
- default_adapter = default_adapters[config.adapter_name]
56
+ default_adapter = default_adapters.find(config.adapter_name)
40
57
  config.adapter ||= default_adapter.dup
41
58
 
42
59
  config.adapter.configure_from_adapter(default_adapter)
43
- config.adapter.configure_from_adapter(default_adapters[nil])
60
+
44
61
  config.adapter.configure_for_database(config.database_url)
45
62
 
46
63
  self
@@ -48,7 +65,7 @@ module Hanami
48
65
 
49
66
  # @api private
50
67
  def cache_keys
51
- [config.database_url, config.adapter.gateway_cache_keys]
68
+ [config.database_url, config.connection_options, config.adapter.gateway_cache_keys]
52
69
  end
53
70
 
54
71
  private
@@ -13,7 +13,7 @@ module Hanami
13
13
  # @api public
14
14
  # @since 2.2.0
15
15
  def extension(*extensions)
16
- self.extensions.concat(extensions)
16
+ self.extensions.concat(extensions).uniq!
17
17
  end
18
18
 
19
19
  # @api public
@@ -73,7 +73,7 @@ module Hanami
73
73
  )
74
74
 
75
75
  # Extensions for specific databases
76
- if database_url.to_s.start_with?(%r{postgres(ql)*://}) # FIXME: what is the canonical postgres URL?
76
+ if database_url.to_s.start_with?(%r{postgres(ql)*://})
77
77
  extension(
78
78
  :pg_array,
79
79
  :pg_enum,
@@ -85,7 +85,7 @@ module Hanami
85
85
 
86
86
  # @api private
87
87
  def gateway_options
88
- {extensions: config.extensions}
88
+ {extensions: extensions}
89
89
  end
90
90
 
91
91
  # @api public
@@ -113,7 +113,7 @@ module Hanami
113
113
  # Preserve settings already configured locally
114
114
  next if config.configured?(key)
115
115
 
116
- # Do not copy gateways, these are always configured per slice
116
+ # Skip gateway config, we handle this in #configure_gateways
117
117
  next if key == :gateways
118
118
 
119
119
  # Skip adapter config, we handle this below
@@ -123,12 +123,12 @@ module Hanami
123
123
  end
124
124
 
125
125
  parent_db_provider.source.config.adapters.each do |adapter_name, parent_adapter|
126
- adapter = config.adapters[adapter_name]
126
+ adapter = config.adapter(adapter_name)
127
127
 
128
128
  adapter.class.settings.keys.each do |key|
129
129
  next if adapter.config.configured?(key)
130
130
 
131
- adapter.config[key] = parent_adapter.config[key]
131
+ adapter.config[key] = parent_adapter.config[key].dup
132
132
  end
133
133
  end
134
134
  end
@@ -196,18 +196,40 @@ module Hanami
196
196
 
197
197
  ensure_database_gem(gw_config.database_url)
198
198
 
199
+ apply_parent_gateway_config(key, gw_config) if apply_parent_config?
200
+
199
201
  gw_config.configure_adapter(config.adapters)
200
202
  end
201
203
  end
202
204
 
205
+ def apply_parent_gateway_config(key, gw_config)
206
+ parent_gw_config = parent_db_provider.source.config.gateways[key]
207
+
208
+ # Only copy config from a parent gateway with the same name _and_ database URL
209
+ return unless parent_gw_config&.database_url == gw_config.database_url
210
+
211
+ # Copy config from matching parent gateway
212
+ (gw_config.class.settings.keys - [:adapter]).each do |key|
213
+ next if gw_config.config.configured?(key)
214
+
215
+ gw_config.config[key] = parent_gw_config.config[key].dup
216
+ end
217
+
218
+ # If there is an adapter configured within this slice, prefer that, and do not copy the
219
+ # adapter from the parent gateway
220
+ unless config.adapters[gw_config.adapter_name] || gw_config.configured?(:adapter)
221
+ gw_config.adapter = parent_gw_config.adapter.dup
222
+ end
223
+ end
224
+
203
225
  def prepare_gateways
204
226
  config.gateways.transform_values { |gw_config|
205
227
  # Avoid spurious connections by reusing identically configured gateways across slices
206
- gateway = fetch_or_store(gw_config.cache_keys) {
228
+ fetch_or_store(gw_config.cache_keys) {
207
229
  ROM::Gateway.setup(
208
230
  gw_config.adapter_name,
209
231
  gw_config.database_url,
210
- **gw_config.adapter.gateway_options
232
+ **gw_config.options
211
233
  )
212
234
  }
213
235
  }
@@ -7,7 +7,7 @@ module Hanami
7
7
  # @api private
8
8
  module Version
9
9
  # @api public
10
- VERSION = "2.2.0.beta2"
10
+ VERSION = "2.2.0"
11
11
 
12
12
  # @since 0.9.0
13
13
  # @api private
@@ -17,6 +17,7 @@ RSpec.describe "DB / Slices", :app_integration do
17
17
 
18
18
  module TestApp
19
19
  class App < Hanami::App
20
+ config.logger.stream = File::NULL
20
21
  end
21
22
  end
22
23
  RUBY
@@ -32,6 +33,67 @@ RSpec.describe "DB / Slices", :app_integration do
32
33
  end
33
34
  end
34
35
 
36
+ specify "slices using a parent gateway with connection options share a gateway/connection" do
37
+ with_tmp_directory(@dir = Dir.mktmpdir) do
38
+ write "config/app.rb", <<~RUBY
39
+ require "hanami"
40
+
41
+ module TestApp
42
+ class App < Hanami::App
43
+ config.logger.stream = File::NULL
44
+ end
45
+ end
46
+ RUBY
47
+
48
+ write "config/providers/db.rb", <<~RUBY
49
+ Hanami.app.configure_provider :db do
50
+ config.gateway :default do |gw|
51
+ gw.connection_options timeout: 10_000
52
+ end
53
+
54
+ config.gateway :extra do |gw|
55
+ gw.connection_options timeout: 20_000
56
+ end
57
+ end
58
+ RUBY
59
+
60
+ write "slices/main/config/providers/db.rb", <<~RUBY
61
+ Main::Slice.configure_provider :db do
62
+ config.gateway :bonus do |gw|
63
+ gw.connection_options timeout: 5_000
64
+ end
65
+ end
66
+ RUBY
67
+
68
+ write "db/.keep", ""
69
+ write "slices/admin/relations/.keep", ""
70
+ write "slices/main/relations/.keep", ""
71
+
72
+ ENV["DATABASE_URL"] = "sqlite://" + Pathname(@dir).realpath.join("app.sqlite").to_s
73
+ ENV["DATABASE_URL__EXTRA"] = "sqlite://" + Pathname(@dir).realpath.join("extra.sqlite").to_s
74
+ ENV["DATABASE_URL__BONUS"] = "sqlite://" + Pathname(@dir).realpath.join("bonus.sqlite").to_s
75
+
76
+ # "extra" gateway in admin slice, same URL as app
77
+ ENV["ADMIN__DATABASE_URL__EXTRA"] = ENV["DATABASE_URL__EXTRA"]
78
+ # "extra" gatway in main slice, different URL
79
+ ENV["MAIN__DATABASE_URL__EXTRA"] = "sqlite://" + Pathname(@dir).realpath.join("extra-main.sqlite").to_s
80
+ # "bonus" gateway in admin slice, same URL as app
81
+ ENV["ADMIN__DATABASE_URL__BONUS"] = ENV["DATABASE_URL__BONUS"]
82
+ # "bonus" gateway in main slice, same URL as app; different connection options in provider
83
+ ENV["MAIN__DATABASE_URL__BONUS"] = ENV["DATABASE_URL__BONUS"]
84
+
85
+ require "hanami/prepare"
86
+
87
+ expect(Admin::Slice["db.gateway"]).to be Hanami.app["db.gateway"]
88
+
89
+ expect(Admin::Slice["db.gateways.extra"]).to be Hanami.app["db.gateways.extra"]
90
+ expect(Main::Slice["db.gateways.extra"]).not_to be Hanami.app["db.gateways.extra"]
91
+
92
+ expect(Admin::Slice["db.gateways.bonus"]).to be Hanami.app["db.gateways.bonus"]
93
+ expect(Main::Slice["db.gateways.bonus"]).not_to be Hanami.app["db.gateways.bonus"]
94
+ end
95
+ end
96
+
35
97
  specify "slices using the same database_url but different extensions have distinct gateways/connections" do
36
98
  with_tmp_directory(@dir = Dir.mktmpdir) do
37
99
  write "config/app.rb", <<~RUBY
@@ -39,6 +101,7 @@ RSpec.describe "DB / Slices", :app_integration do
39
101
 
40
102
  module TestApp
41
103
  class App < Hanami::App
104
+ config.logger.stream = File::NULL
42
105
  end
43
106
  end
44
107
  RUBY
@@ -80,6 +143,7 @@ RSpec.describe "DB / Slices", :app_integration do
80
143
 
81
144
  module TestApp
82
145
  class App < Hanami::App
146
+ config.logger.stream = File::NULL
83
147
  end
84
148
  end
85
149
  RUBY
@@ -213,6 +277,7 @@ RSpec.describe "DB / Slices", :app_integration do
213
277
 
214
278
  module TestApp
215
279
  class App < Hanami::App
280
+ config.logger.stream = File::NULL
216
281
  end
217
282
  end
218
283
  RUBY
@@ -253,6 +318,7 @@ RSpec.describe "DB / Slices", :app_integration do
253
318
 
254
319
  module TestApp
255
320
  class App < Hanami::App
321
+ config.logger.stream = File::NULL
256
322
  end
257
323
  end
258
324
  RUBY
@@ -81,7 +81,48 @@ RSpec.describe "DB / Gateways", :app_integration do
81
81
  end
82
82
  end
83
83
 
84
+ it "configures connection options on their respective gateways" do
85
+ with_tmp_directory(@dir = Dir.mktmpdir) do
86
+ write "config/app.rb", <<~RUBY
87
+ require "hanami"
88
+
89
+ module TestApp
90
+ class App < Hanami::App
91
+ end
92
+ end
93
+ RUBY
94
+
95
+ write "db/.keep", ""
96
+
97
+ write "config/providers/db.rb", <<~RUBY
98
+ Hanami.app.configure_provider :db do
99
+ config.gateway :default do |gw|
100
+ gw.connection_options timeout: 10_000
84
101
 
102
+ gw.adapter :sql do |a|
103
+ a.skip_defaults :extensions
104
+ a.extension :error_sql
105
+ end
106
+ end
107
+
108
+ config.gateway :extra do |gw|
109
+ gw.connection_options readonly: true
110
+ end
111
+ end
112
+ RUBY
113
+
114
+ ENV["DATABASE_URL"] = "sqlite::memory"
115
+ ENV["DATABASE_URL__EXTRA"] = "sqlite::memory"
116
+
117
+ require "hanami/prepare"
118
+
119
+ default = Hanami.app["db.gateways.default"]
120
+ extra = Hanami.app["db.gateways.extra"]
121
+
122
+ expect(default.options).to eq({timeout: 10_000, extensions: [:error_sql]})
123
+ expect(extra.options).to eq({readonly: true, extensions: %i[caller_logging error_sql sql_comments]})
124
+ end
125
+ end
85
126
 
86
127
  it "exposes all database URLs as #database_urls on the provider source (for CLI commands)" do
87
128
  with_tmp_directory(@dir = Dir.mktmpdir) do
@@ -155,7 +196,7 @@ RSpec.describe "DB / Gateways", :app_integration do
155
196
  end
156
197
  end
157
198
 
158
- it "combines ROM plugins from the default adapter and all gateways" do
199
+ it "combines ROM plugins from both default adapter and gateway-configured adapters" do
159
200
  with_tmp_directory(@dir = Dir.mktmpdir) do
160
201
  write "config/app.rb", <<~RUBY
161
202
  require "hanami"
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/operation"
4
+
5
+ RSpec.describe "Operation / Extensions", :app_integration do
6
+ before do
7
+ @env = ENV.to_h
8
+ allow(Hanami::Env).to receive(:loaded?).and_return(false)
9
+ end
10
+
11
+ after { ENV.replace(@env) }
12
+
13
+ specify "Transaction interface is made available automatically" do
14
+ with_tmp_directory(Dir.mktmpdir) do
15
+ write "config/app.rb", <<~RUBY
16
+ require "hanami"
17
+
18
+ module TestApp
19
+ class App < Hanami::App
20
+ end
21
+ end
22
+ RUBY
23
+
24
+ write "app/operation.rb", <<~RUBY
25
+ module TestApp
26
+ class Operation < Dry::Operation
27
+ end
28
+ end
29
+ RUBY
30
+
31
+ write "slices/main/operation.rb", <<~RUBY
32
+ module Main
33
+ class Operation < Dry::Operation
34
+ end
35
+ end
36
+ RUBY
37
+
38
+ write "db/.keep", ""
39
+ write "app/relations/.keep", ""
40
+
41
+ write "slices/main/db/.keep", ""
42
+ write "slices/main/relations/.keep", ""
43
+
44
+ ENV["DATABASE_URL"] = "sqlite::memory"
45
+ ENV["MAIN__DATABASE_URL"] = "sqlite::memory"
46
+
47
+ require "hanami/prepare"
48
+
49
+ app = TestApp::Operation.new
50
+ main = Main::Operation.new
51
+
52
+ expect(app).to respond_to(:transaction)
53
+
54
+ expect(app.rom).to be TestApp::App["db.rom"]
55
+ expect(app.rom).not_to be Main::Slice["db.rom"]
56
+ expect(main.rom).to be Main::Slice["db.rom"]
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/system"
4
+ require "hanami/providers/db"
5
+
6
+ RSpec.describe "Hanami::Providers::DB / Config / Gateway config", :app_integration do
7
+ subject(:config) { provider.source.config }
8
+
9
+ let(:provider) {
10
+ Hanami.app.prepare
11
+ Hanami.app.configure_provider(:db)
12
+ Hanami.app.container.providers[:db]
13
+ }
14
+
15
+ before do
16
+ module TestApp
17
+ class App < Hanami::App
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "sql adapter" do
23
+ before do
24
+ config.adapter(:sql).configure_for_database("sqlite::memory")
25
+ end
26
+
27
+ describe "connection_options" do
28
+ let(:default) { config.gateway(:default) }
29
+
30
+ it "merges kwargs into connection_options configuration" do
31
+ expect { default.connection_options(timeout: 10_000) }
32
+ .to change { default.connection_options }.from({}).to({timeout: 10_000})
33
+ end
34
+
35
+ it "sets options per-gateway" do
36
+ other = config.gateway(:other)
37
+ expect { default.connection_options(timeout: 10_000) }
38
+ .to_not change { other.connection_options }
39
+ end
40
+
41
+ it "is reflected in Gateway#cache_keys" do
42
+ default.adapter(:sql) {}
43
+ expect { default.connection_options(timeout: 10_000) }
44
+ .to change { default.cache_keys }
45
+ end
46
+ end
47
+
48
+ describe "options" do
49
+ it "combines connection_options with adapter.gateway_options" do
50
+ config.gateway :default do |gw|
51
+ gw.connection_options foo: "bar"
52
+
53
+ gw.adapter :sql do |a|
54
+ a.skip_defaults
55
+ a.extension :baz, :quux
56
+ end
57
+ end
58
+
59
+ expect(config.gateway(:default).options)
60
+ .to include(foo: "bar", extensions: [:baz, :quux])
61
+ end
62
+
63
+ it "ignores conflicting keys from connection_options" do
64
+ config.gateway :default do |gw|
65
+ gw.connection_options extensions: "foo"
66
+ gw.adapter(:sql) { _1.skip_defaults }
67
+ end
68
+
69
+ expect(config.gateway(:default).options).to eq({extensions: []})
70
+ end
71
+ end
72
+ end
73
+ end
@@ -32,19 +32,6 @@ RSpec.describe "Hanami::Providers::DB.config", :app_integration do
32
32
  end
33
33
  end
34
34
 
35
- describe "#any_adapter" do
36
- it "adds an adapter keyed without a name" do
37
- expect { config.any_adapter }
38
- .to change { config.adapters.to_h }
39
- .to hash_including(nil)
40
- end
41
-
42
- it "yields the adapter for configuration" do
43
- expect { |b| config.any_adapter(&b) }
44
- .to yield_with_args(an_instance_of(Hanami::Providers::DB::Adapter))
45
- end
46
- end
47
-
48
35
  describe "adapters" do
49
36
  subject(:adapter) { config.adapter(:yaml) }
50
37
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  RSpec.describe "Hanami::VERSION" do
4
4
  it "returns current version" do
5
- expect(Hanami::VERSION).to eq("2.2.0.beta2")
5
+ expect(Hanami::VERSION).to eq("2.2.0")
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0.beta2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-25 00:00:00.000000000 Z
11
+ date: 2024-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -132,16 +132,16 @@ dependencies:
132
132
  name: dry-system
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - '='
135
+ - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 1.1.0.beta2
137
+ version: '1.1'
138
138
  type: :runtime
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - '='
142
+ - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 1.1.0.beta2
144
+ version: '1.1'
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: dry-logger
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -166,30 +166,44 @@ dependencies:
166
166
  name: hanami-cli
167
167
  requirement: !ruby/object:Gem::Requirement
168
168
  requirements:
169
- - - '='
169
+ - - "~>"
170
170
  - !ruby/object:Gem::Version
171
- version: 2.2.0.beta2
171
+ version: '2.2'
172
172
  type: :runtime
173
173
  prerelease: false
174
174
  version_requirements: !ruby/object:Gem::Requirement
175
175
  requirements:
176
- - - '='
176
+ - - "~>"
177
177
  - !ruby/object:Gem::Version
178
- version: 2.2.0.beta2
178
+ version: '2.2'
179
179
  - !ruby/object:Gem::Dependency
180
180
  name: hanami-utils
181
181
  requirement: !ruby/object:Gem::Requirement
182
182
  requirements:
183
183
  - - "~>"
184
184
  - !ruby/object:Gem::Version
185
- version: 2.2.beta
185
+ version: '2.2'
186
186
  type: :runtime
187
187
  prerelease: false
188
188
  version_requirements: !ruby/object:Gem::Requirement
189
189
  requirements:
190
190
  - - "~>"
191
191
  - !ruby/object:Gem::Version
192
- version: 2.2.beta
192
+ version: '2.2'
193
+ - !ruby/object:Gem::Dependency
194
+ name: json
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ version: 2.7.2
200
+ type: :runtime
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: 2.7.2
193
207
  - !ruby/object:Gem::Dependency
194
208
  name: zeitwerk
195
209
  requirement: !ruby/object:Gem::Requirement
@@ -280,6 +294,7 @@ files:
280
294
  - lib/hanami/extensions/action.rb
281
295
  - lib/hanami/extensions/action/slice_configured_action.rb
282
296
  - lib/hanami/extensions/db/repo.rb
297
+ - lib/hanami/extensions/operation.rb
283
298
  - lib/hanami/extensions/router/errors.rb
284
299
  - lib/hanami/extensions/view.rb
285
300
  - lib/hanami/extensions/view/context.rb
@@ -376,6 +391,7 @@ files:
376
391
  - spec/integration/logging/exception_logging_spec.rb
377
392
  - spec/integration/logging/notifications_spec.rb
378
393
  - spec/integration/logging/request_logging_spec.rb
394
+ - spec/integration/operations/extension_spec.rb
379
395
  - spec/integration/rack_app/body_parser_spec.rb
380
396
  - spec/integration/rack_app/method_override_spec.rb
381
397
  - spec/integration/rack_app/middleware_spec.rb
@@ -455,6 +471,7 @@ files:
455
471
  - spec/unit/hanami/helpers/form_helper_spec.rb
456
472
  - spec/unit/hanami/port_spec.rb
457
473
  - spec/unit/hanami/providers/db/config/default_config_spec.rb
474
+ - spec/unit/hanami/providers/db/config/gateway_spec.rb
458
475
  - spec/unit/hanami/providers/db/config_spec.rb
459
476
  - spec/unit/hanami/router/errors/not_allowed_error_spec.rb
460
477
  - spec/unit/hanami/router/errors/not_found_error_spec.rb
@@ -486,7 +503,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
486
503
  - !ruby/object:Gem::Version
487
504
  version: '0'
488
505
  requirements: []
489
- rubygems_version: 3.5.16
506
+ rubygems_version: 3.5.22
490
507
  signing_key:
491
508
  specification_version: 4
492
509
  summary: The web, with simplicity
@@ -535,6 +552,7 @@ test_files:
535
552
  - spec/integration/logging/exception_logging_spec.rb
536
553
  - spec/integration/logging/notifications_spec.rb
537
554
  - spec/integration/logging/request_logging_spec.rb
555
+ - spec/integration/operations/extension_spec.rb
538
556
  - spec/integration/rack_app/body_parser_spec.rb
539
557
  - spec/integration/rack_app/method_override_spec.rb
540
558
  - spec/integration/rack_app/middleware_spec.rb
@@ -614,6 +632,7 @@ test_files:
614
632
  - spec/unit/hanami/helpers/form_helper_spec.rb
615
633
  - spec/unit/hanami/port_spec.rb
616
634
  - spec/unit/hanami/providers/db/config/default_config_spec.rb
635
+ - spec/unit/hanami/providers/db/config/gateway_spec.rb
617
636
  - spec/unit/hanami/providers/db/config_spec.rb
618
637
  - spec/unit/hanami/router/errors/not_allowed_error_spec.rb
619
638
  - spec/unit/hanami/router/errors/not_found_error_spec.rb