atomically 1.0.3 → 1.0.4
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 +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
|

|
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
|