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,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,238 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "DB / Logging", :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 "logs SQL queries" do
|
14
|
+
with_tmp_directory(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 "app/relations/posts.rb", <<~RUBY
|
25
|
+
module TestApp
|
26
|
+
module Relations
|
27
|
+
class Posts < Hanami::DB::Relation
|
28
|
+
schema :posts, infer: true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
|
34
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
35
|
+
|
36
|
+
require "hanami/setup"
|
37
|
+
|
38
|
+
logger_stream = StringIO.new
|
39
|
+
Hanami.app.config.logger.stream = logger_stream
|
40
|
+
|
41
|
+
require "hanami/prepare"
|
42
|
+
|
43
|
+
Hanami.app.prepare :db
|
44
|
+
|
45
|
+
# Manually run a migration and add a test record
|
46
|
+
gateway = Hanami.app["db.gateway"]
|
47
|
+
migration = gateway.migration do
|
48
|
+
change do
|
49
|
+
create_table :posts do
|
50
|
+
primary_key :id
|
51
|
+
column :title, :text, null: false
|
52
|
+
end
|
53
|
+
|
54
|
+
create_table :authors do
|
55
|
+
primary_key :id
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
migration.apply(gateway, :up)
|
60
|
+
gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
|
61
|
+
|
62
|
+
relation = Hanami.app["relations.posts"]
|
63
|
+
expect(relation.select(:title).to_a).to eq [{:title=>"Together breakfast"}]
|
64
|
+
|
65
|
+
logger_stream.rewind
|
66
|
+
log_lines = logger_stream.read.split("\n")
|
67
|
+
|
68
|
+
expect(log_lines.length).to eq 1
|
69
|
+
expect(log_lines.first).to match /Loaded :sqlite in \d+ms SELECT `posts`.`title` FROM `posts` ORDER BY `posts`.`id`/
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "slices sharing app db config" do
|
74
|
+
it "logs SQL queries" do
|
75
|
+
with_tmp_directory(Dir.mktmpdir) do
|
76
|
+
write "config/app.rb", <<~RUBY
|
77
|
+
require "hanami"
|
78
|
+
|
79
|
+
module TestApp
|
80
|
+
class App < Hanami::App
|
81
|
+
end
|
82
|
+
end
|
83
|
+
RUBY
|
84
|
+
|
85
|
+
write "config/providers/db.rb", <<~RUBY
|
86
|
+
Hanami.app.configure_provider :db do
|
87
|
+
end
|
88
|
+
RUBY
|
89
|
+
|
90
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
91
|
+
|
92
|
+
write "slices/admin/relations/posts.rb", <<~RUBY
|
93
|
+
module Admin
|
94
|
+
module Relations
|
95
|
+
class Posts < Hanami::DB::Relation
|
96
|
+
schema :posts, infer: true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
RUBY
|
101
|
+
|
102
|
+
write "slices/main/relations/posts.rb", <<~RUBY
|
103
|
+
module Main
|
104
|
+
module Relations
|
105
|
+
class Posts < Hanami::DB::Relation
|
106
|
+
schema :posts, infer: true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
RUBY
|
111
|
+
|
112
|
+
require "hanami/setup"
|
113
|
+
|
114
|
+
logger_stream = StringIO.new
|
115
|
+
Hanami.app.config.logger.stream = logger_stream
|
116
|
+
|
117
|
+
require "hanami/prepare"
|
118
|
+
|
119
|
+
Admin::Slice.prepare :db
|
120
|
+
|
121
|
+
# Manually run a migration
|
122
|
+
gateway = Admin::Slice["db.gateway"]
|
123
|
+
migration = gateway.migration do
|
124
|
+
change do
|
125
|
+
create_table :posts do
|
126
|
+
primary_key :id
|
127
|
+
column :title, :text, null: false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
migration.apply(gateway, :up)
|
132
|
+
gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
|
133
|
+
|
134
|
+
Hanami.app.boot
|
135
|
+
|
136
|
+
# Booting the app will have the ROM schemas infer themself via some `PRAGMA` queries to the
|
137
|
+
# database, which themselves will emit logs. Clear those logs, since we want to focus on
|
138
|
+
# individual query logging in this test.
|
139
|
+
logger_stream.truncate(0)
|
140
|
+
|
141
|
+
relation = Admin::Slice["relations.posts"]
|
142
|
+
relation.select(:title).to_a
|
143
|
+
|
144
|
+
log_lines = logger_stream.string.split("\n")
|
145
|
+
expect(log_lines.length).to eq 1
|
146
|
+
expect(log_lines.last).to match /Loaded :sqlite in \d+ms SELECT `posts`.`title` FROM `posts` ORDER BY `posts`.`id`/
|
147
|
+
|
148
|
+
relation = Main::Slice["relations.posts"]
|
149
|
+
relation.select(:id).to_a
|
150
|
+
|
151
|
+
log_lines = logger_stream.string.split("\n")
|
152
|
+
expect(log_lines.length).to eq 2
|
153
|
+
expect(log_lines.last).to match /Loaded :sqlite in \d+ms SELECT `posts`.`id` FROM `posts` ORDER BY `posts`.`id`/
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "slices with independent db config" do
|
159
|
+
# This is the same test as above, except without the config/providers/db.rb file.
|
160
|
+
it "logs SQL queries" do
|
161
|
+
with_tmp_directory(Dir.mktmpdir) do
|
162
|
+
write "config/app.rb", <<~RUBY
|
163
|
+
require "hanami"
|
164
|
+
|
165
|
+
module TestApp
|
166
|
+
class App < Hanami::App
|
167
|
+
end
|
168
|
+
end
|
169
|
+
RUBY
|
170
|
+
|
171
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
172
|
+
|
173
|
+
write "slices/admin/relations/posts.rb", <<~RUBY
|
174
|
+
module Admin
|
175
|
+
module Relations
|
176
|
+
class Posts < Hanami::DB::Relation
|
177
|
+
schema :posts, infer: true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
RUBY
|
182
|
+
|
183
|
+
write "slices/main/relations/posts.rb", <<~RUBY
|
184
|
+
module Main
|
185
|
+
module Relations
|
186
|
+
class Posts < Hanami::DB::Relation
|
187
|
+
schema :posts, infer: true
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
RUBY
|
192
|
+
|
193
|
+
require "hanami/setup"
|
194
|
+
|
195
|
+
logger_stream = StringIO.new
|
196
|
+
Hanami.app.config.logger.stream = logger_stream
|
197
|
+
|
198
|
+
require "hanami/prepare"
|
199
|
+
|
200
|
+
Admin::Slice.prepare :db
|
201
|
+
|
202
|
+
# Manually run a migration
|
203
|
+
gateway = Admin::Slice["db.gateway"]
|
204
|
+
migration = gateway.migration do
|
205
|
+
change do
|
206
|
+
create_table :posts do
|
207
|
+
primary_key :id
|
208
|
+
column :title, :text, null: false
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
migration.apply(gateway, :up)
|
213
|
+
gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
|
214
|
+
|
215
|
+
Hanami.app.boot
|
216
|
+
|
217
|
+
# Booting the app will have the ROM schemas infer themself via some `PRAGMA` queries to the
|
218
|
+
# database, which themselves will emit logs. Clear those logs, since we want to focus on
|
219
|
+
# individual query logging in this test.
|
220
|
+
logger_stream.truncate(0)
|
221
|
+
|
222
|
+
relation = Admin::Slice["relations.posts"]
|
223
|
+
relation.select(:title).to_a
|
224
|
+
|
225
|
+
log_lines = logger_stream.string.split("\n")
|
226
|
+
expect(log_lines.length).to eq 1
|
227
|
+
expect(log_lines.last).to match /Loaded :sqlite in \d+ms SELECT `posts`.`title` FROM `posts` ORDER BY `posts`.`id`/
|
228
|
+
|
229
|
+
relation = Main::Slice["relations.posts"]
|
230
|
+
relation.select(:id).to_a
|
231
|
+
|
232
|
+
log_lines = logger_stream.string.split("\n")
|
233
|
+
expect(log_lines.length).to eq 2
|
234
|
+
expect(log_lines.last).to match /Loaded :sqlite in \d+ms SELECT `posts`.`id` FROM `posts` ORDER BY `posts`.`id`/
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
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
|