pg_easy_replicate 0.2.0 → 0.2.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/CHANGELOG.md +9 -0
 - data/Gemfile.lock +17 -17
 - data/lib/pg_easy_replicate/cli.rb +10 -0
 - data/lib/pg_easy_replicate/helper.rb +27 -0
 - data/lib/pg_easy_replicate/index_manager.rb +4 -3
 - data/lib/pg_easy_replicate/orchestrate.rb +28 -57
 - data/lib/pg_easy_replicate/version.rb +1 -1
 - data/lib/pg_easy_replicate.rb +79 -3
 - metadata +4 -4
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: efcbf369a4410abd783ea1dba49ead97fa471705842df4a35d28864349b1c70c
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 676d97aa0c551dd0f9d58c3bccb229951bcb2dfc34653995375c359718bc1d7f
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 774ef530f4be4b409fdf2d4956a44deb09aebf59c8ef480074d426ca4c72006673c7a6915d860e61846fb00df8e14fa9534e920f5802873ed727e37564197b25
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 50055941c3a83351b22ceaeb539b807a7cec5e3130732944c63e8a5440a7707a273a546681b1d581d4f79d9fba616998fc48cffc009e401bfc570e76e27064f0
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,3 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ## [0.2.1] - 2023-12-29
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            - Don't attempt to drop and recreate unique indices - #88
         
     | 
| 
      
 4 
     | 
    
         
            +
            - Dependency updates
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ## [0.2.0] - 2023-12-29
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            - Recreate indices post COPY, once all tables are in replicating mode - #81
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
       1 
10 
     | 
    
         
             
            ## [0.1.12] - 2023-12-13
         
     | 
| 
       2 
11 
     | 
    
         | 
| 
       3 
12 
     | 
    
         
             
            - Bump rubocop-rspec from 2.24.1 to 2.25.0 - #65
         
     | 
    
        data/Gemfile.lock
    CHANGED
    
    | 
         @@ -1,31 +1,31 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            PATH
         
     | 
| 
       2 
2 
     | 
    
         
             
              remote: .
         
     | 
| 
       3 
3 
     | 
    
         
             
              specs:
         
     | 
| 
       4 
     | 
    
         
            -
                pg_easy_replicate (0.2. 
     | 
| 
      
 4 
     | 
    
         
            +
                pg_easy_replicate (0.2.2)
         
     | 
| 
       5 
5 
     | 
    
         
             
                  ougai (~> 2.0.0)
         
     | 
| 
       6 
6 
     | 
    
         
             
                  pg (~> 1.5.3)
         
     | 
| 
       7 
     | 
    
         
            -
                  sequel (>= 5.69, < 5. 
     | 
| 
      
 7 
     | 
    
         
            +
                  sequel (>= 5.69, < 5.77)
         
     | 
| 
       8 
8 
     | 
    
         
             
                  thor (>= 1.2.2, < 1.4.0)
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            GEM
         
     | 
| 
       11 
11 
     | 
    
         
             
              remote: https://rubygems.org/
         
     | 
| 
       12 
12 
     | 
    
         
             
              specs:
         
     | 
| 
       13 
13 
     | 
    
         
             
                ast (2.4.2)
         
     | 
| 
       14 
     | 
    
         
            -
                bigdecimal (3.1. 
     | 
| 
      
 14 
     | 
    
         
            +
                bigdecimal (3.1.5)
         
     | 
| 
       15 
15 
     | 
    
         
             
                coderay (1.1.3)
         
     | 
| 
       16 
16 
     | 
    
         
             
                diff-lcs (1.5.0)
         
     | 
| 
       17 
17 
     | 
    
         
             
                haml (6.1.1)
         
     | 
| 
       18 
18 
     | 
    
         
             
                  temple (>= 0.8.2)
         
     | 
| 
       19 
19 
     | 
    
         
             
                  thor
         
     | 
| 
       20 
20 
     | 
    
         
             
                  tilt
         
     | 
| 
       21 
     | 
    
         
            -
                json (2.7. 
     | 
| 
      
 21 
     | 
    
         
            +
                json (2.7.1)
         
     | 
| 
       22 
22 
     | 
    
         
             
                language_server-protocol (3.17.0.3)
         
     | 
| 
       23 
23 
     | 
    
         
             
                method_source (1.0.0)
         
     | 
| 
       24 
24 
     | 
    
         
             
                oj (3.14.3)
         
     | 
| 
       25 
25 
     | 
    
         
             
                ougai (2.0.0)
         
     | 
| 
       26 
26 
     | 
    
         
             
                  oj (~> 3.10)
         
     | 
| 
       27 
     | 
    
         
            -
                parallel (1. 
     | 
| 
       28 
     | 
    
         
            -
                parser (3. 
     | 
| 
      
 27 
     | 
    
         
            +
                parallel (1.24.0)
         
     | 
| 
      
 28 
     | 
    
         
            +
                parser (3.3.0.4)
         
     | 
| 
       29 
29 
     | 
    
         
             
                  ast (~> 2.4.1)
         
     | 
| 
       30 
30 
     | 
    
         
             
                  racc
         
     | 
| 
       31 
31 
     | 
    
         
             
                pg (1.5.4)
         
     | 
| 
         @@ -37,7 +37,7 @@ GEM 
     | 
|
| 
       37 
37 
     | 
    
         
             
                rainbow (3.1.1)
         
     | 
| 
       38 
38 
     | 
    
         
             
                rake (13.1.0)
         
     | 
| 
       39 
39 
     | 
    
         
             
                rbs (3.1.0)
         
     | 
| 
       40 
     | 
    
         
            -
                regexp_parser (2. 
     | 
| 
      
 40 
     | 
    
         
            +
                regexp_parser (2.9.0)
         
     | 
| 
       41 
41 
     | 
    
         
             
                rexml (3.2.6)
         
     | 
| 
       42 
42 
     | 
    
         
             
                rspec (3.12.0)
         
     | 
| 
       43 
43 
     | 
    
         
             
                  rspec-core (~> 3.12.0)
         
     | 
| 
         @@ -52,11 +52,11 @@ GEM 
     | 
|
| 
       52 
52 
     | 
    
         
             
                  diff-lcs (>= 1.2.0, < 2.0)
         
     | 
| 
       53 
53 
     | 
    
         
             
                  rspec-support (~> 3.12.0)
         
     | 
| 
       54 
54 
     | 
    
         
             
                rspec-support (3.12.0)
         
     | 
| 
       55 
     | 
    
         
            -
                rubocop (1. 
     | 
| 
      
 55 
     | 
    
         
            +
                rubocop (1.60.1)
         
     | 
| 
       56 
56 
     | 
    
         
             
                  json (~> 2.3)
         
     | 
| 
       57 
57 
     | 
    
         
             
                  language_server-protocol (>= 3.17.0)
         
     | 
| 
       58 
58 
     | 
    
         
             
                  parallel (~> 1.10)
         
     | 
| 
       59 
     | 
    
         
            -
                  parser (>= 3. 
     | 
| 
      
 59 
     | 
    
         
            +
                  parser (>= 3.3.0.2)
         
     | 
| 
       60 
60 
     | 
    
         
             
                  rainbow (>= 2.2.2, < 4.0)
         
     | 
| 
       61 
61 
     | 
    
         
             
                  regexp_parser (>= 1.8, < 3.0)
         
     | 
| 
       62 
62 
     | 
    
         
             
                  rexml (>= 3.2.5, < 4.0)
         
     | 
| 
         @@ -65,23 +65,23 @@ GEM 
     | 
|
| 
       65 
65 
     | 
    
         
             
                  unicode-display_width (>= 2.4.0, < 3.0)
         
     | 
| 
       66 
66 
     | 
    
         
             
                rubocop-ast (1.30.0)
         
     | 
| 
       67 
67 
     | 
    
         
             
                  parser (>= 3.2.1.0)
         
     | 
| 
       68 
     | 
    
         
            -
                rubocop-capybara (2. 
     | 
| 
      
 68 
     | 
    
         
            +
                rubocop-capybara (2.20.0)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  rubocop (~> 1.41)
         
     | 
| 
      
 70 
     | 
    
         
            +
                rubocop-factory_bot (2.25.1)
         
     | 
| 
       69 
71 
     | 
    
         
             
                  rubocop (~> 1.41)
         
     | 
| 
       70 
     | 
    
         
            -
                rubocop-factory_bot (2.24.0)
         
     | 
| 
       71 
     | 
    
         
            -
                  rubocop (~> 1.33)
         
     | 
| 
       72 
72 
     | 
    
         
             
                rubocop-packaging (0.5.2)
         
     | 
| 
       73 
73 
     | 
    
         
             
                  rubocop (>= 1.33, < 2.0)
         
     | 
| 
       74 
     | 
    
         
            -
                rubocop-performance (1. 
     | 
| 
       75 
     | 
    
         
            -
                  rubocop (>= 1. 
     | 
| 
       76 
     | 
    
         
            -
                  rubocop-ast (>=  
     | 
| 
      
 74 
     | 
    
         
            +
                rubocop-performance (1.20.2)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  rubocop (>= 1.48.1, < 2.0)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  rubocop-ast (>= 1.30.0, < 2.0)
         
     | 
| 
       77 
77 
     | 
    
         
             
                rubocop-rake (0.6.0)
         
     | 
| 
       78 
78 
     | 
    
         
             
                  rubocop (~> 1.0)
         
     | 
| 
       79 
     | 
    
         
            -
                rubocop-rspec (2. 
     | 
| 
      
 79 
     | 
    
         
            +
                rubocop-rspec (2.26.1)
         
     | 
| 
       80 
80 
     | 
    
         
             
                  rubocop (~> 1.40)
         
     | 
| 
       81 
81 
     | 
    
         
             
                  rubocop-capybara (~> 2.17)
         
     | 
| 
       82 
82 
     | 
    
         
             
                  rubocop-factory_bot (~> 2.22)
         
     | 
| 
       83 
83 
     | 
    
         
             
                ruby-progressbar (1.13.0)
         
     | 
| 
       84 
     | 
    
         
            -
                sequel (5. 
     | 
| 
      
 84 
     | 
    
         
            +
                sequel (5.76.0)
         
     | 
| 
       85 
85 
     | 
    
         
             
                  bigdecimal
         
     | 
| 
       86 
86 
     | 
    
         
             
                syntax_tree (6.2.0)
         
     | 
| 
       87 
87 
     | 
    
         
             
                  prettier_print (>= 1.2.0)
         
     | 
| 
         @@ -16,10 +16,20 @@ module PgEasyReplicate 
     | 
|
| 
       16 
16 
     | 
    
         
             
                              aliases: "-c",
         
     | 
| 
       17 
17 
     | 
    
         
             
                              boolean: true,
         
     | 
| 
       18 
18 
     | 
    
         
             
                              desc: "Copy schema to the new database"
         
     | 
| 
      
 19 
     | 
    
         
            +
                method_option :tables,
         
     | 
| 
      
 20 
     | 
    
         
            +
                              aliases: "-t",
         
     | 
| 
      
 21 
     | 
    
         
            +
                              desc:
         
     | 
| 
      
 22 
     | 
    
         
            +
                                "Comma separated list of table names. Default: All tables"
         
     | 
| 
      
 23 
     | 
    
         
            +
                method_option :schema_name,
         
     | 
| 
      
 24 
     | 
    
         
            +
                              aliases: "-s",
         
     | 
| 
      
 25 
     | 
    
         
            +
                              desc:
         
     | 
| 
      
 26 
     | 
    
         
            +
                                "Name of the schema tables are in, only required if passing list of tables"
         
     | 
| 
       19 
27 
     | 
    
         
             
                def config_check
         
     | 
| 
       20 
28 
     | 
    
         
             
                  PgEasyReplicate.assert_config(
         
     | 
| 
       21 
29 
     | 
    
         
             
                    special_user_role: options[:special_user_role],
         
     | 
| 
       22 
30 
     | 
    
         
             
                    copy_schema: options[:copy_schema],
         
     | 
| 
      
 31 
     | 
    
         
            +
                    tables: options[:tables],
         
     | 
| 
      
 32 
     | 
    
         
            +
                    schema_name: options[:schema_name],
         
     | 
| 
       23 
33 
     | 
    
         
             
                  )
         
     | 
| 
       24 
34 
     | 
    
         | 
| 
       25 
35 
     | 
    
         
             
                  puts "✅ Config is looking good."
         
     | 
| 
         @@ -72,5 +72,32 @@ module PgEasyReplicate 
     | 
|
| 
       72 
72 
     | 
    
         
             
                  raise(msg) if test_env?
         
     | 
| 
       73 
73 
     | 
    
         
             
                  abort(msg)
         
     | 
| 
       74 
74 
     | 
    
         
             
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def determine_tables(conn_string:, list: "", schema: nil)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  schema ||= "public"
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  tables = list&.split(",") || []
         
     | 
| 
      
 80 
     | 
    
         
            +
                  if tables.size > 0
         
     | 
| 
      
 81 
     | 
    
         
            +
                    tables
         
     | 
| 
      
 82 
     | 
    
         
            +
                  else
         
     | 
| 
      
 83 
     | 
    
         
            +
                    list_all_tables(schema: schema, conn_string: conn_string)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def list_all_tables(schema:, conn_string:)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  Query
         
     | 
| 
      
 89 
     | 
    
         
            +
                    .run(
         
     | 
| 
      
 90 
     | 
    
         
            +
                      query:
         
     | 
| 
      
 91 
     | 
    
         
            +
                        "SELECT table_name
         
     | 
| 
      
 92 
     | 
    
         
            +
                         FROM information_schema.tables
         
     | 
| 
      
 93 
     | 
    
         
            +
                         WHERE table_schema = '#{schema}' AND
         
     | 
| 
      
 94 
     | 
    
         
            +
                           table_type = 'BASE TABLE'
         
     | 
| 
      
 95 
     | 
    
         
            +
                         ORDER BY table_name",
         
     | 
| 
      
 96 
     | 
    
         
            +
                      connection_url: conn_string,
         
     | 
| 
      
 97 
     | 
    
         
            +
                      user: db_user(conn_string),
         
     | 
| 
      
 98 
     | 
    
         
            +
                    )
         
     | 
| 
      
 99 
     | 
    
         
            +
                    .map(&:values)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    .flatten
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
       75 
102 
     | 
    
         
             
              end
         
     | 
| 
       76 
103 
     | 
    
         
             
            end
         
     | 
| 
         @@ -17,7 +17,7 @@ module PgEasyReplicate 
     | 
|
| 
       17 
17 
     | 
    
         
             
                    tables: tables,
         
     | 
| 
       18 
18 
     | 
    
         
             
                    schema: schema,
         
     | 
| 
       19 
19 
     | 
    
         
             
                  ).each do |index|
         
     | 
| 
       20 
     | 
    
         
            -
                    drop_sql = "DROP INDEX CONCURRENTLY #{index[:index_name]};"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    drop_sql = "DROP INDEX CONCURRENTLY #{schema}.#{index[:index_name]};"
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
                    Query.run(
         
     | 
| 
       23 
23 
     | 
    
         
             
                      query: drop_sql,
         
     | 
| 
         @@ -56,8 +56,8 @@ module PgEasyReplicate 
     | 
|
| 
       56 
56 
     | 
    
         
             
                end
         
     | 
| 
       57 
57 
     | 
    
         | 
| 
       58 
58 
     | 
    
         
             
                def self.fetch_indices(conn_string:, tables:, schema:)
         
     | 
| 
       59 
     | 
    
         
            -
                  return [] if tables. 
     | 
| 
       60 
     | 
    
         
            -
                  table_list = tables. 
     | 
| 
      
 59 
     | 
    
         
            +
                  return [] if tables.empty?
         
     | 
| 
      
 60 
     | 
    
         
            +
                  table_list = tables.map { |table| "'#{table}'" }.join(",")
         
     | 
| 
       61 
61 
     | 
    
         | 
| 
       62 
62 
     | 
    
         
             
                  sql = <<-SQL
         
     | 
| 
       63 
63 
     | 
    
         
             
                    SELECT
         
     | 
| 
         @@ -75,6 +75,7 @@ module PgEasyReplicate 
     | 
|
| 
       75 
75 
     | 
    
         
             
                        AND n.oid = t.relnamespace
         
     | 
| 
       76 
76 
     | 
    
         
             
                        AND t.relkind = 'r'  -- only find indexes of tables
         
     | 
| 
       77 
77 
     | 
    
         
             
                        AND ix.indisprimary = FALSE  -- exclude primary keys
         
     | 
| 
      
 78 
     | 
    
         
            +
                        AND ix.indisunique = FALSE  -- exclude unique indexes
         
     | 
| 
       78 
79 
     | 
    
         
             
                        AND n.nspname = '#{schema}'
         
     | 
| 
       79 
80 
     | 
    
         
             
                        AND t.relname IN (#{table_list})
         
     | 
| 
       80 
81 
     | 
    
         
             
                    ORDER BY
         
     | 
| 
         @@ -46,7 +46,7 @@ module PgEasyReplicate 
     | 
|
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                    Group.create(
         
     | 
| 
       48 
48 
     | 
    
         
             
                      name: options[:group_name],
         
     | 
| 
       49 
     | 
    
         
            -
                      table_names: tables,
         
     | 
| 
      
 49 
     | 
    
         
            +
                      table_names: tables.join(","),
         
     | 
| 
       50 
50 
     | 
    
         
             
                      schema_name: schema_name,
         
     | 
| 
       51 
51 
     | 
    
         
             
                      started_at: Time.now.utc,
         
     | 
| 
       52 
52 
     | 
    
         
             
                      recreate_indices_post_copy: options[:recreate_indices_post_copy],
         
     | 
| 
         @@ -63,7 +63,7 @@ module PgEasyReplicate 
     | 
|
| 
       63 
63 
     | 
    
         
             
                    else
         
     | 
| 
       64 
64 
     | 
    
         
             
                      Group.create(
         
     | 
| 
       65 
65 
     | 
    
         
             
                        name: options[:group_name],
         
     | 
| 
       66 
     | 
    
         
            -
                        table_names: tables,
         
     | 
| 
      
 66 
     | 
    
         
            +
                        table_names: tables.join(","),
         
     | 
| 
       67 
67 
     | 
    
         
             
                        schema_name: schema_name,
         
     | 
| 
       68 
68 
     | 
    
         
             
                        started_at: Time.now.utc,
         
     | 
| 
       69 
69 
     | 
    
         
             
                        failed_at: Time.now.utc,
         
     | 
| 
         @@ -92,42 +92,24 @@ module PgEasyReplicate 
     | 
|
| 
       92 
92 
     | 
    
         
             
                    schema:,
         
     | 
| 
       93 
93 
     | 
    
         
             
                    group_name:,
         
     | 
| 
       94 
94 
     | 
    
         
             
                    conn_string:,
         
     | 
| 
       95 
     | 
    
         
            -
                    tables:  
     | 
| 
      
 95 
     | 
    
         
            +
                    tables: []
         
     | 
| 
       96 
96 
     | 
    
         
             
                  )
         
     | 
| 
       97 
97 
     | 
    
         
             
                    logger.info(
         
     | 
| 
       98 
98 
     | 
    
         
             
                      "Adding tables up publication",
         
     | 
| 
       99 
99 
     | 
    
         
             
                      { publication_name: publication_name(group_name) },
         
     | 
| 
       100 
100 
     | 
    
         
             
                    )
         
     | 
| 
       101 
101 
     | 
    
         | 
| 
       102 
     | 
    
         
            -
                    tables
         
     | 
| 
       103 
     | 
    
         
            -
                      . 
     | 
| 
       104 
     | 
    
         
            -
                      .map do |table_name|
         
     | 
| 
       105 
     | 
    
         
            -
                        Query.run(
         
     | 
| 
       106 
     | 
    
         
            -
                          query:
         
     | 
| 
       107 
     | 
    
         
            -
                            "ALTER PUBLICATION #{quote_ident(publication_name(group_name))}
         
     | 
| 
       108 
     | 
    
         
            -
                                    ADD TABLE #{quote_ident(table_name)}",
         
     | 
| 
       109 
     | 
    
         
            -
                          connection_url: conn_string,
         
     | 
| 
       110 
     | 
    
         
            -
                          schema: schema,
         
     | 
| 
       111 
     | 
    
         
            -
                        )
         
     | 
| 
       112 
     | 
    
         
            -
                      end
         
     | 
| 
       113 
     | 
    
         
            -
                  rescue => e
         
     | 
| 
       114 
     | 
    
         
            -
                    raise "Unable to add tables to publication: #{e.message}"
         
     | 
| 
       115 
     | 
    
         
            -
                  end
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                  def list_all_tables(schema:, conn_string:)
         
     | 
| 
       118 
     | 
    
         
            -
                    Query
         
     | 
| 
       119 
     | 
    
         
            -
                      .run(
         
     | 
| 
      
 102 
     | 
    
         
            +
                    tables.map do |table_name|
         
     | 
| 
      
 103 
     | 
    
         
            +
                      Query.run(
         
     | 
| 
       120 
104 
     | 
    
         
             
                        query:
         
     | 
| 
       121 
     | 
    
         
            -
                          " 
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                           WHERE table_schema = '#{schema}' AND
         
     | 
| 
       124 
     | 
    
         
            -
                             table_type = 'BASE TABLE'
         
     | 
| 
       125 
     | 
    
         
            -
                           ORDER BY table_name",
         
     | 
| 
      
 105 
     | 
    
         
            +
                          "ALTER PUBLICATION #{quote_ident(publication_name(group_name))}
         
     | 
| 
      
 106 
     | 
    
         
            +
                                    ADD TABLE #{quote_ident(table_name)}",
         
     | 
| 
       126 
107 
     | 
    
         
             
                        connection_url: conn_string,
         
     | 
| 
      
 108 
     | 
    
         
            +
                        schema: schema,
         
     | 
| 
       127 
109 
     | 
    
         
             
                      )
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  rescue => e
         
     | 
| 
      
 112 
     | 
    
         
            +
                    raise "Unable to add tables to publication: #{e.message}"
         
     | 
| 
       131 
113 
     | 
    
         
             
                  end
         
     | 
| 
       132 
114 
     | 
    
         | 
| 
       133 
115 
     | 
    
         
             
                  def drop_publication(group_name:, conn_string:)
         
     | 
| 
         @@ -225,10 +207,11 @@ module PgEasyReplicate 
     | 
|
| 
       225 
207 
     | 
    
         
             
                    lag_delta_size: nil
         
     | 
| 
       226 
208 
     | 
    
         
             
                  )
         
     | 
| 
       227 
209 
     | 
    
         
             
                    group = Group.find(group_name)
         
     | 
| 
      
 210 
     | 
    
         
            +
                    tables_list = group[:table_names].split(",")
         
     | 
| 
       228 
211 
     | 
    
         | 
| 
       229 
212 
     | 
    
         
             
                    run_vacuum_analyze(
         
     | 
| 
       230 
213 
     | 
    
         
             
                      conn_string: target_conn_string,
         
     | 
| 
       231 
     | 
    
         
            -
                      tables:  
     | 
| 
      
 214 
     | 
    
         
            +
                      tables: tables_list,
         
     | 
| 
       232 
215 
     | 
    
         
             
                      schema: group[:schema_name],
         
     | 
| 
       233 
216 
     | 
    
         
             
                    )
         
     | 
| 
       234 
217 
     | 
    
         | 
| 
         @@ -239,7 +222,7 @@ module PgEasyReplicate 
     | 
|
| 
       239 
222 
     | 
    
         
             
                      IndexManager.recreate_indices(
         
     | 
| 
       240 
223 
     | 
    
         
             
                        source_conn_string: source_db_url,
         
     | 
| 
       241 
224 
     | 
    
         
             
                        target_conn_string: target_db_url,
         
     | 
| 
       242 
     | 
    
         
            -
                        tables:  
     | 
| 
      
 225 
     | 
    
         
            +
                        tables: tables_list,
         
     | 
| 
       243 
226 
     | 
    
         
             
                        schema: group[:schema_name],
         
     | 
| 
       244 
227 
     | 
    
         
             
                      )
         
     | 
| 
       245 
228 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -257,7 +240,7 @@ module PgEasyReplicate 
     | 
|
| 
       257 
240 
     | 
    
         
             
                    # Run vacuum analyze to refresh the planner post switchover
         
     | 
| 
       258 
241 
     | 
    
         
             
                    run_vacuum_analyze(
         
     | 
| 
       259 
242 
     | 
    
         
             
                      conn_string: target_conn_string,
         
     | 
| 
       260 
     | 
    
         
            -
                      tables:  
     | 
| 
      
 243 
     | 
    
         
            +
                      tables: tables_list,
         
     | 
| 
       261 
244 
     | 
    
         
             
                      schema: group[:schema_name],
         
     | 
| 
       262 
245 
     | 
    
         
             
                    )
         
     | 
| 
       263 
246 
     | 
    
         
             
                    drop_subscription(
         
     | 
| 
         @@ -369,21 +352,19 @@ module PgEasyReplicate 
     | 
|
| 
       369 
352 
     | 
    
         
             
                  end
         
     | 
| 
       370 
353 
     | 
    
         | 
| 
       371 
354 
     | 
    
         
             
                  def run_vacuum_analyze(conn_string:, tables:, schema:)
         
     | 
| 
       372 
     | 
    
         
            -
                    tables
         
     | 
| 
       373 
     | 
    
         
            -
                      . 
     | 
| 
       374 
     | 
    
         
            -
             
     | 
| 
       375 
     | 
    
         
            -
                         
     | 
| 
       376 
     | 
    
         
            -
             
     | 
| 
       377 
     | 
    
         
            -
             
     | 
| 
       378 
     | 
    
         
            -
             
     | 
| 
       379 
     | 
    
         
            -
                         
     | 
| 
       380 
     | 
    
         
            -
                         
     | 
| 
       381 
     | 
    
         
            -
             
     | 
| 
       382 
     | 
    
         
            -
             
     | 
| 
       383 
     | 
    
         
            -
             
     | 
| 
       384 
     | 
    
         
            -
             
     | 
| 
       385 
     | 
    
         
            -
                        )
         
     | 
| 
       386 
     | 
    
         
            -
                      end
         
     | 
| 
      
 355 
     | 
    
         
            +
                    tables.each do |t|
         
     | 
| 
      
 356 
     | 
    
         
            +
                      logger.info(
         
     | 
| 
      
 357 
     | 
    
         
            +
                        "Running vacuum analyze on #{t}",
         
     | 
| 
      
 358 
     | 
    
         
            +
                        schema: schema,
         
     | 
| 
      
 359 
     | 
    
         
            +
                        table: t,
         
     | 
| 
      
 360 
     | 
    
         
            +
                      )
         
     | 
| 
      
 361 
     | 
    
         
            +
                      Query.run(
         
     | 
| 
      
 362 
     | 
    
         
            +
                        query: "VACUUM VERBOSE ANALYZE #{t}",
         
     | 
| 
      
 363 
     | 
    
         
            +
                        connection_url: conn_string,
         
     | 
| 
      
 364 
     | 
    
         
            +
                        schema: schema,
         
     | 
| 
      
 365 
     | 
    
         
            +
                        transaction: false,
         
     | 
| 
      
 366 
     | 
    
         
            +
                      )
         
     | 
| 
      
 367 
     | 
    
         
            +
                    end
         
     | 
| 
       387 
368 
     | 
    
         
             
                  rescue => e
         
     | 
| 
       388 
369 
     | 
    
         
             
                    raise "Unable to run vacuum and analyze: #{e.message}"
         
     | 
| 
       389 
370 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -391,16 +372,6 @@ module PgEasyReplicate 
     | 
|
| 
       391 
372 
     | 
    
         
             
                  def mark_switchover_complete(group_name)
         
     | 
| 
       392 
373 
     | 
    
         
             
                    Group.update(group_name: group_name, switchover_completed_at: Time.now)
         
     | 
| 
       393 
374 
     | 
    
         
             
                  end
         
     | 
| 
       394 
     | 
    
         
            -
             
     | 
| 
       395 
     | 
    
         
            -
                  private
         
     | 
| 
       396 
     | 
    
         
            -
             
     | 
| 
       397 
     | 
    
         
            -
                  def determine_tables(schema:, conn_string:, list: "")
         
     | 
| 
       398 
     | 
    
         
            -
                    tables = list&.split(",") || []
         
     | 
| 
       399 
     | 
    
         
            -
                    unless tables.size > 0
         
     | 
| 
       400 
     | 
    
         
            -
                      return list_all_tables(schema: schema, conn_string: conn_string)
         
     | 
| 
       401 
     | 
    
         
            -
                    end
         
     | 
| 
       402 
     | 
    
         
            -
                    ""
         
     | 
| 
       403 
     | 
    
         
            -
                  end
         
     | 
| 
       404 
375 
     | 
    
         
             
                end
         
     | 
| 
       405 
376 
     | 
    
         
             
              end
         
     | 
| 
       406 
377 
     | 
    
         
             
            end
         
     | 
    
        data/lib/pg_easy_replicate.rb
    CHANGED
    
    | 
         @@ -26,7 +26,12 @@ module PgEasyReplicate 
     | 
|
| 
       26 
26 
     | 
    
         
             
              extend Helper
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
              class << self
         
     | 
| 
       29 
     | 
    
         
            -
                def config( 
     | 
| 
      
 29 
     | 
    
         
            +
                def config(
         
     | 
| 
      
 30 
     | 
    
         
            +
                  special_user_role: nil,
         
     | 
| 
      
 31 
     | 
    
         
            +
                  copy_schema: false,
         
     | 
| 
      
 32 
     | 
    
         
            +
                  tables: "",
         
     | 
| 
      
 33 
     | 
    
         
            +
                  schema_name: nil
         
     | 
| 
      
 34 
     | 
    
         
            +
                )
         
     | 
| 
       30 
35 
     | 
    
         
             
                  abort_with("SOURCE_DB_URL is missing") if source_db_url.nil?
         
     | 
| 
       31 
36 
     | 
    
         
             
                  abort_with("TARGET_DB_URL is missing") if target_db_url.nil?
         
     | 
| 
       32 
37 
     | 
    
         | 
| 
         @@ -56,15 +61,31 @@ module PgEasyReplicate 
     | 
|
| 
       56 
61 
     | 
    
         
             
                            user: db_user(target_db_url),
         
     | 
| 
       57 
62 
     | 
    
         
             
                          ),
         
     | 
| 
       58 
63 
     | 
    
         
             
                        pg_dump_exists: pg_dump_exists,
         
     | 
| 
      
 64 
     | 
    
         
            +
                        tables_have_replica_identity:
         
     | 
| 
      
 65 
     | 
    
         
            +
                          tables_have_replica_identity?(
         
     | 
| 
      
 66 
     | 
    
         
            +
                            conn_string: source_db_url,
         
     | 
| 
      
 67 
     | 
    
         
            +
                            tables: tables,
         
     | 
| 
      
 68 
     | 
    
         
            +
                            schema_name: schema_name,
         
     | 
| 
      
 69 
     | 
    
         
            +
                          ),
         
     | 
| 
       59 
70 
     | 
    
         
             
                      }
         
     | 
| 
       60 
71 
     | 
    
         
             
                    rescue => e
         
     | 
| 
       61 
72 
     | 
    
         
             
                      abort_with("Unable to check config: #{e.message}")
         
     | 
| 
       62 
73 
     | 
    
         
             
                    end
         
     | 
| 
       63 
74 
     | 
    
         
             
                end
         
     | 
| 
       64 
75 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                def assert_config( 
     | 
| 
      
 76 
     | 
    
         
            +
                def assert_config(
         
     | 
| 
      
 77 
     | 
    
         
            +
                  special_user_role: nil,
         
     | 
| 
      
 78 
     | 
    
         
            +
                  copy_schema: false,
         
     | 
| 
      
 79 
     | 
    
         
            +
                  tables: "",
         
     | 
| 
      
 80 
     | 
    
         
            +
                  schema_name: nil
         
     | 
| 
      
 81 
     | 
    
         
            +
                )
         
     | 
| 
       66 
82 
     | 
    
         
             
                  config_hash =
         
     | 
| 
       67 
     | 
    
         
            -
                    config( 
     | 
| 
      
 83 
     | 
    
         
            +
                    config(
         
     | 
| 
      
 84 
     | 
    
         
            +
                      special_user_role: special_user_role,
         
     | 
| 
      
 85 
     | 
    
         
            +
                      copy_schema: copy_schema,
         
     | 
| 
      
 86 
     | 
    
         
            +
                      tables: tables,
         
     | 
| 
      
 87 
     | 
    
         
            +
                      schema_name: schema_name,
         
     | 
| 
      
 88 
     | 
    
         
            +
                    )
         
     | 
| 
       68 
89 
     | 
    
         | 
| 
       69 
90 
     | 
    
         
             
                  if copy_schema && !config_hash.dig(:pg_dump_exists)
         
     | 
| 
       70 
91 
     | 
    
         
             
                    abort_with("pg_dump must exist if copy_schema (-c) is passed")
         
     | 
| 
         @@ -82,6 +103,19 @@ module PgEasyReplicate 
     | 
|
| 
       82 
103 
     | 
    
         
             
                    abort_with("User on source database does not have super user privilege")
         
     | 
| 
       83 
104 
     | 
    
         
             
                  end
         
     | 
| 
       84 
105 
     | 
    
         | 
| 
      
 106 
     | 
    
         
            +
                  if tables.split(",").size > 0 && (schema_name.nil? || schema_name == "")
         
     | 
| 
      
 107 
     | 
    
         
            +
                    abort_with("Schema name is required if tables are passed")
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  unless config_hash.dig(:tables_have_replica_identity)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    abort_with(
         
     | 
| 
      
 112 
     | 
    
         
            +
                      "Ensure all tables involved in logical replication have an appropriate replica identity set. This can be done using:
         
     | 
| 
      
 113 
     | 
    
         
            +
                    1. Default (Primary Key): `ALTER TABLE table_name REPLICA IDENTITY DEFAULT;`
         
     | 
| 
      
 114 
     | 
    
         
            +
                    2. Unique Index: `ALTER TABLE table_name REPLICA IDENTITY USING INDEX index_name;`
         
     | 
| 
      
 115 
     | 
    
         
            +
                    3. Full (All Columns): `ALTER TABLE table_name REPLICA IDENTITY FULL;`",
         
     | 
| 
      
 116 
     | 
    
         
            +
                    )
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
       85 
119 
     | 
    
         
             
                  return if config_hash.dig(:target_db_is_super_user)
         
     | 
| 
       86 
120 
     | 
    
         
             
                  abort_with("User on target database does not have super user privilege")
         
     | 
| 
       87 
121 
     | 
    
         
             
                end
         
     | 
| 
         @@ -352,5 +386,47 @@ module PgEasyReplicate 
     | 
|
| 
       352 
386 
     | 
    
         
             
                    )
         
     | 
| 
       353 
387 
     | 
    
         
             
                    .any? { |q| q[:username] == user }
         
     | 
| 
       354 
388 
     | 
    
         
             
                end
         
     | 
| 
      
 389 
     | 
    
         
            +
             
     | 
| 
      
 390 
     | 
    
         
            +
                def tables_have_replica_identity?(
         
     | 
| 
      
 391 
     | 
    
         
            +
                  conn_string:,
         
     | 
| 
      
 392 
     | 
    
         
            +
                  tables: "",
         
     | 
| 
      
 393 
     | 
    
         
            +
                  schema_name: nil
         
     | 
| 
      
 394 
     | 
    
         
            +
                )
         
     | 
| 
      
 395 
     | 
    
         
            +
                  schema_name ||= "public"
         
     | 
| 
      
 396 
     | 
    
         
            +
             
     | 
| 
      
 397 
     | 
    
         
            +
                  table_list =
         
     | 
| 
      
 398 
     | 
    
         
            +
                    determine_tables(
         
     | 
| 
      
 399 
     | 
    
         
            +
                      schema: schema_name,
         
     | 
| 
      
 400 
     | 
    
         
            +
                      conn_string: source_db_url,
         
     | 
| 
      
 401 
     | 
    
         
            +
                      list: tables,
         
     | 
| 
      
 402 
     | 
    
         
            +
                    )
         
     | 
| 
      
 403 
     | 
    
         
            +
                  return false if table_list.empty?
         
     | 
| 
      
 404 
     | 
    
         
            +
             
     | 
| 
      
 405 
     | 
    
         
            +
                  formatted_table_list = table_list.map { |table| "'#{table}'" }.join(", ")
         
     | 
| 
      
 406 
     | 
    
         
            +
             
     | 
| 
      
 407 
     | 
    
         
            +
                  sql = <<~SQL
         
     | 
| 
      
 408 
     | 
    
         
            +
                    SELECT t.relname AS table_name,
         
     | 
| 
      
 409 
     | 
    
         
            +
                          CASE
         
     | 
| 
      
 410 
     | 
    
         
            +
                            WHEN t.relreplident = 'd' THEN 'default'
         
     | 
| 
      
 411 
     | 
    
         
            +
                            WHEN t.relreplident = 'n' THEN 'nothing'
         
     | 
| 
      
 412 
     | 
    
         
            +
                            WHEN t.relreplident = 'i' THEN 'index'
         
     | 
| 
      
 413 
     | 
    
         
            +
                            WHEN t.relreplident = 'f' THEN 'full'
         
     | 
| 
      
 414 
     | 
    
         
            +
                          END AS replica_identity
         
     | 
| 
      
 415 
     | 
    
         
            +
                    FROM pg_class t
         
     | 
| 
      
 416 
     | 
    
         
            +
                    JOIN pg_namespace ns ON t.relnamespace = ns.oid
         
     | 
| 
      
 417 
     | 
    
         
            +
                    WHERE ns.nspname = '#{schema_name}'
         
     | 
| 
      
 418 
     | 
    
         
            +
                      AND t.relkind = 'r'
         
     | 
| 
      
 419 
     | 
    
         
            +
                      AND t.relname IN (#{formatted_table_list})
         
     | 
| 
      
 420 
     | 
    
         
            +
                  SQL
         
     | 
| 
      
 421 
     | 
    
         
            +
             
     | 
| 
      
 422 
     | 
    
         
            +
                  results =
         
     | 
| 
      
 423 
     | 
    
         
            +
                    Query.run(
         
     | 
| 
      
 424 
     | 
    
         
            +
                      query: sql,
         
     | 
| 
      
 425 
     | 
    
         
            +
                      connection_url: conn_string,
         
     | 
| 
      
 426 
     | 
    
         
            +
                      user: db_user(conn_string),
         
     | 
| 
      
 427 
     | 
    
         
            +
                    )
         
     | 
| 
      
 428 
     | 
    
         
            +
             
     | 
| 
      
 429 
     | 
    
         
            +
                  results.all? { |r| r[:replica_identity] != "nothing" }
         
     | 
| 
      
 430 
     | 
    
         
            +
                end
         
     | 
| 
       355 
431 
     | 
    
         
             
              end
         
     | 
| 
       356 
432 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: pg_easy_replicate
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.2. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.2
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Shayon Mukherjee
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2024-01-21 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: ougai
         
     | 
| 
         @@ -47,7 +47,7 @@ dependencies: 
     | 
|
| 
       47 
47 
     | 
    
         
             
                    version: '5.69'
         
     | 
| 
       48 
48 
     | 
    
         
             
                - - "<"
         
     | 
| 
       49 
49 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       50 
     | 
    
         
            -
                    version: '5. 
     | 
| 
      
 50 
     | 
    
         
            +
                    version: '5.77'
         
     | 
| 
       51 
51 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       52 
52 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       53 
53 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -57,7 +57,7 @@ dependencies: 
     | 
|
| 
       57 
57 
     | 
    
         
             
                    version: '5.69'
         
     | 
| 
       58 
58 
     | 
    
         
             
                - - "<"
         
     | 
| 
       59 
59 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       60 
     | 
    
         
            -
                    version: '5. 
     | 
| 
      
 60 
     | 
    
         
            +
                    version: '5.77'
         
     | 
| 
       61 
61 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       62 
62 
     | 
    
         
             
              name: thor
         
     | 
| 
       63 
63 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     |