hanami 2.1.0 → 2.2.0.beta1
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 +30 -6
- data/FEATURES.md +1 -1
- data/README.md +7 -7
- data/hanami.gemspec +6 -6
- data/lib/hanami/app.rb +6 -2
- data/lib/hanami/config/actions.rb +1 -1
- data/lib/hanami/config/assets.rb +1 -1
- data/lib/hanami/config/db.rb +33 -0
- data/lib/hanami/config/logger.rb +2 -2
- data/lib/hanami/config.rb +37 -10
- data/lib/hanami/extensions/db/repo.rb +103 -0
- data/lib/hanami/extensions/view/context.rb +1 -1
- data/lib/hanami/extensions/view/part.rb +1 -1
- data/lib/hanami/extensions/view/slice_configured_helpers.rb +1 -1
- data/lib/hanami/extensions.rb +4 -0
- data/lib/hanami/helpers/assets_helper.rb +5 -5
- data/lib/hanami/helpers/form_helper/form_builder.rb +4 -6
- data/lib/hanami/middleware/public_errors_app.rb +2 -2
- data/lib/hanami/provider_registrar.rb +26 -0
- data/lib/hanami/providers/assets.rb +2 -20
- data/lib/hanami/providers/db/adapter.rb +68 -0
- data/lib/hanami/providers/db/adapters.rb +44 -0
- data/lib/hanami/providers/db/config.rb +66 -0
- data/lib/hanami/providers/db/sql_adapter.rb +80 -0
- data/lib/hanami/providers/db.rb +203 -0
- data/lib/hanami/providers/db_logging.rb +22 -0
- data/lib/hanami/providers/rack.rb +3 -3
- data/lib/hanami/providers/relations.rb +31 -0
- data/lib/hanami/providers/routes.rb +1 -13
- data/lib/hanami/rake_tasks.rb +9 -8
- data/lib/hanami/settings.rb +3 -3
- data/lib/hanami/slice.rb +90 -10
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +3 -3
- 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/db_inflector_spec.rb +57 -0
- data/spec/integration/db/db_slices_spec.rb +327 -0
- data/spec/integration/db/db_spec.rb +220 -0
- data/spec/integration/db/logging_spec.rb +238 -0
- data/spec/integration/db/provider_config_spec.rb +88 -0
- data/spec/integration/db/provider_spec.rb +35 -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/integration/view/config/template_spec.rb +1 -1
- data/spec/integration/view/context/request_spec.rb +1 -1
- 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 +33 -2
- data/spec/unit/hanami/providers/db/config/default_config_spec.rb +107 -0
- data/spec/unit/hanami/providers/db/config_spec.rb +206 -0
- data/spec/unit/hanami/slice_spec.rb +33 -1
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +62 -20
@@ -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,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "DB / Provider / Config", :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
|
+
describe "default config" do
|
14
|
+
it "provides default plugins and extensions" do
|
15
|
+
with_tmp_directory(Dir.mktmpdir) do
|
16
|
+
write "config/app.rb", <<~RUBY
|
17
|
+
require "hanami"
|
18
|
+
|
19
|
+
module TestApp
|
20
|
+
class App < Hanami::App
|
21
|
+
end
|
22
|
+
end
|
23
|
+
RUBY
|
24
|
+
|
25
|
+
write "config/db/.keep", ""
|
26
|
+
|
27
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
28
|
+
|
29
|
+
require "hanami/prepare"
|
30
|
+
|
31
|
+
Hanami.app.prepare :db
|
32
|
+
|
33
|
+
plugins = Hanami.app["db.config"].setup.plugins
|
34
|
+
expect(plugins).to match [
|
35
|
+
an_object_satisfying {
|
36
|
+
_1.name == :instrumentation && _1.type == :relation &&
|
37
|
+
_1.config.notifications == Hanami.app["notifications"]
|
38
|
+
},
|
39
|
+
an_object_satisfying { _1.name == :auto_restrictions && _1.type == :relation }
|
40
|
+
]
|
41
|
+
|
42
|
+
extensions = Hanami.app["db.gateway"].options[:extensions]
|
43
|
+
expect(extensions).to eq [:caller_logging, :error_sql, :sql_comments]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "evaluates plugin config blocks in the context of the provider" do
|
49
|
+
with_tmp_directory(Dir.mktmpdir) do
|
50
|
+
write "config/app.rb", <<~RUBY
|
51
|
+
require "hanami"
|
52
|
+
|
53
|
+
module TestApp
|
54
|
+
class App < Hanami::App
|
55
|
+
end
|
56
|
+
end
|
57
|
+
RUBY
|
58
|
+
|
59
|
+
write "config/providers/db.rb", <<~RUBY
|
60
|
+
Hanami.app.configure_provider :db do
|
61
|
+
config.adapter :sql do |a|
|
62
|
+
a.skip_defaults :plugins
|
63
|
+
|
64
|
+
a.plugin relations: :instrumentation do |plugin|
|
65
|
+
plugin.notifications = target["custom_notifications"]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
RUBY
|
70
|
+
|
71
|
+
write "app/custom_notifications.rb", <<~RUBY
|
72
|
+
module TestApp
|
73
|
+
class CustomNotifications
|
74
|
+
end
|
75
|
+
end
|
76
|
+
RUBY
|
77
|
+
|
78
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
79
|
+
|
80
|
+
require "hanami/prepare"
|
81
|
+
|
82
|
+
Hanami.app.prepare :db
|
83
|
+
|
84
|
+
plugin = Hanami.app["db.config"].setup.plugins.find { _1.name == :instrumentation }
|
85
|
+
expect(plugin.config.notifications).to be_an_instance_of TestApp::CustomNotifications
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "DB / Provider", :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 "is registered when only a config/db/ dir exists" 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 "config/db/.keep", ""
|
25
|
+
|
26
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
27
|
+
|
28
|
+
require "hanami/prepare"
|
29
|
+
|
30
|
+
Hanami.app.prepare :db
|
31
|
+
|
32
|
+
expect(Hanami.app["db.gateway"]).to be
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "DB / Repo", :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
|
+
specify "repos have a root inferred from their name, or can set their own" 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/repo.rb", <<~RUBY
|
25
|
+
module TestApp
|
26
|
+
class Repo < Hanami::DB::Repo
|
27
|
+
end
|
28
|
+
end
|
29
|
+
RUBY
|
30
|
+
|
31
|
+
write "app/relations/posts.rb", <<~RUBY
|
32
|
+
module TestApp
|
33
|
+
module Relations
|
34
|
+
class Posts < Hanami::DB::Relation
|
35
|
+
schema :posts, infer: true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
RUBY
|
40
|
+
|
41
|
+
write "app/repos/post_repo.rb", <<~RUBY
|
42
|
+
module TestApp
|
43
|
+
module Repos
|
44
|
+
class PostRepo < Repo
|
45
|
+
def get(id)
|
46
|
+
posts.by_pk(id).one!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
RUBY
|
52
|
+
|
53
|
+
write "app/repos/no_implicit_root_relation_repo.rb", <<~RUBY
|
54
|
+
module TestApp
|
55
|
+
module Repos
|
56
|
+
class NoImplicitRootRelationRepo < Repo
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
RUBY
|
61
|
+
|
62
|
+
write "app/repos/explicit_root_relation_repo.rb", <<~RUBY
|
63
|
+
module TestApp
|
64
|
+
module Repos
|
65
|
+
class ExplicitRootRelationRepo < Repo[:posts]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
RUBY
|
70
|
+
|
71
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
72
|
+
|
73
|
+
require "hanami/prepare"
|
74
|
+
|
75
|
+
Hanami.app.prepare :db
|
76
|
+
|
77
|
+
# Manually run a migration and add a test record
|
78
|
+
gateway = Hanami.app["db.gateway"]
|
79
|
+
migration = gateway.migration do
|
80
|
+
change do
|
81
|
+
# drop_table? :posts
|
82
|
+
create_table :posts do
|
83
|
+
primary_key :id
|
84
|
+
column :title, :text, null: false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
migration.apply(gateway, :up)
|
89
|
+
gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
|
90
|
+
|
91
|
+
# Repos use a matching root relation automatically
|
92
|
+
repo = Hanami.app["repos.post_repo"]
|
93
|
+
expect(repo.get(1).title).to eq "Together breakfast"
|
94
|
+
expect(repo.root).to eql Hanami.app["relations.posts"]
|
95
|
+
|
96
|
+
# Non-matching repos still work, just with no root relation
|
97
|
+
repo = Hanami.app["repos.no_implicit_root_relation_repo"]
|
98
|
+
expect(repo.root).to be nil
|
99
|
+
|
100
|
+
# Repos can provide an explicit root relation
|
101
|
+
repo = Hanami.app["repos.explicit_root_relation_repo"]
|
102
|
+
expect(repo.root).to eql Hanami.app["relations.posts"]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
specify "repos use relations and structs only from their own slice" do
|
107
|
+
with_tmp_directory(Dir.mktmpdir) do
|
108
|
+
write "config/app.rb", <<~RUBY
|
109
|
+
require "hanami"
|
110
|
+
|
111
|
+
module TestApp
|
112
|
+
class App < Hanami::App
|
113
|
+
end
|
114
|
+
end
|
115
|
+
RUBY
|
116
|
+
|
117
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
118
|
+
|
119
|
+
write "slices/admin/db/struct.rb", <<~RUBY
|
120
|
+
module Admin
|
121
|
+
module DB
|
122
|
+
class Struct < Hanami::DB::Struct
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
RUBY
|
127
|
+
|
128
|
+
write "slices/admin/relations/posts.rb", <<~RUBY
|
129
|
+
module Admin
|
130
|
+
module Relations
|
131
|
+
class Posts < Hanami::DB::Relation
|
132
|
+
schema :posts, infer: true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
RUBY
|
137
|
+
|
138
|
+
write "slices/admin/repo.rb", <<~RUBY
|
139
|
+
module Admin
|
140
|
+
class Repo < Hanami::DB::Repo
|
141
|
+
end
|
142
|
+
end
|
143
|
+
RUBY
|
144
|
+
|
145
|
+
write "slices/admin/repos/post_repo.rb", <<~RUBY
|
146
|
+
module Admin
|
147
|
+
module Repos
|
148
|
+
class PostRepo < Repo
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
RUBY
|
153
|
+
|
154
|
+
write "slices/admin/structs/post.rb", <<~RUBY
|
155
|
+
module Admin
|
156
|
+
module Structs
|
157
|
+
class Post < DB::Struct
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
RUBY
|
162
|
+
|
163
|
+
write "slices/main/relations/posts.rb", <<~RUBY
|
164
|
+
module Main
|
165
|
+
module Relations
|
166
|
+
class Posts < Hanami::DB::Relation
|
167
|
+
schema :posts, infer: true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
RUBY
|
172
|
+
|
173
|
+
write "slices/main/repo.rb", <<~RUBY
|
174
|
+
module Main
|
175
|
+
class Repo < Hanami::DB::Repo
|
176
|
+
end
|
177
|
+
end
|
178
|
+
RUBY
|
179
|
+
|
180
|
+
write "slices/main/repos/post_repo.rb", <<~RUBY
|
181
|
+
module Main
|
182
|
+
module Repos
|
183
|
+
class PostRepo < Repo
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
RUBY
|
188
|
+
|
189
|
+
require "hanami/prepare"
|
190
|
+
|
191
|
+
Admin::Slice.prepare :db
|
192
|
+
|
193
|
+
# Manually run a migration
|
194
|
+
gateway = Admin::Slice["db.gateway"]
|
195
|
+
migration = gateway.migration do
|
196
|
+
change do
|
197
|
+
# drop_table? :posts
|
198
|
+
create_table :posts do
|
199
|
+
primary_key :id
|
200
|
+
column :title, :text, null: false
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
migration.apply(gateway, :up)
|
205
|
+
gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
|
206
|
+
|
207
|
+
expect(Admin::Slice["repos.post_repo"].posts).to eql Admin::Slice["relations.posts"]
|
208
|
+
expect(Admin::Slice["repos.post_repo"].posts.by_pk(1).one!.class).to be < Admin::Structs::Post
|
209
|
+
|
210
|
+
expect(Main::Slice["repos.post_repo"].posts).to eql Main::Slice["relations.posts"]
|
211
|
+
# Slice struct namespace used even when no concrete struct classes are defined
|
212
|
+
expect(Main::Slice["repos.post_repo"].posts.by_pk(1).one!.class).to be < Main::Structs::Post
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe "DB / Slices / Importing from app", :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
|
+
specify "app DB components do not import into slices by default" 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
|
+
write "slices/admin/.keep", ""
|
35
|
+
|
36
|
+
require "hanami/prepare"
|
37
|
+
|
38
|
+
expect { Admin::Slice.start :db }.to raise_error Dry::System::ProviderNotFoundError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "importing app DB components into slices via config.db.import_from_parent = true" do
|
43
|
+
with_tmp_directory(Dir.mktmpdir) do
|
44
|
+
write "config/app.rb", <<~RUBY
|
45
|
+
require "hanami"
|
46
|
+
|
47
|
+
module TestApp
|
48
|
+
class App < Hanami::App
|
49
|
+
config.db.import_from_parent = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
RUBY
|
53
|
+
|
54
|
+
write "app/relations/posts.rb", <<~RUBY
|
55
|
+
module TestApp
|
56
|
+
module Relations
|
57
|
+
class Posts < Hanami::DB::Relation
|
58
|
+
schema :posts, infer: true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
RUBY
|
63
|
+
|
64
|
+
write "slices/admin/.keep", ""
|
65
|
+
|
66
|
+
ENV["DATABASE_URL"] = "sqlite::memory"
|
67
|
+
|
68
|
+
require "hanami/prepare"
|
69
|
+
|
70
|
+
Hanami.app.prepare :db
|
71
|
+
|
72
|
+
# Manually run a migration and add a test record
|
73
|
+
gateway = Hanami.app["db.gateway"]
|
74
|
+
migration = gateway.migration do
|
75
|
+
change do
|
76
|
+
# drop_table? :posts
|
77
|
+
create_table :posts do
|
78
|
+
primary_key :id
|
79
|
+
column :title, :text, null: false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
migration.apply(gateway, :up)
|
84
|
+
gateway.connection.execute("INSERT INTO posts (title) VALUES ('Together breakfast')")
|
85
|
+
|
86
|
+
Admin::Slice.start :db
|
87
|
+
|
88
|
+
expect(Admin::Slice["db.rom"]).to be(Hanami.app["db.rom"])
|
89
|
+
expect(Admin::Slice["relations.posts"]).to be(Hanami.app["relations.posts"])
|
90
|
+
|
91
|
+
expect(Admin::Slice["relations.posts"].to_a).to eq [{id: 1, title: "Together breakfast"}]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
specify "disabling import of the DB components within a specific slice" do
|
96
|
+
with_tmp_directory(Dir.mktmpdir) do
|
97
|
+
write "config/app.rb", <<~RUBY
|
98
|
+
require "hanami"
|
99
|
+
|
100
|
+
module TestApp
|
101
|
+
class App < Hanami::App
|
102
|
+
config.db.import_from_parent = true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
RUBY
|
106
|
+
|
107
|
+
write "config/slices/admin.rb", <<~RUBY
|
108
|
+
module Admin
|
109
|
+
class Slice < Hanami::Slice
|
110
|
+
config.db.import_from_parent = false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
RUBY
|
114
|
+
|
115
|
+
write "app/relations/posts.rb", <<~RUBY
|
116
|
+
module TestApp
|
117
|
+
module Relations
|
118
|
+
class Posts < Hanami::DB::Relation
|
119
|
+
schema :posts, infer: true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
RUBY
|
124
|
+
|
125
|
+
require "hanami/prepare"
|
126
|
+
|
127
|
+
expect { Admin::Slice.start :db }.to raise_error Dry::System::ProviderNotFoundError
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|