statesman 1.2.2 → 1.2.3

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