schema_plus_core 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.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +18 -0
  4. data/Gemfile +5 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +434 -0
  7. data/Rakefile +9 -0
  8. data/gemfiles/Gemfile.base +4 -0
  9. data/gemfiles/activerecord-4.2/Gemfile.base +3 -0
  10. data/gemfiles/activerecord-4.2/Gemfile.mysql2 +10 -0
  11. data/gemfiles/activerecord-4.2/Gemfile.postgresql +10 -0
  12. data/gemfiles/activerecord-4.2/Gemfile.sqlite3 +10 -0
  13. data/lib/schema_plus/core.rb +27 -0
  14. data/lib/schema_plus/core/active_record/base.rb +22 -0
  15. data/lib/schema_plus/core/active_record/connection_adapters/abstract_adapter.rb +43 -0
  16. data/lib/schema_plus/core/active_record/connection_adapters/abstract_mysql_adapter.rb +17 -0
  17. data/lib/schema_plus/core/active_record/connection_adapters/mysql2_adapter.rb +64 -0
  18. data/lib/schema_plus/core/active_record/connection_adapters/postgresql_adapter.rb +46 -0
  19. data/lib/schema_plus/core/active_record/connection_adapters/sqlite3_adapter.rb +43 -0
  20. data/lib/schema_plus/core/active_record/connection_adapters/table_definition.rb +36 -0
  21. data/lib/schema_plus/core/active_record/migration/command_recorder.rb +16 -0
  22. data/lib/schema_plus/core/active_record/schema_dumper.rb +102 -0
  23. data/lib/schema_plus/core/middleware.rb +71 -0
  24. data/lib/schema_plus/core/schema_dump.rb +123 -0
  25. data/lib/schema_plus/core/sql_struct.rb +30 -0
  26. data/lib/schema_plus/core/version.rb +5 -0
  27. data/schema_dev.yml +8 -0
  28. data/schema_plus_core.gemspec +31 -0
  29. data/spec/dumper_spec.rb +53 -0
  30. data/spec/middleware_spec.rb +175 -0
  31. data/spec/spec_helper.rb +35 -0
  32. data/spec/sql_struct_spec.rb +29 -0
  33. data/spec/support/enableable.rb +30 -0
  34. data/spec/support/test_dumper.rb +42 -0
  35. data/spec/support/test_reporter.rb +57 -0
  36. metadata +212 -0
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'schema_dev/tasks'
5
+
6
+ task :default => :spec
7
+
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ gemspec :path => File.expand_path('..', __FILE__)
3
+
4
+ File.exist?(gemfile_local = File.expand_path('../Gemfile.local', __FILE__)) and eval File.read(gemfile_local), binding, gemfile_local
@@ -0,0 +1,3 @@
1
+ eval File.read File.expand_path('../../Gemfile.base', __FILE__)
2
+
3
+ gem "activerecord", "~> 4.2.0"
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "mysql2"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "sqlite3"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter', '>=1.3.0.beta2'
10
+ end
@@ -0,0 +1,27 @@
1
+ require "schema_monkey"
2
+
3
+ module SchemaPlus
4
+ module Core
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ DIR = Pathname.new(__FILE__).dirname + "core/active_record/connection_adapters"
8
+ autoload :PostgresqlAdapter, DIR + "postgresql_adapter"
9
+ autoload :Mysql2Adapter, DIR + "mysql2_adapter"
10
+ autoload :AbstractMysqlAdapter, DIR + "abstract_mysql_adapter"
11
+ autoload :Sqlite3Adapter, DIR + "sqlite3_adapter"
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ require_relative "core/active_record/base"
18
+ require_relative "core/active_record/connection_adapters/abstract_adapter"
19
+ require_relative "core/active_record/connection_adapters/table_definition"
20
+ require_relative "core/active_record/migration/command_recorder"
21
+ require_relative "core/active_record/schema_dumper"
22
+ require_relative "core/middleware"
23
+ require_relative "core/schema_dump"
24
+ require_relative "core/sql_struct"
25
+ require_relative "core/version"
26
+
27
+ SchemaMonkey.register(SchemaPlus::Core)
@@ -0,0 +1,22 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module Base
5
+ module ClassMethods
6
+
7
+ def columns
8
+ SchemaMonkey::Middleware::Model::Columns.start(model: self, columns: []) { |env|
9
+ env.columns += super
10
+ }.columns
11
+ end
12
+
13
+ def reset_column_information
14
+ SchemaMonkey::Middleware::Model::ResetColumnInformation.start(model: self) do |env|
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module AbstractAdapter
6
+
7
+ def add_column(table_name, name, type, options = {})
8
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :add, table_name: table_name, column_name: name, type: type, options: options.deep_dup) do |env|
9
+ super env.table_name, env.column_name, env.type, env.options
10
+ end
11
+ end
12
+
13
+ def add_reference(table_name, name, options = {})
14
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :add, table_name: table_name, column_name: "#{name}_id", type: :reference, options: options.deep_dup) do |env|
15
+ super env.table_name, env.column_name.sub(/_id$/, ''), env.options
16
+ end
17
+ end
18
+
19
+ def add_index_options(table_name, column_names, options={})
20
+ SchemaMonkey::Middleware::Sql::IndexComponents.start(connection: self, table_name: table_name, column_names: Array.wrap(column_names), options: options.deep_dup, sql: SqlStruct::IndexComponents.new) { |env|
21
+ env.sql.name, env.sql.type, env.sql.columns, env.sql.options, env.sql.algorithm, env.sql.using = super env.table_name, env.column_names, env.options
22
+ }.sql.to_hash.values
23
+ end
24
+
25
+ module SchemaCreation
26
+
27
+ def add_column_options!(sql, options)
28
+ sql << " " + SchemaMonkey::Middleware::Sql::ColumnOptions.start(caller: self, connection: self.instance_variable_get('@conn'), sql: "", column: options[:column], options: options.except(:column)) { |env|
29
+ super env.sql, env.options.merge(column: env.column)
30
+ }.sql.lstrip
31
+ end
32
+
33
+ def visit_TableDefinition(o)
34
+ SchemaMonkey::Middleware::Sql::Table.start(caller: self, connection: self.instance_variable_get('@conn'), table_definition: o, sql: SqlStruct::Table.new) { |env|
35
+ env.sql.parse! super env.table_definition
36
+ }.sql.assemble
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module AbstractMysqlAdapter
6
+ module SchemaCreation
7
+ def visit_TableDefinition(o)
8
+ SchemaMonkey::Middleware::Sql::Table.start(caller: self, connection: self.instance_variable_get('@conn'), table_definition: o, sql: SqlStruct::Table.new) { |env|
9
+ env.sql.parse! super env.table_definition
10
+ }.sql.assemble
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,64 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module Mysql2Adapter
6
+
7
+ def change_column(table_name, name, type, options = {})
8
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :change, table_name: table_name, column_name: name, type: type, options: options.deep_dup) do |env|
9
+ super env.table_name, env.column_name, env.type, env.options
10
+ end
11
+ end
12
+
13
+ def add_index(table_name, column_names, options={})
14
+ SchemaMonkey::Middleware::Migration::Index.start(caller: self, operation: :add, table_name: table_name, column_names: column_names, options: options.deep_dup) do |env|
15
+ super env.table_name, env.column_names, env.options
16
+ end
17
+ end
18
+
19
+ def indexes(table_name, query_name=nil)
20
+ SchemaMonkey::Middleware::Schema::Indexes.start(connection: self, table_name: table_name, query_name: query_name, index_definitions: []) { |env|
21
+ env.index_definitions += super env.table_name, env.query_name
22
+ }.index_definitions
23
+ end
24
+
25
+ def tables(query_name=nil, database=nil, like=nil)
26
+ SchemaMonkey::Middleware::Schema::Tables.start(connection: self, query_name: query_name, database: database, like: like, tables: []) { |env|
27
+ env.tables += super env.query_name, env.database, env.like
28
+ }.tables
29
+ end
30
+
31
+ def select_rows(sql, name=nil, binds=[])
32
+ SchemaMonkey::Middleware::Query::Exec.start(connection: self, sql: sql, query_name: name, binds: binds) { |env|
33
+ env.result = super env.sql, env.query_name, env.binds
34
+ }.result
35
+ end
36
+
37
+ def exec_query(sql, name='SQL', binds=[])
38
+ SchemaMonkey::Middleware::Query::Exec.start(connection: self, sql: sql, query_name: name, binds: binds) { |env|
39
+ env.result = super env.sql, env.query_name, env.binds
40
+ }.result
41
+ end
42
+
43
+ alias exec_without_stmt exec_query
44
+
45
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
46
+ SchemaMonkey::Middleware::Query::Exec.start(connection: self, sql: sql, query_name: name, binds: binds) { |env|
47
+ env.result = super env.sql, env.query_name, env.binds, pk, sequence_name
48
+ }.result
49
+ end
50
+
51
+ def exec_delete(sql, name, binds)
52
+ SchemaMonkey::Middleware::Query::Exec.start(connection: self, sql: sql, query_name: name, binds: binds) { |env|
53
+ env.result = super env.sql, env.query_name, env.binds
54
+ }.result
55
+ end
56
+
57
+ alias :exec_update :exec_delete
58
+
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,46 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module PostgresqlAdapter
6
+
7
+ def change_column(table_name, name, type, options = {})
8
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :change, table_name: table_name, column_name: name, type: type, options: options.deep_dup) do |env|
9
+ super env.table_name, env.column_name, env.type, env.options
10
+ end
11
+ end
12
+
13
+ def add_index(table_name, column_names, options={})
14
+ SchemaMonkey::Middleware::Migration::Index.start(caller: self, operation: :add, table_name: table_name, column_names: column_names, options: options.deep_dup) do |env|
15
+ super env.table_name, env.column_names, env.options
16
+ end
17
+ end
18
+
19
+ def exec_cache(sql, name, binds)
20
+ SchemaMonkey::Middleware::Query::Exec.start(connection: self, sql: sql, query_name: name, binds: binds) { |env|
21
+ env.result = super env.sql, env.query_name, env.binds
22
+ }.result
23
+ end
24
+
25
+ def exec_no_cache(sql, name, binds)
26
+ SchemaMonkey::Middleware::Query::Exec.start(connection: self, sql: sql, query_name: name, binds: binds) { |env|
27
+ env.result = super env.sql, env.query_name, env.binds
28
+ }.result
29
+ end
30
+
31
+ def indexes(table_name, query_name=nil)
32
+ SchemaMonkey::Middleware::Schema::Indexes.start(connection: self, table_name: table_name, query_name: query_name, index_definitions: []) { |env|
33
+ env.index_definitions += super env.table_name, env.query_name
34
+ }.index_definitions
35
+ end
36
+
37
+ def tables(query_name=nil)
38
+ SchemaMonkey::Middleware::Schema::Tables.start(connection: self, query_name: query_name, tables: []) { |env|
39
+ env.tables += super env.query_name
40
+ }.tables
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module Sqlite3Adapter
6
+
7
+ def change_column(table_name, name, type, options = {})
8
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :change, table_name: table_name, column_name: name, type: type, options: options.deep_dup) do |env|
9
+ super env.table_name, env.column_name, env.type, env.options
10
+ end
11
+ end
12
+
13
+ def add_index(table_name, column_names, options={})
14
+ SchemaMonkey::Middleware::Migration::Index.start(caller: self, operation: :add, table_name: table_name, column_names: column_names, options: options.deep_dup) do |env|
15
+ super env.table_name, env.column_names, env.options
16
+ end
17
+ end
18
+
19
+ def exec_query(sql, name=nil, binds=[])
20
+ SchemaMonkey::Middleware::Query::Exec.start(connection: self, sql: sql, query_name: name, binds: binds) { |env|
21
+ env.result = super env.sql, env.query_name, env.binds
22
+ }.result
23
+ end
24
+
25
+ def indexes(table_name, query_name=nil)
26
+ SchemaMonkey::Middleware::Schema::Indexes.start(connection: self, table_name: table_name, query_name: query_name, index_definitions: []) { |env|
27
+ env.index_definitions += super env.table_name, env.query_name
28
+ }.index_definitions
29
+ end
30
+
31
+ def tables(query_name=nil, table_name=nil)
32
+ SchemaMonkey::Middleware::Schema::Tables.start(connection: self, query_name: query_name, table_name: table_name, tables: []) { |env|
33
+ env.tables += super env.query_name, env.table_name
34
+ }.tables
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+
@@ -0,0 +1,36 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module TableDefinition
6
+
7
+ def column(name, type, options = {})
8
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :define, table_name: self.name, column_name: name, type: type, options: options.deep_dup) do |env|
9
+ super env.column_name, env.type, env.options
10
+ end
11
+ end
12
+
13
+ def references(name, options = {})
14
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :define, table_name: self.name, column_name: "#{name}_id", type: :reference, options: options.deep_dup) do |env|
15
+ super env.column_name.sub(/_id$/, ''), env.options
16
+ end
17
+ end
18
+
19
+ def belongs_to(name, options = {})
20
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :define, table_name: self.name, column_name: "#{name}_id", type: :reference, options: options.deep_dup) do |env|
21
+ super env.column_name.sub(/_id$/, ''), env.options
22
+ end
23
+ end
24
+
25
+ def index(*args)
26
+ options = args.extract_options!
27
+ column_name = args.first
28
+ SchemaMonkey::Middleware::Migration::Index.start(caller: self, operation: :define, table_name: self.name, column_names: column_name, options: options.deep_dup) do |env|
29
+ super env.column_names, env.options
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ module SchemaPlus
2
+ module Core
3
+ module ActiveRecord
4
+ module Migration
5
+ module CommandRecorder
6
+
7
+ def add_column(table_name, column_name, type, options = {})
8
+ SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :record, table_name: table_name, column_name: column_name, type: type, options: options.deep_dup) do |env|
9
+ super env.table_name, env.column_name, env.type, env.options
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,102 @@
1
+ require 'ostruct'
2
+ require 'tsort'
3
+
4
+ module SchemaPlus
5
+ module Core
6
+ module ActiveRecord
7
+ module SchemaDumper
8
+
9
+ def self.prepended(base)
10
+ base.class_eval do
11
+ public :ignored?
12
+ end
13
+ end
14
+
15
+ def dump(stream)
16
+ @dump = SchemaDump.new(self)
17
+ super stream
18
+ @dump.assemble(stream)
19
+ end
20
+
21
+ def foreign_keys(table, _)
22
+ stream = StringIO.new
23
+ super table, stream
24
+ @dump.final += stream.string.split("\n").map(&:strip)
25
+ end
26
+
27
+ def trailer(_)
28
+ stream = StringIO.new
29
+ super stream
30
+ @dump.trailer = stream.string
31
+ end
32
+
33
+ def extensions(_)
34
+ SchemaMonkey::Middleware::Dumper::Initial.start(dumper: self, connection: @connection, dump: @dump, initial: @dump.initial) do |env|
35
+ stream = StringIO.new
36
+ super stream
37
+ env.dump.initial << stream.string unless stream.string.blank?
38
+ end
39
+ end
40
+
41
+ def tables(_)
42
+ SchemaMonkey::Middleware::Dumper::Tables.start(dumper: self, connection: @connection, dump: @dump) do |env|
43
+ super nil
44
+ end
45
+ end
46
+
47
+ def table(table, _)
48
+ SchemaMonkey::Middleware::Dumper::Table.start(dumper: self, connection: @connection, dump: @dump, table: @dump.tables[table] = SchemaDump::Table.new(name: table)) do |env|
49
+ stream = StringIO.new
50
+ super env.table.name, stream
51
+ m = stream.string.match %r{
52
+ \A \s*
53
+ create_table \s*
54
+ [:'"](?<name>[^'"\s]+)['"]? \s*
55
+ ,? \s*
56
+ (?<options>.*) \s+
57
+ do \s* \|t\| \s* $
58
+ (?<columns>.*)
59
+ ^\s*end\s*$
60
+ (?<trailer>.*)
61
+ \Z
62
+ }xm
63
+ env.table.pname = m[:name]
64
+ env.table.options = m[:options].strip
65
+ env.table.trailer = m[:trailer].split("\n").map(&:strip).reject{|s| s.blank?}
66
+ env.table.columns = m[:columns].strip.split("\n").map { |col|
67
+ m = col.strip.match %r{
68
+ ^
69
+ t\.(?<type>\S+) \s*
70
+ [:'"](?<name>[^"\s]+)[,"]? \s*
71
+ ,? \s*
72
+ (?<options>.*)
73
+ $
74
+ }x
75
+ SchemaDump::Table::Column.new(name: m[:name], type: m[:type], options: m[:options])
76
+ }
77
+ end
78
+ end
79
+
80
+ def indexes(table, _)
81
+ SchemaMonkey::Middleware::Dumper::Indexes.start(dumper: self, connection: @connection, dump: @dump, table: @dump.tables[table]) do |env|
82
+ stream = StringIO.new
83
+ super env.table.name, stream
84
+ env.table.indexes += stream.string.split("\n").map { |string|
85
+ m = string.strip.match %r{
86
+ ^
87
+ add_index \s*
88
+ [:'"](?<table>[^'"\s]+)['"]? \s* , \s*
89
+ (?<columns>.*) \s*
90
+ name: \s* [:'"](?<name>[^'"\s]+)['"]? \s*
91
+ (, \s* (?<options>.*))?
92
+ $
93
+ }x
94
+ columns = m[:columns].tr(%q{[]'":}, '').strip.split(/\s*,\s*/)
95
+ SchemaDump::Table::Index.new name: m[:name], columns: columns, options: m[:options]
96
+ }
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end