lhm-shopify 4.4.2 → 4.5.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: 938d28fc99ea36454247de34a03ff3a202f0892e11f590b0c41556de4e041ee4
4
- data.tar.gz: e28790317276015c4ffaeb9150c7e2a5eeb3a3fad1713604bda670225c6e181b
3
+ metadata.gz: 56380d3c695085c3fdc5ea625014ad7a90948a0a227d9f543cfc23efc8ec9403
4
+ data.tar.gz: b06d43bb5c314e15846ee46ed50acfe8a076069558b0fd8f94a620a574bd2a38
5
5
  SHA512:
6
- metadata.gz: 6eeca296f8626d383bccc0978440f26dd05c7a4da002648101db578e553d4a407da4238e35cf7ee18a21e821d7c1f66a30c55bd665dff9863bdad80e3f6c60b9
7
- data.tar.gz: 78b1799fd87375c9042b3340b40db4439702b007977632afe104800bd01b12aad34e44f9694b3d58e9a277a3a42a8785794d87c31d2b56c3a9b59f448b60eda4
6
+ metadata.gz: 0244a6df042163ed02c77dd37bfaa800ff99a8a5af518561694fb071eb630dafd73cc12146be38a41e1e02d1f5523f7ae9ebcbd90a9696ae267d2b1e5e425957
7
+ data.tar.gz: 4fda241d6c7f516d96c679c1fee6bfdabc5c13e8e27baa95623406f0fb568294271fac81a836e3611b4f9d3243ef14fa7d433693603b3ae5056fdd7a31acc66c
@@ -15,17 +15,19 @@ jobs:
15
15
  fail-fast: false
16
16
  max-parallel: 8
17
17
  matrix:
18
- activerecord: ["6.1", "7.0", "7.1", "head"]
18
+ activerecord: ["7.2", "8.0", "head"]
19
19
  ruby: ["3.1", "3.2", "3.3", "head"]
20
20
  mysql: ["5.7", "8.0"]
21
21
  adapter: ["mysql2", "trilogy"]
22
22
  exclude:
23
23
  - activerecord: 6.1
24
24
  ruby: head
25
- - activerecord: 7.0
25
+ - activerecord: 7.2
26
26
  ruby: head
27
+ - activerecord: 8.0
28
+ ruby: 3.1
27
29
  - activerecord: head
28
- ruby: 3.0
30
+ ruby: 3.1
29
31
 
30
32
  env:
31
33
  BUNDLE_GEMFILE: "${{ github.workspace }}/gemfiles/activerecord_${{ matrix.activerecord }}.gemfile"
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.2
1
+ 3.3.6
data/Appraisals CHANGED
@@ -1,15 +1,9 @@
1
- appraise "activerecord-6.1" do
2
- gem "activerecord", "6.1.0"
3
- gem "activerecord-trilogy-adapter"
1
+ appraise "activerecord-7.2" do
2
+ gem "activerecord", "7.2.2.1"
4
3
  end
5
4
 
6
- appraise "activerecord-7.0" do
7
- gem "activerecord", "7.0.8"
8
- gem "activerecord-trilogy-adapter"
9
- end
10
-
11
- appraise "activerecord-7.1" do
12
- gem "activerecord", "7.1.1"
5
+ appraise "activerecord-8.0" do
6
+ gem "activerecord", "8.0.1"
13
7
  end
14
8
 
15
9
  appraise "activerecord-head" do
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Unreleased
2
2
 
3
+ # 4.5.0 (Feb, 2025)
4
+ * Update test matrix to include Rails 8
5
+ * Add option to force tables to use default engine
6
+ * Change default algorithm for add/rename/remove column operations
7
+ * Drop support for ActiveRecord version 6.1, as it has reached EOL
8
+ * Add support for tables with generated columns
9
+
3
10
  # 4.4.2 (Sep, 2024)
4
11
  * Allow caller to set the algorithm that will be used for DDL ALTER TABLE operations
5
12
 
data/Gemfile.lock CHANGED
@@ -1,20 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lhm-shopify (4.4.2)
4
+ lhm-shopify (4.5.0)
5
5
  retriable (>= 3.0.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (7.2.0)
11
- activesupport (= 7.2.0)
12
- activerecord (7.2.0)
13
- activemodel (= 7.2.0)
14
- activesupport (= 7.2.0)
10
+ activemodel (8.0.1)
11
+ activesupport (= 8.0.1)
12
+ activerecord (8.0.1)
13
+ activemodel (= 8.0.1)
14
+ activesupport (= 8.0.1)
15
15
  timeout (>= 0.4.0)
16
- activesupport (7.2.0)
16
+ activesupport (8.0.1)
17
17
  base64
18
+ benchmark (>= 0.3)
18
19
  bigdecimal
19
20
  concurrent-ruby (~> 1.0, >= 1.3.1)
20
21
  connection_pool (>= 2.2.5)
@@ -24,45 +25,50 @@ GEM
24
25
  minitest (>= 5.1)
25
26
  securerandom (>= 0.3)
26
27
  tzinfo (~> 2.0, >= 2.0.5)
28
+ uri (>= 0.13.1)
27
29
  after_do (0.4.0)
28
30
  appraisal (2.5.0)
29
31
  bundler
30
32
  rake
31
33
  thor (>= 0.14.0)
32
34
  base64 (0.2.0)
33
- bigdecimal (3.1.8)
35
+ benchmark (0.4.0)
36
+ bigdecimal (3.1.9)
34
37
  byebug (11.1.3)
35
- concurrent-ruby (1.3.4)
36
- connection_pool (2.4.1)
38
+ concurrent-ruby (1.3.5)
39
+ connection_pool (2.5.0)
37
40
  docile (1.4.1)
38
41
  drb (2.2.1)
39
- i18n (1.14.5)
42
+ i18n (1.14.7)
40
43
  concurrent-ruby (~> 1.0)
41
- logger (1.6.0)
42
- minitest (5.25.1)
44
+ logger (1.6.5)
45
+ minitest (5.25.4)
43
46
  mocha (2.4.5)
44
47
  ruby2_keywords (>= 0.0.5)
45
48
  mysql2 (0.5.6)
49
+ ostruct (0.6.1)
46
50
  rake (13.2.1)
47
51
  retriable (3.1.2)
48
52
  ruby2_keywords (0.0.5)
49
- securerandom (0.3.1)
53
+ securerandom (0.4.1)
50
54
  simplecov (0.22.0)
51
55
  docile (~> 1.1)
52
56
  simplecov-html (~> 0.11)
53
57
  simplecov_json_formatter (~> 0.1)
54
58
  simplecov-html (0.12.3)
55
59
  simplecov_json_formatter (0.1.4)
56
- thor (1.3.1)
57
- timeout (0.4.1)
60
+ thor (1.3.2)
61
+ timeout (0.4.3)
58
62
  toxiproxy (2.0.2)
59
63
  trilogy (2.8.1)
60
64
  tzinfo (2.0.6)
61
65
  concurrent-ruby (~> 1.0)
66
+ uri (1.0.2)
62
67
 
63
68
  PLATFORMS
64
69
  arm64-darwin-21
65
70
  arm64-darwin-22
71
+ arm64-darwin-23
66
72
  x86_64-darwin-20
67
73
  x86_64-linux
68
74
 
@@ -72,13 +78,15 @@ DEPENDENCIES
72
78
  appraisal
73
79
  byebug
74
80
  lhm-shopify!
81
+ logger
75
82
  minitest
76
83
  mocha
77
84
  mysql2
85
+ ostruct
78
86
  rake
79
87
  simplecov
80
88
  toxiproxy
81
89
  trilogy
82
90
 
83
91
  BUNDLED WITH
84
- 2.2.22
92
+ 2.6.3
@@ -2,7 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "6.1.0"
6
- gem "activerecord-trilogy-adapter"
5
+ gem "activerecord", "7.2.2.1"
7
6
 
8
7
  gemspec path: "../"
@@ -1,76 +1,90 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- lhm-shopify (4.4.2)
4
+ lhm-shopify (4.5.0)
5
5
  retriable (>= 3.0.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (6.1.0)
11
- activesupport (= 6.1.0)
12
- activerecord (6.1.0)
13
- activemodel (= 6.1.0)
14
- activesupport (= 6.1.0)
15
- activerecord-trilogy-adapter (3.1.2)
16
- activerecord (>= 6.0.a, < 7.1.a)
17
- trilogy (>= 2.4.0)
18
- activesupport (6.1.0)
19
- concurrent-ruby (~> 1.0, >= 1.0.2)
10
+ activemodel (7.2.2.1)
11
+ activesupport (= 7.2.2.1)
12
+ activerecord (7.2.2.1)
13
+ activemodel (= 7.2.2.1)
14
+ activesupport (= 7.2.2.1)
15
+ timeout (>= 0.4.0)
16
+ activesupport (7.2.2.1)
17
+ base64
18
+ benchmark (>= 0.3)
19
+ bigdecimal
20
+ concurrent-ruby (~> 1.0, >= 1.3.1)
21
+ connection_pool (>= 2.2.5)
22
+ drb
20
23
  i18n (>= 1.6, < 2)
24
+ logger (>= 1.4.2)
21
25
  minitest (>= 5.1)
22
- tzinfo (~> 2.0)
23
- zeitwerk (~> 2.3)
26
+ securerandom (>= 0.3)
27
+ tzinfo (~> 2.0, >= 2.0.5)
24
28
  after_do (0.4.0)
25
29
  appraisal (2.5.0)
26
30
  bundler
27
31
  rake
28
32
  thor (>= 0.14.0)
33
+ base64 (0.2.0)
34
+ benchmark (0.4.0)
35
+ bigdecimal (3.1.9)
29
36
  byebug (11.1.3)
30
- concurrent-ruby (1.2.2)
37
+ concurrent-ruby (1.3.5)
38
+ connection_pool (2.5.0)
31
39
  docile (1.4.0)
32
- i18n (1.14.1)
40
+ drb (2.2.1)
41
+ i18n (1.14.7)
33
42
  concurrent-ruby (~> 1.0)
34
- minitest (5.22.2)
43
+ logger (1.6.5)
44
+ minitest (5.25.4)
35
45
  mocha (2.1.0)
36
46
  ruby2_keywords (>= 0.0.5)
37
47
  mysql2 (0.5.5)
48
+ ostruct (0.6.1)
38
49
  rake (13.0.6)
39
50
  retriable (3.1.2)
40
51
  ruby2_keywords (0.0.5)
52
+ securerandom (0.4.1)
41
53
  simplecov (0.22.0)
42
54
  docile (~> 1.1)
43
55
  simplecov-html (~> 0.11)
44
56
  simplecov_json_formatter (~> 0.1)
45
57
  simplecov-html (0.12.3)
46
58
  simplecov_json_formatter (0.1.4)
47
- thor (1.2.2)
59
+ thor (1.3.2)
60
+ timeout (0.4.3)
48
61
  toxiproxy (2.0.2)
49
- trilogy (2.6.0)
62
+ trilogy (2.9.0)
50
63
  tzinfo (2.0.6)
51
64
  concurrent-ruby (~> 1.0)
52
- zeitwerk (2.6.12)
53
65
 
54
66
  PLATFORMS
55
67
  arm64-darwin-21
56
68
  arm64-darwin-22
69
+ arm64-darwin-23
57
70
  x86_64-darwin-20
58
71
  x86_64-linux
59
72
 
60
73
  DEPENDENCIES
61
- activerecord (= 6.1.0)
62
- activerecord-trilogy-adapter
74
+ activerecord (= 7.2.2.1)
63
75
  after_do
64
76
  appraisal
65
77
  byebug
66
78
  lhm-shopify!
79
+ logger
67
80
  minitest
68
81
  mocha
69
82
  mysql2
83
+ ostruct
70
84
  rake
71
85
  simplecov
72
86
  toxiproxy
73
87
  trilogy
74
88
 
75
89
  BUNDLED WITH
76
- 2.2.22
90
+ 2.6.3
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "7.1.1"
5
+ gem "activerecord", "8.0.1"
6
6
 
7
7
  gemspec path: "../"
@@ -1,83 +1,92 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- lhm-shopify (4.4.2)
4
+ lhm-shopify (4.5.0)
5
5
  retriable (>= 3.0.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (7.1.1)
11
- activesupport (= 7.1.1)
12
- activerecord (7.1.1)
13
- activemodel (= 7.1.1)
14
- activesupport (= 7.1.1)
10
+ activemodel (8.0.1)
11
+ activesupport (= 8.0.1)
12
+ activerecord (8.0.1)
13
+ activemodel (= 8.0.1)
14
+ activesupport (= 8.0.1)
15
15
  timeout (>= 0.4.0)
16
- activesupport (7.1.1)
16
+ activesupport (8.0.1)
17
17
  base64
18
+ benchmark (>= 0.3)
18
19
  bigdecimal
19
- concurrent-ruby (~> 1.0, >= 1.0.2)
20
+ concurrent-ruby (~> 1.0, >= 1.3.1)
20
21
  connection_pool (>= 2.2.5)
21
22
  drb
22
23
  i18n (>= 1.6, < 2)
24
+ logger (>= 1.4.2)
23
25
  minitest (>= 5.1)
24
- mutex_m
25
- tzinfo (~> 2.0)
26
+ securerandom (>= 0.3)
27
+ tzinfo (~> 2.0, >= 2.0.5)
28
+ uri (>= 0.13.1)
26
29
  after_do (0.4.0)
27
30
  appraisal (2.5.0)
28
31
  bundler
29
32
  rake
30
33
  thor (>= 0.14.0)
31
- base64 (0.1.1)
32
- bigdecimal (3.1.4)
34
+ base64 (0.2.0)
35
+ benchmark (0.4.0)
36
+ bigdecimal (3.1.9)
33
37
  byebug (11.1.3)
34
- concurrent-ruby (1.2.2)
35
- connection_pool (2.4.1)
38
+ concurrent-ruby (1.3.5)
39
+ connection_pool (2.5.0)
36
40
  docile (1.4.0)
37
- drb (2.1.1)
38
- ruby2_keywords
41
+ drb (2.2.1)
39
42
  i18n (1.14.1)
40
43
  concurrent-ruby (~> 1.0)
44
+ logger (1.6.1)
41
45
  minitest (5.22.2)
42
46
  mocha (2.1.0)
43
47
  ruby2_keywords (>= 0.0.5)
44
- mutex_m (0.1.2)
45
48
  mysql2 (0.5.5)
49
+ ostruct (0.6.1)
46
50
  rake (13.0.6)
47
51
  retriable (3.1.2)
48
52
  ruby2_keywords (0.0.5)
53
+ securerandom (0.4.1)
49
54
  simplecov (0.22.0)
50
55
  docile (~> 1.1)
51
56
  simplecov-html (~> 0.11)
52
57
  simplecov_json_formatter (~> 0.1)
53
58
  simplecov-html (0.12.3)
54
59
  simplecov_json_formatter (0.1.4)
55
- thor (1.2.2)
56
- timeout (0.4.0)
60
+ thor (1.3.2)
61
+ timeout (0.4.3)
57
62
  toxiproxy (2.0.2)
58
- trilogy (2.6.0)
63
+ trilogy (2.9.0)
59
64
  tzinfo (2.0.6)
60
65
  concurrent-ruby (~> 1.0)
66
+ uri (1.0.2)
61
67
 
62
68
  PLATFORMS
63
69
  arm64-darwin-21
64
70
  arm64-darwin-22
71
+ arm64-darwin-23
65
72
  x86_64-darwin-20
66
73
  x86_64-linux
67
74
 
68
75
  DEPENDENCIES
69
- activerecord (= 7.1.1)
76
+ activerecord (= 8.0.1)
70
77
  after_do
71
78
  appraisal
72
79
  byebug
73
80
  lhm-shopify!
81
+ logger
74
82
  minitest
75
83
  mocha
76
84
  mysql2
85
+ ostruct
77
86
  rake
78
87
  simplecov
79
88
  toxiproxy
80
89
  trilogy
81
90
 
82
91
  BUNDLED WITH
83
- 2.2.22
92
+ 2.6.3
@@ -1,16 +1,17 @@
1
1
  GIT
2
2
  remote: https://github.com/rails/rails.git
3
- revision: f4a9b7618fc32f0d3b2c0ff03a3f34f4964cc553
3
+ revision: bdad2707835949a96dd29e747b8c324593efd4d8
4
4
  branch: main
5
5
  specs:
6
- activemodel (8.0.0.alpha)
7
- activesupport (= 8.0.0.alpha)
8
- activerecord (8.0.0.alpha)
9
- activemodel (= 8.0.0.alpha)
10
- activesupport (= 8.0.0.alpha)
6
+ activemodel (8.1.0.alpha)
7
+ activesupport (= 8.1.0.alpha)
8
+ activerecord (8.1.0.alpha)
9
+ activemodel (= 8.1.0.alpha)
10
+ activesupport (= 8.1.0.alpha)
11
11
  timeout (>= 0.4.0)
12
- activesupport (8.0.0.alpha)
12
+ activesupport (8.1.0.alpha)
13
13
  base64
14
+ benchmark (>= 0.3)
14
15
  bigdecimal
15
16
  concurrent-ruby (~> 1.0, >= 1.3.1)
16
17
  connection_pool (>= 2.2.5)
@@ -20,11 +21,12 @@ GIT
20
21
  minitest (>= 5.1)
21
22
  securerandom (>= 0.3)
22
23
  tzinfo (~> 2.0, >= 2.0.5)
24
+ uri (>= 0.13.1)
23
25
 
24
26
  PATH
25
27
  remote: ..
26
28
  specs:
27
- lhm-shopify (4.4.2)
29
+ lhm-shopify (4.5.0)
28
30
  retriable (>= 3.0.0)
29
31
 
30
32
  GEM
@@ -36,38 +38,42 @@ GEM
36
38
  rake
37
39
  thor (>= 0.14.0)
38
40
  base64 (0.2.0)
39
- bigdecimal (3.1.8)
41
+ benchmark (0.4.0)
42
+ bigdecimal (3.1.9)
40
43
  byebug (11.1.3)
41
- concurrent-ruby (1.3.3)
42
- connection_pool (2.4.1)
44
+ concurrent-ruby (1.3.5)
45
+ connection_pool (2.5.0)
43
46
  docile (1.4.1)
44
47
  drb (2.2.1)
45
- i18n (1.14.5)
48
+ i18n (1.14.7)
46
49
  concurrent-ruby (~> 1.0)
47
- logger (1.6.0)
48
- minitest (5.24.1)
50
+ logger (1.6.5)
51
+ minitest (5.25.4)
49
52
  mocha (2.4.5)
50
53
  ruby2_keywords (>= 0.0.5)
51
54
  mysql2 (0.5.6)
55
+ ostruct (0.6.1)
52
56
  rake (13.2.1)
53
57
  retriable (3.1.2)
54
58
  ruby2_keywords (0.0.5)
55
- securerandom (0.3.1)
59
+ securerandom (0.4.1)
56
60
  simplecov (0.22.0)
57
61
  docile (~> 1.1)
58
62
  simplecov-html (~> 0.11)
59
63
  simplecov_json_formatter (~> 0.1)
60
64
  simplecov-html (0.12.3)
61
65
  simplecov_json_formatter (0.1.4)
62
- thor (1.3.1)
63
- timeout (0.4.1)
66
+ thor (1.3.2)
67
+ timeout (0.4.3)
64
68
  toxiproxy (2.0.2)
65
- trilogy (2.8.1)
69
+ trilogy (2.9.0)
66
70
  tzinfo (2.0.6)
67
71
  concurrent-ruby (~> 1.0)
72
+ uri (1.0.2)
68
73
 
69
74
  PLATFORMS
70
75
  arm64-darwin-22
76
+ arm64-darwin-23
71
77
  x86_64-linux
72
78
 
73
79
  DEPENDENCIES
@@ -76,13 +82,15 @@ DEPENDENCIES
76
82
  appraisal
77
83
  byebug
78
84
  lhm-shopify!
85
+ logger
79
86
  minitest
80
87
  mocha
81
88
  mysql2
89
+ ostruct
82
90
  rake
83
91
  simplecov
84
92
  toxiproxy
85
93
  trilogy
86
94
 
87
95
  BUNDLED WITH
88
- 2.2.22
96
+ 2.6.3
data/lhm.gemspec CHANGED
@@ -36,4 +36,6 @@ Gem::Specification.new do |s|
36
36
  s.add_development_dependency 'toxiproxy'
37
37
  s.add_development_dependency 'appraisal'
38
38
  s.add_development_dependency 'byebug'
39
+ s.add_development_dependency 'ostruct'
40
+ s.add_development_dependency 'logger'
39
41
  end
@@ -4,10 +4,11 @@
4
4
  module Lhm
5
5
  # Determine and format columns common to origin and destination.
6
6
  class Intersection
7
- def initialize(origin, destination, renames = {})
7
+ def initialize(origin, destination, renames = {}, generated_column_names = [])
8
8
  @origin = origin
9
9
  @destination = destination
10
10
  @renames = renames
11
+ @generated_column_names = generated_column_names
11
12
  end
12
13
 
13
14
  def origin
@@ -21,7 +22,7 @@ module Lhm
21
22
  private
22
23
 
23
24
  def common
24
- (@origin.columns.keys & @destination.columns.keys).sort
25
+ ((@origin.columns.keys & @destination.columns.keys) - @generated_column_names).sort
25
26
  end
26
27
 
27
28
  module Joiners
data/lib/lhm/invoker.rb CHANGED
@@ -21,9 +21,11 @@ module Lhm
21
21
 
22
22
  attr_reader :migrator, :connection
23
23
 
24
- def initialize(origin, connection)
24
+ def initialize(origin, connection, options = {})
25
25
  @connection = connection
26
- @migrator = Migrator.new(origin, connection)
26
+ @migrator = Migrator.new(origin, connection, options)
27
+ @options = options
28
+ normalize_options(@options)
27
29
  end
28
30
 
29
31
  def set_session_lock_wait_timeouts
@@ -45,17 +47,16 @@ module Lhm
45
47
  end
46
48
  end
47
49
 
48
- def run(options = {})
49
- normalize_options(options)
50
+ def run
50
51
  set_session_lock_wait_timeouts
51
52
  migration = @migrator.run
52
53
  entangler = Entangler.new(migration, @connection)
53
54
 
54
55
  entangler.run do
55
- options[:verifier] ||= Proc.new { |conn| triggers_still_exist?(conn, entangler) }
56
- Chunker.new(migration, @connection, options).run
56
+ @options[:verifier] ||= Proc.new { |conn| triggers_still_exist?(conn, entangler) }
57
+ Chunker.new(migration, @connection, @options).run
57
58
  raise "Required triggers do not exist" unless triggers_still_exist?(@connection, entangler)
58
- if options[:atomic_switch]
59
+ if @options[:atomic_switch]
59
60
  AtomicSwitcher.new(migration, @connection).run
60
61
  else
61
62
  LockedSwitcher.new(migration, @connection).run
data/lib/lhm/migration.rb CHANGED
@@ -8,12 +8,13 @@ module Lhm
8
8
  class Migration
9
9
  attr_reader :origin, :destination, :conditions, :renames
10
10
 
11
- def initialize(origin, destination, conditions = nil, renames = {}, time = Time.now)
11
+ def initialize(origin, destination, conditions = nil, renames = {}, time = Time.now, generated_column_names = [])
12
12
  @origin = origin
13
13
  @destination = destination
14
14
  @conditions = conditions
15
15
  @renames = renames
16
16
  @table_name = TableName.new(@origin.name, time)
17
+ @generated_column_names = generated_column_names
17
18
  end
18
19
 
19
20
  def archive_name
@@ -21,7 +22,7 @@ module Lhm
21
22
  end
22
23
 
23
24
  def intersection
24
- Intersection.new(@origin, @destination, @renames)
25
+ Intersection.new(@origin, @destination, @renames, @generated_column_names)
25
26
  end
26
27
 
27
28
  def origin_name
data/lib/lhm/migrator.rb CHANGED
@@ -15,12 +15,13 @@ module Lhm
15
15
 
16
16
  attr_reader :name, :statements, :connection, :conditions, :renames, :origin
17
17
 
18
- def initialize(table, connection = nil)
18
+ def initialize(table, connection = nil, options = {})
19
19
  @connection = connection
20
20
  @origin = table
21
21
  @name = table.destination_name
22
22
  @statements = []
23
23
  @renames = {}
24
+ @options = options
24
25
  end
25
26
 
26
27
  # Alter a table with a custom statement
@@ -55,7 +56,7 @@ module Lhm
55
56
  # @param [String] name Name of the column to add
56
57
  # @param [String] definition Valid SQL column definition
57
58
  # @param [String] algorithm Algorithm that will be used in the DDL operation
58
- def add_column(name, definition, algorithm: 'INPLACE')
59
+ def add_column(name, definition, algorithm: 'COPY')
59
60
  ddl('alter table `%s` add column `%s` %s' % [@name, name, definition], algorithm:)
60
61
  end
61
62
 
@@ -88,7 +89,7 @@ module Lhm
88
89
  # @param [String] old Name of the column to change
89
90
  # @param [String] nu New name to use for the column
90
91
  # @param [String] algorithm Algorithm that will be used in the DDL operation
91
- def rename_column(old, nu, algorithm: 'INPLACE')
92
+ def rename_column(old, nu, algorithm: 'COPY')
92
93
  col = @origin.columns[old.to_s]
93
94
 
94
95
  definition = col[:type]
@@ -112,7 +113,7 @@ module Lhm
112
113
  #
113
114
  # @param [String] name Name of the column to delete
114
115
  # @param [String] algorithm Algorithm that will be used in the DDL operation
115
- def remove_column(name, algorithm: 'INPLACE')
116
+ def remove_column(name, algorithm: 'COPY')
116
117
  ddl('alter table `%s` drop `%s`' % [@name, name], algorithm:)
117
118
  end
118
119
 
@@ -215,13 +216,22 @@ module Lhm
215
216
  @statements.each do |stmt|
216
217
  @connection.execute(tagged(stmt))
217
218
  end
218
- Migration.new(@origin, destination_read, conditions, renames)
219
+ Migration.new(@origin, destination_read, conditions, renames, Time.now, generated_column_names)
220
+ end
221
+
222
+ def generated_column_names
223
+ @connection.columns(@origin.name).select(&:virtual?).map(&:name)
219
224
  end
220
225
 
221
226
  def destination_create
222
227
  original = %{CREATE TABLE `#{ @origin.name }`}
223
228
  replacement = %{CREATE TABLE `#{ @origin.destination_name }`}
224
229
  stmt = @origin.ddl.gsub(original, replacement)
230
+
231
+ if @options[:force_default_engine]
232
+ stmt = stmt.sub(/ENGINE=\w+\s/, "")
233
+ end
234
+
225
235
  @connection.execute(tagged(stmt))
226
236
 
227
237
  Lhm.logger.info("Created destination table #{@origin.destination_name}")
data/lib/lhm/sql_retry.rb CHANGED
@@ -199,6 +199,7 @@ module Lhm
199
199
  /The MySQL server is running with the --read-only option so it cannot execute this statement/,
200
200
  ],
201
201
  Trilogy::ConnectionError => nil,
202
+ Trilogy::TimeoutError => nil,
202
203
  }
203
204
 
204
205
  if ActiveRecord::VERSION::STRING >= "7.1"
@@ -134,7 +134,7 @@ module Lhm
134
134
  raise ArgumentError, "Expected #{config_proc.inspect} to respond to `call`"
135
135
  end
136
136
  else
137
- db_config
137
+ ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
138
138
  end
139
139
  config.deep_symbolize_keys!
140
140
  config[:host] = @host
@@ -147,23 +147,6 @@ module Lhm
147
147
  Lhm.logger.info "Unable to connect and/or query #{host}: #{e}"
148
148
  [nil]
149
149
  end
150
-
151
- private
152
-
153
- def db_config
154
- if ar_supports_db_config?
155
- ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
156
- else
157
- ActiveRecord::Base.connection_pool.spec.config.dup
158
- end
159
- end
160
-
161
- def ar_supports_db_config?
162
- # https://api.rubyonrails.org/v6.0/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has spec
163
- # vs
164
- # https://api.rubyonrails.org/v6.1/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html <-- has db_config
165
- ActiveRecord::VERSION::MAJOR > 6 || ActiveRecord::VERSION::MAJOR == 6 && ActiveRecord::VERSION::MINOR >= 1
166
- end
167
150
  end
168
151
  end
169
152
  end
data/lib/lhm/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Schmidt
3
3
 
4
4
  module Lhm
5
- VERSION = '4.4.2'
5
+ VERSION = '4.5.0'
6
6
  end
data/lib/lhm.rb CHANGED
@@ -54,9 +54,9 @@ module Lhm
54
54
  def change_table(table_name, options = {}, &block)
55
55
  with_flags(options) do
56
56
  origin = Table.parse(table_name, connection)
57
- invoker = Invoker.new(origin, connection)
57
+ invoker = Invoker.new(origin, connection, options)
58
58
  block.call(invoker.migrator)
59
- invoker.run(options)
59
+ invoker.run
60
60
  true
61
61
  end
62
62
  end
@@ -0,0 +1,10 @@
1
+ CREATE TABLE `myisam_users` (
2
+ `id` int(11) NOT NULL AUTO_INCREMENT,
3
+ `reference` int(11) DEFAULT NULL,
4
+ `username` varchar(255) DEFAULT NULL,
5
+ `group` varchar(255) DEFAULT 'Superfriends',
6
+ `created_at` datetime DEFAULT NULL,
7
+ `comment` varchar(20) DEFAULT NULL,
8
+ `description` text,
9
+ PRIMARY KEY (`id`)
10
+ ) ENGINE=MyISAM CHARSET=utf8
@@ -531,6 +531,61 @@ describe Lhm do
531
531
  end
532
532
  end
533
533
 
534
+ it 'works when table has generated columns' do
535
+ table_create(:users)
536
+ execute("insert into `users` set id = 1, `username` = 'memyself'")
537
+ execute("insert into `users` set id = 2, `username` = 'youyourself'")
538
+
539
+ # Add a generated column
540
+ Lhm.change_table(:users) do |t|
541
+ t.add_column(:sample_generated_column, 'VARCHAR(255) GENERATED ALWAYS AS (SUBSTRING(`username`, -2))')
542
+ end
543
+
544
+ # Without the handling of generated columns
545
+ Lhm::Migrator.any_instance.stubs(:generated_column_names).returns([])
546
+ # without the Migration passing in generated columns to Intersection, we observe an error as an attempt to write
547
+ # directly into generated columns will fail.
548
+ exception = assert_raises ActiveRecord::StatementInvalid do
549
+ Lhm.change_table(:users) do |t|
550
+ t.add_column(:sample_additional_column, "VARCHAR(255)")
551
+ end
552
+ end
553
+ assert_match "The value specified for generated column 'sample_generated_column' in table 'lhmn_users' is not allowed.", exception.message
554
+
555
+ Lhm.cleanup(true)
556
+
557
+ # With the handling of generated columns
558
+ Lhm::Migrator.any_instance.unstub(:generated_column_names)
559
+ # As we are now skipping the writing to generated columns, this migration should succeed
560
+ Lhm.change_table(:users) do |t|
561
+ t.add_column(:sample_additional_column, "VARCHAR(255)")
562
+ end
563
+
564
+ replica do
565
+ # new column is added
566
+ value(table_read(:users).columns['sample_additional_column']).must_equal({
567
+ :type => 'varchar(255)',
568
+ :is_nullable => 'YES',
569
+ :column_default => nil,
570
+ :comment => '',
571
+ :collate => collation,
572
+ })
573
+
574
+ # generated column remains intact
575
+ value(table_read(:users).columns['sample_generated_column']).must_equal({
576
+ :type => 'varchar(255)',
577
+ :is_nullable => 'YES',
578
+ :column_default => nil,
579
+ :comment => '',
580
+ :collate => collation,
581
+ })
582
+ end
583
+
584
+ result = select_one('SELECT sample_generated_column FROM users')
585
+ # generated column populated appropriately
586
+ assert_match "lf", result["sample_generated_column"]
587
+ end
588
+
534
589
  it 'works when mysql reserved words are used' do
535
590
  table_create(:lines)
536
591
  execute("insert into `lines` set id = 1, `between` = 'foo'")
@@ -553,6 +608,39 @@ describe Lhm do
553
608
  end
554
609
  end
555
610
 
611
+ it 'creates the shadow table with the default engine when the `force_default_engine` option is used' do
612
+ table_create(:myisam_users)
613
+
614
+ engine = select_value("SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_NAME = 'myisam_users'")
615
+ value(engine).must_equal("MyISAM")
616
+
617
+ Lhm.change_table(:myisam_users) do |t|
618
+ t.add_column(:logins, "INT(12) DEFAULT '0'", algorithm: "COPY")
619
+ end
620
+
621
+ engine = select_value("SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_NAME = 'myisam_users'")
622
+ value(engine).must_equal("MyISAM")
623
+
624
+ Lhm.change_table(:myisam_users, force_default_engine: true) do |t|
625
+ t.remove_column(:logins)
626
+ end
627
+
628
+ engine = select_value("SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_NAME = 'myisam_users'")
629
+ value(engine).must_equal("InnoDB")
630
+ end
631
+
632
+ it "should not fail using the default algorithms when changing tables with fulltext indexes" do
633
+ table_create(:users)
634
+ execute("DROP INDEX `index_with_a_custom_name` ON `users`")
635
+ execute("CREATE FULLTEXT INDEX `index_with_a_custom_name` ON `users` (`username`, `group`)")
636
+
637
+ Lhm.change_table(:users) do |t|
638
+ t.add_column(:email, "VARCHAR(255)")
639
+ end
640
+
641
+ value(table_read(:users).columns).must_include("email")
642
+ end
643
+
556
644
  describe 'parallel' do
557
645
  it 'should perserve inserts during migration' do
558
646
  50.times { |n| execute("insert into users set reference = '#{ n }'") }
@@ -616,7 +704,13 @@ describe Lhm do
616
704
  table_create(:users)
617
705
  100.times { |n| execute("insert into users set reference = '#{ n }'") }
618
706
 
619
- assert_raises ActiveRecord::StatementInvalid do
707
+ error = if ActiveRecord.version >= ::Gem::Version.new('8.1.0.alpha')
708
+ ActiveRecord::ConnectionNotEstablished
709
+ else
710
+ ActiveRecord::StatementInvalid
711
+ end
712
+
713
+ assert_raises error do
620
714
  Toxiproxy[:mysql_master].down do
621
715
  Lhm.change_table(:users, :atomic_switch => false) do |t|
622
716
  t.ddl("ALTER TABLE #{t.name} CHANGE id id bigint (20) NOT NULL")
@@ -20,7 +20,7 @@ class DBConnectionHelper
20
20
  :database => test_db_name,
21
21
  :port => db_config[key]['port']
22
22
  )
23
- conn = conn.connection
23
+ conn = conn.respond_to?(:lease_connection) ? conn.lease_connection : conn.connection
24
24
  init_with_dummy_data(conn) if with_data
25
25
  conn
26
26
  end
@@ -81,10 +81,12 @@ describe Lhm::SqlRetry do
81
81
  logs = @logger.string.split("\n")
82
82
  assert_equal 2, logs.length
83
83
 
84
- assert logs.first.include?("Lock wait timeout exceeded; try restarting transaction' - 1 tries")
84
+ assert logs.first.include?("Lock wait timeout exceeded; try restarting transaction")
85
+ assert logs.first.include?("- 1 tries")
85
86
  assert logs.first.include?("0.2 seconds until the next try")
86
87
 
87
- assert logs.last.include?("Lock wait timeout exceeded; try restarting transaction' - 2 tries")
88
+ assert logs.last.include?("Lock wait timeout exceeded; try restarting transaction")
89
+ assert logs.last.include?("- 2 tries")
88
90
  assert logs.last.include?("0.2 seconds until the next try")
89
91
  end
90
92
 
@@ -97,7 +97,7 @@ describe Lhm::Migrator do
97
97
  @creator.add_column('logins', 'INT(12)')
98
98
 
99
99
  value(@creator.statements).must_equal([
100
- 'alter table `lhmn_alt` add column `logins` INT(12), ALGORITHM=INPLACE'
100
+ 'alter table `lhmn_alt` add column `logins` INT(12), ALGORITHM=COPY'
101
101
  ])
102
102
  end
103
103
 
@@ -113,7 +113,7 @@ describe Lhm::Migrator do
113
113
  @creator.remove_column('logins')
114
114
 
115
115
  value(@creator.statements).must_equal([
116
- 'alter table `lhmn_alt` drop `logins`, ALGORITHM=INPLACE'
116
+ 'alter table `lhmn_alt` drop `logins`, ALGORITHM=COPY'
117
117
  ])
118
118
  end
119
119
 
@@ -167,24 +167,24 @@ describe Lhm::Migrator do
167
167
  value(@creator.statements.length).must_equal(2)
168
168
 
169
169
  value(@creator.statements[0])
170
- .must_equal('alter table `lhmn_alt` add column `first` VARCHAR(64), ALGORITHM=INPLACE')
170
+ .must_equal('alter table `lhmn_alt` add column `first` VARCHAR(64), ALGORITHM=COPY')
171
171
 
172
172
  value(@creator.statements[1])
173
- .must_equal('alter table `lhmn_alt` add column `last` VARCHAR(64), ALGORITHM=INPLACE')
173
+ .must_equal('alter table `lhmn_alt` add column `last` VARCHAR(64), ALGORITHM=COPY')
174
174
  end
175
175
  end
176
176
 
177
177
  describe 'multiple changes using the passed algorithm' do
178
178
  it 'should add two columns' do
179
- @creator.add_column('first', 'VARCHAR(64)', algorithm: 'COPY')
180
- @creator.add_column('last', 'VARCHAR(64)', algorithm: 'COPY')
179
+ @creator.add_column('first', 'VARCHAR(64)', algorithm: 'INPLACE')
180
+ @creator.add_column('last', 'VARCHAR(64)', algorithm: 'INPLACE')
181
181
  value(@creator.statements.length).must_equal(2)
182
182
 
183
183
  value(@creator.statements[0])
184
- .must_equal('alter table `lhmn_alt` add column `first` VARCHAR(64), ALGORITHM=COPY')
184
+ .must_equal('alter table `lhmn_alt` add column `first` VARCHAR(64), ALGORITHM=INPLACE')
185
185
 
186
186
  value(@creator.statements[1])
187
- .must_equal('alter table `lhmn_alt` add column `last` VARCHAR(64), ALGORITHM=COPY')
187
+ .must_equal('alter table `lhmn_alt` add column `last` VARCHAR(64), ALGORITHM=INPLACE')
188
188
  end
189
189
  end
190
190
  end
@@ -66,11 +66,7 @@ describe Lhm::Throttler::Replica do
66
66
  describe 'with active record config' do
67
67
  it 'logs and creates client' do
68
68
  active_record_config = { username: 'user', password: 'pw', database: 'db' }
69
- if ActiveRecord::VERSION::MAJOR > 6 || ActiveRecord::VERSION::MAJOR == 6 && ActiveRecord::VERSION::MINOR >= 1
70
- ActiveRecord::Base.stubs(:connection_pool).returns(stub(db_config: stub(configuration_hash: active_record_config)))
71
- else
72
- ActiveRecord::Base.stubs(:connection_pool).returns(stub(spec: stub(config: active_record_config)))
73
- end
69
+ ActiveRecord::Base.stubs(:connection_pool).returns(stub(db_config: stub(configuration_hash: active_record_config)))
74
70
 
75
71
  DATABASE.client.stubs(:new).returns(mock())
76
72
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lhm-shopify
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.2
4
+ version: 4.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SoundCloud
@@ -9,10 +9,9 @@ authors:
9
9
  - Rany Keddo
10
10
  - Tobias Bielohlawek
11
11
  - Tobias Schmidt
12
- autorequire:
13
12
  bindir: bin
14
13
  cert_chain: []
15
- date: 2024-09-09 00:00:00.000000000 Z
14
+ date: 2025-02-07 00:00:00.000000000 Z
16
15
  dependencies:
17
16
  - !ruby/object:Gem::Dependency
18
17
  name: retriable
@@ -182,6 +181,34 @@ dependencies:
182
181
  - - ">="
183
182
  - !ruby/object:Gem::Version
184
183
  version: '0'
184
+ - !ruby/object:Gem::Dependency
185
+ name: ostruct
186
+ requirement: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ type: :development
192
+ prerelease: false
193
+ version_requirements: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - ">="
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ - !ruby/object:Gem::Dependency
199
+ name: logger
200
+ requirement: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: '0'
205
+ type: :development
206
+ prerelease: false
207
+ version_requirements: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
185
212
  description: Migrate large tables without downtime by copying to a temporary table
186
213
  in chunks. The old table is not dropped. Instead, it is moved to timestamp_table_name
187
214
  for verification.
@@ -206,12 +233,10 @@ files:
206
233
  - docker-compose-mysql-5.7.yml
207
234
  - docker-compose-mysql-8.0.yml
208
235
  - docker-compose.yml
209
- - gemfiles/activerecord_6.1.gemfile
210
- - gemfiles/activerecord_6.1.gemfile.lock
211
- - gemfiles/activerecord_7.0.gemfile
212
- - gemfiles/activerecord_7.0.gemfile.lock
213
- - gemfiles/activerecord_7.1.gemfile
214
- - gemfiles/activerecord_7.1.gemfile.lock
236
+ - gemfiles/activerecord_7.2.gemfile
237
+ - gemfiles/activerecord_7.2.gemfile.lock
238
+ - gemfiles/activerecord_8.0.gemfile
239
+ - gemfiles/activerecord_8.0.gemfile.lock
215
240
  - gemfiles/activerecord_head.gemfile
216
241
  - gemfiles/activerecord_head.gemfile.lock
217
242
  - lhm.gemspec
@@ -263,6 +288,7 @@ files:
263
288
  - spec/fixtures/custom_primary_key_dest.ddl
264
289
  - spec/fixtures/destination.ddl
265
290
  - spec/fixtures/lines.ddl
291
+ - spec/fixtures/myisam_users.ddl
266
292
  - spec/fixtures/origin.ddl
267
293
  - spec/fixtures/permissions.ddl
268
294
  - spec/fixtures/small_table.ddl
@@ -312,7 +338,6 @@ licenses:
312
338
  - BSD-3-Clause
313
339
  metadata:
314
340
  allowed_push_host: https://rubygems.org
315
- post_install_message:
316
341
  rdoc_options: []
317
342
  require_paths:
318
343
  - lib
@@ -327,8 +352,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
327
352
  - !ruby/object:Gem::Version
328
353
  version: '0'
329
354
  requirements: []
330
- rubygems_version: 3.5.18
331
- signing_key:
355
+ rubygems_version: 3.6.3
332
356
  specification_version: 4
333
357
  summary: online schema changer for mysql
334
358
  test_files: []
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "7.0.8"
6
- gem "activerecord-trilogy-adapter"
7
-
8
- gemspec path: "../"
@@ -1,74 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- lhm-shopify (4.4.2)
5
- retriable (>= 3.0.0)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activemodel (7.0.8)
11
- activesupport (= 7.0.8)
12
- activerecord (7.0.8)
13
- activemodel (= 7.0.8)
14
- activesupport (= 7.0.8)
15
- activerecord-trilogy-adapter (3.1.2)
16
- activerecord (>= 6.0.a, < 7.1.a)
17
- trilogy (>= 2.4.0)
18
- activesupport (7.0.8)
19
- concurrent-ruby (~> 1.0, >= 1.0.2)
20
- i18n (>= 1.6, < 2)
21
- minitest (>= 5.1)
22
- tzinfo (~> 2.0)
23
- after_do (0.4.0)
24
- appraisal (2.5.0)
25
- bundler
26
- rake
27
- thor (>= 0.14.0)
28
- byebug (11.1.3)
29
- concurrent-ruby (1.2.2)
30
- docile (1.4.0)
31
- i18n (1.14.1)
32
- concurrent-ruby (~> 1.0)
33
- minitest (5.22.2)
34
- mocha (2.1.0)
35
- ruby2_keywords (>= 0.0.5)
36
- mysql2 (0.5.5)
37
- rake (13.0.6)
38
- retriable (3.1.2)
39
- ruby2_keywords (0.0.5)
40
- simplecov (0.22.0)
41
- docile (~> 1.1)
42
- simplecov-html (~> 0.11)
43
- simplecov_json_formatter (~> 0.1)
44
- simplecov-html (0.12.3)
45
- simplecov_json_formatter (0.1.4)
46
- thor (1.2.2)
47
- toxiproxy (2.0.2)
48
- trilogy (2.6.0)
49
- tzinfo (2.0.6)
50
- concurrent-ruby (~> 1.0)
51
-
52
- PLATFORMS
53
- arm64-darwin-21
54
- arm64-darwin-22
55
- x86_64-darwin-20
56
- x86_64-linux
57
-
58
- DEPENDENCIES
59
- activerecord (= 7.0.8)
60
- activerecord-trilogy-adapter
61
- after_do
62
- appraisal
63
- byebug
64
- lhm-shopify!
65
- minitest
66
- mocha
67
- mysql2
68
- rake
69
- simplecov
70
- toxiproxy
71
- trilogy
72
-
73
- BUNDLED WITH
74
- 2.2.22