hanami 2.1.1 → 2.2.0.beta2
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 +33 -0
- data/README.md +7 -7
- data/hanami.gemspec +6 -6
- data/lib/hanami/app.rb +5 -1
- data/lib/hanami/config/db.rb +33 -0
- data/lib/hanami/config.rb +36 -9
- data/lib/hanami/constants.rb +4 -0
- data/lib/hanami/extensions/db/repo.rb +103 -0
- data/lib/hanami/extensions.rb +4 -0
- data/lib/hanami/helpers/form_helper/form_builder.rb +4 -6
- data/lib/hanami/provider/source.rb +16 -0
- data/lib/hanami/provider_registrar.rb +28 -0
- data/lib/hanami/providers/assets.rb +2 -20
- data/lib/hanami/providers/db/adapter.rb +75 -0
- data/lib/hanami/providers/db/adapters.rb +50 -0
- data/lib/hanami/providers/db/config.rb +62 -0
- data/lib/hanami/providers/db/gateway.rb +70 -0
- data/lib/hanami/providers/db/sql_adapter.rb +100 -0
- data/lib/hanami/providers/db.rb +298 -0
- data/lib/hanami/providers/db_logging.rb +22 -0
- data/lib/hanami/providers/inflector.rb +1 -1
- data/lib/hanami/providers/logger.rb +1 -1
- data/lib/hanami/providers/rack.rb +3 -3
- data/lib/hanami/providers/relations.rb +31 -0
- data/lib/hanami/providers/routes.rb +2 -14
- data/lib/hanami/rake_tasks.rb +8 -7
- data/lib/hanami/slice.rb +84 -4
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami.rb +3 -0
- data/spec/integration/container/provider_environment_spec.rb +52 -0
- data/spec/integration/db/auto_registration_spec.rb +39 -0
- data/spec/integration/db/commands_spec.rb +80 -0
- data/spec/integration/db/db_inflector_spec.rb +57 -0
- data/spec/integration/db/db_slices_spec.rb +332 -0
- data/spec/integration/db/db_spec.rb +245 -0
- data/spec/integration/db/gateways_spec.rb +320 -0
- data/spec/integration/db/logging_spec.rb +238 -0
- data/spec/integration/db/mappers_spec.rb +84 -0
- data/spec/integration/db/provider_config_spec.rb +88 -0
- data/spec/integration/db/provider_spec.rb +35 -0
- data/spec/integration/db/relations_spec.rb +60 -0
- data/spec/integration/db/repo_spec.rb +215 -0
- data/spec/integration/db/slices_importing_from_parent.rb +130 -0
- data/spec/integration/slices/slice_configuration_spec.rb +4 -4
- data/spec/support/app_integration.rb +3 -0
- data/spec/unit/hanami/config/db_spec.rb +38 -0
- data/spec/unit/hanami/config/router_spec.rb +1 -1
- data/spec/unit/hanami/helpers/form_helper_spec.rb +35 -4
- data/spec/unit/hanami/providers/db/config/default_config_spec.rb +100 -0
- data/spec/unit/hanami/providers/db/config_spec.rb +156 -0
- data/spec/unit/hanami/slice_spec.rb +32 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +72 -20
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
module Providers
|
7
|
+
class DB < Hanami::Provider::Source
|
8
|
+
# @api public
|
9
|
+
# @since 2.2.0
|
10
|
+
class Config < Dry::Configurable::Config
|
11
|
+
include Dry::Core::Constants
|
12
|
+
|
13
|
+
# @api public
|
14
|
+
# @since 2.2.0
|
15
|
+
def gateway(key)
|
16
|
+
gateway = (gateways[key] ||= Gateway.new)
|
17
|
+
yield gateway if block_given?
|
18
|
+
gateway
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api public
|
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)
|
41
|
+
yield adapter if block_given?
|
42
|
+
adapter
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
def each_plugin
|
47
|
+
return to_enum(__method__) unless block_given?
|
48
|
+
|
49
|
+
universal_plugins = adapters[nil].plugins
|
50
|
+
|
51
|
+
gateways.values.group_by(&:adapter_name).each do |adapter_name, adapter_gateways|
|
52
|
+
per_adapter_plugins = adapter_gateways.map { _1.adapter.plugins }.flatten(1)
|
53
|
+
|
54
|
+
(universal_plugins + per_adapter_plugins).uniq.each do |plugin_spec, config_block|
|
55
|
+
yield adapter_name, plugin_spec, config_block
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "dry/core"
|
5
|
+
|
6
|
+
module Hanami
|
7
|
+
module Providers
|
8
|
+
class DB < Hanami::Provider::Source
|
9
|
+
# @api public
|
10
|
+
# @since 2.2.0
|
11
|
+
class Gateway
|
12
|
+
include Dry::Core::Constants
|
13
|
+
include Dry::Configurable
|
14
|
+
|
15
|
+
setting :database_url
|
16
|
+
setting :adapter_name, default: :sql
|
17
|
+
setting :adapter, mutable: true
|
18
|
+
|
19
|
+
# @api public
|
20
|
+
# @since 2.2.0
|
21
|
+
def adapter(name = Undefined)
|
22
|
+
return config.adapter if name.eql?(Undefined)
|
23
|
+
|
24
|
+
if block_given?
|
25
|
+
# If a block is given, explicitly configure the gateway's adapter
|
26
|
+
config.adapter_name = name
|
27
|
+
adapter = (config.adapter ||= Adapters.new_adapter(name))
|
28
|
+
yield adapter
|
29
|
+
adapter
|
30
|
+
else
|
31
|
+
# If an adapter name is given without a block, use the default adapter configured with
|
32
|
+
# the same name
|
33
|
+
config.adapter_name = adapter_name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
def configure_adapter(default_adapters)
|
39
|
+
default_adapter = default_adapters[config.adapter_name]
|
40
|
+
config.adapter ||= default_adapter.dup
|
41
|
+
|
42
|
+
config.adapter.configure_from_adapter(default_adapter)
|
43
|
+
config.adapter.configure_from_adapter(default_adapters[nil])
|
44
|
+
config.adapter.configure_for_database(config.database_url)
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
def cache_keys
|
51
|
+
[config.database_url, config.adapter.gateway_cache_keys]
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def method_missing(name, *args, &block)
|
57
|
+
if config.respond_to?(name)
|
58
|
+
config.public_send(name, *args, &block)
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def respond_to_missing?(name, _include_all = false)
|
65
|
+
config.respond_to?(name) || super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Providers
|
5
|
+
class DB < Hanami::Provider::Source
|
6
|
+
# @api public
|
7
|
+
# @since 2.2.0
|
8
|
+
class SQLAdapter < Adapter
|
9
|
+
# @api public
|
10
|
+
# @since 2.2.0
|
11
|
+
setting :extensions, mutable: true
|
12
|
+
|
13
|
+
# @api public
|
14
|
+
# @since 2.2.0
|
15
|
+
def extension(*extensions)
|
16
|
+
self.extensions.concat(extensions)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api public
|
20
|
+
# @since 2.2.0
|
21
|
+
def extensions
|
22
|
+
config.extensions ||= []
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def configure_from_adapter(other_adapter)
|
27
|
+
super
|
28
|
+
|
29
|
+
return if skip_defaults?
|
30
|
+
|
31
|
+
# As part of gateway configuration, every gateway will receive the "any adapter" here,
|
32
|
+
# which is a plain `Adapter`, not an `SQLAdapter`. Its configuration will have been merged
|
33
|
+
# by `super`, so no further work is required.
|
34
|
+
return unless other_adapter.is_a?(self.class)
|
35
|
+
|
36
|
+
extensions.concat(other_adapter.extensions).uniq! unless skip_defaults?(:extensions)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def configure_for_database(database_url)
|
41
|
+
return if skip_defaults?
|
42
|
+
|
43
|
+
configure_plugins
|
44
|
+
configure_extensions(database_url)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @api private
|
48
|
+
private def configure_plugins
|
49
|
+
return if skip_defaults?(:plugins)
|
50
|
+
|
51
|
+
# Configure the plugin via a frozen proc, so it can be properly uniq'ed when configured
|
52
|
+
# for multiple gateways. See `Hanami::Providers::DB::Config#each_plugin`.
|
53
|
+
plugin(relations: :instrumentation, &INSTRUMENTATION_PLUGIN_CONFIG)
|
54
|
+
|
55
|
+
plugin relations: :auto_restrictions
|
56
|
+
end
|
57
|
+
|
58
|
+
# @api private
|
59
|
+
INSTRUMENTATION_PLUGIN_CONFIG = -> plugin {
|
60
|
+
plugin.notifications = target["notifications"]
|
61
|
+
}.freeze
|
62
|
+
private_constant :INSTRUMENTATION_PLUGIN_CONFIG
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
private def configure_extensions(database_url)
|
66
|
+
return if skip_defaults?(:extensions)
|
67
|
+
|
68
|
+
# Extensions for all SQL databases
|
69
|
+
extension(
|
70
|
+
:caller_logging,
|
71
|
+
:error_sql,
|
72
|
+
:sql_comments
|
73
|
+
)
|
74
|
+
|
75
|
+
# Extensions for specific databases
|
76
|
+
if database_url.to_s.start_with?(%r{postgres(ql)*://}) # FIXME: what is the canonical postgres URL?
|
77
|
+
extension(
|
78
|
+
:pg_array,
|
79
|
+
:pg_enum,
|
80
|
+
:pg_json,
|
81
|
+
:pg_range
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @api private
|
87
|
+
def gateway_options
|
88
|
+
{extensions: config.extensions}
|
89
|
+
end
|
90
|
+
|
91
|
+
# @api public
|
92
|
+
# @since 2.2.0
|
93
|
+
def clear
|
94
|
+
config.extensions = nil
|
95
|
+
super
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,298 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "dry/core"
|
5
|
+
require "uri"
|
6
|
+
require_relative "../constants"
|
7
|
+
|
8
|
+
module Hanami
|
9
|
+
module Providers
|
10
|
+
# @api private
|
11
|
+
# @since 2.2.0
|
12
|
+
class DB < Hanami::Provider::Source
|
13
|
+
extend Dry::Core::Cache
|
14
|
+
|
15
|
+
include Dry::Configurable(config_class: Providers::DB::Config)
|
16
|
+
|
17
|
+
setting :adapters, mutable: true, default: Adapters.new
|
18
|
+
setting :gateways, default: {}
|
19
|
+
|
20
|
+
def initialize(...)
|
21
|
+
super(...)
|
22
|
+
|
23
|
+
@config_finalized = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def finalize_config
|
27
|
+
return if @config_finalized
|
28
|
+
|
29
|
+
apply_parent_config if apply_parent_config?
|
30
|
+
|
31
|
+
configure_gateways
|
32
|
+
|
33
|
+
@config_finalized = true
|
34
|
+
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def prepare
|
39
|
+
prepare_and_import_parent_db and return if import_from_parent?
|
40
|
+
|
41
|
+
override_rom_inflector
|
42
|
+
|
43
|
+
finalize_config
|
44
|
+
|
45
|
+
require "hanami-db"
|
46
|
+
|
47
|
+
gateways = prepare_gateways
|
48
|
+
|
49
|
+
if gateways[:default]
|
50
|
+
register "gateway", gateways[:default]
|
51
|
+
elsif gateways.length == 1
|
52
|
+
register "gateway", gateways.values.first
|
53
|
+
end
|
54
|
+
gateways.each do |key, gateway|
|
55
|
+
register "gateways.#{key}", gateway
|
56
|
+
end
|
57
|
+
|
58
|
+
@rom_config = ROM::Configuration.new(gateways)
|
59
|
+
|
60
|
+
config.each_plugin do |adapter_name, plugin_spec, config_block|
|
61
|
+
if config_block
|
62
|
+
@rom_config.plugin(adapter_name, plugin_spec) do |plugin_config|
|
63
|
+
instance_exec(plugin_config, &config_block)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
@rom_config.plugin(adapter_name, plugin_spec)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
register "config", @rom_config
|
71
|
+
end
|
72
|
+
|
73
|
+
def start
|
74
|
+
start_and_import_parent_db and return if import_from_parent?
|
75
|
+
|
76
|
+
# Set up DB logging for the whole app. We share the app's notifications bus across all
|
77
|
+
# slices, so we only need to configure the subsciprtion for DB logging just once.
|
78
|
+
slice.app.start :db_logging
|
79
|
+
|
80
|
+
# Register ROM components
|
81
|
+
register_rom_components :relation, "relations"
|
82
|
+
register_rom_components :command, File.join("db", "commands")
|
83
|
+
register_rom_components :mapper, File.join("db", "mappers")
|
84
|
+
|
85
|
+
rom = ROM.container(@rom_config)
|
86
|
+
|
87
|
+
register "rom", rom
|
88
|
+
end
|
89
|
+
|
90
|
+
def stop
|
91
|
+
slice["db.rom"].disconnect
|
92
|
+
end
|
93
|
+
|
94
|
+
# @api private
|
95
|
+
# @since 2.2.0
|
96
|
+
def database_urls
|
97
|
+
finalize_config
|
98
|
+
config.gateways.transform_values { _1.database_url }
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def parent_db_provider
|
104
|
+
return @parent_db_provider if instance_variable_defined?(:@parent_db_provider)
|
105
|
+
|
106
|
+
@parent_db_provider = slice.parent && slice.parent.container.providers[:db]
|
107
|
+
end
|
108
|
+
|
109
|
+
def apply_parent_config
|
110
|
+
parent_db_provider.source.finalize_config
|
111
|
+
|
112
|
+
self.class.settings.keys.each do |key|
|
113
|
+
# Preserve settings already configured locally
|
114
|
+
next if config.configured?(key)
|
115
|
+
|
116
|
+
# Do not copy gateways, these are always configured per slice
|
117
|
+
next if key == :gateways
|
118
|
+
|
119
|
+
# Skip adapter config, we handle this below
|
120
|
+
next if key == :adapters
|
121
|
+
|
122
|
+
config[key] = parent_db_provider.source.config[key]
|
123
|
+
end
|
124
|
+
|
125
|
+
parent_db_provider.source.config.adapters.each do |adapter_name, parent_adapter|
|
126
|
+
adapter = config.adapters[adapter_name]
|
127
|
+
|
128
|
+
adapter.class.settings.keys.each do |key|
|
129
|
+
next if adapter.config.configured?(key)
|
130
|
+
|
131
|
+
adapter.config[key] = parent_adapter.config[key]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def apply_parent_config?
|
137
|
+
slice.config.db.configure_from_parent && parent_db_provider
|
138
|
+
end
|
139
|
+
|
140
|
+
def import_from_parent?
|
141
|
+
slice.config.db.import_from_parent && slice.parent
|
142
|
+
end
|
143
|
+
|
144
|
+
def prepare_and_import_parent_db
|
145
|
+
return unless parent_db_provider
|
146
|
+
|
147
|
+
slice.parent.prepare :db
|
148
|
+
@rom_config = slice.parent["db.config"]
|
149
|
+
|
150
|
+
register "config", (@rom_config = slice.parent["db.config"])
|
151
|
+
register "gateway", slice.parent["db.gateway"]
|
152
|
+
end
|
153
|
+
|
154
|
+
def start_and_import_parent_db
|
155
|
+
return unless parent_db_provider
|
156
|
+
|
157
|
+
slice.parent.start :db
|
158
|
+
|
159
|
+
register "rom", slice.parent["db.rom"]
|
160
|
+
end
|
161
|
+
|
162
|
+
# ROM 5.3 doesn't have a configurable inflector.
|
163
|
+
#
|
164
|
+
# This is a problem in Hanami because using different
|
165
|
+
# inflection rules for ROM will lead to constant loading
|
166
|
+
# errors.
|
167
|
+
def override_rom_inflector
|
168
|
+
return if ROM::Inflector == Hanami.app["inflector"]
|
169
|
+
|
170
|
+
ROM.instance_eval {
|
171
|
+
remove_const :Inflector
|
172
|
+
const_set :Inflector, Hanami.app["inflector"]
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
def configure_gateways
|
177
|
+
# Create gateway configs for gateways detected from database_url ENV vars
|
178
|
+
database_urls_from_env = detect_database_urls_from_env
|
179
|
+
database_urls_from_env.keys.each do |key|
|
180
|
+
config.gateways[key] ||= Gateway.new
|
181
|
+
end
|
182
|
+
|
183
|
+
# Create a single default gateway if none is configured or detected from database URLs
|
184
|
+
config.gateways[:default] = Gateway.new if config.gateways.empty?
|
185
|
+
|
186
|
+
# Leave gateways in a stable order: :default first, followed by others in sort order
|
187
|
+
if config.gateways.length > 1
|
188
|
+
gateways = config.gateways
|
189
|
+
config.gateways = {default: gateways[:default], **gateways.sort.to_h}.compact
|
190
|
+
end
|
191
|
+
|
192
|
+
config.gateways.each do |key, gw_config|
|
193
|
+
gw_config.database_url ||= database_urls_from_env.fetch(key) {
|
194
|
+
raise Hanami::ComponentLoadError, "A database_url for gateway #{key} is required to start :db."
|
195
|
+
}
|
196
|
+
|
197
|
+
ensure_database_gem(gw_config.database_url)
|
198
|
+
|
199
|
+
gw_config.configure_adapter(config.adapters)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def prepare_gateways
|
204
|
+
config.gateways.transform_values { |gw_config|
|
205
|
+
# Avoid spurious connections by reusing identically configured gateways across slices
|
206
|
+
gateway = fetch_or_store(gw_config.cache_keys) {
|
207
|
+
ROM::Gateway.setup(
|
208
|
+
gw_config.adapter_name,
|
209
|
+
gw_config.database_url,
|
210
|
+
**gw_config.adapter.gateway_options
|
211
|
+
)
|
212
|
+
}
|
213
|
+
}
|
214
|
+
end
|
215
|
+
|
216
|
+
def detect_database_urls_from_env
|
217
|
+
database_urls = {}
|
218
|
+
|
219
|
+
env_var_prefix = slice.slice_name.name.gsub("/", "__").upcase + "__" unless slice.app?
|
220
|
+
|
221
|
+
# Build gateway URLs from ENV vars with specific gateway named suffixes
|
222
|
+
gateway_prefix = "#{env_var_prefix}DATABASE_URL__"
|
223
|
+
ENV.select { |(k, _)| k.start_with?(gateway_prefix) }
|
224
|
+
.each do |(var, _)|
|
225
|
+
gateway_name = var.split(gateway_prefix).last.downcase
|
226
|
+
|
227
|
+
database_urls[gateway_name.to_sym] = ENV[var]
|
228
|
+
end
|
229
|
+
|
230
|
+
# Set the default gateway from ENV var without suffix
|
231
|
+
if !database_urls.key?(:default)
|
232
|
+
fallback_vars = ["#{env_var_prefix}DATABASE_URL", "DATABASE_URL"].uniq
|
233
|
+
|
234
|
+
fallback_vars.each do |var|
|
235
|
+
url = ENV[var]
|
236
|
+
database_urls[:default] = url and break if url
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
if Hanami.env?(:test)
|
241
|
+
database_urls.transform_values! { Hanami::DB::Testing.database_url(_1) }
|
242
|
+
end
|
243
|
+
|
244
|
+
database_urls
|
245
|
+
end
|
246
|
+
|
247
|
+
# @api private
|
248
|
+
# @since 2.2.0
|
249
|
+
DATABASE_GEMS = {
|
250
|
+
"mysql2" => "mysql2",
|
251
|
+
"postgres" => "pg",
|
252
|
+
"sqlite" => "sqlite3"
|
253
|
+
}.freeze
|
254
|
+
private_constant :DATABASE_GEMS
|
255
|
+
|
256
|
+
# Raises an error if the relevant database gem for the configured database_url is not
|
257
|
+
# installed.
|
258
|
+
#
|
259
|
+
# Takes a conservative approach to raising errors. It only does so for the database_url
|
260
|
+
# schemes generated by the `hanami new` CLI command. Uknown schemes are ignored and no errors
|
261
|
+
# are raised.
|
262
|
+
def ensure_database_gem(database_url)
|
263
|
+
scheme = URI(database_url).scheme
|
264
|
+
return unless scheme
|
265
|
+
|
266
|
+
database_gem = DATABASE_GEMS[scheme]
|
267
|
+
return unless database_gem
|
268
|
+
|
269
|
+
return if Hanami.bundled?(database_gem)
|
270
|
+
|
271
|
+
raise Hanami::ComponentLoadError, %(The "#{database_gem}" gem is required to connect to #{database_url}. Please add it to your Gemfile.)
|
272
|
+
end
|
273
|
+
|
274
|
+
def register_rom_components(component_type, path)
|
275
|
+
components_path = target.source_path.join(path)
|
276
|
+
components_path.glob("**/*.rb").each do |component_file|
|
277
|
+
component_name = component_file
|
278
|
+
.relative_path_from(components_path)
|
279
|
+
.sub(RB_EXT_REGEXP, "")
|
280
|
+
.to_s
|
281
|
+
|
282
|
+
component_class = target.inflector.camelize(
|
283
|
+
"#{target.slice_name.name}/#{path}/#{component_name}"
|
284
|
+
).then { target.inflector.constantize(_1) }
|
285
|
+
|
286
|
+
@rom_config.public_send(:"register_#{component_type}", component_class)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
Dry::System.register_provider_source(
|
292
|
+
:db,
|
293
|
+
source: DB,
|
294
|
+
group: :hanami,
|
295
|
+
provider_options: {namespace: true}
|
296
|
+
)
|
297
|
+
end
|
298
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Providers
|
5
|
+
# @api private
|
6
|
+
# @since 2.2.0
|
7
|
+
class DBLogging < Hanami::Provider::Source
|
8
|
+
# @api private
|
9
|
+
# @since 2.2.0
|
10
|
+
def prepare
|
11
|
+
require "dry/monitor/sql/logger"
|
12
|
+
slice["notifications"].register_event :sql
|
13
|
+
end
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
# @since 2.2.0
|
17
|
+
def start
|
18
|
+
Dry::Monitor::SQL::Logger.new(slice["logger"]).subscribe(slice["notifications"])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -12,7 +12,7 @@ module Hanami
|
|
12
12
|
#
|
13
13
|
# @api private
|
14
14
|
# @since 2.0.0
|
15
|
-
class Rack <
|
15
|
+
class Rack < Hanami::Provider::Source
|
16
16
|
# @api private
|
17
17
|
def prepare
|
18
18
|
Dry::Monitor.load_extensions(:rack)
|
@@ -30,14 +30,14 @@ module Hanami
|
|
30
30
|
|
31
31
|
# @api private
|
32
32
|
def start
|
33
|
-
|
33
|
+
slice.start :logger
|
34
34
|
|
35
35
|
monitor_middleware = Dry::Monitor::Rack::Middleware.new(
|
36
36
|
target["notifications"],
|
37
37
|
clock: Dry::Monitor::Clock.new(unit: :microsecond)
|
38
38
|
)
|
39
39
|
|
40
|
-
rack_logger = Hanami::Web::RackLogger.new(target[:logger], env:
|
40
|
+
rack_logger = Hanami::Web::RackLogger.new(target[:logger], env: slice.container.env)
|
41
41
|
rack_logger.attach(monitor_middleware)
|
42
42
|
|
43
43
|
register "monitor", monitor_middleware
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Providers
|
5
|
+
# @api private
|
6
|
+
# @since 2.2.0
|
7
|
+
class Relations < Hanami::Provider::Source
|
8
|
+
def start
|
9
|
+
start_and_import_parent_relations and return if slice.parent && slice.config.db.import_from_parent
|
10
|
+
|
11
|
+
slice.start :db
|
12
|
+
|
13
|
+
register_relations target["db.rom"]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def register_relations(rom)
|
19
|
+
rom.relations.each do |name, _|
|
20
|
+
register name, rom.relations[name]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def start_and_import_parent_relations
|
25
|
+
slice.parent.start :relations
|
26
|
+
|
27
|
+
register_relations slice.parent["db.rom"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -9,19 +9,7 @@ module Hanami
|
|
9
9
|
#
|
10
10
|
# @api private
|
11
11
|
# @since 2.0.0
|
12
|
-
class Routes <
|
13
|
-
# @api private
|
14
|
-
def self.for_slice(slice)
|
15
|
-
Class.new(self) do |klass|
|
16
|
-
klass.instance_variable_set(:@slice, slice)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# @api private
|
21
|
-
def self.slice
|
22
|
-
@slice || Hanami.app
|
23
|
-
end
|
24
|
-
|
12
|
+
class Routes < Hanami::Provider::Source
|
25
13
|
# @api private
|
26
14
|
def prepare
|
27
15
|
require "hanami/slice/routes_helper"
|
@@ -33,7 +21,7 @@ module Hanami
|
|
33
21
|
# router during the process of booting. This ensures the router's resolver can run strict
|
34
22
|
# action key checks once when it runs on a fully booted slice.
|
35
23
|
register :routes do
|
36
|
-
Hanami::Slice::RoutesHelper.new(
|
24
|
+
Hanami::Slice::RoutesHelper.new(slice.router)
|
37
25
|
end
|
38
26
|
end
|
39
27
|
end
|
data/lib/hanami/rake_tasks.rb
CHANGED
@@ -33,13 +33,14 @@ Hanami::CLI::RakeTasks.register_tasks do
|
|
33
33
|
#
|
34
34
|
# If you're not in control and your deployment requires these "standard"
|
35
35
|
# Rake tasks, they are here only to solve this specific problem.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
|
37
|
+
if Hanami.bundled?("hanami-db")
|
38
|
+
namespace :db do
|
39
|
+
task :migrate do
|
40
|
+
Hanami::CLI::Commands::App::DB::Migrate.new.call
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
43
44
|
|
44
45
|
if Hanami.bundled?("hanami-assets")
|
45
46
|
namespace :assets do
|