lockless 0.1.1 → 0.2.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
  SHA256:
3
- metadata.gz: 04eeee62146005a7c2f6f68e89ba5ad82763a9b80918d68e63a1c47fcd486839
4
- data.tar.gz: e2ae421f25787bbb0a52413710c67ae1d2c29279c0436eb1f08bafe1561b14b0
3
+ metadata.gz: b5cc6bb9658c48705098956a9caabc7c3f10cd99631dcd6b0fe776592f57cc9d
4
+ data.tar.gz: 48d0dc5d8709224b6481e6d5b6316487c66b82b735a88a77d370d783bcaa62fd
5
5
  SHA512:
6
- metadata.gz: 8ff5c03de7a60853770cb7ae0fa0d07a06faa7750bb46dee3826eea73e9679b171011831e8e39f57d01fac9694028942959f88febcda3d8b0c758535ffce22d1
7
- data.tar.gz: add5bb7893659aba38ec88c41a20b56bd2c532f1275db13a029c35aa1ef1874f48c9bf82f643f933fd4003d9f479637b561e4ff5579591db18b54f3b528df7e7
6
+ metadata.gz: a6580bfc5ac693248c355b82d6e6b9113c2772660ce0d7b2d9c31553a2da212d122cf0b757c93df78b7a985544f030b6bb66697e400f8857a749418a17ca16c0
7
+ data.tar.gz: 3a6da4c0530cbe62a28831aec86966953cecf54433fac6ccd75070ff659b4febb1db2b1b5232f521476fca6595fc0a36402bcf4e3a42be9ba980e578e2e4cfb7
@@ -1,4 +1,4 @@
1
- name: Ruby
1
+ name: RubyCI
2
2
 
3
3
  on: [push,pull_request]
4
4
 
data/.rspec_status CHANGED
@@ -1,7 +1,9 @@
1
1
  example_id | status | run_time |
2
2
  ------------------------------------------ | ------ | --------------- |
3
- ./spec/lockless/model_spec.rb[1:1] | passed | 0.01249 seconds |
4
- ./spec/lockless/model_spec.rb[1:2:1:1] | passed | 0.02708 seconds |
5
- ./spec/lockless/model_spec.rb[1:2:2:1:1] | passed | 0.00505 seconds |
6
- ./spec/lockless/model_spec.rb[1:2:2:1:2:1] | passed | 0.02621 seconds |
7
- ./spec/lockless/model_spec.rb[1:2:2:2:1] | passed | 0.00658 seconds |
3
+ ./spec/lockless/model_spec.rb[1:1] | passed | 0.01148 seconds |
4
+ ./spec/lockless/model_spec.rb[1:2:1:1] | passed | 0.02232 seconds |
5
+ ./spec/lockless/model_spec.rb[1:3:1:1] | passed | 0.00415 seconds |
6
+ ./spec/lockless/model_spec.rb[1:3:2:1:1] | passed | 0.005 seconds |
7
+ ./spec/lockless/model_spec.rb[1:3:2:1:2:1] | passed | 0.03027 seconds |
8
+ ./spec/lockless/model_spec.rb[1:3:2:2:1] | passed | 0.00563 seconds |
9
+ ./spec/lockless/model_spec.rb[1:3:2:2:2] | passed | 0.00243 seconds |
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Lockless
2
2
 
3
- Concurrently update records without locks.
3
+ [![Gem Version](https://badge.fury.io/rb/lockless.png)](https://badge.fury.io/rb/lockless)
4
+ [![CI Status](https://github.com/cianmce/lockless/actions/workflows/main.yml/badge.svg)](https://github.com/cianmce/lockless/actions)
4
5
 
5
6
  Allows for safe concurrent updates to a single record without the need for locks.
6
7
 
@@ -66,6 +67,8 @@ user2.name = "new name2"
66
67
 
67
68
  # Save user2 before saving user1
68
69
  user2.lockless_save! # => true
70
+
71
+ # user1 fails to save as it's been updated earlier by user2
69
72
  user1.lockless_save! # => false
70
73
 
71
74
  # when lockless_save doesn't work you can either ignored the update
@@ -75,6 +78,15 @@ user1.reload
75
78
  user1.name # => "new name2"
76
79
  user1.name = "new name3"
77
80
  user1.lockless_save! # => true
81
+ user1.reload.name # => "new name3"
82
+
83
+ user1.reload
84
+ user1.name = "new name1"
85
+ User.all.update_all(name: "new name4")
86
+
87
+ # user1 fails to save as it's been updated earlier in `update_all`
88
+ user1.lockless_save! # => false
89
+ user1.reload.name # => "new name4"
78
90
  ```
79
91
 
80
92
  ## Development
@@ -83,13 +95,26 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
83
95
 
84
96
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
85
97
 
86
- ### Run all specs + standardrb
98
+ ### Testing
99
+ #### Run all specs + standardrb
87
100
 
88
101
  ```sh
89
102
  bundle exec rake
90
103
  ```
91
104
 
92
- ### Run specs using guard
105
+ #### Run only standardrb
106
+
107
+ ```sh
108
+ bundle exec rake standard
109
+ ````
110
+
111
+ #### Apply standardrb auto fixes
112
+
113
+ ```sh
114
+ bundle exec rake standard:fix
115
+ ```
116
+
117
+ #### Run specs using guard
93
118
 
94
119
  ```sh
95
120
  bundle exec guard
@@ -111,6 +136,5 @@ Everyone interacting in the Lockless project's codebases, issue trackers, chat r
111
136
 
112
137
  ## TODO
113
138
 
114
- - [ ] Allow for custom lockless column name
115
139
  - [ ] Allow for custom primary key column name
116
140
  - [ ] Allow a boolean to be passed to allow for validation to be skipped like in `.save`
@@ -2,6 +2,11 @@
2
2
 
3
3
  module Lockless
4
4
  # Handles lockless saves
5
+
6
+ #
7
+ # Options:
8
+ #
9
+ # - :lockless_column - The columns used to track soft delete, defaults to `:lockless_uuid`.
5
10
  module Model
6
11
  extend ActiveSupport::Concern
7
12
 
@@ -10,6 +15,14 @@ module Lockless
10
15
  self.lockless_column = :lockless_uuid
11
16
 
12
17
  before_save :set_lockless_uuid
18
+
19
+ delegate :generate_uuid, :lockless_column, to: :class
20
+ end
21
+
22
+ class_methods do
23
+ def generate_uuid
24
+ SecureRandom.uuid
25
+ end
13
26
  end
14
27
 
15
28
  # Saves record if it has not be modified in the time after it was loaded from the database.
@@ -18,18 +31,18 @@ module Lockless
18
31
  # false is returned if record is outdated or invalid
19
32
  def lockless_save
20
33
  return false unless valid?
21
- old_lockless_uuid = lockless_uuid
34
+ old_lockless_uuid = public_send(lockless_column)
22
35
  return save if new_record?
23
36
 
24
37
  run_callbacks(:save) do |variable|
25
38
  new_attrs = changed.collect { |prop| [prop.to_sym, self[prop]] }.to_h
26
39
 
27
- update_count = self.class.where(id: id, lockless_uuid: old_lockless_uuid).update_all(new_attrs)
40
+ update_count = self.class.where(:id => id, lockless_column => old_lockless_uuid).update_all(new_attrs)
28
41
  if update_count == 1
29
42
  changes_applied
30
43
  true
31
44
  else
32
- self.lockless_uuid = old_lockless_uuid
45
+ public_send("#{lockless_column}=", old_lockless_uuid)
33
46
  false
34
47
  end
35
48
  end
@@ -49,7 +62,7 @@ module Lockless
49
62
  private
50
63
 
51
64
  def set_lockless_uuid
52
- self.lockless_uuid = SecureRandom.uuid
65
+ public_send("#{lockless_column}=", generate_uuid)
53
66
  end
54
67
  end
55
68
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lockless
4
+ module Relation
5
+ def update_all(updates)
6
+ if model.method_defined?(:lockless_column) && updates[model.lockless_column].blank?
7
+ updates[model.lockless_column] = model.generate_uuid
8
+ end
9
+
10
+ super(updates)
11
+ end
12
+ end
13
+ end
14
+
15
+ ActiveRecord::Relation.prepend(Lockless::Relation)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lockless
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/lockless.rb CHANGED
@@ -4,3 +4,4 @@ require "active_record"
4
4
 
5
5
  require "lockless/version"
6
6
  require "lockless/model"
7
+ require "lockless/relation"
data/lockless.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "Allows for safe concurrent updates to a single record without the need for locks."
13
13
  spec.homepage = "https://github.com/cianmce/lockless"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.3.0"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
18
  spec.metadata["source_code_uri"] = spec.homepage
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockless
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cian McElhinney
@@ -215,6 +215,7 @@ files:
215
215
  - bin/setup
216
216
  - lib/lockless.rb
217
217
  - lib/lockless/model.rb
218
+ - lib/lockless/relation.rb
218
219
  - lib/lockless/version.rb
219
220
  - lockless.gemspec
220
221
  homepage: https://github.com/cianmce/lockless