postgres_upsert 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OGQ4YTc4MTFmYzBjYzE1MWY3ODI3NGQ5Yjc5Njk4Mjk2MGJlZjdhNg==
4
+ NmI3N2Q0NmE4M2E3NjcxNzQxOTA2MDQ5NzAzMTZlMzk1Y2QzNmNlZQ==
5
5
  data.tar.gz: !binary |-
6
- ZmNhNzkxNDg4NzhlOWFhYjRjMWNkZDI5ZTMyMGQwMjZlMmM2ZjI4NQ==
6
+ MjEwODZlMTFlOGIwNTk2NGE3Y2FjMThhYjM0ZDU1YTZkOTAzOWFlMA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODU0N2IzZmM4ZDc1ODgzYzZmMDM1YzEyNTgwN2Y3MWUyMjI0ZmIxNjIzMjEy
10
- M2YyOGFlZjRiM2MzMjcwMTU2MzZjM2IyNWExNWQ3YTFiMzk4ZDIzYWY0MzZi
11
- ZTNmNGUwMDAxZDQxNGUwYjI4MTk0MWU3OWYxZDYwMzE5YmU0YjE=
9
+ MjQ5NTI0MzAyOWM0NTU3MmI2ZjBmYjMzNWJkZTcyYTdiOWNjNTk4MDYxMTdi
10
+ NDY3ZmQwNjRiNjE0YjE0ZDgyYzU0N2Q1NzhhZTcxNjRmZThiNjUyZTJkMTkw
11
+ NjY0NDI2ODU1OWYyNjA3ZmVlY2EwODRiMzBmYTNhYzQxODQ2ODk=
12
12
  data.tar.gz: !binary |-
13
- ZTVmMDBkMmFjZDRkNzIwZjI0MDNhNWRkZjlkMjg4YWU2YTI1MGM4NDVjMWY4
14
- MzI2NDE2MzMwOWQzY2Y3N2UwMjYxZDY1YzE4YTJkMDc2ZDg1M2MyZGVlN2Uz
15
- NzA0YjQ1YWUyNTBjMDhmNDNmZTNmYTNkZjE4ZmY0YTk2YWYxNzY=
13
+ ZGIyNzNiZGUxOTNmZDVlNTQxMWRkNjk4OWYxZWUyNTQ2OTkzNGZlYzBjOGVj
14
+ NmY2NDNlZmZmNWYzZTEwZTEwZWEzMjAyYzE3ZGQyNjUyY2NjY2Q4NGFjODgw
15
+ MzY1ZjZlNjUwZjU4MmY3NDMwOGViMDhlNjJmZThhN2MyNjg3NGY=
data/.gitignore CHANGED
@@ -9,6 +9,8 @@
9
9
  /test/version_tmp/
10
10
  /tmp/
11
11
  /log
12
+ .DS_Store
13
+ */.Ds_Store
12
14
 
13
15
  ## Specific to RubyMotion:
14
16
  .dat*
@@ -1,9 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.1.0
4
- - jruby-18mode
5
- - jruby-19mode
6
4
  - rbx-2
7
5
  - ruby-head
8
- - jruby-head
9
- - ree
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- postgres_upsert (4.0.0)
4
+ postgres_upsert (5.0.0)
5
5
  activerecord (>= 3.0.0)
6
- pg (~> 0.17.0)
6
+ pg (>= 0.17.0)
7
7
  rails (>= 3.0.0)
8
8
 
9
9
  GEM
@@ -49,9 +49,8 @@ GEM
49
49
  coderay (1.1.0)
50
50
  diff-lcs (1.1.3)
51
51
  erubis (2.7.0)
52
- globalid (0.3.3)
52
+ globalid (0.3.5)
53
53
  activesupport (>= 4.1.0)
54
- hike (1.2.3)
55
54
  i18n (0.7.0)
56
55
  json (1.8.2)
57
56
  loofah (2.0.1)
@@ -59,13 +58,12 @@ GEM
59
58
  mail (2.6.3)
60
59
  mime-types (>= 1.16, < 3)
61
60
  method_source (0.8.2)
62
- mime-types (2.4.3)
61
+ mime-types (2.6.1)
63
62
  mini_portile (0.6.2)
64
63
  minitest (5.5.1)
65
- multi_json (1.10.1)
66
64
  nokogiri (1.6.6.2)
67
65
  mini_portile (~> 0.6.0)
68
- pg (0.17.1)
66
+ pg (0.18.2)
69
67
  pry (0.10.1)
70
68
  coderay (~> 1.1.0)
71
69
  method_source (~> 0.8.1)
@@ -120,18 +118,14 @@ GEM
120
118
  rspec-expectations (~> 2.99.0)
121
119
  rspec-mocks (~> 2.99.0)
122
120
  slop (3.6.0)
123
- sprockets (2.12.3)
124
- hike (~> 1.2)
125
- multi_json (~> 1.0)
121
+ sprockets (3.2.0)
126
122
  rack (~> 1.0)
127
- tilt (~> 1.1, != 1.3.0)
128
- sprockets-rails (2.2.4)
123
+ sprockets-rails (2.3.2)
129
124
  actionpack (>= 3.0)
130
125
  activesupport (>= 3.0)
131
126
  sprockets (>= 2.8, < 4.0)
132
127
  thor (0.19.1)
133
128
  thread_safe (0.3.4)
134
- tilt (1.4.1)
135
129
  tzinfo (1.2.2)
136
130
  thread_safe (~> 0.1)
137
131
 
data/README.md CHANGED
@@ -28,7 +28,7 @@ PostgresUpsert.write <class_or_table_name>, <io_object_or_file_path>[, options]
28
28
  options:
29
29
  - :delimiter - the string to use to delimit fields from the source data. Default is ","
30
30
  - :header => specifies if the file/io source contains a header row. Either :header option must be true, or :columns list must be passed. Default true
31
- - :key_column => the primary key or unique key column on your destination table, used to distinguish new records from existing records. Default is the primary_key of your destination table/model.
31
+ - :unique_key => the primary key or unique key column (or composite key columns) on your destination table, used to distinguish new records from existing records. Default is the primary_key of your destination table/model.
32
32
  - :update_only => when true, postgres_upsert will ONLY update existing records, and not insert new. Default is false.
33
33
 
34
34
  ## Examples
@@ -66,16 +66,23 @@ currently postgres_upsert detects and manages the default rails timestamp column
66
66
  * records that are in the destination table but not the source will not have their timestamps changed.
67
67
 
68
68
 
69
- ### Overriding the key_column
69
+ ### Overriding the unique_key
70
70
 
71
- By default postgres_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:
71
+ By default postgres_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 :unique_key option:
72
72
 
73
73
  ```ruby
74
- PostgresUpsert.write User "/tmp/users.csv", :key_column => ["external_twitter_id"]
74
+ PostgresUpsert.write User "/tmp/users.csv", :unique_key => ["external_twitter_id"]
75
75
  ```
76
76
 
77
77
  obviously, the field you pass must be a unique key in your database (this is not enforced at the moment, but will be)
78
78
 
79
+ If your source data does not contain the primary key, or an individual unique key, you can pass multiple columns in the unique_key option:
80
+
81
+ ```ruby
82
+ PostgresUpsert.write User "/tmp/users.csv", :unique_key => ["state_id_numer", "state_name"]
83
+ ```
84
+ As long as combined columns represent a unique value, row, we can successfully upsert.
85
+
79
86
  passing :update_only => true will ensure that no new records are created, but records will be updated.
80
87
 
81
88
  ### Insert/Update Counts
@@ -124,7 +131,7 @@ def insert_smart
124
131
  end
125
132
  end
126
133
  io = StringIO.new(csv_string)
127
- PostgresUpsert.write User io, key_column: "email"
134
+ PostgresUpsert.write User io, unique_key: "email"
128
135
  end
129
136
  puts time
130
137
  end
@@ -0,0 +1,9 @@
1
+ class CreateCompositeModelsTable < ActiveRecord::Migration
2
+ def change
3
+ create_table :composite_key_models do |t|
4
+ t.integer :comp_key_1
5
+ t.integer :comp_key_2
6
+ t.string :data
7
+ end
8
+ end
9
+ end
@@ -11,18 +11,33 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20150214192135) do
14
+ ActiveRecord::Schema.define(version: 20150710162236) do
15
15
 
16
16
  # These are extensions that must be enabled in order to support this database
17
17
  enable_extension "plpgsql"
18
18
 
19
- # Could not dump table "reserved_word_models" because of following NoMethodError
20
- # undefined method `[]' for nil:NilClass
19
+ create_table "composite_key_models", force: :cascade do |t|
20
+ t.integer "comp_key_1"
21
+ t.integer "comp_key_2"
22
+ t.string "data"
23
+ end
21
24
 
22
- # Could not dump table "test_models" because of following NoMethodError
23
- # undefined method `[]' for nil:NilClass
25
+ create_table "reserved_word_models", force: :cascade do |t|
26
+ t.string "select", limit: 255
27
+ t.string "group", limit: 255
28
+ end
24
29
 
25
- # Could not dump table "three_columns" because of following NoMethodError
26
- # undefined method `[]' for nil:NilClass
30
+ create_table "test_models", force: :cascade do |t|
31
+ t.string "data", limit: 255
32
+ t.datetime "created_at"
33
+ t.datetime "updated_at"
34
+ end
35
+
36
+ create_table "three_columns", force: :cascade do |t|
37
+ t.string "data", limit: 255
38
+ t.string "extra", limit: 255
39
+ t.datetime "created_at"
40
+ t.datetime "updated_at"
41
+ end
27
42
 
28
43
  end
@@ -2,9 +2,22 @@ module PostgresUpsert
2
2
  class Result
3
3
  attr_reader :inserted, :updated
4
4
 
5
- def initialize(insert_result, update_result)
5
+ def initialize(insert_result, update_result, copy_result)
6
6
  @inserted = insert_result ? insert_result.cmd_tuples : 0
7
7
  @updated = update_result ? update_result.cmd_tuples : 0
8
+ @copied = copy_result ? copy_result.cmd_tuples : 0
9
+ end
10
+
11
+ def changed_rows
12
+ @inserted + @updated
13
+ end
14
+
15
+ def copied_rows
16
+ @copied
17
+ end
18
+
19
+ def updated_rows
20
+ @updated
8
21
  end
9
22
  end
10
23
  end
@@ -10,6 +10,10 @@ module PostgresUpsert
10
10
 
11
11
  private
12
12
 
13
+ def database_connection
14
+ ActiveRecord::Base.connection
15
+ end
16
+
13
17
  def primary_key
14
18
  @primary_key ||= begin
15
19
  query = <<-sql
@@ -4,17 +4,18 @@ module PostgresUpsert
4
4
  def initialize(klass, source, options = {})
5
5
  @klass = klass
6
6
  @options = options.reverse_merge({
7
- :delimiter => ",",
8
- :header => true,
9
- :key_column => primary_key,
7
+ :delimiter => ",",
8
+ :header => true,
9
+ :unique_key => [primary_key],
10
10
  :update_only => false})
11
+ @options[:unique_key] = Array.wrap(@options[:unique_key])
11
12
  @source = source.instance_of?(String) ? File.open(source, 'r') : source
12
13
  @columns_list = get_columns
13
14
  generate_temp_table_name
14
15
  end
15
16
 
16
17
  def write
17
- if @columns_list.empty?
18
+ if @columns_list.empty?
18
19
  raise "Either the :columns option or :header => true are required"
19
20
  end
20
21
 
@@ -24,21 +25,37 @@ module PostgresUpsert
24
25
  columns_string = columns_string_for_copy
25
26
  create_temp_table
26
27
 
27
- ActiveRecord::Base.connection.raw_connection.copy_data %{COPY #{copy_table} #{columns_string} FROM STDIN #{csv_options}} do
28
+ @copy_result = database_connection.raw_connection.copy_data %{COPY #{copy_table} #{columns_string} FROM STDIN #{csv_options}} do
28
29
 
29
30
  while line = @source.gets do
30
31
  next if line.strip.size == 0
31
- ActiveRecord::Base.connection.raw_connection.put_copy_data line
32
+ database_connection.raw_connection.put_copy_data line
32
33
  end
33
34
  end
34
35
 
35
36
  upsert_from_temp_table
36
37
  drop_temp_table
37
- PostgresUpsert::Result.new(@insert_result, @update_result)
38
+
39
+ summarize_results
38
40
  end
39
41
 
40
42
  private
41
43
 
44
+ def database_connection
45
+ @klass.connection
46
+ end
47
+
48
+ def summarize_results
49
+ result = PostgresUpsert::Result.new(@insert_result, @update_result, @copy_result)
50
+ expected_rows = @options[:update_only] ? result.updated_rows : result.copied_rows
51
+
52
+ if result.changed_rows != expected_rows
53
+ raise "#{expected_rows} rows were copied, but #{result.changed_rows} were upserted to destination table. Check to make sure your key is unique."
54
+ end
55
+
56
+ return result
57
+ end
58
+
42
59
  def primary_key
43
60
  @klass.primary_key
44
61
  end
@@ -93,7 +110,9 @@ module PostgresUpsert
93
110
 
94
111
  def select_string_for_create
95
112
  columns = @columns_list.map(&:to_sym)
96
- columns << @options[:key_column].to_sym unless columns.include?(@options[:key_column].to_sym)
113
+ @options[:unique_key].each do |key_component|
114
+ columns << key_component.to_sym unless columns.include?(key_component.to_sym)
115
+ end
97
116
  get_columns_string(columns)
98
117
  end
99
118
 
@@ -112,12 +131,12 @@ module PostgresUpsert
112
131
  end
113
132
 
114
133
  def update_from_temp_table
115
- @update_result = ActiveRecord::Base.connection.execute <<-SQL
134
+ @update_result = database_connection.execute <<-SQL
116
135
  UPDATE #{quoted_table_name} AS d
117
136
  #{update_set_clause}
118
137
  FROM #{@temp_table_name} as t
119
- WHERE t.#{@options[:key_column]} = d.#{@options[:key_column]}
120
- AND d.#{@options[:key_column]} IS NOT NULL;
138
+ WHERE #{unique_key_select("t", "d")}
139
+ AND #{unique_key_present("d")}
121
140
  SQL
122
141
  end
123
142
 
@@ -132,39 +151,48 @@ module PostgresUpsert
132
151
  def insert_from_temp_table
133
152
  columns_string = columns_string_for_insert
134
153
  select_string = select_string_for_insert
135
- @insert_result = ActiveRecord::Base.connection.execute <<-SQL
154
+ @insert_result = database_connection.execute <<-SQL
136
155
  INSERT INTO #{quoted_table_name} (#{columns_string})
137
156
  SELECT #{select_string}
138
157
  FROM #{@temp_table_name} as t
139
- WHERE NOT EXISTS
140
- (SELECT 1
141
- FROM #{quoted_table_name} as d
142
- WHERE d.#{@options[:key_column]} = t.#{@options[:key_column]})
143
- AND t.#{@options[:key_column]} IS NOT NULL;
158
+ WHERE NOT EXISTS
159
+ (SELECT 1
160
+ FROM #{quoted_table_name} as d
161
+ WHERE #{unique_key_select("t", "d")});
144
162
  SQL
145
163
  end
146
164
 
165
+ def unique_key_select(source, dest)
166
+ @options[:unique_key].map {|field| "#{source}.#{field} = #{dest}.#{field}"}.join(' AND ')
167
+ end
168
+
169
+ def unique_key_present(source)
170
+ @options[:unique_key].map {|field| "#{source}.#{field} IS NOT NULL"}.join(' AND ')
171
+ end
172
+
147
173
  def create_temp_table
148
174
  columns_string = select_string_for_create
149
175
  verify_temp_has_key
150
- ActiveRecord::Base.connection.execute <<-SQL
176
+ database_connection.execute <<-SQL
151
177
  SET client_min_messages=WARNING;
152
178
  DROP TABLE IF EXISTS #{@temp_table_name};
153
179
 
154
- CREATE TEMP TABLE #{@temp_table_name}
180
+ CREATE TEMP TABLE #{@temp_table_name}
155
181
  AS SELECT #{columns_string} FROM #{quoted_table_name} WHERE 0 = 1;
156
182
  SQL
157
183
  end
158
184
 
159
185
  def verify_temp_has_key
160
- unless @columns_list.include?(@options[:key_column].to_s)
161
- raise "Expected a unique column '#{@options[:key_column]}' but the source data does not include this column. Update the :columns list or explicitly set the :key_column option.}"
186
+ @options[:unique_key].each do |key_component|
187
+ unless @columns_list.include?(key_component.to_s)
188
+ raise "Expected a unique column '#{key_component}' but the source data does not include this column. Update the :columns list or explicitly set the unique_key option.}"
189
+ end
162
190
  end
163
191
  end
164
192
 
165
193
  def drop_temp_table
166
- ActiveRecord::Base.connection.execute <<-SQL
167
- DROP TABLE #{@temp_table_name}
194
+ database_connection.execute <<-SQL
195
+ DROP TABLE #{@temp_table_name}
168
196
  SQL
169
197
  end
170
198
  end
@@ -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 = "4.0.0"
8
+ s.version = "5.0.0"
9
9
 
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.required_ruby_version = ">= 1.8.7"
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.require_paths = ["lib"]
23
23
  s.summary = "A rubygem that integrates with ActiveRecord to insert/update large data sets into the database efficiently"
24
24
 
25
- s.add_dependency "pg", '~> 0.17.0'
25
+ s.add_dependency "pg", '>= 0.17.0'
26
26
  s.add_dependency "activerecord", '>= 3.0.0'
27
27
  s.add_dependency "rails", '>= 3.0.0'
28
28
  s.add_development_dependency "bundler"
@@ -0,0 +1,56 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "pg_upsert from file with CSV format" do
4
+ before(:each) do
5
+ ActiveRecord::Base.connection.execute %{
6
+ TRUNCATE TABLE composite_key_models;
7
+ SELECT setval('composite_key_models_id_seq', 1, false);
8
+ }
9
+ end
10
+
11
+ before do
12
+ DateTime.stub_chain(:now, :utc).and_return (DateTime.parse("2012-01-01").utc)
13
+ end
14
+
15
+ def timestamp
16
+ DateTime.now.utc
17
+ end
18
+
19
+ context 'composite_key_support' do
20
+ it 'inserts records if the passed match composite key doesnt exist' do
21
+ file = File.open(File.expand_path('spec/fixtures/composite_key_with_header.csv'), 'r')
22
+
23
+ PostgresUpsert.write(CompositeKeyModel, file, :unique_key => ["comp_key_1", "comp_key_2"])
24
+ expect(
25
+ CompositeKeyModel.last.attributes
26
+ ).to include("data" => "test data 2")
27
+ end
28
+
29
+ it 'updates records if the passed composite key exists' do
30
+ file = File.open(File.expand_path('spec/fixtures/composite_key_with_header.csv'), 'r')
31
+ existing = CompositeKeyModel.create(comp_key_1: 2, comp_key_2:3, data: "old stuff")
32
+
33
+ PostgresUpsert.write(CompositeKeyModel, file, :unique_key => ["comp_key_1", "comp_key_2"])
34
+
35
+ expect(
36
+ CompositeKeyModel.find_by({comp_key_1: 2, comp_key_2:3}).attributes
37
+ ).to include("data" => "test data 2")
38
+
39
+ expect(
40
+ CompositeKeyModel.find_by({comp_key_1: 1, comp_key_2:2}).attributes
41
+ ).to include("data" => "test data 1")
42
+ end
43
+
44
+ it 'fails if composite keys are not unique.' do
45
+ file = File.open(File.expand_path('spec/fixtures/composite_nonkey_with_header.csv'), 'r')
46
+ existing = CompositeKeyModel.create(comp_key_1: 1, comp_key_2:2, data: "old stuff")
47
+
48
+ expect{
49
+ PostgresUpsert.write(CompositeKeyModel, file, :unique_key => ["comp_key_1", "comp_key_2"])
50
+ }.to raise_error(/Check to make sure your key is unique/)
51
+ end
52
+
53
+ end
54
+
55
+
56
+ end
@@ -0,0 +1,4 @@
1
+ require 'postgres_upsert'
2
+
3
+ class CompositeKeyModel < ActiveRecord::Base
4
+ end
@@ -0,0 +1,3 @@
1
+ comp_key_1,comp_key_2,data
2
+ 1,2,test data 1
3
+ 2,3,test data 2
@@ -0,0 +1,3 @@
1
+ comp_key_1,comp_key_2,data
2
+ 1,2,test data 1
3
+ 1,2,test data 4
@@ -173,7 +173,7 @@ describe "pg_upsert from file with CSV format" do
173
173
  three_col = ThreeColumn.create(id: 1, data: "old stuff", extra: "neva change!")
174
174
  file = File.open(File.expand_path('spec/fixtures/no_id.csv'), 'r')
175
175
 
176
- PostgresUpsert.write(ThreeColumn, file, :key_column => "data")
176
+ PostgresUpsert.write(ThreeColumn, file, :unique_key => "data")
177
177
  expect(
178
178
  three_col.reload.extra
179
179
  ).to eq("ABC: Always Be Changing.")
@@ -182,7 +182,7 @@ describe "pg_upsert from file with CSV format" do
182
182
  it 'inserts records if the passed match column doesnt exist' do
183
183
  file = File.open(File.expand_path('spec/fixtures/no_id.csv'), 'r')
184
184
 
185
- PostgresUpsert.write(ThreeColumn, file, :key_column => "data")
185
+ PostgresUpsert.write(ThreeColumn, file, :unique_key => "data")
186
186
  expect(
187
187
  ThreeColumn.last.attributes
188
188
  ).to include("data" => "old stuff", "extra" => "ABC: Always Be Changing.")
@@ -191,7 +191,7 @@ describe "pg_upsert from file with CSV format" do
191
191
  it 'allows key column to be a string or symbol' do
192
192
  file = File.open(File.expand_path('spec/fixtures/no_id.csv'), 'r')
193
193
 
194
- PostgresUpsert.write(ThreeColumn, file, :header => true, :key_column => :data)
194
+ PostgresUpsert.write(ThreeColumn, file, :header => true, :unique_key => :data)
195
195
  expect(
196
196
  ThreeColumn.last.attributes
197
197
  ).to include("data" => "old stuff", "extra" => "ABC: Always Be Changing.")
@@ -247,7 +247,7 @@ describe "pg_upsert from file with CSV format" do
247
247
 
248
248
  it "should still report results" do
249
249
  TestModel.create(data: "test data 1")
250
- result = result = PostgresUpsert.write TestModel.table_name, File.expand_path('spec/fixtures/tab_with_two_lines.csv'), :delimiter => "\t"
250
+ result = PostgresUpsert.write TestModel.table_name, File.expand_path('spec/fixtures/tab_with_two_lines.csv'), :delimiter => "\t"
251
251
 
252
252
  expect(
253
253
  result.updated
@@ -258,7 +258,6 @@ describe "pg_upsert from file with CSV format" do
258
258
  ).to eq(1)
259
259
  end
260
260
 
261
-
262
261
  end
263
262
  end
264
263
 
@@ -4,6 +4,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
4
  require 'fixtures/test_model'
5
5
  require 'fixtures/three_column'
6
6
  require 'fixtures/reserved_word_model'
7
+ require 'fixtures/composite_key_model'
7
8
  require 'rspec'
8
9
  require 'rspec/rails'
9
10
  require 'rspec/autorun'
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: 4.0.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Mitchell
@@ -14,14 +14,14 @@ dependencies:
14
14
  name: pg
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - ! '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.17.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - ! '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.17.0
27
27
  - !ruby/object:Gem::Dependency
@@ -139,6 +139,7 @@ files:
139
139
  - config/routes.rb
140
140
  - config/secrets.yml
141
141
  - db/migrate/20150214192135_create_test_tables.rb
142
+ - db/migrate/20150710162236_create_composite_models_table.rb
142
143
  - db/schema.rb
143
144
  - db/seeds.rb
144
145
  - lib/postgres_upsert.rb
@@ -146,10 +147,14 @@ files:
146
147
  - lib/postgres_upsert/table_writer.rb
147
148
  - lib/postgres_upsert/writer.rb
148
149
  - postgres_upsert.gemspec
150
+ - spec/composite_key_spec.rb
149
151
  - spec/fixtures/comma_with_header.csv
150
152
  - spec/fixtures/comma_with_header_and_comma_values.csv
151
153
  - spec/fixtures/comma_with_header_and_unquoted_comma.csv
152
154
  - spec/fixtures/comma_without_header.csv
155
+ - spec/fixtures/composite_key_model.rb
156
+ - spec/fixtures/composite_key_with_header.csv
157
+ - spec/fixtures/composite_nonkey_with_header.csv
153
158
  - spec/fixtures/no_id.csv
154
159
  - spec/fixtures/reserved_word_model.rb
155
160
  - spec/fixtures/reserved_words.csv
@@ -190,10 +195,14 @@ specification_version: 4
190
195
  summary: A rubygem that integrates with ActiveRecord to insert/update large data sets
191
196
  into the database efficiently
192
197
  test_files:
198
+ - spec/composite_key_spec.rb
193
199
  - spec/fixtures/comma_with_header.csv
194
200
  - spec/fixtures/comma_with_header_and_comma_values.csv
195
201
  - spec/fixtures/comma_with_header_and_unquoted_comma.csv
196
202
  - spec/fixtures/comma_without_header.csv
203
+ - spec/fixtures/composite_key_model.rb
204
+ - spec/fixtures/composite_key_with_header.csv
205
+ - spec/fixtures/composite_nonkey_with_header.csv
197
206
  - spec/fixtures/no_id.csv
198
207
  - spec/fixtures/reserved_word_model.rb
199
208
  - spec/fixtures/reserved_words.csv