statesman-solid_objects 0.1.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.
@@ -0,0 +1,95 @@
1
+ # rbs_inline: enabled
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ class Execution
6
+ # @rbs @arguments: Hash[String, untyped]
7
+ # @rbs @context: untyped
8
+ # @rbs @definition: Registration
9
+ # @rbs @parent: untyped
10
+ # @rbs @write_started: bool
11
+
12
+ # @rbs () -> Execution?
13
+ def self.current
14
+ ActiveSupport::IsolatedExecutionState[:statesman_solid_objects_execution]
15
+ end
16
+
17
+ # @rbs (Hash[String, untyped], untyped) -> void
18
+ def initialize(arguments, context)
19
+ @arguments = arguments
20
+ @context = context
21
+ @definition = SolidObjects.registrations.fetch(arguments.fetch("registration"))
22
+ @parent = @definition.parent_class.find(arguments.fetch("parent_id"))
23
+ @write_started = false
24
+ end
25
+
26
+ # @rbs () -> void
27
+ def call
28
+ within do
29
+ machine = definition.machine(parent)
30
+ if arguments.fetch("operation") == "initialize_state"
31
+ persist(machine, "", definition.machine_class.initial_state, {})
32
+ else
33
+ machine.transition_to!(arguments.fetch("to"), arguments.fetch("metadata"))
34
+ end
35
+ end
36
+ rescue Statesman::TransitionFailedError, Statesman::GuardFailedError => error
37
+ code = error.is_a?(Statesman::GuardFailedError) ? "guard_failed" : "transition_failed"
38
+ raise ::SolidObjects::Rejected.new(code:, message: error.message, details: { from: error.from, to: error.to })
39
+ end
40
+
41
+ # @rbs () -> nil
42
+ def after_commit
43
+ within do
44
+ transition = definition.history(parent).find_by!(sort_key: arguments.fetch("sort_key"))
45
+ definition.machine(parent).execute(:after_commit, arguments.fetch("from"), transition.to_state, transition)
46
+ end
47
+ nil
48
+ end
49
+
50
+ # @rbs (Registration, untyped) -> bool
51
+ def matches?(registration, record)
52
+ registration == definition && record.instance_of?(parent.class) && record.id == parent.id
53
+ end
54
+
55
+ # @rbs (untyped, String, String, Hash[untyped, untyped]) -> untyped
56
+ def persist(observer, from, to, metadata)
57
+ unless !@write_started && context.is_a?(::SolidObjects::CommitActionContext) && ActiveRecord::Base.connection.transaction_open?
58
+ raise ArgumentError, "callback transitions require a new actor message"
59
+ end
60
+ @write_started = true
61
+
62
+ transition = definition.history(parent).build(
63
+ to_state: to, metadata:, sort_key: arguments.fetch("sort_key"), most_recent: true
64
+ )
65
+ observer.execute(:before, from, to, transition)
66
+ previous_value = definition.transition_class.columns_hash.fetch("most_recent").null ? nil : false
67
+ definition.history(parent).where(most_recent: true).update_all(most_recent: previous_value)
68
+ transition.save!
69
+ observer.execute(:after, from, to, transition)
70
+ return transition if definition.after_commit == :effect
71
+
72
+ connection = ActiveRecord::Base.connection
73
+ connection.add_transaction_record(
74
+ Statesman::Adapters::ActiveRecordAfterCommitWrap.new(connection) do
75
+ within { observer.execute(:after_commit, from, to, transition) }
76
+ end
77
+ )
78
+ transition
79
+ end
80
+
81
+ private
82
+
83
+ attr_reader :arguments, :context, :definition, :parent
84
+
85
+ # @rbs () { () -> untyped } -> untyped
86
+ def within
87
+ previous = self.class.current
88
+ ActiveSupport::IsolatedExecutionState[:statesman_solid_objects_execution] = self
89
+ yield
90
+ ensure
91
+ ActiveSupport::IsolatedExecutionState[:statesman_solid_objects_execution] = previous
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,53 @@
1
+ # rbs_inline: enabled
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ class Registration
6
+ # @rbs @name: String
7
+ # @rbs @parent_class: untyped
8
+ # @rbs @transition_class: untyped
9
+ # @rbs @machine_class: untyped
10
+ # @rbs @association: Symbol
11
+ # @rbs @after_commit: Symbol
12
+
13
+ attr_reader :name, :parent_class, :transition_class, :machine_class, :association, :after_commit
14
+
15
+ # @rbs (name: String, parent_class: untyped, transition_class: untyped, machine_class: untyped, association: Symbol, ?after_commit: Symbol) -> void
16
+ def initialize(name:, parent_class:, transition_class:, machine_class:, association:, after_commit: :inline)
17
+ raise ArgumentError, "after_commit must be :inline or :effect" unless [ :inline, :effect ].include?(after_commit)
18
+
19
+ @name = name
20
+ @parent_class = parent_class
21
+ @transition_class = transition_class
22
+ @machine_class = machine_class
23
+ @association = association
24
+ @after_commit = after_commit
25
+ pool = ActiveRecord::Base.connection_pool
26
+ unless [ parent_class, transition_class, ::SolidObjects::Record ].all? { |model| model.connection_pool.equal?(pool) }
27
+ raise ArgumentError, "parent, transition, and actor models must use the same connection pool"
28
+ end
29
+ freeze
30
+ end
31
+
32
+ # @rbs (untyped) -> String
33
+ def actor_id(parent)
34
+ unless parent.is_a?(parent_class) && parent.persisted?
35
+ raise ArgumentError, "parent must be a persisted #{parent_class.name}"
36
+ end
37
+ JSON.generate([ parent_class.base_class.name, parent.id.to_s ])
38
+ end
39
+
40
+ # @rbs (untyped) -> untyped
41
+ def history(parent)
42
+ parent.public_send(association).reorder(:sort_key)
43
+ end
44
+
45
+ # @rbs (untyped, ?authorization_context: untyped, **untyped) -> untyped
46
+ def machine(parent, authorization_context: nil, **options)
47
+ actor_id(parent)
48
+ machine_class.new(parent, **options, transition_class:, association_name: association,
49
+ solid_objects_registration: name, authorization_context:)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ # rbs_inline: enabled
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ # @rbs VERSION: String
6
+ VERSION = "0.1.0"
7
+ end
8
+ end
@@ -0,0 +1,38 @@
1
+ # rbs_inline: enabled
2
+
3
+ require "solid_objects"
4
+ require "statesman"
5
+ require "statesman/adapters/active_record"
6
+ require_relative "solid_objects/version"
7
+ require_relative "solid_objects/registration"
8
+ require_relative "solid_objects/execution"
9
+ require_relative "solid_objects/actor"
10
+ require_relative "solid_objects/adapter"
11
+
12
+ module Statesman
13
+ module SolidObjects
14
+ # @rbs @registrations: Hash[String, Registration]
15
+
16
+ # @rbs () -> Hash[String, Registration]
17
+ def self.registrations
18
+ @registrations ||= {}
19
+ end
20
+
21
+ # @rbs (String | Symbol, **untyped) -> Registration
22
+ def self.register(name, **options)
23
+ registrations[name.to_s] = Registration.new(name: name.to_s, **options)
24
+ end
25
+
26
+ # @rbs () -> void
27
+ def self.install
28
+ ::SolidObjects.registry.register(Actor.actor_type, Actor)
29
+ ::SolidObjects.register_commit_action(:statesman_transition) do |arguments, context|
30
+ Execution.new(arguments, context).call
31
+ end
32
+ ::SolidObjects.register_effect(:statesman_after_commit) do |arguments, context|
33
+ Execution.new(arguments, context).after_commit
34
+ end
35
+ Statesman.configure { storage_adapter(Adapter) }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "statesman/solid_objects"
@@ -0,0 +1,21 @@
1
+ # Generated from lib/statesman/solid_objects/actor.rb with RBS::Inline
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ class Actor < ::SolidObjects::Actor
6
+ # @rbs (registration: String, parent_id: String, to: String, metadata: Hash[String, untyped]) -> Integer
7
+ def transition: (registration: String, parent_id: String, to: String, metadata: Hash[String, untyped]) -> Integer
8
+
9
+ # @rbs (registration: String, parent_id: String) -> Integer
10
+ def initialize_state: (registration: String, parent_id: String) -> Integer
11
+
12
+ private
13
+
14
+ # @rbs (Registration, String) -> untyped
15
+ def parent_for: (Registration, String) -> untyped
16
+
17
+ # @rbs (Registration, untyped, String, Hash[String, untyped], from: String, operation: String) -> Integer
18
+ def stage_transition: (Registration, untyped, String, Hash[String, untyped], from: String, operation: String) -> Integer
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ # Generated from lib/statesman/solid_objects/adapter.rb with RBS::Inline
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ class Adapter
6
+ @transition_class: untyped
7
+
8
+ @parent_model: untyped
9
+
10
+ @observer: untyped
11
+
12
+ @definition: Registration
13
+
14
+ @authorization_context: untyped
15
+
16
+ attr_reader transition_class: untyped
17
+
18
+ attr_reader parent_model: untyped
19
+
20
+ # @rbs (untyped, untyped, untyped, ?Hash[Symbol, untyped]) -> void
21
+ def initialize: (untyped, untyped, untyped, ?Hash[Symbol, untyped]) -> void
22
+
23
+ # @rbs (String | Symbol | nil, String | Symbol, ?Hash[untyped, untyped]) -> untyped
24
+ def create: (String | Symbol | nil, String | Symbol, ?Hash[untyped, untyped]) -> untyped
25
+
26
+ # @rbs (?force_reload: bool) -> untyped
27
+ def last: (?force_reload: bool) -> untyped
28
+
29
+ # @rbs (?force_reload: bool) -> Array[untyped]
30
+ def history: (?force_reload: bool) -> Array[untyped]
31
+
32
+ # @rbs () -> nil
33
+ def reset: () -> nil
34
+
35
+ private
36
+
37
+ attr_reader definition: untyped
38
+
39
+ # @rbs () -> Integer
40
+ def next_sort_key: () -> Integer
41
+
42
+ # @rbs () -> Execution?
43
+ def execution: () -> Execution?
44
+
45
+ # @rbs (String) -> void
46
+ def authorize_read: (String) -> void
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ # Generated from lib/statesman/solid_objects/execution.rb with RBS::Inline
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ class Execution
6
+ @arguments: Hash[String, untyped]
7
+
8
+ @context: untyped
9
+
10
+ @definition: Registration
11
+
12
+ @parent: untyped
13
+
14
+ @write_started: bool
15
+
16
+ # @rbs () -> Execution?
17
+ def self.current: () -> Execution?
18
+
19
+ # @rbs (Hash[String, untyped], untyped) -> void
20
+ def initialize: (Hash[String, untyped], untyped) -> void
21
+
22
+ # @rbs () -> void
23
+ def call: () -> void
24
+
25
+ # @rbs () -> nil
26
+ def after_commit: () -> nil
27
+
28
+ # @rbs (Registration, untyped) -> bool
29
+ def matches?: (Registration, untyped) -> bool
30
+
31
+ # @rbs (untyped, String, String, Hash[untyped, untyped]) -> untyped
32
+ def persist: (untyped, String, String, Hash[untyped, untyped]) -> untyped
33
+
34
+ private
35
+
36
+ attr_reader arguments: untyped
37
+
38
+ attr_reader context: untyped
39
+
40
+ attr_reader definition: untyped
41
+
42
+ attr_reader parent: untyped
43
+
44
+ # @rbs () { () -> untyped } -> untyped
45
+ def within: () { () -> untyped } -> untyped
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,43 @@
1
+ # Generated from lib/statesman/solid_objects/registration.rb with RBS::Inline
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ class Registration
6
+ @name: String
7
+
8
+ @parent_class: untyped
9
+
10
+ @transition_class: untyped
11
+
12
+ @machine_class: untyped
13
+
14
+ @association: Symbol
15
+
16
+ @after_commit: Symbol
17
+
18
+ attr_reader name: untyped
19
+
20
+ attr_reader parent_class: untyped
21
+
22
+ attr_reader transition_class: untyped
23
+
24
+ attr_reader machine_class: untyped
25
+
26
+ attr_reader association: untyped
27
+
28
+ attr_reader after_commit: untyped
29
+
30
+ # @rbs (name: String, parent_class: untyped, transition_class: untyped, machine_class: untyped, association: Symbol, ?after_commit: Symbol) -> void
31
+ def initialize: (name: String, parent_class: untyped, transition_class: untyped, machine_class: untyped, association: Symbol, ?after_commit: Symbol) -> void
32
+
33
+ # @rbs (untyped) -> String
34
+ def actor_id: (untyped) -> String
35
+
36
+ # @rbs (untyped) -> untyped
37
+ def history: (untyped) -> untyped
38
+
39
+ # @rbs (untyped, ?authorization_context: untyped, **untyped) -> untyped
40
+ def machine: (untyped, ?authorization_context: untyped, **untyped) -> untyped
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,8 @@
1
+ # Generated from lib/statesman/solid_objects/version.rb with RBS::Inline
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ # @rbs VERSION: String
6
+ VERSION: ::String
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ # Generated from lib/statesman/solid_objects.rb with RBS::Inline
2
+
3
+ module Statesman
4
+ module SolidObjects
5
+ @registrations: Hash[String, Registration]
6
+
7
+ # @rbs () -> Hash[String, Registration]
8
+ def self.registrations: () -> Hash[String, Registration]
9
+
10
+ # @rbs (String | Symbol, **untyped) -> Registration
11
+ def self.register: (String | Symbol, **untyped) -> Registration
12
+
13
+ # @rbs () -> void
14
+ def self.install: () -> void
15
+ end
16
+ end
@@ -0,0 +1,2 @@
1
+ # Generated from lib/statesman-solid_objects.rb with RBS::Inline
2
+
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: statesman-solid_objects
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Solid Objects contributors
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-09-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: solid_objects
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.14'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.14.6
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.14'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.14.6
33
+ - !ruby/object:Gem::Dependency
34
+ name: statesman
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.3'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '13.3'
47
+ description: A registered-machine Statesman storage adapter backed by Solid Objects
48
+ mailboxes and transactional Active Record writes.
49
+ email:
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - CHANGELOG.md
55
+ - MIT-LICENSE
56
+ - README.md
57
+ - docs/compatibility.md
58
+ - docs/core-follow-up-prompt.md
59
+ - docs/design.md
60
+ - docs/findings.md
61
+ - docs/prototype-plan.md
62
+ - docs/release-plan.md
63
+ - docs/releases.md
64
+ - docs/verification.md
65
+ - lib/statesman-solid_objects.rb
66
+ - lib/statesman/solid_objects.rb
67
+ - lib/statesman/solid_objects/actor.rb
68
+ - lib/statesman/solid_objects/adapter.rb
69
+ - lib/statesman/solid_objects/execution.rb
70
+ - lib/statesman/solid_objects/registration.rb
71
+ - lib/statesman/solid_objects/version.rb
72
+ - sig/generated/statesman-solid_objects.rbs
73
+ - sig/generated/statesman/solid_objects.rbs
74
+ - sig/generated/statesman/solid_objects/actor.rbs
75
+ - sig/generated/statesman/solid_objects/adapter.rbs
76
+ - sig/generated/statesman/solid_objects/execution.rbs
77
+ - sig/generated/statesman/solid_objects/registration.rbs
78
+ - sig/generated/statesman/solid_objects/version.rbs
79
+ homepage: https://solidobjects.dev
80
+ licenses:
81
+ - MIT
82
+ metadata:
83
+ rubygems_mfa_required: 'true'
84
+ allowed_push_host: https://rubygems.org
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '3.3'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubygems_version: 3.5.22
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Serialized Statesman transitions for Rails
104
+ test_files: []