igniter-ledger 0.5.2
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 +7 -0
- data/README.md +481 -0
- data/examples/intelligent_ledger/availability_boundary_ledger.rb +1190 -0
- data/examples/intelligent_ledger/availability_deriver.rb +150 -0
- data/examples/intelligent_ledger/availability_ledger.rb +197 -0
- data/examples/intelligent_ledger/ledger_boundary.rb +180 -0
- data/examples/store_poc.rb +45 -0
- data/exe/igniter-ledger-server +111 -0
- data/exe/igniter-store-server +6 -0
- data/ext/igniter_store_native/Cargo.toml +28 -0
- data/ext/igniter_store_native/extconf.rb +6 -0
- data/ext/igniter_store_native/src/fact.rs +303 -0
- data/ext/igniter_store_native/src/fact_log.rs +180 -0
- data/ext/igniter_store_native/src/file_backend.rs +91 -0
- data/ext/igniter_store_native/src/lib.rs +55 -0
- data/lib/igniter/ledger.rb +7 -0
- data/lib/igniter/store/access_path.rb +84 -0
- data/lib/igniter/store/change_event.rb +65 -0
- data/lib/igniter/store/changefeed_buffer.rb +585 -0
- data/lib/igniter/store/codecs.rb +253 -0
- data/lib/igniter/store/contractable_receipt_sink.rb +172 -0
- data/lib/igniter/store/fact.rb +121 -0
- data/lib/igniter/store/fact_log.rb +103 -0
- data/lib/igniter/store/file_backend.rb +269 -0
- data/lib/igniter/store/http_adapter.rb +413 -0
- data/lib/igniter/store/igniter_store.rb +838 -0
- data/lib/igniter/store/mcp_adapter.rb +403 -0
- data/lib/igniter/store/native.rb +80 -0
- data/lib/igniter/store/network_backend.rb +159 -0
- data/lib/igniter/store/protocol/handlers/access_path_handler.rb +38 -0
- data/lib/igniter/store/protocol/handlers/command_handler.rb +59 -0
- data/lib/igniter/store/protocol/handlers/derivation_handler.rb +27 -0
- data/lib/igniter/store/protocol/handlers/effect_handler.rb +65 -0
- data/lib/igniter/store/protocol/handlers/history_handler.rb +24 -0
- data/lib/igniter/store/protocol/handlers/projection_handler.rb +41 -0
- data/lib/igniter/store/protocol/handlers/relation_handler.rb +43 -0
- data/lib/igniter/store/protocol/handlers/store_handler.rb +24 -0
- data/lib/igniter/store/protocol/handlers/subscription_handler.rb +24 -0
- data/lib/igniter/store/protocol/interpreter.rb +447 -0
- data/lib/igniter/store/protocol/receipt.rb +96 -0
- data/lib/igniter/store/protocol/sync_profile.rb +53 -0
- data/lib/igniter/store/protocol/wire_envelope.rb +214 -0
- data/lib/igniter/store/protocol.rb +27 -0
- data/lib/igniter/store/read_cache.rb +163 -0
- data/lib/igniter/store/schema_graph.rb +248 -0
- data/lib/igniter/store/segmented_file_backend.rb +699 -0
- data/lib/igniter/store/server_config.rb +55 -0
- data/lib/igniter/store/server_logger.rb +64 -0
- data/lib/igniter/store/server_metrics.rb +222 -0
- data/lib/igniter/store/store_server.rb +597 -0
- data/lib/igniter/store/subscription_registry.rb +73 -0
- data/lib/igniter/store/tbackend_adapter_descriptor.rb +307 -0
- data/lib/igniter/store/tcp_adapter.rb +127 -0
- data/lib/igniter/store/wire_protocol.rb +42 -0
- data/lib/igniter/store.rb +64 -0
- data/lib/igniter-ledger.rb +4 -0
- data/lib/igniter-store.rb +5 -0
- metadata +212 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Igniter
|
|
4
|
+
module Store
|
|
5
|
+
# Engine routing descriptor: how the store routes scope queries for a given store/scope pair.
|
|
6
|
+
AccessPath = Struct.new(
|
|
7
|
+
:store,
|
|
8
|
+
:lookup,
|
|
9
|
+
:scope,
|
|
10
|
+
:filters,
|
|
11
|
+
:cache_ttl,
|
|
12
|
+
:consumers,
|
|
13
|
+
keyword_init: true
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Retention policy for a store — controls compaction behaviour.
|
|
17
|
+
# strategy: :permanent — never compact (default)
|
|
18
|
+
# :ephemeral — keep only latest fact per key; drop all historical
|
|
19
|
+
# :rolling_window — drop historical facts older than duration seconds,
|
|
20
|
+
# always preserving the latest per key
|
|
21
|
+
# duration: Float seconds (required for :rolling_window)
|
|
22
|
+
RetentionPolicy = Struct.new(
|
|
23
|
+
:strategy, # Symbol
|
|
24
|
+
:duration, # Float | nil
|
|
25
|
+
keyword_init: true
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Derivation rule: when facts matching source_store/source_filters change, call
|
|
29
|
+
# rule.(source_facts) and write the result to target_store at target_key.
|
|
30
|
+
# source_filters: {} means all latest facts per key in that store.
|
|
31
|
+
# rule returning nil skips the derived write.
|
|
32
|
+
# target_key may be a String/Symbol or a callable(Array<Fact>) → String.
|
|
33
|
+
DerivationRule = Struct.new(
|
|
34
|
+
:source_store, # Symbol
|
|
35
|
+
:source_filters, # Hash
|
|
36
|
+
:target_store, # Symbol
|
|
37
|
+
:target_key, # String | Symbol | callable
|
|
38
|
+
:rule, # callable(Array<Fact>) → Hash | nil
|
|
39
|
+
keyword_init: true
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Read-model descriptor: which stores and relations a cross-record projection reads.
|
|
43
|
+
# Metadata-only — no execution happens inside the store engine.
|
|
44
|
+
# Registered in SchemaGraph so the engine knows which projections depend on which stores.
|
|
45
|
+
ProjectionPath = Struct.new(
|
|
46
|
+
:name, # Symbol — projection name, e.g. :tracker_read_model
|
|
47
|
+
:reads, # Array<Symbol> — store names this projection reads from
|
|
48
|
+
:relations, # Array<Symbol> — relation names used when composing sources
|
|
49
|
+
:consumer_hint, # Symbol — which layer executes this projection (:contract_node, etc.)
|
|
50
|
+
:reactive, # Boolean — whether push-reactive delivery is expected
|
|
51
|
+
keyword_init: true
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Declarative relation between two stores. Backed by a ScatterRule that
|
|
55
|
+
# maintains a materialized index in :"__rel_<name>".
|
|
56
|
+
# source: Symbol — store whose facts carry the foreign key
|
|
57
|
+
# partition: Symbol — field in source fact's value that holds the FK value
|
|
58
|
+
# target: Symbol — logical "owning" store (informational / metadata only)
|
|
59
|
+
# Resolved via IgniterStore#resolve(name, from: partition_value).
|
|
60
|
+
RelationRule = Struct.new(
|
|
61
|
+
:name, # Symbol — relation name, e.g. :article_comments
|
|
62
|
+
:source, # Symbol — source store
|
|
63
|
+
:partition, # Symbol — FK field in source fact's value
|
|
64
|
+
:target, # Symbol — logical target store (metadata only)
|
|
65
|
+
keyword_init: true
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Scatter derivation rule: when a fact is written to source_store,
|
|
69
|
+
# extract partition_by field from its value to determine the target key,
|
|
70
|
+
# then call rule.(partition_key, existing_value, new_fact) → Hash | nil
|
|
71
|
+
# to update exactly one entry in target_store.
|
|
72
|
+
#
|
|
73
|
+
# Unlike Gather (DerivationRule), Scatter is 1-source → 1-index-entry:
|
|
74
|
+
# the rule accumulates into an existing value rather than re-evaluating
|
|
75
|
+
# the full source set. rule returning nil skips the write.
|
|
76
|
+
ScatterRule = Struct.new(
|
|
77
|
+
:source_store, # Symbol — store that triggers the scatter
|
|
78
|
+
:partition_by, # Symbol — key in source fact's value used as target key
|
|
79
|
+
:target_store, # Symbol — store where the index entry is written
|
|
80
|
+
:rule, # callable(partition_key, existing_value, new_fact) → Hash | nil
|
|
81
|
+
keyword_init: true
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module Igniter
|
|
6
|
+
module Store
|
|
7
|
+
# Immutable value object emitted after each committed fact write.
|
|
8
|
+
#
|
|
9
|
+
# Carries a compact reference to the committed fact (fact_id, store, key,
|
|
10
|
+
# timestamps, causation) plus a monotonic cursor sequence assigned by the
|
|
11
|
+
# emitting ChangefeedBuffer.
|
|
12
|
+
#
|
|
13
|
+
# The +fact+ field carries the full Fact object for transports (e.g. TCP push)
|
|
14
|
+
# that need the complete payload on delivery. It is not included in +to_h+
|
|
15
|
+
# to keep wire representations compact.
|
|
16
|
+
ChangeEvent = Struct.new(
|
|
17
|
+
:schema_version,
|
|
18
|
+
:id,
|
|
19
|
+
:type,
|
|
20
|
+
:store,
|
|
21
|
+
:key,
|
|
22
|
+
:fact_id,
|
|
23
|
+
:transaction_time,
|
|
24
|
+
:emitted_at,
|
|
25
|
+
:producer,
|
|
26
|
+
:causation,
|
|
27
|
+
:cursor,
|
|
28
|
+
:fact,
|
|
29
|
+
keyword_init: true
|
|
30
|
+
) do
|
|
31
|
+
def self.from_fact(fact, sequence:)
|
|
32
|
+
new(
|
|
33
|
+
schema_version: 1,
|
|
34
|
+
id: "change_#{SecureRandom.uuid}",
|
|
35
|
+
type: :fact_committed,
|
|
36
|
+
store: fact.store,
|
|
37
|
+
key: fact.key,
|
|
38
|
+
fact_id: fact.id,
|
|
39
|
+
transaction_time: fact.transaction_time,
|
|
40
|
+
emitted_at: Process.clock_gettime(Process::CLOCK_REALTIME),
|
|
41
|
+
producer: fact.producer,
|
|
42
|
+
causation: fact.causation,
|
|
43
|
+
cursor: { sequence: sequence }.freeze,
|
|
44
|
+
fact: fact
|
|
45
|
+
).freeze
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_h
|
|
49
|
+
{
|
|
50
|
+
schema_version: schema_version,
|
|
51
|
+
id: id,
|
|
52
|
+
type: type,
|
|
53
|
+
store: store,
|
|
54
|
+
key: key,
|
|
55
|
+
fact_id: fact_id,
|
|
56
|
+
transaction_time: transaction_time,
|
|
57
|
+
emitted_at: emitted_at,
|
|
58
|
+
producer: producer,
|
|
59
|
+
causation: causation,
|
|
60
|
+
cursor: cursor
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|