schema_monkey 1.0.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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