Skip to content

Commit c1bc7ee

Browse files
committed
Refactoring Database generators
Extract all the DB information (gems, dockerfile packages, devcontainer etc.) into an object. This let's us remove the growing number of case statements in this code.
1 parent 5b91084 commit c1bc7ee

File tree

8 files changed

+317
-214
lines changed

8 files changed

+317
-214
lines changed

railties/lib/rails/generators/app_base.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
module Rails
1313
module Generators
1414
class AppBase < Base # :nodoc:
15-
include Database
1615
include Devcontainer
1716
include AppName
1817

@@ -40,7 +39,7 @@ def self.add_shared_options_for(name)
4039
desc: "Path to some #{name} template (can be a filesystem path or URL)"
4140

4241
class_option :database, type: :string, aliases: "-d", default: "sqlite3",
43-
enum: DATABASES,
42+
enum: Database::DATABASES,
4443
desc: "Preconfigure for selected database"
4544

4645
class_option :skip_git, type: :boolean, aliases: "-G", default: nil,
@@ -279,7 +278,7 @@ def set_default_accessors! # :doc:
279278
def database_gemfile_entry # :doc:
280279
return if options[:skip_active_record]
281280

282-
gem_name, gem_version = gem_for_database
281+
gem_name, gem_version = database.gem
283282
GemfileEntry.version gem_name, gem_version,
284283
"Use #{options[:database]} as the database for Active Record"
285284
end
@@ -574,7 +573,7 @@ def dockerfile_base_packages
574573
packages = ["curl"]
575574

576575
# ActiveRecord databases
577-
packages << base_package_for_database unless skip_active_record?
576+
packages << database.base_package unless skip_active_record?
578577

579578
# ActiveStorage preview support
580579
packages << "libvips" unless skip_active_storage?
@@ -590,7 +589,7 @@ def dockerfile_build_packages
590589
packages = %w(build-essential git pkg-config)
591590

592591
# add database support
593-
packages << build_package_for_database unless skip_active_record?
592+
packages << database.build_package unless skip_active_record?
594593

595594
packages << "unzip" if using_bun?
596595

@@ -772,6 +771,10 @@ def dockerfile_chown_directories
772771

773772
directories.sort
774773
end
774+
775+
def database
776+
@database ||= Database.build(options[:database])
777+
end
775778
end
776779
end
777780
end

railties/lib/rails/generators/database.rb

Lines changed: 262 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,84 @@
22

33
module Rails
44
module Generators
5-
module Database # :nodoc:
5+
class Database
66
DATABASES = %w( mysql trilogy postgresql sqlite3 )
77

8-
def gem_for_database(database = options[:database])
9-
case database
10-
when "mysql" then ["mysql2", ["~> 0.5"]]
11-
when "trilogy" then ["trilogy", ["~> 2.7"]]
12-
when "postgresql" then ["pg", ["~> 1.1"]]
13-
when "sqlite3" then ["sqlite3", [">= 1.4"]]
14-
else [database, nil]
8+
class << self
9+
def build(database_name)
10+
case database_name
11+
when "mysql" then MySQL.new
12+
when "postgresql" then PostgreSQL.new
13+
when "trilogy" then MariaDB.new
14+
when "sqlite3" then SQLite3.new
15+
else Null.new
16+
end
1517
end
16-
end
1718

18-
def docker_for_database_base(database = options[:database])
19-
case database
20-
when "mysql" then "curl default-mysql-client libvips"
21-
when "trilogy" then "curl libvips"
22-
when "postgresql" then "curl libvips postgresql-client"
23-
when "sqlite3" then "curl libsqlite3-0 libvips"
24-
else nil
19+
def all
20+
@all ||= [
21+
MySQL.new,
22+
PostgreSQL.new,
23+
MariaDB.new,
24+
SQLite3.new,
25+
]
2526
end
2627
end
2728

28-
def docker_for_database_build(database = options[:database])
29-
case database
30-
when "mysql" then "build-essential default-libmysqlclient-dev git"
31-
when "trilogy" then "build-essential git"
32-
when "postgresql" then "build-essential git libpq-dev"
33-
when "sqlite3" then "build-essential git"
34-
else nil
35-
end
29+
def name
30+
raise NotImplementedError
3631
end
3732

38-
def base_package_for_database(database = options[:database])
39-
case database
40-
when "mysql" then "default-mysql-client"
41-
when "postgresql" then "postgresql-client"
42-
when "sqlite3" then "libsqlite3-0"
43-
else nil
44-
end
33+
def service
34+
raise NotImplementedError
4535
end
4636

47-
def build_package_for_database(database = options[:database])
48-
case database
49-
when "mysql" then "default-libmysqlclient-dev"
50-
when "postgresql" then "libpq-dev"
51-
else nil
52-
end
37+
def port
38+
raise NotImplementedError
39+
end
40+
41+
def feature_name
42+
raise NotImplementedError
5343
end
5444

55-
private
56-
def mysql_socket
57-
@mysql_socket ||= [
45+
def gem
46+
raise NotImplementedError
47+
end
48+
49+
def docker_base
50+
raise NotImplementedError
51+
end
52+
53+
def docker_build
54+
raise NotImplementedError
55+
end
56+
57+
def base_package
58+
raise NotImplementedError
59+
end
60+
61+
def build_package
62+
raise NotImplementedError
63+
end
64+
65+
def socket; end
66+
def host; end
67+
68+
def feature
69+
return unless feature_name
70+
71+
{ feature_name => {} }
72+
end
73+
74+
def volume
75+
return unless service
76+
77+
"#{name}-data"
78+
end
79+
80+
module MySqlSocket
81+
def socket
82+
@socket ||= [
5883
"/tmp/mysql.sock", # default
5984
"/var/run/mysqld/mysqld.sock", # debian/gentoo
6085
"/var/tmp/mysql.sock", # freebsd
@@ -67,13 +92,204 @@ def mysql_socket
6792
].find { |f| File.exist?(f) } unless Gem.win_platform?
6893
end
6994

70-
def mysql_database_host
71-
if options[:skip_devcontainer]
72-
"localhost"
73-
else
74-
"<%= ENV.fetch(\"DB_HOST\") { \"localhost\" } %>"
75-
end
95+
def host
96+
"localhost"
97+
end
98+
end
99+
100+
class MySQL < Database
101+
include MySqlSocket
102+
103+
def name
104+
"mysql"
105+
end
106+
107+
def service
108+
{
109+
"image" => "mysql/mysql-server:8.0",
110+
"restart" => "unless-stopped",
111+
"environment" => {
112+
"MYSQL_ALLOW_EMPTY_PASSWORD" => "true",
113+
"MYSQL_ROOT_HOST" => "%"
114+
},
115+
"volumes" => ["mysql-data:/var/lib/mysql"],
116+
"networks" => ["default"],
117+
}
118+
end
119+
120+
def port
121+
3306
122+
end
123+
124+
def gem
125+
["mysql2", ["~> 0.5"]]
126+
end
127+
128+
def docker_base
129+
"curl default-mysql-client libvips"
130+
end
131+
132+
def docker_build
133+
"build-essential default-libmysqlclient-dev git"
134+
end
135+
136+
def base_package
137+
"default-mysql-client"
138+
end
139+
140+
def build_package
141+
"default-libmysqlclient-dev"
142+
end
143+
144+
def feature_name
145+
"ghcr.io/rails/devcontainer/features/mysql-client"
146+
end
147+
end
148+
149+
class PostgreSQL < Database
150+
def name
151+
"postgres"
152+
end
153+
154+
def service
155+
{
156+
"image" => "postgres:16.1",
157+
"restart" => "unless-stopped",
158+
"networks" => ["default"],
159+
"volumes" => ["postgres-data:/var/lib/postgresql/data"],
160+
"environment" => {
161+
"POSTGRES_USER" => "postgres",
162+
"POSTGRES_PASSWORD" => "postgres"
163+
}
164+
}
165+
end
166+
167+
def port
168+
5432
169+
end
170+
171+
def gem
172+
["pg", ["~> 1.1"]]
173+
end
174+
175+
def docker_base
176+
"curl libvips postgresql-client"
177+
end
178+
179+
def docker_build
180+
"build-essential git libpq-dev"
181+
end
182+
183+
def base_package
184+
"postgresql-client"
185+
end
186+
187+
def build_package
188+
"libpq-dev"
189+
end
190+
191+
def feature_name
192+
"ghcr.io/rails/devcontainer/features/postgres-client"
193+
end
194+
end
195+
196+
class MariaDB < Database
197+
include MySqlSocket
198+
199+
def name
200+
"mariadb"
201+
end
202+
203+
def service
204+
{
205+
"image" => "mariadb:10.5",
206+
"restart" => "unless-stopped",
207+
"networks" => ["default"],
208+
"volumes" => ["mariadb-data:/var/lib/mysql"],
209+
"environment" => {
210+
"MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" => "true",
211+
},
212+
}
213+
end
214+
215+
def port
216+
3306
217+
end
218+
219+
def gem
220+
["trilogy", ["~> 2.7"]]
221+
end
222+
223+
def docker_base
224+
"curl libvips"
225+
end
226+
227+
def docker_build
228+
"build-essential git"
229+
end
230+
231+
def base_package
232+
nil
76233
end
234+
235+
def build_package
236+
nil
237+
end
238+
239+
def feature_name
240+
nil
241+
end
242+
end
243+
244+
class SQLite3 < Database
245+
def name
246+
"sqlite3"
247+
end
248+
249+
def service
250+
nil
251+
end
252+
253+
def port
254+
nil
255+
end
256+
257+
def gem
258+
["sqlite3", [">= 1.4"]]
259+
end
260+
261+
def docker_base
262+
"curl libsqlite3-0 libvips"
263+
end
264+
265+
def docker_build
266+
"build-essential git"
267+
end
268+
269+
def base_package
270+
"libsqlite3-0"
271+
end
272+
273+
def build_package
274+
nil
275+
end
276+
277+
def feature_name
278+
"ghcr.io/rails/devcontainer/features/sqlite3"
279+
end
280+
end
281+
282+
class Null < Database
283+
def name; end
284+
def service; end
285+
def port; end
286+
def volume; end
287+
def docker_base; end
288+
def docker_build; end
289+
def base_package; end
290+
def build_package; end
291+
def feature_name; end
292+
end
77293
end
78294
end
79295
end

0 commit comments

Comments
 (0)