@feltdb/core 0.4.12 → 0.4.14

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 (165) hide show
  1. package/dist/cli/commands.js +42 -25
  2. package/dist/cli/index.js +1 -1
  3. package/dist/create/cli.js +39 -4
  4. package/dist/create/create.js +30 -18
  5. package/dist/create/docker-compose-generator.js +68 -11
  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/ConflictExplorer.d.ts.map +1 -1
  160. package/dist/studio/components/index.js +1 -1
  161. package/dist/studio/{components-Q0Nx6gLE.js → components-9kDSWiGL.js} +163 -47
  162. package/dist/studio/index.js +31 -28
  163. package/dist/studio-app/assets/{index-BHOmLZF-.js → index-DVdvmf69.js} +9 -9
  164. package/dist/studio-app/index.html +1 -1
  165. package/package.json +1 -1
@@ -0,0 +1,344 @@
1
+ /// Operation Log Persistence
2
+ ///
3
+ /// Append-only log storing all executed operations for durability, replay, and recovery.
4
+ /// Operations are immutable once appended; the log is the authoritative source for
5
+ /// what has been executed in the system.
6
+
7
+ use crate::transactions::{OperationId, Operation, StateVersion};
8
+ use std::collections::HashMap;
9
+ use std::sync::{Arc, Mutex};
10
+
11
+ /// Persisted operation log entry
12
+ #[derive(Clone, Debug)]
13
+ pub struct OperationLogEntry {
14
+ pub log_index: u64,
15
+ pub operation_id: OperationId,
16
+ pub operation: Operation,
17
+ pub timestamp_ms: u64,
18
+ }
19
+
20
+ /// In-memory operation log (for testing/development)
21
+ /// For production, implement FileOperationLog or DatabaseOperationLog
22
+ #[derive(Clone)]
23
+ pub struct MemoryOperationLog {
24
+ entries: Arc<Mutex<Vec<OperationLogEntry>>>,
25
+ by_id: Arc<Mutex<HashMap<String, u64>>>,
26
+ }
27
+
28
+ impl MemoryOperationLog {
29
+ pub fn new() -> Self {
30
+ Self {
31
+ entries: Arc::new(Mutex::new(Vec::new())),
32
+ by_id: Arc::new(Mutex::new(HashMap::new())),
33
+ }
34
+ }
35
+
36
+ /// Append an operation to the log
37
+ /// Returns the log index assigned to this operation
38
+ pub fn append(&self, operation: Operation) -> Result<u64, String> {
39
+ let mut entries = self.entries.lock().unwrap();
40
+ let mut by_id = self.by_id.lock().unwrap();
41
+
42
+ let op_id_key = format!("{}:{}", operation.operation_id.node_id, operation.operation_id.sequence);
43
+
44
+ if by_id.contains_key(&op_id_key) {
45
+ return Err(format!("Operation already logged: {}", op_id_key));
46
+ }
47
+
48
+ let log_index = entries.len() as u64;
49
+ let timestamp_ms = std::time::SystemTime::now()
50
+ .duration_since(std::time::UNIX_EPOCH)
51
+ .unwrap()
52
+ .as_millis() as u64;
53
+
54
+ let entry = OperationLogEntry {
55
+ log_index,
56
+ operation_id: operation.operation_id.clone(),
57
+ operation: operation.clone(),
58
+ timestamp_ms,
59
+ };
60
+
61
+ by_id.insert(op_id_key, log_index);
62
+ entries.push(entry);
63
+
64
+ Ok(log_index)
65
+ }
66
+
67
+ /// Get an operation by its ID
68
+ pub fn get_by_id(&self, operation_id: &OperationId) -> Option<OperationLogEntry> {
69
+ let by_id = self.by_id.lock().unwrap();
70
+ let op_id_key = format!("{}:{}", operation_id.node_id, operation_id.sequence);
71
+
72
+ if let Some(&log_index) = by_id.get(&op_id_key) {
73
+ let entries = self.entries.lock().unwrap();
74
+ entries.get(log_index as usize).cloned()
75
+ } else {
76
+ None
77
+ }
78
+ }
79
+
80
+ /// Get an operation by log index
81
+ pub fn get_by_index(&self, log_index: u64) -> Option<OperationLogEntry> {
82
+ let entries = self.entries.lock().unwrap();
83
+ entries.get(log_index as usize).cloned()
84
+ }
85
+
86
+ /// Get all operations in range [start_index, end_index)
87
+ pub fn get_range(&self, start_index: u64, end_index: u64) -> Vec<OperationLogEntry> {
88
+ let entries = self.entries.lock().unwrap();
89
+ entries
90
+ .iter()
91
+ .skip(start_index as usize)
92
+ .take((end_index - start_index) as usize)
93
+ .cloned()
94
+ .collect()
95
+ }
96
+
97
+ /// Get the current size of the log (number of entries)
98
+ pub fn size(&self) -> u64 {
99
+ let entries = self.entries.lock().unwrap();
100
+ entries.len() as u64
101
+ }
102
+
103
+ /// Iterate over all entries in the log
104
+ pub fn iter(&self) -> Vec<OperationLogEntry> {
105
+ let entries = self.entries.lock().unwrap();
106
+ entries.clone()
107
+ }
108
+
109
+ /// Check if an operation ID has been logged
110
+ pub fn contains_operation_id(&self, operation_id: &OperationId) -> bool {
111
+ let by_id = self.by_id.lock().unwrap();
112
+ let op_id_key = format!("{}:{}", operation_id.node_id, operation_id.sequence);
113
+ by_id.contains_key(&op_id_key)
114
+ }
115
+
116
+ /// Truncate the log at the given index (for recovery/compaction)
117
+ /// Keeps entries with log_index < truncate_at
118
+ pub fn truncate(&self, truncate_at: u64) -> Result<(), String> {
119
+ let mut entries = self.entries.lock().unwrap();
120
+ let mut by_id = self.by_id.lock().unwrap();
121
+
122
+ if truncate_at > entries.len() as u64 {
123
+ return Err("Truncate index beyond log size".to_string());
124
+ }
125
+
126
+ let removed: Vec<_> = entries.drain(truncate_at as usize..).collect();
127
+ for entry in removed {
128
+ let op_id_key = format!("{}:{}", entry.operation_id.node_id, entry.operation_id.sequence);
129
+ by_id.remove(&op_id_key);
130
+ }
131
+
132
+ Ok(())
133
+ }
134
+ }
135
+
136
+ impl Default for MemoryOperationLog {
137
+ fn default() -> Self {
138
+ Self::new()
139
+ }
140
+ }
141
+
142
+ #[cfg(test)]
143
+ mod tests {
144
+ use super::*;
145
+ use crate::transactions::{OperationCommand, OperationId};
146
+ use std::collections::HashMap;
147
+
148
+ #[test]
149
+ fn test_append_and_retrieve() {
150
+ let log = MemoryOperationLog::new();
151
+ let mut vc = crate::convergence::VectorClock::new();
152
+ vc.increment("node1");
153
+ let version = StateVersion::new(vc, "hash0".to_string());
154
+
155
+ let op = Operation::new(
156
+ OperationId::new("node1".to_string(), 1),
157
+ version.clone(),
158
+ "Update".to_string(),
159
+ OperationCommand {
160
+ op_type: "UpdateField".to_string(),
161
+ collection: "test".to_string(),
162
+ record_id: "rec1".to_string(),
163
+ fields: {
164
+ let mut m = HashMap::new();
165
+ m.insert("field".to_string(), serde_json::json!("value"));
166
+ m
167
+ },
168
+ },
169
+ "user".to_string(),
170
+ );
171
+
172
+ let op_id = op.operation_id.clone();
173
+ let idx = log.append(op).unwrap();
174
+
175
+ assert_eq!(idx, 0);
176
+ assert!(log.get_by_id(&op_id).is_some());
177
+ assert_eq!(log.size(), 1);
178
+ }
179
+
180
+ #[test]
181
+ fn test_duplicate_rejection() {
182
+ let log = MemoryOperationLog::new();
183
+ let mut vc = crate::convergence::VectorClock::new();
184
+ vc.increment("node1");
185
+ let version = StateVersion::new(vc, "hash0".to_string());
186
+
187
+ let op = Operation::new(
188
+ OperationId::new("node1".to_string(), 1),
189
+ version.clone(),
190
+ "Update".to_string(),
191
+ OperationCommand {
192
+ op_type: "UpdateField".to_string(),
193
+ collection: "test".to_string(),
194
+ record_id: "rec1".to_string(),
195
+ fields: {
196
+ let mut m = HashMap::new();
197
+ m.insert("field".to_string(), serde_json::json!("value"));
198
+ m
199
+ },
200
+ },
201
+ "user".to_string(),
202
+ );
203
+
204
+ let _ = log.append(op.clone()).unwrap();
205
+ let result = log.append(op);
206
+
207
+ assert!(result.is_err());
208
+ assert!(result.unwrap_err().contains("already logged"));
209
+ }
210
+
211
+ #[test]
212
+ fn test_range_query() {
213
+ let log = MemoryOperationLog::new();
214
+ let mut vc = crate::convergence::VectorClock::new();
215
+ vc.increment("node1");
216
+ let version = StateVersion::new(vc, "hash0".to_string());
217
+
218
+ for i in 0..5 {
219
+ let op = Operation::new(
220
+ OperationId::new("node1".to_string(), i + 1),
221
+ version.clone(),
222
+ format!("Update{}", i),
223
+ OperationCommand {
224
+ op_type: "UpdateField".to_string(),
225
+ collection: "test".to_string(),
226
+ record_id: format!("rec{}", i),
227
+ fields: {
228
+ let mut m = HashMap::new();
229
+ m.insert("field".to_string(), serde_json::json!(i));
230
+ m
231
+ },
232
+ },
233
+ "user".to_string(),
234
+ );
235
+ let _ = log.append(op);
236
+ }
237
+
238
+ let range = log.get_range(1, 4);
239
+ assert_eq!(range.len(), 3);
240
+ assert_eq!(range[0].log_index, 1);
241
+ assert_eq!(range[2].log_index, 3);
242
+ }
243
+
244
+ #[test]
245
+ fn test_contains_operation_id() {
246
+ let log = MemoryOperationLog::new();
247
+ let mut vc = crate::convergence::VectorClock::new();
248
+ vc.increment("node1");
249
+ let version = StateVersion::new(vc, "hash0".to_string());
250
+
251
+ let op_id = OperationId::new("node1".to_string(), 1);
252
+ let op = Operation::new(
253
+ op_id.clone(),
254
+ version.clone(),
255
+ "Update".to_string(),
256
+ OperationCommand {
257
+ op_type: "UpdateField".to_string(),
258
+ collection: "test".to_string(),
259
+ record_id: "rec1".to_string(),
260
+ fields: {
261
+ let mut m = HashMap::new();
262
+ m.insert("field".to_string(), serde_json::json!("value"));
263
+ m
264
+ },
265
+ },
266
+ "user".to_string(),
267
+ );
268
+
269
+ let _ = log.append(op);
270
+
271
+ assert!(log.contains_operation_id(&op_id));
272
+
273
+ let other_id = OperationId::new("node1".to_string(), 999);
274
+ assert!(!log.contains_operation_id(&other_id));
275
+ }
276
+
277
+ #[test]
278
+ fn test_truncate() {
279
+ let log = MemoryOperationLog::new();
280
+ let mut vc = crate::convergence::VectorClock::new();
281
+ vc.increment("node1");
282
+ let version = StateVersion::new(vc, "hash0".to_string());
283
+
284
+ for i in 0..5 {
285
+ let op = Operation::new(
286
+ OperationId::new("node1".to_string(), i + 1),
287
+ version.clone(),
288
+ format!("Update{}", i),
289
+ OperationCommand {
290
+ op_type: "UpdateField".to_string(),
291
+ collection: "test".to_string(),
292
+ record_id: format!("rec{}", i),
293
+ fields: {
294
+ let mut m = HashMap::new();
295
+ m.insert("field".to_string(), serde_json::json!(i));
296
+ m
297
+ },
298
+ },
299
+ "user".to_string(),
300
+ );
301
+ let _ = log.append(op);
302
+ }
303
+
304
+ assert_eq!(log.size(), 5);
305
+ let _ = log.truncate(3).unwrap();
306
+ assert_eq!(log.size(), 3);
307
+
308
+ let op_id = OperationId::new("node1".to_string(), 4);
309
+ assert!(!log.contains_operation_id(&op_id));
310
+ }
311
+
312
+ #[test]
313
+ fn test_iteration() {
314
+ let log = MemoryOperationLog::new();
315
+ let mut vc = crate::convergence::VectorClock::new();
316
+ vc.increment("node1");
317
+ let version = StateVersion::new(vc, "hash0".to_string());
318
+
319
+ for i in 0..3 {
320
+ let op = Operation::new(
321
+ OperationId::new("node1".to_string(), i + 1),
322
+ version.clone(),
323
+ format!("Update{}", i),
324
+ OperationCommand {
325
+ op_type: "UpdateField".to_string(),
326
+ collection: "test".to_string(),
327
+ record_id: format!("rec{}", i),
328
+ fields: {
329
+ let mut m = HashMap::new();
330
+ m.insert("field".to_string(), serde_json::json!(i));
331
+ m
332
+ },
333
+ },
334
+ "user".to_string(),
335
+ );
336
+ let _ = log.append(op);
337
+ }
338
+
339
+ let all = log.iter();
340
+ assert_eq!(all.len(), 3);
341
+ assert_eq!(all[0].log_index, 0);
342
+ assert_eq!(all[2].log_index, 2);
343
+ }
344
+ }