data_plan 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README +57 -0
- data/Rakefile +8 -0
- data/lib/data_plan/generators/migration/lib/auto_migrations.rb +216 -0
- data/lib/data_plan/generators/migration/lib/sexy_statements_hook.rb +58 -0
- data/lib/data_plan/generators/migration/migration_generator.rb +28 -0
- data/lib/data_plan/generators/migration/migration_generator_core.rb +76 -0
- data/lib/data_plan/generators/migration/sinatra.rb +49 -0
- data/lib/data_plan/generators/migration/templates/migration.rb +11 -0
- data/test/test_data_plan.rb +10 -0
- metadata +74 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2012 Pavel Vasev
|
2
|
+
Copyright (c) 2007 PJ Hyett
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
== Data Plan
|
2
|
+
|
3
|
+
A tool for easy migration generation. Works with Sinatra/ActiveRecord and with Rails too.
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
Before use in Sinatra, install 'sinatra-activerecord' gem.
|
8
|
+
It extends Sinatra with extension methods and Rake tasks for dealing with an SQL database using the ActiveRecord ORM.
|
9
|
+
Follow it's instructions and create a Rakefile with migration commands.
|
10
|
+
After that you can invoke 'rake db:create_migration' and get migrations.
|
11
|
+
|
12
|
+
And then, magic begins.
|
13
|
+
* Add to Rakefile:
|
14
|
+
require 'data_plan/generators/migration/sinatra'
|
15
|
+
* Create db/plan.rb file and describe desired db schema in it.
|
16
|
+
|
17
|
+
Now, when you create a migration, DataPlan will generate a new migration and put all differencies
|
18
|
+
between plan.rb and your current database schema! You can migrate immediately, or add some
|
19
|
+
more tweaks to your migration, or something else.
|
20
|
+
|
21
|
+
Why is it great? Because you don't need to remember all that syntax like
|
22
|
+
change_column, add_column, etc - you just modify your schema (in the plan.rb).
|
23
|
+
|
24
|
+
Nice bonus: migrations are automatically named (of course you may override name suggested).
|
25
|
+
|
26
|
+
== How to use with Rails
|
27
|
+
Copy from the gem the folder
|
28
|
+
GEMROOT/lib/data_plan/generators/migration/*
|
29
|
+
to the Rails project as follows:
|
30
|
+
YOURAPPROOT/lib/generators/migration/*
|
31
|
+
Thats it, Data Plan now in your rails app, and you can invoke 'script/generate migration'
|
32
|
+
and get migrations auto-generated as described above.
|
33
|
+
|
34
|
+
== How to install
|
35
|
+
|
36
|
+
gem install data_plan
|
37
|
+
|
38
|
+
== Todo
|
39
|
+
|
40
|
+
Indices are partially supported at the moment.
|
41
|
+
|
42
|
+
== Changelog
|
43
|
+
|
44
|
+
Workaround on views. Thanks to Cyril Boswell.
|
45
|
+
|
46
|
+
== Legal
|
47
|
+
|
48
|
+
Found a bug? Fix it and email pull request to me: pavel.vasev@gmail.com
|
49
|
+
|
50
|
+
Want to add a feature? Implement it and email the patch!
|
51
|
+
|
52
|
+
Pavel Vasev [ pavel.vasev@gmail.com ]
|
53
|
+
|
54
|
+
|
55
|
+
Released under the MIT license (included)
|
56
|
+
|
57
|
+
p.s. Schema-Definition plugin is hugely based on Auto-Migrations by PJ Hyett [ pjhyett@gmail.com ]
|
data/Rakefile
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
module AutoMigrations
|
2
|
+
|
3
|
+
def self.run
|
4
|
+
# Turn off schema_info code for auto-migration
|
5
|
+
class << ActiveRecord::Schema
|
6
|
+
alias :old_define :define
|
7
|
+
def define(info={}, &block) instance_eval(&block) end
|
8
|
+
end
|
9
|
+
|
10
|
+
load(File.join(DB_PROJECT_ROOT, 'db', 'plan.rb'))
|
11
|
+
ActiveRecord::Migration.drop_unused_tables
|
12
|
+
ActiveRecord::Migration.drop_unused_views
|
13
|
+
ActiveRecord::Migration.drop_unused_indexes
|
14
|
+
|
15
|
+
class << ActiveRecord::Schema
|
16
|
+
alias :define :old_define
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.schema_to_migration
|
21
|
+
schema = File.read(File.join(DB_PROJECT_ROOT, "db", "plan.rb")) rescue begin
|
22
|
+
puts "Please copy your schema.rb file to plan.rb before generating migrations!"
|
23
|
+
raise
|
24
|
+
end
|
25
|
+
schema.gsub!(/#(.)+\n/, '')
|
26
|
+
schema.sub!(/ActiveRecord::Schema.define(.+)do[ ]?\n/, '')
|
27
|
+
schema.gsub!(/^/, ' ')
|
28
|
+
schema = "class InitialSchema < ActiveRecord::Migration\n def self.up\n" + schema
|
29
|
+
schema << "\n def self.down\n"
|
30
|
+
schema << (ActiveRecord::Base.connection.tables - ["schema_info"]).map do |table|
|
31
|
+
" drop_table :#{table}\n"
|
32
|
+
end.join
|
33
|
+
schema << " end\nend\n"
|
34
|
+
migration_file = File.join(DB_PROJECT_ROOT, "db", "migrate", "001_initial_schema.rb")
|
35
|
+
File.open(migration_file, "w") { |f| f << schema }
|
36
|
+
puts "Migration created at db/migrate/001_initial_schema.rb"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.included(base)
|
40
|
+
base.extend ClassMethods
|
41
|
+
class << base
|
42
|
+
cattr_accessor :tables_in_schema, :indexes_in_schema, :views_in_schema
|
43
|
+
self.tables_in_schema, self.indexes_in_schema, self.views_in_schema = [], [], []
|
44
|
+
alias_method_chain :method_missing, :auto_migration
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module ClassMethods
|
49
|
+
|
50
|
+
def method_missing_with_auto_migration(method, *args, &block)
|
51
|
+
case method
|
52
|
+
when :create_table
|
53
|
+
auto_create_table(method, *args, &block)
|
54
|
+
when :create_view
|
55
|
+
auto_create_view(method, *args, &block)
|
56
|
+
when :add_index
|
57
|
+
auto_add_index(method, *args, &block)
|
58
|
+
else
|
59
|
+
method_missing_without_auto_migration(method, *args, &block)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def auto_create_table(method, *args, &block)
|
64
|
+
table_name = args.shift.to_s
|
65
|
+
options = args.pop || {}
|
66
|
+
|
67
|
+
(self.tables_in_schema ||= []) << table_name
|
68
|
+
|
69
|
+
# Table doesn't exist, create it
|
70
|
+
unless ActiveRecord::Base.connection.tables.include?(table_name)
|
71
|
+
return method_missing_without_auto_migration(method, *[table_name, options], &block)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Grab database columns
|
75
|
+
fields_in_db = ActiveRecord::Base.connection.columns(table_name).inject({}) do |hash, column|
|
76
|
+
hash[column.name] = column
|
77
|
+
hash
|
78
|
+
end
|
79
|
+
|
80
|
+
# Grab schema columns (lifted from active_record/connection_adapters/abstract/schema_statements.rb)
|
81
|
+
table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(ActiveRecord::Base.connection)
|
82
|
+
table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
|
83
|
+
yield table_definition
|
84
|
+
fields_in_schema = table_definition.columns.inject({}) do |hash, column|
|
85
|
+
hash[column.name.to_s] = column
|
86
|
+
hash
|
87
|
+
end
|
88
|
+
|
89
|
+
# Add fields to db new to schema
|
90
|
+
(fields_in_schema.keys - fields_in_db.keys).each do |field|
|
91
|
+
column = fields_in_schema[field]
|
92
|
+
add_column table_name, column.name, column.type.to_sym, :limit => column.limit, :precision => column.precision,
|
93
|
+
:scale => column.scale, :default => column.default, :null => column.null
|
94
|
+
end
|
95
|
+
|
96
|
+
# Remove fields from db no longer in schema
|
97
|
+
(fields_in_db.keys - fields_in_schema.keys & fields_in_db.keys).each do |field|
|
98
|
+
column = fields_in_db[field]
|
99
|
+
remove_column table_name, column.name
|
100
|
+
end
|
101
|
+
|
102
|
+
# Change field type if schema is different from db
|
103
|
+
(fields_in_schema.keys & fields_in_db.keys).each do |field|
|
104
|
+
# TYPE
|
105
|
+
if (field != 'id') && (fields_in_schema[field].type.to_sym != fields_in_db[field].type.to_sym)
|
106
|
+
change_column table_name, fields_in_schema[field].name.to_sym, fields_in_schema[field].type.to_sym
|
107
|
+
end
|
108
|
+
# DEFAULT VALUE
|
109
|
+
if (field != 'id') && (fields_in_schema[field].default != fields_in_db[field].default)
|
110
|
+
change_column_default table_name, fields_in_schema[field].name.to_sym, fields_in_schema[field].default
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def auto_create_view(method, *args, &block)
|
116
|
+
# we are working on it with Cyril Boswell
|
117
|
+
return true
|
118
|
+
# so when we'll find an idea, we'll remove this return true.
|
119
|
+
view_name = args.shift.to_s
|
120
|
+
select_query = args.pop
|
121
|
+
options = args.pop || {}
|
122
|
+
|
123
|
+
(self.views_in_schema ||= []) << view_name
|
124
|
+
|
125
|
+
# View doesn't exist, create it
|
126
|
+
unless ActiveRecord::Base.connection.views.include?(view_name)
|
127
|
+
return method_missing_without_auto_migration(method, *[view_name, options], &block)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Grab database view select
|
131
|
+
db_select = ActiveRecord::Base.connection.view_select_statement( view_name )
|
132
|
+
|
133
|
+
# Grab database columns
|
134
|
+
fields_in_db = ActiveRecord::Base.connection.columns(view_name).inject({}) do |hash, column|
|
135
|
+
hash[column.name] = column
|
136
|
+
hash
|
137
|
+
end
|
138
|
+
|
139
|
+
# Grab schema columns (lifted from active_record/connection_adapters/abstract/schema_statements.rb)
|
140
|
+
view_definition = RailsSqlViews::ConnectionAdapters::ViewDefinition.new(ActiveRecord::Base.connection,select_query)
|
141
|
+
|
142
|
+
yield view_definition
|
143
|
+
|
144
|
+
fields_in_schema = view_definition.columns.inject({}) do |hash, column|
|
145
|
+
hash[column.to_s] = column
|
146
|
+
hash
|
147
|
+
end
|
148
|
+
|
149
|
+
not_same = false
|
150
|
+
# Add fields to db new to schema
|
151
|
+
(fields_in_schema.keys - fields_in_db.keys).each do |field|
|
152
|
+
not_same = true
|
153
|
+
# column = fields_in_schema[field]
|
154
|
+
# add_column view_name, column
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
# Remove fields from db no longer in schema
|
159
|
+
(fields_in_db.keys - fields_in_schema.keys & fields_in_db.keys).each do |field|
|
160
|
+
not_same = true
|
161
|
+
# column = fields_in_db[field]
|
162
|
+
# remove_column view_name, column.name
|
163
|
+
end
|
164
|
+
|
165
|
+
puts "DB_SELECT="+db_select
|
166
|
+
puts "QUERY="+select_query
|
167
|
+
puts "NOT SAME="+not_same.to_s
|
168
|
+
if not_same or (db_select != select_query)
|
169
|
+
drop_view view_name
|
170
|
+
return method_missing_without_auto_migration(method, *[view_name, options], &block)
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
def auto_add_index(method, *args, &block)
|
177
|
+
table_name = args.shift.to_s
|
178
|
+
fields = Array(args.shift).map(&:to_s)
|
179
|
+
options = args.shift
|
180
|
+
|
181
|
+
index_name = options[:name] if options
|
182
|
+
index_name ||= "index_#{table_name}_on_#{fields.join('_and_')}"
|
183
|
+
|
184
|
+
(self.indexes_in_schema ||= []) << index_name
|
185
|
+
|
186
|
+
unless ActiveRecord::Base.connection.indexes(table_name).detect { |i| i.name == index_name }
|
187
|
+
method_missing_without_auto_migration(method, *[table_name, fields, options], &block)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def drop_unused_tables
|
192
|
+
(ActiveRecord::Base.connection.tables - tables_in_schema - ["schema_info"]).each do |table|
|
193
|
+
drop_table table if table != "schema_migrations"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def drop_unused_views
|
198
|
+
# temporary
|
199
|
+
return true
|
200
|
+
(ActiveRecord::Base.connection.views - views_in_schema - ["schema_info"]).each do |view|
|
201
|
+
drop_view view
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def drop_unused_indexes
|
206
|
+
tables_in_schema.each do |table_name|
|
207
|
+
indexes_in_db = ActiveRecord::Base.connection.indexes(table_name).map(&:name) rescue next
|
208
|
+
(indexes_in_db - indexes_in_schema & indexes_in_db).each do |index_name|
|
209
|
+
remove_index table_name, :name => index_name
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module SexyStatementsHook
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
class << base
|
6
|
+
cattr_accessor :sexy_up, :sexy_down, :desired_migration_name
|
7
|
+
self.sexy_up, self.sexy_down, self.desired_migration_name = "","",""
|
8
|
+
alias_method_chain :method_missing, :sexy_statements
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
def add_to_migration_name(what)
|
15
|
+
if self.desired_migration_name.length < 100
|
16
|
+
self.desired_migration_name << "_" unless self.desired_migration_name.blank?
|
17
|
+
self.desired_migration_name << what
|
18
|
+
else
|
19
|
+
self.desired_migration_name << "and_more" unless self.desired_migration_name.index("and_more")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing_with_sexy_statements(method, *args, &block)
|
24
|
+
case method
|
25
|
+
when :create_table, :create_view
|
26
|
+
table_name = args.shift.to_s
|
27
|
+
lines = IO.readlines(File.join(DB_PROJECT_ROOT, 'db', 'plan.rb'))
|
28
|
+
inside_table = false
|
29
|
+
self.sexy_up << "\n"
|
30
|
+
for line in lines do
|
31
|
+
clean_line = line.gsub(/#.*/,"")
|
32
|
+
if clean_line =~ /create_(table|view)\W+#{table_name}(\W+|$)/i
|
33
|
+
inside_table = true
|
34
|
+
end
|
35
|
+
self.sexy_up << " " + line if inside_table
|
36
|
+
if inside_table and (clean_line =~ /\send\s*/i || clean_line =~ /^end\s*/i)
|
37
|
+
break
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
add_to_migration_name( "create_#{table_name}" )
|
42
|
+
|
43
|
+
else
|
44
|
+
add_to_migration_name( method.to_s.split('_')[0] + ("_"+args[0].to_s rescue "") + ("_"+args[1].to_s rescue "") )
|
45
|
+
self.sexy_up << " " + method.to_s + " " + args.collect{ |a| a.inspect }.join(",") + "\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
# auto_create_table(method, *args, &block)
|
49
|
+
# when :add_index
|
50
|
+
# auto_add_index(method, *args, &block)
|
51
|
+
# else
|
52
|
+
# method_missing_without_auto_migration(method, *args, &block)
|
53
|
+
# end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# This is for Rails
|
2
|
+
|
3
|
+
#require 'rails_generator'
|
4
|
+
#require 'rails_generator/base'
|
5
|
+
#require 'railties/lib/rails_generator/base'
|
6
|
+
|
7
|
+
DB_PROJECT_ROOT = RAILS_ROOT
|
8
|
+
require File.join( File.expand_path(File.dirname(__FILE__)),'','migration_generator_core' )
|
9
|
+
|
10
|
+
class MigrationGenerator < Rails::Generator::Base
|
11
|
+
|
12
|
+
def initialize(runtime_args, runtime_options = {})
|
13
|
+
super
|
14
|
+
@migration_arg_name = runtime_args.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def manifest
|
18
|
+
mg = MigrationGeneratorCore.new
|
19
|
+
up,down,hints,migration_name = mg.calculate_migration( @migration_arg_name )
|
20
|
+
|
21
|
+
record do |m|
|
22
|
+
m.migration_template 'migration.rb', 'db/migrate',
|
23
|
+
:assigns => { :up => up, :down => down, :hints => hints, :migration_name => migration_name.camelize },
|
24
|
+
:migration_file_name => migration_name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# you should set DB_PROJECT_ROOT constant to some path before including this file
|
2
|
+
|
3
|
+
class MigrationGeneratorCore
|
4
|
+
|
5
|
+
DB_PROJECT_ROOT = "." if not defined?(DB_PROJECT_ROOT)
|
6
|
+
|
7
|
+
def migration_default_name
|
8
|
+
i = Dir["#{DB_PROJECT_ROOT}/db/migrate/*definition_migration*"].length
|
9
|
+
"definition_migration_#{i+1}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def calculate_migration(predefined_migration_name=nil)
|
13
|
+
require File.join( File.expand_path(File.dirname(__FILE__)),'lib','auto_migrations.rb')
|
14
|
+
require File.join( File.expand_path(File.dirname(__FILE__)),'lib','sexy_statements_hook.rb')
|
15
|
+
ActiveRecord::Migration.send :include, SexyStatementsHook
|
16
|
+
ActiveRecord::Migration.send :include, AutoMigrations
|
17
|
+
|
18
|
+
AutoMigrations.run
|
19
|
+
|
20
|
+
print "Migration generated. Self.up is:\n" + ActiveRecord::Migration.sexy_up
|
21
|
+
|
22
|
+
migration_name = predefined_migration_name
|
23
|
+
if migration_name.blank?
|
24
|
+
name = ActiveRecord::Migration.desired_migration_name
|
25
|
+
name = migration_default_name if name.blank?
|
26
|
+
migration_name = input("\nEnter filename [#{name}]:").strip.gsub(' ', '_')
|
27
|
+
migration_name = name if migration_name.blank?
|
28
|
+
end
|
29
|
+
|
30
|
+
up = ActiveRecord::Migration.sexy_up + " "
|
31
|
+
down = ActiveRecord::Migration.sexy_down
|
32
|
+
|
33
|
+
hints = <<HINT
|
34
|
+
|
35
|
+
# Hints on migrations syntax.
|
36
|
+
#
|
37
|
+
# add_column(table_name, column_name, type, options = {})
|
38
|
+
# Types are: :primary_key, :string, :text, :integer, :float, :datetime, :timestamp, :time, :date, :binary, :boolean.
|
39
|
+
#
|
40
|
+
# Other stuff:
|
41
|
+
# change_column(table_name, column_name, type, options = {}) - options as in add_column
|
42
|
+
# change_column_default(table_name, column_name, default)
|
43
|
+
# remove_column(table_name, column_name)
|
44
|
+
# rename_column(table_name, column_name, new_column_name)
|
45
|
+
#
|
46
|
+
# Sample: Don't add a primary key column
|
47
|
+
# create_table(:categories_suppliers, :id => false) do |t|
|
48
|
+
# t.column :category_id, :integer
|
49
|
+
# t.column :supplier_id, :integer
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# Sample: reload columns for a model from DB
|
53
|
+
# Person.reset_column_information
|
54
|
+
#
|
55
|
+
# More samples here: http://guides.rubyonrails.org/migrations.html
|
56
|
+
HINT
|
57
|
+
|
58
|
+
#return { :up => up, :down => down, :hints => hints, :migration_name => migration_name.camelize, :migration_file_name => migration_name }
|
59
|
+
return up,down,hints,migration_name
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def input(prompt, options=nil)
|
65
|
+
print(prompt + " ")
|
66
|
+
if options
|
67
|
+
while !(response = STDIN.readline.strip.downcase).in?(options);
|
68
|
+
print(prompt + " ")
|
69
|
+
end
|
70
|
+
response
|
71
|
+
else
|
72
|
+
STDIN.readline
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This is for Sinatra
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
require 'active_support/core_ext/string/strip'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
DB_PROJECT_ROOT = "."
|
8
|
+
require File.join( File.expand_path(File.dirname(__FILE__)),'migration_generator_core' )
|
9
|
+
|
10
|
+
module Sinatra
|
11
|
+
module ActiveRecordTasks
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def create_migration(migration_name, version = nil)
|
15
|
+
|
16
|
+
mg = MigrationGeneratorCore.new
|
17
|
+
up,down,hints,migration_name = mg.calculate_migration( migration_name )
|
18
|
+
|
19
|
+
migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
20
|
+
migration_file = File.join(migrations_dir, "#{migration_number}_#{migration_name}.rb")
|
21
|
+
|
22
|
+
FileUtils.mkdir_p(migrations_dir)
|
23
|
+
|
24
|
+
File.open(migration_file, 'w') do |file|
|
25
|
+
file.write <<-MIGRATION.strip_heredoc
|
26
|
+
class #{ migration_name.camelize } < ActiveRecord::Migration
|
27
|
+
def self.up
|
28
|
+
#{ up }
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.down
|
32
|
+
#{ down }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
#{ hints }
|
37
|
+
MIGRATION
|
38
|
+
end
|
39
|
+
|
40
|
+
# puts "done"
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
# no need to load because already loaded from sinatra_activerecord
|
49
|
+
# load 'sinatra/activerecord/tasks.rake'
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: data_plan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Pavel Vasev
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-11-28 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Edit you db schema in db/plan.rb file. It has same syntax as rails schema.rb, but you can also leave comments and so on. Then, generate migration, and it will be prefilled with diff between plan.rb and your current db.
|
22
|
+
email: pavel.vasev@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- lib/data_plan/generators/migration/lib/auto_migrations.rb
|
31
|
+
- lib/data_plan/generators/migration/lib/sexy_statements_hook.rb
|
32
|
+
- lib/data_plan/generators/migration/migration_generator.rb
|
33
|
+
- lib/data_plan/generators/migration/migration_generator_core.rb
|
34
|
+
- lib/data_plan/generators/migration/sinatra.rb
|
35
|
+
- lib/data_plan/generators/migration/templates/migration.rb
|
36
|
+
- Rakefile
|
37
|
+
- README
|
38
|
+
- LICENSE
|
39
|
+
- test/test_data_plan.rb
|
40
|
+
homepage: http://rubygems.org/gems/data_plan
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
hash: 3
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 3
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.24
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Sinatra/ActiveRecord tool for easy migration generation. Works with Rails too.
|
73
|
+
test_files: []
|
74
|
+
|