postgres_upsert 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +30 -35
- data/lib/postgres_upsert/active_record.rb +1 -1
- data/lib/postgres_upsert/writer.rb +47 -26
- data/postgres_upsert.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b0a956bd60011cf247a58c3031d5157be3c6f7f
|
4
|
+
data.tar.gz: 918a0d163efa3915f8b3d76421ab69e67e2469d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1dda03e61a25fb875bbaf8eab001d0f8b780dbcb329f8be1c0aabbb03c4be4bb66c6adf2dbfbf21d3edb55135be2fc01826dcc79259b928b64c7bb1748c0369
|
7
|
+
data.tar.gz: ca59859938a0671ffed159495d10a08328a498500f8c18610c4d50f9d452901b55c5e81e63e62eb35dc8c74b532a713e4f2285db690721be5f4de9b3aed3f8ad
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
postgres_upsert (
|
4
|
+
postgres_upsert (3.0.0)
|
5
5
|
activerecord (>= 3.0.0)
|
6
6
|
pg (~> 0.17.0)
|
7
7
|
rails (>= 3.0.0)
|
@@ -9,26 +9,26 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
actionmailer (4.0.
|
13
|
-
actionpack (= 4.0.
|
14
|
-
mail (~> 2.5.4)
|
15
|
-
actionpack (4.0.
|
16
|
-
activesupport (= 4.0.
|
12
|
+
actionmailer (4.0.11)
|
13
|
+
actionpack (= 4.0.11)
|
14
|
+
mail (~> 2.5, >= 2.5.4)
|
15
|
+
actionpack (4.0.11)
|
16
|
+
activesupport (= 4.0.11)
|
17
17
|
builder (~> 3.1.0)
|
18
18
|
erubis (~> 2.7.0)
|
19
19
|
rack (~> 1.5.2)
|
20
20
|
rack-test (~> 0.6.2)
|
21
|
-
activemodel (4.0.
|
22
|
-
activesupport (= 4.0.
|
21
|
+
activemodel (4.0.11)
|
22
|
+
activesupport (= 4.0.11)
|
23
23
|
builder (~> 3.1.0)
|
24
|
-
activerecord (4.0.
|
25
|
-
activemodel (= 4.0.
|
24
|
+
activerecord (4.0.11)
|
25
|
+
activemodel (= 4.0.11)
|
26
26
|
activerecord-deprecated_finders (~> 1.0.2)
|
27
|
-
activesupport (= 4.0.
|
27
|
+
activesupport (= 4.0.11)
|
28
28
|
arel (~> 4.0.0)
|
29
29
|
activerecord-deprecated_finders (1.0.3)
|
30
|
-
activesupport (4.0.
|
31
|
-
i18n (~> 0.6, >= 0.6.
|
30
|
+
activesupport (4.0.11)
|
31
|
+
i18n (~> 0.6, >= 0.6.9)
|
32
32
|
minitest (~> 4.2)
|
33
33
|
multi_json (~> 1.3)
|
34
34
|
thread_safe (~> 0.1)
|
@@ -41,15 +41,13 @@ GEM
|
|
41
41
|
hike (1.2.3)
|
42
42
|
i18n (0.6.11)
|
43
43
|
json (1.7.6)
|
44
|
-
mail (2.
|
45
|
-
mime-types (
|
46
|
-
treetop (~> 1.4.8)
|
44
|
+
mail (2.6.3)
|
45
|
+
mime-types (>= 1.16, < 3)
|
47
46
|
method_source (0.8.2)
|
48
|
-
mime-types (
|
47
|
+
mime-types (2.4.3)
|
49
48
|
minitest (4.7.5)
|
50
49
|
multi_json (1.10.1)
|
51
50
|
pg (0.17.1)
|
52
|
-
polyglot (0.3.5)
|
53
51
|
pry (0.10.1)
|
54
52
|
coderay (~> 1.1.0)
|
55
53
|
method_source (~> 0.8.1)
|
@@ -59,17 +57,17 @@ GEM
|
|
59
57
|
rack (1.5.2)
|
60
58
|
rack-test (0.6.2)
|
61
59
|
rack (>= 1.0)
|
62
|
-
rails (4.0.
|
63
|
-
actionmailer (= 4.0.
|
64
|
-
actionpack (= 4.0.
|
65
|
-
activerecord (= 4.0.
|
66
|
-
activesupport (= 4.0.
|
60
|
+
rails (4.0.11)
|
61
|
+
actionmailer (= 4.0.11)
|
62
|
+
actionpack (= 4.0.11)
|
63
|
+
activerecord (= 4.0.11)
|
64
|
+
activesupport (= 4.0.11)
|
67
65
|
bundler (>= 1.3.0, < 2.0)
|
68
|
-
railties (= 4.0.
|
69
|
-
sprockets-rails (~> 2.0
|
70
|
-
railties (4.0.
|
71
|
-
actionpack (= 4.0.
|
72
|
-
activesupport (= 4.0.
|
66
|
+
railties (= 4.0.11)
|
67
|
+
sprockets-rails (~> 2.0)
|
68
|
+
railties (4.0.11)
|
69
|
+
actionpack (= 4.0.11)
|
70
|
+
activesupport (= 4.0.11)
|
73
71
|
rake (>= 0.8.7)
|
74
72
|
thor (>= 0.18.1, < 2.0)
|
75
73
|
rake (10.3.2)
|
@@ -84,22 +82,19 @@ GEM
|
|
84
82
|
diff-lcs (~> 1.1.3)
|
85
83
|
rspec-mocks (2.12.2)
|
86
84
|
slop (3.6.0)
|
87
|
-
sprockets (2.
|
85
|
+
sprockets (2.12.3)
|
88
86
|
hike (~> 1.2)
|
89
87
|
multi_json (~> 1.0)
|
90
88
|
rack (~> 1.0)
|
91
89
|
tilt (~> 1.1, != 1.3.0)
|
92
|
-
sprockets-rails (2.0
|
90
|
+
sprockets-rails (2.2.0)
|
93
91
|
actionpack (>= 3.0)
|
94
92
|
activesupport (>= 3.0)
|
95
|
-
sprockets (
|
93
|
+
sprockets (>= 2.8, < 4.0)
|
96
94
|
thor (0.19.1)
|
97
95
|
thread_safe (0.3.4)
|
98
96
|
tilt (1.4.1)
|
99
|
-
|
100
|
-
polyglot
|
101
|
-
polyglot (>= 0.3.1)
|
102
|
-
tzinfo (0.3.40)
|
97
|
+
tzinfo (0.3.42)
|
103
98
|
|
104
99
|
PLATFORMS
|
105
100
|
ruby
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
# * You can map fields from the file to different fields in the table using a map in the options hash
|
8
8
|
# * For further details on usage take a look at the README.md
|
9
9
|
def self.pg_upsert path_or_io, options = {}
|
10
|
-
PostgresUpsert::Writer.new(
|
10
|
+
PostgresUpsert::Writer.new(table_name, path_or_io, options).write
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -2,13 +2,13 @@ module PostgresUpsert
|
|
2
2
|
|
3
3
|
class Writer
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
@
|
5
|
+
def initialize(table_name, source, options = {})
|
6
|
+
@table_name = table_name
|
7
7
|
@options = options.reverse_merge({
|
8
8
|
:delimiter => ",",
|
9
9
|
:format => :csv,
|
10
10
|
:header => true,
|
11
|
-
:key_column =>
|
11
|
+
:key_column => primary_key,
|
12
12
|
:update_only => false})
|
13
13
|
@source = source.instance_of?(String) ? File.open(source, 'r') : source
|
14
14
|
@columns_list = get_columns
|
@@ -23,7 +23,6 @@ module PostgresUpsert
|
|
23
23
|
csv_options = @options[:format] == :binary ? "BINARY" : "DELIMITER '#{@options[:delimiter]}' CSV"
|
24
24
|
|
25
25
|
copy_table = @temp_table_name
|
26
|
-
destination_table = get_table_name
|
27
26
|
|
28
27
|
columns_string = columns_string_for_copy
|
29
28
|
create_temp_table
|
@@ -36,14 +35,40 @@ module PostgresUpsert
|
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
drop_temp_table
|
42
|
-
end
|
38
|
+
upsert_from_temp_table
|
39
|
+
drop_temp_table
|
43
40
|
end
|
44
41
|
|
45
42
|
private
|
46
43
|
|
44
|
+
def primary_key
|
45
|
+
@primary_key ||= begin
|
46
|
+
query = <<-sql
|
47
|
+
SELECT
|
48
|
+
pg_attribute.attname,
|
49
|
+
format_type(pg_attribute.atttypid, pg_attribute.atttypmod)
|
50
|
+
FROM pg_index, pg_class, pg_attribute
|
51
|
+
WHERE
|
52
|
+
pg_class.oid = '#{@table_name}'::regclass AND
|
53
|
+
indrelid = pg_class.oid AND
|
54
|
+
pg_attribute.attrelid = pg_class.oid AND
|
55
|
+
pg_attribute.attnum = any(pg_index.indkey)
|
56
|
+
AND indisprimary
|
57
|
+
sql
|
58
|
+
|
59
|
+
pg_result = ActiveRecord::Base.connection.execute query
|
60
|
+
pg_result.each{ |row| return row['attname'] }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def column_names
|
65
|
+
@column_names ||= begin
|
66
|
+
query = "SELECT * FROM information_schema.columns WHERE TABLE_NAME = '#{@table_name}'"
|
67
|
+
pg_result = ActiveRecord::Base.connection.execute query
|
68
|
+
pg_result.map{ |row| row['column_name'] }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
47
72
|
def get_columns
|
48
73
|
columns_list = @options[:columns] || []
|
49
74
|
if @options[:format] != :binary && @options[:header]
|
@@ -64,23 +89,23 @@ module PostgresUpsert
|
|
64
89
|
|
65
90
|
def columns_string_for_select
|
66
91
|
columns = @columns_list.clone
|
67
|
-
columns << "created_at" if
|
68
|
-
columns << "updated_at" if
|
92
|
+
columns << "created_at" if column_names.include?("created_at")
|
93
|
+
columns << "updated_at" if column_names.include?("updated_at")
|
69
94
|
str = get_columns_string(columns)
|
70
95
|
end
|
71
96
|
|
72
97
|
def columns_string_for_insert
|
73
98
|
columns = @columns_list.clone
|
74
|
-
columns << "created_at" if
|
75
|
-
columns << "updated_at" if
|
99
|
+
columns << "created_at" if column_names.include?("created_at")
|
100
|
+
columns << "updated_at" if column_names.include?("updated_at")
|
76
101
|
str = get_columns_string(columns)
|
77
102
|
end
|
78
103
|
|
79
104
|
def select_string_for_insert
|
80
105
|
columns = @columns_list.clone
|
81
106
|
str = get_columns_string(columns)
|
82
|
-
str << ",'#{DateTime.now.utc}'" if
|
83
|
-
str << ",'#{DateTime.now.utc}'" if
|
107
|
+
str << ",'#{DateTime.now.utc}'" if column_names.include?("created_at")
|
108
|
+
str << ",'#{DateTime.now.utc}'" if column_names.include?("updated_at")
|
84
109
|
str
|
85
110
|
end
|
86
111
|
|
@@ -95,16 +120,12 @@ module PostgresUpsert
|
|
95
120
|
columns.size > 0 ? "\"#{columns.join('","')}\"" : ""
|
96
121
|
end
|
97
122
|
|
98
|
-
def
|
99
|
-
|
100
|
-
connection.quote_table_name(@options[:table])
|
101
|
-
else
|
102
|
-
@klass.quoted_table_name
|
103
|
-
end
|
123
|
+
def quoted_table_name
|
124
|
+
@quoted_table_name ||= ActiveRecord::Base.connection.quote_table_name(@table_name)
|
104
125
|
end
|
105
126
|
|
106
127
|
def generate_temp_table_name
|
107
|
-
@temp_table_name = "#{@
|
128
|
+
@temp_table_name = "#{@table_name}_temp_#{rand(1000)}"
|
108
129
|
end
|
109
130
|
|
110
131
|
def read_input_line
|
@@ -126,7 +147,7 @@ module PostgresUpsert
|
|
126
147
|
|
127
148
|
def update_from_temp_table
|
128
149
|
ActiveRecord::Base.connection.execute <<-SQL
|
129
|
-
UPDATE #{
|
150
|
+
UPDATE #{quoted_table_name} AS d
|
130
151
|
#{update_set_clause}
|
131
152
|
FROM #{@temp_table_name} as t
|
132
153
|
WHERE t.#{@options[:key_column]} = d.#{@options[:key_column]}
|
@@ -138,7 +159,7 @@ module PostgresUpsert
|
|
138
159
|
command = @columns_list.map do |col|
|
139
160
|
"\"#{col}\" = t.\"#{col}\""
|
140
161
|
end
|
141
|
-
command << "\"updated_at\" = '#{DateTime.now.utc}'" if
|
162
|
+
command << "\"updated_at\" = '#{DateTime.now.utc}'" if column_names.include?("updated_at")
|
142
163
|
"SET #{command.join(',')}"
|
143
164
|
end
|
144
165
|
|
@@ -146,12 +167,12 @@ module PostgresUpsert
|
|
146
167
|
columns_string = columns_string_for_insert
|
147
168
|
select_string = select_string_for_insert
|
148
169
|
ActiveRecord::Base.connection.execute <<-SQL
|
149
|
-
INSERT INTO #{
|
170
|
+
INSERT INTO #{quoted_table_name} (#{columns_string})
|
150
171
|
SELECT #{select_string}
|
151
172
|
FROM #{@temp_table_name} as t
|
152
173
|
WHERE NOT EXISTS
|
153
174
|
(SELECT 1
|
154
|
-
FROM #{
|
175
|
+
FROM #{quoted_table_name} as d
|
155
176
|
WHERE d.#{@options[:key_column]} = t.#{@options[:key_column]})
|
156
177
|
AND t.#{@options[:key_column]} IS NOT NULL;
|
157
178
|
SQL
|
@@ -164,7 +185,7 @@ module PostgresUpsert
|
|
164
185
|
DROP TABLE IF EXISTS #{@temp_table_name};
|
165
186
|
|
166
187
|
CREATE TEMP TABLE #{@temp_table_name}
|
167
|
-
AS SELECT #{columns_string} FROM #{
|
188
|
+
AS SELECT #{columns_string} FROM #{quoted_table_name} WHERE 0 = 1;
|
168
189
|
SQL
|
169
190
|
end
|
170
191
|
|
data/postgres_upsert.gemspec
CHANGED