statesman_mongoid 0.1.1 → 0.4.0

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: 12b141e7bcaf520970181af415dcdfe5256b148573fd01e3a4639d6585811f97
4
- data.tar.gz: 536f5ef0cd30da45fa1abb42ff78fcb80f1be5362fa57257c515580d32676c9a
3
+ metadata.gz: e91c70458d4fc19660876de07d0943d6556dd74b21128224fac9fbff5e949bc3
4
+ data.tar.gz: 7c334f7ab383ba19a2ea4a023069c295f61011fbad0a104dd0953b866201cb01
5
5
  SHA512:
6
- metadata.gz: 836739d3e0bc37bebcb07a509bf4e5609715545b3aa564954999d6da5823a0f2442e0f60ef1756e1ce47163a6d1481e284c1591608b6c8f9376f30293fda4805
7
- data.tar.gz: 90d396cfbec77f2e354970e214a7f845e5dac8bbeac546ac2262a41cead4abe11da8d9485e3aa9dcdfc576d538c60b66fbc5059cdddcc8cc9da88a2bac18caed
6
+ metadata.gz: 6774cea42364ac55c0be27f00de380f6a4404069099b7a0656c4ac36969dfb67d4d8125b05abbf56775b2f0530f1d843270c0f736f5ec9ccfa22302b2f2982ad
7
+ data.tar.gz: b277d6b9e6611b538955fcce1cb75b088f600d053c0e8d0297f6cd5239ba534f01d9af98bc77a1ee7c8ada6afd2807f0530eb9e8b53168b4b10881477c0f797f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- statesman_mongoid (0.1.1)
4
+ statesman_mongoid (0.4.0)
5
5
  statesman (~> 10.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Statesman Mongoid
2
2
 
3
- Restored mongoid adapters for the Statesman gem.
3
+ Mongoid adapters for [Statesman](https://github.com/gocardless/statesman).
4
+
5
+ TODO: Restore & update specs
6
+
7
+ NOTE: Restored Statesman's mongoid support with some fixes & updates. This project is in an early stage, please report any bugs or missing features. Use at your own risk and feel free to contribute.
4
8
 
5
9
  ## Installation
6
10
 
@@ -20,7 +24,19 @@ Or install it yourself as:
20
24
 
21
25
  ## Usage
22
26
 
23
- TODO: Write usage instructions here
27
+ TODO: Expand usage instructions
28
+
29
+ Follow instructions in the Statesman's doc and replace invoked classes with these ones when approriate:
30
+ ``` ruby
31
+ Statesman::Adapters::Mongoid
32
+ Statesman::Adapters::MongoidTransition
33
+ Statesman::Adapters::MongoidQueries
34
+ ```
35
+
36
+ Generator:
37
+ ```
38
+ rails generate statesman:mongoid_transition Order OrderTransition
39
+ ```
24
40
 
25
41
  ## Development
26
42
 
@@ -30,7 +46,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
30
46
 
31
47
  ## Contributing
32
48
 
33
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/statesman_mongoid.
49
+ Bug reports and pull requests are welcome on GitHub at https://github.com/oz-tal/statesman_mongoid.
34
50
 
35
51
  ## License
36
52
 
@@ -0,0 +1,27 @@
1
+ # Extracted from commit b9906ee1cf0ac6c1bbdd56c003ffe407c2f59833
2
+
3
+ require "rails/generators"
4
+ require "generators/statesman/generator_helpers"
5
+
6
+ module Statesman
7
+ class MongoidTransitionGenerator < Rails::Generators::Base
8
+ include Statesman::GeneratorHelpers
9
+
10
+ desc "Create a Mongoid-based transition model with the required attributes"
11
+
12
+ argument :parent, type: :string, desc: "Your parent model name"
13
+ argument :klass, type: :string, desc: "Your transition model name"
14
+
15
+ source_root File.expand_path("templates", __dir__)
16
+
17
+ def create_model_file
18
+ template("mongoid_transition_model.rb.erb", model_file_name)
19
+ end
20
+
21
+ private
22
+
23
+ def collection_name
24
+ klass.underscore.pluralize
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ class <%= klass %>
2
+ include Statesman::Adapters::MongoidTransition
3
+
4
+ index({ sort_key: 1 })
5
+
6
+ belongs_to :<%= parent %><%= class_name_option %>, index: true
7
+ end
@@ -1,4 +1,4 @@
1
- # Restored mongoid support, untouched
1
+ # Restored mongoid support with feature parity
2
2
  # Extracted from commit b9906ee1cf0ac6c1bbdd56c003ffe407c2f59833
3
3
 
4
4
  module Statesman
@@ -33,18 +33,25 @@ module Statesman
33
33
  @last_transition = nil
34
34
  end
35
35
 
36
- def history(*)
36
+ def history(force_reload: false)
37
+ reset if force_reload
37
38
  transitions_for_parent.asc(:sort_key)
38
39
  end
39
40
 
40
41
  def last(force_reload: false)
41
42
  if force_reload
42
- @last_transition = history.last
43
+ @last_transition = history(force_reload: true).last
43
44
  else
44
45
  @last_transition ||= history.last
45
46
  end
46
47
  end
47
48
 
49
+ def reset
50
+ # Aggressive, but the query cache can't be targeted at a more granular level
51
+ ::Mongoid::QueryCache.clear_cache
52
+ end
53
+
54
+
48
55
  private
49
56
 
50
57
  def transition_class_hash_fields
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Based on the somewhat compatible ActiveRecordQueries at commit 455a21dd74bb7d3b7555de0dd66e2ece9461c22d
4
+
5
+ module Statesman
6
+ module Adapters
7
+ module MongoidQueries
8
+ def self.check_missing_methods!(base)
9
+ missing_methods = %i[transition_class initial_state].
10
+ reject { |m| base.respond_to?(m) }
11
+ return if missing_methods.none?
12
+
13
+ raise NotImplementedError,
14
+ "#{missing_methods.join(', ')} method(s) should be defined on " \
15
+ "the model. Alternatively, use the new form of `include " \
16
+ "Statesman::Adapters::MongoidQueries[" \
17
+ "transition_class: MyTransition, " \
18
+ "initial_state: :some_state]`"
19
+ end
20
+
21
+ def self.included(base)
22
+ check_missing_methods!(base)
23
+
24
+ base.include(
25
+ ClassMethods.new(
26
+ transition_class: base.transition_class,
27
+ initial_state: base.initial_state,
28
+ most_recent_transition_alias: base.try(:most_recent_transition_alias),
29
+ transition_name: base.try(:transition_name),
30
+ ),
31
+ )
32
+ end
33
+
34
+ def self.[](**args)
35
+ ClassMethods.new(**args)
36
+ end
37
+
38
+ class ClassMethods < Module
39
+ def initialize(**args)
40
+ @args = args
41
+ end
42
+
43
+ def included(base)
44
+ ensure_inheritance(base)
45
+
46
+ query_builder = QueryBuilder.new(base, **@args)
47
+
48
+ define_in_state(base, query_builder)
49
+ define_not_in_state(base, query_builder)
50
+
51
+ define_method(:reload) do |*a|
52
+ instance = super(*a)
53
+ if instance.respond_to?(:state_machine, true)
54
+ instance.state_machine.reset
55
+ end
56
+ instance
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def ensure_inheritance(base)
63
+ klass = self
64
+ existing_inherited = base.method(:inherited)
65
+ base.define_singleton_method(:inherited) do |subclass|
66
+ existing_inherited.call(subclass)
67
+ subclass.send(:include, klass)
68
+ end
69
+ end
70
+
71
+ def define_in_state(base, query_builder)
72
+ base.define_singleton_method(:in_state) do |*states|
73
+ query_builder.states_where(states.flatten)
74
+ end
75
+ end
76
+
77
+ def define_not_in_state(base, query_builder)
78
+ base.define_singleton_method(:not_in_state) do |*states|
79
+ query_builder.states_where_not(states.flatten)
80
+ end
81
+ end
82
+ end
83
+
84
+ class QueryBuilder
85
+ def initialize(model, transition_class:, initial_state:,
86
+ most_recent_transition_alias: nil,
87
+ transition_name: nil)
88
+ @model = model
89
+ @transition_class = transition_class
90
+ @initial_state = initial_state
91
+ @most_recent_transition_alias = most_recent_transition_alias
92
+ @transition_name = transition_name
93
+ end
94
+
95
+ def states_where(states)
96
+ ids = aggregate_ids_for_most_recent(states, inclusive_match: true)
97
+ model.where(_id: { '$in' => ids })
98
+ end
99
+
100
+ def states_where_not(states)
101
+ ids = aggregate_ids_for_most_recent(states, inclusive_match: false)
102
+ model.where(_id: { '$in' => ids })
103
+ end
104
+
105
+ def aggregate_ids_for_most_recent(states, inclusive_match: true)
106
+ aggregation = [
107
+ # Sort most recent
108
+ { '$sort': { sort_key: -1 } },
109
+ # Group by foreign key & get most recent states
110
+ {
111
+ '$group': {
112
+ _id: "$#{model_foreign_key}",
113
+ to_state: { '$first': '$to_state' },
114
+ model_foreign_key => { '$first': "$#{model_foreign_key}" },
115
+ },
116
+ },
117
+ # Include/exclude states by provided states
118
+ { '$match': { to_state: { (inclusive_match ? '$in' : '$nin') => states } } },
119
+ # Trim response to only the foreign key
120
+ { '$project': { _id: 0, to_state: 0 } },
121
+ ]
122
+
123
+ # Hit the database and return a flat array of ids
124
+ transition_class.collection.aggregate(aggregation).pluck(model_foreign_key)
125
+ end
126
+
127
+
128
+ private
129
+
130
+ attr_reader :model, :transition_class, :initial_state
131
+
132
+ def transition_name
133
+ @transition_name || transition_class.collection.name.to_sym
134
+ end
135
+
136
+ def transition_reflection
137
+ model.reflect_on_all_associations(:has_many).each do |value|
138
+ return value if value.klass == transition_class
139
+ end
140
+
141
+ raise MissingTransitionAssociation,
142
+ "Could not find has_many association between #{self.class} " \
143
+ "and #{transition_class}."
144
+ end
145
+
146
+ def model_primary_key
147
+ transition_reflection.primary_key
148
+ end
149
+
150
+ def model_foreign_key
151
+ transition_reflection.foreign_key
152
+ end
153
+
154
+ def model_table
155
+ transition_reflection.name
156
+ end
157
+
158
+ def most_recent_transition_alias
159
+ @most_recent_transition_alias ||
160
+ "most_recent_#{transition_name.to_s.singularize}"
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StatesmanMongoid
4
- VERSION = "0.1.1"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "statesman_mongoid/version"
4
- require_relative "statesman/adapters/mongoid"
5
- require_relative "statesman/adapters/mongoid_transition"
3
+ # require_relative "statesman_mongoid/version"
4
+ Dir[__dir__ + '/statesman/adapters/*'].each &method(:require)
6
5
 
7
6
  module StatesmanMongoid
8
7
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statesman_mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - oz-tal
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-03 00:00:00.000000000 Z
11
+ date: 2023-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: statesman
@@ -36,7 +36,10 @@ files:
36
36
  - LICENSE.txt
37
37
  - README.md
38
38
  - Rakefile
39
+ - lib/generators/statesman/mongoid_transition_generator.rb
40
+ - lib/generators/statesman/templates/mongoid_transition_model.rb.erb
39
41
  - lib/statesman/adapters/mongoid.rb
42
+ - lib/statesman/adapters/mongoid_queries.rb
40
43
  - lib/statesman/adapters/mongoid_transition.rb
41
44
  - lib/statesman_mongoid.rb
42
45
  - lib/statesman_mongoid/version.rb