statesman 7.2.0 → 8.0.1

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: 421da0e6d201060df4733a0e52e2742df2b1d527f241873dfd4b820c74cc587f
4
- data.tar.gz: 20cd64e291373c21b83886cfdc12c7e68450759515557f3853bfc68bfff8ed38
3
+ metadata.gz: aa4a88371cc60e6698eb820b60096f681fbaedf8dbbbec5991d47db81daf695d
4
+ data.tar.gz: b67153a87f62722deb2053ddf661e79e7918fca5339f9a6829a086e30a2abf02
5
5
  SHA512:
6
- metadata.gz: c48d5415915aee8e4f595b78b9018b9a048bfb3d8e3ff33a3efce0ba962540f71af1fe982a389d5b51104c8284fc485f4bfa62390a3c92f03fa7ce4592a2ffbf
7
- data.tar.gz: cf11b1793461381b835efe9b2343b54c348a01de85fc0cbd63623a0c18cf21f9935f6cb4251d9117a7d73b52df7041458a943d160628073afc96eb5c16237d73
6
+ metadata.gz: ac43c11e5dc1791bac7a00ba8e84b459daad104be9c9b460626c7569e4b9bdf215f0d080b5151ff754ee109640e70d1ca6cec4b958acfeadd974aab6962f16fd
7
+ data.tar.gz: 965b0a4020631cb18c39ce6af8870f3e165c87058aaf25f40f217a71d51cf65345818f974569191156a5ed94021c63595cf049c45fa11b62e132b1631e6d3d46
@@ -86,11 +86,11 @@ jobs:
86
86
  - POSTGRES_DB=statesman_test
87
87
  - POSTGRES_PASSWORD=statesman
88
88
  steps: *steps
89
- build-ruby265-rails-master-mysql:
89
+ build-ruby265-rails-main-mysql:
90
90
  docker:
91
91
  - image: circleci/ruby:2.6.5-node
92
92
  environment:
93
- - RAILS_VERSION=master
93
+ - RAILS_VERSION=main
94
94
  - DATABASE_URL=mysql2://root@127.0.0.1/statesman_test
95
95
  - DATABASE_DEPENDENCY_PORT=3306
96
96
  - image: circleci/mysql:5.7.18
@@ -100,11 +100,11 @@ jobs:
100
100
  - MYSQL_PASSWORD=
101
101
  - MYSQL_DATABASE=statesman_test
102
102
  steps: *steps
103
- build-ruby265-rails-master-postgres:
103
+ build-ruby265-rails-main-postgres:
104
104
  docker:
105
105
  - image: circleci/ruby:2.6.5-node
106
106
  environment:
107
- - RAILS_VERSION=master
107
+ - RAILS_VERSION=main
108
108
  - DATABASE_URL=postgres://postgres@localhost/statesman_test
109
109
  - EXCLUDE_MONGOID=true
110
110
  - DATABASE_DEPENDENCY_PORT=5432
@@ -142,11 +142,11 @@ jobs:
142
142
  - POSTGRES_DB=statesman_test
143
143
  - POSTGRES_PASSWORD=statesman
144
144
  steps: *steps
145
- build-ruby270-rails-master-mysql:
145
+ build-ruby270-rails-main-mysql:
146
146
  docker:
147
147
  - image: circleci/ruby:2.7.0-node
148
148
  environment:
149
- - RAILS_VERSION=master
149
+ - RAILS_VERSION=main
150
150
  - DATABASE_URL=mysql2://root@127.0.0.1/statesman_test
151
151
  - DATABASE_DEPENDENCY_PORT=3306
152
152
  - image: circleci/mysql:5.7.18
@@ -156,11 +156,11 @@ jobs:
156
156
  - MYSQL_PASSWORD=
157
157
  - MYSQL_DATABASE=statesman_test
158
158
  steps: *steps
159
- build-ruby270-rails-master-postgres:
159
+ build-ruby270-rails-main-postgres:
160
160
  docker:
161
161
  - image: circleci/ruby:2.7.0-node
162
162
  environment:
163
- - RAILS_VERSION=master
163
+ - RAILS_VERSION=main
164
164
  - DATABASE_URL=postgres://postgres@localhost/statesman_test
165
165
  - EXCLUDE_MONGOID=true
166
166
  - DATABASE_DEPENDENCY_PORT=5432
@@ -179,9 +179,9 @@ workflows:
179
179
  - build-ruby249-rails-524-postgres
180
180
  - build-ruby265-rails-602-mysql
181
181
  - build-ruby265-rails-602-postgres
182
- - build-ruby265-rails-master-mysql
183
- - build-ruby265-rails-master-postgres
182
+ - build-ruby265-rails-main-mysql
183
+ - build-ruby265-rails-main-postgres
184
184
  - build-ruby270-rails-602-mysql
185
185
  - build-ruby270-rails-602-postgres
186
- - build-ruby270-rails-master-mysql
187
- - build-ruby270-rails-master-postgres
186
+ - build-ruby270-rails-main-mysql
187
+ - build-ruby270-rails-main-postgres
@@ -1,3 +1,40 @@
1
+ ## v8.0.0 6th January 2021
2
+
3
+ ### Added
4
+
5
+ - Use AR Arel table to type cast booleans in order to avoid deprecation warning [#421](https://github.com/gocardless/statesman/pull/421)
6
+ - Support relationships that doesn't use `id` as a Primary Key
7
+ [#422](https://github.com/gocardless/statesman/pull/422)
8
+
9
+ ## v7.4.1 11th November 2020
10
+
11
+ ### Added
12
+
13
+ - Add #reset method to state machine and adapter interfaces
14
+ [#417](https://github.com/gocardless/statesman/pull/417)
15
+
16
+ ## v7.4.0 26th August 2020
17
+
18
+ ### Added
19
+
20
+ - [Gem Metadata](https://guides.rubygems.org/specification-reference/#metadata)
21
+ to make finding changes between releases even easier.
22
+
23
+ ## v7.3.0, 24th August 2020
24
+
25
+ ### Changed
26
+
27
+ - Use correct Arel for null [#409](https://github.com/gocardless/statesman/pull/#409)
28
+
29
+ ## v7.2.0, 19th May 2020
30
+
31
+ ### Changed
32
+
33
+ - Set non-empty password for postgres tests [#398](https://github.com/gocardless/statesman/pull/#398)
34
+ - Handle transitions differently for MySQL [#399](https://github.com/gocardless/statesman/pull/#399)
35
+ - pg requirement from >= 0.18, <= 1.1 to >= 0.18, <= 1.3 [#400](https://github.com/gocardless/statesman/pull/#400)
36
+ - Lazily enable mysql gaplock protection [#402](https://github.com/gocardless/statesman/pull/#402)
37
+
1
38
  ## v7.1.0, 10th Feb 2020
2
39
 
3
40
  - Fix `to_s` on `TransitionFailedError` & `GuardFailedError`. `.message` and
data/Gemfile CHANGED
@@ -5,8 +5,8 @@ source 'https://rubygems.org'
5
5
  gemspec
6
6
 
7
7
  # rubocop:disable Bundler/DuplicatedGem
8
- if ENV['RAILS_VERSION'] == 'master'
9
- gem "rails", git: "https://github.com/rails/rails"
8
+ if ENV['RAILS_VERSION'] == 'main'
9
+ gem "rails", git: "https://github.com/rails/rails", branch: "main"
10
10
  elsif ENV['RAILS_VERSION']
11
11
  gem "rails", "~> #{ENV['RAILS_VERSION']}"
12
12
  end
data/README.md CHANGED
@@ -322,6 +322,10 @@ Machine.successors
322
322
  #### `Machine#current_state`
323
323
  Returns the current state based on existing transition objects.
324
324
 
325
+ Takes an optional keyword argument to force a reload of data from the
326
+ database.
327
+ e.g `current_state(force_reload: true)`
328
+
325
329
  #### `Machine#in_state?(:state_1, :state_2, ...)`
326
330
  Returns true if the machine is in any of the given states.
327
331
 
@@ -404,10 +408,12 @@ Model.in_state(:state_1).or(
404
408
  #### Storing the state on the model object
405
409
 
406
410
  If you wish to store the model state on the model directly, you can keep it up
407
- to date using an `after_transition` hook:
411
+ to date using an `after_transition` hook.
412
+ Combine it with the `after_commit` option to ensure the model state will only be
413
+ saved once the transition has made it irreversibly to the database:
408
414
 
409
415
  ```ruby
410
- after_transition do |model, transition|
416
+ after_transition(after_commit: true) do |model, transition|
411
417
  model.state = transition.to_state
412
418
  model.save!
413
419
  end
@@ -39,8 +39,16 @@ module Statesman
39
39
  end
40
40
 
41
41
  def mysql?
42
- ActiveRecord::Base.configurations[Rails.env].
43
- try(:[], "adapter").try(:match, /mysql/)
42
+ configuration.try(:[], "adapter").try(:match, /mysql/)
43
+ end
44
+
45
+ # [] is deprecated and will be removed in 6.2
46
+ def configuration
47
+ if ActiveRecord::Base.configurations.respond_to?(:configs_for)
48
+ ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first
49
+ else
50
+ ActiveRecord::Base.configurations[Rails.env]
51
+ end
44
52
  end
45
53
 
46
54
  def database_supports_partial_indexes?
@@ -67,6 +67,10 @@ module Statesman
67
67
  end
68
68
  end
69
69
 
70
+ def reset
71
+ @last_transition = nil
72
+ end
73
+
70
74
  private
71
75
 
72
76
  # rubocop:disable Metrics/MethodLength
@@ -113,7 +117,7 @@ module Statesman
113
117
  to_state: to,
114
118
  sort_key: next_sort_key,
115
119
  metadata: metadata,
116
- most_recent: not_most_recent_value,
120
+ most_recent: not_most_recent_value(db_cast: false),
117
121
  }
118
122
  end
119
123
 
@@ -301,19 +305,21 @@ module Statesman
301
305
  end
302
306
 
303
307
  def db_true
304
- value = ::ActiveRecord::Base.connection.type_cast(
305
- true,
306
- transition_class.columns_hash["most_recent"],
307
- )
308
- ::ActiveRecord::Base.connection.quote(value)
308
+ ::ActiveRecord::Base.connection.quote(type_cast(true))
309
309
  end
310
310
 
311
311
  def db_false
312
- value = ::ActiveRecord::Base.connection.type_cast(
313
- false,
314
- transition_class.columns_hash["most_recent"],
315
- )
316
- ::ActiveRecord::Base.connection.quote(value)
312
+ ::ActiveRecord::Base.connection.quote(type_cast(false))
313
+ end
314
+
315
+ def db_null
316
+ Arel::Nodes::SqlLiteral.new("NULL")
317
+ end
318
+
319
+ # Type casting against a column is deprecated and will be removed in Rails 6.2.
320
+ # See https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
321
+ def type_cast(value)
322
+ ::ActiveRecord::Base.connection.type_cast(value)
317
323
  end
318
324
 
319
325
  # Check whether the `most_recent` column allows null values. If it doesn't, set old
@@ -323,10 +329,12 @@ module Statesman
323
329
  # indexes. By doing the conditioning on the column, rather than Rails' opinion of
324
330
  # whether the database supports partial indexes, we're robust to DBs later adding
325
331
  # support for partial indexes.
326
- def not_most_recent_value
327
- return db_false if transition_class.columns_hash["most_recent"].null == false
332
+ def not_most_recent_value(db_cast: true)
333
+ if transition_class.columns_hash["most_recent"].null == false
334
+ return db_cast ? db_false : false
335
+ end
328
336
 
329
- nil
337
+ db_cast ? db_null : nil
330
338
  end
331
339
  end
332
340
 
@@ -104,7 +104,7 @@ module Statesman
104
104
 
105
105
  def most_recent_transition_join
106
106
  "LEFT OUTER JOIN #{model_table} AS #{most_recent_transition_alias} " \
107
- "ON #{model.table_name}.id = " \
107
+ "ON #{model.table_name}.#{model_primary_key} = " \
108
108
  "#{most_recent_transition_alias}.#{model_foreign_key} " \
109
109
  "AND #{most_recent_transition_alias}.most_recent = #{db_true}"
110
110
  end
@@ -127,6 +127,10 @@ module Statesman
127
127
  "and #{transition_class}."
128
128
  end
129
129
 
130
+ def model_primary_key
131
+ transition_reflection.active_record_primary_key
132
+ end
133
+
130
134
  def model_foreign_key
131
135
  transition_reflection.foreign_key
132
136
  end
@@ -37,6 +37,10 @@ module Statesman
37
37
  @history
38
38
  end
39
39
 
40
+ def reset
41
+ @history = []
42
+ end
43
+
40
44
  private
41
45
 
42
46
  def next_sort_key
@@ -257,6 +257,10 @@ module Statesman
257
257
  false
258
258
  end
259
259
 
260
+ def reset
261
+ @storage_adapter.reset
262
+ end
263
+
260
264
  private
261
265
 
262
266
  def adapter_class(transition_class)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Statesman
4
- VERSION = "7.2.0"
4
+ VERSION = "8.0.1"
5
5
  end
@@ -154,6 +154,31 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
154
154
  end
155
155
  end
156
156
 
157
+ context "with a custom primary key for the model" do
158
+ before do
159
+ # Switch to using OtherActiveRecordModelTransition, so the existing
160
+ # relation with MyActiveRecordModelTransition doesn't interfere with
161
+ # this spec.
162
+ # Configure the relationship to use a different primary key,
163
+ MyActiveRecordModel.send(:has_many,
164
+ :custom_name,
165
+ class_name: "OtherActiveRecordModelTransition",
166
+ primary_key: :external_id)
167
+
168
+ MyActiveRecordModel.class_eval do
169
+ def self.transition_class
170
+ OtherActiveRecordModelTransition
171
+ end
172
+ end
173
+ end
174
+
175
+ describe ".in_state" do
176
+ subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
177
+
178
+ specify { expect { query }.to_not raise_error }
179
+ end
180
+ end
181
+
157
182
  context "after_commit transactional integrity" do
158
183
  before do
159
184
  MyStateMachine.class_eval do
@@ -355,6 +355,19 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
355
355
  end
356
356
  end
357
357
 
358
+ it "resets last with #reload" do
359
+ model.save!
360
+ ActiveRecord::Base.transaction do
361
+ model.state_machine.transition_to!(:succeeded)
362
+ # force to cache value in last_transition instance variable
363
+ expect(model.state_machine.current_state).to eq("succeeded")
364
+ raise ActiveRecord::Rollback
365
+ end
366
+ expect(model.state_machine.current_state).to eq("succeeded")
367
+ model.reload
368
+ expect(model.state_machine.current_state).to eq("initial")
369
+ end
370
+
358
371
  context "with a namespaced model" do
359
372
  before do
360
373
  CreateNamespacedARModelMigration.migrate(:up)
@@ -33,6 +33,11 @@ class MyActiveRecordModel < ActiveRecord::Base
33
33
  def metadata
34
34
  super || {}
35
35
  end
36
+
37
+ def reload(*)
38
+ state_machine.reset
39
+ super
40
+ end
36
41
  end
37
42
 
38
43
  class MyActiveRecordModelTransition < ActiveRecord::Base
@@ -4,6 +4,8 @@ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "statesman/version"
6
6
 
7
+ GITHUB_URL = "https://github.com/gocardless/statesman"
8
+
7
9
  Gem::Specification.new do |spec|
8
10
  spec.name = "statesman"
9
11
  spec.version = Statesman::VERSION
@@ -11,7 +13,7 @@ Gem::Specification.new do |spec|
11
13
  spec.email = ["developers@gocardless.com"]
12
14
  spec.description = "A statesman-like state machine library"
13
15
  spec.summary = spec.description
14
- spec.homepage = "https://github.com/gocardless/statesman"
16
+ spec.homepage = GITHUB_URL
15
17
  spec.license = "MIT"
16
18
 
17
19
  spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
@@ -35,4 +37,12 @@ Gem::Specification.new do |spec|
35
37
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.0"
36
38
  spec.add_development_dependency "sqlite3", "~> 1.4.2"
37
39
  spec.add_development_dependency "timecop", "~> 0.9.1"
40
+
41
+ spec.metadata = {
42
+ "bug_tracker_uri" => "#{GITHUB_URL}/issues",
43
+ "changelog_uri" => "#{GITHUB_URL}/blob/master/CHANGELOG.md",
44
+ "documentation_uri" => "#{GITHUB_URL}/blob/master/README.md",
45
+ "homepage_uri" => GITHUB_URL,
46
+ "source_code_uri" => GITHUB_URL,
47
+ }
38
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statesman
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 8.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - GoCardless
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-19 00:00:00.000000000 Z
11
+ date: 2021-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ammeter
@@ -282,8 +282,13 @@ files:
282
282
  homepage: https://github.com/gocardless/statesman
283
283
  licenses:
284
284
  - MIT
285
- metadata: {}
286
- post_install_message:
285
+ metadata:
286
+ bug_tracker_uri: https://github.com/gocardless/statesman/issues
287
+ changelog_uri: https://github.com/gocardless/statesman/blob/master/CHANGELOG.md
288
+ documentation_uri: https://github.com/gocardless/statesman/blob/master/README.md
289
+ homepage_uri: https://github.com/gocardless/statesman
290
+ source_code_uri: https://github.com/gocardless/statesman
291
+ post_install_message:
287
292
  rdoc_options: []
288
293
  require_paths:
289
294
  - lib
@@ -298,8 +303,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
298
303
  - !ruby/object:Gem::Version
299
304
  version: '0'
300
305
  requirements: []
301
- rubygems_version: 3.1.1
302
- signing_key:
306
+ rubygems_version: 3.1.2
307
+ signing_key:
303
308
  specification_version: 4
304
309
  summary: A statesman-like state machine library
305
310
  test_files: