hanami 2.2.0.beta1 → 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 +14 -0
- data/hanami.gemspec +2 -2
- data/lib/hanami/constants.rb +4 -0
- data/lib/hanami/helpers/form_helper/form_builder.rb +2 -2
- data/lib/hanami/provider/source.rb +16 -0
- data/lib/hanami/provider_registrar.rb +4 -2
- data/lib/hanami/providers/assets.rb +3 -3
- data/lib/hanami/providers/db/adapter.rb +8 -1
- data/lib/hanami/providers/db/adapters.rb +8 -2
- data/lib/hanami/providers/db/config.rb +17 -21
- data/lib/hanami/providers/db/gateway.rb +70 -0
- data/lib/hanami/providers/db/sql_adapter.rb +25 -5
- data/lib/hanami/providers/db.rb +162 -67
- data/lib/hanami/providers/db_logging.rb +3 -3
- 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 +5 -5
- data/lib/hanami/providers/routes.rb +2 -2
- data/lib/hanami/version.rb +1 -1
- data/spec/integration/db/commands_spec.rb +80 -0
- data/spec/integration/db/db_slices_spec.rb +9 -4
- data/spec/integration/db/db_spec.rb +32 -7
- data/spec/integration/db/gateways_spec.rb +320 -0
- data/spec/integration/db/mappers_spec.rb +84 -0
- data/spec/integration/db/relations_spec.rb +60 -0
- data/spec/unit/hanami/helpers/form_helper_spec.rb +4 -4
- data/spec/unit/hanami/providers/db/config/default_config_spec.rb +1 -8
- data/spec/unit/hanami/providers/db/config_spec.rb +1 -51
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +17 -7
data/lib/hanami/providers/db.rb
CHANGED
@@ -2,31 +2,37 @@
|
|
2
2
|
|
3
3
|
require "dry/configurable"
|
4
4
|
require "dry/core"
|
5
|
+
require "uri"
|
6
|
+
require_relative "../constants"
|
5
7
|
|
6
8
|
module Hanami
|
7
9
|
module Providers
|
8
10
|
# @api private
|
9
11
|
# @since 2.2.0
|
10
|
-
class DB <
|
12
|
+
class DB < Hanami::Provider::Source
|
11
13
|
extend Dry::Core::Cache
|
12
14
|
|
13
15
|
include Dry::Configurable(config_class: Providers::DB::Config)
|
14
16
|
|
15
|
-
setting :database_url
|
16
|
-
setting :adapter, default: :sql
|
17
17
|
setting :adapters, mutable: true, default: Adapters.new
|
18
|
-
setting :
|
18
|
+
setting :gateways, default: {}
|
19
19
|
|
20
20
|
def initialize(...)
|
21
21
|
super(...)
|
22
22
|
|
23
|
-
@
|
23
|
+
@config_finalized = false
|
24
24
|
end
|
25
25
|
|
26
26
|
def finalize_config
|
27
|
-
|
27
|
+
return if @config_finalized
|
28
28
|
|
29
|
-
|
29
|
+
apply_parent_config if apply_parent_config?
|
30
|
+
|
31
|
+
configure_gateways
|
32
|
+
|
33
|
+
@config_finalized = true
|
34
|
+
|
35
|
+
self
|
30
36
|
end
|
31
37
|
|
32
38
|
def prepare
|
@@ -38,59 +44,43 @@ module Hanami
|
|
38
44
|
|
39
45
|
require "hanami-db"
|
40
46
|
|
41
|
-
|
42
|
-
raise Hanami::ComponentLoadError, "A database_url is required to start :db."
|
43
|
-
end
|
47
|
+
gateways = prepare_gateways
|
44
48
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
53
57
|
|
54
|
-
@rom_config = ROM::Configuration.new(
|
58
|
+
@rom_config = ROM::Configuration.new(gateways)
|
55
59
|
|
56
|
-
config.each_plugin do |plugin_spec, config_block|
|
60
|
+
config.each_plugin do |adapter_name, plugin_spec, config_block|
|
57
61
|
if config_block
|
58
|
-
@rom_config.plugin(
|
62
|
+
@rom_config.plugin(adapter_name, plugin_spec) do |plugin_config|
|
59
63
|
instance_exec(plugin_config, &config_block)
|
60
64
|
end
|
61
65
|
else
|
62
|
-
@rom_config.plugin(
|
66
|
+
@rom_config.plugin(adapter_name, plugin_spec)
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
66
70
|
register "config", @rom_config
|
67
|
-
register "gateway", gateway
|
68
71
|
end
|
69
72
|
|
70
|
-
# @api private
|
71
73
|
def start
|
72
74
|
start_and_import_parent_db and return if import_from_parent?
|
73
75
|
|
74
76
|
# Set up DB logging for the whole app. We share the app's notifications bus across all
|
75
77
|
# slices, so we only need to configure the subsciprtion for DB logging just once.
|
76
|
-
|
77
|
-
|
78
|
-
# Find and register relations
|
79
|
-
relations_path = target.source_path.join(config.relations_path)
|
80
|
-
relations_path.glob("*.rb").each do |relation_file|
|
81
|
-
relation_name = relation_file
|
82
|
-
.relative_path_from(relations_path)
|
83
|
-
.basename(relation_file.extname)
|
84
|
-
.to_s
|
85
|
-
|
86
|
-
relation_class = target.namespace
|
87
|
-
.const_get(:Relations) # TODO don't hardcode
|
88
|
-
.const_get(target.inflector.camelize(relation_name))
|
89
|
-
|
90
|
-
@rom_config.register_relation(relation_class)
|
91
|
-
end
|
78
|
+
slice.app.start :db_logging
|
92
79
|
|
93
|
-
#
|
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")
|
94
84
|
|
95
85
|
rom = ROM.container(@rom_config)
|
96
86
|
|
@@ -98,19 +88,14 @@ module Hanami
|
|
98
88
|
end
|
99
89
|
|
100
90
|
def stop
|
101
|
-
|
91
|
+
slice["db.rom"].disconnect
|
102
92
|
end
|
103
93
|
|
104
94
|
# @api private
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
slice_url_var = "#{target.slice_name.name.gsub("/", "__").upcase}__DATABASE_URL"
|
110
|
-
chosen_url = config.database_url || ENV[slice_url_var] || ENV["DATABASE_URL"]
|
111
|
-
chosen_url &&= Hanami::DB::Testing.database_url(chosen_url) if Hanami.env?(:test)
|
112
|
-
|
113
|
-
@database_url = chosen_url
|
95
|
+
# @since 2.2.0
|
96
|
+
def database_urls
|
97
|
+
finalize_config
|
98
|
+
config.gateways.transform_values { _1.database_url }
|
114
99
|
end
|
115
100
|
|
116
101
|
private
|
@@ -118,7 +103,7 @@ module Hanami
|
|
118
103
|
def parent_db_provider
|
119
104
|
return @parent_db_provider if instance_variable_defined?(:@parent_db_provider)
|
120
105
|
|
121
|
-
@parent_db_provider =
|
106
|
+
@parent_db_provider = slice.parent && slice.parent.container.providers[:db]
|
122
107
|
end
|
123
108
|
|
124
109
|
def apply_parent_config
|
@@ -128,6 +113,9 @@ module Hanami
|
|
128
113
|
# Preserve settings already configured locally
|
129
114
|
next if config.configured?(key)
|
130
115
|
|
116
|
+
# Do not copy gateways, these are always configured per slice
|
117
|
+
next if key == :gateways
|
118
|
+
|
131
119
|
# Skip adapter config, we handle this below
|
132
120
|
next if key == :adapters
|
133
121
|
|
@@ -146,36 +134,29 @@ module Hanami
|
|
146
134
|
end
|
147
135
|
|
148
136
|
def apply_parent_config?
|
149
|
-
|
150
|
-
end
|
151
|
-
|
152
|
-
def configure_for_database
|
153
|
-
return if @configured_for_database
|
154
|
-
|
155
|
-
config.adapter(config.adapter_name).configure_for_database(database_url)
|
156
|
-
@configured_for_database = true
|
137
|
+
slice.config.db.configure_from_parent && parent_db_provider
|
157
138
|
end
|
158
139
|
|
159
140
|
def import_from_parent?
|
160
|
-
|
141
|
+
slice.config.db.import_from_parent && slice.parent
|
161
142
|
end
|
162
143
|
|
163
144
|
def prepare_and_import_parent_db
|
164
145
|
return unless parent_db_provider
|
165
146
|
|
166
|
-
|
167
|
-
@rom_config =
|
147
|
+
slice.parent.prepare :db
|
148
|
+
@rom_config = slice.parent["db.config"]
|
168
149
|
|
169
|
-
register "config", (@rom_config =
|
170
|
-
register "gateway",
|
150
|
+
register "config", (@rom_config = slice.parent["db.config"])
|
151
|
+
register "gateway", slice.parent["db.gateway"]
|
171
152
|
end
|
172
153
|
|
173
154
|
def start_and_import_parent_db
|
174
155
|
return unless parent_db_provider
|
175
156
|
|
176
|
-
|
157
|
+
slice.parent.start :db
|
177
158
|
|
178
|
-
register "rom",
|
159
|
+
register "rom", slice.parent["db.rom"]
|
179
160
|
end
|
180
161
|
|
181
162
|
# ROM 5.3 doesn't have a configurable inflector.
|
@@ -191,6 +172,120 @@ module Hanami
|
|
191
172
|
const_set :Inflector, Hanami.app["inflector"]
|
192
173
|
}
|
193
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
|
194
289
|
end
|
195
290
|
|
196
291
|
Dry::System.register_provider_source(
|
@@ -4,18 +4,18 @@ module Hanami
|
|
4
4
|
module Providers
|
5
5
|
# @api private
|
6
6
|
# @since 2.2.0
|
7
|
-
class DBLogging <
|
7
|
+
class DBLogging < Hanami::Provider::Source
|
8
8
|
# @api private
|
9
9
|
# @since 2.2.0
|
10
10
|
def prepare
|
11
11
|
require "dry/monitor/sql/logger"
|
12
|
-
|
12
|
+
slice["notifications"].register_event :sql
|
13
13
|
end
|
14
14
|
|
15
15
|
# @api private
|
16
16
|
# @since 2.2.0
|
17
17
|
def start
|
18
|
-
Dry::Monitor::SQL::Logger.new(
|
18
|
+
Dry::Monitor::SQL::Logger.new(slice["logger"]).subscribe(slice["notifications"])
|
19
19
|
end
|
20
20
|
end
|
21
21
|
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
|
@@ -4,11 +4,11 @@ module Hanami
|
|
4
4
|
module Providers
|
5
5
|
# @api private
|
6
6
|
# @since 2.2.0
|
7
|
-
class Relations <
|
7
|
+
class Relations < Hanami::Provider::Source
|
8
8
|
def start
|
9
|
-
start_and_import_parent_relations and return if
|
9
|
+
start_and_import_parent_relations and return if slice.parent && slice.config.db.import_from_parent
|
10
10
|
|
11
|
-
|
11
|
+
slice.start :db
|
12
12
|
|
13
13
|
register_relations target["db.rom"]
|
14
14
|
end
|
@@ -22,9 +22,9 @@ module Hanami
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def start_and_import_parent_relations
|
25
|
-
|
25
|
+
slice.parent.start :relations
|
26
26
|
|
27
|
-
register_relations
|
27
|
+
register_relations slice.parent["db.rom"]
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -9,7 +9,7 @@ module Hanami
|
|
9
9
|
#
|
10
10
|
# @api private
|
11
11
|
# @since 2.0.0
|
12
|
-
class Routes <
|
12
|
+
class Routes < Hanami::Provider::Source
|
13
13
|
# @api private
|
14
14
|
def prepare
|
15
15
|
require "hanami/slice/routes_helper"
|
@@ -21,7 +21,7 @@ module Hanami
|
|
21
21
|
# router during the process of booting. This ensures the router's resolver can run strict
|
22
22
|
# action key checks once when it runs on a fully booted slice.
|
23
23
|
register :routes do
|
24
|
-
Hanami::Slice::RoutesHelper.new(
|
24
|
+
Hanami::Slice::RoutesHelper.new(slice.router)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
data/lib/hanami/version.rb
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "DB / Commands", :app_integration do
|
4
|
+
before do
|
5
|
+
@env = ENV.to_h
|
6
|
+
allow(Hanami::Env).to receive(:loaded?).and_return(false)
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
ENV.replace(@env)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "registers custom commands" do
|
14
|
+
with_tmp_directory(@dir = Dir.mktmpdir) do
|
15
|
+
write "config/app.rb", <<~RUBY
|
16
|
+
require "hanami"
|
17
|
+
|
18
|
+
module TestApp
|
19
|
+
class App < Hanami::App
|
20
|
+
config.logger.stream = File::NULL
|
21
|
+
end
|
22
|
+
end
|
23
|
+
RUBY
|
24
|
+
|
25
|
+
write "app/relations/posts.rb", <<~RUBY
|
26
|
+
module TestApp
|
27
|
+
module Relations
|
28
|
+
class Posts < Hanami::DB::Relation
|
29
|
+
schema :posts, infer: true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
RUBY
|
34
|
+
|
35
|
+
write "app/db/commands/nested/create_post_with_default_title.rb", <<~RUBY
|
36
|
+
module TestApp
|
37
|
+
module DB
|
38
|
+
module Commands
|
39
|
+
module Nested
|
40
|
+
class CreatePostWithDefaultTitle < ROM::SQL::Commands::Create
|
41
|
+
relation :posts
|
42
|
+
register_as :create_with_default_title
|
43
|
+
result :one
|
44
|
+
|
45
|
+
before :set_title
|
46
|
+
|
47
|
+
def set_title(tuple, *)
|
48
|
+
tuple[:title] ||= "Default title from command"
|
49
|
+
tuple
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
RUBY
|
57
|
+
|
58
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
59
|
+
|
60
|
+
require "hanami/prepare"
|
61
|
+
|
62
|
+
Hanami.app.prepare :db
|
63
|
+
|
64
|
+
# Manually run a migration and add a test record
|
65
|
+
gateway = TestApp::App["db.gateway"]
|
66
|
+
migration = gateway.migration do
|
67
|
+
change do
|
68
|
+
create_table :posts do
|
69
|
+
primary_key :id
|
70
|
+
column :title, :text, null: false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
migration.apply(gateway, :up)
|
75
|
+
|
76
|
+
post = TestApp::App["relations.posts"].command(:create_with_default_title).call({})
|
77
|
+
expect(post[:title]).to eq "Default title from command"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -84,13 +84,9 @@ RSpec.describe "DB / Slices", :app_integration do
|
|
84
84
|
end
|
85
85
|
RUBY
|
86
86
|
|
87
|
-
write "config/db/.keep", ""
|
88
|
-
|
89
87
|
write "config/providers/db.rb", <<~RUBY
|
90
88
|
Hanami.app.configure_provider :db do
|
91
89
|
config.adapter :sql do |a|
|
92
|
-
# a.skip_defaults
|
93
|
-
# a.plugin relation: :auto_restrictions
|
94
90
|
a.extension :exclude_or_null
|
95
91
|
end
|
96
92
|
end
|
@@ -119,6 +115,7 @@ RSpec.describe "DB / Slices", :app_integration do
|
|
119
115
|
write "slices/main/config/providers/db.rb", <<~RUBY
|
120
116
|
Main::Slice.configure_provider :db do
|
121
117
|
config.adapter :sql do |a|
|
118
|
+
a.skip_defaults :extensions
|
122
119
|
a.extensions.clear
|
123
120
|
end
|
124
121
|
end
|
@@ -136,6 +133,9 @@ RSpec.describe "DB / Slices", :app_integration do
|
|
136
133
|
|
137
134
|
ENV["DATABASE_URL"] = "sqlite://" + Pathname(@dir).realpath.join("database.db").to_s
|
138
135
|
|
136
|
+
# Extra gateway for app only. Unlike other config, not copied to child slices.
|
137
|
+
ENV["DATABASE_URL__EXTRA"] = "sqlite://" + Pathname(@dir).realpath.join("extra.db").to_s
|
138
|
+
|
139
139
|
require "hanami/prepare"
|
140
140
|
|
141
141
|
Main::Slice.prepare :db
|
@@ -167,6 +167,11 @@ RSpec.describe "DB / Slices", :app_integration do
|
|
167
167
|
migration.apply(gateway, :up)
|
168
168
|
gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
|
169
169
|
|
170
|
+
# Gateways on app are not passed down to child slices
|
171
|
+
expect(Hanami.app["db.rom"].gateways.keys).to eq [:default, :extra]
|
172
|
+
expect(Main::Slice["db.rom"].gateways.keys).to eq [:default]
|
173
|
+
expect(Admin::Slice["db.rom"].gateways.keys).to eq [:default]
|
174
|
+
|
170
175
|
# Admin slice has appropriate relations registered, and can access data
|
171
176
|
expect(Admin::Slice["db.rom"].relations[:posts].to_a).to eq [{id: 1, title: "Together breakfast"}]
|
172
177
|
expect(Admin::Slice["relations.posts"]).to be Admin::Slice["db.rom"].relations[:posts]
|
@@ -39,6 +39,7 @@ RSpec.describe "DB", :app_integration do
|
|
39
39
|
|
40
40
|
expect(Hanami.app["db.config"]).to be_an_instance_of ROM::Configuration
|
41
41
|
expect(Hanami.app["db.gateway"]).to be_an_instance_of ROM::SQL::Gateway
|
42
|
+
expect(Hanami.app["db.gateways.default"]).to be Hanami.app["db.gateway"]
|
42
43
|
|
43
44
|
# Manually run a migration and add a test record
|
44
45
|
gateway = Hanami.app["db.gateway"]
|
@@ -90,6 +91,7 @@ RSpec.describe "DB", :app_integration do
|
|
90
91
|
|
91
92
|
expect(Hanami.app["db.config"]).to be_an_instance_of ROM::Configuration
|
92
93
|
expect(Hanami.app["db.gateway"]).to be_an_instance_of ROM::SQL::Gateway
|
94
|
+
expect(Hanami.app["db.gateways.default"]).to be Hanami.app["db.gateway"]
|
93
95
|
|
94
96
|
# Manually run a migration and add a test record
|
95
97
|
gateway = Hanami.app["db.gateway"]
|
@@ -117,8 +119,6 @@ RSpec.describe "DB", :app_integration do
|
|
117
119
|
|
118
120
|
module TestApp
|
119
121
|
class App < Hanami::App
|
120
|
-
config.inflections do |inflections|
|
121
|
-
end
|
122
122
|
end
|
123
123
|
end
|
124
124
|
RUBY
|
@@ -131,6 +131,32 @@ RSpec.describe "DB", :app_integration do
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
+
it "raises an error when the database driver gem is missing" do
|
135
|
+
allow(Hanami).to receive(:bundled?).and_call_original
|
136
|
+
expect(Hanami).to receive(:bundled?).with("pg").and_return false
|
137
|
+
|
138
|
+
with_tmp_directory(Dir.mktmpdir) do
|
139
|
+
write "config/app.rb", <<~RUBY
|
140
|
+
require "hanami"
|
141
|
+
|
142
|
+
module TestApp
|
143
|
+
class App < Hanami::App
|
144
|
+
end
|
145
|
+
end
|
146
|
+
RUBY
|
147
|
+
|
148
|
+
write "app/relations/.keep", ""
|
149
|
+
|
150
|
+
ENV["DATABASE_URL"] = "postgres://127.0.0.0"
|
151
|
+
|
152
|
+
require "hanami/prepare"
|
153
|
+
|
154
|
+
expect { Hanami.app.prepare :db }.to raise_error(Hanami::ComponentLoadError) { |error|
|
155
|
+
expect(error.message).to include %(The "pg" gem is required)
|
156
|
+
}
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
134
160
|
it "allows the user to configure the provider" do
|
135
161
|
with_tmp_directory(Dir.mktmpdir) do
|
136
162
|
write "config/app.rb", <<~RUBY
|
@@ -154,11 +180,10 @@ RSpec.describe "DB", :app_integration do
|
|
154
180
|
|
155
181
|
write "config/providers/db.rb", <<~RUBY
|
156
182
|
Hanami.app.configure_provider :db do
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
config.database_url = "sqlite::memory"
|
183
|
+
# In this test, we're not setting an ENV["DATABASE_URL"], and instead configuring
|
184
|
+
# it via the provider source config, to prove that this works
|
185
|
+
config.gateway :default do |gw|
|
186
|
+
gw.database_url = "sqlite::memory"
|
162
187
|
end
|
163
188
|
end
|
164
189
|
RUBY
|