active_record_upsert 0.6.3 → 0.7.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: 385757b53b221b5a937972a8fae3fddc3b8d7961
4
- data.tar.gz: 85c767dfb3b0256dc87e0957067d7324fca7239e
3
+ metadata.gz: 861dbd4abac80eae38c3644d5a982f3b4c7d95a8
4
+ data.tar.gz: fe700280c47b2cff78e3f8eeed2a14d966a10b72
5
5
  SHA512:
6
- metadata.gz: d37843428c375432fe428096d17d9e9aa5f3c7cb5a866eb0b28a3956d5bcb79db515b6941212eaae67b9b8c2df1f4667e5c7e307f375d8d233754bfaaa3c39df
7
- data.tar.gz: 6a47e3bfb52cd8fa1ea29650c044fa8d747e1c9ec695e54c6ed4146bafb08572fc377393d57a333fe248dd433eb621a2a875ef6618f012fd1aae49797a7625b0
6
+ metadata.gz: 3254084380ac0b9a14189ed071f53ec45e74d2701962b892720839d93b2855156e684f26e025742d19e8575031b3062e662c034bc19705caacabfafddde1a6ad
7
+ data.tar.gz: 859f1a55e2f6f2b64f192f18f305ae634fc50b4d24475a01bd5d0049cf4ad6d70cb931bd7215d4cfae492941046c04b4f15ca7a907fc2bbe844635bec5a0e340
data/README.md CHANGED
@@ -40,21 +40,40 @@ Or install it yourself as:
40
40
  ## Usage
41
41
  Just use `ActiveRecord.upsert` or `ActiveRecord#upsert`.
42
42
  *ActiveRecordUpsert* respects timestamps.
43
-
44
- ```
43
+
44
+ ```ruby
45
45
  class MyRecord < ActiveRecord::Base
46
46
  end
47
47
 
48
48
  MyRecord.create(name: 'foo', wisdom: 1)
49
- => #<MyRecord id: 1, name: "foo", created_at: "2016-02-20 14:15:55", updated_at: "2016-02-20 14:15:55", wisdom: 1>
49
+ # => #<MyRecord id: 1, name: "foo", created_at: "2016-02-20 14:15:55", updated_at: "2016-02-20 14:15:55", wisdom: 1>
50
50
 
51
51
  MyRecord.upsert(id: 1, wisdom: 3)
52
- => #<MyRecord id: 2, name: "foo", created_at: "2016-02-20 14:15:55", updated_at: "2016-02-20 14:18:15", wisdom: 3>
52
+ # => #<MyRecord id: 1, name: "foo", created_at: "2016-02-20 14:15:55", updated_at: "2016-02-20 14:18:15", wisdom: 3>
53
53
 
54
54
  r = MyRecord.new(id: 1)
55
55
  r.name = 'bar'
56
56
  r.upsert
57
- => #<MyRecord id: 2, name: "bar", created_at: "2016-02-20 14:17:50", updated_at: "2016-02-20 14:18:49", wisdom: 3>
57
+ # => #<MyRecord id: 1, name: "bar", created_at: "2016-02-20 14:15:55", updated_at: "2016-02-20 14:18:49", wisdom: 3>
58
+ ```
59
+
60
+ Also, it's possible to specify which columns should be used for the conflict clause. **These must comprise a unique index in Postgres.**
61
+
62
+ ```ruby
63
+ class Vehicle < ActiveRecord::Base
64
+ upsert_keys [:make, :name]
65
+ end
66
+
67
+ Vehicle.upsert(make: 'Ford', name: 'F-150', doors: 4)
68
+ # => #<Vehicle id: 1, make: 'Ford', name: 'Focus', doors: 2>
69
+
70
+ Vehicle.create(make: 'Ford', name: 'Focus', doors: 4)
71
+ # => #<Vehicle id: 2, make: 'Ford', name: 'Focus', doors: 4>
72
+
73
+ r = Vehicle.new(make: 'Ford', name: 'F-150')
74
+ r.doors = 2
75
+ r.upsert
76
+ # => #<Vehicle id: 1, make: 'Ford', name: 'Focus', doors: 2>
58
77
  ```
59
78
 
60
79
  ## Tests
@@ -77,3 +96,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/jesjos
77
96
  - Jens Nockert
78
97
  - Olle Jonsson
79
98
  - Simon Dahlbacka
99
+ - Paul Hoffer
@@ -12,21 +12,15 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = %q{Real PostgreSQL 9.5+ upserts using ON CONFLICT for ActiveRecord}
14
14
 
15
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(bin|test|spec|features)/}) } -
16
+ %w[.gitignore .rspec .travis.yml Dockerfile Gemfile Gemfile.docker docker-compose.yml]
16
17
  spec.bindir = "exe"
17
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
19
  spec.require_paths = ["lib"]
19
20
 
20
- spec.add_runtime_dependency 'activerecord', '>= 5.0', '< 5.1'
21
- spec.add_runtime_dependency "arel", "~>7.0"
22
-
23
21
  spec.platform = Gem::Platform::RUBY
24
- spec.add_runtime_dependency 'pg', '~> 0.18'
25
22
 
26
- spec.add_development_dependency "bundler", ">= 1.13"
27
- spec.add_development_dependency "rake", ">= 10.0"
28
- spec.add_development_dependency "rspec", ">= 3.0", "< 4"
29
- spec.add_development_dependency "pry", "> 0"
30
- spec.add_development_dependency "database_cleaner", "~> 1.5.3"
31
- spec.add_development_dependency 'rails', '>= 5.0', '< 5.1'
23
+ spec.add_runtime_dependency 'activerecord', '>= 5.0', '< 5.2'
24
+ spec.add_runtime_dependency 'arel', '> 7.0', '< 9.0'
25
+ spec.add_runtime_dependency 'pg', '~> 0.18'
32
26
  end
@@ -2,12 +2,16 @@ module ActiveRecordUpsert
2
2
  module ActiveRecord
3
3
  module PersistenceExtensions
4
4
 
5
- def upsert
5
+ def upsert(attribute_names=nil)
6
6
  raise ::ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
7
7
  raise ::ActiveRecord::RecordSavedError, "Can't upsert a record that has already been saved" if persisted?
8
8
  values = run_callbacks(:save) {
9
9
  run_callbacks(:create) {
10
- _upsert_record
10
+ attribute_names ||= changed
11
+ attribute_names = attribute_names.map(&:to_s) +
12
+ timestamp_attributes_for_create_in_model +
13
+ timestamp_attributes_for_update_in_model
14
+ _upsert_record(attribute_names.uniq)
11
15
  }
12
16
  }
13
17
  assign_attributes(values.first.to_h)
@@ -28,9 +32,14 @@ module ActiveRecordUpsert
28
32
  if attributes.is_a?(Array)
29
33
  attributes.collect { |hash| upsert(hash, &block) }
30
34
  else
31
- new(attributes, &block).upsert
35
+ new(attributes, &block).upsert(attributes.keys)
32
36
  end
33
37
  end
38
+ def upsert_keys(*keys)
39
+ return @_upsert_keys if keys.empty?
40
+ keys = keys.first if keys.size == 1 # support single string/symbol, multiple string/symbols, and array
41
+ @_upsert_keys = Array(keys).map(&:to_s)
42
+ end
34
43
  end
35
44
  end
36
45
  end
@@ -14,11 +14,13 @@ module ActiveRecordUpsert
14
14
  im.into arel_table
15
15
 
16
16
  substitutes, binds = substitute_values values
17
+ column_arr = self.klass.upsert_keys || [primary_key]
18
+ column_name = column_arr.join(',')
17
19
 
18
20
  cm = arel_table.create_on_conflict_do_update
19
- cm.target = arel_table[primary_key]
21
+ cm.target = arel_table[column_name]
22
+ filter = ->(o) { [*column_arr, 'created_at'].include?(o.name) }
20
23
 
21
- filter = ->(o) { [primary_key, 'created_at'].include?(o.name) }
22
24
  cm.set(substitutes.reject { |s| filter.call(s.first) })
23
25
  on_conflict_binds = binds.reject(&filter)
24
26
 
@@ -29,8 +31,8 @@ module ActiveRecordUpsert
29
31
  @klass.connection.upsert(
30
32
  im,
31
33
  'SQL',
32
- primary_key,
33
- primary_key_value,
34
+ primary_key, # not used
35
+ primary_key_value, # not used
34
36
  nil,
35
37
  binds + on_conflict_binds)
36
38
  end
@@ -5,7 +5,7 @@ module ActiveRecordUpsert
5
5
  if self.record_timestamps
6
6
  current_time = current_time_from_proper_timezone
7
7
 
8
- all_timestamp_attributes.each do |column|
8
+ all_timestamp_attributes_in_model.each do |column|
9
9
  column = column.to_s
10
10
  if has_attribute?(column) && !attribute_present?(column)
11
11
  write_attribute(column, current_time)
@@ -13,7 +13,7 @@ module ActiveRecordUpsert
13
13
 
14
14
  def visit_Arel_Nodes_OnConflict o, collector
15
15
  collector << "ON CONFLICT "
16
- collector << " (#{quote_column_name o.target.name}) "
16
+ collector << " (#{quote_column_name o.target.name}) ".gsub(',', '","')
17
17
  maybe_visit o.action, collector
18
18
  end
19
19
 
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordUpsert
2
- VERSION = "0.6.3"
2
+ VERSION = "0.7.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_upsert
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesper Josefsson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-10-17 00:00:00.000000000 Z
12
+ date: 2017-08-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -20,7 +20,7 @@ dependencies:
20
20
  version: '5.0'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '5.1'
23
+ version: '5.2'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,21 +30,27 @@ dependencies:
30
30
  version: '5.0'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '5.1'
33
+ version: '5.2'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: arel
36
36
  requirement: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '7.0'
41
+ - - "<"
42
+ - !ruby/object:Gem::Version
43
+ version: '9.0'
41
44
  type: :runtime
42
45
  prerelease: false
43
46
  version_requirements: !ruby/object:Gem::Requirement
44
47
  requirements:
45
- - - "~>"
48
+ - - ">"
46
49
  - !ruby/object:Gem::Version
47
50
  version: '7.0'
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: '9.0'
48
54
  - !ruby/object:Gem::Dependency
49
55
  name: pg
50
56
  requirement: !ruby/object:Gem::Requirement
@@ -59,102 +65,6 @@ dependencies:
59
65
  - - "~>"
60
66
  - !ruby/object:Gem::Version
61
67
  version: '0.18'
62
- - !ruby/object:Gem::Dependency
63
- name: bundler
64
- requirement: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '1.13'
69
- type: :development
70
- prerelease: false
71
- version_requirements: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '1.13'
76
- - !ruby/object:Gem::Dependency
77
- name: rake
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '10.0'
83
- type: :development
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '10.0'
90
- - !ruby/object:Gem::Dependency
91
- name: rspec
92
- requirement: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '3.0'
97
- - - "<"
98
- - !ruby/object:Gem::Version
99
- version: '4'
100
- type: :development
101
- prerelease: false
102
- version_requirements: !ruby/object:Gem::Requirement
103
- requirements:
104
- - - ">="
105
- - !ruby/object:Gem::Version
106
- version: '3.0'
107
- - - "<"
108
- - !ruby/object:Gem::Version
109
- version: '4'
110
- - !ruby/object:Gem::Dependency
111
- name: pry
112
- requirement: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - ">"
115
- - !ruby/object:Gem::Version
116
- version: '0'
117
- type: :development
118
- prerelease: false
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - ">"
122
- - !ruby/object:Gem::Version
123
- version: '0'
124
- - !ruby/object:Gem::Dependency
125
- name: database_cleaner
126
- requirement: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - "~>"
129
- - !ruby/object:Gem::Version
130
- version: 1.5.3
131
- type: :development
132
- prerelease: false
133
- version_requirements: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - "~>"
136
- - !ruby/object:Gem::Version
137
- version: 1.5.3
138
- - !ruby/object:Gem::Dependency
139
- name: rails
140
- requirement: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - ">="
143
- - !ruby/object:Gem::Version
144
- version: '5.0'
145
- - - "<"
146
- - !ruby/object:Gem::Version
147
- version: '5.1'
148
- type: :development
149
- prerelease: false
150
- version_requirements: !ruby/object:Gem::Requirement
151
- requirements:
152
- - - ">="
153
- - !ruby/object:Gem::Version
154
- version: '5.0'
155
- - - "<"
156
- - !ruby/object:Gem::Version
157
- version: '5.1'
158
68
  description:
159
69
  email:
160
70
  - jesper.josefsson@gmail.com
@@ -163,21 +73,9 @@ executables: []
163
73
  extensions: []
164
74
  extra_rdoc_files: []
165
75
  files:
166
- - ".gitignore"
167
- - ".rspec"
168
- - ".travis.yml"
169
- - Dockerfile
170
- - Gemfile
171
- - Gemfile.docker
172
76
  - README.md
173
77
  - Rakefile
174
78
  - active_record_upsert.gemspec
175
- - bin/console
176
- - bin/release
177
- - bin/run_docker_test.sh
178
- - bin/run_rails.sh
179
- - bin/setup
180
- - docker-compose.yml
181
79
  - lib/active_record_upsert.rb
182
80
  - lib/active_record_upsert/active_record.rb
183
81
  - lib/active_record_upsert/active_record/connection_adapters/abstract/database_statements.rb
@@ -218,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
116
  version: '0'
219
117
  requirements: []
220
118
  rubyforge_project:
221
- rubygems_version: 2.6.7
119
+ rubygems_version: 2.6.12
222
120
  signing_key:
223
121
  specification_version: 4
224
122
  summary: Real PostgreSQL 9.5+ upserts using ON CONFLICT for ActiveRecord
data/.gitignore DELETED
@@ -1,10 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- /spec/dummy/log/*.log
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --require spec_helper
2
- --format documentation
3
- --color
data/.travis.yml DELETED
@@ -1,16 +0,0 @@
1
- sudo: required
2
- dist: trusty
3
- language: ruby
4
- env:
5
- - DATABASE_URL="postgresql://postgres@localhost/upsert_test"
6
- rvm:
7
- - 2.3.1
8
- before_script:
9
- - createdb --echo -U postgres upsert_test
10
- - psql -U postgres upsert_test < spec/dummy/db/structure.sql
11
-
12
- before_install: gem install bundler -v 1.13.3
13
-
14
- addons:
15
- postgresql: "9.5"
16
-
data/Dockerfile DELETED
@@ -1,18 +0,0 @@
1
- FROM quay.io/travisci/travis-ruby
2
- RUN apt-add-repository ppa:brightbox/ruby-ng
3
- RUN apt-get update
4
- RUN apt-get install ruby2.3 ruby2.3-dev
5
- RUN ruby --version
6
-
7
- ENV BUNDLE_GEMFILE=/app/Gemfile.docker
8
- RUN gem install nokogiri
9
- RUN gem install bundler
10
- COPY Gemfile* *.gemspec /app/
11
- RUN mkdir -p /app/lib/active_record_upsert
12
- COPY lib/active_record_upsert/version.rb /app/lib/active_record_upsert/
13
- WORKDIR /app
14
- RUN bundle install
15
- COPY . /app
16
- CMD bin/run_docker_test.sh
17
-
18
-
data/Gemfile DELETED
@@ -1,5 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in active_record_upsert.gemspec
4
- gemspec
5
-
data/Gemfile.docker DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in active_record_upsert.gemspec
4
- gemspec
data/bin/console DELETED
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require 'active_record'
5
- require 'active_record/connection_adapters/postgresql_adapter'
6
- require "active_record_upsert"
7
- require File.join(__dir__, '../spec/setup')
8
- ActiveRecord::Base.logger = Logger.new(STDOUT)
9
-
10
- # You can add fixtures and/or initialization code here to make experimenting
11
- # with your gem easier. You can also use a different console, if you like.
12
-
13
- # (If you use this, don't forget to add pry to your Gemfile!)
14
- # require "pry"
15
- # Pry.start
16
-
17
- require "irb"
18
- IRB.start
data/bin/release DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -e
3
- OUR_RUBY=2.3.1
4
-
5
- rvm $OUR_RUBY do bundle check
6
- rvm $OUR_RUBY do bundle exec rake release
7
-
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
- pushd spec/dummy
3
- RAILS_ENV=test rails db:migrate
4
- popd
5
- RAILS_ENV=test bundle exec rspec
data/bin/run_rails.sh DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env bash
2
- pushd spec/dummy
3
- RAILS_ENV=test bundle exec rails $@
4
- popd
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
data/docker-compose.yml DELETED
@@ -1,14 +0,0 @@
1
- version: '2'
2
- services:
3
- db:
4
- image: postgres:9.5
5
- ports:
6
- - "5432:5432"
7
- app:
8
- environment:
9
- - DATABASE_URL=postgresql://postgres@db/active_record_upsert_test
10
- build: .
11
- depends_on:
12
- - db
13
- links:
14
- - db