db_auto_migrations 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/LICENSE +21 -0
- data/README +46 -0
- data/Rakefile +40 -0
- data/VERSION +1 -0
- data/bin/setup +8 -0
- data/db_auto_migrations.gemspec +39 -0
- data/init.rb +1 -0
- data/lib/db_auto_migrations.rb +194 -0
- data/lib/tasks/db_auto_migrations_tasks.rake +20 -0
- data/test/db_auto_migrations_test.rb +8 -0
- metadata +55 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: df6c792de2c4c0f0b66a8b3820e90c3009a50cdbce199fd1131cb0de91e6d0cc
|
4
|
+
data.tar.gz: 67a006293c936f44c594180e32510fa4dba8b97fef80a8aac436316c4ab3c870
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 93296e2066d8659e27f97bea67ddbbf3d8629f8203e8302d8fc9d608c4e216992c36a336fc07a50cf25272044faff5c64c804003cb0f49a94948b5b90c37c2ee
|
7
|
+
data.tar.gz: ff3cb880fb309b4c50628aa9c4a3b1f5c80584bf09f4ba76ec96378bd51428ff70e2356be0f6f63ccb841190a50733cce38c38e31794f61a46fe2b23d9383f3e
|
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 sai
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
== AutoMigrations
|
2
|
+
|
3
|
+
Forget migrations, auto-migrate!
|
4
|
+
|
5
|
+
|
6
|
+
== Usage
|
7
|
+
|
8
|
+
Write out your schema (or use an existing one)
|
9
|
+
|
10
|
+
$ cat db/schema.rb
|
11
|
+
|
12
|
+
ActiveRecord::Schema.define do
|
13
|
+
|
14
|
+
create_table :posts do |t|
|
15
|
+
t.string :title
|
16
|
+
t.text :body
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
$ rake db:auto:migrate
|
23
|
+
|
24
|
+
Created posts table
|
25
|
+
|
26
|
+
...a few days later
|
27
|
+
|
28
|
+
$ cat db/schema.rb
|
29
|
+
|
30
|
+
ActiveRecord::Schema.define do
|
31
|
+
|
32
|
+
create_table :posts do |t|
|
33
|
+
t.string :title
|
34
|
+
t.text :content
|
35
|
+
t.timestamps
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
$ rake db:auto:migrate
|
41
|
+
-- add_column("posts", :content, :text)
|
42
|
+
-> 0.0307s
|
43
|
+
-- remove_column("posts", "body")
|
44
|
+
-> 0.0311s
|
45
|
+
|
46
|
+
* PJ Hyett [ pjhyett@gmail.com ]
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gemspec|
|
9
|
+
gemspec.name = "db_auto_migrations"
|
10
|
+
gemspec.summary = "Auto database migration."
|
11
|
+
gemspec.description = "Auto database migration."
|
12
|
+
gemspec.email = "rubyer1993@gmail.com"
|
13
|
+
gemspec.homepage = "https://github.com/sai1024/auto_migrations"
|
14
|
+
gemspec.authors = ["sai (originally by PJ Hyett)"]
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Default: run unit tests.'
|
22
|
+
task :default => :test
|
23
|
+
|
24
|
+
desc 'Test the auto_migrations plugin.'
|
25
|
+
Rake::TestTask.new(:test) do |t|
|
26
|
+
t.libs << 'lib'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Generate documentation for the auto_migrations plugin.'
|
32
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
33
|
+
files = ['README', 'LICENSE', 'lib/**/*.rb']
|
34
|
+
rdoc.rdoc_files.add(files)
|
35
|
+
rdoc.main = "README" # page to start on
|
36
|
+
rdoc.title = "auto_migrations"
|
37
|
+
rdoc.template = File.exists?(t="/Users/chris/ruby/projects/err/rock/template.rb") ? t : "/var/www/rock/template.rb"
|
38
|
+
rdoc.rdoc_dir = 'doc' # rdoc output folder
|
39
|
+
rdoc.options << '--inline-source'
|
40
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.1
|
data/bin/setup
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: db_auto_migrations 1.0.1 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "db_auto_migrations".freeze
|
9
|
+
s.version = "1.0.1"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib".freeze]
|
13
|
+
s.authors = ["sai (originally by PJ Hyett)".freeze]
|
14
|
+
s.date = "2021-12-07"
|
15
|
+
s.description = "Auto database migration.".freeze
|
16
|
+
s.email = "rubyer1993@gmail.com".freeze
|
17
|
+
s.executables = ["setup".freeze]
|
18
|
+
s.extra_rdoc_files = [
|
19
|
+
"LICENSE",
|
20
|
+
"README"
|
21
|
+
]
|
22
|
+
s.files = [
|
23
|
+
".document",
|
24
|
+
"LICENSE",
|
25
|
+
"README",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"bin/setup",
|
29
|
+
"db_auto_migrations.gemspec",
|
30
|
+
"init.rb",
|
31
|
+
"lib/db_auto_migrations.rb",
|
32
|
+
"lib/tasks/db_auto_migrations_tasks.rake",
|
33
|
+
"test/db_auto_migrations_test.rb"
|
34
|
+
]
|
35
|
+
s.homepage = "https://github.com/sai1024/auto_migrations".freeze
|
36
|
+
s.rubygems_version = "3.0.9".freeze
|
37
|
+
s.summary = "Auto database migration.".freeze
|
38
|
+
end
|
39
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'auto_migrations'
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# load rake
|
2
|
+
Dir[File.join(File.dirname(__FILE__),'tasks/**/*.rake')].each { |f| load f } if defined?(Rake)
|
3
|
+
|
4
|
+
module AutoMigrations
|
5
|
+
|
6
|
+
def self.run
|
7
|
+
# Turn off schema_info code for auto-migration
|
8
|
+
class << ActiveRecord::Schema
|
9
|
+
alias :old_define :define
|
10
|
+
attr_accessor :version
|
11
|
+
def define(info={}, &block) @version = Time.now.utc.strftime("%Y%m%d%H%M%S"); instance_eval(&block) end
|
12
|
+
end
|
13
|
+
|
14
|
+
load(File.join(Rails.root, 'db', 'schema.rb'))
|
15
|
+
ActiveRecord::Migration.drop_unused_tables
|
16
|
+
ActiveRecord::Migration.drop_unused_indexes
|
17
|
+
ActiveRecord::Migration.update_schema_version(ActiveRecord::Schema.version) if ActiveRecord::Schema.version
|
18
|
+
|
19
|
+
class << ActiveRecord::Schema
|
20
|
+
alias :define :old_define
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.schema_to_migration(with_reset = false)
|
25
|
+
schema_in = File.read(File.join(Rails.root, "db", "schema.rb"))
|
26
|
+
schema_in.gsub!(/#(.)+\n/, '')
|
27
|
+
schema_in.sub!(/ActiveRecord::Schema.define(.+)do[ ]?\n/, '')
|
28
|
+
schema_in.gsub!(/^/, ' ')
|
29
|
+
schema = "class InitialSchema < ActiveRecord::Migration\n def self.up\n"
|
30
|
+
schema += " # We're resetting the migrations database...\n" +
|
31
|
+
" drop_table :schema_migrations\n" +
|
32
|
+
" initialize_schema_migrations_table\n\n" if with_reset
|
33
|
+
schema += schema_in
|
34
|
+
schema << "\n def self.down\n"
|
35
|
+
schema << (ActiveRecord::Base.connection.tables - %w(schema_info schema_migrations)).map do |table|
|
36
|
+
" drop_table :#{table}\n"
|
37
|
+
end.join
|
38
|
+
schema << " end\nend\n"
|
39
|
+
migration_file = File.join(Rails.root, "db", "migrate", "001_initial_schema.rb")
|
40
|
+
File.open(migration_file, "w") { |f| f << schema }
|
41
|
+
puts "Migration created at db/migrate/001_initial_schema.rb"
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.included(base)
|
45
|
+
base.extend ClassMethods
|
46
|
+
class << base
|
47
|
+
cattr_accessor :tables_in_schema, :indexes_in_schema
|
48
|
+
self.tables_in_schema, self.indexes_in_schema = [], []
|
49
|
+
alias_method_chain :method_missing, :auto_migration
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
|
55
|
+
def method_missing_with_auto_migration(method, *args, &block)
|
56
|
+
case method
|
57
|
+
when :create_table
|
58
|
+
auto_create_table(method, *args, &block)
|
59
|
+
when :add_index
|
60
|
+
auto_add_index(method, *args, &block)
|
61
|
+
else
|
62
|
+
method_missing_without_auto_migration(method, *args, &block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def auto_create_table(method, *args, &block)
|
67
|
+
table_name = args.shift.to_s
|
68
|
+
options = args.pop || {}
|
69
|
+
|
70
|
+
(self.tables_in_schema ||= []) << table_name
|
71
|
+
|
72
|
+
# Table doesn't exist, create it
|
73
|
+
unless ActiveRecord::Base.connection.tables.include?(table_name)
|
74
|
+
return method_missing_without_auto_migration(method, *[table_name, options], &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Grab database columns
|
78
|
+
fields_in_db = ActiveRecord::Base.connection.columns(table_name).inject({}) do |hash, column|
|
79
|
+
hash[column.name] = column
|
80
|
+
hash
|
81
|
+
end
|
82
|
+
|
83
|
+
# Grab schema columns (lifted from active_record/connection_adapters/abstract/schema_statements.rb)
|
84
|
+
table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(ActiveRecord::Base.connection)
|
85
|
+
primary_key = options[:primary_key] || "id"
|
86
|
+
table_definition.primary_key(primary_key) unless options[:id] == false
|
87
|
+
yield table_definition
|
88
|
+
fields_in_schema = table_definition.columns.inject({}) do |hash, column|
|
89
|
+
hash[column.name.to_s] = column
|
90
|
+
hash
|
91
|
+
end
|
92
|
+
|
93
|
+
# Add fields to db new to schema
|
94
|
+
(fields_in_schema.keys - fields_in_db.keys).each do |field|
|
95
|
+
column = fields_in_schema[field]
|
96
|
+
options = {:limit => column.limit, :precision => column.precision, :scale => column.scale}
|
97
|
+
options[:default] = column.default if !column.default.nil?
|
98
|
+
options[:null] = column.null if !column.null.nil?
|
99
|
+
add_column table_name, column.name, column.type.to_sym, options
|
100
|
+
end
|
101
|
+
|
102
|
+
# Remove fields from db no longer in schema
|
103
|
+
(fields_in_db.keys - fields_in_schema.keys & fields_in_db.keys).each do |field|
|
104
|
+
column = fields_in_db[field]
|
105
|
+
remove_column table_name, column.name
|
106
|
+
end
|
107
|
+
|
108
|
+
(fields_in_schema.keys & fields_in_db.keys).each do |field|
|
109
|
+
if field != primary_key #ActiveRecord::Base.get_primary_key(table_name)
|
110
|
+
changed = false # flag
|
111
|
+
new_type = fields_in_schema[field].type.to_sym
|
112
|
+
new_attr = {}
|
113
|
+
|
114
|
+
# First, check if the field type changed
|
115
|
+
if fields_in_schema[field].type.to_sym != fields_in_db[field].type.to_sym
|
116
|
+
changed = true
|
117
|
+
end
|
118
|
+
|
119
|
+
# Special catch for precision/scale, since *both* must be specified together
|
120
|
+
# Always include them in the attr struct, but they'll only get applied if changed = true
|
121
|
+
new_attr[:precision] = fields_in_schema[field][:precision]
|
122
|
+
new_attr[:scale] = fields_in_schema[field][:scale]
|
123
|
+
|
124
|
+
# Next, iterate through our extended attributes, looking for any differences
|
125
|
+
# This catches stuff like :null, :precision, etc
|
126
|
+
fields_in_schema[field].each_pair do |att,value|
|
127
|
+
next if att == :type or att == :base or att == :name # special cases
|
128
|
+
if !value.nil?
|
129
|
+
value_in_db = fields_in_db[field].send(att)
|
130
|
+
value_in_db = value_in_db.to_i if att == :default && new_type == :integer && value_in_db.class == String
|
131
|
+
if att == :default && new_type == :boolean && value_in_db.class == String
|
132
|
+
value_in_db_to_i = value_in_db.to_i
|
133
|
+
value_in_db = false if value_in_db_to_i == 0
|
134
|
+
value_in_db = true if value_in_db_to_i == 1
|
135
|
+
end
|
136
|
+
|
137
|
+
if value != value_in_db
|
138
|
+
new_attr[att] = value
|
139
|
+
changed = true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Change the column if applicable
|
145
|
+
change_column table_name, field, new_type, new_attr if changed
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def auto_add_index(method, *args, &block)
|
151
|
+
table_name = args.shift.to_s
|
152
|
+
fields = Array(args.shift).map(&:to_s)
|
153
|
+
options = args.shift
|
154
|
+
|
155
|
+
index_name = options[:name] if options
|
156
|
+
index_name ||= ActiveRecord::Base.connection.index_name(table_name, :column => fields)
|
157
|
+
|
158
|
+
(self.indexes_in_schema ||= []) << index_name
|
159
|
+
|
160
|
+
unless ActiveRecord::Base.connection.indexes(table_name).detect { |i| i.name == index_name }
|
161
|
+
method_missing_without_auto_migration(method, *[table_name, fields, options], &block)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def drop_unused_tables
|
166
|
+
(ActiveRecord::Base.connection.tables - tables_in_schema - %w(schema_info schema_migrations)).each do |table|
|
167
|
+
drop_table table
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def drop_unused_indexes
|
172
|
+
tables_in_schema.each do |table_name|
|
173
|
+
indexes_in_db = ActiveRecord::Base.connection.indexes(table_name).map(&:name)
|
174
|
+
(indexes_in_db - indexes_in_schema & indexes_in_db).each do |index_name|
|
175
|
+
remove_index table_name, :name => index_name
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def update_schema_version(version)
|
181
|
+
if ActiveRecord::Base.connection.tables.include?("schema_migrations")
|
182
|
+
ActiveRecord::Base.connection.update("INSERT INTO schema_migrations VALUES ('#{version}')")
|
183
|
+
end
|
184
|
+
schema_file = File.join(Rails.root, "db", "schema.rb")
|
185
|
+
schema = File.read(schema_file)
|
186
|
+
schema.sub!(/:version => \d+/, ":version => #{version}")
|
187
|
+
File.open(schema_file, "w") { |f| f << schema }
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
ActiveRecord::Migration.send :include, AutoMigrations
|
@@ -0,0 +1,20 @@
|
|
1
|
+
namespace :db do
|
2
|
+
namespace :auto do
|
3
|
+
desc "Use schema.rb to auto-migrate"
|
4
|
+
task :migrate => :environment do
|
5
|
+
AutoMigrations.run
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
namespace :schema do
|
10
|
+
desc "Create migration from schema.rb"
|
11
|
+
task :to_migration => :environment do
|
12
|
+
AutoMigrations.schema_to_migration
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Create migration from schema.rb and reset migrations log"
|
16
|
+
task :to_migration_with_reset => :environment do
|
17
|
+
AutoMigrations.schema_to_migration(true)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: db_auto_migrations
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- sai (originally by PJ Hyett)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-12-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Auto database migration.
|
14
|
+
email: rubyer1993@gmail.com
|
15
|
+
executables:
|
16
|
+
- setup
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- LICENSE
|
20
|
+
- README
|
21
|
+
files:
|
22
|
+
- ".document"
|
23
|
+
- LICENSE
|
24
|
+
- README
|
25
|
+
- Rakefile
|
26
|
+
- VERSION
|
27
|
+
- bin/setup
|
28
|
+
- db_auto_migrations.gemspec
|
29
|
+
- init.rb
|
30
|
+
- lib/db_auto_migrations.rb
|
31
|
+
- lib/tasks/db_auto_migrations_tasks.rake
|
32
|
+
- test/db_auto_migrations_test.rb
|
33
|
+
homepage: https://github.com/sai1024/auto_migrations
|
34
|
+
licenses: []
|
35
|
+
metadata: {}
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubygems_version: 3.0.9
|
52
|
+
signing_key:
|
53
|
+
specification_version: 4
|
54
|
+
summary: Auto database migration.
|
55
|
+
test_files: []
|