active_record_patch_first_or_create 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: c5478264fa26b04687d1f600cec8ebcf8c26cf68
4
- data.tar.gz: 26c207ae53c67c8b4b128d5c7d81aeeac0e598f8
3
+ metadata.gz: b56bc4e68ceb6b1ae6089c20fe56b25d324497fa
4
+ data.tar.gz: 7d90a7e02899bee82c47cf3f260998b6cfb7ec11
5
5
  SHA512:
6
- metadata.gz: 7742d1e4bc569d0288d14bb27e64755acacac0718edc1355efc5003ec31cecf6859c4e23bc61b8c4c2dac4705edcb6b8592d19c07a1bb87ed50d11613f57cb2a
7
- data.tar.gz: 125ae54308548403d7ef4993f5ae457c786a55f94314ceb0a2e93fe237e7889ec9c11f572439e6eefe63e3ffe53997220352bfc6731bd596b9d438a978e3aa5e
6
+ metadata.gz: 391e2fe0cf2643db27a2cd3e4bff5d470b396f9f5e529aae934f64d8055f87ce4417383aaeffcb6e525f51b4627fbdfcdd942a709cee8adf32af07a0d24966e7
7
+ data.tar.gz: de16600866569f8b6ee9f409ee49046fbfeab5a6641a0b0eddd50cf05e7264906bbdce2845002031cb2fb1129dd43e35f0792c7663912b3ee871a9fc8bbd7f86
data/README.md CHANGED
@@ -26,15 +26,19 @@ We find out that methods like first_or_create or find_or_create_by are not atomi
26
26
 
27
27
  Finds the first record with the given attributes, or creates a record with the attributes if one is not found:
28
28
 
29
+ ```ruby
29
30
  # Find the first user with uid "abc123" or create a new one.
30
31
  User.where(uid: 'abc123').atomic_first_or_create(name: 'John', uid: 'abc123')
31
32
  # => #<User id: 1, uid: "abc123", name: 'John'>
32
-
33
+ ```
34
+ ```ruby
33
35
  # Find the first user with uid "abc123" or create a new one.
34
36
  # We already have one so the existing record will be returned.
35
37
  User.where(uid: 'abc123').atomic_first_or_create(name: 'John', uid: 'abc123')
36
38
  # => #<User id: 1, uid: "abc123", name: 'John'>
37
-
39
+ ```
40
+ ```ruby
38
41
  # Find the first user with uid "abc1234" or create a new one
39
42
  User.where(uid: 'abc123').atomic_first_or_create(name: 'Johansson', uid: 'abc1234')
40
43
  # => #<User id: 2, uid: "abc1234", name: 'Johansson'>
44
+ ```
@@ -20,9 +20,9 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.5"
22
22
  spec.add_development_dependency "rake", "~> 0"
23
- spec.add_development_dependency "minitest"
24
- spec.add_development_dependency "mocha"
25
- spec.add_development_dependency "webmock"
26
- spec.add_development_dependency "activerecord"
27
- spec.add_development_dependency "sqlite3"
23
+ spec.add_development_dependency "minitest", "~> 0"
24
+ spec.add_development_dependency "mocha", "~> 0"
25
+ spec.add_development_dependency "webmock", "~> 0"
26
+ spec.add_development_dependency "activerecord", "~> 0"
27
+ spec.add_development_dependency "sqlite3", "~> 0"
28
28
  end
@@ -1,16 +1,14 @@
1
1
  require "active_record_patch_first_or_create/version"
2
+ require "active_record_patch_first_or_create/arel_query_creator"
2
3
 
3
4
  module ActiveRecordPatchFirstOrCreate
4
5
  def self.first_or_create relation, attributes
6
+
5
7
  attributes = attributes.merge(relation.where_values_hash)
6
8
  attributes = attributes.merge(rails_timestamps(relation))
7
9
  attributes = serialize_columns(relation, attributes)
8
10
 
9
- sql = "INSERT INTO #{relation.table_name} (#{attributes.keys.join(",")})
10
- SELECT #{(['?'] * attributes.values.count).join(', ')}
11
- WHERE NOT EXISTS (#{relation.select('1').to_sql})"
12
-
13
- relation.klass.find_by_sql([sql] + attributes.values)
11
+ ActiveRecord::Base.connection.execute(ArelQueryCreator.new(relation, attributes).to_sql)
14
12
 
15
13
  relation.first
16
14
  end
@@ -22,9 +20,8 @@ module ActiveRecordPatchFirstOrCreate
22
20
 
23
21
  def self.serialize_columns relation, attributes
24
22
  Hash[attributes.map do |key, value|
25
- serializer = relation.klass.serialized_attributes[key.to_s]
26
- value = serializer.dump(value) unless serializer.nil?
27
- [key, value]
23
+ column = relation.klass.columns.find { |c| c.name == key.to_s }
24
+ [key, column ? column.cast_type.type_cast_for_database(value) : value]
28
25
  end]
29
26
  end
30
27
  end
@@ -35,4 +32,4 @@ module ActiveRecord
35
32
  ActiveRecordPatchFirstOrCreate.first_or_create(self, attributes)
36
33
  end
37
34
  end
38
- end
35
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveRecordPatchFirstOrCreate
2
+ class ArelQueryCreator < Struct.new(:relation, :attributes)
3
+ def to_sql
4
+ insert_query.to_sql
5
+ end
6
+
7
+ private
8
+
9
+ def insert_query
10
+ manager = Arel::InsertManager.new(ActiveRecord::Base)
11
+ manager.into table
12
+
13
+ attributes.keys.each do |name|
14
+ manager.columns << table[name]
15
+ end
16
+
17
+ manager.select select_query
18
+ manager
19
+ end
20
+
21
+ def select_query
22
+ select = Arel::SelectManager.new(ActiveRecord::Base)
23
+ attributes.values.each do |value|
24
+ select.project Arel.sql(ActiveRecord::Base.connection.quote(value))
25
+ end
26
+ select.where(not_exists_query.exists.not)
27
+ select
28
+ end
29
+
30
+ def not_exists_query
31
+ query = table.project(Arel.sql('1'))
32
+ relation.where_values_hash.each do |k,v|
33
+ query.where(table[k.to_sym].eq(v))
34
+ end
35
+ query
36
+ end
37
+
38
+ def table
39
+ Arel::Table.new relation.table_name
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordPatchFirstOrCreate
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_patch_first_or_create
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
  - NDrive DevOps Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-12 00:00:00.000000000 Z
11
+ date: 2015-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -42,70 +42,70 @@ dependencies:
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mocha
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activerecord
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: sqlite3
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  description: This patch provides first_or_create method to be atomic, once the default
@@ -122,6 +122,7 @@ files:
122
122
  - Rakefile
123
123
  - active_record_patch_first_or_create.gemspec
124
124
  - lib/active_record_patch_first_or_create.rb
125
+ - lib/active_record_patch_first_or_create/arel_query_creator.rb
125
126
  - lib/active_record_patch_first_or_create/version.rb
126
127
  homepage: http://www.ndrive.com
127
128
  licenses:
@@ -143,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
144
  version: '0'
144
145
  requirements: []
145
146
  rubyforge_project:
146
- rubygems_version: 2.2.0
147
+ rubygems_version: 2.4.3
147
148
  signing_key:
148
149
  specification_version: 4
149
150
  summary: ActiveRecord patch first_or_create atomic version