ridgepole 0.9.6 → 1.0.2
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/Appraisals +4 -0
- data/CHANGELOG.md +251 -0
- data/README.md +45 -155
- data/bin/ridgepole +83 -85
- data/docker-compose.yml +26 -18
- data/gemfiles/activerecord_7.0.gemfile +7 -0
- data/lib/ridgepole/client.rb +5 -0
- data/lib/ridgepole/delta.rb +22 -0
- data/lib/ridgepole/diff.rb +57 -3
- data/lib/ridgepole/dsl_parser/context.rb +16 -0
- data/lib/ridgepole/execute_expander.rb +4 -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 +4 -3
- metadata +19 -10
@@ -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
@@ -24,12 +24,12 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.required_ruby_version = Gem::Requirement.new('>= 2.2.7') # rubocop:disable Gemspec/RequiredRubyVersion
|
26
26
|
|
27
|
-
spec.add_dependency 'activerecord', '>= 5.1', '<
|
27
|
+
spec.add_dependency 'activerecord', '>= 5.1', '< 7.1'
|
28
28
|
spec.add_dependency 'diffy'
|
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: 0.
|
4
|
+
version: 1.0.2
|
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-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '5.1'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '7.1'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '5.1'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7.1'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: diffy
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -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
|
@@ -281,6 +281,7 @@ files:
|
|
281
281
|
- ".rubocop.yml"
|
282
282
|
- ".simplecov"
|
283
283
|
- Appraisals
|
284
|
+
- CHANGELOG.md
|
284
285
|
- Gemfile
|
285
286
|
- LICENSE.txt
|
286
287
|
- README.md
|
@@ -291,6 +292,7 @@ files:
|
|
291
292
|
- gemfiles/activerecord_5.2.gemfile
|
292
293
|
- gemfiles/activerecord_6.0.gemfile
|
293
294
|
- gemfiles/activerecord_6.1.gemfile
|
295
|
+
- gemfiles/activerecord_7.0.gemfile
|
294
296
|
- lib/ridgepole.rb
|
295
297
|
- lib/ridgepole/cli/config.rb
|
296
298
|
- lib/ridgepole/client.rb
|
@@ -304,7 +306,13 @@ files:
|
|
304
306
|
- lib/ridgepole/dumper.rb
|
305
307
|
- lib/ridgepole/execute_expander.rb
|
306
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
|
307
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
|
308
316
|
- lib/ridgepole/ext/pp_sort_hash.rb
|
309
317
|
- lib/ridgepole/ext/schema_dumper.rb
|
310
318
|
- lib/ridgepole/external_sql_executer.rb
|
@@ -317,7 +325,8 @@ files:
|
|
317
325
|
homepage: https://github.com/ridgepole/ridgepole
|
318
326
|
licenses:
|
319
327
|
- MIT
|
320
|
-
metadata:
|
328
|
+
metadata:
|
329
|
+
rubygems_mfa_required: 'true'
|
321
330
|
post_install_message:
|
322
331
|
rdoc_options: []
|
323
332
|
require_paths:
|
@@ -333,7 +342,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
333
342
|
- !ruby/object:Gem::Version
|
334
343
|
version: '0'
|
335
344
|
requirements: []
|
336
|
-
rubygems_version: 3.
|
345
|
+
rubygems_version: 3.2.32
|
337
346
|
signing_key:
|
338
347
|
specification_version: 4
|
339
348
|
summary: Ridgepole is a tool to manage DB schema.
|