db_auto_migrations 1.0.1
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.
- 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: []
|