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 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
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+
3
+ class AutoMigrationsTest < Test::Unit::TestCase
4
+ # Replace this with your real tests.
5
+ def test_this_plugin
6
+ puts 'hello world'
7
+ end
8
+ 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: []