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 +4 -4
- data/CHANGELOG.md +19 -0
- data/hanami.gemspec +4 -3
- data/lib/hanami/extensions/operation.rb +48 -0
- data/lib/hanami/extensions.rb +4 -0
- data/lib/hanami/providers/db/adapters.rb +19 -3
- data/lib/hanami/providers/db/config.rb +4 -22
- data/lib/hanami/providers/db/gateway.rb +20 -3
- data/lib/hanami/providers/db/sql_adapter.rb +3 -3
- data/lib/hanami/providers/db.rb +27 -5
- data/lib/hanami/version.rb +1 -1
- data/spec/integration/db/db_slices_spec.rb +66 -0
- data/spec/integration/db/gateways_spec.rb +42 -1
- data/spec/integration/operations/extension_spec.rb +59 -0
- data/spec/unit/hanami/providers/db/config/gateway_spec.rb +73 -0
- data/spec/unit/hanami/providers/db/config_spec.rb +0 -13
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +32 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ebc4cbb51db37137a558abeeb3c4aa509d2a6d4db521458b465a427e503b098
|
4
|
+
data.tar.gz: fdd74d2e280be11ba0db6852a0dcfcd15df7629a1edb6e6b7067f623103d9fdd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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", "
|
39
|
+
spec.add_dependency "dry-system", "~> 1.1"
|
40
40
|
spec.add_dependency "dry-logger", "~> 1.0", "< 2"
|
41
|
-
spec.add_dependency "hanami-cli", "
|
42
|
-
spec.add_dependency "hanami-utils", "~> 2.2
|
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)
|
data/lib/hanami/extensions.rb
CHANGED
@@ -30,9 +30,7 @@ module Hanami
|
|
30
30
|
# @api private
|
31
31
|
# @since 2.2.0
|
32
32
|
def initialize
|
33
|
-
@adapters =
|
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
|
24
|
-
|
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
|
-
|
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
|
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
|
-
|
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)*://})
|
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:
|
88
|
+
{extensions: extensions}
|
89
89
|
end
|
90
90
|
|
91
91
|
# @api public
|
data/lib/hanami/providers/db.rb
CHANGED
@@ -113,7 +113,7 @@ module Hanami
|
|
113
113
|
# Preserve settings already configured locally
|
114
114
|
next if config.configured?(key)
|
115
115
|
|
116
|
-
#
|
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.
|
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
|
-
|
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.
|
232
|
+
**gw_config.options
|
211
233
|
)
|
212
234
|
}
|
213
235
|
}
|
data/lib/hanami/version.rb
CHANGED
@@ -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
|
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
|
|
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
|
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-
|
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
|
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
|
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
|
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
|
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
|
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
|
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.
|
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
|