migsupo 0.1.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 +7 -0
- data/README.md +246 -0
- data/lib/migsupo/configuration.rb +19 -0
- data/lib/migsupo/differ/diff.rb +22 -0
- data/lib/migsupo/differ/diff_calculator.rb +123 -0
- data/lib/migsupo/differ/operations/add_column.rb +27 -0
- data/lib/migsupo/differ/operations/add_index.rb +27 -0
- data/lib/migsupo/differ/operations/change_column.rb +33 -0
- data/lib/migsupo/differ/operations/create_table.rb +30 -0
- data/lib/migsupo/differ/operations/drop_table.rb +30 -0
- data/lib/migsupo/differ/operations/remove_column.rb +31 -0
- data/lib/migsupo/differ/operations/remove_index.rb +27 -0
- data/lib/migsupo/differ/operations/rename_column.rb +28 -0
- data/lib/migsupo/generator/migration_builder.rb +185 -0
- data/lib/migsupo/generator/migration_generator.rb +65 -0
- data/lib/migsupo/generator/naming.rb +45 -0
- data/lib/migsupo/loader/active_record_loader.rb +97 -0
- data/lib/migsupo/loader/schema_rb_loader.rb +24 -0
- data/lib/migsupo/parser/dsl_context.rb +49 -0
- data/lib/migsupo/parser/schemafile_parser.rb +18 -0
- data/lib/migsupo/parser/table_dsl_context.rb +92 -0
- data/lib/migsupo/railtie.rb +11 -0
- data/lib/migsupo/schema/column_definition.rb +42 -0
- data/lib/migsupo/schema/index_definition.rb +44 -0
- data/lib/migsupo/schema/schema_definition.rb +20 -0
- data/lib/migsupo/schema/table_definition.rb +31 -0
- data/lib/migsupo/tasks/migsupo.rake +56 -0
- data/lib/migsupo/version.rb +3 -0
- data/lib/migsupo.rb +75 -0
- data/migsupo.gemspec +23 -0
- metadata +156 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9f22d99bd89a407d32621aadf871aa3a6059291b338aa2df6b9f12cd29fa6abf
|
|
4
|
+
data.tar.gz: 555ccc440d31b410b015f4975b3835f590fa15e900c759d166b3ad1cbb842327
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c9d49e0b2092d947a31783bad5c5052b658da6be8b383f4473e91d0afa82e59a0f198288fcffd9eeb03b3a787b85771cefa2bac502fd806616d8460bd5419362
|
|
7
|
+
data.tar.gz: cb2ff4341a47c1c646b32cce37dc771b1e85acb1d42d97b42394f8d15f174716707495d118731d8043a8d468eb8fd17414f041ceff7001b23fc4b0539c5c89cb
|
data/README.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Migsupo
|
|
2
|
+
|
|
3
|
+
Migsupo is a Rails gem that generates migration files from the diff between a **Schemafile** (your desired schema) and the current database state.
|
|
4
|
+
|
|
5
|
+
It is inspired by [ridgepole](https://github.com/ridgepole/ridgepole) but with a key difference: instead of applying schema changes directly to the database, Migsupo generates standard Rails migration files that you can review, modify, and run through the normal `rails db:migrate` workflow.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Schemafile → migsupo → db/migrate/*.rb → rails db:migrate → DB
|
|
11
|
+
(desired state) (auto-generated) ↓
|
|
12
|
+
db/schema.rb
|
|
13
|
+
(managed by Rails)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
You define your desired schema in a `Schemafile` using the same DSL as ridgepole. Migsupo compares it against the current database and generates migration files for any differences.
|
|
17
|
+
|
|
18
|
+
### File Responsibilities
|
|
19
|
+
|
|
20
|
+
| File | Managed by | Purpose |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `Schemafile` | You | Declares the desired schema state |
|
|
23
|
+
| `db/migrate/*.rb` | Migsupo (generated) + you (reviewed) | Incremental changes to apply |
|
|
24
|
+
| `db/schema.rb` | Rails | Snapshot of the current schema after migrations — do not edit manually |
|
|
25
|
+
|
|
26
|
+
The `Schemafile` and `db/schema.rb` are intentionally separate. Rails owns `db/schema.rb` and keeps it in sync after every `rails db:migrate`. The `Schemafile` is yours to manage — Rails never touches it.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
Add to your `Gemfile`:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
gem "migsupo"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then run:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bundle install
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Getting Started
|
|
43
|
+
|
|
44
|
+
### 1. Create a Schemafile
|
|
45
|
+
|
|
46
|
+
Create a `Schemafile` in your Rails root. For existing projects, you can use `db/schema.rb` as a reference — copy the `create_table` and `add_index` blocks as-is (without the `ActiveRecord::Schema.define` wrapper).
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Example: use schema.rb as a starting point
|
|
50
|
+
grep -v "ActiveRecord::Schema\|^end$\|^#\|version:" db/schema.rb > Schemafile
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
From this point on, the `Schemafile` is yours to manage. Rails will not touch it.
|
|
54
|
+
|
|
55
|
+
### 2. Edit the Schemafile to describe your desired schema
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
# Schemafile
|
|
59
|
+
|
|
60
|
+
create_table "users", force: :cascade do |t|
|
|
61
|
+
t.string "name", null: false
|
|
62
|
+
t.string "email", null: false
|
|
63
|
+
t.integer "age"
|
|
64
|
+
t.timestamps
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
add_index "users", ["email"], name: "index_users_on_email", unique: true
|
|
68
|
+
|
|
69
|
+
create_table "posts", force: :cascade do |t|
|
|
70
|
+
t.string "title", null: false
|
|
71
|
+
t.text "body"
|
|
72
|
+
t.references "user"
|
|
73
|
+
t.timestamps
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3. Generate migration files
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
rails db:generate_migration
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Migsupo compares the Schemafile against the current database and writes migration files to `db/migrate/`.
|
|
84
|
+
|
|
85
|
+
### 4. Review and run migrations
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Review the generated files
|
|
89
|
+
cat db/migrate/20260324120000_create_users.rb
|
|
90
|
+
|
|
91
|
+
# Apply to the database
|
|
92
|
+
rails db:migrate
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Commands
|
|
96
|
+
|
|
97
|
+
### `rails db:generate_migration`
|
|
98
|
+
|
|
99
|
+
Generate migration files for all differences between the Schemafile and the current database.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
rails db:generate_migration
|
|
103
|
+
rails db:generate_migration SCHEMAFILE=db/Schemafile
|
|
104
|
+
rails db:generate_migration OUTPUT_DIR=db/migrate
|
|
105
|
+
rails db:generate_migration DRY_RUN=true # print to stdout, no files written
|
|
106
|
+
rails db:generate_migration VERBOSE=true # also print diff summary
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `rails db:generate_migration:diff`
|
|
110
|
+
|
|
111
|
+
Print a human-readable diff between the Schemafile and the current database. No files are written.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
rails db:generate_migration:diff
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `rails db:generate_migration:check`
|
|
118
|
+
|
|
119
|
+
Exit with code 1 if the Schemafile and the current database are not in sync. Useful in CI pipelines.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
rails db:generate_migration:check
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Environment Variables
|
|
126
|
+
|
|
127
|
+
| Variable | Default | Description |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `SCHEMAFILE` | `Schemafile` | Path to the Schemafile |
|
|
130
|
+
| `OUTPUT_DIR` | `db/migrate` | Output directory for generated migration files |
|
|
131
|
+
| `LOADER` | `activerecord` | Schema loader: `activerecord` or `schema_rb` |
|
|
132
|
+
| `DRY_RUN` | `false` | Print migrations to stdout instead of writing files |
|
|
133
|
+
| `VERBOSE` | `false` | Print diff summary before generating files |
|
|
134
|
+
|
|
135
|
+
### Loaders
|
|
136
|
+
|
|
137
|
+
- **`activerecord`** (default): Reads the current schema directly from the database via `ActiveRecord::Base.connection`. Always reflects the true current state.
|
|
138
|
+
- **`schema_rb`**: Reads from `db/schema.rb` without a live database connection. Useful for offline environments, but only as accurate as the last `rails db:migrate` run.
|
|
139
|
+
|
|
140
|
+
## Configuration
|
|
141
|
+
|
|
142
|
+
You can configure Migsupo in an initializer:
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
# config/initializers/migsupo.rb
|
|
146
|
+
Migsupo.configure do |config|
|
|
147
|
+
config.schemafile_path = Rails.root.join("db/Schemafile")
|
|
148
|
+
config.migrations_dir = Rails.root.join("db/migrate")
|
|
149
|
+
config.ignored_tables = %w[schema_migrations ar_internal_metadata]
|
|
150
|
+
config.migration_version = "7.1" # defaults to current Rails version
|
|
151
|
+
|
|
152
|
+
# Explicit rename hints (see "Column Renames" below)
|
|
153
|
+
config.rename_hints = {
|
|
154
|
+
"users" => { "full_name" => "name" }
|
|
155
|
+
}
|
|
156
|
+
end
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Generated Migration Examples
|
|
160
|
+
|
|
161
|
+
### New table
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
class CreateUsers < ActiveRecord::Migration[7.1]
|
|
165
|
+
def change
|
|
166
|
+
create_table :users do |t|
|
|
167
|
+
t.string :name, null: false
|
|
168
|
+
t.string :email, null: false
|
|
169
|
+
t.integer :age
|
|
170
|
+
|
|
171
|
+
t.timestamps
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
add_index :users, [:email], name: "index_users_on_email", unique: true
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Add columns
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
class AddColumnsToUsers < ActiveRecord::Migration[7.1]
|
|
183
|
+
def change
|
|
184
|
+
add_column :users, :phone, :string
|
|
185
|
+
add_index :users, [:phone], name: "index_users_on_phone"
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Change column type (uses explicit `up`/`down`)
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
class ModifyUsers < ActiveRecord::Migration[7.1]
|
|
194
|
+
def up
|
|
195
|
+
change_column :users, :age, :bigint
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def down
|
|
199
|
+
change_column :users, :age, :integer
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Column Renames
|
|
205
|
+
|
|
206
|
+
Migsupo cannot automatically distinguish a rename from a drop + add, so rename detection is **opt-in** via `rename_hints`. Without a hint, Migsupo will emit `remove_column` + `add_column`, which would cause data loss.
|
|
207
|
+
|
|
208
|
+
```ruby
|
|
209
|
+
# config/initializers/migsupo.rb
|
|
210
|
+
Migsupo.configure do |config|
|
|
211
|
+
config.rename_hints = {
|
|
212
|
+
"users" => { "full_name" => "name" }
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
This generates `rename_column` instead of `remove_column` + `add_column`.
|
|
218
|
+
|
|
219
|
+
## CI Integration
|
|
220
|
+
|
|
221
|
+
Use `db:generate_migration:check` to verify that your Schemafile and database are always in sync after all migrations have been applied:
|
|
222
|
+
|
|
223
|
+
```yaml
|
|
224
|
+
# .github/workflows/ci.yml
|
|
225
|
+
- name: Check schema sync
|
|
226
|
+
run: bundle exec rails db:generate_migration:check
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Comparison with ridgepole
|
|
230
|
+
|
|
231
|
+
| | ridgepole | migsupo |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| Schema definition | Schemafile | Schemafile (compatible) |
|
|
234
|
+
| How changes are applied | Directly to DB | Generates Rails migration files |
|
|
235
|
+
| Rails migration workflow | Bypassed | Preserved |
|
|
236
|
+
| Rollback support | No | Yes (via `rails db:rollback`) |
|
|
237
|
+
| Review before applying | Not built-in | Yes (review generated files) |
|
|
238
|
+
|
|
239
|
+
## Requirements
|
|
240
|
+
|
|
241
|
+
- Ruby >= 3.0
|
|
242
|
+
- Rails >= 6.1
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_accessor :schemafile_path
|
|
4
|
+
attr_accessor :migrations_dir
|
|
5
|
+
attr_accessor :loader
|
|
6
|
+
attr_accessor :ignored_tables
|
|
7
|
+
attr_accessor :rename_hints
|
|
8
|
+
attr_accessor :migration_version
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@schemafile_path = "Schemafile"
|
|
12
|
+
@migrations_dir = "db/migrate"
|
|
13
|
+
@loader = :active_record
|
|
14
|
+
@ignored_tables = %w[schema_migrations ar_internal_metadata]
|
|
15
|
+
@rename_hints = {}
|
|
16
|
+
@migration_version = nil
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
class Diff
|
|
4
|
+
attr_reader :operations
|
|
5
|
+
|
|
6
|
+
def initialize(operations: [])
|
|
7
|
+
@operations = operations.freeze
|
|
8
|
+
freeze
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def empty?
|
|
12
|
+
@operations.empty?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_s
|
|
16
|
+
return "No changes." if empty?
|
|
17
|
+
|
|
18
|
+
@operations.map(&:to_s).join("\n")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require "set"
|
|
2
|
+
require_relative "diff"
|
|
3
|
+
require_relative "operations/create_table"
|
|
4
|
+
require_relative "operations/drop_table"
|
|
5
|
+
require_relative "operations/add_column"
|
|
6
|
+
require_relative "operations/remove_column"
|
|
7
|
+
require_relative "operations/change_column"
|
|
8
|
+
require_relative "operations/rename_column"
|
|
9
|
+
require_relative "operations/add_index"
|
|
10
|
+
require_relative "operations/remove_index"
|
|
11
|
+
|
|
12
|
+
module Migsupo
|
|
13
|
+
module Differ
|
|
14
|
+
class DiffCalculator
|
|
15
|
+
def initialize(rename_hints: {})
|
|
16
|
+
@rename_hints = rename_hints
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def calculate(desired:, current:)
|
|
20
|
+
operations = []
|
|
21
|
+
|
|
22
|
+
desired_names = Set.new(desired.tables.keys)
|
|
23
|
+
current_names = Set.new(current.tables.keys)
|
|
24
|
+
|
|
25
|
+
(desired_names - current_names).each do |name|
|
|
26
|
+
operations << Operations::CreateTable.new(desired.tables[name])
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
(current_names - desired_names).each do |name|
|
|
30
|
+
operations << Operations::DropTable.new(current.tables[name])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
(desired_names & current_names).each do |name|
|
|
34
|
+
operations.concat(diff_table(desired.tables[name], current.tables[name]))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Diff.new(operations: operations)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def diff_table(desired, current)
|
|
43
|
+
operations = []
|
|
44
|
+
operations.concat(diff_columns(desired, current))
|
|
45
|
+
operations.concat(diff_indexes(desired, current))
|
|
46
|
+
operations
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def diff_columns(desired, current)
|
|
50
|
+
desired_cols = desired.columns.each_with_object({}) { |c, h| h[c.name] = c }
|
|
51
|
+
current_cols = current.columns.each_with_object({}) { |c, h| h[c.name] = c }
|
|
52
|
+
|
|
53
|
+
added = desired_cols.keys - current_cols.keys
|
|
54
|
+
removed = current_cols.keys - desired_cols.keys
|
|
55
|
+
|
|
56
|
+
hints = @rename_hints[desired.name] || {}
|
|
57
|
+
operations = apply_rename_hints(desired.name, hints, added, removed, desired_cols, current_cols)
|
|
58
|
+
|
|
59
|
+
# Remaining added/removed after renames
|
|
60
|
+
renamed_old = operations.select { |op| op.is_a?(Operations::RenameColumn) }.map(&:old_name)
|
|
61
|
+
renamed_new = operations.select { |op| op.is_a?(Operations::RenameColumn) }.map(&:new_name)
|
|
62
|
+
|
|
63
|
+
(added - renamed_new).each do |name|
|
|
64
|
+
operations << Operations::AddColumn.new(table_name: desired.name, column: desired_cols[name])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
(removed - renamed_old).each do |name|
|
|
68
|
+
operations << Operations::RemoveColumn.new(table_name: desired.name, column: current_cols[name])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
(desired_cols.keys & current_cols.keys).each do |name|
|
|
72
|
+
next if desired_cols[name] == current_cols[name]
|
|
73
|
+
|
|
74
|
+
operations << Operations::ChangeColumn.new(
|
|
75
|
+
table_name: desired.name,
|
|
76
|
+
new_column: desired_cols[name],
|
|
77
|
+
old_column: current_cols[name]
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
operations
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def apply_rename_hints(table_name, hints, added, removed, desired_cols, current_cols)
|
|
85
|
+
operations = []
|
|
86
|
+
hints.each do |old_name, new_name|
|
|
87
|
+
next unless removed.include?(old_name) && added.include?(new_name)
|
|
88
|
+
|
|
89
|
+
operations << Operations::RenameColumn.new(
|
|
90
|
+
table_name: table_name,
|
|
91
|
+
old_name: old_name,
|
|
92
|
+
new_name: new_name
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
operations
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def diff_indexes(desired, current)
|
|
99
|
+
desired_idxs = desired.indexes.each_with_object({}) { |i, h| h[i.name] = i }
|
|
100
|
+
current_idxs = current.indexes.each_with_object({}) { |i, h| h[i.name] = i }
|
|
101
|
+
|
|
102
|
+
operations = []
|
|
103
|
+
|
|
104
|
+
(desired_idxs.keys - current_idxs.keys).each do |name|
|
|
105
|
+
operations << Operations::AddIndex.new(table_name: desired.name, index: desired_idxs[name])
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
(current_idxs.keys - desired_idxs.keys).each do |name|
|
|
109
|
+
operations << Operations::RemoveIndex.new(table_name: desired.name, index: current_idxs[name])
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
(desired_idxs.keys & current_idxs.keys).each do |name|
|
|
113
|
+
next if desired_idxs[name] == current_idxs[name]
|
|
114
|
+
|
|
115
|
+
operations << Operations::RemoveIndex.new(table_name: desired.name, index: current_idxs[name])
|
|
116
|
+
operations << Operations::AddIndex.new(table_name: desired.name, index: desired_idxs[name])
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
operations
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class AddColumn
|
|
5
|
+
attr_reader :table_name, :column
|
|
6
|
+
|
|
7
|
+
def initialize(table_name:, column:)
|
|
8
|
+
@table_name = table_name.to_s
|
|
9
|
+
@column = column
|
|
10
|
+
freeze
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def migration_type
|
|
14
|
+
:add_column
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def reversible?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
"add_column #{table_name}.#{column.name} (#{column.type})"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class AddIndex
|
|
5
|
+
attr_reader :table_name, :index
|
|
6
|
+
|
|
7
|
+
def initialize(table_name:, index:)
|
|
8
|
+
@table_name = table_name.to_s
|
|
9
|
+
@index = index
|
|
10
|
+
freeze
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def migration_type
|
|
14
|
+
:add_index
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def reversible?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
"add_index #{table_name} [#{index.columns.join(', ')}]"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class ChangeColumn
|
|
5
|
+
attr_reader :table_name, :new_column, :old_column
|
|
6
|
+
|
|
7
|
+
def initialize(table_name:, new_column:, old_column:)
|
|
8
|
+
@table_name = table_name.to_s
|
|
9
|
+
@new_column = new_column
|
|
10
|
+
@old_column = old_column
|
|
11
|
+
freeze
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def column_name
|
|
15
|
+
@new_column.name
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def migration_type
|
|
19
|
+
:change_column
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# change_column is irreversible in Rails unless we provide explicit up/down
|
|
23
|
+
def reversible?
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_s
|
|
28
|
+
"change_column #{table_name}.#{column_name} (#{old_column.type} -> #{new_column.type})"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class CreateTable
|
|
5
|
+
attr_reader :table
|
|
6
|
+
|
|
7
|
+
def initialize(table)
|
|
8
|
+
@table = table
|
|
9
|
+
freeze
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def table_name
|
|
13
|
+
@table.name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def migration_type
|
|
17
|
+
:create_table
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reversible?
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
"create_table #{table_name}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class DropTable
|
|
5
|
+
attr_reader :table
|
|
6
|
+
|
|
7
|
+
def initialize(table)
|
|
8
|
+
@table = table
|
|
9
|
+
freeze
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def table_name
|
|
13
|
+
@table.name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def migration_type
|
|
17
|
+
:drop_table
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reversible?
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
"drop_table #{table_name}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class RemoveColumn
|
|
5
|
+
attr_reader :table_name, :column
|
|
6
|
+
|
|
7
|
+
def initialize(table_name:, column:)
|
|
8
|
+
@table_name = table_name.to_s
|
|
9
|
+
@column = column
|
|
10
|
+
freeze
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def column_name
|
|
14
|
+
@column.name
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def migration_type
|
|
18
|
+
:remove_column
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def reversible?
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s
|
|
26
|
+
"remove_column #{table_name}.#{column_name}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class RemoveIndex
|
|
5
|
+
attr_reader :table_name, :index
|
|
6
|
+
|
|
7
|
+
def initialize(table_name:, index:)
|
|
8
|
+
@table_name = table_name.to_s
|
|
9
|
+
@index = index
|
|
10
|
+
freeze
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def migration_type
|
|
14
|
+
:remove_index
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def reversible?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
"remove_index #{table_name} [#{index.columns.join(', ')}]"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Differ
|
|
3
|
+
module Operations
|
|
4
|
+
class RenameColumn
|
|
5
|
+
attr_reader :table_name, :old_name, :new_name
|
|
6
|
+
|
|
7
|
+
def initialize(table_name:, old_name:, new_name:)
|
|
8
|
+
@table_name = table_name.to_s
|
|
9
|
+
@old_name = old_name.to_s
|
|
10
|
+
@new_name = new_name.to_s
|
|
11
|
+
freeze
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def migration_type
|
|
15
|
+
:rename_column
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def reversible?
|
|
19
|
+
true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
"rename_column #{table_name}.#{old_name} -> #{new_name}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|