table_copy 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/table_copy/copier.rb +22 -13
- data/lib/table_copy/pg/destination.rb +31 -1
- data/lib/table_copy/version.rb +1 -1
- data/spec/lib/table_copy/copier_spec.rb +2 -0
- data/spec/lib/table_copy/pg/destination_spec.rb +38 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a22be48d16345c92700399d3cffdddff1df4378e
|
4
|
+
data.tar.gz: b7df0eafee1cd537a06931fd036a7663a0ebf539
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f914d7745eb8e29085dcac211c7fef39dc03374bde943528d1e9037eb2dea78789be06b0e5b1c84600315189a02f2e3e18da7990584b7da7568f1216412e63ee
|
7
|
+
data.tar.gz: b927514b338af025f253de8cf6897ed1f3208d18e7b644bc678586332dea0e9a3022784773f4df216b44ef9d119920bfb52091e4b66937283be947fe1e68c9a1
|
data/lib/table_copy/copier.rb
CHANGED
@@ -10,27 +10,25 @@ module TableCopy
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def update
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
data/lib/table_copy/version.rb
CHANGED
@@ -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.
|
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-
|
11
|
+
date: 2014-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|