Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate db files during hanami new #180

Merged
merged 25 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bef0355
Add without hanami-db test context
cllns Jun 18, 2024
a911eb1
Add hanami-db to Gemfile, unless --skip-db is present
cllns Jun 18, 2024
e079ad0
Add generated app/repo.rb file to new project
cllns Jun 18, 2024
47c574d
Add generated app/db/relation.rb file
cllns Jun 18, 2024
6b56556
Add generated app/db/struct.rb file
cllns Jun 18, 2024
cab64e2
Add folders with .keep files for app/structs and app/repos
cllns Jun 18, 2024
37f487a
Add .keep file to config/db/migrate, to create that folder and its pa…
cllns Jun 18, 2024
03c340d
Add support for postgres, including pg gem
cllns Jun 18, 2024
ceeafaf
Add support for mysql databases
cllns Jun 18, 2024
b162ace
Prevent using --skip-db with --database
cllns Jun 18, 2024
5a702fa
Support common other names for the databases
cllns Jun 18, 2024
48c8fa0
Add more examples, simplify database pattern matching
cllns Jun 18, 2024
566379b
Remove kwargs
cllns Jun 18, 2024
fe6fc88
Add AbcSize to enable
cllns Jun 18, 2024
156c3a0
Remove FIXME, irrelevant
cllns Jul 1, 2024
f71c774
Remove deps, since it's not necessary
cllns Jul 1, 2024
56c0166
Simplify test
cllns Jul 1, 2024
03c2b93
Merge remote-tracking branch 'origin/main' into generate-db-files-dur…
cllns Jul 5, 2024
187d0ff
Fix specs
cllns Jul 5, 2024
e4142d0
x.x.x => 2.2.0
cllns Jul 5, 2024
a0bdcb5
Make examples less verbose
cllns Jul 5, 2024
bfaea68
Ignore .env*.local
cllns Jul 5, 2024
fad7333
Add ROM transaction helper into base operation
cllns Jul 5, 2024
f6d116c
Add comment to .env
cllns Jul 5, 2024
6a6d04f
Put base Repo in DB namespace
cllns Jul 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/hanami/cli/commands/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ def self.extended(base)
register "generate", aliases: ["g"] do |prefix|
prefix.register "action", Generate::Action
prefix.register "component", Generate::Component
prefix.register "slice", Generate::Slice
prefix.register "operation", Generate::Operation
prefix.register "part", Generate::Part
prefix.register "slice", Generate::Slice
prefix.register "view", Generate::View
end
end
Expand Down
86 changes: 75 additions & 11 deletions lib/hanami/cli/commands/gem/new.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ class New < Command
SKIP_ASSETS_DEFAULT = false
private_constant :SKIP_ASSETS_DEFAULT

# @since 2.2.0
# @api private
SKIP_DB_DEFAULT = false
private_constant :SKIP_DB_DEFAULT

# @since 2.2.0
# @api private
DATABASE_SQLITE = "sqlite"

# @since 2.2.0
# @api private
DATABASE_POSTGRES = "postgres"

# @since 2.2.0
# @api private
DATABASE_MYSQL = "mysql"

# @since 2.2.0
# @api private
SUPPORTED_DATABASES = [DATABASE_SQLITE, DATABASE_POSTGRES, DATABASE_MYSQL].freeze

desc "Generate a new Hanami app"

# @since 2.0.0
Expand All @@ -47,14 +68,28 @@ class New < Command
# @api private
option :skip_assets, type: :boolean, required: false,
default: SKIP_ASSETS_DEFAULT,
desc: "Skip assets"
desc: "Skip including hanami-assets"

# @since 2.2.0
# @api private
option :skip_db, type: :boolean, required: false,
default: SKIP_DB_DEFAULT,
desc: "Skip including hanami-db"

# @since 2.2.0
# @api private
option :database, type: :string, required: false,
default: DATABASE_SQLITE,
desc: "Database adapter (supported: sqlite, mysql, postgres)"

# rubocop:disable Layout/LineLength
example [
"bookshelf # Generate a new Hanami app in `bookshelf/' directory, using `Bookshelf' namespace",
"bookshelf --head # Generate a new Hanami app, using Hanami HEAD version from GitHub `main' branches",
"bookshelf --skip-install # Generate a new Hanami app, but it skips Hanami installation",
"bookshelf --skip-assets # Generate a new Hanami app without assets"
"bookshelf # Generate a new Hanami app in `bookshelf/' directory, using `Bookshelf' namespace",
"bookshelf --head # Generate a new Hanami app, using Hanami HEAD version from GitHub `main' branches",
"bookshelf --skip-install # Generate a new Hanami app, but it skips Hanami installation",
"bookshelf --skip-assets # Generate a new Hanami app without hanmai-assets",
"bookshelf --skip-db # Generate a new Hanami app without hanami-db",
"bookshelf --database={sqlite|postgres|mysql} # Generate a new Hanami app with a specified database (default: sqlite)",
]
# rubocop:enable Layout/LineLength

Expand All @@ -75,20 +110,36 @@ def initialize(
@system_call = system_call
end

# rubocop:enable Metrics/ParameterLists

# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity

# @since 2.0.0
# @api private
def call(app:, head: HEAD_DEFAULT, skip_install: SKIP_INSTALL_DEFAULT, skip_assets: SKIP_ASSETS_DEFAULT, **)
def call(
app:,
head: HEAD_DEFAULT,
skip_install: SKIP_INSTALL_DEFAULT,
skip_assets: SKIP_ASSETS_DEFAULT,
skip_db: SKIP_DB_DEFAULT,
database: nil
)
# rubocop:enable Metrics/ParameterLists
app = inflector.underscore(app)

raise PathAlreadyExistsError.new(app) if fs.exist?(app)
raise ConflictingOptionsError.new("--skip-db", "--database") if skip_db && database

normalized_database ||= normalize_database(database)

fs.mkdir(app)
fs.chdir(app) do
context = Generators::Context.new(inflector, app, head: head, skip_assets: skip_assets)
context = Generators::Context.new(
inflector,
app,
head: head,
skip_assets: skip_assets,
skip_db: skip_db,
database: normalized_database
)
generator.call(app, context: context) do
if skip_install
out.puts "Skipping installation, please enter `#{app}' directory and run `bundle exec hanami install'"
Expand All @@ -112,14 +163,27 @@ def call(app:, head: HEAD_DEFAULT, skip_install: SKIP_INSTALL_DEFAULT, skip_asse
end
end
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity

private

attr_reader :bundler
attr_reader :generator
attr_reader :system_call

def normalize_database(database)
case database
when nil, "sqlite", "sqlite3"
DATABASE_SQLITE
when "mysql", "mysql2"
DATABASE_MYSQL
when "postgres", "postgresql", "pg"
DATABASE_POSTGRES
else
raise DatabaseNotSupportedError.new(database, SUPPORTED_DATABASES)
end
end

def run_install_command!(head:)
head_flag = head ? " --head" : ""
bundler.exec("hanami install#{head_flag}").tap do |result|
Expand Down
16 changes: 16 additions & 0 deletions lib/hanami/cli/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,21 @@ def initialize(scheme)
super("`#{scheme}' is not a supported db scheme")
end
end

# @since 2.2.0
# @api public
class DatabaseNotSupportedError < Error
def initialize(invalid_database, supported_databases)
super("`#{invalid_database}' is not a supported database. Supported databases are: #{supported_databases.join(', ')}")
end
end

# @since 2.2.0
# @api public
class ConflictingOptionsError < Error
def initialize(option1, option2)
super("`#{option1}' and `#{option2}' cannot be used together")
end
end
end
end
42 changes: 42 additions & 0 deletions lib/hanami/cli/generators/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,44 @@ def generate_assets?
!options.fetch(:skip_assets, false)
end

# @since 2.2.0
# @api private
def generate_db?
!options.fetch(:skip_db, false)
end

# @since 2.2.0
# @api private
def generate_sqlite?
database_option == Commands::Gem::New::DATABASE_SQLITE
end

# @since 2.2.0
# @api private
def generate_postgres?
database_option == Commands::Gem::New::DATABASE_POSTGRES
end

# @since 2.2.0
# @api private
def generate_mysql?
database_option == Commands::Gem::New::DATABASE_MYSQL
end

# @since 2.2.0
# @api private
def database_url
if generate_sqlite?
"sqlite://db/#{app}.sqlite"
elsif generate_postgres?
"postgres://localhost/#{app}"
elsif generate_mysql?
"mysql://localhost/#{app}"
else
raise "Unknown database option: #{database_option}"
end
end

# @since 2.1.0
# @api private
def bundled_views?
Expand Down Expand Up @@ -108,6 +146,10 @@ def ruby_omit_hash_values?

private

def database_option
options.fetch(:database, Commands::Gem::New::DATABASE_SQLITE)
end

# @since 2.0.0
# @api private
attr_reader :inflector
Expand Down
9 changes: 9 additions & 0 deletions lib/hanami/cli/generators/gem/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ def generate_app(app, context) # rubocop:disable Metrics/AbcSize
fs.write("app/assets/images/favicon.ico", file("favicon.ico"))
end

if context.generate_db?
fs.write("app/db/repo.rb", t("repo.erb", context))
fs.write("app/db/relation.rb", t("relation.erb", context))
fs.write("app/db/struct.rb", t("struct.erb", context))
fs.touch("app/structs/.keep")
fs.touch("app/repos/.keep")
fs.touch("config/db/migrate/.keep")
end

fs.write("app/operation.rb", t("operation.erb", context))

fs.write("public/404.html", file("404.html"))
Expand Down
4 changes: 4 additions & 0 deletions lib/hanami/cli/generators/gem/app/env.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This is checked into source control, so put sensitive values into `.env.local`
<%- if generate_db? -%>
DATABASE_URL=<%= database_url %>
<%- end -%>
10 changes: 10 additions & 0 deletions lib/hanami/cli/generators/gem/app/gemfile.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ source "https://rubygems.org"
<%= hanami_gem("assets") %>
<%- end -%>
<%= hanami_gem("controller") %>
<%- if generate_db? -%>
<%= hanami_gem("db") %>
<%- end -%>
<%= hanami_gem("router") %>
<%= hanami_gem("validations") %>
<%= hanami_gem("view") %>
Expand All @@ -15,6 +18,13 @@ gem "dry-types", "~> 1.0", ">= 1.6.1"
gem "dry-operation", github: "dry-rb/dry-operation"
gem "puma"
gem "rake"
<%- if generate_sqlite? -%>
gem "sqlite3"
<%- elsif generate_postgres? -%>
gem "pg"
<%- elsif generate_mysql? -%>
gem "mysql2"
<%- end -%>

group :development do
<%= hanami_gem("webconsole") %>
Expand Down
2 changes: 1 addition & 1 deletion lib/hanami/cli/generators/gem/app/gitignore.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.env
.env*.local
log/*
<%- if generate_assets? -%>
public/
Expand Down
4 changes: 4 additions & 0 deletions lib/hanami/cli/generators/gem/app/operation.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@ require "dry/operation"

module <%= camelized_app_name %>
class Operation < Dry::Operation
<%- if generate_db? -%>
# Provide `transaction do ... end` method for database transactions
include Dry::Operation::Extensions::ROM
Comment on lines +9 to +10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for thinking to include this! ❤️

This is definitely good to go in now. We want these operations to support DB transactions natively.

Seeing this inspired me to create an issue to help us eliminate this line of boilerplate before 2.2 final: hanami/hanami#1437

<%- end -%>
end
end
10 changes: 10 additions & 0 deletions lib/hanami/cli/generators/gem/app/relation.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require "hanami/db/relation"

module <%= camelized_app_name %>
module DB
class Relation < Hanami::DB::Relation
end
end
end
10 changes: 10 additions & 0 deletions lib/hanami/cli/generators/gem/app/repo.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require "hanami/db/repo"

module <%= camelized_app_name %>
module DB
class Repo < Hanami::DB::Repo
end
end
end
10 changes: 10 additions & 0 deletions lib/hanami/cli/generators/gem/app/struct.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require "hanami/db/struct"

module <%= camelized_app_name %>
module DB
class Struct < Hanami::DB::Struct
end
end
end
Loading