ardb 0.28.3 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -7
  2. data/Gemfile +4 -9
  3. data/README.md +252 -3
  4. data/ardb.gemspec +8 -7
  5. data/bin/ardb +1 -1
  6. data/lib/ardb.rb +35 -34
  7. data/lib/ardb/adapter/base.rb +34 -30
  8. data/lib/ardb/adapter/mysql.rb +2 -17
  9. data/lib/ardb/adapter/postgresql.rb +24 -30
  10. data/lib/ardb/adapter/sqlite.rb +4 -8
  11. data/lib/ardb/adapter_spy.rb +2 -16
  12. data/lib/ardb/cli.rb +15 -15
  13. data/lib/ardb/cli/clirb.rb +14 -17
  14. data/lib/ardb/cli/commands.rb +204 -114
  15. data/lib/ardb/db_tests.rb +2 -4
  16. data/lib/ardb/default_order_by.rb +3 -13
  17. data/lib/ardb/migration.rb +9 -13
  18. data/lib/ardb/record_spy.rb +7 -26
  19. data/lib/ardb/relation_spy.rb +0 -6
  20. data/lib/ardb/require_autoloaded_active_record_files.rb +103 -58
  21. data/lib/ardb/test_helpers.rb +2 -5
  22. data/lib/ardb/use_db_default.rb +4 -15
  23. data/lib/ardb/version.rb +1 -1
  24. data/script/determine_autoloaded_active_record_files.rb +11 -8
  25. data/test/helper.rb +4 -13
  26. data/test/support/factory.rb +2 -2
  27. data/test/support/postgresql/migrations/{.gitkeep → .keep} +0 -0
  28. data/test/support/postgresql/schema.rb +0 -1
  29. data/test/support/postgresql/setup_test_db.rb +14 -15
  30. data/test/system/.keep +0 -0
  31. data/test/unit/adapter/base_tests.rb +73 -53
  32. data/test/unit/adapter/mysql_tests.rb +2 -19
  33. data/test/unit/adapter/postgresql_tests.rb +14 -23
  34. data/test/unit/adapter/sqlite_tests.rb +3 -11
  35. data/test/unit/adapter_spy_tests.rb +2 -16
  36. data/test/unit/ardb_tests.rb +43 -43
  37. data/test/unit/cli_tests.rb +220 -158
  38. data/test/unit/db_tests_tests.rb +3 -6
  39. data/test/unit/default_order_by_tests.rb +4 -8
  40. data/test/unit/migration_tests.rb +11 -15
  41. data/test/unit/record_spy_tests.rb +17 -22
  42. data/test/unit/relation_spy_tests.rb +17 -46
  43. data/test/unit/test_helpers_tests.rb +3 -14
  44. data/test/unit/use_db_default_tests.rb +7 -11
  45. metadata +100 -84
  46. data/lib/ardb/has_slug.rb +0 -107
  47. data/lib/ardb/migration_helpers.rb +0 -77
  48. data/lib/ardb/pg_json.rb +0 -90
  49. data/test/support/postgresql/pg_json_migrations/20160519133432_create_pg_json_migrate_test.rb +0 -13
  50. data/test/system/pg_json_tests.rb +0 -85
  51. data/test/unit/has_slug_tests.rb +0 -341
  52. data/test/unit/migration_helpers_tests.rb +0 -65
  53. data/test/unit/pg_json_tests.rb +0 -39
@@ -1,14 +1,13 @@
1
- require 'ardb'
1
+ require "ardb"
2
2
 
3
3
  module Ardb; end
4
4
  module Ardb::Adapter
5
-
6
5
  class Base
7
-
8
6
  attr_reader :config
9
7
 
10
8
  def initialize(config)
11
9
  @config = config
10
+ validate!
12
11
  end
13
12
 
14
13
  def connect_hash; self.config.activerecord_connect_hash; end
@@ -33,9 +32,6 @@ module Ardb::Adapter
33
32
  pattern
34
33
  end
35
34
 
36
- def foreign_key_add_sql(*args); raise NotImplementedError; end
37
- def foreign_key_drop_sql(*args); raise NotImplementedError; end
38
-
39
35
  def create_db(*args); raise NotImplementedError; end
40
36
  def drop_db(*args); raise NotImplementedError; end
41
37
 
@@ -43,33 +39,34 @@ module Ardb::Adapter
43
39
 
44
40
  def connect_db
45
41
  ActiveRecord::Base.establish_connection(self.connect_hash)
46
- # checkout a connection to ensure we can connect to the DB, we don't do
42
+ # checkout a connection to ensure we can connect to the DB, we don"t do
47
43
  # anything with the connection and immediately check it back in
48
44
  ActiveRecord::Base.connection_pool.with_connection{ }
49
45
  end
50
46
 
51
47
  def migrate_db
52
- verbose = ENV["MIGRATE_QUIET"].nil?
53
- version = ENV["MIGRATE_VERSION"] ? ENV["MIGRATE_VERSION"].to_i : nil
54
-
55
- if defined?(ActiveRecord::Migration::CommandRecorder)
56
- require 'ardb/migration_helpers'
57
- ActiveRecord::Migration::CommandRecorder.class_eval do
58
- include Ardb::MigrationHelpers::RecorderMixin
59
- end
60
- end
48
+ migrate_db_up
49
+ end
61
50
 
62
- ActiveRecord::Migrator.migrations_path = self.migrations_path
63
- ActiveRecord::Migration.verbose = verbose
64
- ActiveRecord::Migrator.migrate(self.migrations_path, version) do |migration|
65
- ENV["MIGRATE_SCOPE"].blank? || (ENV["MIGRATE_SCOPE"] == migration.scope)
66
- end
51
+ def migrate_db_up(target_version = nil)
52
+ migration_context.up(target_version)
53
+ end
54
+
55
+ def migrate_db_down(target_version = nil)
56
+ migration_context.down(target_version)
57
+ end
58
+
59
+ def migrate_db_forward(steps = 1)
60
+ migration_context.forward(steps)
61
+ end
62
+
63
+ def migrate_db_backward(steps = 1)
64
+ migration_context.rollback(steps)
67
65
  end
68
66
 
69
67
  def load_schema
70
- # silence STDOUT
71
- current_stdout = $stdout.dup
72
- $stdout = File.new('/dev/null', 'w')
68
+ current_stdout = $stdout.dup # silence STDOUT
69
+ $stdout = File.new("/dev/null", "w")
73
70
  load_ruby_schema if self.schema_format == Ardb::Config::RUBY_SCHEMA_FORMAT
74
71
  load_sql_schema if self.schema_format == Ardb::Config::SQL_SCHEMA_FORMAT
75
72
  $stdout = current_stdout
@@ -84,18 +81,17 @@ module Ardb::Adapter
84
81
  end
85
82
 
86
83
  def dump_schema
87
- # silence STDOUT
88
- current_stdout = $stdout.dup
89
- $stdout = File.new('/dev/null', 'w')
84
+ current_stdout = $stdout.dup # silence STDOUT
85
+ $stdout = File.new("/dev/null", "w")
90
86
  dump_ruby_schema
91
87
  dump_sql_schema if self.schema_format == Ardb::Config::SQL_SCHEMA_FORMAT
92
88
  $stdout = current_stdout
93
89
  end
94
90
 
95
91
  def dump_ruby_schema
96
- require 'active_record/schema_dumper'
92
+ require "active_record/schema_dumper"
97
93
  FileUtils.mkdir_p File.dirname(self.ruby_schema_path)
98
- File.open(self.ruby_schema_path, 'w:utf-8') do |file|
94
+ File.open(self.ruby_schema_path, "w:utf-8") do |file|
99
95
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
100
96
  end
101
97
  end
@@ -112,6 +108,14 @@ module Ardb::Adapter
112
108
  end
113
109
  end
114
110
 
115
- end
111
+ private
116
112
 
113
+ def validate!
114
+ # override as needed
115
+ end
116
+
117
+ def migration_context
118
+ ActiveRecord::MigrationContext.new(migrations_path)
119
+ end
120
+ end
117
121
  end
@@ -1,21 +1,6 @@
1
- require 'ardb/adapter/base'
1
+ require "ardb/adapter/base"
2
2
 
3
3
  module Ardb::Adapter
4
-
5
- class Mysql < Base
6
-
7
- def foreign_key_add_sql
8
- "ALTER TABLE :from_table"\
9
- " ADD CONSTRAINT :name"\
10
- " FOREIGN KEY (:from_column)"\
11
- " REFERENCES :to_table (:to_column)"
12
- end
13
-
14
- def foreign_key_drop_sql
15
- "ALTER TABLE :from_table"\
16
- " DROP FOREIGN KEY :name"
17
- end
18
-
4
+ class Mysql < Ardb::Adapter::Base
19
5
  end
20
-
21
6
  end
@@ -1,16 +1,14 @@
1
- require 'ardb/adapter/base'
1
+ require "ardb/adapter/base"
2
2
 
3
3
  module Ardb::Adapter
4
-
5
- class Postgresql < Base
6
-
7
- # the 'postgres' db is a "public" (doesn't typically require auth/grants to
4
+ class Postgresql < Ardb::Adapter::Base
5
+ # the "postgres" db is a "public" (doesn"t typically require auth/grants to
8
6
  # connect to) db that typically exists for all postgres installations; the
9
7
  # adapter uses it to create/drop other databases
10
8
  def public_connect_hash
11
9
  @public_connect_hash ||= self.connect_hash.merge({
12
- 'database' => 'postgres',
13
- 'schema_search_path' => 'public'
10
+ "database" => "postgres",
11
+ "schema_search_path" => "public"
14
12
  })
15
13
  end
16
14
 
@@ -42,47 +40,43 @@ module Ardb::Adapter
42
40
  tables = conn.execute "SELECT table_name"\
43
41
  " FROM information_schema.tables"\
44
42
  " WHERE table_schema = 'public';"
45
- tables.each{ |row| conn.execute "DROP TABLE #{row['table_name']} CASCADE" }
43
+ tables.each{ |row| conn.execute "DROP TABLE #{row["table_name"]} CASCADE" }
46
44
  end
47
45
  end
48
46
 
49
- def foreign_key_add_sql
50
- "ALTER TABLE :from_table"\
51
- " ADD CONSTRAINT :name"\
52
- " FOREIGN KEY (:from_column)"\
53
- " REFERENCES :to_table (:to_column)"
54
- end
55
-
56
- def foreign_key_drop_sql
57
- "ALTER TABLE :from_table"\
58
- " DROP CONSTRAINT :name"
59
- end
60
-
61
47
  def load_sql_schema
62
- require 'scmd'
48
+ require "scmd"
63
49
  cmd_str = "psql -f \"#{self.sql_schema_path}\" #{self.database}"
64
50
  cmd = Scmd.new(cmd_str, :env => env_var_hash).tap(&:run)
65
- raise 'Error loading database' unless cmd.success?
51
+ raise "Error loading database" unless cmd.success?
66
52
  end
67
53
 
68
54
  def dump_sql_schema
69
- require 'scmd'
55
+ require "scmd"
70
56
  cmd_str = "pg_dump -i -s -x -O -f \"#{self.sql_schema_path}\" #{self.database}"
71
57
  cmd = Scmd.new(cmd_str, :env => env_var_hash).tap(&:run)
72
- raise 'Error dumping database' unless cmd.success?
58
+ raise "Error dumping database" unless cmd.success?
73
59
  end
74
60
 
75
61
  private
76
62
 
63
+ def validate!
64
+ if self.database =~ /\W/
65
+ raise(
66
+ Ardb::ConfigurationError,
67
+ "database value must not contain non-word characters. "\
68
+ "Given: #{self.database.inspect}."
69
+ )
70
+ end
71
+ end
72
+
77
73
  def env_var_hash
78
74
  @env_var_hash ||= {
79
- 'PGHOST' => self.connect_hash['host'],
80
- 'PGPORT' => self.connect_hash['port'],
81
- 'PGUSER' => self.connect_hash['username'],
82
- 'PGPASSWORD' => self.connect_hash['password']
75
+ "PGHOST" => self.connect_hash["host"],
76
+ "PGPORT" => self.connect_hash["port"],
77
+ "PGUSER" => self.connect_hash["username"],
78
+ "PGPASSWORD" => self.connect_hash["password"]
83
79
  }
84
80
  end
85
-
86
81
  end
87
-
88
82
  end
@@ -1,11 +1,9 @@
1
- require 'fileutils'
2
- require 'ardb'
3
- require 'ardb/adapter/base'
1
+ require "fileutils"
2
+ require "ardb"
3
+ require "ardb/adapter/base"
4
4
 
5
5
  module Ardb::Adapter
6
-
7
- class Sqlite < Base
8
-
6
+ class Sqlite < Ardb::Adapter::Base
9
7
  def db_file_path
10
8
  File.expand_path(self.database, self.config.root_path)
11
9
  end
@@ -25,7 +23,5 @@ module Ardb::Adapter
25
23
  def drop_db
26
24
  FileUtils.rm(self.db_file_path) if File.exist?(self.db_file_path)
27
25
  end
28
-
29
26
  end
30
-
31
27
  end
@@ -1,10 +1,8 @@
1
- require 'ardb'
2
- require 'ardb/adapter/base'
1
+ require "ardb"
2
+ require "ardb/adapter/base"
3
3
 
4
4
  module Ardb
5
-
6
5
  class AdapterSpy < Ardb::Adapter::Base
7
-
8
6
  attr_accessor :drop_tables_called_count
9
7
  attr_accessor :dump_schema_called_count, :load_schema_called_count
10
8
  attr_accessor :drop_db_called_count, :create_db_called_count
@@ -51,16 +49,6 @@ module Ardb
51
49
 
52
50
  # Overwritten `Adapter::Base` methods
53
51
 
54
- def foreign_key_add_sql
55
- "FAKE ADD FOREIGN KEY SQL :from_table :from_column " \
56
- ":to_table :to_column :name"
57
- end
58
-
59
- def foreign_key_drop_sql
60
- "FAKE DROP FOREIGN KEY SQL :from_table :from_column " \
61
- ":to_table :to_column :name"
62
- end
63
-
64
52
  def create_db(*args, &block)
65
53
  self.create_db_called_count += 1
66
54
  end
@@ -88,7 +76,5 @@ module Ardb
88
76
  def dump_schema(*args, &block)
89
77
  self.dump_schema_called_count += 1
90
78
  end
91
-
92
79
  end
93
-
94
80
  end
@@ -1,17 +1,19 @@
1
- require 'ardb/cli/clirb'
2
- require 'ardb/cli/commands'
3
- require 'ardb/version'
1
+ require "ardb/cli/clirb"
2
+ require "ardb/cli/commands"
3
+ require "ardb/version"
4
4
 
5
5
  module Ardb
6
-
7
6
  class CLI
8
-
9
7
  COMMANDS = CommandSet.new{ |unknown| InvalidCommand.new(unknown) }.tap do |c|
10
- c.add(ConnectCommand, 'connect')
11
- c.add(CreateCommand, 'create')
12
- c.add(DropCommand, 'drop')
13
- c.add(MigrateCommand, 'migrate')
14
- c.add(GenerateMigrationCommand, 'generate-migration')
8
+ c.add(ConnectCommand)
9
+ c.add(CreateCommand)
10
+ c.add(DropCommand)
11
+ c.add(GenerateMigrationCommand)
12
+ c.add(MigrateCommand)
13
+ c.add(MigrateUpCommand)
14
+ c.add(MigrateDownCommand)
15
+ c.add(MigrateForwardCommand)
16
+ c.add(MigrateBackwardCommand)
15
17
  end
16
18
 
17
19
  def self.run(args)
@@ -32,13 +34,13 @@ module Ardb
32
34
  cmd = COMMANDS[cmd_name]
33
35
  cmd.run(args)
34
36
  rescue CLIRB::HelpExit
35
- @stdout.puts cmd.help
37
+ @stdout.puts cmd.command_help
36
38
  rescue CLIRB::VersionExit
37
39
  @stdout.puts Ardb::VERSION
38
40
  rescue CLIRB::Error, ArgumentError, InvalidCommandError => exception
39
41
  display_debug(exception)
40
42
  @stderr.puts "#{exception.message}\n\n"
41
- @stdout.puts cmd.help
43
+ @stdout.puts cmd.command_help
42
44
  @kernel.exit 1
43
45
  rescue CommandExitError
44
46
  @kernel.exit 1
@@ -53,12 +55,10 @@ module Ardb
53
55
  private
54
56
 
55
57
  def display_debug(exception)
56
- if ENV['DEBUG']
58
+ if ENV["DEBUG"]
57
59
  @stderr.puts "#{exception.class}: #{exception.message}"
58
60
  @stderr.puts exception.backtrace.join("\n")
59
61
  end
60
62
  end
61
-
62
63
  end
63
-
64
64
  end
@@ -1,20 +1,19 @@
1
1
  module Ardb; end
2
2
  class Ardb::CLI
3
-
4
- class CLIRB # Version 1.0.0, https://github.com/redding/cli.rb
3
+ class CLIRB # Version 1.1.0, https://github.com/redding/cli.rb
5
4
  Error = Class.new(RuntimeError);
6
5
  HelpExit = Class.new(RuntimeError); VersionExit = Class.new(RuntimeError)
7
6
  attr_reader :argv, :args, :opts, :data
8
7
 
9
8
  def initialize(&block)
10
9
  @options = []; instance_eval(&block) if block
11
- require 'optparse'
10
+ require "optparse"
12
11
  @data, @args, @opts = [], [], {}; @parser = OptionParser.new do |p|
13
- p.banner = ''; @options.each do |o|
12
+ p.banner = ""; @options.each do |o|
14
13
  @opts[o.name] = o.value; p.on(*o.parser_args){ |v| @opts[o.name] = v }
15
14
  end
16
- p.on_tail('--version', ''){ |v| raise VersionExit, v.to_s }
17
- p.on_tail('--help', ''){ |v| raise HelpExit, v.to_s }
15
+ p.on_tail("--version", ""){ |v| raise VersionExit, v.to_s }
16
+ p.on_tail("--help", ""){ |v| raise HelpExit, v.to_s }
18
17
  end
19
18
  end
20
19
 
@@ -27,33 +26,31 @@ class Ardb::CLI
27
26
  end
28
27
  def to_s; @parser.to_s; end
29
28
  def inspect
30
- "#<#{self.class}:#{'0x0%x' % (object_id << 1)} @data=#{@data.inspect}>"
29
+ "#<#{self.class}:#{"0x0%x" % (object_id << 1)} @data=#{@data.inspect}>"
31
30
  end
32
31
 
33
32
  class Option
34
33
  attr_reader :name, :opt_name, :desc, :abbrev, :value, :klass, :parser_args
35
34
 
36
- def initialize(name, *args)
37
- settings, @desc = args.last.kind_of?(::Hash) ? args.pop : {}, args.pop || ''
38
- @name, @opt_name, @abbrev = parse_name_values(name, settings[:abbrev])
39
- @value, @klass = gvalinfo(settings[:value])
35
+ def initialize(name, desc = nil, abbrev: nil, value: nil)
36
+ @name, @desc = name, desc || ""
37
+ @opt_name, @abbrev = parse_name_values(name, abbrev)
38
+ @value, @klass = gvalinfo(value)
40
39
  @parser_args = if [TrueClass, FalseClass, NilClass].include?(@klass)
41
40
  ["-#{@abbrev}", "--[no-]#{@opt_name}", @desc]
42
41
  else
43
- ["-#{@abbrev}", "--#{@opt_name} #{@opt_name.upcase}", @klass, @desc]
42
+ ["-#{@abbrev}", "--#{@opt_name} VALUE", @klass, @desc]
44
43
  end
45
44
  end
46
45
 
47
46
  private
48
47
 
49
48
  def parse_name_values(name, custom_abbrev)
50
- [ (processed_name = name.to_s.strip.downcase), processed_name.gsub('_', '-'),
51
- custom_abbrev || processed_name.gsub(/[^a-z]/, '').chars.first || 'a'
49
+ [ (processed_name = name.to_s.strip.downcase).gsub("_", "-"),
50
+ custom_abbrev || processed_name.gsub(/[^a-z]/, "").chars.first || "a"
52
51
  ]
53
52
  end
54
- def gvalinfo(v); v.kind_of?(Class) ? [nil,gklass(v)] : [v,gklass(v.class)]; end
55
- def gklass(k); k == Fixnum ? Integer : k; end
53
+ def gvalinfo(v); v.kind_of?(Class) ? [nil,v] : [v,v.class]; end
56
54
  end
57
55
  end
58
-
59
56
  end
@@ -1,15 +1,13 @@
1
- require 'ardb'
2
- require 'ardb/cli/clirb'
3
- require 'much-plugin'
1
+ require "ardb"
2
+ require "ardb/cli/clirb"
3
+ require "much-plugin"
4
4
 
5
5
  module Ardb; end
6
6
  class Ardb::CLI
7
-
8
7
  InvalidCommandError = Class.new(ArgumentError)
9
8
  CommandExitError = Class.new(RuntimeError)
10
9
 
11
10
  class InvalidCommand
12
-
13
11
  attr_reader :name, :clirb
14
12
 
15
13
  def initialize(name)
@@ -22,27 +20,26 @@ class Ardb::CLI
22
20
  def run(argv)
23
21
  @clirb.parse!([@name, argv].flatten.compact)
24
22
  raise CLIRB::HelpExit if @name.to_s.empty?
25
- raise InvalidCommandError, "'#{self.name}' is not a command."
23
+ raise InvalidCommandError, "\"#{self.name}\" is not a command."
26
24
  end
27
25
 
28
- def help
26
+ def command_help
29
27
  "Usage: ardb [COMMAND] [options]\n\n" \
30
28
  "Options: #{@clirb}\n" \
31
29
  "Commands:\n" \
32
30
  "#{COMMANDS.to_s.split("\n").map{ |l| " #{l}" }.join("\n")}\n"
33
31
  end
34
-
35
32
  end
36
33
 
37
34
  module ValidCommand
38
35
  include MuchPlugin
39
36
 
40
- plugin_included do
41
- include InstanceMethods
37
+ plugin_class_methods do
38
+ def command_name; raise NotImplementedError; end
39
+ def command_summary; ""; end
42
40
  end
43
41
 
44
- module InstanceMethods
45
-
42
+ plugin_instance_methods do
46
43
  def initialize(&clirb_build)
47
44
  @clirb = CLIRB.new(&clirb_build)
48
45
  end
@@ -55,24 +52,34 @@ class Ardb::CLI
55
52
  @stderr = stderr || $stderr
56
53
  end
57
54
 
58
- def summary
59
- ''
60
- end
55
+ def command_name; self.class.command_name; end
56
+ def command_summary; self.class.command_summary; end
61
57
 
58
+ def command_help
59
+ "Usage: ardb #{self.command_name} [options]\n\n" \
60
+ "Options: #{self.clirb}\n" \
61
+ "Description:\n" \
62
+ " #{self.command_summary}"
63
+ end
62
64
  end
63
-
64
65
  end
65
66
 
66
67
  class ConnectCommand
67
68
  include ValidCommand
68
69
 
70
+ def self.command_name; "connect"; end
71
+ def self.command_summary; "Connect to the configured DB"; end
72
+
69
73
  def run(argv, *args)
70
74
  super
71
75
 
72
- Ardb.init(false)
73
76
  begin
77
+ Ardb.init(false)
74
78
  Ardb.adapter.connect_db
75
- @stdout.puts "connected to #{Ardb.config.adapter} db `#{Ardb.config.database}`"
79
+ @stdout.puts "connected to #{Ardb.config.adapter} db #{Ardb.config.database.inspect}"
80
+ rescue ActiveRecord::NoDatabaseError => e
81
+ @stderr.puts "error: database #{Ardb.config.database.inspect} "\
82
+ "does not exist"
76
83
  rescue StandardError => e
77
84
  @stderr.puts e
78
85
  @stderr.puts e.backtrace.join("\n")
@@ -81,150 +88,237 @@ class Ardb::CLI
81
88
  raise CommandExitError
82
89
  end
83
90
  end
84
-
85
- def summary
86
- "Connect to the configured DB"
87
- end
88
-
89
- def help
90
- "Usage: ardb connect [options]\n\n" \
91
- "Options: #{@clirb}\n" \
92
- "Description:\n" \
93
- " #{self.summary}"
94
- end
95
-
96
91
  end
97
92
 
98
93
  class CreateCommand
99
94
  include ValidCommand
100
95
 
96
+ def self.command_name; "create"; end
97
+ def self.command_summary; "Create the configured DB"; end
98
+
101
99
  def run(argv, *args)
102
100
  super
103
101
 
104
- Ardb.init(false)
105
102
  begin
103
+ Ardb.init(false)
106
104
  Ardb.adapter.create_db
107
- @stdout.puts "created #{Ardb.config.adapter} db `#{Ardb.config.database}`"
105
+ @stdout.puts "created #{Ardb.config.adapter} db #{Ardb.config.database.inspect}"
106
+ rescue ActiveRecord::StatementInvalid => e
107
+ @stderr.puts "error: database #{Ardb.config.database.inspect} "\
108
+ "already exists"
108
109
  rescue StandardError => e
109
110
  @stderr.puts e
110
111
  @stderr.puts "error creating #{Ardb.config.database.inspect} database"
111
112
  raise CommandExitError
112
113
  end
113
114
  end
114
-
115
- def summary
116
- "Create the configured DB"
117
- end
118
-
119
- def help
120
- "Usage: ardb create [options]\n\n" \
121
- "Options: #{@clirb}\n" \
122
- "Description:\n" \
123
- " #{self.summary}"
124
- end
125
-
126
115
  end
127
116
 
128
117
  class DropCommand
129
118
  include ValidCommand
130
119
 
120
+ def self.command_name; "drop"; end
121
+ def self.command_summary; "Drop the configured DB"; end
122
+
131
123
  def run(argv, *args)
132
124
  super
133
125
 
134
- Ardb.init(true)
135
126
  begin
127
+ Ardb.init(true)
136
128
  Ardb.adapter.drop_db
137
- @stdout.puts "dropped #{Ardb.config.adapter} db `#{Ardb.config.database}`"
129
+ @stdout.puts "dropped #{Ardb.config.adapter} db #{Ardb.config.database.inspect}"
130
+ rescue ActiveRecord::NoDatabaseError => e
131
+ @stderr.puts "error: database #{Ardb.config.database.inspect} "\
132
+ "does not exist"
138
133
  rescue StandardError => e
139
134
  @stderr.puts e
140
135
  @stderr.puts "error dropping #{Ardb.config.database.inspect} database"
141
136
  raise CommandExitError
142
137
  end
143
138
  end
144
-
145
- def summary
146
- "Drop the configured DB"
147
- end
148
-
149
- def help
150
- "Usage: ardb drop [options]\n\n" \
151
- "Options: #{@clirb}\n" \
152
- "Description:\n" \
153
- " #{self.summary}"
154
- end
155
-
156
139
  end
157
140
 
158
- class MigrateCommand
141
+ class GenerateMigrationCommand
159
142
  include ValidCommand
160
143
 
144
+ def self.command_name; "generate-migration"; end
145
+ def self.command_summary; "Generate a MIGRATION-NAME migration file"; end
146
+
161
147
  def run(argv, *args)
162
148
  super
163
149
 
164
- Ardb.init(true)
165
150
  begin
166
- Ardb.adapter.migrate_db
167
- Ardb.adapter.dump_schema unless ENV['ARDB_MIGRATE_NO_SCHEMA']
151
+ Ardb.init(false)
152
+
153
+ require "ardb/migration"
154
+ migration = Ardb::Migration.new(Ardb.config, @clirb.args.first)
155
+ migration.save!
156
+ @stdout.puts "generated #{migration.file_path}"
157
+ rescue Ardb::Migration::NoIdentifierError => exception
158
+ error = ArgumentError.new("MIGRATION-NAME must be provided")
159
+ error.set_backtrace(exception.backtrace)
160
+ raise error
168
161
  rescue StandardError => e
169
162
  @stderr.puts e
170
163
  @stderr.puts e.backtrace.join("\n")
171
- @stderr.puts "error migrating #{Ardb.config.database.inspect} database"
164
+ @stderr.puts "error generating migration"
172
165
  raise CommandExitError
173
166
  end
174
167
  end
175
168
 
176
- def summary
177
- "Migrate the configured DB"
169
+ def command_help
170
+ "Usage: ardb #{self.command_name} MIGRATION-NAME [options]\n\n" \
171
+ "Options: #{self.clirb}\n" \
172
+ "Description:\n" \
173
+ " #{self.command_summary}"
178
174
  end
175
+ end
179
176
 
180
- def help
181
- "Usage: ardb migrate [options]\n\n" \
182
- "Options: #{@clirb}\n" \
183
- "Description:\n" \
184
- " #{self.summary}"
177
+ module MigrateCommandBehaviors
178
+ include MuchPlugin
179
+
180
+ plugin_included do
181
+ include ValidCommand
185
182
  end
186
183
 
184
+ plugin_instance_methods do
185
+ def migrate; raise NotImplementedError; end
186
+
187
+ def run(argv, *args)
188
+ super
189
+
190
+ begin
191
+ Ardb.init(true)
192
+ self.migrate
193
+ Ardb.adapter.dump_schema unless ENV["ARDB_MIGRATE_NO_SCHEMA"]
194
+ rescue ActiveRecord::NoDatabaseError => e
195
+ @stderr.puts "error: database #{Ardb.config.database.inspect} "\
196
+ "does not exist"
197
+ rescue StandardError => e
198
+ @stderr.puts e
199
+ @stderr.puts e.backtrace.join("\n")
200
+ @stderr.puts "error migrating #{Ardb.config.database.inspect} database"
201
+ raise CommandExitError
202
+ end
203
+ end
204
+ end
187
205
  end
188
206
 
189
- class GenerateMigrationCommand
190
- include ValidCommand
207
+ class MigrateCommand
208
+ include MigrateCommandBehaviors
191
209
 
192
- def run(argv, *args)
193
- super
210
+ def self.command_name; "migrate"; end
211
+ def self.command_summary; "Migrate the configured DB"; end
194
212
 
195
- Ardb.init(false)
196
- begin
197
- require 'ardb/migration'
198
- migration = Ardb::Migration.new(Ardb.config, @clirb.args.first)
199
- migration.save!
200
- @stdout.puts "generated #{migration.file_path}"
201
- rescue Ardb::Migration::NoIdentifierError => exception
202
- error = ArgumentError.new("MIGRATION-NAME must be provided")
203
- error.set_backtrace(exception.backtrace)
204
- raise error
205
- rescue StandardError => e
206
- @stderr.puts e
207
- @stderr.puts e.backtrace.join("\n")
208
- @stderr.puts "error generating migration"
209
- raise CommandExitError
213
+ def migrate
214
+ Ardb.adapter.migrate_db
215
+ end
216
+ end
217
+
218
+ module MigrateStyleBehaviors
219
+ include MuchPlugin
220
+
221
+ plugin_included do
222
+ include MigrateCommandBehaviors
223
+ end
224
+
225
+ plugin_class_methods do
226
+ def command_style; raise NotImplementedError; end
227
+
228
+ def command_name; "migrate-#{self.command_style}"; end
229
+ def command_summary; "Migrate the configured DB #{self.command_style}"; end
230
+ end
231
+
232
+ plugin_instance_methods do
233
+ def migrate
234
+ Ardb.adapter.send("migrate_db_#{self.class.command_style}", *migrate_args)
210
235
  end
236
+
237
+ private
238
+
239
+ def migrate_args; raise NotImplementedError; end
211
240
  end
241
+ end
212
242
 
213
- def summary
214
- "Generate a migration file given a MIGRATION-NAME"
243
+ module MigrateDirectionBehaviors
244
+ include MuchPlugin
245
+
246
+ plugin_included do
247
+ include MigrateStyleBehaviors
215
248
  end
216
249
 
217
- def help
218
- "Usage: ardb generate-migration [options] MIGRATION-NAME\n\n" \
219
- "Options: #{@clirb}\n" \
220
- "Description:\n" \
221
- " #{self.summary}"
250
+ plugin_class_methods do
251
+ def command_style; self.command_direction; end
252
+ def command_direction; raise NotImplementedError; end
253
+ end
254
+
255
+ plugin_instance_methods do
256
+ def initialize
257
+ super do
258
+ option(:target_version, "version to migrate to", value: String)
259
+ end
260
+ end
261
+
262
+ private
263
+
264
+ def migrate_args
265
+ [@clirb.opts[:target_version]]
266
+ end
267
+ end
268
+ end
269
+
270
+ module MigrateStepDirectionBehaviors
271
+ include MuchPlugin
272
+
273
+ plugin_included do
274
+ include MigrateStyleBehaviors
275
+ end
276
+
277
+ plugin_class_methods do
278
+ def command_style; self.command_direction; end
279
+ def command_direction; raise NotImplementedError; end
222
280
  end
223
281
 
282
+ plugin_instance_methods do
283
+ def initialize
284
+ super do
285
+ option(:steps, "number of migrations to migrate", value: 1)
286
+ end
287
+ end
288
+
289
+ private
290
+
291
+ def migrate_args
292
+ [@clirb.opts[:steps]]
293
+ end
294
+ end
224
295
  end
225
296
 
226
- class CommandSet
297
+ class MigrateUpCommand
298
+ include MigrateDirectionBehaviors
299
+
300
+ def self.command_direction; "up"; end
301
+ end
302
+
303
+ class MigrateDownCommand
304
+ include MigrateDirectionBehaviors
227
305
 
306
+ def self.command_direction; "down"; end
307
+ end
308
+
309
+ class MigrateForwardCommand
310
+ include MigrateStepDirectionBehaviors
311
+
312
+ def self.command_direction; "forward"; end
313
+ end
314
+
315
+ class MigrateBackwardCommand
316
+ include MigrateStepDirectionBehaviors
317
+
318
+ def self.command_direction; "backward"; end
319
+ end
320
+
321
+ class CommandSet
228
322
  def initialize(&unknown_cmd_block)
229
323
  @lookup = Hash.new{ |h,k| unknown_cmd_block.call(k) }
230
324
  @names = []
@@ -232,29 +326,28 @@ class Ardb::CLI
232
326
  @summaries = {}
233
327
  end
234
328
 
235
- def add(klass, name, *aliases)
329
+ def add(klass)
236
330
  begin
237
331
  cmd = klass.new
238
- rescue StandardError => err
239
- # don't add any commands you can't init
332
+ rescue StandardError
333
+ # don"t add any commands you can"t initialize
240
334
  else
241
- ([name] + aliases).each{ |n| @lookup[n] = cmd }
335
+ @lookup[cmd.command_name] = cmd
242
336
  @to_s = nil
243
- @names << name
244
- @aliases[name] = aliases.empty? ? '' : "(#{aliases.join(', ')})"
245
- @summaries[name] = cmd.summary.to_s.empty? ? '' : "# #{cmd.summary}"
337
+ @names << cmd.command_name
338
+ @summaries[cmd.command_name] = cmd.command_summary.to_s
246
339
  end
247
340
  end
248
341
 
249
- def remove(name)
250
- @lookup.delete(name)
251
- @names.delete(name)
252
- @aliases.delete(name)
342
+ def remove(klass)
343
+ @lookup.delete(klass.command_name)
344
+ @names.delete(klass.command_name)
345
+ @summaries.delete(klass.command_name)
253
346
  @to_s = nil
254
347
  end
255
348
 
256
- def [](name)
257
- @lookup[name]
349
+ def [](cmd_name)
350
+ @lookup[cmd_name]
258
351
  end
259
352
 
260
353
  def size
@@ -263,13 +356,10 @@ class Ardb::CLI
263
356
 
264
357
  def to_s
265
358
  max_name_size = @names.map{ |n| n.size }.max || 0
266
- max_alias_size = @aliases.values.map{ |v| v.size }.max || 0
267
359
 
268
360
  @to_s ||= @names.map do |n|
269
- "#{n.ljust(max_name_size)} #{@aliases[n].ljust(max_alias_size)} #{@summaries[n]}"
361
+ "#{n.ljust(max_name_size)} #{@summaries[n]}"
270
362
  end.join("\n")
271
363
  end
272
-
273
364
  end
274
-
275
365
  end