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.
@@ -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