statecraft 0.1.0 → 0.1.1
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/README.md +20 -0
- data/lib/generators/statecraft/machine/machine_generator.rb +0 -7
- data/lib/generators/statecraft/machine/templates/add_migration.rb.tt +35 -0
- data/lib/generators/statecraft/machine/templates/application_machine.rb.tt +8 -0
- data/lib/generators/statecraft/machine/templates/create_migration.rb.tt +35 -0
- data/lib/generators/statecraft/machine/templates/log_model.rb.tt +9 -0
- data/lib/generators/statecraft/machine/templates/machine.rb.tt +16 -0
- data/lib/generators/statecraft/machine/templates/model.rb.tt +5 -0
- data/lib/statecraft/version.rb +1 -1
- metadata +12 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b9f0a6cac349045859dd7966a325ae9d0a4b27175b846e8f43bd924b298576b6
|
|
4
|
+
data.tar.gz: a148de67af8ddd2bb976ae5ed03db6a38122ebd795013f9aae6c5803e45f7120
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a48dbba9f2e06f23bbcffc0fc632f17f6915954737c2f104c132fa8763823bb9f07a0e754dabf4eb95d14b21b97c912885d0d1efa252c7e3ce64cedeeb206a22
|
|
7
|
+
data.tar.gz: 8256c0463e14d6ddf19d2a757647f81bae4bfa73ecc37796f905adc82d397dbdcb730c45861d23b172711e75aff224482de7dbbdc94a07fbbc9c4cca95fd4c37
|
data/README.md
CHANGED
|
@@ -349,6 +349,26 @@ degrades — the locking clause is dropped, the reload still runs, and
|
|
|
349
349
|
statecraft warns once per machine per process that row-locking guarantees
|
|
350
350
|
require PostgreSQL.
|
|
351
351
|
|
|
352
|
+
## Running the tests
|
|
353
|
+
|
|
354
|
+
Natively, against SQLite:
|
|
355
|
+
|
|
356
|
+
```sh
|
|
357
|
+
bundle install
|
|
358
|
+
bundle exec rspec
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Against PostgreSQL — where the concurrency proof actually runs — point
|
|
362
|
+
`DATABASE_URL` at a database of your own, or use the bundled containers, which
|
|
363
|
+
pin the same PostgreSQL major as CI and take the Ruby and ActiveRecord versions
|
|
364
|
+
as parameters, so any CI matrix cell reproduces locally:
|
|
365
|
+
|
|
366
|
+
```sh
|
|
367
|
+
docker compose run --rm test # sqlite, default Ruby
|
|
368
|
+
docker compose run --rm test-postgres # PostgreSQL 16
|
|
369
|
+
AR_VERSION=7.2 RUBY_VERSION=3.3 docker compose run --rm test-postgres
|
|
370
|
+
```
|
|
371
|
+
|
|
352
372
|
## License
|
|
353
373
|
|
|
354
374
|
MIT. See [LICENSE.txt](LICENSE.txt).
|
|
@@ -93,13 +93,6 @@ module Statecraft
|
|
|
93
93
|
def migration_class_name
|
|
94
94
|
"Create#{class_name}StateMachine"
|
|
95
95
|
end
|
|
96
|
-
|
|
97
|
-
def metadata_column_type
|
|
98
|
-
adapter = ActiveRecord::Base.connection.adapter_name
|
|
99
|
-
adapter.match?(/postg/i) ? "jsonb" : "json"
|
|
100
|
-
rescue ActiveRecord::ActiveRecordError
|
|
101
|
-
"jsonb"
|
|
102
|
-
end
|
|
103
96
|
end
|
|
104
97
|
end
|
|
105
98
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
4
|
+
def change
|
|
5
|
+
add_column :<%= table_name %>, :state, :string, null: false, default: "pending"
|
|
6
|
+
add_index :<%= table_name %>, :state
|
|
7
|
+
add_column :<%= table_name %>, :state_changed_at, :datetime
|
|
8
|
+
|
|
9
|
+
# The existing table may carry legacy values, so no CHECK constraint is
|
|
10
|
+
# generated here. To add one later without blocking writes:
|
|
11
|
+
# ALTER TABLE ... ADD CONSTRAINT ... CHECK (state IN (...)) NOT VALID;
|
|
12
|
+
# -- clean the data --
|
|
13
|
+
# ALTER TABLE ... VALIDATE CONSTRAINT ...;
|
|
14
|
+
|
|
15
|
+
create_table :<%= log_table_name.pluralize %> do |t|
|
|
16
|
+
t.references :<%= file_name %>, null: false,
|
|
17
|
+
foreign_key: { to_table: :<%= table_name %>, on_delete: :cascade },
|
|
18
|
+
index: false
|
|
19
|
+
t.string :from_state, null: false
|
|
20
|
+
t.string :to_state, null: false
|
|
21
|
+
t.string :event
|
|
22
|
+
t.column :metadata, metadata_column_type, null: false, default: {}
|
|
23
|
+
t.datetime :created_at, null: false
|
|
24
|
+
t.index %i[<%= foreign_key_column %> id]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# jsonb where the database has it, json elsewhere: the adapter is known
|
|
31
|
+
# only when the migration actually runs, never at generation time.
|
|
32
|
+
def metadata_column_type
|
|
33
|
+
connection.adapter_name.match?(/postg/i) ? :jsonb : :json
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Shared home for private guard helpers used by several machines. Keep it
|
|
4
|
+
# free of DSL declarations (states, transitions, events): machine definitions
|
|
5
|
+
# are NOT inherited — each machine declares its own graph.
|
|
6
|
+
class ApplicationMachine
|
|
7
|
+
include Statecraft::Machine
|
|
8
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
4
|
+
def change
|
|
5
|
+
create_table :<%= table_name %> do |t|
|
|
6
|
+
t.string :state, null: false, default: "pending", index: true
|
|
7
|
+
t.datetime :state_changed_at
|
|
8
|
+
t.timestamps null: false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# add new states here when the machine grows
|
|
12
|
+
add_check_constraint :<%= table_name %>, "state IN ('pending')",
|
|
13
|
+
name: "<%= table_name %>_state_check"
|
|
14
|
+
|
|
15
|
+
create_table :<%= log_table_name.pluralize %> do |t|
|
|
16
|
+
t.references :<%= file_name %>, null: false,
|
|
17
|
+
foreign_key: { to_table: :<%= table_name %>, on_delete: :cascade },
|
|
18
|
+
index: false
|
|
19
|
+
t.string :from_state, null: false
|
|
20
|
+
t.string :to_state, null: false
|
|
21
|
+
t.string :event
|
|
22
|
+
t.column :metadata, metadata_column_type, null: false, default: {}
|
|
23
|
+
t.datetime :created_at, null: false
|
|
24
|
+
t.index %i[<%= foreign_key_column %> id]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# jsonb where the database has it, json elsewhere: the adapter is known
|
|
31
|
+
# only when the migration actually runs, never at generation time.
|
|
32
|
+
def metadata_column_type
|
|
33
|
+
connection.adapter_name.match?(/postg/i) ? :jsonb : :json
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Append-only transition log for <%= class_name %>. This is a read-model:
|
|
4
|
+
# scopes, reading methods and serializers are yours; the transition pipeline
|
|
5
|
+
# writes rows through the insert path and never calls validations or
|
|
6
|
+
# callbacks declared here.
|
|
7
|
+
class <%= class_name %>Transition < <%= parent_class_name %>
|
|
8
|
+
def readonly? = persisted?
|
|
9
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class <%= class_name %>Flow < ApplicationMachine
|
|
4
|
+
state :pending, initial: true
|
|
5
|
+
# state :paid
|
|
6
|
+
#
|
|
7
|
+
# event :pay, from: :pending, to: :paid, guard: :payable?
|
|
8
|
+
#
|
|
9
|
+
# Guards and callbacks resolve to instance methods of this class:
|
|
10
|
+
#
|
|
11
|
+
# private
|
|
12
|
+
#
|
|
13
|
+
# def payable?(record, metadata)
|
|
14
|
+
# metadata["amount"].to_i.positive?
|
|
15
|
+
# end
|
|
16
|
+
end
|
data/lib/statecraft/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: statecraft
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Igor Pugachev
|
|
@@ -61,6 +61,12 @@ files:
|
|
|
61
61
|
- LICENSE.txt
|
|
62
62
|
- README.md
|
|
63
63
|
- lib/generators/statecraft/machine/machine_generator.rb
|
|
64
|
+
- lib/generators/statecraft/machine/templates/add_migration.rb.tt
|
|
65
|
+
- lib/generators/statecraft/machine/templates/application_machine.rb.tt
|
|
66
|
+
- lib/generators/statecraft/machine/templates/create_migration.rb.tt
|
|
67
|
+
- lib/generators/statecraft/machine/templates/log_model.rb.tt
|
|
68
|
+
- lib/generators/statecraft/machine/templates/machine.rb.tt
|
|
69
|
+
- lib/generators/statecraft/machine/templates/model.rb.tt
|
|
64
70
|
- lib/statecraft.rb
|
|
65
71
|
- lib/statecraft/errors.rb
|
|
66
72
|
- lib/statecraft/instrumentation.rb
|
|
@@ -71,9 +77,14 @@ files:
|
|
|
71
77
|
- lib/statecraft/pipeline.rb
|
|
72
78
|
- lib/statecraft/version.rb
|
|
73
79
|
- lib/statecraft/warnings.rb
|
|
80
|
+
homepage: https://supostat.github.io/statecraft/
|
|
74
81
|
licenses:
|
|
75
82
|
- MIT
|
|
76
83
|
metadata:
|
|
84
|
+
homepage_uri: https://supostat.github.io/statecraft/
|
|
85
|
+
source_code_uri: https://github.com/supostat/statecraft
|
|
86
|
+
changelog_uri: https://github.com/supostat/statecraft/releases
|
|
87
|
+
bug_tracker_uri: https://github.com/supostat/statecraft/issues
|
|
77
88
|
rubygems_mfa_required: 'true'
|
|
78
89
|
rdoc_options: []
|
|
79
90
|
require_paths:
|