statesman_mongoid 0.1.1 → 0.3.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +14 -3
- data/lib/statesman/adapters/mongoid.rb +9 -2
- data/lib/statesman/adapters/mongoid_queries.rb +165 -0
- data/lib/statesman_mongoid/version.rb +1 -1
- data/lib/statesman_mongoid.rb +2 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 150c388e7dc52a4d1cd5f7dc8aec635bb70d254ecbab0928e151463ac9ca43d1
|
4
|
+
data.tar.gz: 4db6ce07d5bca4cb8bb8f60cd07e0165072d23c977b1b165e7358e150eb580e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 172df6b8fe89efababe619552ed5391765b7e18f38998f7cebf7fa00861a05a770436659b23c0ce4f59435643ac32ae5d1f8eb48bcb3a6d19fb01f68a7e65424
|
7
|
+
data.tar.gz: 15460af6a52050507a9d8443ab696ce89a74a9bca276351ee78decaaed5279f476eac3d0ba3f8e6104cf4b5884100b5a43dccf7d4af59d4282048527e523cf55
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# Statesman Mongoid
|
2
2
|
|
3
|
-
Restored mongoid adapters for
|
3
|
+
Restored mongoid adapters for [Statesman](https://github.com/gocardless/statesman).
|
4
|
+
|
5
|
+
TODO: Restore generators and test units
|
6
|
+
|
7
|
+
NOTE: This is an early salvage of the dropped mongoid support with a refitted queries adapter, a couple of fixes and some manual testing, use at your own risk and feel free to contribute.
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
@@ -20,7 +24,14 @@ Or install it yourself as:
|
|
20
24
|
|
21
25
|
## Usage
|
22
26
|
|
23
|
-
TODO:
|
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
|
+
```
|
24
35
|
|
25
36
|
## Development
|
26
37
|
|
@@ -30,7 +41,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
30
41
|
|
31
42
|
## Contributing
|
32
43
|
|
33
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
44
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/oz-tal/statesman_mongoid.
|
34
45
|
|
35
46
|
## License
|
36
47
|
|
@@ -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
|
data/lib/statesman_mongoid.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "statesman_mongoid/version"
|
4
|
-
|
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.
|
4
|
+
version: 0.3.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-
|
11
|
+
date: 2023-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: statesman
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- README.md
|
38
38
|
- Rakefile
|
39
39
|
- lib/statesman/adapters/mongoid.rb
|
40
|
+
- lib/statesman/adapters/mongoid_queries.rb
|
40
41
|
- lib/statesman/adapters/mongoid_transition.rb
|
41
42
|
- lib/statesman_mongoid.rb
|
42
43
|
- lib/statesman_mongoid/version.rb
|