Skip to content

Commit

Permalink
Improve the install generator to handle two- and three-tier database.…
Browse files Browse the repository at this point in the history
…yml configuration files

Resolves #204
  • Loading branch information
fractaledmind committed Sep 4, 2024
1 parent 816458c commit ed9c53a
Showing 1 changed file with 125 additions and 30 deletions.
155 changes: 125 additions & 30 deletions lib/generators/solid_cache/install/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ def create_config_solid_cache_yml
end

def add_cache_db_to_database_yml
if app_is_using_sqlite?
gsub_file database_yml, /production:\s*<<: \*default.*/m, sqlite_database_config_with_cache
if two_tier_production_configuration?
append_cache_db_to_two_tier_configuration
elsif three_tier_production_configuration?
append_cache_db_to_three_tier_configuration
else
gsub_file database_yml, /production:\s*<<: \*default.*/m, generic_database_config_with_cache
append_configuration_comment
end
end

Expand All @@ -33,40 +35,133 @@ def database_yml
app_root.join("config/database.yml")
end

def app_is_using_sqlite?
database_yml.read.match?(/production:.*sqlite3/m)
def database_config
@database_config ||= YAML.load(database_yml.read, aliases: true)
end

def sqlite_database_config_with_cache
<<~YAML
production:
primary:
<<: *default
database: storage/production.sqlite3
cache:
<<: *default
database: storage/production_cache.sqlite3
migrations_paths: db/cache_migrate
YAML
def production_block
return @production_block if defined? @production_block

production_block_regex = %r{
\nproduction: # Match 'production:' at the start of a line
(?: # Start of non-capturing group for block
\n # Match newline
(?: # Start of another non-capturing group for lines
[ \t]+.* # Match indented lines (one or more spaces/tabs, then any content)
| # OR
[ \t]* # Match blank lines (any number of spaces/tabs, including none)
)
)* # End of outer group, repeat 0 or more times
}x
@production_block = database_yml.read[production_block_regex]
end

def app_name_from_production_database_name
database_yml.read.scan(/database: (\w+)_production/).flatten.first
def deconstruct_production_block
newline, name, *contents = production_block.split "\n"
indentation = contents.first[/^([ \t]*)\S/, 1]

[indentation, newline, name, *contents]
end

def two_tier_production_configuration?
database_config["production"].key?("adapter")
end

def append_cache_db_to_two_tier_configuration
indentation, newline, name, *contents = deconstruct_production_block
app_name = app_name_from_production_database_name

if database_config.dig("production", "adapter") == "sqlite3"
output = [
newline,
name,
"#{indentation}primary:",
*contents.map { |it| "#{indentation * 2}#{it.strip}" },
"#{indentation}cache:",
"#{indentation * 2}<<: *default",
"#{indentation * 2}database: storage/production_cache.sqlite3",
"#{indentation * 2}migrations_paths: db/cache_migrate",
""
]
else
output = [
newline,
name,
"#{indentation}primary: &production_primary",
*contents.map { |it| "#{indentation * 2}#{it}" },
"#{indentation}cache:",
"#{indentation * 2}<<: *production_primary",
"#{indentation * 2}database: #{app_name}_production_cache",
""
]
end

gsub_file database_yml, production_block, output.join("\n")
end

def three_tier_production_configuration?
database_config["production"].key?("primary")
end

def append_cache_db_to_three_tier_configuration
return if database_config["production"].key?("cache")

indentation, newline, name, *contents = deconstruct_production_block
app_name = app_name_from_production_database_name

if database_config.dig("production", "primary", "adapter") == "sqlite3"
output = [
newline,
name,
*contents,
"#{indentation}cache:",
"#{indentation * 2}<<: *default",
"#{indentation * 2}database: storage/production_cache.sqlite3",
"#{indentation * 2}migrations_paths: db/cache_migrate",
""
]
else
primary = contents.find { |it| it.match?(/^([ \t]*)primary:.*$/) }
primary_alias = primary[/primary:\s*&([^ \t]*)/, 1] || "default"

output = [
newline,
name,
*contents,
"#{indentation}cache:",
"#{indentation * 2}<<: *#{primary_alias}",
"#{indentation * 2}database: #{app_name}_production_cache",
""
]
end

gsub_file database_yml, production_block, output.join("\n")
end

def generic_database_config_with_cache
def append_configuration_comment
app_name = app_name_from_production_database_name

<<~YAML
production:
primary: &production_primary
<<: *default
database: #{app_name}_production
username: #{app_name}
password: <%= ENV["#{app_name.upcase}_DATABASE_PASSWORD"] %>
cache:
<<: *production_primary
database: #{app_name}_production_cache
YAML
append_to_file "config/database.yml", <<~TEXT
# You need to add the following configuration to your production environment configuration:
#
TEXT
if database_yml.read.include?("adapter: sqlite3")
append_to_file "config/database.yml", <<~TEXT
# cache:
# <<: *default
# database: storage/production_cache.sqlite3
# migrations_paths: db/cache_migrate
TEXT
else
append_to_file "config/database.yml", <<~TEXT
# cache:
# <<: *production_primary
# database: #{app_name}_production_cache
TEXT
end
end

def app_name_from_production_database_name
database_yml.read.scan(/database: (\w+)_production/).flatten.first
end
end

0 comments on commit ed9c53a

Please sign in to comment.