postgres_upsert 1.0.0 → 1.1.0

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: 00a22a21bea95bc98d7a991c5ed30a5bbea6a67c
4
- data.tar.gz: 9824edf28ac08e7a8aed28ebcdee8c07c46ffa11
3
+ metadata.gz: a30c825147ef323c1e0d60d9fc08e9668b6bdf02
4
+ data.tar.gz: d3f8799b61a273b4abde1eae7a6b38eea3ba614c
5
5
  SHA512:
6
- metadata.gz: b6183d68e0791491f6417ffbc99b7f2a984090aa3640f1348cfe74e39e11011edce3985029b259bd28296fc7725ad4def14db3f209d95b15f7324d2ebb5dbba3
7
- data.tar.gz: 4dd39aa87168d5866874de9c6a11097731e015bbdea624535164f413cf1fabb7c9fbca73612c805289db800383d134c5e88f1198efe2cc9d7d365a72f4f2a9be
6
+ metadata.gz: 07649b13cae7be995e12c02e5418bde744f932127587141a160bd09f502f9342f2ce5f2038d20953eed9425043f67c056dde96dec78ed5a8fcf5ec0c11392bea
7
+ data.tar.gz: e963592a3c91c61d206d018cbcc63aa07995a50165c97dbb88e9352e8b16c76cdcbaef85a9c9b655716d0e0ab387c9c155bf1890200374ce074e5405899929fd
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- postgres_upsert (0.1.0)
4
+ postgres_upsert (1.0.0)
5
5
  activerecord (>= 3.0.0)
6
6
  pg (~> 0.17.0)
7
7
  rails (>= 3.0.0)
data/README.md CHANGED
@@ -75,6 +75,17 @@ This merge/upsert happend in 5 steps (assume your data table is called "users")
75
75
  * issue a query to update all records in users with the data in users_temp_### (matching on primary key)
76
76
  * drop the temp table.
77
77
 
78
+ ### overriding the key_column
79
+
80
+ By default pg_upsert uses the primary key on your ActiveRecord table to determine if each record should be inserted or updated. You can override the column using the :key_field option:
81
+
82
+ ```ruby
83
+ User.pg_upsert "/tmp/users.dat", :format => :binary, :key_column => ["external_twitter_id"]
84
+ ```
85
+
86
+ obviously, the field you pass must be a unique key in your database (this is not enforced at the moment, but will be)
87
+
88
+
78
89
  ## Note on Patches/Pull Requests
79
90
 
80
91
  * Fork the project
@@ -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
- options.reverse_merge!({:delimiter => ",", :format => :csv, :header => true})
10
+ options.reverse_merge!({:delimiter => ",", :format => :csv, :header => true, :key_column => primary_key})
11
11
  options_string = options[:format] == :binary ? "BINARY" : "DELIMITER '#{options[:delimiter]}' CSV"
12
12
 
13
13
  io = path_or_io.instance_of?(String) ? File.open(path_or_io, 'r') : path_or_io
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  destination_table = get_table_name(options)
21
21
 
22
22
  columns_string = columns_string_for_copy(columns_list)
23
- create_temp_table(copy_table, destination_table, columns_list) if destination_table
23
+ create_temp_table(copy_table, destination_table, columns_list, options) if destination_table
24
24
 
25
25
  connection.raw_connection.copy_data %{COPY #{copy_table} #{columns_string} FROM STDIN #{options_string}} do
26
26
  if block_given?
@@ -33,7 +33,7 @@ module ActiveRecord
33
33
  end
34
34
 
35
35
  if destination_table
36
- upsert_from_temp_table(copy_table, destination_table, columns_list)
36
+ upsert_from_temp_table(copy_table, destination_table, columns_list, options)
37
37
  drop_temp_table(copy_table)
38
38
  end
39
39
  end
@@ -80,9 +80,9 @@ module ActiveRecord
80
80
  str
81
81
  end
82
82
 
83
- def self.select_string_for_create(columns_list)
83
+ def self.select_string_for_create(columns_list, options)
84
84
  columns = columns_list.map(&:to_sym)
85
- columns << primary_key.to_sym unless columns.include?(primary_key.to_sym)
85
+ columns << options[:key_column].to_sym unless columns.include?(options[:key_column].to_sym)
86
86
  get_columns_string(columns)
87
87
  end
88
88
 
@@ -119,18 +119,18 @@ module ActiveRecord
119
119
  end
120
120
  end
121
121
 
122
- def self.upsert_from_temp_table(temp_table, dest_table, columns_list)
123
- update_from_temp_table(temp_table, dest_table, columns_list)
124
- insert_from_temp_table(temp_table, dest_table, columns_list)
122
+ def self.upsert_from_temp_table(temp_table, dest_table, columns_list, options)
123
+ update_from_temp_table(temp_table, dest_table, columns_list, options)
124
+ insert_from_temp_table(temp_table, dest_table, columns_list, options)
125
125
  end
126
126
 
127
- def self.update_from_temp_table(temp_table, dest_table, columns_list)
127
+ def self.update_from_temp_table(temp_table, dest_table, columns_list, options)
128
128
  ActiveRecord::Base.connection.execute <<-SQL
129
129
  UPDATE #{dest_table} AS d
130
130
  #{update_set_clause(columns_list)}
131
131
  FROM #{temp_table} as t
132
- WHERE t.#{primary_key} = d.#{primary_key}
133
- AND d.#{primary_key} IS NOT NULL;
132
+ WHERE t.#{options[:key_column]} = d.#{options[:key_column]}
133
+ AND d.#{options[:key_column]} IS NOT NULL;
134
134
  SQL
135
135
  end
136
136
 
@@ -142,7 +142,7 @@ module ActiveRecord
142
142
  "SET #{command.join(',')}"
143
143
  end
144
144
 
145
- def self.insert_from_temp_table(temp_table, dest_table, columns_list)
145
+ def self.insert_from_temp_table(temp_table, dest_table, columns_list, options)
146
146
  columns_string = columns_string_for_insert(columns_list)
147
147
  select_string = select_string_for_insert(columns_list)
148
148
  ActiveRecord::Base.connection.execute <<-SQL
@@ -152,13 +152,13 @@ module ActiveRecord
152
152
  WHERE NOT EXISTS
153
153
  (SELECT 1
154
154
  FROM #{dest_table} as d
155
- WHERE d.#{primary_key} = t.#{primary_key})
156
- AND t.#{primary_key} IS NOT NULL;
155
+ WHERE d.#{options[:key_column]} = t.#{options[:key_column]})
156
+ AND t.#{options[:key_column]} IS NOT NULL;
157
157
  SQL
158
158
  end
159
159
 
160
- def self.create_temp_table(temp_table, dest_table, columns_list)
161
- columns_string = select_string_for_create(columns_list)
160
+ def self.create_temp_table(temp_table, dest_table, columns_list, options)
161
+ columns_string = select_string_for_create(columns_list, options)
162
162
  ActiveRecord::Base.connection.execute <<-SQL
163
163
  SET client_min_messages=WARNING;
164
164
  DROP TABLE IF EXISTS #{temp_table};
@@ -5,7 +5,7 @@ $:.unshift lib unless $:.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "postgres_upsert"
8
- s.version = "1.0.0"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.required_ruby_version = ">= 1.8.7"
@@ -0,0 +1,2 @@
1
+ data,extra
2
+ old stuff,ABC: Always Be Changing.
@@ -4,6 +4,7 @@ describe "pg_upsert from file with CSV format" do
4
4
  before(:each) do
5
5
  ActiveRecord::Base.connection.execute %{
6
6
  TRUNCATE TABLE test_models;
7
+ TRUNCATE TABLE three_columns;
7
8
  SELECT setval('test_models_id_seq', 1, false);
8
9
  }
9
10
  end
@@ -183,5 +184,27 @@ describe "pg_upsert from file with CSV format" do
183
184
  ).to eq('id' => 1, 'data' => 'test data 1', 'extra' => "neva change!", 'created_at' => original_created_at, 'updated_at' => timestamp)
184
185
  end
185
186
  end
187
+
188
+ context 'overriding the comparison column' do
189
+ it 'updates records based the match column option if its passed in' do
190
+ three_col = ThreeColumn.create(id: 1, data: "old stuff", extra: "neva change!")
191
+ file = File.open(File.expand_path('spec/fixtures/no_id.csv'), 'r')
192
+
193
+
194
+ ThreeColumn.pg_upsert(file, :key_column => "data")
195
+ expect(
196
+ three_col.reload.extra
197
+ ).to eq("ABC: Always Be Changing.")
198
+ end
199
+
200
+ it 'inserts records if the passed match column doesnt exist' do
201
+ file = File.open(File.expand_path('spec/fixtures/no_id.csv'), 'r')
202
+
203
+ ThreeColumn.pg_upsert(file, :key_column => "data")
204
+ expect(
205
+ ThreeColumn.last.attributes
206
+ ).to include("id" => 1, "data" => "old stuff", "extra" => "ABC: Always Be Changing.")
207
+ end
208
+ end
186
209
  end
187
210
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postgres_upsert
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Mitchell
@@ -130,6 +130,7 @@ files:
130
130
  - spec/fixtures/comma_with_header_and_comma_values.csv
131
131
  - spec/fixtures/comma_with_header_and_unquoted_comma.csv
132
132
  - spec/fixtures/comma_without_header.csv
133
+ - spec/fixtures/no_id.csv
133
134
  - spec/fixtures/reserved_word_model.rb
134
135
  - spec/fixtures/reserved_words.csv
135
136
  - spec/fixtures/semicolon_with_different_header.csv
@@ -176,6 +177,7 @@ test_files:
176
177
  - spec/fixtures/comma_with_header_and_comma_values.csv
177
178
  - spec/fixtures/comma_with_header_and_unquoted_comma.csv
178
179
  - spec/fixtures/comma_without_header.csv
180
+ - spec/fixtures/no_id.csv
179
181
  - spec/fixtures/reserved_word_model.rb
180
182
  - spec/fixtures/reserved_words.csv
181
183
  - spec/fixtures/semicolon_with_different_header.csv