postgres_upsert 4.0.0 → 5.0.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 +8 -8
- data/.gitignore +2 -0
- data/.travis.yml +0 -4
- data/Gemfile.lock +7 -13
- data/README.md +12 -5
- data/db/migrate/20150710162236_create_composite_models_table.rb +9 -0
- data/db/schema.rb +22 -7
- data/lib/postgres_upsert/result.rb +14 -1
- data/lib/postgres_upsert/table_writer.rb +4 -0
- data/lib/postgres_upsert/writer.rb +51 -23
- data/postgres_upsert.gemspec +2 -2
- data/spec/composite_key_spec.rb +56 -0
- data/spec/fixtures/composite_key_model.rb +4 -0
- data/spec/fixtures/composite_key_with_header.csv +3 -0
- data/spec/fixtures/composite_nonkey_with_header.csv +3 -0
- data/spec/pg_upsert_csv_spec.rb +4 -5
- data/spec/spec_helper.rb +1 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NmI3N2Q0NmE4M2E3NjcxNzQxOTA2MDQ5NzAzMTZlMzk1Y2QzNmNlZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MjEwODZlMTFlOGIwNTk2NGE3Y2FjMThhYjM0ZDU1YTZkOTAzOWFlMA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MjQ5NTI0MzAyOWM0NTU3MmI2ZjBmYjMzNWJkZTcyYTdiOWNjNTk4MDYxMTdi
|
10
|
+
NDY3ZmQwNjRiNjE0YjE0ZDgyYzU0N2Q1NzhhZTcxNjRmZThiNjUyZTJkMTkw
|
11
|
+
NjY0NDI2ODU1OWYyNjA3ZmVlY2EwODRiMzBmYTNhYzQxODQ2ODk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZGIyNzNiZGUxOTNmZDVlNTQxMWRkNjk4OWYxZWUyNTQ2OTkzNGZlYzBjOGVj
|
14
|
+
NmY2NDNlZmZmNWYzZTEwZTEwZWEzMjAyYzE3ZGQyNjUyY2NjY2Q4NGFjODgw
|
15
|
+
MzY1ZjZlNjUwZjU4MmY3NDMwOGViMDhlNjJmZThhN2MyNjg3NGY=
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
postgres_upsert (
|
4
|
+
postgres_upsert (5.0.0)
|
5
5
|
activerecord (>= 3.0.0)
|
6
|
-
pg (
|
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.
|
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.
|
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.
|
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.
|
124
|
-
hike (~> 1.2)
|
125
|
-
multi_json (~> 1.0)
|
121
|
+
sprockets (3.2.0)
|
126
122
|
rack (~> 1.0)
|
127
|
-
|
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
|
-
- :
|
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
|
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 :
|
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", :
|
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,
|
134
|
+
PostgresUpsert.write User io, unique_key: "email"
|
128
135
|
end
|
129
136
|
puts time
|
130
137
|
end
|
data/db/schema.rb
CHANGED
@@ -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:
|
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
|
-
|
20
|
-
|
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
|
-
|
23
|
-
|
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
|
-
|
26
|
-
|
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
|
@@ -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
|
-
:
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
120
|
-
AND d
|
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 =
|
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
|
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
|
-
|
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
|
-
|
161
|
-
|
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
|
-
|
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
|
data/postgres_upsert.gemspec
CHANGED
@@ -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 = "
|
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", '
|
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
|
data/spec/pg_upsert_csv_spec.rb
CHANGED
@@ -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, :
|
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, :
|
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, :
|
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 =
|
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
|
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|
+
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
|