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.
@@ -0,0 +1,320 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "DB / Gateways", :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 "configures gateways by detecting ENV vars" 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
+ end
21
+ end
22
+ RUBY
23
+
24
+ write "db/.keep", ""
25
+ write "app/relations/.keep", ""
26
+ write "slices/admin/relations/.keep", ""
27
+
28
+ ENV["DATABASE_URL"] = "sqlite://db/default.sqlite3"
29
+ ENV["DATABASE_URL__EXTRA"] = "sqlite://db/extra.sqlite3"
30
+ ENV["ADMIN__DATABASE_URL__DEFAULT"] = "sqlite://db/admin.sqlite3"
31
+ ENV["ADMIN__DATABASE_URL__SPECIAL"] = "sqlite://db/admin_special.sqlite3"
32
+
33
+ require "hanami/prepare"
34
+
35
+ expect(Hanami.app["db.rom"].gateways[:default]).to be
36
+ expect(Hanami.app["db.rom"].gateways[:extra]).to be
37
+ expect(Hanami.app["db.gateway"]).to be Hanami.app["db.rom"].gateways[:default]
38
+ expect(Hanami.app["db.gateways.default"]).to be Hanami.app["db.rom"].gateways[:default]
39
+ expect(Hanami.app["db.gateways.extra"]).to be Hanami.app["db.rom"].gateways[:extra]
40
+
41
+ expect(Admin::Slice["db.rom"].gateways[:default]).to be
42
+ expect(Admin::Slice["db.rom"].gateways[:special]).to be
43
+ expect(Admin::Slice["db.gateway"]).to be Admin::Slice["db.rom"].gateways[:default]
44
+ expect(Admin::Slice["db.gateways.default"]).to be Admin::Slice["db.rom"].gateways[:default]
45
+ expect(Admin::Slice["db.gateways.special"]).to be Admin::Slice["db.rom"].gateways[:special]
46
+ end
47
+ end
48
+
49
+ it "configures gateways from explicit config in the provider" do
50
+ with_tmp_directory(@dir = Dir.mktmpdir) do
51
+ write "config/app.rb", <<~RUBY
52
+ require "hanami"
53
+
54
+ module TestApp
55
+ class App < Hanami::App
56
+ end
57
+ end
58
+ RUBY
59
+
60
+ write "db/.keep", ""
61
+
62
+ write "config/providers/db.rb", <<~RUBY
63
+ Hanami.app.configure_provider :db do
64
+ config.gateway :default do |gw|
65
+ gw.database_url = "sqlite://db/default.sqlite3"
66
+ end
67
+
68
+ config.gateway :extra do |gw|
69
+ gw.database_url = "sqlite://db/extra.sqlite3"
70
+ end
71
+ end
72
+ RUBY
73
+
74
+ require "hanami/prepare"
75
+
76
+ expect(Hanami.app["db.rom"].gateways[:default]).to be
77
+ expect(Hanami.app["db.rom"].gateways[:extra]).to be
78
+ expect(Hanami.app["db.gateway"]).to be Hanami.app["db.rom"].gateways[:default]
79
+ expect(Hanami.app["db.gateways.default"]).to be Hanami.app["db.rom"].gateways[:default]
80
+ expect(Hanami.app["db.gateways.extra"]).to be Hanami.app["db.rom"].gateways[:extra]
81
+ end
82
+ end
83
+
84
+
85
+
86
+ it "exposes all database URLs as #database_urls on the provider source (for CLI commands)" do
87
+ with_tmp_directory(@dir = Dir.mktmpdir) do
88
+ write "config/app.rb", <<~RUBY
89
+ require "hanami"
90
+
91
+ module TestApp
92
+ class App < Hanami::App
93
+ end
94
+ end
95
+ RUBY
96
+
97
+ write "config/providers/db.rb", <<~RUBY
98
+ Hanami.app.configure_provider :db do
99
+ config.gateway :special do |gw|
100
+ gw.database_url = "sqlite://db/special.sqlite3"
101
+ end
102
+ end
103
+ RUBY
104
+
105
+ ENV["DATABASE_URL"] = "sqlite://db/default.sqlite3"
106
+ ENV["DATABASE_URL__EXTRA"] = "sqlite://db/extra.sqlite3"
107
+
108
+ require "hanami/prepare"
109
+
110
+ database_urls = Hanami.app.container.providers[:db].source.finalize_config.database_urls
111
+
112
+ expect(database_urls).to eq(
113
+ default: "sqlite://db/default.sqlite3",
114
+ extra: "sqlite://db/extra.sqlite3",
115
+ special: "sqlite://db/special.sqlite3"
116
+ )
117
+ end
118
+ end
119
+
120
+ it "applies extensions from the default adapter to explicitly configured gateway adapters" do
121
+ with_tmp_directory(@dir = Dir.mktmpdir) do
122
+ write "config/app.rb", <<~RUBY
123
+ require "hanami"
124
+
125
+ module TestApp
126
+ class App < Hanami::App
127
+ end
128
+ end
129
+ RUBY
130
+
131
+ write "config/providers/db.rb", <<~RUBY
132
+ Hanami.app.configure_provider :db do
133
+ config.adapter :sql do |a|
134
+ a.extension :is_distinct_from
135
+ end
136
+
137
+ config.gateway :default do |gw|
138
+ gw.adapter :sql do |a|
139
+ a.extension :exclude_or_null
140
+ end
141
+ end
142
+ end
143
+ RUBY
144
+
145
+ ENV["DATABASE_URL"] = "sqlite::memory"
146
+ ENV["DATABASE_URL__SPECIAL"] = "sqlite::memory"
147
+
148
+ require "hanami/prepare"
149
+
150
+ expect(Hanami.app["db.gateways.default"].options[:extensions])
151
+ .to eq [:exclude_or_null, :is_distinct_from, :caller_logging, :error_sql, :sql_comments]
152
+
153
+ expect(Hanami.app["db.gateways.special"].options[:extensions])
154
+ .to eq [:is_distinct_from, :caller_logging, :error_sql, :sql_comments]
155
+ end
156
+ end
157
+
158
+ it "combines ROM plugins from the default adapter and all gateways" do
159
+ with_tmp_directory(@dir = Dir.mktmpdir) do
160
+ write "config/app.rb", <<~RUBY
161
+ require "hanami"
162
+
163
+ module TestApp
164
+ class App < Hanami::App
165
+ end
166
+ end
167
+ RUBY
168
+
169
+ write "config/providers/db.rb", <<~RUBY
170
+ Hanami.app.configure_provider :db do
171
+ config.adapter :sql do |a|
172
+ a.plugin command: :associates
173
+ end
174
+
175
+ config.gateway :default do |gw|
176
+ gw.database_url = "sqlite::memory"
177
+ gw.adapter :sql do |a|
178
+ a.plugin relation: :nullify
179
+ end
180
+ end
181
+
182
+ config.gateway :special do |gw|
183
+ gw.adapter :sql do |a|
184
+ a.plugin relation: :pagination
185
+ end
186
+ end
187
+ end
188
+ RUBY
189
+
190
+ ENV["DATABASE_URL"] = "sqlite::memory"
191
+ ENV["DATABASE_URL__SPECIAL"] = "sqlite::memory"
192
+
193
+ require "hanami/prepare"
194
+
195
+ expect(Hanami.app["db.config"].setup.plugins.length).to eq 5
196
+ expect(Hanami.app["db.config"].setup.plugins).to include(
197
+ satisfying { |plugin| plugin.type == :command && plugin.name == :associates },
198
+ satisfying { |plugin| plugin.type == :relation && plugin.name == :nullify },
199
+ satisfying { |plugin| plugin.type == :relation && plugin.name == :pagination },
200
+ satisfying { |plugin| plugin.type == :relation && plugin.name == :auto_restrictions },
201
+ satisfying { |plugin| plugin.type == :relation && plugin.name == :instrumentation }
202
+ )
203
+ end
204
+ end
205
+
206
+ it "configures gateway adapters for their specific database types" do
207
+ with_tmp_directory(@dir = Dir.mktmpdir) do
208
+ write "config/app.rb", <<~RUBY
209
+ require "hanami"
210
+
211
+ module TestApp
212
+ class App < Hanami::App
213
+ end
214
+ end
215
+ RUBY
216
+
217
+ write "config/providers/db.rb", <<~RUBY
218
+ Hanami.app.configure_provider :db do
219
+ config.gateway :default do |gw|
220
+ gw.database_url = "sqlite::memory"
221
+ end
222
+ end
223
+ RUBY
224
+
225
+ ENV["DATABASE_URL"] = "sqlite::memory"
226
+ ENV["DATABASE_URL__SPECIAL"] = "postgres://localhost/database"
227
+
228
+ require "hanami/prepare"
229
+
230
+ # Get the provider source and finalize config, because the tests here aren't set up to handle
231
+ # connections to a running postgres database
232
+ allow(Hanami).to receive(:bundled?).and_call_original
233
+ allow(Hanami).to receive(:bundled?).with("pg").and_return true
234
+ provider_source = Hanami.app.container.providers[:db].source
235
+ provider_source.finalize_config
236
+
237
+ expect(provider_source.config.gateways[:default].config.adapter.extensions)
238
+ .to eq [:caller_logging, :error_sql, :sql_comments]
239
+
240
+ expect(provider_source.config.gateways[:special].config.adapter.extensions)
241
+ .to eq [
242
+ :caller_logging, :error_sql, :sql_comments,
243
+ :pg_array, :pg_enum, :pg_json, :pg_range
244
+ ]
245
+ end
246
+ end
247
+
248
+ it "makes the gateways available to relations" do
249
+ with_tmp_directory(@dir = Dir.mktmpdir) do
250
+ write "config/app.rb", <<~RUBY
251
+ require "hanami"
252
+
253
+ module TestApp
254
+ class App < Hanami::App
255
+ config.logger.stream = File::NULL
256
+ end
257
+ end
258
+ RUBY
259
+
260
+ write "app/relations/posts.rb", <<~RUBY
261
+ module TestApp
262
+ module Relations
263
+ class Posts < Hanami::DB::Relation
264
+ schema :posts, infer: true
265
+ end
266
+ end
267
+ end
268
+ RUBY
269
+
270
+ write "app/relations/users.rb", <<~RUBY
271
+ module TestApp
272
+ module Relations
273
+ class Users < Hanami::DB::Relation
274
+ gateway :extra
275
+ schema :users, infer: true
276
+ end
277
+ end
278
+ end
279
+ RUBY
280
+
281
+ write "db/.keep", ""
282
+ ENV["DATABASE_URL"] = "sqlite://db/default.sqlite3"
283
+ ENV["DATABASE_URL__EXTRA"] = "sqlite://db/extra.sqlite3"
284
+
285
+ require "hanami/prepare"
286
+
287
+ Hanami.app.prepare :db
288
+
289
+ # Manually run a migration and add a test record
290
+ default_gateway = Hanami.app["db.gateways.default"]
291
+ migration = default_gateway.migration do
292
+ change do
293
+ create_table :posts do
294
+ primary_key :id
295
+ column :title, :text, null: false
296
+ end
297
+ end
298
+ end
299
+ migration.apply(default_gateway, :up)
300
+ default_gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
301
+
302
+ extra_gateway = Hanami.app["db.gateways.extra"]
303
+ migration = extra_gateway.migration do
304
+ change do
305
+ create_table :users do
306
+ primary_key :id
307
+ column :name, :text, null: false
308
+ end
309
+ end
310
+ end
311
+ migration.apply(extra_gateway, :up)
312
+ extra_gateway.connection.execute("INSERT INTO users (name) VALUES ('Jane Doe')")
313
+
314
+ Hanami.app.boot
315
+
316
+ expect(Hanami.app["relations.posts"].to_a).to eq [{id: 1, title: "Together breakfast"}]
317
+ expect(Hanami.app["relations.users"].to_a).to eq [{id: 1, name: "Jane Doe"}]
318
+ end
319
+ end
320
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "DB / Mappers", :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 mappers" 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/mappers/nested/default_title_mapper.rb", <<~RUBY
36
+ require "rom/transformer"
37
+
38
+ module TestApp
39
+ module DB
40
+ module Mappers
41
+ module Nested
42
+ class DefaultTitleMapper < ROM::Transformer
43
+ relation :posts
44
+ register_as :default_title_mapper
45
+
46
+ map do
47
+ set_default_title
48
+ end
49
+
50
+ def set_default_title(row)
51
+ row[:title] ||= "Default title from mapper"
52
+ row
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ RUBY
60
+
61
+ ENV["DATABASE_URL"] = "sqlite::memory"
62
+
63
+ require "hanami/prepare"
64
+
65
+ Hanami.app.prepare :db
66
+
67
+ # Manually run a migration and add a test record
68
+ gateway = TestApp::App["db.gateway"]
69
+ migration = gateway.migration do
70
+ change do
71
+ create_table :posts do
72
+ primary_key :id
73
+ column :title, :text
74
+ end
75
+ end
76
+ end
77
+ migration.apply(gateway, :up)
78
+ gateway.connection.execute("INSERT INTO posts (title) VALUES (NULL)")
79
+
80
+ post = TestApp::App["relations.posts"].map_with(:default_title_mapper).to_a[0]
81
+ expect(post[:title]).to eq "Default title from mapper"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "DB / Relations", :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 nested relations" 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/nested/posts.rb", <<~RUBY
26
+ module TestApp
27
+ module Relations
28
+ module Nested
29
+ class Posts < Hanami::DB::Relation
30
+ schema :posts, infer: true
31
+ end
32
+ end
33
+ end
34
+ end
35
+ RUBY
36
+
37
+ ENV["DATABASE_URL"] = "sqlite::memory"
38
+
39
+ require "hanami/prepare"
40
+
41
+ Hanami.app.prepare :db
42
+
43
+ # Manually run a migration and add a test record
44
+ gateway = TestApp::App["db.gateway"]
45
+ migration = gateway.migration do
46
+ change do
47
+ create_table :posts do
48
+ primary_key :id
49
+ column :title, :text
50
+ end
51
+ end
52
+ end
53
+ migration.apply(gateway, :up)
54
+ gateway.connection.execute("INSERT INTO posts (title) VALUES ('Hi from nested relation')")
55
+
56
+ post = TestApp::App["relations.posts"].to_a[0]
57
+ expect(post[:title]).to eq "Hi from nested relation"
58
+ end
59
+ end
60
+ end
@@ -2659,7 +2659,7 @@ RSpec.describe Hanami::Helpers::FormHelper do
2659
2659
  f.select "book.store", option_values, options: {prompt: "Select a store"}
2660
2660
  end
2661
2661
 
2662
- expect(html).to include %(<select name="book[store]" id="book-store"><option disabled="disabled">Select a store</option><option value="it">Italy</option><option value="us">United States</option></select>)
2662
+ expect(html).to include %(<select name="book[store]" id="book-store"><option>Select a store</option><option value="it">Italy</option><option value="us">United States</option></select>)
2663
2663
  end
2664
2664
 
2665
2665
  it "allows blank string" do
@@ -2667,7 +2667,7 @@ RSpec.describe Hanami::Helpers::FormHelper do
2667
2667
  f.select "book.store", option_values, options: {prompt: ""}
2668
2668
  end
2669
2669
 
2670
- expect(html).to include %(<select name="book[store]" id="book-store"><option disabled="disabled"></option><option value="it">Italy</option><option value="us">United States</option></select>)
2670
+ expect(html).to include %(<select name="book[store]" id="book-store"><option></option><option value="it">Italy</option><option value="us">United States</option></select>)
2671
2671
  end
2672
2672
 
2673
2673
  context "with values" do
@@ -2679,7 +2679,7 @@ RSpec.describe Hanami::Helpers::FormHelper do
2679
2679
  f.select "book.store", option_values, options: {prompt: "Select a store"}
2680
2680
  end
2681
2681
 
2682
- expect(html).to include %(<select name="book[store]" id="book-store"><option disabled="disabled">Select a store</option><option value="it" selected="selected">Italy</option><option value="us">United States</option></select>)
2682
+ expect(html).to include %(<select name="book[store]" id="book-store"><option>Select a store</option><option value="it" selected="selected">Italy</option><option value="us">United States</option></select>)
2683
2683
  end
2684
2684
  end
2685
2685
 
@@ -2693,7 +2693,7 @@ RSpec.describe Hanami::Helpers::FormHelper do
2693
2693
  f.select "book.store", option_values, options: {prompt: "Select a store"}
2694
2694
  end
2695
2695
 
2696
- expect(html).to include %(<select name="book[store]" id="book-store"><option disabled="disabled">Select a store</option><option value="it" selected="selected">Italy</option><option value="us">United States</option></select>)
2696
+ expect(html).to include %(<select name="book[store]" id="book-store"><option>Select a store</option><option value="it" selected="selected">Italy</option><option value="us">United States</option></select>)
2697
2697
  end
2698
2698
  end
2699
2699
 
@@ -7,6 +7,7 @@ RSpec.describe "Hanami::Providers::DB / Config / Default config", :app_integrati
7
7
  subject(:config) { provider.source.config }
8
8
 
9
9
  let(:provider) {
10
+ Hanami.app.prepare
10
11
  Hanami.app.configure_provider(:db)
11
12
  Hanami.app.container.providers[:db]
12
13
  }
@@ -18,14 +19,6 @@ RSpec.describe "Hanami::Providers::DB / Config / Default config", :app_integrati
18
19
  end
19
20
  end
20
21
 
21
- specify "database_url = nil" do
22
- expect(config.database_url).to be nil
23
- end
24
-
25
- specify "adapter = :sql" do
26
- expect(config.adapter).to eq :sql
27
- end
28
-
29
22
  specify %(relations_path = "relations") do
30
23
  expect(config)
31
24
  end
@@ -7,6 +7,7 @@ RSpec.describe "Hanami::Providers::DB.config", :app_integration do
7
7
  subject(:config) { provider.source.config }
8
8
 
9
9
  let(:provider) {
10
+ Hanami.app.prepare
10
11
  Hanami.app.configure_provider(:db)
11
12
  Hanami.app.container.providers[:db]
12
13
  }
@@ -18,14 +19,6 @@ RSpec.describe "Hanami::Providers::DB.config", :app_integration do
18
19
  end
19
20
  end
20
21
 
21
- describe "#adapter_name" do
22
- it "aliases #adapter" do
23
- expect { config.adapter = :yaml }
24
- .to change { config.adapter_name }
25
- .to :yaml
26
- end
27
- end
28
-
29
22
  describe "#adapter" do
30
23
  it "adds an adapter" do
31
24
  expect { config.adapter(:yaml) }
@@ -158,49 +151,6 @@ RSpec.describe "Hanami::Providers::DB.config", :app_integration do
158
151
  .and change { adapter.extensions }.to([])
159
152
  end
160
153
  end
161
-
162
- # TODO clear
163
- end
164
- end
165
-
166
- describe "#gateway_cache_keys" do
167
- it "returns the cache keys from the currently configured adapter" do
168
- config.adapter(:sql) { |a| a.clear; a.extension :foo }
169
- config.adapter = :sql
170
-
171
- expect(config.gateway_cache_keys).to eq(config.adapter(:sql).gateway_cache_keys)
172
- end
173
- end
174
-
175
- describe "#gateway_options" do
176
- it "returns the options from the currently configured adapter" do
177
- config.adapter(:sql) { |a| a.clear; a.extension :foo }
178
- config.adapter = :sql
179
-
180
- expect(config.gateway_options).to eq(config.adapter(:sql).gateway_options)
181
- end
182
- end
183
-
184
- describe "#each_plugin" do
185
- before do
186
- config.any_adapter { |a| a.plugin relations: :any_foo }
187
- config.adapter(:yaml) { |a| a.plugin relations: :yaml_foo }
188
- config.adapter = :yaml
189
- end
190
-
191
- it "yields the plugins specified for any adapter as well as the currently configured adapter" do
192
- expect { |b| config.each_plugin(&b) }
193
- .to yield_successive_args(
194
- [{relations: :any_foo}, nil],
195
- [{relations: :yaml_foo}, nil]
196
- )
197
- end
198
-
199
- it "returns the plugins as an enumerator if no block is given" do
200
- expect(config.each_plugin.to_a).to eq [
201
- [{relations: :any_foo}, nil],
202
- [{relations: :yaml_foo}, nil]
203
- ]
204
154
  end
205
155
  end
206
156
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  RSpec.describe "Hanami::VERSION" do
4
4
  it "returns current version" do
5
- expect(Hanami::VERSION).to eq("2.2.0.beta1")
5
+ expect(Hanami::VERSION).to eq("2.2.0.beta2")
6
6
  end
7
7
  end