Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Break Versioning](https://www.taoensso.com/break-ve

- Add `hanami new --skip-git` to generate an app without initializing a git repository or generating a `.gitignore`. (@aaronmallen #441)
- Proper support for MariaDB (@katafrakt in #458)
- Add `--sql` flag to migration generator to use a SQL template instead of Ruby. (@alassek in #470)

### Changed

Expand Down
11 changes: 8 additions & 3 deletions lib/hanami/cli/commands/app/generate/migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Generate
class Migration < Command
argument :name, required: true, desc: "Migration name"
option :gateway, desc: "Generate migration for gateway"
option :sql, type: :boolean, default: false, desc: "Generate SQL (default: Ruby)"

example "create_posts", "Migration for the app"
example "add_published_at_to_posts", "Migration for the app"
Expand All @@ -20,20 +21,24 @@ def generator_class
Generators::App::Migration
end

def call(name:, slice: nil, gateway: nil)
def call(name:, slice: nil, gateway: nil, sql: false)
ext = sql ? "sql" : "rb"
Comment thread
katafrakt marked this conversation as resolved.
Resolved

if slice
generator.call(
key: name,
namespace: slice,
base_path: fs.join("slices", inflector.underscore(slice)),
gateway: gateway
gateway: gateway,
ext: ext
)
else
generator.call(
key: name,
namespace: app.namespace,
base_path: "app",
gateway: gateway
gateway: gateway,
ext: ext
)
end
end
Expand Down
25 changes: 19 additions & 6 deletions lib/hanami/cli/generators/app/migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ def initialize(fs:, inflector:, stdout: $stdout)

# @since 2.2.0
# @api private
def call(key:, base_path:, gateway: nil, **_opts)
def call(key:, base_path:, gateway: nil, ext: "rb", **_opts)
name = inflector.underscore(key)
ensure_valid_name(name)

base_path = nil if base_path == "app" # Migrations are in the root dir, not app/
migrate_dir = gateway ? "#{gateway}_migrate" : "migrate"

path = fs.join(*[base_path, "config", "db", migrate_dir, file_name(name)].compact)
path = fs.join(*[base_path, "config", "db", migrate_dir, file_name(name, ext)].compact)

fs.create(path, FILE_CONTENTS)
fs.create(path, FILE_CONTENTS[ext])
end

private
Expand All @@ -42,14 +42,14 @@ def ensure_valid_name(name)
end
end

def file_name(name)
"#{Time.now.strftime(VERSION_FORMAT)}_#{name}.rb"
def file_name(name, ext)
"#{Time.now.strftime(VERSION_FORMAT)}_#{name}.#{ext}"
end

VERSION_FORMAT = "%Y%m%d%H%M%S"
private_constant :VERSION_FORMAT

FILE_CONTENTS = <<~RUBY
FILE_CONTENTS = {"rb" => <<~RUBY, "sql" => <<~SQL}.freeze
# frozen_string_literal: true

ROM::SQL.migration do
Expand All @@ -60,6 +60,19 @@ def file_name(name)
end
end
RUBY
-- Add your migration here.
--
-- See https://hanakai.org/learn/hanami/database/migrations/ for details.
Comment thread
katafrakt marked this conversation as resolved.
Resolved
-- @migrate up
-- @begin
SELECT 'up SQL query';
-- @end

-- @migrate down
-- @begin
SELECT 'down SQL query';
-- @end
SQL
private_constant :FILE_CONTENTS
end
end
Expand Down
129 changes: 94 additions & 35 deletions spec/unit/hanami/cli/commands/app/generate/migration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,57 +14,116 @@ def output

let(:app) { Hanami.app.namespace }

let(:migration_file_contents) {
<<~RUBY
# frozen_string_literal: true

ROM::SQL.migration do
# Add your migration here.
#
# See https://hanakai.org/learn/hanami/database/migrations/ for details.
change do
end
end
RUBY
}

before do
allow(Time).to receive(:now) { Time.new(2024, 7, 13, 14, 6, 0) }
end

context "generating for app" do
it "generates a migration" do
subject.call(name: "create_posts")
context "Ruby migration" do
let(:migration_file_contents) { <<~RUBY }
# frozen_string_literal: true

ROM::SQL.migration do
# Add your migration here.
#
# See https://hanakai.org/learn/hanami/database/migrations/ for details.
change do
end
end
RUBY

expect(fs.read("config/db/migrate/20240713140600_create_posts.rb")).to eq migration_file_contents
expect(output).to eq("Created config/db/migrate/20240713140600_create_posts.rb")
end
it "generates a migration" do
subject.call(name: "create_posts")

it "generates a migration for a gateway" do
subject.call(name: "create_posts", gateway: "extra")
expect(fs.read("config/db/migrate/20240713140600_create_posts.rb")).to eq migration_file_contents
expect(output).to eq("Created config/db/migrate/20240713140600_create_posts.rb")
end

expect(fs.read("config/db/extra_migrate/20240713140600_create_posts.rb")).to eq migration_file_contents
expect(output).to eq("Created config/db/extra_migrate/20240713140600_create_posts.rb")
end
it "generates a migration for a gateway" do
subject.call(name: "create_posts", gateway: "extra")

it "generates a migration with underscored version of camel cased name" do
subject.call(name: "CreatePosts")
expect(fs.read("config/db/extra_migrate/20240713140600_create_posts.rb")).to eq migration_file_contents
expect(output).to eq("Created config/db/extra_migrate/20240713140600_create_posts.rb")
end

it "generates a migration with underscored version of camel cased name" do
subject.call(name: "CreatePosts")

expect(fs.read("config/db/migrate/20240713140600_create_posts.rb")).to eq migration_file_contents
expect(output).to eq("Created config/db/migrate/20240713140600_create_posts.rb")
expect(fs.read("config/db/migrate/20240713140600_create_posts.rb")).to eq migration_file_contents
expect(output).to eq("Created config/db/migrate/20240713140600_create_posts.rb")
end

it "raises an error if given an invalid name" do
expect {
subject.call(name: "create posts")
}.to raise_error(include_in_order(
"Invalid migration name: create posts",
"Name must contain only letters, numbers, and underscores."
))
end
end

it "raises an error if given an invalid name" do
expect {
subject.call(name: "create posts")
}.to raise_error(include_in_order(
"Invalid migration name: create posts",
"Name must contain only letters, numbers, and underscores."
))
context "SQL migration" do
let(:migration_file_contents) { <<~SQL }
-- Add your migration here.
--
-- See https://hanakai.org/learn/hanami/database/migrations/ for details.
-- @migrate up
-- @begin
SELECT 'up SQL query';
-- @end

-- @migrate down
-- @begin
SELECT 'down SQL query';
-- @end
SQL

it "generates a migration" do
subject.call(name: "create_posts", sql: true)

expect(fs.read("config/db/migrate/20240713140600_create_posts.sql")).to eq migration_file_contents
expect(output).to eq("Created config/db/migrate/20240713140600_create_posts.sql")
end

it "generates a migration for a gateway" do
subject.call(name: "create_posts", gateway: "extra", sql: true)

expect(fs.read("config/db/extra_migrate/20240713140600_create_posts.sql")).to eq migration_file_contents
expect(output).to eq("Created config/db/extra_migrate/20240713140600_create_posts.sql")
end

it "generates a migration with underscored version of camel cased name" do
subject.call(name: "CreatePosts", sql: true)

expect(fs.read("config/db/migrate/20240713140600_create_posts.sql")).to eq migration_file_contents
expect(output).to eq("Created config/db/migrate/20240713140600_create_posts.sql")
end

it "raises an error if given an invalid name" do
expect {
subject.call(name: "create posts", sql: true)
}.to raise_error(include_in_order(
"Invalid migration name: create posts",
"Name must contain only letters, numbers, and underscores."
))
end
end
end

context "generating for a slice" do
let(:migration_file_contents) { <<~RUBY }
# frozen_string_literal: true

ROM::SQL.migration do
# Add your migration here.
#
# See https://hanakai.org/learn/hanami/database/migrations/ for details.
change do
end
end
RUBY

it "generates a migration" do
fs.mkdir("slices/main")
stdout.truncate 0
Expand Down
Loading