nonschema_migrations 1.0.0

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: 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: []