atomically 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 215319d576e714905af55fcb2ec48b1924c5971bf0e0bdaf3c61f75be3862a13
4
- data.tar.gz: 6171664742f2758011c79058fc2fd13850e11bb61c28604f24625e4ed107026f
3
+ metadata.gz: ec69d82cbee452fb2b61bd973aa1a885e5cffd5cdd8c5b5e6bb96ea066c8f7b1
4
+ data.tar.gz: be3720c0644d7c8228ea3b8ae88fd05c1850c66f629819977cc4758b8ec0d3d9
5
5
  SHA512:
6
- metadata.gz: 117f29a0644c694a25bef5ebd0d5bf8219e1a9e2521e0fad95f8ee5180ebad418d2651b10d3259a06735b495d23ceb4de1a75d3e928fe4dc725203aece924306
7
- data.tar.gz: 62482706f8a98ad1bc71041c323596a117e810330921b90e9395134c7d495c9c7e2b7f01378151178abd20b11dffad42678e9b2fdd0e851776d2de81537c10be
6
+ metadata.gz: 1b88cc95978a5c3cf4913d812e99e32aa4ef6b2bee12572e7e9eccea51edeadae8c78cdd42ad2f436ea9f3749832c1cacec0dd380a64900b0caa1936446b9a7a
7
+ data.tar.gz: ea519708c2c2d24b7876f810095adf0a9b599d713b3e7cb4091981d567886ce9c28644d42bca688790ada4d0e9e5b153bc3f9c6149fc060818768ec12493d437
@@ -19,8 +19,8 @@ matrix:
19
19
  - gemfile: gemfiles/3.2.gemfile
20
20
  rvm: 2.5
21
21
  before_install:
22
+ - gem i rubygems-update -v '<3' && update_rubygems
22
23
  - gem install bundler
23
- - gem update --system
24
24
  - gem --version
25
25
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
26
26
  - chmod +x ./cc-test-reporter
data/README.md CHANGED
@@ -10,6 +10,19 @@
10
10
 
11
11
  Supports Rails 3.2, 4.2, 5.0, 5.1, 5.2.
12
12
 
13
+ ## Table of contents
14
+
15
+ 1. [Installation](#installation)
16
+ 2. [Methods](#methods)
17
+ - [create_or_plus](#create_or_plus-columns-values-on_duplicate_update_columns)
18
+ - [pay_all](#pay_all-hash-update_columns-primary_key-id)
19
+ - [update_all](#update_all-expected_number-updates)
20
+ - [update](#update-attrs-from-not_set)
21
+ - [update_all_and_get_ids](#update_all_and_get_ids-updates)
22
+ 3. [Development](#development)
23
+ 4. [Contributing](#contributing)
24
+ 5. [License](#license)
25
+
13
26
  ## Installation
14
27
 
15
28
  Add this line to your application's Gemfile:
@@ -26,7 +39,9 @@ Or install it yourself as:
26
39
 
27
40
  $ gem install atomically
28
41
 
29
- ## Usage
42
+ ## Methods
43
+
44
+ Note: ActiveRecord validations and callbacks will **NOT** be triggered when calling below methods.
30
45
 
31
46
  ### create_or_plus _(columns, values, on_duplicate_update_columns)_
32
47
 
@@ -39,6 +54,7 @@ It is useful to add `items` to `user` when `user_items` may not exist.
39
54
  - `on_duplicate_update_columns` - The column that will be updated on duplicate.
40
55
 
41
56
  #### Example
57
+
42
58
  ```rb
43
59
  user = User.find(2)
44
60
  item1 = Item.find(1)
@@ -61,7 +77,16 @@ after
61
77
 
62
78
  ![image](https://user-images.githubusercontent.com/4011729/48999092-8d1ef100-f190-11e8-8372-86e2e99cbe08.png)
63
79
 
80
+ #### SQL queries
64
81
 
82
+ ```sql
83
+ INSERT INTO `user_items` (`user_id`,`item_id`,`quantity`,`created_at`,`updated_at`) VALUES
84
+ (2,1,3,'2018-11-27 03:44:25','2018-11-27 03:44:25'),
85
+ (2,2,2,'2018-11-27 03:44:25','2018-11-27 03:44:25')
86
+ ON DUPLICATE KEY UPDATE `quantity` = `quantity` + VALUES(`quantity`)
87
+ ```
88
+
89
+ ---
65
90
  ### pay_all _(hash, update_columns, primary_key: :id)_
66
91
 
67
92
  Reduce the quantity of items and return how many rows and updated if all of them is enough.
@@ -79,19 +104,20 @@ Do nothing and return zero if any of them is not enough.
79
104
  user.user_items.atomically.pay_all({ item1.id => 4, item2.id => 3 }, [:quantity], primary_key: :item_id)
80
105
  ```
81
106
 
107
+ #### SQL queries
108
+
82
109
  ```sql
83
- # generated sql
84
- UPDATE `user_items` SET `quantity` = `quantity` + (@change :=
110
+ UPDATE `user_items` SET `quantity` = `quantity` + (@change :=
85
111
  CASE `item_id`
86
112
  WHEN 1 THEN -4
87
113
  WHEN 2 THEN -3
88
- END)
114
+ END)
89
115
  WHERE `user_items`.`user_id` = 1 AND (
90
- `user_items`.`item_id` = 1 AND (`quantity` >= 4) OR `user_items`.`item_id` = -2 AND (`quantity` >= 3)
116
+ `user_items`.`item_id` = 1 AND (`quantity` >= 4) OR `user_items`.`item_id` = 2 AND (`quantity` >= 3)
91
117
  ) AND (
92
118
  (
93
119
  SELECT COUNT(*) FROM (
94
- SELECT `user_items`.* FROM `user_items`
120
+ SELECT `user_items`.* FROM `user_items`
95
121
  WHERE `user_items`.`user_id` = 1 AND (
96
122
  `user_items`.`item_id` = 1 AND (`quantity` >= 4) OR `user_items`.`item_id` = 2 AND (`quantity` >= 3)
97
123
  )
@@ -100,6 +126,7 @@ WHERE `user_items`.`user_id` = 1 AND (
100
126
  )
101
127
  ```
102
128
 
129
+ ---
103
130
  ### update_all _(expected_number, updates)_
104
131
 
105
132
  Behaves like [ActiveRecord::Relation#update_all](https://apidock.com/rails/ActiveRecord/Relation/update_all) but add an additional constrain that the number of affected rows equals to what you specify.
@@ -118,6 +145,20 @@ User.where(id: [1, 2, 3]).atomically.update_all(2, name: '')
118
145
  # => 0
119
146
  ```
120
147
 
148
+ #### SQL queries
149
+
150
+ ```sql
151
+ # User.where(id: [1, 2, 3]).atomically.update_all(2, name: '')
152
+ UPDATE `users` SET `users`.`name` = '' WHERE `users`.`id` IN (1, 2, 3) AND (
153
+ (
154
+ SELECT COUNT(*) FROM (
155
+ SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2, 3)
156
+ ) subquery
157
+ ) = 2
158
+ )
159
+ ```
160
+
161
+ ---
121
162
  ### update _(attrs, from: :not_set)_
122
163
 
123
164
  Updates the attributes of the model from the passed-in hash and saves the record. The difference between this method and [ActiveRecord#update](https://apidock.com/rails/ActiveRecord/Persistence/update) is that it will add extra WHERE conditions to prevent race condition.
@@ -126,8 +167,9 @@ Updates the attributes of the model from the passed-in hash and saves the record
126
167
 
127
168
  - `attrs` - Same with the first parameter of [ActiveRecord#update](https://apidock.com/rails/ActiveRecord/Persistence/update)
128
169
  - `from` - The value before update. If not set, use the attriutes of the model.
129
-
170
+
130
171
  #### Example
172
+
131
173
  ```rb
132
174
  class Arena < ApplicationRecord
133
175
  def atomically_close!
@@ -139,6 +181,9 @@ class Arena < ApplicationRecord
139
181
  end
140
182
  end
141
183
  ```
184
+
185
+ #### SQL queries
186
+
142
187
  ```sql
143
188
  # arena.atomically_close!
144
189
  UPDATE `arenas` SET `arenas`.`closed_at` = '2018-11-27 03:44:25', `updated_at` = '2018-11-27 03:44:25'
@@ -149,6 +194,33 @@ UPDATE `arenas` SET `arenas`.`closed_at` = '2018-11-27 03:44:25', `updated_at` =
149
194
  WHERE `arenas`.`id` = 1752
150
195
  ```
151
196
 
197
+ ---
198
+ ### update_all_and_get_ids _(updates)_
199
+
200
+ Behaves like [ActiveRecord::Relation#update_all](https://apidock.com/rails/ActiveRecord/Relation/update_all), but return the ids array of updated records instead of the number of updated records.
201
+
202
+
203
+ #### Parameters
204
+
205
+ - `updates` - A string, array, or hash representing the SET part of an SQL statement.
206
+
207
+ #### Example
208
+
209
+ ```rb
210
+ User.where(account: ['moon', 'wolf']).atomically.update_all_and_get_ids('money = money + 1')
211
+ # => [254, 371]
212
+ ```
213
+
214
+ #### SQL queries
215
+
216
+ ```sql
217
+ BEGIN
218
+ SET @ids := NULL
219
+ UPDATE `users` SET money = money + 1 WHERE `users`.`account` IN ('moon', 'wolf') AND ((SELECT @ids := CONCAT_WS(',', `users`.`id`, @ids)))
220
+ SELECT @ids FROM DUAL
221
+ COMMIT
222
+ ```
223
+
152
224
  ## Development
153
225
 
154
226
  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.
@@ -48,6 +48,17 @@ class Atomically::QueryService
48
48
  return success
49
49
  end
50
50
 
51
+ def update_all_and_get_ids(*args)
52
+ ids = nil
53
+ id_column = "#{@klass.quoted_table_name}.#{quote_column(:id)}"
54
+ @klass.transaction do
55
+ @relation.connection.execute('SET @ids := NULL')
56
+ @relation.where("(SELECT @ids := CONCAT_WS(',', #{id_column}, @ids))").update_all(*args) # 撈出有真的被更新的 id,用逗號串在一起
57
+ ids = @klass.from(nil).pluck('@ids').first
58
+ end
59
+ return ids.try{|s| s.split(',').map(&:to_i).uniq.sort } || [] # 將 id 從字串取出來 @id 的格式範例: '1,4,12'
60
+ end
61
+
51
62
  private
52
63
 
53
64
  def on_duplicate_key_plus_sql(columns)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Atomically
4
- VERSION = '1.0.3'
4
+ VERSION = '1.0.4'
5
5
  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.3
4
+ version: 1.0.4
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-28 00:00:00.000000000 Z
11
+ date: 2018-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler