schema_monkey 1.0.1 → 2.0.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +0 -1
  4. data/Gemfile +2 -0
  5. data/README.md +204 -28
  6. data/lib/schema_monkey.rb +30 -17
  7. data/lib/schema_monkey/active_record.rb +25 -0
  8. data/lib/schema_monkey/client.rb +65 -0
  9. data/lib/schema_monkey/errors.rb +6 -0
  10. data/lib/schema_monkey/{tool/module.rb → module.rb} +10 -7
  11. data/lib/schema_monkey/monkey.rb +31 -0
  12. data/lib/schema_monkey/{tool/rake.rb → rake.rb} +1 -1
  13. data/lib/schema_monkey/stack.rb +44 -0
  14. data/lib/schema_monkey/{tool/tasks → tasks}/insert.rake +0 -0
  15. data/lib/schema_monkey/version.rb +1 -1
  16. data/schema_dev.yml +0 -1
  17. data/schema_monkey.gemspec +2 -2
  18. data/spec/active_record_spec.rb +75 -0
  19. data/spec/middleware_spec.rb +0 -7
  20. data/spec/spec_helper.rb +2 -2
  21. metadata +18 -41
  22. data/lib/schema_monkey/core_extensions.rb +0 -23
  23. data/lib/schema_monkey/core_extensions/active_record/base.rb +0 -31
  24. data/lib/schema_monkey/core_extensions/active_record/connection_adapters/abstract_adapter.rb +0 -38
  25. data/lib/schema_monkey/core_extensions/active_record/connection_adapters/mysql2_adapter.rb +0 -31
  26. data/lib/schema_monkey/core_extensions/active_record/connection_adapters/postgresql_adapter.rb +0 -30
  27. data/lib/schema_monkey/core_extensions/active_record/connection_adapters/schema_statements.rb +0 -83
  28. data/lib/schema_monkey/core_extensions/active_record/connection_adapters/sqlite3_adapter.rb +0 -33
  29. data/lib/schema_monkey/core_extensions/active_record/connection_adapters/table_definition.rb +0 -42
  30. data/lib/schema_monkey/core_extensions/active_record/migration/command_recorder.rb +0 -19
  31. data/lib/schema_monkey/core_extensions/active_record/schema_dumper.rb +0 -227
  32. data/lib/schema_monkey/core_extensions/middleware.rb +0 -62
  33. data/lib/schema_monkey/tool.rb +0 -43
  34. data/lib/schema_monkey/tool/client.rb +0 -67
  35. data/lib/schema_monkey/tool/errors.rb +0 -4
  36. data/lib/schema_monkey/tool/monkey.rb +0 -46
  37. data/lib/schema_monkey/tool/stack.rb +0 -90
@@ -1,31 +0,0 @@
1
- module SchemaMonkey::CoreExtensions
2
- module ActiveRecord
3
- module ConnectionAdapters
4
- module Mysql2Adapter
5
-
6
- def self.included(base)
7
- base.class_eval do
8
- alias_method_chain :indexes, :schema_monkey
9
- alias_method_chain :tables, :schema_monkey
10
- end
11
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Column
12
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Reference
13
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Index
14
- end
15
-
16
- def indexes_with_schema_monkey(table_name, query_name=nil)
17
- SchemaMonkey::Middleware::Query::Indexes.start(connection: self, table_name: table_name, query_name: query_name, index_definitions: []) { |env|
18
- env.index_definitions += indexes_without_schema_monkey env.table_name, env.query_name
19
- }.index_definitions
20
- end
21
-
22
- def tables_with_schema_monkey(query_name=nil, database=nil, like=nil)
23
- SchemaMonkey::Middleware::Query::Tables.start(connection: self, query_name: query_name, database: database, like: like, tables: []) { |env|
24
- env.tables += tables_without_schema_monkey env.query_name, env.database, env.like
25
- }.tables
26
- end
27
- end
28
- end
29
- end
30
- end
31
-
@@ -1,30 +0,0 @@
1
- module SchemaMonkey::CoreExtensions
2
- module ActiveRecord
3
- module ConnectionAdapters
4
- module PostgresqlAdapter
5
-
6
- def self.included(base)
7
- base.class_eval do
8
- alias_method_chain :exec_cache, :schema_monkey
9
- alias_method_chain :indexes, :schema_monkey
10
- end
11
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Reference
12
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Column
13
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Index
14
- end
15
-
16
- def exec_cache_with_schema_monkey(sql, name, binds)
17
- SchemaMonkey::Middleware::Query::ExecCache.start(connection: self, sql: sql, name: name, binds: binds) { |env|
18
- env.result = exec_cache_without_schema_monkey(env.sql, env.name, env.binds)
19
- }.result
20
- end
21
-
22
- def indexes_with_schema_monkey(table_name, query_name=nil)
23
- SchemaMonkey::Middleware::Query::Indexes.start(connection: self, table_name: table_name, query_name: query_name, index_definitions: []) { |env|
24
- env.index_definitions += indexes_without_schema_monkey env.table_name, env.query_name
25
- }.index_definitions
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,83 +0,0 @@
1
- module SchemaMonkey::CoreExtensions
2
- module ActiveRecord
3
- module ConnectionAdapters
4
- module SchemaStatements
5
-
6
- #
7
- # The hooks at the top level of this module are for the base class, which are not overriden by
8
- # any specific adapters in AR.
9
- #
10
- def self.included(base)
11
- base.class_eval do
12
- alias_method_chain :add_index_options, :schema_monkey
13
- end
14
- end
15
-
16
- IndexComponentsSql = KeyStruct[:name, :type, :columns, :options, :algorithm, :using]
17
-
18
- def add_index_options_with_schema_monkey(table_name, column_names, options={})
19
- env = SchemaMonkey::Middleware::Migration::IndexComponentsSql.start(connection: self, table_name: table_name, column_names: Array.wrap(column_names), options: options.deep_dup, sql: IndexComponentsSql.new) { |env|
20
- env.sql.name, env.sql.type, env.sql.columns, env.sql.options, env.sql.algorithm, env.sql.using = add_index_options_without_schema_monkey(env.table_name, env.column_names, env.options)
21
- }
22
- [env.sql.name, env.sql.type, env.sql.columns, env.sql.options, env.sql.algorithm, env.sql.using]
23
- end
24
-
25
- #
26
- # The hooks below here are grouped into modules. Different
27
- # connection adapters define this methods in different places, so
28
- # each will include the hooks into the appropriate class
29
- #
30
-
31
- module Column
32
- def self.included(base)
33
- base.class_eval do
34
- alias_method_chain :add_column, :schema_monkey
35
- alias_method_chain :change_column, :schema_monkey
36
- end
37
- end
38
-
39
- def add_column_with_schema_monkey(table_name, name, type, options = {})
40
- SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :add, table_name: table_name, column_name: name, type: type, options: options.deep_dup) do |env|
41
- add_column_without_schema_monkey env.table_name, env.column_name, env.type, env.options
42
- end
43
- end
44
-
45
- def change_column_with_schema_monkey(table_name, name, type, options = {})
46
- SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :change, table_name: table_name, column_name: name, type: type, options: options.deep_dup) do |env|
47
- change_column_without_schema_monkey env.table_name, env.column_name, env.type, env.options
48
- end
49
- end
50
- end
51
-
52
- module Reference
53
- def self.included(base)
54
- base.class_eval do
55
- alias_method_chain :add_reference, :schema_monkey
56
- end
57
- end
58
- def add_reference_with_schema_monkey(table_name, name, options = {})
59
- 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|
60
- add_reference_without_schema_monkey env.table_name, env.column_name.sub(/_id$/, ''), env.options
61
- end
62
- end
63
- end
64
-
65
- module Index
66
- def self.included(base)
67
- base.class_eval do
68
- alias_method_chain :add_index, :schema_monkey
69
- end
70
- end
71
- def add_index_with_schema_monkey(*args)
72
- options = args.extract_options!
73
- table_name, column_names = args
74
- SchemaMonkey::Middleware::Migration::Index.start(caller: self, operation: :add, table_name: table_name, column_names: column_names, options: options.deep_dup) do |env|
75
- add_index_without_schema_monkey env.table_name, env.column_names, env.options
76
- end
77
- end
78
- end
79
-
80
- end
81
- end
82
- end
83
- end
@@ -1,33 +0,0 @@
1
- module SchemaMonkey::CoreExtensions
2
- module ActiveRecord
3
- module ConnectionAdapters
4
- module Sqlite3Adapter
5
-
6
- def self.included(base)
7
- base.class_eval do
8
- alias_method_chain :indexes, :schema_monkey
9
- alias_method_chain :tables, :schema_monkey
10
- end
11
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Column
12
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Reference
13
- SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::CoreExtensions::ActiveRecord::ConnectionAdapters::SchemaStatements::Index
14
- end
15
-
16
- def indexes_with_schema_monkey(table_name, query_name=nil)
17
- SchemaMonkey::Middleware::Query::Indexes.start(connection: self, table_name: table_name, query_name: query_name, index_definitions: []) { |env|
18
- env.index_definitions += indexes_without_schema_monkey env.table_name, env.query_name
19
- }.index_definitions
20
- end
21
-
22
- def tables_with_schema_monkey(query_name=nil, table_name=nil)
23
- SchemaMonkey::Middleware::Query::Tables.start(connection: self, query_name: query_name, table_name: table_name, tables: []) { |env|
24
- env.tables += tables_without_schema_monkey env.query_name, env.table_name
25
- }.tables
26
- end
27
-
28
- end
29
- end
30
- end
31
- end
32
-
33
-
@@ -1,42 +0,0 @@
1
- module SchemaMonkey::CoreExtensions
2
- module ActiveRecord
3
- module ConnectionAdapters
4
- module TableDefinition
5
- def self.included(base)
6
- base.class_eval do
7
- alias_method_chain :column, :schema_monkey
8
- alias_method_chain :references, :schema_monkey
9
- alias_method_chain :belongs_to, :schema_monkey
10
- alias_method_chain :index, :schema_monkey
11
- end
12
- end
13
-
14
- def column_with_schema_monkey(name, type, options = {})
15
- SchemaMonkey::Middleware::Migration::Column.start(caller: self, operation: :define, table_name: self.name, column_name: name, type: type, options: options.deep_dup) do |env|
16
- column_without_schema_monkey env.column_name, env.type, env.options
17
- end
18
- end
19
-
20
- def references_with_schema_monkey(name, options = {})
21
- 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|
22
- references_without_schema_monkey env.column_name.sub(/_id$/, ''), env.options
23
- end
24
- end
25
-
26
- def belongs_to_with_schema_monkey(name, options = {})
27
- 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|
28
- belongs_to_without_schema_monkey env.column_name.sub(/_id$/, ''), env.options
29
- end
30
- end
31
-
32
- def index_with_schema_monkey(*args)
33
- options = args.extract_options!
34
- column_name = args.first
35
- SchemaMonkey::Middleware::Migration::Index.start(caller: self, operation: :define, table_name: self.name, column_names: column_name, options: options.deep_dup) do |env|
36
- index_without_schema_monkey env.column_names, env.options
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,19 +0,0 @@
1
- module SchemaMonkey::CoreExtensions
2
- module ActiveRecord
3
- module Migration
4
- module CommandRecorder
5
- def self.included(base)
6
- base.class_eval do
7
- alias_method_chain :add_column, :schema_monkey
8
- end
9
- end
10
-
11
- def add_column_with_schema_monkey(table_name, column_name, type, options = {})
12
- 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|
13
- add_column_without_schema_monkey env.table_name, env.column_name, env.type, env.options
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,227 +0,0 @@
1
- require 'ostruct'
2
- require 'tsort'
3
-
4
- module SchemaMonkey::CoreExtensions
5
- module ActiveRecord
6
- module SchemaDumper
7
-
8
- class Dump
9
- include TSort
10
-
11
- attr_reader :extensions, :tables, :dependencies, :data
12
- attr_accessor :foreign_keys, :trailer
13
-
14
- def initialize(dumper)
15
- @dumper = dumper
16
- @dependencies = Hash.new { |h, k| h[k] = [] }
17
- @extensions = []
18
- @tables = {}
19
- @foreign_keys = []
20
- @data = OpenStruct.new # a place for middleware to leave data
21
- end
22
-
23
- def depends(tablename, dependents)
24
- @tables[tablename] ||= false # placeholder for dependencies applied before defining the table
25
- @dependencies[tablename] += Array.wrap(dependents)
26
- end
27
-
28
- def assemble(stream)
29
- stream.puts @extensions.join("\n") if extensions.any?
30
- assemble_tables(stream)
31
- foreign_keys.each do |statement|
32
- stream.puts " #{statement}"
33
- end
34
- stream.puts @trailer
35
- end
36
-
37
- def assemble_tables(stream)
38
- tsort().each do |table|
39
- @tables[table].assemble(stream) if @tables[table]
40
- end
41
- end
42
-
43
- def tsort_each_node(&block)
44
- @tables.keys.sort.each(&block)
45
- end
46
-
47
- def tsort_each_child(tablename, &block)
48
- @dependencies[tablename].sort.uniq.reject{|t| @dumper.ignored? t}.each(&block)
49
- end
50
-
51
- class Table < KeyStruct[:name, :pname, :options, :columns, :indexes, :statements, :trailer]
52
- def initialize(*args)
53
- super
54
- self.columns ||= []
55
- self.indexes ||= []
56
- self.statements ||= []
57
- self.trailer ||= []
58
- end
59
-
60
- def assemble(stream)
61
- stream.write " create_table #{pname.inspect}"
62
- stream.write ", #{options}" unless options.blank?
63
- stream.puts " do |t|"
64
- typelen = columns.map{|col| col.type.length}.max
65
- namelen = columns.map{|col| col.name.length}.max
66
- columns.each do |column|
67
- stream.write " "
68
- column.assemble(stream, typelen, namelen)
69
- stream.puts ""
70
- end
71
- statements.each do |statement|
72
- stream.puts " #{statement}"
73
- end
74
- stream.puts " end"
75
- indexes.each do |index|
76
- stream.write " add_index #{pname.inspect}, "
77
- index.assemble(stream)
78
- stream.puts ""
79
- end
80
- trailer.each do |statement|
81
- stream.puts " #{statement}"
82
- end
83
- stream.puts ""
84
- end
85
-
86
- class Column < KeyStruct[:name, :type, :options, :comments]
87
-
88
- def add_option(option)
89
- self.options = [options, option].reject(&:blank?).join(', ')
90
- end
91
-
92
- def add_comment(comment)
93
- self.comments = [comments, comment].reject(&:blank?).join('; ')
94
- end
95
-
96
- def assemble(stream, typelen, namelen)
97
- stream.write "t.%-#{typelen}s " % type
98
- if options.blank? && comments.blank?
99
- stream.write name.inspect
100
- else
101
- pr = name.inspect
102
- pr += "," unless options.blank?
103
- stream.write "%-#{namelen+3}s " % pr
104
- end
105
- stream.write "#{options}" unless options.blank?
106
- stream.write " " unless options.blank? or comments.blank?
107
- stream.write "# #{comments}" unless comments.blank?
108
- end
109
- end
110
-
111
- class Index < KeyStruct[:name, :columns, :options]
112
-
113
- def add_option(option)
114
- self.options = [options, option].reject(&:blank?).join(', ')
115
- end
116
-
117
- def assemble(stream)
118
- stream.write [
119
- columns.inspect,
120
- "name: #{name.inspect}",
121
- options
122
- ].reject(&:blank?).join(", ")
123
- end
124
- end
125
- end
126
- end
127
-
128
- def self.included(base)
129
- base.class_eval do
130
- alias_method_chain :dump, :schema_monkey
131
- alias_method_chain :extensions, :schema_monkey
132
- alias_method_chain :tables, :schema_monkey
133
- alias_method_chain :table, :schema_monkey
134
- alias_method_chain :foreign_keys, :schema_monkey
135
- alias_method_chain :trailer, :schema_monkey
136
- alias_method_chain :indexes, :schema_monkey
137
- public :ignored?
138
- end
139
- end
140
-
141
- def dump_with_schema_monkey(stream)
142
- @dump = Dump.new(self)
143
- dump_without_schema_monkey(stream)
144
- @dump.assemble(stream)
145
- end
146
-
147
- def foreign_keys_with_schema_monkey(table, _)
148
- stream = StringIO.new
149
- foreign_keys_without_schema_monkey(table, stream)
150
- @dump.foreign_keys += stream.string.split("\n").map(&:strip)
151
- end
152
-
153
- def trailer_with_schema_monkey(_)
154
- stream = StringIO.new
155
- trailer_without_schema_monkey(stream)
156
- @dump.trailer = stream.string
157
- end
158
-
159
- def extensions_with_schema_monkey(_)
160
- SchemaMonkey::Middleware::Dumper::Extensions.start(dumper: self, connection: @connection, dump: @dump, extensions: @dump.extensions) do |env|
161
- stream = StringIO.new
162
- extensions_without_schema_monkey(stream)
163
- env.dump.extensions << stream.string unless stream.string.blank?
164
- end
165
- end
166
-
167
- def tables_with_schema_monkey(_)
168
- SchemaMonkey::Middleware::Dumper::Tables.start(dumper: self, connection: @connection, dump: @dump) do |env|
169
- tables_without_schema_monkey(nil)
170
- end
171
- end
172
-
173
- def table_with_schema_monkey(table, _)
174
- SchemaMonkey::Middleware::Dumper::Table.start(dumper: self, connection: @connection, dump: @dump, table: @dump.tables[table] = Dump::Table.new(name: table)) do |env|
175
- stream = StringIO.new
176
- table_without_schema_monkey(env.table.name, stream)
177
- m = stream.string.match %r{
178
- \A \s*
179
- create_table \s*
180
- [:'"](?<name>[^'"\s]+)['"]? \s*
181
- ,? \s*
182
- (?<options>.*) \s+
183
- do \s* \|t\| \s* $
184
- (?<columns>.*)
185
- ^\s*end\s*$
186
- (?<trailer>.*)
187
- \Z
188
- }xm
189
- env.table.pname = m[:name]
190
- env.table.options = m[:options].strip
191
- env.table.trailer = m[:trailer].split("\n").map(&:strip).reject{|s| s.blank?}
192
- env.table.columns = m[:columns].strip.split("\n").map { |col|
193
- m = col.strip.match %r{
194
- ^
195
- t\.(?<type>\S+) \s*
196
- [:'"](?<name>[^"\s]+)[,"]? \s*
197
- ,? \s*
198
- (?<options>.*)
199
- $
200
- }x
201
- Dump::Table::Column.new(name: m[:name], type: m[:type], options: m[:options])
202
- }
203
- end
204
- end
205
-
206
- def indexes_with_schema_monkey(table, _)
207
- SchemaMonkey::Middleware::Dumper::Indexes.start(dumper: self, connection: @connection, dump: @dump, table: @dump.tables[table]) do |env|
208
- stream = StringIO.new
209
- indexes_without_schema_monkey(env.table.name, stream)
210
- env.table.indexes += stream.string.split("\n").map { |string|
211
- m = string.strip.match %r{
212
- ^
213
- add_index \s*
214
- [:'"](?<table>[^'"\s]+)['"]? \s* , \s*
215
- (?<columns>.*) \s*
216
- name: \s* [:'"](?<name>[^'"\s]+)['"]? \s*
217
- (, \s* (?<options>.*))?
218
- $
219
- }x
220
- columns = m[:columns].tr(%q{[]'":}, '').strip.split(/\s*,\s*/)
221
- Dump::Table::Index.new name: m[:name], columns: columns, options: m[:options]
222
- }
223
- end
224
- end
225
- end
226
- end
227
- end