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
@@ -1,4 +1,5 @@
1
- module Ardb
1
+ module Ardb; end
2
+ class Ardb::CLI
2
3
 
3
4
  class CLIRB # Version 1.0.0, https://github.com/redding/cli.rb
4
5
  Error = Class.new(RuntimeError);
@@ -0,0 +1,275 @@
1
+ require 'ardb'
2
+ require 'ardb/cli/clirb'
3
+ require 'much-plugin'
4
+
5
+ module Ardb; end
6
+ class Ardb::CLI
7
+
8
+ InvalidCommandError = Class.new(ArgumentError)
9
+ CommandExitError = Class.new(RuntimeError)
10
+
11
+ class InvalidCommand
12
+
13
+ attr_reader :name, :clirb
14
+
15
+ def initialize(name)
16
+ @name = name
17
+ @clirb = CLIRB.new
18
+ end
19
+
20
+ def new; self; end
21
+
22
+ def run(argv)
23
+ @clirb.parse!([@name, argv].flatten.compact)
24
+ raise CLIRB::HelpExit if @name.to_s.empty?
25
+ raise InvalidCommandError, "'#{self.name}' is not a command."
26
+ end
27
+
28
+ def help
29
+ "Usage: ardb [COMMAND] [options]\n\n" \
30
+ "Options: #{@clirb}\n" \
31
+ "Commands:\n" \
32
+ "#{COMMANDS.to_s.split("\n").map{ |l| " #{l}" }.join("\n")}\n"
33
+ end
34
+
35
+ end
36
+
37
+ module ValidCommand
38
+ include MuchPlugin
39
+
40
+ plugin_included do
41
+ include InstanceMethods
42
+ end
43
+
44
+ module InstanceMethods
45
+
46
+ def initialize(&clirb_build)
47
+ @clirb = CLIRB.new(&clirb_build)
48
+ end
49
+
50
+ def clirb; @clirb; end
51
+
52
+ def run(argv, stdout = nil, stderr = nil)
53
+ @clirb.parse!(argv)
54
+ @stdout = stdout || $stdout
55
+ @stderr = stderr || $stderr
56
+ end
57
+
58
+ def summary
59
+ ''
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ class ConnectCommand
67
+ include ValidCommand
68
+
69
+ def run(argv, *args)
70
+ super
71
+
72
+ Ardb.init(false)
73
+ begin
74
+ Ardb.adapter.connect_db
75
+ @stdout.puts "connected to #{Ardb.config.adapter} db `#{Ardb.config.database}`"
76
+ rescue StandardError => e
77
+ @stderr.puts e
78
+ @stderr.puts e.backtrace.join("\n")
79
+ @stderr.puts "error connecting to #{Ardb.config.database.inspect} database " \
80
+ "with #{Ardb.config.activerecord_connect_hash.inspect}"
81
+ raise CommandExitError
82
+ end
83
+ 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
+ end
97
+
98
+ class CreateCommand
99
+ include ValidCommand
100
+
101
+ def run(argv, *args)
102
+ super
103
+
104
+ Ardb.init(false)
105
+ begin
106
+ Ardb.adapter.create_db
107
+ @stdout.puts "created #{Ardb.config.adapter} db `#{Ardb.config.database}`"
108
+ rescue StandardError => e
109
+ @stderr.puts e
110
+ @stderr.puts "error creating #{Ardb.config.database.inspect} database"
111
+ raise CommandExitError
112
+ end
113
+ 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
+ end
127
+
128
+ class DropCommand
129
+ include ValidCommand
130
+
131
+ def run(argv, *args)
132
+ super
133
+
134
+ Ardb.init(true)
135
+ begin
136
+ Ardb.adapter.drop_db
137
+ @stdout.puts "dropped #{Ardb.config.adapter} db `#{Ardb.config.database}`"
138
+ rescue StandardError => e
139
+ @stderr.puts e
140
+ @stderr.puts "error dropping #{Ardb.config.database.inspect} database"
141
+ raise CommandExitError
142
+ end
143
+ 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
+ end
157
+
158
+ class MigrateCommand
159
+ include ValidCommand
160
+
161
+ def run(argv, *args)
162
+ super
163
+
164
+ Ardb.init(true)
165
+ begin
166
+ Ardb.adapter.migrate_db
167
+ Ardb.adapter.dump_schema unless ENV['ARDB_MIGRATE_NO_SCHEMA']
168
+ rescue StandardError => e
169
+ @stderr.puts e
170
+ @stderr.puts e.backtrace.join("\n")
171
+ @stderr.puts "error migrating #{Ardb.config.database.inspect} database"
172
+ raise CommandExitError
173
+ end
174
+ end
175
+
176
+ def summary
177
+ "Migrate the configured DB"
178
+ end
179
+
180
+ def help
181
+ "Usage: ardb migrate [options]\n\n" \
182
+ "Options: #{@clirb}\n" \
183
+ "Description:\n" \
184
+ " #{self.summary}"
185
+ end
186
+
187
+ end
188
+
189
+ class GenerateMigrationCommand
190
+ include ValidCommand
191
+
192
+ def run(argv, *args)
193
+ super
194
+
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
210
+ end
211
+ end
212
+
213
+ def summary
214
+ "Generate a migration file given a MIGRATION-NAME"
215
+ end
216
+
217
+ def help
218
+ "Usage: ardb generate-migration [options] MIGRATION-NAME\n\n" \
219
+ "Options: #{@clirb}\n" \
220
+ "Description:\n" \
221
+ " #{self.summary}"
222
+ end
223
+
224
+ end
225
+
226
+ class CommandSet
227
+
228
+ def initialize(&unknown_cmd_block)
229
+ @lookup = Hash.new{ |h,k| unknown_cmd_block.call(k) }
230
+ @names = []
231
+ @aliases = {}
232
+ @summaries = {}
233
+ end
234
+
235
+ def add(klass, name, *aliases)
236
+ begin
237
+ cmd = klass.new
238
+ rescue StandardError => err
239
+ # don't add any commands you can't init
240
+ else
241
+ ([name] + aliases).each{ |n| @lookup[n] = cmd }
242
+ @to_s = nil
243
+ @names << name
244
+ @aliases[name] = aliases.empty? ? '' : "(#{aliases.join(', ')})"
245
+ @summaries[name] = cmd.summary.to_s.empty? ? '' : "# #{cmd.summary}"
246
+ end
247
+ end
248
+
249
+ def remove(name)
250
+ @lookup.delete(name)
251
+ @names.delete(name)
252
+ @aliases.delete(name)
253
+ @to_s = nil
254
+ end
255
+
256
+ def [](name)
257
+ @lookup[name]
258
+ end
259
+
260
+ def size
261
+ @names.size
262
+ end
263
+
264
+ def to_s
265
+ max_name_size = @names.map{ |n| n.size }.max || 0
266
+ max_alias_size = @aliases.values.map{ |v| v.size }.max || 0
267
+
268
+ @to_s ||= @names.map do |n|
269
+ "#{n.ljust(max_name_size)} #{@aliases[n].ljust(max_alias_size)} #{@summaries[n]}"
270
+ end.join("\n")
271
+ end
272
+
273
+ end
274
+
275
+ end
@@ -4,16 +4,18 @@ module Ardb
4
4
 
5
5
  class Migration
6
6
 
7
- attr_reader :identifier, :class_name, :file_name, :file_path
8
- attr_reader :source
7
+ attr_reader :migrations_path, :identifier
8
+ attr_reader :class_name, :file_name, :file_path, :source
9
9
 
10
- def initialize(identifier)
10
+ def initialize(ardb_config, identifier)
11
11
  raise NoIdentifierError if identifier.to_s.empty?
12
12
 
13
- @identifier = identifier
13
+ @migrations_path = ardb_config.migrations_path
14
+ @identifier = identifier
15
+
14
16
  @class_name = @identifier.classify.pluralize
15
17
  @file_name = get_file_name(@identifier)
16
- @file_path = File.join(Ardb.config.migrations_path, "#{@file_name}.rb")
18
+ @file_path = File.join(self.migrations_path, "#{@file_name}.rb")
17
19
 
18
20
  @source = "require 'ardb/migration_helpers'\n\n" \
19
21
  "class #{@class_name} < ActiveRecord::Migration\n" \
@@ -24,7 +26,7 @@ module Ardb
24
26
  end
25
27
 
26
28
  def save!
27
- FileUtils.mkdir_p Ardb.config.migrations_path
29
+ FileUtils.mkdir_p self.migrations_path
28
30
  File.open(self.file_path, 'w'){ |f| f.write(self.source) }
29
31
  self
30
32
  end
@@ -32,7 +32,7 @@ module Ardb
32
32
  @to_table = to_table.to_s
33
33
  @to_column = (options[:to_column] || 'id').to_s
34
34
  @name = (options[:name] || "fk_#{@from_table}_#{@from_column}").to_s
35
- @adapter = Ardb::Adapter.send(Ardb.config.db.adapter)
35
+ @adapter = Ardb::Adapter.new(Ardb.config)
36
36
  end
37
37
 
38
38
  def add_sql
@@ -0,0 +1,90 @@
1
+ require 'active_record'
2
+ require 'active_support'
3
+
4
+ # Allow ActiveRecord to work with PostgreSQL json/jsonb fields, which aren't
5
+ # supported with ActiveRecord 3.2
6
+ # https://github.com/romanbsd/activerecord-postgres-json/blob/master/lib/activerecord-postgres-json/activerecord.rb
7
+ require 'active_record/connection_adapters/postgresql_adapter'
8
+
9
+ module ActiveRecord
10
+ module ConnectionAdapters
11
+ PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:json] = { :name => 'json' }
12
+ PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:jsonb] = { :name => 'jsonb' }
13
+
14
+ class PostgreSQLColumn < Column
15
+ # Adds the json type for the column.
16
+ def simplified_type_with_json(field_type)
17
+ case field_type
18
+ when 'json'
19
+ :json
20
+ when 'jsonb'
21
+ :jsonb
22
+ else
23
+ simplified_type_without_json(field_type)
24
+ end
25
+ end
26
+
27
+ alias_method_chain :simplified_type, :json
28
+
29
+ class << self
30
+ def extract_value_from_default_with_json(default)
31
+ case default
32
+ when "'{}'::json", "'{}'::jsonb"
33
+ '{}'
34
+ when "'[]'::json", "'[]'::jsonb"
35
+ '[]'
36
+ else
37
+ extract_value_from_default_without_json(default)
38
+ end
39
+ end
40
+
41
+ alias_method_chain :extract_value_from_default, :json
42
+ end
43
+
44
+ end
45
+
46
+ class TableDefinition
47
+ # Adds json type for migrations. So you can add columns to a table like:
48
+ # create_table :people do |t|
49
+ # ...
50
+ # t.json :info
51
+ # ...
52
+ # end
53
+ def json(*args)
54
+ options = args.extract_options!
55
+ column_names = args
56
+ column_names.each { |name| column(name, 'json', options) }
57
+ end
58
+
59
+ def jsonb(*args)
60
+ options = args.extract_options!
61
+ column_names = args
62
+ column_names.each { |name| column(name, 'jsonb', options) }
63
+ end
64
+
65
+ end
66
+
67
+ class Table
68
+ # Adds json type for migrations. So you can add columns to a table like:
69
+ # change_table :people do |t|
70
+ # ...
71
+ # t.json :info
72
+ # ...
73
+ # end
74
+ def json(*args)
75
+ options = args.extract_options!
76
+ column_names = args
77
+ column_names.each { |name| column(name, 'json', options) }
78
+ end
79
+
80
+ def jsonb(*args)
81
+ options = args.extract_options!
82
+ column_names = args
83
+ column_names.each { |name| column(name, 'jsonb', options) }
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -1,3 +1,3 @@
1
1
  module Ardb
2
- VERSION = "0.27.3"
2
+ VERSION = "0.28.0"
3
3
  end
@@ -4,10 +4,22 @@
4
4
  # add the root dir to the load path
5
5
  $LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
6
6
 
7
+ TEST_SUPPORT_PATH = File.expand_path("../support", __FILE__)
8
+ TMP_PATH = File.expand_path("../../tmp", __FILE__)
9
+
10
+ require 'logger'
11
+ log_path = File.expand_path("../../log/test.log", __FILE__)
12
+ TEST_LOGGER = Logger.new(File.open(log_path, 'w'))
13
+
7
14
  # require pry for debugging (`binding.pry`)
8
15
  require 'pry'
9
16
  require 'test/support/factory'
10
17
 
11
- ENV['ARDB_DB_FILE'] = 'tmp/testdb/config/db'
12
- require 'ardb'
13
- Ardb.init(false)
18
+ # 1.8.7 backfills
19
+
20
+ # Array#sample
21
+ if !(a = Array.new).respond_to?(:sample) && a.respond_to?(:choice)
22
+ class Array
23
+ alias_method :sample, :choice
24
+ end
25
+ end
@@ -8,4 +8,19 @@ module Factory
8
8
  "#{Factory.string}_things"
9
9
  end
10
10
 
11
+ def self.ardb_config
12
+ Ardb::Config.new.tap do |c|
13
+ c.adapter = Factory.string
14
+ c.database = Factory.string
15
+ c.encoding = Factory.string
16
+ c.host = Factory.string
17
+ c.port = Factory.integer
18
+ c.username = Factory.string
19
+ c.password = Factory.string
20
+ c.pool = Factory.integer
21
+ c.checkout_timeout = Factory.integer
22
+ c.min_messages = Factory.string
23
+ end
24
+ end
25
+
11
26
  end