nonschema_migrations 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: da4a766ada05593da5379df6b6dc1fde7b18aae17138f07f458dab54784f019f
4
+ data.tar.gz: c7d572cd3a1b3a37b2d6aa795efeb7939731ccbd9e2d14bee4d89ef1f447d74a
5
+ SHA512:
6
+ metadata.gz: 17fb2d645b46f83ddb25c069e8e2beeae6eb80d7821a0abe4f65386897644a075e54c88088d09f91cbd31f157eba63b547225891f93a9097d3bd63a42cfa8249
7
+ data.tar.gz: 83daa3c35a73bc96fbb26953e554a173f1079ea040b8737c6764b107efb7d2d8501dce9f337adf9cff4cc3a48bfcc7e7f787e37b9d0cc1da224234b8a76cdae1
@@ -0,0 +1,52 @@
1
+ require 'active_record/scoping/default'
2
+ require 'active_record/scoping/named'
3
+ require 'active_record/base'
4
+
5
+ module ActiveRecord
6
+ class DataMigration < ActiveRecord::Base
7
+ class << self
8
+ def primary_key
9
+ nil
10
+ end
11
+
12
+ def table_name
13
+ "#{table_name_prefix}data_migrations#{table_name_suffix}"
14
+ end
15
+
16
+ def index_name
17
+ "#{table_name_prefix}unique_data_migrations#{table_name_suffix}"
18
+ end
19
+
20
+ def table_exists?
21
+ connection.table_exists?(table_name)
22
+ end
23
+
24
+ def create_table(limit=nil)
25
+ unless table_exists?
26
+ version_options = {null: false}
27
+ version_options[:limit] = limit if limit
28
+
29
+ connection.create_table(table_name, id: false) do |t|
30
+ t.column :version, :string, version_options
31
+ end
32
+ connection.add_index table_name, :version, unique: true, name: index_name
33
+ end
34
+ end
35
+
36
+ def drop_table
37
+ if table_exists?
38
+ connection.remove_index table_name, name: index_name
39
+ connection.drop_table(table_name)
40
+ end
41
+ end
42
+
43
+ def normalize_migration_number(number)
44
+ "%.3d" % number.to_i
45
+ end
46
+ end
47
+
48
+ def version
49
+ super.to_i
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,28 @@
1
+
2
+ # this is the generator used to create a data migration
3
+
4
+ class DataMigrationGenerator < ActiveRecord::Generators::Base
5
+ self.source_root(File.join(self.superclass.base_root,'active_record/migration/templates'))
6
+
7
+ desc <<-DESC
8
+ Description:
9
+ Creates new nondestructive migration
10
+ DESC
11
+
12
+ def create_data_migration_file
13
+ migration_template "migration.rb", "db/data_migrate/#{file_name}.rb"
14
+ end
15
+
16
+ # 'migration.rb' now requires this var/method
17
+ def migration_action
18
+ 'create'
19
+ end
20
+
21
+ private
22
+
23
+ # this used in migration template which is inherited, we want this values to be an empty array.
24
+ def attributes
25
+ []
26
+ end
27
+ end
28
+
@@ -0,0 +1,22 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record'
4
+
5
+ module DataMigrations
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ desc "Creates an initializer and copy files to your application."
11
+ class_option :orm, type: 'boolean'
12
+
13
+ def self.next_migration_number(path)
14
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
15
+ end
16
+
17
+ def copy_initializer
18
+ migration_template "create_data_migrations.rb",
19
+ "db/migrate/create_data_migrations.rb"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ class CreateDataMigrations < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :data_migrations do |t|
4
+ t.string :version
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :data_migrations
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ require 'nonschema_migrations'
2
+
3
+ module DataMigrations
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ require 'tasks/data.rb'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+
2
+ MIGRATIONS_PATH = 'db/data_migrate'
3
+
4
+ require 'generators/data_migrations/install_generator.rb'
5
+ require 'generators/data_migration_generator.rb'
6
+ require 'active_record/data_migration.rb'
7
+ require 'nonschema_migrator.rb'
8
+
9
+ module NondestructiveMigrations
10
+ require "nonschema_migrations/railtie.rb" if defined?(Rails)
11
+ end
@@ -0,0 +1,161 @@
1
+
2
+
3
+
4
+ class NondestructiveMigrator < ActiveRecord::Migrator
5
+ # This class related to data migration.
6
+ # Used in rake tasks (rake data:[migrate|rollback|up|down])
7
+
8
+ if defined?(ActiveRecord::MigrationContext)
9
+ class SchemaMigration < ActiveRecord::SchemaMigration
10
+ def self.table_name
11
+ NondestructiveMigrator.schema_migrations_table_name
12
+ end
13
+ end
14
+
15
+ class MigrationContext < ActiveRecord::MigrationContext
16
+ def initialize(migrations_paths)
17
+ super(migrations_paths)
18
+ @schema_migration = NondestructiveMigrator::SchemaMigration
19
+ end
20
+
21
+ def new_migrator(*args)
22
+ result = NondestructiveMigrator.new(*args)
23
+ result.migration_context = self
24
+ result
25
+ end
26
+
27
+ # these methods are copied from ActiveRecord::Migrator
28
+ # replaced:
29
+ # 1.) ActiveRecord::SchemaMigration with @schema_migration
30
+ # 2.) ActiveRecord::Migrator.new with new_migrator
31
+
32
+ def get_all_versions
33
+ if @schema_migration.table_exists?
34
+ @schema_migration.all_versions.map(&:to_i)
35
+ else
36
+ []
37
+ end
38
+ end
39
+
40
+ def migrations_status
41
+ db_list = @schema_migration.normalized_versions
42
+
43
+ file_list = migration_files.map do |file|
44
+ version, name, scope = parse_migration_filename(file)
45
+ raise IllegalMigrationNameError.new(file) unless version
46
+ version = @schema_migration.normalize_migration_number(version)
47
+ status = db_list.delete(version) ? "up" : "down"
48
+ [status, version, (name + scope).humanize]
49
+ end.compact
50
+
51
+ db_list.map! do |version|
52
+ ["up", version, "********** NO FILE **********"]
53
+ end
54
+
55
+ (db_list + file_list).sort_by { |_, version, _| version }
56
+ end
57
+
58
+ def move(direction, steps)
59
+ migrator = new_migrator(direction, migrations)
60
+
61
+ if current_version != 0 && !migrator.current_migration
62
+ raise UnknownMigrationVersionError.new(current_version)
63
+ end
64
+
65
+ start_index =
66
+ if current_version == 0
67
+ 0
68
+ else
69
+ migrator.migrations.index(migrator.current_migration)
70
+ end
71
+
72
+ finish = migrator.migrations[start_index + steps]
73
+ version = finish ? finish.version : 0
74
+ send(direction, version)
75
+ end
76
+
77
+ def up(target_version = nil)
78
+ selected_migrations = if block_given?
79
+ migrations.select { |m| yield m }
80
+ else
81
+ migrations
82
+ end
83
+
84
+ new_migrator(:up, selected_migrations, target_version).migrate
85
+ end
86
+
87
+ def down(target_version = nil)
88
+ selected_migrations = if block_given?
89
+ migrations.select { |m| yield m }
90
+ else
91
+ migrations
92
+ end
93
+
94
+ new_migrator(:down, selected_migrations, target_version).migrate
95
+ end
96
+ end
97
+
98
+ class << self
99
+ def context(path)
100
+ NondestructiveMigrator::MigrationContext.new(path)
101
+ end
102
+
103
+ def new_migrator(path, *args)
104
+ result = self.new(*args)
105
+ result.migration_context=context(path)
106
+ result
107
+ end
108
+
109
+ def migrate(path)
110
+ context(path).migrate()
111
+ end
112
+
113
+ def run(direction, path, target_version)
114
+ new_migrator(path, direction, context(path).migrations, target_version).run
115
+ end
116
+ end
117
+
118
+ def migration_context=(context)
119
+ @migration_context = context
120
+ end
121
+
122
+ def load_migrated
123
+ @migrated_versions = Set.new(@migration_context.get_all_versions)
124
+ end
125
+ end
126
+
127
+ def record_version_state_after_migrating(version)
128
+ if down?
129
+ migrated.delete(version)
130
+ ActiveRecord::DataMigration.where(:version => version.to_s).delete_all
131
+ else
132
+ migrated << version
133
+ ActiveRecord::DataMigration.create!(:version => version.to_s)
134
+ end
135
+ end
136
+
137
+
138
+ class <<self
139
+ def migrations_path
140
+ MIGRATIONS_PATH
141
+ end
142
+
143
+ def schema_migrations_table_name
144
+ 'data_migrations'
145
+ end
146
+
147
+ def schema_migrations_table_name
148
+ ActiveRecord::DataMigration.table_name
149
+ end
150
+
151
+ def get_all_versions(connection = ActiveRecord::Base.connection)
152
+ if connection.table_exists?(schema_migrations_table_name)
153
+ ActiveRecord::DataMigration.all.map { |x| x.version.to_i }.sort
154
+ else
155
+ []
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+
data/lib/tasks/data.rb ADDED
@@ -0,0 +1,34 @@
1
+
2
+
3
+ namespace :data do
4
+ task :data_migration_dependencies => :environment do
5
+ require 'nonschema_migrations'
6
+ end
7
+
8
+ desc "run data migration (#{MIGRATIONS_PATH})"
9
+ task :migrate => :data_migration_dependencies do
10
+ NondestructiveMigrator.migrate(MIGRATIONS_PATH)
11
+ end
12
+
13
+ desc "rollback data migration (#{MIGRATIONS_PATH})"
14
+ task :rollback => :data_migration_dependencies do
15
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
16
+ NondestructiveMigrator.rollback(MIGRATIONS_PATH,step)
17
+ end
18
+
19
+ namespace :migrate do
20
+ desc %Q{runs the "up" for a given _data_ migration VERSION}
21
+ task :up => :data_migration_dependencies do
22
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
23
+ raise "VERSION is required" unless version
24
+ NondestructiveMigrator.run(:up, MIGRATIONS_PATH, version)
25
+ end
26
+
27
+ desc %Q{runs the "down" for a given _data_ migration VERSION}
28
+ task :down => :data_migration_dependencies do
29
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
30
+ raise "VERSION is required" unless version
31
+ NondestructiveMigrator.run(:down, MIGRATIONS_PATH, version)
32
+ end
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nonschema_migrations
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jason Fleetwood-Boldt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-05-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ description: Separate schema-only migrations from nonschema (data) migrations in your
28
+ Rails app
29
+ email: jason.fb@datatravels.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/active_record/data_migration.rb
35
+ - lib/generators/data_migration_generator.rb
36
+ - lib/generators/data_migrations/install_generator.rb
37
+ - lib/generators/data_migrations/templates/create_data_migrations.rb
38
+ - lib/nonschema_migrations.rb
39
+ - lib/nonschema_migrations/railtie.rb
40
+ - lib/nonschema_migrator.rb
41
+ - lib/tasks/data.rb
42
+ homepage: https://github.com/jasonfb/nonschema_migrations
43
+ licenses:
44
+ - MIT
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.7.9
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: Nonschema(data-only) migrations for your Rails app
66
+ test_files: []