statesman 1.2.2 → 1.2.3

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
  SHA1:
3
- metadata.gz: a4cc83b59dfad9ed139c2215211c93550f06d4ea
4
- data.tar.gz: 170879ce893bcd74ab1742dd609d4a9abb163ffd
3
+ metadata.gz: 747626de855901f8252afbc7bae793d67c3e062a
4
+ data.tar.gz: f6b3c8239d7b92883c4bffce040d133cfc7cedfd
5
5
  SHA512:
6
- metadata.gz: a1c4175b5bc89dbe750b758f37cef8e08469515eb94f470f7872b7dcba2c7dec4650e4ed28670e7fc7d2f64647abf8dbc35e6f2ea0b980041fe38586a8eebfd9
7
- data.tar.gz: fb34e4fd474a1ca62585e7837bc16525b872b9b69f99b65ccb10e69f06b359c2cadc14ef04f75ff90ee459d779e9a15a8769fb7c6b06a2704b84cc6c15869173
6
+ metadata.gz: 3db31cb3e861d3230ab1f631c30727709251d70e109a27c3b723bcfe0f213ed3f73f82920a939e9ac897e87db8cee5852c20f4e8103fc3a7a210a57b62445f07
7
+ data.tar.gz: b17bfbc8186d3c0bc888cb0c92e282cd8174b0cb64dcd78185b6b40ed9bac8b2112314ca4ee0031d0293af07aeaa7cc7b2960809e7daa9ec89a8e5d785ad5550
data/.rubocop.yml CHANGED
@@ -17,11 +17,11 @@ Documentation:
17
17
  Enabled: false
18
18
 
19
19
  SignalException:
20
- Enabled: false
20
+ EnforcedStyle: only_raise
21
21
 
22
- # Avoid methods longer than 30 lines of code
22
+ # Avoid methods longer than 15 lines of code
23
23
  MethodLength:
24
- CountComments: false # count full line comments?
24
+ CountComments: false
25
25
  Max: 15
26
26
 
27
27
  AbcSize:
@@ -40,5 +40,5 @@ GuardClause:
40
40
  SingleSpaceBeforeFirstArg:
41
41
  Enabled: false
42
42
 
43
- Style/DotPosition:
44
- EnforcedStyle: 'trailing'
43
+ DotPosition:
44
+ EnforcedStyle: trailing
data/.travis.yml CHANGED
@@ -20,8 +20,8 @@ script:
20
20
 
21
21
  env:
22
22
  - "RAILS_VERSION=3.2.21"
23
- - "RAILS_VERSION=4.0.12"
24
- - "RAILS_VERSION=4.1.8"
25
- - "RAILS_VERSION=4.2.0"
26
- - "RAILS_VERSION=4.2.0 DATABASE_URL=mysql2://root@localhost/statesman_test"
27
- - "RAILS_VERSION=4.2.0 DATABASE_URL=postgres://postgres@localhost/statesman_test"
23
+ - "RAILS_VERSION=4.0.13"
24
+ - "RAILS_VERSION=4.1.10"
25
+ - "RAILS_VERSION=4.2.1"
26
+ - "RAILS_VERSION=4.2.1 DATABASE_URL=mysql2://root@localhost/statesman_test"
27
+ - "RAILS_VERSION=4.2.1 DATABASE_URL=postgres://postgres@localhost/statesman_test"
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## v1.2.3 14 April 2015
2
+
3
+ - Fix use of most_recent column in MySQL (partial indexes aren't supported) (patch by [@greysteil](https://github.com/greysteil))
4
+
1
5
  ## v1.2.2 24 March 2015
2
6
 
3
7
  - Add support for namespaced transition models (patch by [@DanielWright](https://github.com/DanielWright))
@@ -36,5 +36,9 @@ module Statesman
36
36
  ActiveRecord::Base.configurations[Rails.env].
37
37
  try(:[], "adapter").try(:match, /mysql/)
38
38
  end
39
+
40
+ def database_supports_partial_indexes?
41
+ Statesman::Adapters::ActiveRecord.database_supports_partial_indexes?
42
+ end
39
43
  end
40
44
  end
@@ -2,12 +2,18 @@ class AddConstraintsToMostRecentFor<%= migration_class_name %> < ActiveRecord::M
2
2
  disable_ddl_transaction!
3
3
 
4
4
  def up
5
+ <%- if database_supports_partial_indexes? -%>
5
6
  add_index :<%= table_name %>, [:<%= parent_id %>, :most_recent], unique: true, where: "most_recent", name: "index_<%= table_name %>_parent_most_recent", algorithm: :concurrently
6
7
  change_column_null :<%= table_name %>, :most_recent, false
8
+ <%- else -%>
9
+ add_index :<%= table_name %>, [:<%= parent_id %>, :most_recent], unique: true, name: "index_<%= table_name %>_parent_most_recent", algorithm: :concurrently
10
+ <%- end -%>
7
11
  end
8
12
 
9
13
  def down
10
14
  remove_index :<%= table_name %>, name: "index_<%= table_name %>_parent_most_recent"
15
+ <%- if database_supports_partial_indexes? -%>
11
16
  change_column_null :<%= table_name %>, :most_recent, true
17
+ <%- end -%>
12
18
  end
13
19
  end
@@ -5,11 +5,18 @@ class Create<%= migration_class_name %> < ActiveRecord::Migration
5
5
  t.text :metadata<%= ", default: \"{}\"" unless mysql? %>
6
6
  t.integer :sort_key, null: false
7
7
  t.integer :<%= parent_id %>, null: false
8
- t.boolean :most_recent, null: false
8
+ t.boolean :most_recent<%= ", null: false" if database_supports_partial_indexes? %>
9
9
  t.timestamps null: false
10
10
  end
11
11
 
12
- add_index :<%= table_name %>, [:<%= parent_id %>, :sort_key], unique: true, name: "<%= index_name :parent_sort %>"
13
- add_index :<%= table_name %>, [:<%= parent_id %>, :most_recent], unique: true, where: "most_recent", name: "<%= index_name :parent_most_recent %>"
12
+ add_index(:<%= table_name %>,
13
+ [:<%= parent_id %>, :sort_key],
14
+ unique: true,
15
+ name: "<%= index_name :parent_sort %>")
16
+ add_index(:<%= table_name %>,
17
+ [:<%= parent_id %>, :most_recent],
18
+ unique: true,
19
+ <%= "where: 'most_recent'," if database_supports_partial_indexes? %>
20
+ name: "<%= index_name :parent_most_recent %>")
14
21
  end
15
22
  end
@@ -1,14 +1,14 @@
1
1
  class <%= klass %>
2
2
  include Mongoid::Document
3
3
  include Mongoid::Timestamps
4
- include Statesman::Adapters::MongoidTransition
5
4
 
6
5
  field :to_state, type: String
7
6
  field :sort_key, type: Integer
8
7
  field :statesman_metadata, type: Hash
9
8
 
9
+ include Statesman::Adapters::MongoidTransition
10
+
10
11
  index({ sort_key: 1 })
11
12
 
12
13
  belongs_to :<%= parent %><%= class_name_option %>, index: true
13
-
14
14
  end
@@ -8,6 +8,15 @@ module Statesman
8
8
 
9
9
  JSON_COLUMN_TYPES = %w(json jsonb).freeze
10
10
 
11
+ def self.database_supports_partial_indexes?
12
+ # Rails 3 doesn't implement `supports_partial_index?`
13
+ if ::ActiveRecord::Base.connection.respond_to?(:supports_partial_index?)
14
+ ::ActiveRecord::Base.connection.supports_partial_index?
15
+ else
16
+ ::ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
17
+ end
18
+ end
19
+
11
20
  def initialize(transition_class, parent_model, observer, options = {})
12
21
  serialized = serialized?(transition_class)
13
22
  column_type = transition_class.columns_hash['metadata'].sql_type
@@ -27,15 +36,10 @@ module Statesman
27
36
  end
28
37
 
29
38
  def create(from, to, metadata = {})
30
- from = from.to_s
31
- to = to.to_s
32
- create_transition(from, to, metadata)
39
+ create_transition(from.to_s, to.to_s, metadata)
33
40
  rescue ::ActiveRecord::RecordNotUnique => e
34
- if e.message.include?(@transition_class.table_name) &&
35
- e.message.include?('sort_key') || e.message.include?('most_recent')
36
- raise TransitionConflictError, e.message
37
- else raise
38
- end
41
+ raise TransitionConflictError, e.message if transition_conflict_error? e
42
+ raise
39
43
  ensure
40
44
  @last_transition = nil
41
45
  end
@@ -83,7 +87,18 @@ module Statesman
83
87
 
84
88
  def unset_old_most_recent
85
89
  return unless most_recent_column?
86
- transitions_for_parent.update_all(most_recent: false)
90
+ # Check whether the `most_recent` column allows null values. If it
91
+ # doesn't, set old records to `false`, otherwise, set them to `NULL`.
92
+ #
93
+ # Some conditioning here is required to support databases that don't
94
+ # support partial indexes. By doing the conditioning on the column,
95
+ # rather than Rails' opinion of whether the database supports partial
96
+ # indexes, we're robust to DBs later adding support for partial indexes.
97
+ if transition_class.columns_hash['most_recent'].null == false
98
+ transitions_for_parent.update_all(most_recent: false)
99
+ else
100
+ transitions_for_parent.update_all(most_recent: nil)
101
+ end
87
102
  end
88
103
 
89
104
  def most_recent_column?
@@ -103,6 +118,11 @@ module Statesman
103
118
  transition_class.serialized_attributes.include?("metadata")
104
119
  end
105
120
  end
121
+
122
+ def transition_conflict_error?(e)
123
+ e.message.include?(@transition_class.table_name) &&
124
+ (e.message.include?('sort_key') || e.message.include?('most_recent'))
125
+ end
106
126
  end
107
127
  end
108
128
  end
@@ -38,7 +38,7 @@ module Statesman
38
38
  end
39
39
 
40
40
  def matches_from_state(from, to)
41
- (from == self.from && (to.nil? || self.to.empty?))
41
+ (from == self.from && (to.nil? || self.to.empty?))
42
42
  end
43
43
 
44
44
  def matches_to_state(from, to)
@@ -77,7 +77,7 @@ module Statesman
77
77
  if event
78
78
  events[event] ||= {}
79
79
  events[event][from] ||= []
80
- events[event][from] += to
80
+ events[event][from] += to
81
81
  end
82
82
  end
83
83
 
@@ -1,3 +1,3 @@
1
1
  module Statesman
2
- VERSION = "1.2.2"
2
+ VERSION = "1.2.3"
3
3
  end
@@ -15,9 +15,14 @@ namespace :statesman do
15
15
 
16
16
  parent_class.find_in_batches(batch_size: batch_size) do |models|
17
17
  ActiveRecord::Base.transaction do
18
- # Set all transitions' most_recent to FALSE
19
- transition_class.where(parent_fk => models.map(&:id)).
20
- update_all(most_recent: false)
18
+ if transition_class.columns_hash['most_recent'].null == false
19
+ # Set all transitions' most_recent to FALSE
20
+ transition_class.where(parent_fk => models.map(&:id)).
21
+ update_all(most_recent: false)
22
+ else
23
+ transition_class.where(parent_fk => models.map(&:id)).
24
+ update_all(most_recent: nil)
25
+ end
21
26
 
22
27
  # Set current transition's most_recent to TRUE
23
28
  ActiveRecord::Base.connection.execute %{
@@ -0,0 +1,11 @@
1
+ class AddConstraintsToMostRecentForBaconTransitions < ActiveRecord::Migration
2
+ disable_ddl_transaction!
3
+
4
+ def up
5
+ add_index :bacon_transitions, [:bacon_id, :most_recent], unique: true, name: "index_bacon_transitions_parent_most_recent", algorithm: :concurrently
6
+ end
7
+
8
+ def down
9
+ remove_index :bacon_transitions, name: "index_bacon_transitions_parent_most_recent"
10
+ end
11
+ end
@@ -12,7 +12,7 @@ describe Statesman::ActiveRecordTransitionGenerator, type: :generator do
12
12
  subject { file('app/models/yummy/bacon_transition.rb') }
13
13
 
14
14
  it { is_expected.to contain(/:bacon_transition/) }
15
- it { is_expected.not_to contain(/:yummy\/bacon/) }
15
+ it { is_expected.not_to contain(%r{:yummy/bacon}) }
16
16
  it { is_expected.to contain(/class_name: 'Yummy::Bacon'/) }
17
17
  end
18
18
 
@@ -22,8 +22,13 @@ describe Statesman::AddConstraintsToMostRecentGenerator, type: :generator do
22
22
  end
23
23
 
24
24
  let(:fixture_file) do
25
- File.read("spec/fixtures/add_constraints_to_most_recent_for_"\
26
- "bacon_transitions.rb")
25
+ if Statesman::Adapters::ActiveRecord.database_supports_partial_indexes?
26
+ File.read("spec/fixtures/add_constraints_to_most_recent_for_"\
27
+ "bacon_transitions_with_partial_index.rb")
28
+ else
29
+ File.read("spec/fixtures/add_constraints_to_most_recent_for_"\
30
+ "bacon_transitions_without_partial_index.rb")
31
+ end
27
32
  end
28
33
 
29
34
  before do
@@ -26,7 +26,7 @@ describe Statesman::MigrationGenerator, type: :generator do
26
26
  end
27
27
 
28
28
  it { is_expected.to contain(/:bacon_transition/) }
29
- it { is_expected.not_to contain(/:yummy\/bacon/) }
29
+ it { is_expected.not_to contain(%r{:yummy/bacon}) }
30
30
  it { is_expected.to contain(/null: false/) }
31
31
 
32
32
  it "names the sorting index appropriately" do
@@ -7,7 +7,7 @@ describe Statesman::MongoidTransitionGenerator, type: :generator do
7
7
  before { run_generator %w(Yummy::Bacon Yummy::BaconTransition) }
8
8
  subject { file('app/models/yummy/bacon_transition.rb') }
9
9
 
10
- it { is_expected.not_to contain(/:yummy\/bacon/) }
10
+ it { is_expected.not_to contain(%r{:yummy/bacon}) }
11
11
  it { is_expected.to contain(/class_name: 'Yummy::Bacon'/) }
12
12
  end
13
13
 
data/spec/spec_helper.rb CHANGED
@@ -31,7 +31,7 @@ RSpec.configure do |config|
31
31
  else
32
32
  # Connect to the database for activerecord tests
33
33
  db_conn_spec = ENV["DATABASE_URL"]
34
- db_conn_spec ||= { adapter: "sqlite3", database: ":memory:" }
34
+ db_conn_spec ||= { adapter: "sqlite3", database: ":memory:" }
35
35
  ActiveRecord::Base.establish_connection(db_conn_spec)
36
36
 
37
37
  db_adapter = ActiveRecord::Base.connection.adapter_name
@@ -145,7 +145,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
145
145
  it "updates the previous transition's most_recent flag" do
146
146
  expect { create }.
147
147
  to change { previous_transition.reload.most_recent }.
148
- from(true).to(false)
148
+ from(true).to be_falsey
149
149
  end
150
150
 
151
151
  context "and the parent model is updated in a callback" do
@@ -162,6 +162,18 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
162
162
  end
163
163
  end
164
164
  end
165
+
166
+ context "with two previous transitions" do
167
+ let!(:previous_transition) { adapter.create(from, to) }
168
+ let!(:another_previous_transition) { adapter.create(from, to) }
169
+ its(:most_recent) { is_expected.to eq(true) }
170
+
171
+ it "updates the previous transition's most_recent flag" do
172
+ expect { create }.
173
+ to change { another_previous_transition.reload.most_recent }.
174
+ from(true).to be_falsey
175
+ end
176
+ end
165
177
  end
166
178
 
167
179
  context "when the transition_class doesn't have a most_recent column" do
@@ -50,7 +50,6 @@ class CreateMyActiveRecordModelTransitionMigration < ActiveRecord::Migration
50
50
  t.string :to_state
51
51
  t.integer :my_active_record_model_id
52
52
  t.integer :sort_key
53
- t.boolean :most_recent, default: true, null: false
54
53
 
55
54
  # MySQL doesn't allow default values on text fields
56
55
  if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
@@ -59,17 +58,33 @@ class CreateMyActiveRecordModelTransitionMigration < ActiveRecord::Migration
59
58
  t.text :metadata, default: '{}'
60
59
  end
61
60
 
61
+ if Statesman::Adapters::ActiveRecord.database_supports_partial_indexes?
62
+ t.boolean :most_recent, default: true, null: false
63
+ else
64
+ t.boolean :most_recent, default: true
65
+ end
66
+
62
67
  t.timestamps null: false
63
68
  end
64
69
 
65
70
  add_index :my_active_record_model_transitions,
66
71
  [:my_active_record_model_id, :sort_key],
67
72
  unique: true, name: "sort_key_index"
68
- add_index :my_active_record_model_transitions,
69
- [:my_active_record_model_id, :most_recent],
70
- unique: true, where: "most_recent",
71
- name: "index_my_active_record_model_transitions_"\
72
- "parent_most_recent"
73
+
74
+ if Statesman::Adapters::ActiveRecord.database_supports_partial_indexes?
75
+ add_index :my_active_record_model_transitions,
76
+ [:my_active_record_model_id, :most_recent],
77
+ unique: true,
78
+ where: "most_recent",
79
+ name: "index_my_active_record_model_transitions_"\
80
+ "parent_most_recent"
81
+ else
82
+ add_index :my_active_record_model_transitions,
83
+ [:my_active_record_model_id, :most_recent],
84
+ unique: true,
85
+ name: "index_my_active_record_model_transitions_"\
86
+ "parent_most_recent"
87
+ end
73
88
  end
74
89
  end
75
90
  # rubocop:enable MethodLength
@@ -14,6 +14,7 @@ end
14
14
 
15
15
  class MyMongoidModelTransition
16
16
  include Mongoid::Document
17
+ include Mongoid::Timestamps
17
18
 
18
19
  field :to_state, type: String
19
20
  field :sort_key, type: Integer
@@ -23,6 +24,5 @@ class MyMongoidModelTransition
23
24
 
24
25
  belongs_to :my_mongoid_model, index: true
25
26
 
26
- alias_method :metadata, :statesman_metadata
27
- alias_method :metadata=, :statesman_metadata=
27
+ include Statesman::Adapters::MongoidTransition
28
28
  end
data/statesman.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rspec", "~> 3.1"
24
24
  spec.add_development_dependency "rspec-its", "~> 1.1"
25
25
  spec.add_development_dependency "guard-rspec", "~> 4.3"
26
- spec.add_development_dependency "rubocop", "~> 0.29.1"
26
+ spec.add_development_dependency "rubocop", "~> 0.30.0"
27
27
  spec.add_development_dependency "guard-rubocop", "~> 1.2"
28
28
  spec.add_development_dependency "sqlite3", "~> 1.3"
29
29
  spec.add_development_dependency "mongoid", ">= 3.1"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statesman
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harry Marr
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-24 00:00:00.000000000 Z
12
+ date: 2015-04-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -87,14 +87,14 @@ dependencies:
87
87
  requirements:
88
88
  - - ~>
89
89
  - !ruby/object:Gem::Version
90
- version: 0.29.1
90
+ version: 0.30.0
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - ~>
96
96
  - !ruby/object:Gem::Version
97
- version: 0.29.1
97
+ version: 0.30.0
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: guard-rubocop
100
100
  requirement: !ruby/object:Gem::Requirement
@@ -240,7 +240,8 @@ files:
240
240
  - lib/statesman/railtie.rb
241
241
  - lib/statesman/version.rb
242
242
  - lib/tasks/statesman.rake
243
- - spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions.rb
243
+ - spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_with_partial_index.rb
244
+ - spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_without_partial_index.rb
244
245
  - spec/fixtures/add_most_recent_to_bacon_transitions.rb
245
246
  - spec/generators/statesman/active_record_transition_generator_spec.rb
246
247
  - spec/generators/statesman/add_constraints_to_most_recent_generator_spec.rb
@@ -283,12 +284,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
283
284
  version: '0'
284
285
  requirements: []
285
286
  rubyforge_project:
286
- rubygems_version: 2.4.1
287
+ rubygems_version: 2.2.2
287
288
  signing_key:
288
289
  specification_version: 4
289
290
  summary: A statesmanlike state machine library
290
291
  test_files:
291
- - spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions.rb
292
+ - spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_with_partial_index.rb
293
+ - spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_without_partial_index.rb
292
294
  - spec/fixtures/add_most_recent_to_bacon_transitions.rb
293
295
  - spec/generators/statesman/active_record_transition_generator_spec.rb
294
296
  - spec/generators/statesman/add_constraints_to_most_recent_generator_spec.rb
@@ -310,4 +312,3 @@ test_files:
310
312
  - spec/support/active_record.rb
311
313
  - spec/support/generators_shared_examples.rb
312
314
  - spec/support/mongoid.rb
313
- has_rdoc: