ardb 0.27.3 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -1
  3. data/ardb.gemspec +3 -4
  4. data/lib/ardb.rb +135 -68
  5. data/lib/ardb/adapter/base.rb +39 -24
  6. data/lib/ardb/adapter/mysql.rb +1 -2
  7. data/lib/ardb/adapter/postgresql.rb +14 -12
  8. data/lib/ardb/adapter/sqlite.rb +3 -8
  9. data/lib/ardb/adapter_spy.rb +67 -87
  10. data/lib/ardb/cli.rb +11 -219
  11. data/lib/ardb/{clirb.rb → cli/clirb.rb} +2 -1
  12. data/lib/ardb/cli/commands.rb +275 -0
  13. data/lib/ardb/migration.rb +8 -6
  14. data/lib/ardb/migration_helpers.rb +1 -1
  15. data/lib/ardb/pg_json.rb +90 -0
  16. data/lib/ardb/version.rb +1 -1
  17. data/test/helper.rb +15 -3
  18. data/test/support/factory.rb +15 -0
  19. data/test/support/fake_schema.rb +5 -0
  20. data/test/support/postgresql/migrations/.gitkeep +0 -0
  21. data/test/support/postgresql/pg_json_migrations/20160519133432_create_pg_json_migrate_test.rb +13 -0
  22. data/test/support/postgresql/schema.rb +3 -0
  23. data/test/support/postgresql/setup_test_db.rb +51 -0
  24. data/test/support/relative_require_test_db_file.rb +2 -0
  25. data/test/support/require_test_db_file.rb +1 -0
  26. data/test/system/pg_json_tests.rb +85 -0
  27. data/test/unit/adapter/base_tests.rb +104 -39
  28. data/test/unit/adapter/mysql_tests.rb +2 -1
  29. data/test/unit/adapter/postgresql_tests.rb +10 -9
  30. data/test/unit/adapter/sqlite_tests.rb +8 -3
  31. data/test/unit/adapter_spy_tests.rb +57 -66
  32. data/test/unit/ardb_tests.rb +323 -36
  33. data/test/unit/cli_tests.rb +193 -146
  34. data/test/unit/has_slug_tests.rb +9 -9
  35. data/test/unit/migration_helpers_tests.rb +18 -12
  36. data/test/unit/migration_tests.rb +18 -11
  37. data/test/unit/pg_json_tests.rb +39 -0
  38. data/test/unit/record_spy_tests.rb +1 -1
  39. data/test/unit/test_helpers_tests.rb +2 -6
  40. data/test/unit/use_db_default_tests.rb +2 -2
  41. metadata +29 -34
  42. data/lib/ardb/root_path.rb +0 -15
  43. data/test/unit/config_tests.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: efed4edb38eade9eaa2de6263e30f163b4ffa3db
4
- data.tar.gz: 41bb43c7936a806124cdeb747d78c6a4de2393e4
3
+ data.tar.gz: 33194d527399daa093277e134bbcda8dee5c6069
4
+ metadata.gz: 7718eb32a25016d2d620a820b5a2b04244445b6a
5
5
  SHA512:
6
- metadata.gz: ba2ed871805feac6de258476b78dc906c63b6a4491b8ab24925dc87447e19f4e89f073b6642729d8ec863a3b760257293da95ed4aa7e8d2b3f7d09aedc86cefe
7
- data.tar.gz: f521735072f0ce180c0073593af0aefc5ae16cc3bcab8ed5c0dcf7677f1da6d818fa8b051c1f91fa07b18626582b4beeec021810a51223f6ca538d503c9fb7bb
6
+ data.tar.gz: 1597717aba91e83109628879b8ab51c52a81fe47c9f8182bf8bff32e91b7fe30f72a0543d97e1200b77926824b1d669790144fc3bf39bb9e9a30a95110192a69
7
+ metadata.gz: 02366a02d6aff1a513ea34969017cc07b56be184e906a7cb34b446811c6d4ebaa6fb97f6eddd04344b3f4d2dbca51624c4c57316f996e1b6b98809826e5d03f4
data/Gemfile CHANGED
@@ -2,8 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'pry', "~> 0.9.0"
5
+ gem 'pg', "~> 0.17.1"
6
+ gem 'pry', "~> 0.9.0"
6
7
 
7
8
  # Lock down gem versions because they require a newer version of ruby
8
9
  gem 'i18n', "< 0.7"
9
10
 
11
+ platform :ruby_18 do
12
+ gem 'json', '~> 1.8'
13
+ end
@@ -18,12 +18,11 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
20
 
21
- gem.add_development_dependency("assert", ["~> 2.15.1"])
21
+ gem.add_development_dependency("assert", ["~> 2.16.1"])
22
22
 
23
23
  gem.add_dependency('activerecord', ["~> 3.2"])
24
24
  gem.add_dependency('activesupport', ["~> 3.2"])
25
- gem.add_dependency('much-plugin', ["~> 0.1.0"])
26
- gem.add_dependency('ns-options', ["~> 1.1.6"])
27
- gem.add_dependency('scmd', ["~> 3.0.1"])
25
+ gem.add_dependency('much-plugin', ["~> 0.1.1"])
26
+ gem.add_dependency('scmd', ["~> 3.0.2"])
28
27
 
29
28
  end
@@ -1,115 +1,182 @@
1
- require 'pathname'
2
- require 'singleton'
3
1
  require 'active_record'
4
- require 'ns-options'
2
+ require 'logger'
5
3
 
6
4
  require 'ardb/version'
7
- require 'ardb/root_path'
8
5
 
9
6
  ENV['ARDB_DB_FILE'] ||= 'config/db'
10
7
 
11
8
  module Ardb
12
- NotConfiguredError = Class.new(RuntimeError)
13
9
 
14
- def self.config; Config; end
15
- def self.configure(&block); Config.define(&block); end
16
-
17
- def self.adapter; Adapter.current; end
10
+ def self.config
11
+ @config ||= Config.new
12
+ end
18
13
 
19
- def self.validate!
20
- if !self.config.required_set?
21
- raise NotConfiguredError, "missing required configs"
22
- end
14
+ def self.configure(&block)
15
+ self.config.tap(&block)
23
16
  end
24
17
 
18
+ def self.adapter; @adapter; end
19
+
25
20
  def self.init(establish_connection = true)
26
21
  require 'ardb/require_autoloaded_active_record_files'
27
- require self.config.db_file
28
- validate!
29
- Adapter.init
22
+ begin
23
+ require_db_file
24
+ rescue InvalidDBFileError => exception
25
+ raise exception.tap{ |e| e.set_backtrace(caller) }
26
+ end
27
+
28
+ self.config.validate!
29
+ @adapter = Adapter.new(self.config)
30
30
 
31
31
  # setup AR
32
32
  ActiveRecord::Base.logger = self.config.logger
33
- if establish_connection
34
- ActiveRecord::Base.establish_connection(self.config.db_settings)
35
- end
33
+ self.adapter.connect_db if establish_connection
36
34
  end
37
35
 
38
36
  def self.escape_like_pattern(pattern, escape_char = nil)
39
37
  self.adapter.escape_like_pattern(pattern, escape_char)
40
38
  end
41
39
 
42
- class Config
43
- include NsOptions::Proxy
44
-
45
- namespace :db do
46
- option :adapter, String, :required => true
47
- option :database, String, :required => true
48
- option :encoding, String, :required => false
49
- option :host, String, :required => false
50
- option :port, Integer, :required => false
51
- option :username, String, :required => false
52
- option :password, String, :required => false
53
- option :pool, Integer, :required => false
54
- option :checkout_timeout, Integer, :required => false
40
+ private
41
+
42
+ # try requiring the db file via the load path or as an absolute path, if
43
+ # that fails it tries requiring relative to the current working directory
44
+ def self.require_db_file
45
+ begin
46
+ require ENV['ARDB_DB_FILE']
47
+ rescue LoadError
48
+ require File.expand_path(ENV['ARDB_DB_FILE'], ENV['PWD'])
55
49
  end
50
+ rescue LoadError
51
+ raise InvalidDBFileError, "can't require `#{ENV['ARDB_DB_FILE']}`, " \
52
+ "check that the ARDB_DB_FILE env var is set to " \
53
+ "the file path of your db file"
54
+ end
56
55
 
57
- option :db_file, Pathname, :default => ENV['ARDB_DB_FILE']
58
- option :root_path, Pathname, :required => true
59
- option :logger, :required => true
60
- option :migrations_path, RootPath, :default => proc{ "db/migrations" }
61
- option :schema_path, RootPath, :default => proc{ "db/schema" }
62
- option :schema_format, Symbol, :default => :ruby
63
-
64
- def self.db_settings
65
- db.to_hash.inject({}) do |settings, (k, v)|
66
- settings[k.to_s] = v if !v.nil?
67
- settings
68
- end
56
+ class Config
57
+
58
+ ACTIVERECORD_ATTRS = [
59
+ :adapter,
60
+ :database,
61
+ :encoding,
62
+ :host,
63
+ :port,
64
+ :username,
65
+ :password,
66
+ :pool,
67
+ :checkout_timeout,
68
+ :min_messages
69
+ ].freeze
70
+ DEFAULT_MIGRATIONS_PATH = 'db/migrations'.freeze
71
+ DEFAULT_SCHEMA_PATH = 'db/schema'.freeze
72
+ RUBY_SCHEMA_FORMAT = :ruby.freeze
73
+ SQL_SCHEMA_FORMAT = :sql.freeze
74
+ VALID_SCHEMA_FORMATS = [RUBY_SCHEMA_FORMAT, SQL_SCHEMA_FORMAT].freeze
75
+
76
+ attr_accessor *ACTIVERECORD_ATTRS
77
+ attr_accessor :logger, :root_path
78
+ attr_reader :schema_format
79
+ attr_writer :migrations_path, :schema_path
80
+
81
+ def initialize
82
+ @logger = Logger.new(STDOUT)
83
+ @root_path = ENV['PWD']
84
+ @migrations_path = DEFAULT_MIGRATIONS_PATH
85
+ @schema_path = DEFAULT_SCHEMA_PATH
86
+ @schema_format = RUBY_SCHEMA_FORMAT
69
87
  end
70
88
 
71
- end
89
+ def migrations_path
90
+ File.expand_path(@migrations_path.to_s, @root_path.to_s)
91
+ end
72
92
 
73
- class Adapter
74
- include Singleton
93
+ def schema_path
94
+ File.expand_path(@schema_path.to_s, @root_path.to_s)
95
+ end
75
96
 
76
- attr_accessor :current
97
+ def schema_format=(new_value)
98
+ @schema_format = begin
99
+ new_value.to_sym
100
+ rescue NoMethodError
101
+ raise ArgumentError, "schema format must be a `Symbol`", caller
102
+ end
103
+ end
77
104
 
78
- def init
79
- @current = Adapter.send(Ardb.config.db.adapter)
105
+ def activerecord_connect_hash
106
+ ACTIVERECORD_ATTRS.inject({}) do |h, attr_name|
107
+ value = self.send(attr_name)
108
+ !value.nil? ? h.merge!(attr_name.to_s => value) : h
109
+ end
80
110
  end
81
111
 
82
- def reset
83
- @current = nil
112
+ def validate!
113
+ if self.adapter.to_s.empty? || self.database.to_s.empty?
114
+ raise ConfigurationError, "an adapter and database must be provided"
115
+ elsif !VALID_SCHEMA_FORMATS.include?(self.schema_format)
116
+ raise ConfigurationError, "schema format must be one of: " \
117
+ "#{VALID_SCHEMA_FORMATS.join(', ')}"
118
+ end
119
+ true
84
120
  end
85
121
 
86
- def sqlite
87
- require 'ardb/adapter/sqlite'
88
- Adapter::Sqlite.new
122
+ def ==(other)
123
+ if other.kind_of?(self.class)
124
+ self.activerecord_connect_hash == other.activerecord_connect_hash &&
125
+ self.logger == other.logger &&
126
+ self.root_path == other.root_path &&
127
+ self.schema_format == other.schema_format &&
128
+ self.migrations_path == other.migrations_path &&
129
+ self.schema_path == other.schema_path
130
+ else
131
+ super
132
+ end
89
133
  end
90
- alias_method :sqlite3, :sqlite
91
134
 
92
- def postgresql
93
- require 'ardb/adapter/postgresql'
94
- Adapter::Postgresql.new
135
+ end
136
+
137
+ module Adapter
138
+
139
+ VALID_ADAPTERS = [
140
+ 'sqlite',
141
+ 'sqlite3',
142
+ 'postgresql',
143
+ 'postgres',
144
+ 'mysql',
145
+ 'mysql2'
146
+ ].freeze
147
+
148
+ def self.new(config)
149
+ if !VALID_ADAPTERS.include?(config.adapter)
150
+ raise InvalidAdapterError, "invalid adapter: `#{config.adapter}`"
151
+ end
152
+ self.send(config.adapter, config)
95
153
  end
96
154
 
97
- def mysql
98
- require 'ardb/adapter/mysql'
99
- Adapter::Mysql.new
155
+ def self.sqlite(config)
156
+ require 'ardb/adapter/sqlite'
157
+ Adapter::Sqlite.new(config)
100
158
  end
101
- alias_method :mysql2, :mysql
102
159
 
103
- # nice singleton api
160
+ def self.sqlite3(config); self.sqlite(config); end
104
161
 
105
- def self.method_missing(method, *args, &block)
106
- self.instance.send(method, *args, &block)
162
+ def self.postgresql(config)
163
+ require 'ardb/adapter/postgresql'
164
+ Adapter::Postgresql.new(config)
107
165
  end
108
166
 
109
- def self.respond_to?(method)
110
- super || self.instance.respond_to?(method)
167
+ def self.postgres(config); self.postgresql(config); end
168
+
169
+ def self.mysql(config)
170
+ require 'ardb/adapter/mysql'
171
+ Adapter::Mysql.new(config)
111
172
  end
112
173
 
174
+ def self.mysql2(config); self.mysql(config); end
175
+
113
176
  end
114
177
 
178
+ InvalidDBFileError = Class.new(ArgumentError)
179
+ ConfigurationError = Class.new(ArgumentError)
180
+ InvalidAdapterError = Class.new(RuntimeError)
181
+
115
182
  end
@@ -1,18 +1,27 @@
1
+ require 'ardb'
2
+
1
3
  module Ardb; end
2
- class Ardb::Adapter
4
+ module Ardb::Adapter
3
5
 
4
6
  class Base
5
7
 
6
- attr_reader :config_settings, :database
7
- attr_reader :schema_format, :ruby_schema_path, :sql_schema_path
8
+ attr_reader :config
9
+
10
+ def initialize(config)
11
+ @config = config
12
+ end
13
+
14
+ def connect_hash; self.config.activerecord_connect_hash; end
15
+ def database; self.config.database; end
16
+ def migrations_path; self.config.migrations_path; end
17
+ def schema_format; self.config.schema_format; end
18
+
19
+ def ruby_schema_path
20
+ @ruby_schema_path ||= "#{self.config.schema_path}.rb"
21
+ end
8
22
 
9
- def initialize
10
- @config_settings = Ardb.config.db_settings
11
- @database = Ardb.config.db.database
12
- @schema_format = Ardb.config.schema_format
13
- schema_path = Ardb.config.schema_path
14
- @ruby_schema_path = "#{schema_path}.rb"
15
- @sql_schema_path = "#{schema_path}.sql"
23
+ def sql_schema_path
24
+ @sql_schema_path ||= "#{self.config.schema_path}.sql"
16
25
  end
17
26
 
18
27
  def escape_like_pattern(pattern, escape_char = nil)
@@ -29,14 +38,18 @@ class Ardb::Adapter
29
38
  def create_db(*args); raise NotImplementedError; end
30
39
  def drop_db(*args); raise NotImplementedError; end
31
40
 
41
+ def drop_tables(*args); raise NotImplementedError; end
42
+
32
43
  def connect_db
33
- ActiveRecord::Base.connection
44
+ ActiveRecord::Base.establish_connection(self.connect_hash)
45
+ # checkout a connection to ensure we can connect to the DB, we don't do
46
+ # anything with the connection and immediately check it back in
47
+ ActiveRecord::Base.connection_pool.with_connection{ }
34
48
  end
35
49
 
36
50
  def migrate_db
37
51
  verbose = ENV["MIGRATE_QUIET"].nil?
38
52
  version = ENV["MIGRATE_VERSION"] ? ENV["MIGRATE_VERSION"].to_i : nil
39
- migrations_path = Ardb.config.migrations_path
40
53
 
41
54
  if defined?(ActiveRecord::Migration::CommandRecorder)
42
55
  require 'ardb/migration_helpers'
@@ -45,26 +58,24 @@ class Ardb::Adapter
45
58
  end
46
59
  end
47
60
 
48
- ActiveRecord::Migrator.migrations_path = migrations_path
61
+ ActiveRecord::Migrator.migrations_path = self.migrations_path
49
62
  ActiveRecord::Migration.verbose = verbose
50
- ActiveRecord::Migrator.migrate(migrations_path, version) do |migration|
63
+ ActiveRecord::Migrator.migrate(self.migrations_path, version) do |migration|
51
64
  ENV["MIGRATE_SCOPE"].blank? || (ENV["MIGRATE_SCOPE"] == migration.scope)
52
65
  end
53
66
  end
54
67
 
55
- def drop_tables(*args); raise NotImplementedError; end
56
-
57
68
  def load_schema
58
69
  # silence STDOUT
59
70
  current_stdout = $stdout.dup
60
71
  $stdout = File.new('/dev/null', 'w')
61
- load_ruby_schema if @schema_format == :ruby
62
- load_sql_schema if @schema_format == :sql
72
+ load_ruby_schema if self.schema_format == Ardb::Config::RUBY_SCHEMA_FORMAT
73
+ load_sql_schema if self.schema_format == Ardb::Config::SQL_SCHEMA_FORMAT
63
74
  $stdout = current_stdout
64
75
  end
65
76
 
66
77
  def load_ruby_schema
67
- load @ruby_schema_path
78
+ load self.ruby_schema_path
68
79
  end
69
80
 
70
81
  def load_sql_schema
@@ -76,14 +87,14 @@ class Ardb::Adapter
76
87
  current_stdout = $stdout.dup
77
88
  $stdout = File.new('/dev/null', 'w')
78
89
  dump_ruby_schema
79
- dump_sql_schema if @schema_format == :sql
90
+ dump_sql_schema if self.schema_format == Ardb::Config::SQL_SCHEMA_FORMAT
80
91
  $stdout = current_stdout
81
92
  end
82
93
 
83
94
  def dump_ruby_schema
84
95
  require 'active_record/schema_dumper'
85
- FileUtils.mkdir_p File.dirname(@ruby_schema_path)
86
- File.open(@ruby_schema_path, 'w:utf-8') do |file|
96
+ FileUtils.mkdir_p File.dirname(self.ruby_schema_path)
97
+ File.open(self.ruby_schema_path, 'w:utf-8') do |file|
87
98
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
88
99
  end
89
100
  end
@@ -92,8 +103,12 @@ class Ardb::Adapter
92
103
  raise NotImplementedError
93
104
  end
94
105
 
95
- def ==(other_adapter)
96
- self.class == other_adapter.class
106
+ def ==(other)
107
+ if other.kind_of?(self.class)
108
+ self.config == other.config
109
+ else
110
+ super
111
+ end
97
112
  end
98
113
 
99
114
  end
@@ -1,7 +1,6 @@
1
- require 'ardb'
2
1
  require 'ardb/adapter/base'
3
2
 
4
- class Ardb::Adapter
3
+ module Ardb::Adapter
5
4
 
6
5
  class Mysql < Base
7
6
 
@@ -1,26 +1,28 @@
1
- require 'ardb'
2
1
  require 'ardb/adapter/base'
3
2
 
4
- class Ardb::Adapter
3
+ module Ardb::Adapter
5
4
 
6
5
  class Postgresql < Base
7
6
 
8
- def public_schema_settings
9
- self.config_settings.merge({
7
+ # the 'postgres' db is a "public" (doesn't typically require auth/grants to
8
+ # connect to) db that typically exists for all postgres installations; the
9
+ # adapter uses it to create/drop other databases
10
+ def public_connect_hash
11
+ @public_connect_hash ||= self.connect_hash.merge({
10
12
  'database' => 'postgres',
11
13
  'schema_search_path' => 'public'
12
14
  })
13
15
  end
14
16
 
15
17
  def create_db
16
- ActiveRecord::Base.establish_connection(self.public_schema_settings)
17
- ActiveRecord::Base.connection.create_database(self.database, self.config_settings)
18
- ActiveRecord::Base.establish_connection(self.config_settings)
18
+ ActiveRecord::Base.establish_connection(self.public_connect_hash)
19
+ ActiveRecord::Base.connection.create_database(self.database, self.connect_hash)
20
+ ActiveRecord::Base.establish_connection(self.connect_hash)
19
21
  end
20
22
 
21
23
  def drop_db
22
24
  begin
23
- ActiveRecord::Base.establish_connection(self.public_schema_settings)
25
+ ActiveRecord::Base.establish_connection(self.public_connect_hash)
24
26
  ActiveRecord::Base.connection.tap do |conn|
25
27
  conn.execute "UPDATE pg_catalog.pg_database"\
26
28
  " SET datallowconn=false WHERE datname='#{self.database}'"
@@ -74,10 +76,10 @@ class Ardb::Adapter
74
76
 
75
77
  def env_var_hash
76
78
  @env_var_hash ||= {
77
- 'PGHOST' => self.config_settings['host'],
78
- 'PGPORT' => self.config_settings['port'],
79
- 'PGUSER' => self.config_settings['username'],
80
- 'PGPASSWORD' => self.config_settings['password']
79
+ 'PGHOST' => self.connect_hash['host'],
80
+ 'PGPORT' => self.connect_hash['port'],
81
+ 'PGUSER' => self.connect_hash['username'],
82
+ 'PGPASSWORD' => self.connect_hash['password']
81
83
  }
82
84
  end
83
85