ardb 0.0.1 → 0.1.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.
@@ -19,4 +19,8 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_development_dependency("assert", ["~> 2.0"])
21
21
 
22
+ gem.add_dependency('activerecord', ["~> 3.2"])
23
+ gem.add_dependency('activesupport', ["~> 3.2"])
24
+ gem.add_dependency('ns-options', ["~> 1.1"])
25
+
22
26
  end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2011-Present Kelly Redding and Collin Redding
4
+ #
5
+
6
+ require 'ardb/cli'
7
+ Ardb::CLI.run *ARGV
@@ -1,3 +1,95 @@
1
+ require 'active_record'
2
+ require 'ns-options'
3
+ require 'pathname'
4
+ require 'singleton'
5
+
1
6
  require "ardb/version"
2
7
 
3
- module Ardb; end
8
+ module Ardb
9
+ NotConfiguredError = Class.new(RuntimeError)
10
+
11
+ def self.config; Config; end
12
+ def self.configure(&block); Config.define(&block); end
13
+
14
+ def self.adapter; Adapter.current; end
15
+
16
+ def self.validate!
17
+ if !self.config.required_set?
18
+ raise NotConfiguredError, "missing required configs"
19
+ end
20
+ end
21
+
22
+ def self.init(connection=true)
23
+ validate!
24
+ Adapter.init
25
+
26
+ # setup AR
27
+ ActiveRecord::Base.logger = self.config.logger
28
+ ActiveRecord::Base.establish_connection(self.config.db.to_hash) if connection
29
+ end
30
+
31
+ class Config
32
+ include NsOptions::Proxy
33
+
34
+ namespace :db do
35
+ option :adapter, String, :required => true
36
+ option :database, String, :required => true
37
+ option :encoding, String, :required => false
38
+ option :url, String, :required => false
39
+ option :username, String, :required => false
40
+ option :password, String, :required => false
41
+ end
42
+
43
+ option :root_path, Pathname, :required => true
44
+ option :logger, :required => true
45
+ option :migrations_path, String, :default => proc{ default_migrations_path }
46
+ option :schema_path, String, :default => proc{ default_schema_path }
47
+
48
+ def self.default_migrations_path; root_path.join("db/migrations"); end
49
+ def self.default_schema_path; root_path.join("db/schema.rb"); end
50
+
51
+ end
52
+
53
+ class Adapter
54
+ include Singleton
55
+
56
+ attr_reader :current
57
+
58
+ def init
59
+ @current = Adapter.send(Ardb.config.db.adapter)
60
+ end
61
+
62
+ def reset
63
+ @current = nil
64
+ end
65
+
66
+ def sqlite
67
+ require 'ardb/adapter/sqlite'
68
+ Adapter::Sqlite.new
69
+ end
70
+ alias_method :sqlite3, :sqlite
71
+
72
+ def postgresql
73
+ require 'ardb/adapter/postgresql'
74
+ Adapter::Postgresql.new
75
+ end
76
+
77
+ def mysql
78
+ require 'ardb/adapter/mysql'
79
+ Adapter::Mysql.new
80
+ end
81
+ alias_method :mysql2, :mysql
82
+
83
+ # nice singleton api
84
+
85
+ def self.method_missing(method, *args, &block)
86
+ self.instance.send(method, *args, &block)
87
+ end
88
+
89
+ def self.respond_to?(method)
90
+ super || self.instance.respond_to?(method)
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,24 @@
1
+ module Ardb; end
2
+ class Ardb::Adapter; end
3
+ class Ardb::Adapter::Base
4
+
5
+ attr_reader :config_settings, :database
6
+
7
+ def initialize
8
+ @config_settings = Ardb.config.db.to_hash
9
+ @database = Ardb.config.db.database
10
+ end
11
+
12
+ def foreign_key_add_sql(*args); raise NotImplementedError; end
13
+ def foreign_key_drop_sql(*args); raise NotImplementedError; end
14
+
15
+ def create_db(*args); raise NotImplementedError; end
16
+ def drop_db(*args); raise NotImplementedError; end
17
+
18
+ def drop_tables(*args); raise NotImplementedError; end
19
+
20
+ def ==(other_adapter)
21
+ self.class == other_adapter.class
22
+ end
23
+
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'ardb'
2
+ require 'ardb/adapter/base'
3
+
4
+ class Ardb::Adapter
5
+
6
+ class Mysql < Base
7
+
8
+ def foreign_key_add_sql
9
+ "ALTER TABLE :from_table"\
10
+ " ADD CONSTRAINT :name"\
11
+ " FOREIGN KEY (:from_column)"\
12
+ " REFERENCES :to_table (:to_column)"
13
+ end
14
+
15
+ def foreign_key_drop_sql
16
+ "ALTER TABLE :from_table"\
17
+ " DROP FOREIGN KEY :name"
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,49 @@
1
+ require 'ardb'
2
+ require 'ardb/adapter/base'
3
+
4
+ class Ardb::Adapter
5
+
6
+ class Postgresql < Base
7
+
8
+ def public_schema_settings
9
+ self.config_settings.merge({
10
+ :database => 'postgres',
11
+ :schema_search_path => 'public'
12
+ })
13
+ end
14
+
15
+ 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)
19
+ end
20
+
21
+ def drop_db
22
+ ActiveRecord::Base.establish_connection(self.public_schema_settings)
23
+ ActiveRecord::Base.connection.drop_database(self.database)
24
+ end
25
+
26
+ def drop_tables
27
+ ActiveRecord::Base.connection.tap do |conn|
28
+ tables = conn.execute "SELECT table_name"\
29
+ " FROM information_schema.tables"\
30
+ " WHERE table_schema = 'public';"
31
+ tables.each{ |row| conn.execute "DROP TABLE #{row['table_name']} CASCADE" }
32
+ end
33
+ end
34
+
35
+ def foreign_key_add_sql
36
+ "ALTER TABLE :from_table"\
37
+ " ADD CONSTRAINT :name"\
38
+ " FOREIGN KEY (:from_column)"\
39
+ " REFERENCES :to_table (:to_column)"
40
+ end
41
+
42
+ def foreign_key_drop_sql
43
+ "ALTER TABLE :from_table"\
44
+ " DROP CONSTRAINT :name"
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,36 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'ardb'
4
+ require 'ardb/adapter/base'
5
+
6
+ class Ardb::Adapter
7
+
8
+ class Sqlite < Base
9
+
10
+ def db_file_path
11
+ if (path = Pathname.new(self.database)).absolute?
12
+ path.to_s
13
+ else
14
+ Ardb.config.root_path.join(path).to_s
15
+ end
16
+ end
17
+
18
+ def validate!
19
+ if File.exist?(self.db_file_path)
20
+ raise Ardb::Runner::CmdError, "#{self.database} already exists"
21
+ end
22
+ end
23
+
24
+ def create_db
25
+ validate!
26
+ FileUtils.mkdir_p File.dirname(self.db_file_path)
27
+ ActiveRecord::Base.establish_connection(self.config_settings)
28
+ end
29
+
30
+ def drop_db
31
+ FileUtils.rm(self.db_file_path) if File.exist?(self.db_file_path)
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,113 @@
1
+ require 'ardb/version'
2
+ require 'ardb/runner'
3
+
4
+ module Ardb
5
+
6
+ class CLI
7
+
8
+ def self.run(*args)
9
+ self.new.run(*args)
10
+ end
11
+
12
+ def initialize
13
+ @cli = CLIRB.new do
14
+ option 'root_path', 'root path Ardb should use (`Dir.pwd`)', {
15
+ :abbrev => 'p', :value => String
16
+ }
17
+ end
18
+ end
19
+
20
+ def run(*args)
21
+ begin
22
+ @cli.parse!(args)
23
+ Ardb::Runner.new(@cli.args, @cli.opts).run
24
+ rescue CLIRB::HelpExit
25
+ puts help
26
+ rescue CLIRB::VersionExit
27
+ puts Ardb::VERSION
28
+ rescue Ardb::Runner::UnknownCmdError => err
29
+ $stderr.puts "#{err.message}\n\n"
30
+ $stderr.puts help
31
+ exit(1)
32
+ rescue Ardb::NotConfiguredError, Ardb::Runner::CmdError => err
33
+ $stderr.puts "#{err.message}"
34
+ exit(1)
35
+ rescue Ardb::Runner::CmdFail => err
36
+ exit(1)
37
+ rescue CLIRB::Error => exception
38
+ $stderr.puts "#{exception.message}\n\n"
39
+ $stderr.puts help
40
+ exit(1)
41
+ rescue Exception => exception
42
+ $stderr.puts "#{exception.class}: #{exception.message}"
43
+ $stderr.puts exception.backtrace.join("\n")
44
+ exit(1)
45
+ end
46
+ exit(0)
47
+ end
48
+
49
+ def help
50
+ "Usage: ardb [options] COMMAND\n"\
51
+ "\n"\
52
+ "Options:"\
53
+ "#{@cli}"
54
+ end
55
+
56
+ end
57
+
58
+ class CLIRB # Version 1.0.0, https://github.com/redding/cli.rb
59
+ Error = Class.new(RuntimeError);
60
+ HelpExit = Class.new(RuntimeError); VersionExit = Class.new(RuntimeError)
61
+ attr_reader :argv, :args, :opts, :data
62
+
63
+ def initialize(&block)
64
+ @options = []; instance_eval(&block) if block
65
+ require 'optparse'
66
+ @data, @args, @opts = [], [], {}; @parser = OptionParser.new do |p|
67
+ p.banner = ''; @options.each do |o|
68
+ @opts[o.name] = o.value; p.on(*o.parser_args){ |v| @opts[o.name] = v }
69
+ end
70
+ p.on_tail('--version', ''){ |v| raise VersionExit, v.to_s }
71
+ p.on_tail('--help', ''){ |v| raise HelpExit, v.to_s }
72
+ end
73
+ end
74
+
75
+ def option(*args); @options << Option.new(*args); end
76
+ def parse!(argv)
77
+ @args = (argv || []).dup.tap do |args_list|
78
+ begin; @parser.parse!(args_list)
79
+ rescue OptionParser::ParseError => err; raise Error, err.message; end
80
+ end; @data = @args + [@opts]
81
+ end
82
+ def to_s; @parser.to_s; end
83
+ def inspect
84
+ "#<#{self.class}:#{'0x0%x' % (object_id << 1)} @data=#{@data.inspect}>"
85
+ end
86
+
87
+ class Option
88
+ attr_reader :name, :opt_name, :desc, :abbrev, :value, :klass, :parser_args
89
+
90
+ def initialize(name, *args)
91
+ settings, @desc = args.last.kind_of?(::Hash) ? args.pop : {}, args.pop || ''
92
+ @name, @opt_name, @abbrev = parse_name_values(name, settings[:abbrev])
93
+ @value, @klass = gvalinfo(settings[:value])
94
+ @parser_args = if [TrueClass, FalseClass, NilClass].include?(@klass)
95
+ ["-#{@abbrev}", "--[no-]#{@opt_name}", @desc]
96
+ else
97
+ ["-#{@abbrev}", "--#{@opt_name} #{@opt_name.upcase}", @klass, @desc]
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def parse_name_values(name, custom_abbrev)
104
+ [ (processed_name = name.to_s.strip.downcase), processed_name.gsub('_', '-'),
105
+ custom_abbrev || processed_name.gsub(/[^a-z]/, '').chars.first || 'a'
106
+ ]
107
+ end
108
+ def gvalinfo(v); v.kind_of?(Class) ? [nil,gklass(v)] : [v,gklass(v.class)]; end
109
+ def gklass(k); k == Fixnum ? Integer : k; end
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,74 @@
1
+ require 'ardb'
2
+
3
+ module Ardb; end
4
+ module Ardb::MigrationHelpers
5
+ module_function
6
+
7
+ def foreign_key(from_table, from_column, to_table, options={})
8
+ fk = ForeignKey.new(from_table, from_column, to_table, options)
9
+ execute(fk.add_sql)
10
+ end
11
+
12
+ def drop_foreign_key(*args)
13
+ from_table, from_column = args[0..1]
14
+ options = args.last.kind_of?(Hash) ? args.last : {}
15
+ fk = ForeignKey.new(from_table, from_column, nil, options)
16
+ execute(fk.drop_sql)
17
+ end
18
+
19
+ def remove_column_with_fk(table, column)
20
+ drop_foreign_key(table, column)
21
+ remove_column(table, column)
22
+ end
23
+
24
+ class ForeignKey
25
+ attr_reader :from_table, :from_column, :to_table, :to_column, :name, :adapter
26
+
27
+ def initialize(from_table, from_column, to_table, options=nil)
28
+ options ||= {}
29
+ @from_table = from_table.to_s
30
+ @from_column = from_column.to_s
31
+ @to_table = to_table.to_s
32
+ @to_column = (options[:to_column] || 'id').to_s
33
+ @name = (options[:name] || "fk_#{@from_table}_#{@from_column}").to_s
34
+ @adapter = Ardb::Adapter.send(Ardb.config.db.adapter)
35
+ end
36
+
37
+ def add_sql
38
+ apply_data(@adapter.foreign_key_add_sql)
39
+ end
40
+
41
+ def drop_sql
42
+ apply_data(@adapter.foreign_key_drop_sql)
43
+ end
44
+
45
+ private
46
+
47
+ def apply_data(template_sql)
48
+ template_sql.
49
+ gsub(':from_table', @from_table).
50
+ gsub(':from_column', @from_column).
51
+ gsub(':to_table', @to_table).
52
+ gsub(':to_column', @to_column).
53
+ gsub(':name', @name)
54
+ end
55
+ end
56
+
57
+ # This file will setup the AR migration command recorder for being able to change our
58
+ # stuff, require it in an initializer
59
+
60
+ module RecorderMixin
61
+
62
+ def foreign_key(*args)
63
+ record(:foreign_key, args)
64
+ end
65
+
66
+ protected
67
+
68
+ def invert_foreign_key(args)
69
+ [ :drop_foreign_key, args ]
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,65 @@
1
+ require 'ardb'
2
+
3
+ module Ardb; end
4
+ class Ardb::Runner
5
+ UnknownCmdError = Class.new(ArgumentError)
6
+ CmdError = Class.new(RuntimeError)
7
+ CmdFail = Class.new(RuntimeError)
8
+
9
+ attr_reader :cmd_name, :cmd_args, :opts, :root_path
10
+
11
+ def initialize(args, opts)
12
+ @opts = opts
13
+ @cmd_name = args.shift || ""
14
+ @cmd_args = args
15
+ @root_path = @opts.delete('root_path') || Dir.pwd
16
+ end
17
+
18
+ def run
19
+ setup_run
20
+ case @cmd_name
21
+ when 'migrate'
22
+ require 'ardb/runner/migrate_command'
23
+ MigrateCommand.new.run
24
+ when 'generate'
25
+ require 'ardb/runner/generate_command'
26
+ GenerateCommand.new(@cmd_args).run
27
+ when 'create'
28
+ require 'ardb/runner/create_command'
29
+ CreateCommand.new.run
30
+ when 'drop'
31
+ require 'ardb/runner/drop_command'
32
+ DropCommand.new.run
33
+ when 'null'
34
+ NullCommand.new.run
35
+ else
36
+ raise UnknownCmdError, "unknown command `#{@cmd_name}`"
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def setup_run
43
+ Ardb.config.root_path = @root_path
44
+ DbConfigFile.new.require_if_exists
45
+ Ardb.init(false) # don't establish a connection
46
+ end
47
+
48
+ class DbConfigFile
49
+ PATH = 'config/db.rb'
50
+ def initialize
51
+ @path = Ardb.config.root_path.join(PATH)
52
+ end
53
+
54
+ def require_if_exists
55
+ require @path.to_s if File.exists?(@path.to_s)
56
+ end
57
+ end
58
+
59
+ class NullCommand
60
+ def run
61
+ # if this was a real command it would do something here
62
+ end
63
+ end
64
+
65
+ end