@feltdb/core 0.4.12 → 0.4.13

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.
Files changed (164) hide show
  1. package/dist/cli/commands.js +5 -2
  2. package/dist/cli/index.js +1 -1
  3. package/dist/create/cli.js +16 -1
  4. package/dist/create/create.js +30 -16
  5. package/dist/create/docker-compose-generator.js +48 -9
  6. package/dist/create/package-versions.js +1 -1
  7. package/dist/create/server-source/Cargo.lock +2238 -0
  8. package/dist/create/server-source/Cargo.toml +7 -0
  9. package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
  10. package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
  11. package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
  12. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
  13. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
  14. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
  15. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
  16. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
  17. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
  18. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
  19. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
  20. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
  21. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
  22. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
  23. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
  24. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
  25. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
  26. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
  27. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
  28. package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
  29. package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
  30. package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
  31. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
  32. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
  33. package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
  34. package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
  35. package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
  36. package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
  37. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
  38. package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
  39. package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
  40. package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
  41. package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
  42. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
  43. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
  44. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
  45. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
  46. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
  47. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
  48. package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
  49. package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
  50. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
  51. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
  52. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
  53. package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
  54. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
  55. package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
  56. package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
  57. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
  58. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
  59. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
  60. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
  61. package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
  62. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
  63. package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
  64. package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
  65. package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
  66. package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
  67. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
  68. package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
  69. package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
  70. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
  71. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
  72. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
  73. package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
  74. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
  75. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
  76. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
  77. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
  78. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
  79. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
  80. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
  81. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
  82. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
  83. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
  84. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
  85. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
  86. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
  87. package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
  88. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
  89. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
  90. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
  91. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
  92. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
  93. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
  94. package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
  95. package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
  96. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
  97. package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
  98. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
  99. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
  100. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
  101. package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
  102. package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
  103. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
  104. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
  105. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
  106. package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
  107. package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
  108. package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
  109. package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
  110. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
  111. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
  112. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
  113. package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
  114. package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
  115. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
  116. package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
  117. package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
  118. package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
  119. package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
  120. package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
  121. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
  122. package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
  123. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
  124. package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
  125. package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
  126. package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
  127. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
  128. package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
  129. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
  130. package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
  131. package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
  132. package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
  133. package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
  134. package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
  135. package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
  136. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
  137. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
  138. package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
  139. package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
  140. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
  141. package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
  142. package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
  143. package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
  144. package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
  145. package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
  146. package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
  147. package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
  148. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
  149. package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
  150. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
  151. package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
  152. package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
  153. package/dist/flowspec.d.ts +2 -0
  154. package/dist/flowspec.d.ts.map +1 -1
  155. package/dist/flowspec.js +28 -4
  156. package/dist/state-contract.d.ts +7 -1
  157. package/dist/state-contract.d.ts.map +1 -1
  158. package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
  159. package/dist/studio/components/index.js +1 -1
  160. package/dist/studio/{components-Q0Nx6gLE.js → components-bHTARBin.js} +156 -46
  161. package/dist/studio/index.js +31 -28
  162. package/dist/studio-app/assets/{index-BHOmLZF-.js → index-BqKquLuU.js} +8 -8
  163. package/dist/studio-app/index.html +1 -1
  164. package/package.json +1 -1
@@ -0,0 +1,473 @@
1
+ /// Transaction API Layer
2
+ ///
3
+ /// Public-facing transaction management API that integrates:
4
+ /// - TransactionExecutor for execution logic
5
+ /// - OperationLog for operation persistence
6
+ /// - StateTransitionStore for transition durability
7
+ /// - Precondition validation
8
+ /// - Read/write dependency tracking
9
+
10
+ use crate::convergence::VectorClock;
11
+ use crate::operation_log::{MemoryOperationLog, OperationLogEntry};
12
+ use crate::state_transition_store::{MemoryStateTransitionStore, StateTransitionRecord};
13
+ use crate::transactions::*;
14
+ use std::sync::{Arc, Mutex};
15
+
16
+ /// Result type for transaction API operations
17
+ pub type TxResult<T> = Result<T, TxError>;
18
+
19
+ /// Transaction API errors
20
+ #[derive(Clone, Debug)]
21
+ pub enum TxError {
22
+ PreconditionFailed(String),
23
+ ConflictDetected(String),
24
+ OperationDeduplication(String),
25
+ InvalidState(String),
26
+ PersistenceFailure(String),
27
+ }
28
+
29
+ impl std::fmt::Display for TxError {
30
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31
+ match self {
32
+ TxError::PreconditionFailed(msg) => write!(f, "Precondition failed: {}", msg),
33
+ TxError::ConflictDetected(msg) => write!(f, "Conflict detected: {}", msg),
34
+ TxError::OperationDeduplication(msg) => write!(f, "Operation already executed: {}", msg),
35
+ TxError::InvalidState(msg) => write!(f, "Invalid state: {}", msg),
36
+ TxError::PersistenceFailure(msg) => write!(f, "Persistence failure: {}", msg),
37
+ }
38
+ }
39
+ }
40
+
41
+ impl std::error::Error for TxError {}
42
+
43
+ /// Transaction manager combining execution, persistence, and validation
44
+ pub struct TransactionManager {
45
+ node_id: String,
46
+ executor: TransactionExecutor,
47
+ operation_log: MemoryOperationLog,
48
+ transition_store: MemoryStateTransitionStore,
49
+ current_version: Arc<Mutex<StateVersion>>,
50
+ }
51
+
52
+ impl TransactionManager {
53
+ /// Create a new transaction manager
54
+ pub fn new(node_id: String, initial_version: StateVersion) -> Self {
55
+ Self {
56
+ node_id: node_id.clone(),
57
+ executor: TransactionExecutor::new(node_id),
58
+ operation_log: MemoryOperationLog::new(),
59
+ transition_store: MemoryStateTransitionStore::new(),
60
+ current_version: Arc::new(Mutex::new(initial_version)),
61
+ }
62
+ }
63
+
64
+ /// Get the current state version
65
+ pub fn current_state_version(&self) -> StateVersion {
66
+ self.current_version.lock().unwrap().clone()
67
+ }
68
+
69
+ /// Execute a transaction with full persistence integration
70
+ pub fn execute_and_commit(
71
+ &mut self,
72
+ transaction_id: String,
73
+ mut operations: Vec<Operation>,
74
+ consistency_contract: ConsistencyContract,
75
+ ) -> TxResult<StateTransitionRecord> {
76
+ // 1. Validate all operations are new (not duplicated in operation log)
77
+ for op in &operations {
78
+ if self.operation_log.contains_operation_id(&op.operation_id) {
79
+ return Err(TxError::OperationDeduplication(format!(
80
+ "Operation {} already executed",
81
+ format!("{}:{}", op.operation_id.node_id, op.operation_id.sequence)
82
+ )));
83
+ }
84
+ }
85
+
86
+ // 2. Set transaction_id on all operations
87
+ for op in &mut operations {
88
+ op.transaction_id = Some(transaction_id.clone());
89
+ }
90
+
91
+ // 3. Execute transaction
92
+ let current_version = self.current_version.lock().unwrap().clone();
93
+ let transition = self.executor.execute_transaction(
94
+ transaction_id.clone(),
95
+ current_version,
96
+ operations.clone(),
97
+ consistency_contract,
98
+ );
99
+
100
+ // 4. Validate transition succeeded
101
+ if !transition.is_successful() {
102
+ return Err(TxError::InvalidState("Transaction execution failed".to_string()));
103
+ }
104
+
105
+ // 5. Persist operations to operation log
106
+ for op in &transition.operations {
107
+ self.operation_log
108
+ .append(op.clone())
109
+ .map_err(|e| TxError::PersistenceFailure(e))?;
110
+ }
111
+
112
+ // 6. Persist transition to state transition store
113
+ let store_index = self.transition_store
114
+ .record_transition(transition.clone())
115
+ .map_err(|e| TxError::PersistenceFailure(e))?;
116
+
117
+ // 7. Update current version
118
+ {
119
+ let mut current = self.current_version.lock().unwrap();
120
+ *current = transition.to_version.clone();
121
+ }
122
+
123
+ // 8. Retrieve the recorded transition
124
+ let record = self.transition_store
125
+ .get_by_index(store_index)
126
+ .ok_or_else(|| TxError::PersistenceFailure("Failed to retrieve recorded transition".to_string()))?;
127
+
128
+ Ok(record)
129
+ }
130
+
131
+ /// Get a recorded operation by ID
132
+ pub fn get_operation(&self, operation_id: &OperationId) -> Option<OperationLogEntry> {
133
+ self.operation_log.get_by_id(operation_id)
134
+ }
135
+
136
+ /// Get a recorded transition by transaction ID
137
+ pub fn get_transition(&self, transaction_id: &str) -> Option<StateTransitionRecord> {
138
+ self.transition_store.get_by_transaction_id(transaction_id)
139
+ }
140
+
141
+ /// Get the operation log size
142
+ pub fn operation_log_size(&self) -> u64 {
143
+ self.operation_log.size()
144
+ }
145
+
146
+ /// Get the transition store size
147
+ pub fn transition_store_size(&self) -> u64 {
148
+ self.transition_store.size()
149
+ }
150
+
151
+ /// Rebuild state from operation log (for recovery)
152
+ /// Executes all operations in order to verify state integrity
153
+ pub fn rebuild_from_operation_log(&mut self) -> TxResult<StateVersion> {
154
+ let all_ops = self.operation_log.iter();
155
+
156
+ if all_ops.is_empty() {
157
+ return Ok(self.current_state_version());
158
+ }
159
+
160
+ let mut current_version = StateVersion::new(VectorClock::new(), "genesis".to_string());
161
+
162
+ for entry in all_ops {
163
+ let transition = self.executor.execute_transaction(
164
+ entry.operation.transaction_id.clone().unwrap_or_default(),
165
+ current_version.clone(),
166
+ vec![entry.operation.clone()],
167
+ ConsistencyContract::local(),
168
+ );
169
+
170
+ if !transition.is_successful() {
171
+ return Err(TxError::InvalidState(
172
+ "Failed to rebuild state from operation log".to_string(),
173
+ ));
174
+ }
175
+
176
+ current_version = transition.to_version;
177
+ }
178
+
179
+ {
180
+ let mut current = self.current_version.lock().unwrap();
181
+ *current = current_version.clone();
182
+ }
183
+
184
+ Ok(current_version)
185
+ }
186
+
187
+ /// Get the chain of state transitions from a starting version
188
+ pub fn get_transition_chain_from(&self, from_state_hash: &str) -> Vec<StateTransitionRecord> {
189
+ self.transition_store.get_transition_chain(from_state_hash)
190
+ }
191
+
192
+ /// Validate preconditions for an operation
193
+ /// (Simple string matching - production would have actual condition evaluation)
194
+ pub fn validate_preconditions(
195
+ &self,
196
+ operation: &Operation,
197
+ ) -> TxResult<()> {
198
+ if operation.preconditions.is_empty() {
199
+ return Ok(());
200
+ }
201
+
202
+ // Placeholder: In production, would evaluate actual state conditions
203
+ // For now, just verify preconditions are syntactically valid
204
+ for (condition_name, condition) in &operation.preconditions {
205
+ if condition.is_empty() {
206
+ return Err(TxError::PreconditionFailed(format!(
207
+ "Empty condition: {}",
208
+ condition_name
209
+ )));
210
+ }
211
+ }
212
+
213
+ Ok(())
214
+ }
215
+ }
216
+
217
+ #[cfg(test)]
218
+ mod tests {
219
+ use super::*;
220
+ use crate::transactions::OperationCommand;
221
+ use std::collections::HashMap;
222
+
223
+ #[test]
224
+ fn test_create_transaction_manager() {
225
+ let mut vc = VectorClock::new();
226
+ vc.increment("node1");
227
+ let version = StateVersion::new(vc, "hash0".to_string());
228
+
229
+ let manager = TransactionManager::new("node1".to_string(), version);
230
+
231
+ assert_eq!(manager.operation_log_size(), 0);
232
+ assert_eq!(manager.transition_store_size(), 0);
233
+ }
234
+
235
+ #[test]
236
+ fn test_execute_and_commit_single_operation() {
237
+ let mut vc = VectorClock::new();
238
+ vc.increment("node1");
239
+ let version = StateVersion::new(vc, "hash0".to_string());
240
+
241
+ let mut manager = TransactionManager::new("node1".to_string(), version);
242
+
243
+ let op = Operation::new(
244
+ OperationId::new("node1".to_string(), 1),
245
+ manager.current_state_version(),
246
+ "Update".to_string(),
247
+ OperationCommand {
248
+ op_type: "UpdateField".to_string(),
249
+ collection: "test".to_string(),
250
+ record_id: "rec1".to_string(),
251
+ fields: {
252
+ let mut m = HashMap::new();
253
+ m.insert("field".to_string(), serde_json::json!("value"));
254
+ m
255
+ },
256
+ },
257
+ "user".to_string(),
258
+ );
259
+
260
+ let result = manager.execute_and_commit(
261
+ "txn1".to_string(),
262
+ vec![op],
263
+ ConsistencyContract::local(),
264
+ );
265
+
266
+ assert!(result.is_ok());
267
+ assert_eq!(manager.operation_log_size(), 1);
268
+ assert_eq!(manager.transition_store_size(), 1);
269
+ }
270
+
271
+ #[test]
272
+ fn test_duplicate_operation_rejection() {
273
+ let mut vc = VectorClock::new();
274
+ vc.increment("node1");
275
+ let version = StateVersion::new(vc, "hash0".to_string());
276
+
277
+ let mut manager = TransactionManager::new("node1".to_string(), version);
278
+
279
+ let op = Operation::new(
280
+ OperationId::new("node1".to_string(), 1),
281
+ manager.current_state_version(),
282
+ "Update".to_string(),
283
+ OperationCommand {
284
+ op_type: "UpdateField".to_string(),
285
+ collection: "test".to_string(),
286
+ record_id: "rec1".to_string(),
287
+ fields: {
288
+ let mut m = HashMap::new();
289
+ m.insert("field".to_string(), serde_json::json!("value"));
290
+ m
291
+ },
292
+ },
293
+ "user".to_string(),
294
+ );
295
+
296
+ let _ = manager.execute_and_commit(
297
+ "txn1".to_string(),
298
+ vec![op.clone()],
299
+ ConsistencyContract::local(),
300
+ );
301
+
302
+ let result = manager.execute_and_commit(
303
+ "txn2".to_string(),
304
+ vec![op],
305
+ ConsistencyContract::local(),
306
+ );
307
+
308
+ assert!(result.is_err());
309
+ assert!(result.unwrap_err().to_string().contains("already executed"));
310
+ }
311
+
312
+ #[test]
313
+ fn test_get_operation_after_commit() {
314
+ let mut vc = VectorClock::new();
315
+ vc.increment("node1");
316
+ let version = StateVersion::new(vc, "hash0".to_string());
317
+
318
+ let mut manager = TransactionManager::new("node1".to_string(), version);
319
+
320
+ let op_id = OperationId::new("node1".to_string(), 1);
321
+ let op = Operation::new(
322
+ op_id.clone(),
323
+ manager.current_state_version(),
324
+ "Update".to_string(),
325
+ OperationCommand {
326
+ op_type: "UpdateField".to_string(),
327
+ collection: "test".to_string(),
328
+ record_id: "rec1".to_string(),
329
+ fields: {
330
+ let mut m = HashMap::new();
331
+ m.insert("field".to_string(), serde_json::json!("value"));
332
+ m
333
+ },
334
+ },
335
+ "user".to_string(),
336
+ );
337
+
338
+ let _ = manager.execute_and_commit(
339
+ "txn1".to_string(),
340
+ vec![op],
341
+ ConsistencyContract::local(),
342
+ );
343
+
344
+ let retrieved = manager.get_operation(&op_id);
345
+ assert!(retrieved.is_some());
346
+ }
347
+
348
+ #[test]
349
+ fn test_get_transition_after_commit() {
350
+ let mut vc = VectorClock::new();
351
+ vc.increment("node1");
352
+ let version = StateVersion::new(vc, "hash0".to_string());
353
+
354
+ let mut manager = TransactionManager::new("node1".to_string(), version);
355
+
356
+ let op = Operation::new(
357
+ OperationId::new("node1".to_string(), 1),
358
+ manager.current_state_version(),
359
+ "Update".to_string(),
360
+ OperationCommand {
361
+ op_type: "UpdateField".to_string(),
362
+ collection: "test".to_string(),
363
+ record_id: "rec1".to_string(),
364
+ fields: {
365
+ let mut m = HashMap::new();
366
+ m.insert("field".to_string(), serde_json::json!("value"));
367
+ m
368
+ },
369
+ },
370
+ "user".to_string(),
371
+ );
372
+
373
+ let _ = manager.execute_and_commit(
374
+ "txn1".to_string(),
375
+ vec![op],
376
+ ConsistencyContract::local(),
377
+ );
378
+
379
+ let transition = manager.get_transition("txn1");
380
+ assert!(transition.is_some());
381
+ }
382
+
383
+ #[test]
384
+ fn test_precondition_validation() {
385
+ let mut vc = VectorClock::new();
386
+ vc.increment("node1");
387
+ let version = StateVersion::new(vc, "hash0".to_string());
388
+
389
+ let manager = TransactionManager::new("node1".to_string(), version);
390
+
391
+ let mut op = Operation::new(
392
+ OperationId::new("node1".to_string(), 1),
393
+ manager.current_state_version(),
394
+ "Update".to_string(),
395
+ OperationCommand {
396
+ op_type: "UpdateField".to_string(),
397
+ collection: "test".to_string(),
398
+ record_id: "rec1".to_string(),
399
+ fields: {
400
+ let mut m = HashMap::new();
401
+ m.insert("field".to_string(), serde_json::json!("value"));
402
+ m
403
+ },
404
+ },
405
+ "user".to_string(),
406
+ );
407
+
408
+ op = op.with_preconditions(vec![("count".to_string(), "count >= 2".to_string())]);
409
+
410
+ let result = manager.validate_preconditions(&op);
411
+ assert!(result.is_ok());
412
+
413
+ let mut bad_op = Operation::new(
414
+ OperationId::new("node1".to_string(), 2),
415
+ manager.current_state_version(),
416
+ "Update".to_string(),
417
+ OperationCommand {
418
+ op_type: "UpdateField".to_string(),
419
+ collection: "test".to_string(),
420
+ record_id: "rec2".to_string(),
421
+ fields: {
422
+ let mut m = HashMap::new();
423
+ m.insert("field".to_string(), serde_json::json!("value"));
424
+ m
425
+ },
426
+ },
427
+ "user".to_string(),
428
+ );
429
+
430
+ bad_op = bad_op.with_preconditions(vec![("invalid".to_string(), "".to_string())]);
431
+
432
+ let bad_result = manager.validate_preconditions(&bad_op);
433
+ assert!(bad_result.is_err());
434
+ }
435
+
436
+ #[test]
437
+ fn test_current_state_version_tracking() {
438
+ let mut vc = VectorClock::new();
439
+ vc.increment("node1");
440
+ let initial_version = StateVersion::new(vc, "hash0".to_string());
441
+ let initial_hash = initial_version.state_hash.clone();
442
+
443
+ let mut manager = TransactionManager::new("node1".to_string(), initial_version);
444
+
445
+ assert_eq!(manager.current_state_version().state_hash, initial_hash);
446
+
447
+ let op = Operation::new(
448
+ OperationId::new("node1".to_string(), 1),
449
+ manager.current_state_version(),
450
+ "Update".to_string(),
451
+ OperationCommand {
452
+ op_type: "UpdateField".to_string(),
453
+ collection: "test".to_string(),
454
+ record_id: "rec1".to_string(),
455
+ fields: {
456
+ let mut m = HashMap::new();
457
+ m.insert("field".to_string(), serde_json::json!("value"));
458
+ m
459
+ },
460
+ },
461
+ "user".to_string(),
462
+ );
463
+
464
+ let _ = manager.execute_and_commit(
465
+ "txn1".to_string(),
466
+ vec![op],
467
+ ConsistencyContract::local(),
468
+ );
469
+
470
+ let new_version = manager.current_state_version();
471
+ assert_ne!(new_version.state_hash, initial_hash);
472
+ }
473
+ }