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 +4 -4
- data/.travis.yml +1 -1
- data/README.md +79 -7
- data/lib/atomically/query_service.rb +11 -0
- data/lib/atomically/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec69d82cbee452fb2b61bd973aa1a885e5cffd5cdd8c5b5e6bb96ea066c8f7b1
|
4
|
+
data.tar.gz: be3720c0644d7c8228ea3b8ae88fd05c1850c66f629819977cc4758b8ec0d3d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b88cc95978a5c3cf4913d812e99e32aa4ef6b2bee12572e7e9eccea51edeadae8c78cdd42ad2f436ea9f3749832c1cacec0dd380a64900b0caa1936446b9a7a
|
7
|
+
data.tar.gz: ea519708c2c2d24b7876f810095adf0a9b599d713b3e7cb4091981d567886ce9c28644d42bca688790ada4d0e9e5b153bc3f9c6149fc060818768ec12493d437
|
data/.travis.yml
CHANGED
@@ -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
|
-
##
|
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
|
-
|
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` =
|
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)
|
data/lib/atomically/version.rb
CHANGED
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.
|
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
|
+
date: 2018-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|