hanami 2.2.0.beta1 → 2.2.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|