atomically 1.0.0 → 1.0.1

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
- SHA1:
3
- metadata.gz: 053a70728eaf97d497e01c5eb97d28b8606a13f6
4
- data.tar.gz: d19a6e6f011e0fa73f8ed40a6f48fc514d426c16
2
+ SHA256:
3
+ metadata.gz: d38cf83ab4f1e792cfefbb2c01ac897377fb7af2a81da6f09f932df4d5fa76f2
4
+ data.tar.gz: 88640837b4c69ef162d036b2a3e6ad61087e94a6baa79cde026fb748f09b58f1
5
5
  SHA512:
6
- metadata.gz: 642a937243e5e133294cfc5d97be7201cad09041717ff13ec512f8f23d4fc128d18dfd78d25d4130d0c0526655ccd232b25ada2decf284b1e55ece0c990b2dea
7
- data.tar.gz: 247cbb367d404627ab799af68f35de8dd2294e0a7b1d585c061e8b5d4a25ae5691af646577a51dd8a9b1e696304b1cd784ddc45773c7ec55acb74529d1e7fd77
6
+ metadata.gz: cd968dcc060705bc3d0174daf532fa4c80b8dfadc5845a7406bcf68d930744c6ce78e2f04b97091eb4cea27818ed44df1e4b3c47eefac5e0643ab492b9bed21b
7
+ data.tar.gz: 7577dd5ef6f32a4d3753c71637d218358d48aeac8b7c675c9b780d906af56f08bd9cf5cb14d7b98fd12a9275d28f6d45ec8a5baaccb3b177257e300a04c0c890
data/README.md CHANGED
@@ -31,20 +31,28 @@ Or install it yourself as:
31
31
  ### create_or_plus
32
32
 
33
33
  Import an array of records. When key is duplicate, plus the old value with new value.
34
- It is useful to add `items` to user when `user_items` may not exist.
34
+ It is useful to add `items` to `user` when `user_items` may not exist.
35
35
 
36
36
  First two args (columns, values) are the same with the [import](https://github.com/zdennis/activerecord-import#columns-and-arrays) method.
37
37
 
38
38
  Example:
39
-
40
39
  ```rb
41
- columns = [:user_id, :item_id, :count]
40
+ columns = [:user_id, :item_id, :quantity]
42
41
  values = [[user.id, item1.id, 3], [user.id, item2.id, 2]]
43
- on_duplicate_update_columns = [:count]
42
+ on_duplicate_update_columns = [:quantity]
44
43
 
45
44
  UserItem.atomically.create_or_plus(columns, values, on_duplicate_update_columns)
46
45
  ```
47
46
 
47
+ ### pay_all
48
+ Reduce the quantity of items and return how many rows and updated if all of them is enough.
49
+ Do nothing and return zero if any of them is not enough.
50
+
51
+ Example:
52
+ ```rb
53
+ user.user_items.atomically.pay_all({ item1.id => 4, item2.id => 3 }, [:quantity], primary_key: :item_id)
54
+ ```
55
+
48
56
  ## Development
49
57
 
50
58
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test DB=mysql` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency "mysql2", ">= 0.3"
35
35
  spec.add_development_dependency "pluck_all", ">= 2.0.3"
36
36
 
37
- spec.add_dependency "activerecord-import", ">= 0.27.0"
38
37
  spec.add_dependency "activerecord", ">= 3"
38
+ spec.add_dependency "activerecord-import", ">= 0.27.0"
39
+ spec.add_dependency "rails_or", ">= 1.1.8"
39
40
  end
@@ -3,7 +3,7 @@ require 'atomically/query_service'
3
3
 
4
4
  class ActiveRecord::Relation
5
5
  def atomically
6
- Atomically::QueryService.new(klass)
6
+ Atomically::QueryService.new(klass, relation: self)
7
7
  end
8
8
  end
9
9
 
@@ -0,0 +1,8 @@
1
+ require 'active_record'
2
+
3
+ class << ActiveRecord::Base
4
+ def from(value) # For Rails 3
5
+ value = "(#{value.to_sql}) subquery" if value.is_a?( ActiveRecord::Relation )
6
+ return super
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ require 'active_record'
2
+
3
+ class << ActiveRecord::Base
4
+ def none # For Rails 3
5
+ where('1=0')
6
+ end
7
+ end
@@ -1,21 +1,52 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'activerecord-import'
4
+ require 'rails_or'
5
+ require 'atomically/patches/none' if not ActiveRecord::Base.respond_to?(:none)
6
+ require 'atomically/patches/from' if Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new('4.0.0')
2
7
 
3
8
  class Atomically::QueryService
4
- def initialize(klass)
9
+ def initialize(klass, relation: nil)
5
10
  @klass = klass
11
+ @relation = relation || @klass
6
12
  end
7
13
 
8
14
  def create_or_plus(columns, data, update_columns)
9
15
  @klass.import(columns, data, on_duplicate_key_update: on_duplicate_key_plus_sql(update_columns))
10
16
  end
11
17
 
18
+ def pay_all(hash, update_columns, primary_key: :id) # { id => pay_count }
19
+ return 0 if hash.blank?
20
+
21
+ update_columns = update_columns.map(&method(:quote_column))
22
+
23
+ query = hash.inject(@klass.none) do |relation, (id, pay_count)|
24
+ condition = @relation.where(primary_key => id)
25
+ update_columns.each{|s| condition = condition.where("#{s} >= ?", pay_count) }
26
+ next relation.or(condition)
27
+ end
28
+
29
+ raw_when_sql = hash.map{|id, pay_count| "WHEN #{sanitize(id)} THEN #{sanitize(-pay_count)}" }.join("\n")
30
+ update_sqls = update_columns.map.with_index do |column, idx|
31
+ value = idx == 0 ? "(@change := \nCASE #{quote_column(primary_key)}\n#{raw_when_sql}\nEND)" : '@change'
32
+ next "#{column} = #{column} + #{value}"
33
+ end
34
+
35
+ return query.where("(#{@klass.from(query).select('COUNT(*)').to_sql}) = ?", hash.size)
36
+ .update_all(update_sqls.join(', '))
37
+ end
38
+
12
39
  private
13
40
 
14
41
  def on_duplicate_key_plus_sql( columns)
15
- columns.lazy
16
- .map(&@klass.connection.method(:quote_column_name))
17
- .map{|s| "#{s} = #{s} + VALUES(#{s})" }
18
- .force
19
- .join(', ')
42
+ columns.lazy.map(&method(:quote_column)).map{|s| "#{s} = #{s} + VALUES(#{s})" }.force.join(', ')
43
+ end
44
+
45
+ def quote_column(column)
46
+ @klass.connection.quote_column_name(column)
47
+ end
48
+
49
+ def sanitize(value)
50
+ @klass.connection.quote(value)
20
51
  end
21
52
  end
@@ -1,3 +1,3 @@
1
1
  module Atomically
2
- VERSION = '1.0.0'
2
+ VERSION = '1.0.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atomically
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - khiav reoy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-21 00:00:00.000000000 Z
11
+ date: 2018-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 2.0.3
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '3'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '3'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: activerecord-import
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -109,19 +123,19 @@ dependencies:
109
123
  - !ruby/object:Gem::Version
110
124
  version: 0.27.0
111
125
  - !ruby/object:Gem::Dependency
112
- name: activerecord
126
+ name: rails_or
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - ">="
116
130
  - !ruby/object:Gem::Version
117
- version: '3'
131
+ version: 1.1.8
118
132
  type: :runtime
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
136
  - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: '3'
138
+ version: 1.1.8
125
139
  description: ''
126
140
  email:
127
141
  - mrtmrt15xn@yahoo.com.tw
@@ -149,6 +163,8 @@ files:
149
163
  - gemfiles/5.2.gemfile
150
164
  - lib/atomically.rb
151
165
  - lib/atomically/active_record/extension.rb
166
+ - lib/atomically/patches/from.rb
167
+ - lib/atomically/patches/none.rb
152
168
  - lib/atomically/query_service.rb
153
169
  - lib/atomically/version.rb
154
170
  homepage: https://github.com/khiav223577/atomically
@@ -171,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
187
  version: '0'
172
188
  requirements: []
173
189
  rubyforge_project:
174
- rubygems_version: 2.6.13
190
+ rubygems_version: 2.7.6
175
191
  signing_key:
176
192
  specification_version: 4
177
193
  summary: ''