ridgepole 1.0.7 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7886d7c158b4776c9db77e73c72ab5d882241950ed6a9f2c945a99220b7bcc4a
4
- data.tar.gz: 6429c8b8ed0c17dd1361c0e01592180c521002fa64fead1e625e9ec7ab2436a9
3
+ metadata.gz: '068fca35b633df2e4bc3b2d8ad5d2553496396a78c16ca371f18efc4dbad6adf'
4
+ data.tar.gz: c908229a06ddcbbf28e14b28af7f52f63c933d271db2e24231f6ed588fe5a1a0
5
5
  SHA512:
6
- metadata.gz: a7a06ba181dbdad2e0dd6f054366d745a3dbd119715bdb83b9a5e440c8a2258014859b2f9a8916b75fd5fb0ed9c27c4a32efe7d51761d7dd62a5e313cbad6fae
7
- data.tar.gz: '0277821bd5e0fc9c47ec038bf938a1b1a8c18c8395af8fd5ccfdf14ed9a8b80b03c5b6550f7b11d4da7220023be6e14782261a0a85f5b70ad7d136561bce4724'
6
+ metadata.gz: 6456e47a675dbdeb21ce56c9ed6091e823031ca082b191b7fb0438880d54ee6aea51988d4d9c5e07ded0e684a683d22f0d613cd3697c7c6d12ef6948b41e972e
7
+ data.tar.gz: 4b9f3b573975e0be50dec442e7db23688374754306082275bcc711e20e5813f2c4ca1975993797e02fd5b963cf396b7f5bbd2cd869f02aee468c8d07ce98e3c1
data/.rubocop.yml CHANGED
@@ -30,12 +30,6 @@ Metrics/ParameterLists:
30
30
  Enabled: false
31
31
  Metrics/PerceivedComplexity:
32
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"
39
33
  Style/Documentation:
40
34
  Enabled: false
41
35
  Style/GuardClause:
data/Appraisals CHANGED
@@ -1,22 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise 'activerecord-5.1' do
4
- gem 'activerecord', '~> 5.1.0'
5
- end
6
-
7
- appraise 'activerecord-5.2' do
8
- gem 'activerecord', '~> 5.2.0'
9
- gem 'mysql2', '~> 0.4.4'
10
- end
11
-
12
3
  appraise 'activerecord-6.0' do
13
- gem 'activerecord', '~> 6.0.0'
4
+ gem 'activerecord', '~> 6.0.6'
14
5
  end
15
6
 
16
7
  appraise 'activerecord-6.1' do
17
- gem 'activerecord', '~> 6.1.0'
8
+ gem 'activerecord', '~> 6.1.7'
18
9
  end
19
10
 
20
11
  appraise 'activerecord-7.0' do
21
- gem 'activerecord', '~> 7.0.0'
12
+ gem 'activerecord', '~> 7.0.4'
22
13
  end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2
4
+
5
+ ### 1.2.0 (2022/09/24)
6
+
7
+ * Updated supported column types [pull#399](https://github.com/ridgepole/ridgepole/pull/399) [pull#400](https://github.com/ridgepole/ridgepole/pull/400)
8
+ * Support check constraint [pull#393](https://github.com/ridgepole/ridgepole/pull/393) [pull#397](https://github.com/ridgepole/ridgepole/pull/397)
9
+ * Drop suport Rails 5.x [pull#395](https://github.com/ridgepole/ridgepole/pull/395 )
10
+
11
+ ## 1.1
12
+
13
+ ### 1.1.0 (2022/06/18)
14
+
15
+ * Revert partitioning support [pull#392](https://github.com/ridgepole/ridgepole/pull/392)
16
+
3
17
  ## 1.0
4
18
 
5
19
  ### 1.0.7 (2022/06/09)
data/README.md CHANGED
@@ -6,11 +6,13 @@ It defines DB schema using [Rails DSL](http://guides.rubyonrails.org/migrations.
6
6
  (like Chef/Puppet)
7
7
 
8
8
  [![Gem Version](https://badge.fury.io/rb/ridgepole.svg)](http://badge.fury.io/rb/ridgepole)
9
- [![Build Status](https://github.com/ridgepole/ridgepole/workflows/test/badge.svg?branch=1.0)](https://github.com/ridgepole/ridgepole/actions)
10
- [![Coverage Status](https://coveralls.io/repos/github/ridgepole/ridgepole/badge.svg?branch=1.0)](https://coveralls.io/github/ridgepole/ridgepole?branch=1.0)
9
+ [![Build Status](https://github.com/ridgepole/ridgepole/workflows/test/badge.svg?branch=1.2)](https://github.com/ridgepole/ridgepole/actions)
10
+ [![Coverage Status](https://coveralls.io/repos/github/ridgepole/ridgepole/badge.svg?branch=1.2)](https://coveralls.io/github/ridgepole/ridgepole?branch=1.2)
11
11
 
12
12
  **Notice**
13
13
 
14
+ * Drop support ActiveRecord 5.x in ridgepole v1.2.0.
15
+ * Partitioning is no longer supported in ridgepole v1.1.0.
14
16
  * ActiveRecord 7.x has some incompatible changes. If you get unintended differences in `datetime`, add `precision`.
15
17
  * cf. https://github.com/ridgepole/ridgepole/issues/381
16
18
  * For ActiveRecord 7.x series, please use AcriveRecord 7.0.2 or higher / Ridgepole 1.0.3 or higher.
@@ -216,7 +218,7 @@ See `mysql> show character set;` to find charset / collation pair for your syste
216
218
 
217
219
  ## Generated Column (MySQL)
218
220
 
219
- There should be NO extra white spaces in the expression (such as after comma).
221
+ There should be NO extra white spaces in the expression (such as after comma).
220
222
  Quotes in expression may cause the operations failure with MySQL 8.0.
221
223
 
222
224
  ```ruby
@@ -318,31 +320,6 @@ Apply `Schemafile`
318
320
  ...
319
321
  ```
320
322
 
321
- ## Partitioning
322
-
323
- **Notice:** PostgreSQL `PARTITION BY` must be specified with the create_table option.
324
-
325
- ### List Partitioning
326
-
327
- ```ruby
328
- create_table "articles", force: :cascade, options: "PARTITION BY LIST(id)" do |t|
329
- end
330
-
331
- add_partition("articles", :list, :id, partition_definitions: [{ name: 'p0', values: { in: [0,1,2] } }, { name: 'p1', values: { in: [3,4,5] } }])
332
- ```
333
-
334
- ### Range Partitioning
335
-
336
- ```ruby
337
- create_table "articles", force: :cascade, options: "PARTITION BY RANGE(id)" do |t|
338
- end
339
-
340
- # postgresql
341
- add_partition("articles", :range, :id, partition_definitions: [{ name: 'p0', values: { from: 'MINVALUE', to: 5 }}, { name: 'p1', values: { from: 5, to: 10 } }])
342
- # mysql
343
- add_partition("articles", :range, :id, partition_definitions: [{ name: 'p0', values: { to: 5 }}, { name: 'p1', values: { to: 10 } }])
344
- ```
345
-
346
323
  ## Run tests
347
324
 
348
325
 
data/docker-compose.yml CHANGED
@@ -1,19 +1,19 @@
1
1
  version: "3.8"
2
2
  services:
3
3
  mysql:
4
- image: "mysql:5.6"
4
+ image: "mysql:5.6.51"
5
5
  ports:
6
6
  - "13316:3306"
7
7
  environment:
8
8
  MYSQL_ROOT_PASSWORD: password
9
9
  mysql57:
10
- image: "mysql:5.7"
10
+ image: "mysql:5.7.39"
11
11
  ports:
12
12
  - "13317:3306"
13
13
  environment:
14
14
  MYSQL_ROOT_PASSWORD: password
15
15
  mysql80:
16
- image: "mysql:8.0"
16
+ image: "mysql:8.0.30"
17
17
  ports:
18
18
  - "13318:3306"
19
19
  environment:
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 6.0.0"
5
+ gem "activerecord", "~> 6.0.6"
6
6
 
7
7
  gemspec path: "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 6.1.0"
5
+ gem "activerecord", "~> 6.1.7"
6
6
 
7
7
  gemspec path: "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 7.0.0"
5
+ gem "activerecord", "~> 7.0.4"
6
6
 
7
7
  gemspec path: "../"
@@ -15,12 +15,7 @@ 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
22
18
  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?
24
19
  end
25
20
 
26
21
  def dump(&block)
@@ -245,6 +245,12 @@ create_table(#{table_name.inspect}, #{inspect_options_include_default_proc(optio
245
245
  end
246
246
  end
247
247
 
248
+ unless (check_constraints = attrs[:check_constraints] || {}).empty?
249
+ check_constraints.each do |_, check_constraint_attrs|
250
+ append_add_check_constraint(table_name, check_constraint_attrs, buf, true)
251
+ end
252
+ end
253
+
248
254
  buf.puts(<<-RUBY)
249
255
  end
250
256
  RUBY
@@ -310,29 +316,12 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
310
316
  append_change_table_options(table_name, comment_literal, buf)
311
317
  end
312
318
 
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
-
329
319
  def append_change(table_name, attrs, buf, pre_buf_for_fk, post_buf_for_fk)
330
320
  definition = attrs[:definition] || {}
331
321
  primary_key_definition = attrs[:primary_key_definition] || {}
332
322
  indices = attrs[:indices] || {}
333
323
  foreign_keys = attrs[:foreign_keys] || {}
334
- partition = attrs[:partition] || {}
335
- partition_definitions = attrs[:partition_definitions] || {}
324
+ check_constraints = attrs[:check_constraints] || {}
336
325
  table_options = attrs[:table_options]
337
326
  table_charset = attrs[:table_charset]
338
327
  table_collation = attrs[:table_collation]
@@ -348,6 +337,7 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
348
337
  end
349
338
 
350
339
  append_change_foreign_keys(table_name, foreign_keys, pre_buf_for_fk, post_buf_for_fk, @options) unless foreign_keys.empty?
340
+ append_change_check_constraints(table_name, check_constraints, buf) unless check_constraints.empty?
351
341
 
352
342
  if table_options || table_charset || table_collation
353
343
  append_change_table_raw_options(table_name, table_options, table_charset, table_collation,
@@ -356,10 +346,6 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
356
346
 
357
347
  append_change_table_comment(table_name, table_comment, buf) if table_comment
358
348
 
359
- append_change_partition(table_name, partition, buf) unless partition.empty?
360
-
361
- append_change_partition_definitions(table_name, partition_definitions, buf, post_buf_for_fk) unless partition_definitions.empty?
362
-
363
349
  buf.puts
364
350
  pre_buf_for_fk.puts
365
351
  post_buf_for_fk.puts
@@ -533,6 +519,40 @@ remove_foreign_key(#{table_name.inspect}, #{target})
533
519
  RUBY
534
520
  end
535
521
 
522
+ def append_change_check_constraints(table_name, delta, buf)
523
+ (delta[:delete] || {}).each do |_, attrs|
524
+ append_remove_check_constraint(table_name, attrs, buf)
525
+ end
526
+
527
+ (delta[:add] || {}).each do |_, attrs|
528
+ append_add_check_constraint(table_name, attrs, buf)
529
+ end
530
+ end
531
+
532
+ def append_add_check_constraint(table_name, attrs, buf, force_bulk_change = false)
533
+ expression = attrs.fetch(:expression)
534
+ attrs_options = attrs[:options] || {}
535
+
536
+ if force_bulk_change
537
+ buf.puts(<<-RUBY)
538
+ t.check_constraint(#{expression.inspect}, **#{attrs_options.inspect})
539
+ RUBY
540
+ else
541
+ buf.puts(<<-RUBY)
542
+ add_check_constraint(#{table_name.inspect}, #{expression.inspect}, **#{attrs_options.inspect})
543
+ RUBY
544
+ end
545
+ end
546
+
547
+ def append_remove_check_constraint(table_name, attrs, buf)
548
+ expression = attrs.fetch(:expression)
549
+ attrs_options = attrs[:options] || {}
550
+
551
+ buf.puts(<<-RUBY)
552
+ remove_check_constraint(#{table_name.inspect}, #{expression.inspect}, **#{attrs_options.inspect})
553
+ RUBY
554
+ end
555
+
536
556
  def delta_execute
537
557
  @delta[:execute] || []
538
558
  end
@@ -37,9 +37,6 @@ 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])
43
40
  end
44
41
 
45
42
  scan_relation_info(relation_info)
@@ -104,6 +101,7 @@ module Ridgepole
104
101
  scan_definition_change(from[:definition], to[:definition], from[:indices], table_name, from[:options], table_delta)
105
102
  scan_indices_change(from[:indices], to[:indices], to[:definition], table_delta, from[:options], to[:options])
106
103
  scan_foreign_keys_change(from[:foreign_keys], to[:foreign_keys], table_delta, @options)
104
+ scan_check_constraints_change(from[:check_constraints], to[:check_constraints], table_delta)
107
105
 
108
106
  unless table_delta.empty?
109
107
  delta[:change] ||= {}
@@ -475,6 +473,38 @@ module Ridgepole
475
473
  table_delta[:foreign_keys] = foreign_keys_delta unless foreign_keys_delta.empty?
476
474
  end
477
475
 
476
+ def scan_check_constraints_change(from, to, table_delta)
477
+ from = (from || {}).dup
478
+ to = (to || {}).dup
479
+ check_constraints_delta = {}
480
+
481
+ to.each do |name, to_attrs|
482
+ from_attrs = from.delete(name)
483
+
484
+ if from_attrs
485
+ if from_attrs != to_attrs
486
+ check_constraints_delta[:add] ||= {}
487
+ check_constraints_delta[:add][name] = to_attrs
488
+
489
+ check_constraints_delta[:delete] ||= {}
490
+ check_constraints_delta[:delete][name] = from_attrs
491
+ end
492
+ else
493
+ check_constraints_delta[:add] ||= {}
494
+ check_constraints_delta[:add][name] = to_attrs
495
+ end
496
+ end
497
+
498
+ unless @options[:merge]
499
+ from.each do |name, from_attrs|
500
+ check_constraints_delta[:delete] ||= {}
501
+ check_constraints_delta[:delete][name] = from_attrs
502
+ end
503
+ end
504
+
505
+ table_delta[:check_constraints] = check_constraints_delta unless check_constraints_delta.empty?
506
+ end
507
+
478
508
  # XXX: MySQL only?
479
509
  # https://github.com/rails/rails/blob/v4.2.1/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#L760
480
510
  # https://github.com/rails/rails/blob/v4.2.1/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb#L102
@@ -620,56 +650,6 @@ module Ridgepole
620
650
  end
621
651
  end
622
652
 
623
- def scan_partition_change(table_name, from, to, table_delta)
624
- from = (from || {}).dup
625
- to = (to || {}).dup
626
- partition_delta = {}
627
-
628
- return if to.empty? && from.empty?
629
-
630
- if from.empty? && Ridgepole::ConnectionAdapters.mysql?
631
- partition_delta[:add] ||= {}
632
- partition_delta[:add][table_name] = to
633
- else
634
- if from.present? && (to[:type] != from[:type] || to[:columns] != from[:columns])
635
- @logger.warn(<<-MSG)
636
- "[WARNING] '#{table_name}' partition is skipped because of the different partition type.
637
- to: #{to[:type]} #{to[:columns]}
638
- from: #{from[:type]}" #{from[:columns]}
639
- MSG
640
- return
641
- end
642
-
643
- if from[:partition_definitions].present? && (to[:partition_definitions] & from[:partition_definitions]).empty?
644
- raise "All partition is different. please check partition settings.to: #{to}, from: #{from}"
645
- end
646
-
647
- scan_partition_definition_chanage(from, to, table_delta)
648
- end
649
-
650
- table_delta[:partition] = partition_delta unless partition_delta.empty?
651
- end
652
-
653
- def scan_partition_definition_chanage(from, to, table_delta)
654
- partition_definitions_delta = {}
655
- attrs = { type: from[:type] || to[:type] }
656
-
657
- from_partitions = (from[:partition_definitions] || []).index_by { |partition| partition[:name] }
658
- to_partitions = (to[:partition_definitions] || []).index_by { |partition| partition[:name] }
659
-
660
- (from_partitions.keys - to_partitions.keys).each do |name|
661
- partition_definitions_delta[:delete] ||= {}
662
- partition_definitions_delta[:delete][name] = attrs.merge(values: from_partitions[name][:values])
663
- end
664
-
665
- (to_partitions.keys - from_partitions.keys).each do |name|
666
- partition_definitions_delta[:add] ||= {}
667
- partition_definitions_delta[:add][name] = attrs.merge(values: to_partitions[name][:values])
668
- end
669
-
670
- table_delta[:partition_definitions] = partition_definitions_delta unless partition_definitions_delta.empty?
671
- end
672
-
673
653
  def check_table_existence(definition)
674
654
  return unless @options[:tables]
675
655
 
@@ -91,22 +91,18 @@ 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
- if values.key?(:in)
100
- values[:in] = Array.wrap(values[:in])
101
- values[:in] = values[:in].map(&:to_s) if Ridgepole::ConnectionAdapters.postgresql?
102
- end
103
- values[:to] = Array.wrap(values[:to]) if values.key?(:to)
104
- values[:from] = Array.wrap(values[:from]) if values.key?(:from)
105
- end
106
- @__definition[table_name][:partition] = {
107
- type: type,
108
- columns: Array.wrap(columns),
109
- partition_definitions: partition_definitions,
94
+ def add_check_constraint(table_name, expression, options = {})
95
+ table_name = table_name.to_s
96
+ expression = expression.to_s
97
+ options[:name] = options[:name].to_s if options[:name]
98
+
99
+ idx = options[:name] || expression
100
+
101
+ @__definition[table_name] ||= {}
102
+ @__definition[table_name][:check_constraints] ||= {}
103
+ @__definition[table_name][:check_constraints][idx] = {
104
+ expression: expression,
105
+ options: options,
110
106
  }
111
107
  end
112
108
 
@@ -26,32 +26,41 @@ module Ridgepole
26
26
  DEFAULT_PRIMARY_KEY_TYPE = :bigint
27
27
 
28
28
  TYPES = {
29
- # https://github.com/rails/rails/blob/v4.2.1/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb#L274
30
- string: {},
31
- text: {},
32
- integer: {},
29
+ # https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb#L300-L301
33
30
  bigint: {},
34
- float: {},
35
- decimal: {},
36
- datetime: {},
37
- timestamp: {},
38
- time: {},
39
- date: {},
40
31
  binary: {},
41
32
  boolean: {},
33
+ date: {},
34
+ datetime: {},
35
+ decimal: {},
36
+ float: {},
37
+ integer: {},
38
+ json: {},
39
+ string: {},
40
+ text: {},
41
+ time: {},
42
+ timestamp: {},
43
+ virtual: {},
42
44
 
43
- # https://github.com/rails/rails/blob/v4.2.1/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L79
45
+ # https://github.com/rails/rails/blob/v6.0.6/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L101
44
46
  serial: { null: false },
45
47
  bigserial: { null: false },
48
+ # string: {},
49
+ # text: {},
50
+ # integer: {},
51
+ # float: {},
52
+ # decimal: {},
53
+ # datetime: {},
54
+ # time: {},
55
+ # date: {},
46
56
  daterange: {},
47
57
  numrange: {},
48
58
  tsrange: {},
49
59
  tstzrange: {},
50
60
  int4range: {},
51
61
  int8range: {},
52
- # binary: {}, # dup key
53
- # boolean: {}, # dup key
54
- # bigint: {}, # dup key
62
+ # binary: {},
63
+ # boolean: {},
55
64
  xml: {},
56
65
  tsvector: {},
57
66
  hstore: {},
@@ -59,20 +68,25 @@ module Ridgepole
59
68
  cidr: {},
60
69
  macaddr: {},
61
70
  uuid: {},
62
- json: {},
71
+ # json: {},
63
72
  jsonb: {},
64
73
  ltree: {},
65
74
  citext: {},
66
75
  point: {},
76
+ line: {},
77
+ lseg: {},
78
+ box: {},
79
+ path: {},
80
+ polygon: {},
81
+ circle: {},
67
82
  bit: {},
68
83
  bit_varying: {},
69
84
  money: {},
85
+ interval: {},
86
+ oid: {},
70
87
 
71
- # https://github.com/rails/rails/blob/v5.1.1/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb#L184
72
- virtual: {},
73
-
74
- # https://github.com/rails/rails/blob/v5.0.4/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#L53
75
- # json: {}, # dup key
88
+ # https://github.com/ridgepole/ridgepole/issues/394
89
+ timestamptz: {},
76
90
  }.freeze
77
91
 
78
92
  TYPES.each do |column_type, default_options|
@@ -159,6 +173,10 @@ module Ridgepole
159
173
  end
160
174
  end
161
175
  alias belongs_to references
176
+
177
+ def check_constraint(expression, options = {})
178
+ @base.add_check_constraint(@table_name, expression, options)
179
+ end
162
180
  end
163
181
  end
164
182
  end
@@ -45,30 +45,6 @@ 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
72
48
  end
73
49
  end
74
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ridgepole
4
- VERSION = '1.0.7'
4
+ VERSION = '1.2.0'
5
5
  end
data/lib/ridgepole.rb CHANGED
@@ -16,9 +16,6 @@ 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'
22
19
  require 'ridgepole/ext/pp_sort_hash'
23
20
  require 'ridgepole/ext/schema_dumper'
24
21
  require 'ridgepole/client'
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.7
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Sugawara
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-08 00:00:00.000000000 Z
11
+ date: 2022-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -288,8 +288,6 @@ files:
288
288
  - Rakefile
289
289
  - bin/ridgepole
290
290
  - docker-compose.yml
291
- - gemfiles/activerecord_5.1.gemfile
292
- - gemfiles/activerecord_5.2.gemfile
293
291
  - gemfiles/activerecord_6.0.gemfile
294
292
  - gemfiles/activerecord_6.1.gemfile
295
293
  - gemfiles/activerecord_7.0.gemfile
@@ -306,13 +304,7 @@ files:
306
304
  - lib/ridgepole/dumper.rb
307
305
  - lib/ridgepole/execute_expander.rb
308
306
  - 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
312
307
  - 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
316
308
  - lib/ridgepole/ext/pp_sort_hash.rb
317
309
  - lib/ridgepole/ext/schema_dumper.rb
318
310
  - lib/ridgepole/external_sql_executer.rb
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 5.1.0"
6
-
7
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 5.2.0"
6
- gem "mysql2", "~> 0.4.4"
7
-
8
- gemspec path: "../"
@@ -1,19 +0,0 @@
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
@@ -1,34 +0,0 @@
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
@@ -1,40 +0,0 @@
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
@@ -1,72 +0,0 @@
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,
50
- partition_definitions: partition_definitions))
51
- end
52
-
53
- def add_partition(table_name, name:, values:)
54
- pd = ActiveRecord::ConnectionAdapters::PartitionDefinition.new(name, values)
55
- execute "ALTER TABLE #{quote_table_name(table_name)} ADD PARTITION (#{schema_creation.accept(pd)})"
56
- end
57
-
58
- def remove_partition(table_name, name:)
59
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP PARTITION #{name}"
60
- end
61
- end
62
- end
63
- end
64
- end
65
-
66
- module ActiveRecord
67
- module ConnectionAdapters
68
- class AbstractMysqlAdapter < AbstractAdapter
69
- prepend Ridgepole::Ext::AbstractMysqlAdapter::Partitioning
70
- end
71
- end
72
- end
@@ -1,46 +0,0 @@
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
@@ -1,138 +0,0 @@
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 |name, val_str|
55
- values = if val_str == 'DEFAULT'
56
- { default: true }
57
- else
58
- case options[:type]
59
- when :list
60
- values = val_str.match(/FOR VALUES IN \((?<csv>.+)\)$/)[:csv].split(',').map(&:strip).map { |value| cast_value(value) }
61
- { in: Array.wrap(values) }
62
- when :range
63
- match = val_str.match(/FOR VALUES FROM \((?<from>.+)\) TO \((?<to>.+)\)/)
64
- from = match[:from].split(',').map(&:strip).map { |value| cast_value(value) }
65
- to = match[:to].split(',').map(&:strip).map { |value| cast_value(value) }
66
- { from: from, to: to }
67
- when :hash
68
- match = val_str.match(/FOR VALUES WITH \(modulus (?<modulus>\d+), remainder (?<remainder>\d+)\)/)
69
- { modulus: match[:modulus].to_i, remainder: match[:remainder].to_i }
70
- else
71
- raise NotImplementedError
72
- end
73
- end
74
- { name: name, values: values }
75
- end
76
-
77
- ActiveRecord::ConnectionAdapters::PartitionOptions.new(table_name, options[:type], options[:columns],
78
- partition_definitions: partition_definitions)
79
- end
80
-
81
- def cast_value(value)
82
- Integer(value)
83
- rescue ArgumentError
84
- value.delete(%q("')) # "
85
- end
86
-
87
- def quote_value(value)
88
- if %w[MINVALUE MAXVALUE].include?(value)
89
- value
90
- else
91
- quote(value)
92
- end
93
- end
94
-
95
- def partition_tables
96
- partition_info = query(<<~SQL, 'SCHEMA')
97
- SELECT p.relname
98
- FROM pg_class t
99
- JOIN pg_inherits i on i.inhparent = t.oid
100
- JOIN pg_class p on p.oid = i.inhrelid
101
- ORDER BY p.relname
102
- SQL
103
- partition_info.map { |row| row[0] }
104
- end
105
-
106
- # SchemaStatements
107
- def add_partition(table_name, name:, values:)
108
- condition = if values.key?(:default)
109
- 'DEFAULT'
110
- elsif values.key?(:in)
111
- "FOR VALUES IN (#{values[:in].map { |v| quote_value(v) }.join(',')})"
112
- elsif values.key?(:to)
113
- from = values[:from].map { |v| quote_value(v) }.join(',')
114
- to = values[:to].map { |v| quote_value(v) }.join(',')
115
- "FOR VALUES FROM (#{from}) TO (#{to})"
116
- elsif values.key?(:modulus)
117
- "FOR VALUES WITH (modulus #{values[:modulus]}, remainder #{values[:remainder]})"
118
- else
119
- raise NotImplementedError
120
- end
121
- create_table(name, id: false, options: "PARTITION OF #{table_name} #{condition}")
122
- end
123
-
124
- def remove_partition(_table_name, name:)
125
- drop_table(name)
126
- end
127
- end
128
- end
129
- end
130
- end
131
-
132
- module ActiveRecord
133
- module ConnectionAdapters
134
- class PostgreSQLAdapter
135
- prepend Ridgepole::Ext::PostgreSQLAdapter::Partitioning
136
- end
137
- end
138
- end