ridgepole 1.0.0 → 1.0.3
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 +4 -4
- data/.rubocop.yml +9 -1
- data/.simplecov +1 -1
- data/CHANGELOG.md +65 -48
- data/README.md +38 -10
- data/bin/ridgepole +83 -85
- data/lib/ridgepole/client.rb +5 -0
- data/lib/ridgepole/delta.rb +22 -0
- data/lib/ridgepole/diff.rb +53 -5
- data/lib/ridgepole/dsl_parser/context.rb +16 -0
- data/lib/ridgepole/dumper.rb +1 -1
- data/lib/ridgepole/ext/abstract_adapter/partition_definition.rb +19 -0
- data/lib/ridgepole/ext/abstract_adapter/partition_options.rb +34 -0
- data/lib/ridgepole/ext/abstract_adapter/partitioning.rb +40 -0
- data/lib/ridgepole/ext/abstract_mysql_adapter/partitioning.rb +71 -0
- data/lib/ridgepole/ext/abstract_mysql_adapter/schema_creation.rb +46 -0
- data/lib/ridgepole/ext/postgresql_adapter/partitioning.rb +126 -0
- data/lib/ridgepole/ext/schema_dumper.rb +24 -0
- data/lib/ridgepole/external_sql_executer.rb +11 -13
- data/lib/ridgepole/version.rb +1 -1
- data/lib/ridgepole.rb +3 -0
- data/ridgepole.gemspec +3 -2
- metadata +14 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e83bd61a718b5b97d6be9214742e452fce8c54e9bff48e2b604344753138c0bb
|
|
4
|
+
data.tar.gz: f2ed01a46f18174e3173f07715002fc222467a341d9e93682910ef2c2497d613
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 62a7e740ec77f0124b3b9776a3c78fc8186a9f00d0f97917cae79342664f1a77e1f2ce3992e7e6e463c8fad76e2fba92af0f9a6031a70f7d545768dae2942ba1
|
|
7
|
+
data.tar.gz: 2f43e6f67be8820450c9fd47ddde4dacabe69778bbc1d3837b9ce8988e6b7393f80df3ed5a400a142a0a20a06c58344aa08490ea81cc25d4fdb10b56de824aec
|
data/.rubocop.yml
CHANGED
|
@@ -3,7 +3,7 @@ AllCops:
|
|
|
3
3
|
- "gemfiles/**/*"
|
|
4
4
|
- "omnibus-ridgepole/**/*"
|
|
5
5
|
- "vendor/bundle/**/*"
|
|
6
|
-
TargetRubyVersion: 2.
|
|
6
|
+
TargetRubyVersion: 2.5
|
|
7
7
|
NewCops: enable
|
|
8
8
|
Bundler/OrderedGems:
|
|
9
9
|
Include:
|
|
@@ -24,10 +24,18 @@ Layout/LineLength:
|
|
|
24
24
|
Enabled: false
|
|
25
25
|
Metrics/MethodLength:
|
|
26
26
|
Enabled: false
|
|
27
|
+
Metrics/ModuleLength:
|
|
28
|
+
Max: 106
|
|
27
29
|
Metrics/ParameterLists:
|
|
28
30
|
Enabled: false
|
|
29
31
|
Metrics/PerceivedComplexity:
|
|
30
32
|
Enabled: false
|
|
33
|
+
Naming/MethodName:
|
|
34
|
+
Exclude:
|
|
35
|
+
- "lib/ridgepole/ext/abstract_mysql_adapter/schema_creation.rb"
|
|
36
|
+
Naming/MethodParameterName:
|
|
37
|
+
Exclude:
|
|
38
|
+
- "lib/ridgepole/ext/abstract_mysql_adapter/schema_creation.rb"
|
|
31
39
|
Style/Documentation:
|
|
32
40
|
Enabled: false
|
|
33
41
|
Style/GuardClause:
|
data/.simplecov
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,99 +1,116 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.0
|
|
3
|
+
## 1.0
|
|
4
|
+
|
|
5
|
+
### 1.0.3 (2022/02/12)
|
|
6
|
+
|
|
7
|
+
* Support Rails 7.0.2 [pull#380](https://github.com/ridgepole/ridgepole/pull/380)
|
|
8
|
+
|
|
9
|
+
### 1.0.2 (2022/02/06)
|
|
10
|
+
|
|
11
|
+
* Add support for partitioning ([pull#374](https://github.com/ridgepole/ridgepole/pull/374))
|
|
12
|
+
* Suppress warning of table option differences ([pull#378](https://github.com/ridgepole/ridgepole/pull/378))
|
|
13
|
+
|
|
14
|
+
### 1.0.1 (2022/01/15)
|
|
15
|
+
|
|
16
|
+
* Fix code for RuboCop 1.24.1
|
|
17
|
+
* Fix PostgreSQL spec for Rails 7.0
|
|
18
|
+
* Update ERBh gem (for development)
|
|
19
|
+
|
|
20
|
+
### 1.0.0 (2021/12/19)
|
|
4
21
|
|
|
5
22
|
* Support Rails 7.0
|
|
6
|
-
* `--skip-drop-table` by default ([pull#363](https://github.com/
|
|
23
|
+
* `--skip-drop-table` by default ([pull#363](https://github.com/ridgepole/ridgepole/pull/363))
|
|
7
24
|
|
|
8
25
|
## 0.9
|
|
9
26
|
|
|
10
27
|
### 0.9.6
|
|
11
28
|
|
|
12
|
-
* Fix malformed error ([pull#362](https://github.com/
|
|
29
|
+
* Fix malformed error ([pull#362](https://github.com/ridgepole/ridgepole/pull/362))
|
|
13
30
|
|
|
14
31
|
### 0.9.5
|
|
15
32
|
|
|
16
|
-
* Call `super` in `disable_table_options.rb` ([pull#357](https://github.com/
|
|
33
|
+
* Call `super` in `disable_table_options.rb` ([pull#357](https://github.com/ridgepole/ridgepole/pull/357))
|
|
17
34
|
|
|
18
35
|
### 0.9.4
|
|
19
36
|
|
|
20
|
-
* Fix `--alter-extra` option for unique index ([pull#356](https://github.com/
|
|
37
|
+
* Fix `--alter-extra` option for unique index ([pull#356](https://github.com/ridgepole/ridgepole/pull/356))
|
|
21
38
|
|
|
22
39
|
### 0.9.3
|
|
23
40
|
|
|
24
|
-
* Fix `limit` option for `t.integer` ([pull#354](https://github.com/
|
|
41
|
+
* Fix `limit` option for `t.integer` ([pull#354](https://github.com/ridgepole/ridgepole/pull/354))
|
|
25
42
|
|
|
26
43
|
### 0.9.2
|
|
27
44
|
|
|
28
|
-
* Support `t.column index option` ([pull#353](https://github.com/
|
|
45
|
+
* Support `t.column index option` ([pull#353](https://github.com/ridgepole/ridgepole/pull/353))
|
|
29
46
|
|
|
30
47
|
### 0.9.1
|
|
31
48
|
|
|
32
|
-
* Support `t.foreign_key` ([pull#348](https://github.com/
|
|
49
|
+
* Support `t.foreign_key` ([pull#348](https://github.com/ridgepole/ridgepole/pull/348))
|
|
33
50
|
|
|
34
51
|
### 0.9.0
|
|
35
52
|
|
|
36
|
-
* Remove `--mysql-use-alter` option ([pull#330](https://github.com/
|
|
37
|
-
* Add `--table-hash-options` option ([pull#331](https://github.com/
|
|
38
|
-
* Support Rails 6.1 ([pull#323](https://github.com/
|
|
39
|
-
* Disable Rails 5.0 support ([pull#335](https://github.com/
|
|
40
|
-
* Fix PK AUTO_INCREMENT change bug ([pull#334](https://github.com/
|
|
53
|
+
* Remove `--mysql-use-alter` option ([pull#330](https://github.com/ridgepole/ridgepole/pull/330))
|
|
54
|
+
* Add `--table-hash-options` option ([pull#331](https://github.com/ridgepole/ridgepole/pull/331))
|
|
55
|
+
* Support Rails 6.1 ([pull#323](https://github.com/ridgepole/ridgepole/pull/323))
|
|
56
|
+
* Disable Rails 5.0 support ([pull#335](https://github.com/ridgepole/ridgepole/pull/335))
|
|
57
|
+
* Fix PK AUTO_INCREMENT change bug ([pull#334](https://github.com/ridgepole/ridgepole/pull/334))
|
|
41
58
|
|
|
42
59
|
## 0.8
|
|
43
60
|
|
|
44
61
|
### 0.8.13
|
|
45
62
|
|
|
46
|
-
* Support `serial` and `bigserial` column types ([pull#321](https://github.com/
|
|
63
|
+
* Support `serial` and `bigserial` column types ([pull#321](https://github.com/ridgepole/ridgepole/pull/321))
|
|
47
64
|
|
|
48
65
|
### 0.8.12
|
|
49
66
|
|
|
50
|
-
* Pluralize column specified by `references` ([pull#317](https://github.com/
|
|
67
|
+
* Pluralize column specified by `references` ([pull#317](https://github.com/ridgepole/ridgepole/pull/317))
|
|
51
68
|
|
|
52
69
|
### 0.8.11
|
|
53
70
|
|
|
54
|
-
* Fix FK index check support multiple PK ([pull#315](https://github.com/
|
|
55
|
-
* Support t.reference() foreign_key option ([pull#316](https://github.com/
|
|
71
|
+
* Fix FK index check support multiple PK ([pull#315](https://github.com/ridgepole/ridgepole/pull/315))
|
|
72
|
+
* Support t.reference() foreign_key option ([pull#316](https://github.com/ridgepole/ridgepole/pull/316))
|
|
56
73
|
|
|
57
74
|
### 0.8.10
|
|
58
75
|
|
|
59
|
-
* Raise an error if an InnoDB column has a foreign key but no index ([pull#310](https://github.com/
|
|
76
|
+
* Raise an error if an InnoDB column has a foreign key but no index ([pull#310](https://github.com/ridgepole/ridgepole/pull/310))
|
|
60
77
|
|
|
61
78
|
### 0.8.9
|
|
62
79
|
|
|
63
|
-
* Fix unexpected differences on text types and blob types on Rails 6 ([pull#306](https://github.com/
|
|
64
|
-
* Fix unexpected warning when a foreign key is added on the primary key ([pull#307](https://github.com/
|
|
80
|
+
* Fix unexpected differences on text types and blob types on Rails 6 ([pull#306](https://github.com/ridgepole/ridgepole/pull/306))
|
|
81
|
+
* Fix unexpected warning when a foreign key is added on the primary key ([pull#307](https://github.com/ridgepole/ridgepole/pull/307))
|
|
65
82
|
|
|
66
83
|
### 0.8.8
|
|
67
84
|
|
|
68
|
-
* Fix keyword arguments warnings in Ruby 2.7 ([pull#303](https://github.com/
|
|
85
|
+
* Fix keyword arguments warnings in Ruby 2.7 ([pull#303](https://github.com/ridgepole/ridgepole/pull/303))
|
|
69
86
|
|
|
70
87
|
### 0.8.7
|
|
71
88
|
|
|
72
|
-
* Support `require_relative` ([pull#298](https://github.com/
|
|
89
|
+
* Support `require_relative` ([pull#298](https://github.com/ridgepole/ridgepole/pull/298))
|
|
73
90
|
|
|
74
91
|
### 0.8.6
|
|
75
92
|
|
|
76
|
-
* Support multiple databases feature ([pull#297](https://github.com/
|
|
93
|
+
* Support multiple databases feature ([pull#297](https://github.com/ridgepole/ridgepole/pull/297))
|
|
77
94
|
|
|
78
95
|
### 0.8.5
|
|
79
96
|
|
|
80
|
-
* Improve warning message on table options ([pull#291](https://github.com/
|
|
97
|
+
* Improve warning message on table options ([pull#291](https://github.com/ridgepole/ridgepole/pull/291))
|
|
81
98
|
|
|
82
99
|
### 0.8.4
|
|
83
100
|
|
|
84
|
-
* Display a warning if an InnoDB table doesn't have any indexes on a column where it has a foreign key ([pull#290](https://github.com/
|
|
101
|
+
* Display a warning if an InnoDB table doesn't have any indexes on a column where it has a foreign key ([pull#290](https://github.com/ridgepole/ridgepole/pull/290))
|
|
85
102
|
|
|
86
103
|
### 0.8.3
|
|
87
104
|
|
|
88
|
-
* Fix "topological sort failed" error ([pull#287](https://github.com/
|
|
105
|
+
* Fix "topological sort failed" error ([pull#287](https://github.com/ridgepole/ridgepole/pull/287))
|
|
89
106
|
|
|
90
107
|
### 0.8.2
|
|
91
108
|
|
|
92
|
-
* Support `postgres://` schema ([pull#285](https://github.com/
|
|
109
|
+
* Support `postgres://` schema ([pull#285](https://github.com/ridgepole/ridgepole/pull/285))
|
|
93
110
|
|
|
94
111
|
### 0.8.1
|
|
95
112
|
|
|
96
|
-
* Drop tables in an order considering foreign key constraints ([pull#284](https://github.com/
|
|
113
|
+
* Drop tables in an order considering foreign key constraints ([pull#284](https://github.com/ridgepole/ridgepole/pull/284))
|
|
97
114
|
|
|
98
115
|
### 0.8.0
|
|
99
116
|
|
|
@@ -103,32 +120,32 @@
|
|
|
103
120
|
|
|
104
121
|
### 0.7.8
|
|
105
122
|
|
|
106
|
-
* Fix for `add_foreign_key(..., column: ,,,)` ([pull#278](https://github.com/
|
|
123
|
+
* Fix for `add_foreign_key(..., column: ,,,)` ([pull#278](https://github.com/ridgepole/ridgepole/pull/278))
|
|
107
124
|
|
|
108
125
|
### 0.7.7
|
|
109
126
|
|
|
110
|
-
* Support URI query string ([pull#273](https://github.com/
|
|
127
|
+
* Support URI query string ([pull#273](https://github.com/ridgepole/ridgepole/pull/273))
|
|
111
128
|
|
|
112
129
|
### 0.7.6
|
|
113
130
|
|
|
114
|
-
* Fix database url check ([pull#266](https://github.com/
|
|
115
|
-
* Add ignore option ([pull#267](https://github.com/
|
|
131
|
+
* Fix database url check ([pull#266](https://github.com/ridgepole/ridgepole/pull/266))
|
|
132
|
+
* Add ignore option ([pull#267](https://github.com/ridgepole/ridgepole/pull/267))
|
|
116
133
|
|
|
117
134
|
### 0.7.5
|
|
118
135
|
|
|
119
|
-
* Fix polymorphic options ([pull#263](https://github.com/
|
|
120
|
-
* Fix `--mysql-use-alter` option ([pull#246](https://github.com/
|
|
121
|
-
* Fix Database URI parsing ([pull#265](https://github.com/
|
|
136
|
+
* Fix polymorphic options ([pull#263](https://github.com/ridgepole/ridgepole/pull/263))
|
|
137
|
+
* Fix `--mysql-use-alter` option ([pull#246](https://github.com/ridgepole/ridgepole/pull/264))
|
|
138
|
+
* Fix Database URI parsing ([pull#265](https://github.com/ridgepole/ridgepole/pull/265))
|
|
122
139
|
|
|
123
140
|
### 0.7.4
|
|
124
141
|
|
|
125
|
-
* Fix `add_foreign_key` options ([issue#250](https://github.com/
|
|
142
|
+
* Fix `add_foreign_key` options ([issue#250](https://github.com/ridgepole/ridgepole/issues/250))
|
|
126
143
|
|
|
127
144
|
### 0.7.3
|
|
128
145
|
|
|
129
|
-
* Add `--mysql-change-table-comment option` ([pull#166](https://github.com/
|
|
146
|
+
* Add `--mysql-change-table-comment option` ([pull#166](https://github.com/ridgepole/ridgepole/pull/166))
|
|
130
147
|
* Refactoring with RuboCop
|
|
131
|
-
* Support primary key adding/dropping ([issue#246](https://github.com/
|
|
148
|
+
* Support primary key adding/dropping ([issue#246](https://github.com/ridgepole/ridgepole/issues/246))
|
|
132
149
|
|
|
133
150
|
### 0.7.2
|
|
134
151
|
|
|
@@ -161,33 +178,33 @@
|
|
|
161
178
|
|
|
162
179
|
### 0.6.6
|
|
163
180
|
|
|
164
|
-
* Use `t.column` for migration ([pull#114](https://github.com/
|
|
165
|
-
* Support DATABASE_URL format ([pull#118](https://github.com/
|
|
166
|
-
* Add Ruby2.4 CI ([pull#119](https://github.com/
|
|
181
|
+
* Use `t.column` for migration ([pull#114](https://github.com/ridgepole/ridgepole/pull/114))
|
|
182
|
+
* Support DATABASE_URL format ([pull#118](https://github.com/ridgepole/ridgepole/pull/118))
|
|
183
|
+
* Add Ruby2.4 CI ([pull#119](https://github.com/ridgepole/ridgepole/pull/119))
|
|
167
184
|
|
|
168
185
|
### 0.6.5
|
|
169
186
|
|
|
170
187
|
* Fix rails version `'>= 4.2', '< 6'`
|
|
171
|
-
* Support new types ([pull#84](https://github.com/
|
|
172
|
-
* Support `default: -> { ... }` ([pull#85](https://github.com/
|
|
188
|
+
* Support new types ([pull#84](https://github.com/ridgepole/ridgepole/pull/84))
|
|
189
|
+
* Support `default: -> { ... }` ([pull#85](https://github.com/ridgepole/ridgepole/pull/85))
|
|
173
190
|
* Support DDL Comment (Rails5 only)
|
|
174
191
|
* Output schema diff when pass `--verbose`
|
|
175
|
-
* Support composite primary key (Rails5 only / [pull#97](https://github.com/
|
|
192
|
+
* Support composite primary key (Rails5 only / [pull#97](https://github.com/ridgepole/ridgepole/pull/97))
|
|
176
193
|
|
|
177
194
|
### 0.6.4
|
|
178
195
|
|
|
179
|
-
* Execute sql using external script ([pull#56](https://github.com/
|
|
196
|
+
* Execute sql using external script ([pull#56](https://github.com/ridgepole/ridgepole/pull/56))
|
|
180
197
|
* Add `--mysql-use-alter` option
|
|
181
198
|
* Add `--alter-extra` option
|
|
182
199
|
* Add `--dump-with-default-fk-name` option
|
|
183
|
-
* Support `t.index` ([pull#64](https://github.com/
|
|
200
|
+
* Support `t.index` ([pull#64](https://github.com/ridgepole/ridgepole/pull/64))
|
|
184
201
|
* Remove migration_comments
|
|
185
202
|
* Fix foreign key apply order
|
|
186
203
|
|
|
187
204
|
### 0.6.3
|
|
188
205
|
|
|
189
|
-
* Fix `default` option ([pull#48](https://github.com/
|
|
190
|
-
* Add `--enable-migration-comments` option ([pull#50](https://github.com/
|
|
206
|
+
* Fix `default` option ([pull#48](https://github.com/ridgepole/ridgepole/pull/48))
|
|
207
|
+
* Add `--enable-migration-comments` option ([pull#50](https://github.com/ridgepole/ridgepole/pull/50))
|
|
191
208
|
* Disable `rename_table_indexes`
|
|
192
209
|
|
|
193
210
|
### 0.6.1
|
data/README.md
CHANGED
|
@@ -6,14 +6,16 @@ It defines DB schema using [Rails DSL](http://guides.rubyonrails.org/migrations.
|
|
|
6
6
|
(like Chef/Puppet)
|
|
7
7
|
|
|
8
8
|
[](http://badge.fury.io/rb/ridgepole)
|
|
9
|
-
[](https://github.com/ridgepole/ridgepole/actions)
|
|
10
|
+
[](https://coveralls.io/github/ridgepole/ridgepole?branch=1.0)
|
|
11
11
|
|
|
12
12
|
**Notice**
|
|
13
13
|
|
|
14
|
+
For ActiveRecord 7.x series, please use AcriveRecord 7.0.2 or higher / Ridgepole 1.0.3 or higher.
|
|
15
|
+
* cf. https://github.com/ridgepole/ridgepole/pull/380
|
|
14
16
|
* ActiveRecord 6.1 is supported in ridgepole v0.9, but the ActiveRecord dump has been changed, so there is a difference between ActiveRecord 5.x/6.0 format.
|
|
15
17
|
* **If you use ActiveRecord 6.1, please modify Schemafile format**.
|
|
16
|
-
* cf. https://github.com/
|
|
18
|
+
* cf. https://github.com/ridgepole/ridgepole/pull/323
|
|
17
19
|
* `DROP TABLE` is skipped by default in v1.0 and later versions.
|
|
18
20
|
* If you want to `DROP TABLE`, please pass `--drop-table`.
|
|
19
21
|
* cf. https://github.com/ridgepole/ridgepole/pull/363
|
|
@@ -301,18 +303,44 @@ Apply `Schemafile`
|
|
|
301
303
|
...
|
|
302
304
|
```
|
|
303
305
|
|
|
306
|
+
## Partitioning
|
|
307
|
+
|
|
308
|
+
**Notice:** PostgreSQL `PARTITION BY` must be specified with the create_table option.
|
|
309
|
+
|
|
310
|
+
### List Partitioning
|
|
311
|
+
|
|
312
|
+
```ruby
|
|
313
|
+
create_table "articles", force: :cascade, options: "PARTITION BY LIST(id)" do |t|
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
add_partition("articles", :list, :id, partition_definitions: [{ name: 'p0', values: { in: [0,1,2] } }, { name: 'p1', values: { in: [3,4,5] } }])
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Range Partitioning
|
|
320
|
+
|
|
321
|
+
```ruby
|
|
322
|
+
create_table "articles", force: :cascade, options: "PARTITION BY RANGE(id)" do |t|
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# postgresql
|
|
326
|
+
add_partition("articles", :range, :id, partition_definitions: [{ name: 'p0', values: { from: 'MINVALUE', to: 5 }}, { name: 'p1', values: { from: 5, to: 10 } }])
|
|
327
|
+
# mysql
|
|
328
|
+
add_partition("articles", :range, :id, partition_definitions: [{ name: 'p0', values: { to: 5 }}, { name: 'p1', values: { to: 10 } }])
|
|
329
|
+
```
|
|
330
|
+
|
|
304
331
|
## Run tests
|
|
305
332
|
|
|
333
|
+
|
|
306
334
|
```sh
|
|
307
335
|
docker-compose up -d
|
|
308
336
|
bundle install
|
|
309
337
|
bundle exec appraisal install
|
|
310
|
-
bundle exec appraisal activerecord-
|
|
311
|
-
# POSTGRESQL=1 bundle exec appraisal activerecord-
|
|
312
|
-
# MYSQL57=1 bundle exec appraisal activerecord-
|
|
338
|
+
bundle exec appraisal activerecord-7.0 rake
|
|
339
|
+
# POSTGRESQL=1 bundle exec appraisal activerecord-7.0 rake
|
|
340
|
+
# MYSQL57=1 bundle exec appraisal activerecord-7.0 rake
|
|
313
341
|
```
|
|
314
342
|
|
|
315
|
-
**Notice:** mysql-client/postgresql-client is required.
|
|
343
|
+
**Notice:** Ruby 2.6 or above/mysql-client/postgresql-client is required.
|
|
316
344
|
|
|
317
345
|
## Demo
|
|
318
346
|
|
|
@@ -321,6 +349,6 @@ bundle exec appraisal activerecord-5.1 rake
|
|
|
321
349
|
|
|
322
350
|
## Example project
|
|
323
351
|
|
|
324
|
-
* https://github.com/
|
|
325
|
-
* https://github.com/
|
|
326
|
-
* https://github.com/
|
|
352
|
+
* https://github.com/ridgepole/ridgepole-example
|
|
353
|
+
* https://github.com/ridgepole/ridgepole-example/pull/1
|
|
354
|
+
* https://github.com/ridgepole/ridgepole-example/pull/2
|
data/bin/ridgepole
CHANGED
|
@@ -74,106 +74,104 @@ def noop_migrate(delta, options)
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
ARGV.options do |opt|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
opt.on('-c', '--config CONF_OR_FILE') { |v| config = v }
|
|
78
|
+
opt.on('-E', '--env ENVIRONMENT') { |v| env = v }
|
|
79
|
+
opt.on('-s', '--spec-name SPEC_NAME') { |v| spec_name = v }
|
|
80
|
+
opt.on('-a', '--apply') { set_mode[:apply] }
|
|
81
|
+
opt.on('-m', '--merge') do
|
|
82
|
+
set_mode[:apply]
|
|
83
|
+
options[:merge] = true
|
|
84
|
+
end
|
|
85
|
+
opt.on('-f', '--file SCHEMAFILE') { |v| file = v }
|
|
86
|
+
opt.on('', '--dry-run') { options[:dry_run] = true }
|
|
87
|
+
opt.on('', '--table-options OPTIONS') { |v| options[:table_options] = v }
|
|
88
|
+
opt.on('', '--table-hash-options OPTIONS') do |v|
|
|
89
|
+
# NOTE: Ruby2.4 doesn't support `symbolize_names: true`
|
|
90
|
+
hash = YAML.safe_load(v).deep_symbolize_keys
|
|
91
|
+
|
|
92
|
+
case hash[:id]
|
|
93
|
+
when String
|
|
94
|
+
hash[:id] = hash[:id].to_sym
|
|
95
|
+
when Hash
|
|
96
|
+
hash[:id][:type] = hash[:id][:type].to_sym if hash[:id][:type]
|
|
85
97
|
end
|
|
86
|
-
opt.on('-f', '--file SCHEMAFILE') { |v| file = v }
|
|
87
|
-
opt.on('', '--dry-run') { options[:dry_run] = true }
|
|
88
|
-
opt.on('', '--table-options OPTIONS') { |v| options[:table_options] = v }
|
|
89
|
-
opt.on('', '--table-hash-options OPTIONS') do |v|
|
|
90
|
-
# NOTE: Ruby2.4 doesn't support `symbolize_names: true`
|
|
91
|
-
hash = YAML.safe_load(v).deep_symbolize_keys
|
|
92
|
-
|
|
93
|
-
case hash[:id]
|
|
94
|
-
when String
|
|
95
|
-
hash[:id] = hash[:id].to_sym
|
|
96
|
-
when Hash
|
|
97
|
-
hash[:id][:type] = hash[:id][:type].to_sym if hash[:id][:type]
|
|
98
|
-
end
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
options[:table_hash_options] = hash
|
|
100
|
+
end
|
|
101
|
+
opt.on('', '--alter-extra ALTER_SPEC') { |v| options[:alter_extra] = v }
|
|
102
|
+
opt.on('', '--external-script SCRIPT') { |v| options[:external_script] = v }
|
|
103
|
+
opt.on('', '--bulk-change') do
|
|
104
|
+
raise OptionParser::InvalidOption, 'Cannot use `bulk-change` in `merge`' if options[:merge]
|
|
106
105
|
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
options[:bulk_change] = true
|
|
107
|
+
end
|
|
109
108
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
end
|
|
109
|
+
COLUMN_TYPES.each do |column_type, column_type_alias|
|
|
110
|
+
opt.on('', "--default-#{column_type_alias}-limit LIMIT", Integer) do |v|
|
|
111
|
+
options[:"default_#{column_type}_limit"] = v
|
|
114
112
|
end
|
|
113
|
+
end
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if [diff_arg1, diff_arg2].any? { |i| i.nil? || i.start_with?('-') }
|
|
126
|
-
puts opt.help
|
|
127
|
-
exit 1
|
|
128
|
-
end
|
|
115
|
+
opt.on('', '--pre-query QUERY') { |v| options[:pre_query] = v }
|
|
116
|
+
opt.on('', '--post-query QUERY') { |v| options[:post_query] = v }
|
|
117
|
+
opt.on('-e', '--export') { set_mode[:export] }
|
|
118
|
+
opt.on('', '--split') { split = true }
|
|
119
|
+
opt.on('', '--split-with-dir') { split = :with_dir }
|
|
120
|
+
opt.on('-d', '--diff DSL1 DSL2') do |diff_arg1|
|
|
121
|
+
set_mode[:diff]
|
|
122
|
+
diff_arg2 = ARGV.first
|
|
129
123
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
opt.on('', '--with-apply') { diff_with_apply = true }
|
|
134
|
-
opt.on('-o', '--output SCHEMAFILE') { |v| output_file = v }
|
|
135
|
-
opt.on('-t', '--tables TABLES', Array) { |v| options[:tables] = v }
|
|
136
|
-
opt.on('', '--ignore-tables REGEX_LIST', Array) { |v| options[:ignore_tables] = v.map { |i| Regexp.new(i) } }
|
|
137
|
-
opt.on('', '--dump-without-table-options') { options[:dump_without_table_options] = true }
|
|
138
|
-
opt.on('', '--dump-with-default-fk-name') { options[:dump_with_default_fk_name] = true }
|
|
139
|
-
opt.on('', '--index-removed-drop-column') { options[:index_removed_drop_column] = true }
|
|
140
|
-
opt.on('', '--drop-table') { options[:force_drop_table] = true }
|
|
141
|
-
opt.on('', '--mysql-change-table-options') { options[:mysql_change_table_options] = true }
|
|
142
|
-
opt.on('', '--mysql-change-table-comment') { options[:mysql_change_table_comment] = true }
|
|
143
|
-
opt.on('', '--check-relation-type DEF_PK') { |v| options[:check_relation_type] = v }
|
|
144
|
-
opt.on('', '--ignore-table-comment') { options[:ignore_table_comment] = true }
|
|
145
|
-
opt.on('', '--skip-column-comment-change') { options[:skip_column_comment_change] = true }
|
|
146
|
-
opt.on('', '--allow-pk-change') { options[:allow_pk_change] = true }
|
|
147
|
-
opt.on('', '--create-table-with-index') { options[:create_table_with_index] = true }
|
|
148
|
-
|
|
149
|
-
opt.on('', '--mysql-dump-auto-increment') do
|
|
150
|
-
options[:mysql_dump_auto_increment] = true
|
|
124
|
+
if [diff_arg1, diff_arg2].any? { |i| i.nil? || i.start_with?('-') }
|
|
125
|
+
puts opt.help
|
|
126
|
+
exit 1
|
|
151
127
|
end
|
|
152
128
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
129
|
+
ARGV.shift
|
|
130
|
+
diff_files = [diff_arg1, diff_arg2]
|
|
131
|
+
end
|
|
132
|
+
opt.on('', '--with-apply') { diff_with_apply = true }
|
|
133
|
+
opt.on('-o', '--output SCHEMAFILE') { |v| output_file = v }
|
|
134
|
+
opt.on('-t', '--tables TABLES', Array) { |v| options[:tables] = v }
|
|
135
|
+
opt.on('', '--ignore-tables REGEX_LIST', Array) { |v| options[:ignore_tables] = v.map { |i| Regexp.new(i) } }
|
|
136
|
+
opt.on('', '--dump-without-table-options') { options[:dump_without_table_options] = true }
|
|
137
|
+
opt.on('', '--dump-with-default-fk-name') { options[:dump_with_default_fk_name] = true }
|
|
138
|
+
opt.on('', '--index-removed-drop-column') { options[:index_removed_drop_column] = true }
|
|
139
|
+
opt.on('', '--drop-table') { options[:force_drop_table] = true }
|
|
140
|
+
opt.on('', '--mysql-change-table-options') { options[:mysql_change_table_options] = true }
|
|
141
|
+
opt.on('', '--mysql-change-table-comment') { options[:mysql_change_table_comment] = true }
|
|
142
|
+
opt.on('', '--check-relation-type DEF_PK') { |v| options[:check_relation_type] = v }
|
|
143
|
+
opt.on('', '--ignore-table-comment') { options[:ignore_table_comment] = true }
|
|
144
|
+
opt.on('', '--skip-column-comment-change') { options[:skip_column_comment_change] = true }
|
|
145
|
+
opt.on('', '--allow-pk-change') { options[:allow_pk_change] = true }
|
|
146
|
+
opt.on('', '--create-table-with-index') { options[:create_table_with_index] = true }
|
|
147
|
+
|
|
148
|
+
opt.on('', '--mysql-dump-auto-increment') do
|
|
149
|
+
options[:mysql_dump_auto_increment] = true
|
|
150
|
+
end
|
|
163
151
|
|
|
164
|
-
|
|
152
|
+
opt.on('-r', '--require LIBS', Array) { |v| v.each { |i| require i } }
|
|
153
|
+
opt.on('', '--log-file LOG_FILE') { |v| options[:log_file] = v }
|
|
154
|
+
opt.on('', '--verbose') { Ridgepole::Logger.verbose = true }
|
|
155
|
+
opt.on('', '--debug') { options[:debug] = true }
|
|
156
|
+
opt.on('', '--[no-]color') { |v| options[:color] = v }
|
|
165
157
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
rescue StandardError => e
|
|
171
|
-
warn("[ERROR] #{e.message}")
|
|
158
|
+
opt.on('-v', '--version') do
|
|
159
|
+
puts opt.ver
|
|
160
|
+
exit
|
|
161
|
+
end
|
|
172
162
|
|
|
173
|
-
|
|
163
|
+
opt.parse!
|
|
174
164
|
|
|
165
|
+
if !mode || (%i[apply export].include?(mode) && !config) || (options[:with_apply] && !config)
|
|
166
|
+
puts opt.help
|
|
175
167
|
exit 1
|
|
176
168
|
end
|
|
169
|
+
rescue StandardError => e
|
|
170
|
+
warn("[ERROR] #{e.message}")
|
|
171
|
+
|
|
172
|
+
puts "\t" + e.backtrace.join("\n\t") unless e.is_a?(OptionParser::ParseError)
|
|
173
|
+
|
|
174
|
+
exit 1
|
|
177
175
|
end
|
|
178
176
|
|
|
179
177
|
begin
|
data/lib/ridgepole/client.rb
CHANGED
|
@@ -15,7 +15,12 @@ module Ridgepole
|
|
|
15
15
|
@parser = Ridgepole::DSLParser.new(@options)
|
|
16
16
|
@diff = Ridgepole::Diff.new(@options)
|
|
17
17
|
|
|
18
|
+
if Ridgepole::ConnectionAdapters.mysql?
|
|
19
|
+
require 'ridgepole/ext/abstract_mysql_adapter/partitioning'
|
|
20
|
+
require 'ridgepole/ext/abstract_mysql_adapter/schema_creation'
|
|
21
|
+
end
|
|
18
22
|
require 'ridgepole/ext/abstract_mysql_adapter/dump_auto_increment' if @options[:mysql_dump_auto_increment]
|
|
23
|
+
require 'ridgepole/ext/postgresql_adapter/partitioning' if Ridgepole::ConnectionAdapters.postgresql?
|
|
19
24
|
end
|
|
20
25
|
|
|
21
26
|
def dump(&block)
|
data/lib/ridgepole/delta.rb
CHANGED
|
@@ -310,11 +310,29 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
|
|
|
310
310
|
append_change_table_options(table_name, comment_literal, buf)
|
|
311
311
|
end
|
|
312
312
|
|
|
313
|
+
def append_change_partition(table_name, delta, buf)
|
|
314
|
+
(delta[:add] || {}).each do |_, attrs|
|
|
315
|
+
buf.puts "create_partition #{table_name.inspect}, **#{attrs.inspect}"
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def append_change_partition_definitions(table_name, partition_definitions, buf, _post_buf_for_fk)
|
|
320
|
+
(partition_definitions[:add] || []).each do |partition_name, attrs|
|
|
321
|
+
buf.puts "add_partition #{table_name.inspect}, name: #{partition_name.inspect}, values: #{attrs[:values].inspect}"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
(partition_definitions[:delete] || []).each do |partition_name, _attrs|
|
|
325
|
+
buf.puts "remove_partition #{table_name.inspect}, name: #{partition_name.inspect}"
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
313
329
|
def append_change(table_name, attrs, buf, pre_buf_for_fk, post_buf_for_fk)
|
|
314
330
|
definition = attrs[:definition] || {}
|
|
315
331
|
primary_key_definition = attrs[:primary_key_definition] || {}
|
|
316
332
|
indices = attrs[:indices] || {}
|
|
317
333
|
foreign_keys = attrs[:foreign_keys] || {}
|
|
334
|
+
partition = attrs[:partition] || {}
|
|
335
|
+
partition_definitions = attrs[:partition_definitions] || {}
|
|
318
336
|
table_options = attrs[:table_options]
|
|
319
337
|
table_charset = attrs[:table_charset]
|
|
320
338
|
table_collation = attrs[:table_collation]
|
|
@@ -335,6 +353,10 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
|
|
|
335
353
|
|
|
336
354
|
append_change_table_comment(table_name, table_comment, buf) if table_comment
|
|
337
355
|
|
|
356
|
+
append_change_partition(table_name, partition, buf) unless partition.empty?
|
|
357
|
+
|
|
358
|
+
append_change_partition_definitions(table_name, partition_definitions, buf, post_buf_for_fk) unless partition_definitions.empty?
|
|
359
|
+
|
|
338
360
|
buf.puts
|
|
339
361
|
pre_buf_for_fk.puts
|
|
340
362
|
post_buf_for_fk.puts
|
data/lib/ridgepole/diff.rb
CHANGED
|
@@ -37,6 +37,9 @@ module Ridgepole
|
|
|
37
37
|
delta[:add] ||= {}
|
|
38
38
|
delta[:add][table_name] = to_attrs
|
|
39
39
|
end
|
|
40
|
+
delta[:change] ||= {}
|
|
41
|
+
delta[:change][table_name] ||= {}
|
|
42
|
+
scan_partition_change(table_name, from_attrs&.fetch(:partition, nil), to_attrs&.fetch(:partition, nil), delta[:change][table_name])
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
scan_relation_info(relation_info)
|
|
@@ -182,8 +185,8 @@ module Ridgepole
|
|
|
182
185
|
to = to.except(*PRIMARY_KEY_OPTIONS)
|
|
183
186
|
|
|
184
187
|
unless from == to
|
|
185
|
-
@logger.
|
|
186
|
-
|
|
188
|
+
@logger.verbose_info(<<-MSG)
|
|
189
|
+
# Table option changes are ignored on `#{table_name}`.
|
|
187
190
|
from: #{from}
|
|
188
191
|
to: #{to}
|
|
189
192
|
MSG
|
|
@@ -419,9 +422,6 @@ module Ridgepole
|
|
|
419
422
|
opts[:limit] = 4_294_967_295
|
|
420
423
|
end
|
|
421
424
|
end
|
|
422
|
-
|
|
423
|
-
# Workaround for Active Record 7.0
|
|
424
|
-
opts.delete(:precision) if attrs[:type] == :datetime && opts[:precision].nil?
|
|
425
425
|
end
|
|
426
426
|
end
|
|
427
427
|
|
|
@@ -612,6 +612,54 @@ module Ridgepole
|
|
|
612
612
|
end
|
|
613
613
|
end
|
|
614
614
|
|
|
615
|
+
def scan_partition_change(table_name, from, to, table_delta)
|
|
616
|
+
from = (from || {}).dup
|
|
617
|
+
to = (to || {}).dup
|
|
618
|
+
partition_delta = {}
|
|
619
|
+
|
|
620
|
+
return if to.empty? && from.empty?
|
|
621
|
+
|
|
622
|
+
if from.empty? && Ridgepole::ConnectionAdapters.mysql?
|
|
623
|
+
partition_delta[:add] ||= {}
|
|
624
|
+
partition_delta[:add][table_name] = to
|
|
625
|
+
else
|
|
626
|
+
if from.present? && (to[:type] != from[:type] || to[:columns] != from[:columns])
|
|
627
|
+
@logger.warn(<<-MSG)
|
|
628
|
+
"[WARNING] '#{table_name}' partition is skipped because of the different partition type.
|
|
629
|
+
to: #{to[:type]} #{to[:columns]}
|
|
630
|
+
from: #{from[:type]}" #{from[:columns]}
|
|
631
|
+
MSG
|
|
632
|
+
return
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
raise "All partition is different. please check partition settings.to: #{to}, from: #{from}" if from[:partition_definitions].present? && (to[:partition_definitions] & from[:partition_definitions]).empty?
|
|
636
|
+
|
|
637
|
+
scan_partition_definition_chanage(from, to, table_delta)
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
table_delta[:partition] = partition_delta unless partition_delta.empty?
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
def scan_partition_definition_chanage(from, to, table_delta)
|
|
644
|
+
partition_definitions_delta = {}
|
|
645
|
+
attrs = { type: from[:type] || to[:type] }
|
|
646
|
+
|
|
647
|
+
from_partitions = (from[:partition_definitions] || []).index_by { |partition| partition[:name] }
|
|
648
|
+
to_partitions = (to[:partition_definitions] || []).index_by { |partition| partition[:name] }
|
|
649
|
+
|
|
650
|
+
(from_partitions.keys - to_partitions.keys).each do |name|
|
|
651
|
+
partition_definitions_delta[:delete] ||= {}
|
|
652
|
+
partition_definitions_delta[:delete][name] = attrs.merge(valuve: from_partitions[name][:values])
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
(to_partitions.keys - from_partitions.keys).each do |name|
|
|
656
|
+
partition_definitions_delta[:add] ||= {}
|
|
657
|
+
partition_definitions_delta[:add][name] = attrs.merge(values: to_partitions[name][:values])
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
table_delta[:partition_definitions] = partition_definitions_delta unless partition_definitions_delta.empty?
|
|
661
|
+
end
|
|
662
|
+
|
|
615
663
|
def check_table_existence(definition)
|
|
616
664
|
return unless @options[:tables]
|
|
617
665
|
|
|
@@ -91,6 +91,22 @@ module Ridgepole
|
|
|
91
91
|
}
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
+
def add_partition(table_name, type, columns, partition_definitions: [])
|
|
95
|
+
partition_definitions.each do |partition_definition|
|
|
96
|
+
values = partition_definition.fetch(:values)
|
|
97
|
+
raise ArgumentError unless values.is_a?(Hash)
|
|
98
|
+
|
|
99
|
+
values[:in] = Array.wrap(values[:in]) if values.key?(:in)
|
|
100
|
+
values[:to] = Array.wrap(values[:to]) if values.key?(:to)
|
|
101
|
+
values[:from] = Array.wrap(values[:from]) if values.key?(:from)
|
|
102
|
+
end
|
|
103
|
+
@__definition[table_name][:partition] = {
|
|
104
|
+
type: type,
|
|
105
|
+
columns: Array.wrap(columns),
|
|
106
|
+
partition_definitions: partition_definitions,
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
|
|
94
110
|
def require(file)
|
|
95
111
|
schemafile = %r{\A/}.match?(file) ? file : File.join(@__working_dir, file)
|
|
96
112
|
|
data/lib/ridgepole/dumper.rb
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
4
|
+
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
module ConnectionAdapters
|
|
7
|
+
class PartitionDefinition
|
|
8
|
+
attr_reader :name, :values
|
|
9
|
+
|
|
10
|
+
def initialize(
|
|
11
|
+
name,
|
|
12
|
+
values
|
|
13
|
+
)
|
|
14
|
+
@name = name
|
|
15
|
+
@values = values
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
4
|
+
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
module ConnectionAdapters
|
|
7
|
+
class PartitionOptions
|
|
8
|
+
attr_reader :table, :type, :columns, :partition_definitions
|
|
9
|
+
|
|
10
|
+
TYPES = %i[range list].freeze
|
|
11
|
+
|
|
12
|
+
def initialize(
|
|
13
|
+
table, type,
|
|
14
|
+
columns,
|
|
15
|
+
partition_definitions: []
|
|
16
|
+
)
|
|
17
|
+
@table = table
|
|
18
|
+
@type = type
|
|
19
|
+
@columns = Array.wrap(columns)
|
|
20
|
+
@partition_definitions = build_definitions(partition_definitions)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def build_definitions(definitions)
|
|
26
|
+
definitions.map do |definition|
|
|
27
|
+
next if definition.is_a?(PartitionDefinition)
|
|
28
|
+
|
|
29
|
+
PartitionDefinition.new(definition.fetch(:name), definition.fetch(:values))
|
|
30
|
+
end.compact
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
4
|
+
|
|
5
|
+
module Ridgepole
|
|
6
|
+
module Ext
|
|
7
|
+
module AbstractAdapter
|
|
8
|
+
module Partitioning
|
|
9
|
+
def partition(*)
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def partition_tables
|
|
14
|
+
[]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# SchemaStatements
|
|
18
|
+
def create_partition(*)
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def add_partition(*)
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def remove_partition(*)
|
|
27
|
+
raise NotImplementedError
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
module ActiveRecord
|
|
35
|
+
module ConnectionAdapters
|
|
36
|
+
class AbstractAdapter
|
|
37
|
+
prepend Ridgepole::Ext::AbstractAdapter::Partitioning
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
|
4
|
+
|
|
5
|
+
module Ridgepole
|
|
6
|
+
module Ext
|
|
7
|
+
module AbstractMysqlAdapter
|
|
8
|
+
module Partitioning
|
|
9
|
+
def partition(table_name)
|
|
10
|
+
scope = quoted_scope(table_name)
|
|
11
|
+
|
|
12
|
+
partition_info = exec_query(<<~SQL, 'SCHEMA')
|
|
13
|
+
SELECT PARTITION_NAME, PARTITION_DESCRIPTION, PARTITION_METHOD, PARTITION_EXPRESSION
|
|
14
|
+
FROM information_schema.partitions
|
|
15
|
+
WHERE partition_name IS NOT NULL
|
|
16
|
+
AND table_schema = #{scope[:schema]}
|
|
17
|
+
AND table_name = #{scope[:name]}
|
|
18
|
+
SQL
|
|
19
|
+
return if partition_info.count == 0
|
|
20
|
+
|
|
21
|
+
type = case partition_info.first['PARTITION_METHOD']
|
|
22
|
+
when 'LIST COLUMNS'
|
|
23
|
+
:list
|
|
24
|
+
when 'RANGE COLUMNS'
|
|
25
|
+
:range
|
|
26
|
+
else
|
|
27
|
+
raise NotImplementedError, partition_info.first['PARTITION_METHOD'].to_s
|
|
28
|
+
end
|
|
29
|
+
columns = partition_info.first['PARTITION_EXPRESSION'].delete('`').split(',').map(&:to_sym)
|
|
30
|
+
|
|
31
|
+
partition_definitions = partition_info.map do |row|
|
|
32
|
+
values = case type
|
|
33
|
+
when :list
|
|
34
|
+
{ in: instance_eval("[#{row['PARTITION_DESCRIPTION'].gsub(/\(/, '[').gsub(/\)/, ']')}] # [1,2]", __FILE__, __LINE__) }
|
|
35
|
+
when :range
|
|
36
|
+
{ to: instance_eval("[#{row['PARTITION_DESCRIPTION']}] # [1,2]", __FILE__, __LINE__) }
|
|
37
|
+
else
|
|
38
|
+
raise NotImplementedError
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
{ name: row['PARTITION_NAME'], values: values }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ActiveRecord::ConnectionAdapters::PartitionOptions.new(table_name, type, columns, partition_definitions: partition_definitions)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# SchemaStatements
|
|
48
|
+
def create_partition(table_name, type:, columns:, partition_definitions:)
|
|
49
|
+
execute schema_creation.accept(ActiveRecord::ConnectionAdapters::PartitionOptions.new(table_name, type, columns, partition_definitions: partition_definitions))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add_partition(table_name, name:, values:)
|
|
53
|
+
pd = ActiveRecord::ConnectionAdapters::PartitionDefinition.new(name, values)
|
|
54
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} ADD PARTITION (#{schema_creation.accept(pd)})"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def remove_partition(table_name, name:)
|
|
58
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP PARTITION #{name}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
module ActiveRecord
|
|
66
|
+
module ConnectionAdapters
|
|
67
|
+
class AbstractMysqlAdapter < AbstractAdapter
|
|
68
|
+
prepend Ridgepole::Ext::AbstractMysqlAdapter::Partitioning
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_record/connection_adapters/mysql/schema_creation'
|
|
4
|
+
|
|
5
|
+
module Ridgepole
|
|
6
|
+
module Ext
|
|
7
|
+
module AbstractMysqlAdapter
|
|
8
|
+
module SchemaCreation
|
|
9
|
+
def visit_PartitionOptions(o)
|
|
10
|
+
sqls = o.partition_definitions.map { |partition_definition| accept partition_definition }
|
|
11
|
+
function = case o.type
|
|
12
|
+
when :list
|
|
13
|
+
"LIST COLUMNS(#{o.columns.map { |column| quote_column_name(column) }.join(',')})"
|
|
14
|
+
when :range
|
|
15
|
+
"RANGE COLUMNS(#{o.columns.map { |column| quote_column_name(column) }.join(',')})"
|
|
16
|
+
else
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
end
|
|
19
|
+
"ALTER TABLE #{quote_table_name(o.table)} PARTITION BY #{function} (#{sqls.join(',')})"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def visit_PartitionDefinition(o)
|
|
23
|
+
if o.values.key?(:in)
|
|
24
|
+
"PARTITION #{o.name} VALUES IN (#{o.values[:in].map do |value|
|
|
25
|
+
value.is_a?(Array) ? "(#{value.map(&:inspect).join(',')})" : value.inspect
|
|
26
|
+
end.join(',')})"
|
|
27
|
+
elsif o.values.key?(:to)
|
|
28
|
+
"PARTITION #{o.name} VALUES LESS THAN (#{o.values[:to].map(&:inspect).join(',')})"
|
|
29
|
+
else
|
|
30
|
+
raise NotImplementedError
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module ActiveRecord
|
|
39
|
+
module ConnectionAdapters
|
|
40
|
+
module MySQL
|
|
41
|
+
class SchemaCreation
|
|
42
|
+
prepend Ridgepole::Ext::AbstractMysqlAdapter::SchemaCreation
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
|
4
|
+
|
|
5
|
+
module Ridgepole
|
|
6
|
+
module Ext
|
|
7
|
+
module PostgreSQLAdapter
|
|
8
|
+
module Partitioning
|
|
9
|
+
def supports_partitions?
|
|
10
|
+
ActiveRecord::VERSION::MAJOR >= 6 && postgresql_version >= 100_000 # >= 10.0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def table_options(table_name)
|
|
14
|
+
options = partition_options(table_name)
|
|
15
|
+
if options
|
|
16
|
+
(super || {}).merge(options: "PARTITION BY #{options[:type].to_s.upcase}(#{options[:columns].join(',')})")
|
|
17
|
+
else
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def partition_options(table_name)
|
|
23
|
+
return unless supports_partitions?
|
|
24
|
+
|
|
25
|
+
scope = quoted_scope(table_name)
|
|
26
|
+
result = query_value(<<~SQL, 'SCHEMA')
|
|
27
|
+
SELECT pg_get_partkeydef(t.oid)
|
|
28
|
+
FROM pg_class t
|
|
29
|
+
LEFT JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
30
|
+
WHERE t.relname = #{scope[:name]}
|
|
31
|
+
AND n.nspname = #{scope[:schema]}
|
|
32
|
+
SQL
|
|
33
|
+
return unless result
|
|
34
|
+
|
|
35
|
+
type, *columns = result.scan(/\w+/).map { |value| value.downcase.to_sym }
|
|
36
|
+
{ type: type, columns: columns }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def partition(table_name)
|
|
40
|
+
options = partition_options(table_name)
|
|
41
|
+
return unless options
|
|
42
|
+
|
|
43
|
+
scope = quoted_scope(table_name)
|
|
44
|
+
partition_info = query(<<~SQL, 'SCHEMA')
|
|
45
|
+
SELECT p.relname, pg_get_expr(p.relpartbound, p.oid, true)
|
|
46
|
+
FROM pg_class t
|
|
47
|
+
JOIN pg_inherits i on i.inhparent = t.oid
|
|
48
|
+
JOIN pg_class p on p.oid = i.inhrelid
|
|
49
|
+
WHERE t.relname = #{scope[:name]}
|
|
50
|
+
AND p.relnamespace::regnamespace::text = #{scope[:schema]}
|
|
51
|
+
ORDER BY p.relname
|
|
52
|
+
SQL
|
|
53
|
+
|
|
54
|
+
partition_definitions = partition_info.map do |row|
|
|
55
|
+
values = case options[:type]
|
|
56
|
+
when :list
|
|
57
|
+
values = row[1].match(/FOR VALUES IN \((?<csv>.+)\)$/)[:csv].split(',').map(&:strip).map { |value| cast_value(value) }
|
|
58
|
+
{ in: Array.wrap(values) }
|
|
59
|
+
when :range
|
|
60
|
+
match = row[1].match(/FOR VALUES FROM \((?<from>.+)\) TO \((?<to>.+)\)/)
|
|
61
|
+
from = match[:from].split(',').map(&:strip).map { |value| cast_value(value) }
|
|
62
|
+
to = match[:to].split(',').map(&:strip).map { |value| cast_value(value) }
|
|
63
|
+
{ from: from, to: to }
|
|
64
|
+
else
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
end
|
|
67
|
+
{ name: row[0], values: values }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
ActiveRecord::ConnectionAdapters::PartitionOptions.new(table_name, options[:type], options[:columns], partition_definitions: partition_definitions)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def cast_value(value)
|
|
74
|
+
Integer(value)
|
|
75
|
+
rescue ArgumentError
|
|
76
|
+
value.delete(%q("')) # "
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def quote_value(value)
|
|
80
|
+
if %w[MINVALUE MAXVALUE].include?(value)
|
|
81
|
+
value
|
|
82
|
+
else
|
|
83
|
+
quote(value)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def partition_tables
|
|
88
|
+
partition_info = query(<<~SQL, 'SCHEMA')
|
|
89
|
+
SELECT p.relname
|
|
90
|
+
FROM pg_class t
|
|
91
|
+
JOIN pg_inherits i on i.inhparent = t.oid
|
|
92
|
+
JOIN pg_class p on p.oid = i.inhrelid
|
|
93
|
+
ORDER BY p.relname
|
|
94
|
+
SQL
|
|
95
|
+
partition_info.map { |row| row[0] }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# SchemaStatements
|
|
99
|
+
def add_partition(table_name, name:, values:)
|
|
100
|
+
condition = if values.key?(:in)
|
|
101
|
+
"FOR VALUES IN (#{values[:in].map { |v| quote_value(v) }.join(',')})"
|
|
102
|
+
elsif values.key?(:to)
|
|
103
|
+
from = values[:from].map { |v| quote_value(v) }.join(',')
|
|
104
|
+
to = values[:to].map { |v| quote_value(v) }.join(',')
|
|
105
|
+
"FOR VALUES FROM (#{from}) TO (#{to})"
|
|
106
|
+
else
|
|
107
|
+
raise NotImplementedError
|
|
108
|
+
end
|
|
109
|
+
create_table(name, id: false, options: "PARTITION OF #{table_name} #{condition}")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def remove_partition(_table_name, name:)
|
|
113
|
+
drop_table(name)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
module ActiveRecord
|
|
121
|
+
module ConnectionAdapters
|
|
122
|
+
class PostgreSQLAdapter
|
|
123
|
+
prepend Ridgepole::Ext::PostgreSQLAdapter::Partitioning
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -45,6 +45,30 @@ module Ridgepole
|
|
|
45
45
|
stream.puts add_foreign_key_statements.sort.join("\n")
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
|
+
|
|
49
|
+
def tables(stream)
|
|
50
|
+
original = ignore_tables.dup
|
|
51
|
+
ignore_tables.concat(@connection.partition_tables)
|
|
52
|
+
super
|
|
53
|
+
ensure
|
|
54
|
+
self.ignore_tables = original
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def table(table, stream)
|
|
58
|
+
super
|
|
59
|
+
partition(table, stream)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def partition(table, stream)
|
|
63
|
+
if (partition = @connection.partition(table))
|
|
64
|
+
partition_definitions = partition.partition_definitions.map do |partition_definition|
|
|
65
|
+
"{ name: #{partition_definition.name.inspect}, values: #{partition_definition.values} }"
|
|
66
|
+
end.join(' ,')
|
|
67
|
+
|
|
68
|
+
stream.puts " add_partition #{partition.table.inspect}, #{partition.type.inspect}, #{partition.columns.inspect}, partition_definitions: [#{partition_definitions}]"
|
|
69
|
+
stream.puts
|
|
70
|
+
end
|
|
71
|
+
end
|
|
48
72
|
end
|
|
49
73
|
end
|
|
50
74
|
end
|
|
@@ -25,20 +25,18 @@ module Ridgepole
|
|
|
25
25
|
readable = ready[0]
|
|
26
26
|
|
|
27
27
|
readable.each do |f|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@logger.info("#{script_basename}: #{data}")
|
|
38
|
-
end
|
|
39
|
-
rescue EOFError
|
|
40
|
-
files.delete f
|
|
28
|
+
data = f.read_nonblock(1024)
|
|
29
|
+
next if data.nil?
|
|
30
|
+
|
|
31
|
+
data.chomp!
|
|
32
|
+
|
|
33
|
+
if f == stderr
|
|
34
|
+
@logger.warn("[WARNING] #{script_basename}: #{data}")
|
|
35
|
+
else
|
|
36
|
+
@logger.info("#{script_basename}: #{data}")
|
|
41
37
|
end
|
|
38
|
+
rescue EOFError
|
|
39
|
+
files.delete f
|
|
42
40
|
end
|
|
43
41
|
end
|
|
44
42
|
rescue EOFError
|
data/lib/ridgepole/version.rb
CHANGED
data/lib/ridgepole.rb
CHANGED
|
@@ -16,6 +16,9 @@ require 'diffy'
|
|
|
16
16
|
module Ridgepole; end
|
|
17
17
|
|
|
18
18
|
require 'ridgepole/ext/abstract_adapter/disable_table_options'
|
|
19
|
+
require 'ridgepole/ext/abstract_adapter/partition_definition'
|
|
20
|
+
require 'ridgepole/ext/abstract_adapter/partition_options'
|
|
21
|
+
require 'ridgepole/ext/abstract_adapter/partitioning'
|
|
19
22
|
require 'ridgepole/ext/pp_sort_hash'
|
|
20
23
|
require 'ridgepole/ext/schema_dumper'
|
|
21
24
|
require 'ridgepole/client'
|
data/ridgepole.gemspec
CHANGED
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
|
|
30
30
|
spec.add_development_dependency 'appraisal', '>= 2.2.0'
|
|
31
31
|
spec.add_development_dependency 'bundler'
|
|
32
|
-
spec.add_development_dependency 'erbh', '>= 0.1
|
|
32
|
+
spec.add_development_dependency 'erbh', '>= 0.2.1'
|
|
33
33
|
spec.add_development_dependency 'hash_modern_inspect', '>= 0.1.1'
|
|
34
34
|
spec.add_development_dependency 'hash_order_helper', '>= 0.1.6'
|
|
35
35
|
spec.add_development_dependency 'mysql2'
|
|
@@ -38,9 +38,10 @@ Gem::Specification.new do |spec|
|
|
|
38
38
|
spec.add_development_dependency 'rspec', '>= 3.0.0'
|
|
39
39
|
spec.add_development_dependency 'rspec-match_fuzzy', '>= 0.1.3'
|
|
40
40
|
spec.add_development_dependency 'rspec-match_ruby', '>= 0.1.3'
|
|
41
|
-
spec.add_development_dependency 'rubocop', '1.
|
|
41
|
+
spec.add_development_dependency 'rubocop', '1.24.1'
|
|
42
42
|
spec.add_development_dependency 'rubocop-rake', '>= 0.5.1'
|
|
43
43
|
spec.add_development_dependency 'rubocop-rspec', '>= 2.1.0'
|
|
44
44
|
spec.add_development_dependency 'simplecov'
|
|
45
45
|
spec.add_development_dependency 'simplecov-lcov'
|
|
46
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
46
47
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ridgepole
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Genki Sugawara
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-02-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -78,14 +78,14 @@ dependencies:
|
|
|
78
78
|
requirements:
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 0.1
|
|
81
|
+
version: 0.2.1
|
|
82
82
|
type: :development
|
|
83
83
|
prerelease: false
|
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
85
|
requirements:
|
|
86
86
|
- - ">="
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: 0.1
|
|
88
|
+
version: 0.2.1
|
|
89
89
|
- !ruby/object:Gem::Dependency
|
|
90
90
|
name: hash_modern_inspect
|
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -204,14 +204,14 @@ dependencies:
|
|
|
204
204
|
requirements:
|
|
205
205
|
- - '='
|
|
206
206
|
- !ruby/object:Gem::Version
|
|
207
|
-
version: 1.
|
|
207
|
+
version: 1.24.1
|
|
208
208
|
type: :development
|
|
209
209
|
prerelease: false
|
|
210
210
|
version_requirements: !ruby/object:Gem::Requirement
|
|
211
211
|
requirements:
|
|
212
212
|
- - '='
|
|
213
213
|
- !ruby/object:Gem::Version
|
|
214
|
-
version: 1.
|
|
214
|
+
version: 1.24.1
|
|
215
215
|
- !ruby/object:Gem::Dependency
|
|
216
216
|
name: rubocop-rake
|
|
217
217
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -306,7 +306,13 @@ files:
|
|
|
306
306
|
- lib/ridgepole/dumper.rb
|
|
307
307
|
- lib/ridgepole/execute_expander.rb
|
|
308
308
|
- lib/ridgepole/ext/abstract_adapter/disable_table_options.rb
|
|
309
|
+
- lib/ridgepole/ext/abstract_adapter/partition_definition.rb
|
|
310
|
+
- lib/ridgepole/ext/abstract_adapter/partition_options.rb
|
|
311
|
+
- lib/ridgepole/ext/abstract_adapter/partitioning.rb
|
|
309
312
|
- lib/ridgepole/ext/abstract_mysql_adapter/dump_auto_increment.rb
|
|
313
|
+
- lib/ridgepole/ext/abstract_mysql_adapter/partitioning.rb
|
|
314
|
+
- lib/ridgepole/ext/abstract_mysql_adapter/schema_creation.rb
|
|
315
|
+
- lib/ridgepole/ext/postgresql_adapter/partitioning.rb
|
|
310
316
|
- lib/ridgepole/ext/pp_sort_hash.rb
|
|
311
317
|
- lib/ridgepole/ext/schema_dumper.rb
|
|
312
318
|
- lib/ridgepole/external_sql_executer.rb
|
|
@@ -319,7 +325,8 @@ files:
|
|
|
319
325
|
homepage: https://github.com/ridgepole/ridgepole
|
|
320
326
|
licenses:
|
|
321
327
|
- MIT
|
|
322
|
-
metadata:
|
|
328
|
+
metadata:
|
|
329
|
+
rubygems_mfa_required: 'true'
|
|
323
330
|
post_install_message:
|
|
324
331
|
rdoc_options: []
|
|
325
332
|
require_paths:
|