table_copy 0.0.5 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 82e2e7bc03e341d5b10e172c080499d174abd238
4
- data.tar.gz: ccf3b5eebc929cefe8b9eeec212d7869b3cacb2c
3
+ metadata.gz: a22be48d16345c92700399d3cffdddff1df4378e
4
+ data.tar.gz: b7df0eafee1cd537a06931fd036a7663a0ebf539
5
5
  SHA512:
6
- metadata.gz: 9be2278b5259705cbfb905422385a334145eeb5325d8f97b33eb253343e3838014d081e3f86417c7456c519364ad29e19ea40e3cedece2fe84550ca2514c9567
7
- data.tar.gz: 4191cd39eda48dd99414e3f300a962d6de22e0ad756aaa9f7da8755ac5d0a4d42d14d185d4cf717a40e80524b254f8a80bbfacd4b4c842ba02dbf885a4e698cf
6
+ metadata.gz: f914d7745eb8e29085dcac211c7fef39dc03374bde943528d1e9037eb2dea78789be06b0e5b1c84600315189a02f2e3e18da7990584b7da7568f1216412e63ee
7
+ data.tar.gz: b927514b338af025f253de8cf6897ed1f3208d18e7b644bc678586332dea0e9a3022784773f4df216b44ef9d119920bfb52091e4b66937283be947fe1e68c9a1
@@ -10,27 +10,25 @@ module TableCopy
10
10
  end
11
11
 
12
12
  def update
13
- if destination_table.none?
14
- droppy
15
- elsif (max_sequence = destination_table.max_sequence)
16
- update_data(max_sequence)
17
- else
18
- diffy_update
13
+ with_rescue do
14
+ if destination_table.none?
15
+ droppy
16
+ elsif (max_sequence = destination_table.max_sequence)
17
+ update_data(max_sequence)
18
+ else
19
+ diffy_update
20
+ end
19
21
  end
20
- rescue ::PG::UndefinedTable => e
21
- ([e.inspect] + e.backtrace).each { |l| logger.warn(l) }
22
- create_table
23
- retry
24
- rescue ::PG::UndefinedColumn => e
25
- ([e.inspect] + e.backtrace).each { |l| logger.warn(l) }
26
- droppy
27
22
  end
28
23
 
29
24
  def droppy
30
25
  logger.info { "Droppy #{destination_table.table_name}" }
31
26
  destination_table.transaction do
27
+ views = destination_table.query_views
32
28
  destination_table.drop(cascade: true)
33
29
  create_table
30
+ destination_table.create_views(views)
31
+ logger.info { "Created #{views.count} views for #{destination_table.table_name}" }
34
32
  moved_count = destination_table.copy_data_from(source_table)
35
33
  logger.info { "#{moved_count} rows moved to #{destination_table.table_name}" }
36
34
  destination_table.create_indexes
@@ -91,6 +89,17 @@ module TableCopy
91
89
  destination_table.create(source_table.fields_ddl)
92
90
  end
93
91
 
92
+ def with_rescue
93
+ yield
94
+ rescue ::PG::UndefinedTable => e
95
+ ([e.inspect] + e.backtrace).each { |l| logger.warn(l) }
96
+ create_table
97
+ yield
98
+ rescue ::PG::UndefinedColumn => e
99
+ ([e.inspect] + e.backtrace).each { |l| logger.warn(l) }
100
+ droppy
101
+ end
102
+
94
103
  def logger
95
104
  TableCopy.logger
96
105
  end
@@ -101,8 +101,24 @@ module TableCopy
101
101
  end
102
102
  end
103
103
 
104
+ def query_views
105
+ with_conn do |conn|
106
+ conn.exec(views_sql)
107
+ end
108
+ end
109
+
110
+ def create_views(views)
111
+ with_conn do |conn|
112
+ views.each do |view|
113
+ conn.exec("create or replace view #{view['viewname']} as (#{view['definition'].gsub(/;\z/, '')})")
114
+ end
115
+ end
116
+ end
117
+
104
118
  private
105
119
 
120
+ attr_reader :primary_key
121
+
106
122
  def fields_list
107
123
  @fields_list ||= fields.join(', ')
108
124
  end
@@ -111,7 +127,6 @@ module TableCopy
111
127
  conn_method.call(&block)
112
128
  end
113
129
 
114
- attr_reader :primary_key
115
130
 
116
131
  def drop_sql
117
132
  @drop_sql ||= "drop table if exists #{table_name}"
@@ -157,6 +172,21 @@ module TableCopy
157
172
  "nv.#{key}"
158
173
  end.join(',')
159
174
  end
175
+
176
+ def views_sql
177
+ <<-SQL
178
+ select viewname, definition from pg_views where viewname in
179
+ (SELECT distinct dependee.relname
180
+ FROM pg_depend
181
+ JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
182
+ JOIN pg_class as dependee ON pg_rewrite.ev_class = dependee.oid
183
+ JOIN pg_class as dependent ON pg_depend.refobjid = dependent.oid
184
+ JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid
185
+ AND pg_depend.refobjsubid = pg_attribute.attnum
186
+ WHERE dependent.relname = '#{table_name}'
187
+ AND pg_attribute.attnum > 0)
188
+ SQL
189
+ end
160
190
  end
161
191
  end
162
192
  end
@@ -1,3 +1,3 @@
1
1
  module TableCopy
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -88,9 +88,11 @@ describe TableCopy::Copier do
88
88
 
89
89
  describe '#droppy' do
90
90
  it 'drops and rebuilds the destination table' do
91
+ expect(destination).to receive(:query_views).and_return('views')
91
92
  expect(destination).to receive(:drop).with(cascade: true)
92
93
  expect(source).to receive(:fields_ddl).and_return(fields_ddl)
93
94
  expect(destination).to receive(:create).with(fields_ddl)
95
+ expect(destination).to receive(:create_views).with('views')
94
96
  expect(destination).to receive(:copy_data_from).with(source)
95
97
  expect(destination).to receive(:create_indexes)
96
98
  copier.droppy
@@ -4,6 +4,7 @@ require 'table_copy/pg/index'
4
4
  describe TableCopy::PG::Destination do
5
5
  let(:conn) { $pg_conn }
6
6
  let(:table_name) { 'table_name' }
7
+ let(:view_name) { 'view_name' }
7
8
  let(:indexes_sql) {
8
9
  <<-SQL
9
10
  select
@@ -35,6 +36,10 @@ describe TableCopy::PG::Destination do
35
36
  conn.exec("select count(*) from pg_tables where tablename='#{name}'").first['count'] == '1'
36
37
  end
37
38
 
39
+ def view_exists?(name=view_name)
40
+ conn.exec("select count(*) from pg_views where viewname='#{name}'").first['count'] == '1'
41
+ end
42
+
38
43
  def insert_data(name=table_name)
39
44
  conn.exec("insert into #{name} values(1, 'foo', '{bar, baz}')")
40
45
  end
@@ -57,7 +62,7 @@ describe TableCopy::PG::Destination do
57
62
  )}
58
63
 
59
64
  after do
60
- conn.exec("drop table if exists #{table_name}")
65
+ conn.exec("drop table if exists #{table_name} cascade")
61
66
  end
62
67
 
63
68
  describe '#to_s' do
@@ -71,6 +76,37 @@ describe TableCopy::PG::Destination do
71
76
  create_table
72
77
  end
73
78
 
79
+ let(:expected_view) {
80
+ [
81
+ {
82
+ "viewname" => view_name,
83
+ "definition" => "SELECT #{table_name}.column1, #{table_name}.column2, #{table_name}.column3 FROM #{table_name};"
84
+ }
85
+ ]
86
+ }
87
+
88
+ context 'a view exists' do
89
+ before do
90
+ conn.exec("create view #{view_name} as (select * from #{table_name})")
91
+ end
92
+
93
+ describe '#query_views' do
94
+ it 'returns a hash of name => query for views dependent on this table' do
95
+ expect(dest.query_views.to_a).to eq expected_view
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '#create_views' do
101
+ it 'creates the given views' do
102
+ expect {
103
+ dest.create_views(expected_view)
104
+ }.to change {
105
+ view_exists?
106
+ }.from(false).to(true)
107
+ end
108
+ end
109
+
74
110
  describe '#none?' do
75
111
  it 'indicates whether the table has any data' do
76
112
  expect {
@@ -108,6 +144,7 @@ describe TableCopy::PG::Destination do
108
144
  }
109
145
  end
110
146
  end
147
+
111
148
  end
112
149
 
113
150
  describe '#drop' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: table_copy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - TLH
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-29 00:00:00.000000000 Z
11
+ date: 2014-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler