noxu_db/cursor_config.rs
1//! Cursor configuration.
2//!
3
4/// Configuration for opening a cursor.
5///
6/// Specifies the configuration parameters used to open a cursor on a database.
7///
8/// # Changes in v1.5.1
9///
10/// Four fields that used to live on this struct (`read_committed`,
11/// `non_sticky`, `evict_ln`, `prefix_constraint`) were removed because
12/// the engine never consulted them. See
13/// `docs/src/internal/v1.5-decisions-2026-05.md` for the full rationale
14/// and migration notes.
15///
16/// * `read_committed` — to use read-committed isolation, set it on the
17/// surrounding [`crate::transaction_config::TransactionConfig`] (it
18/// is honoured by [`crate::cursor::Cursor`] via the txn's locker)
19/// or pass [`crate::lock_mode::LockMode::ReadCommitted`] to a
20/// per-operation [`crate::read_options::ReadOptions`].
21/// * `non_sticky` — Rust cursors are bound to their owning scope and
22/// are not sticky to a transaction in the JE sense; the flag had
23/// no observable effect.
24/// * `evict_ln` — use [`crate::cache_mode::CacheMode::Unchanged`] /
25/// `EvictLn` on the surrounding `DatabaseConfig` instead.
26/// * `prefix_constraint` — application code should compare the
27/// returned key against its own prefix and stop iterating; the
28/// engine's BIN-level prefix is independent of the user's
29/// range-scan termination condition.
30#[derive(Debug, Clone, PartialEq, Eq, Default)]
31pub struct CursorConfig {
32 /// Use read-uncommitted isolation (dirty reads).
33 ///
34 /// When `true`, the cursor is opened in read-only mode and skips
35 /// read-lock acquisition. This mirrors JE's
36 /// `CursorConfig.setReadUncommitted(true)` shape and is the only
37 /// isolation override consulted at cursor-open time. Per-operation
38 /// `LockMode` overrides (passed via
39 /// [`crate::read_options::ReadOptions`]) take precedence at the
40 /// individual `get` call.
41 pub read_uncommitted: bool,
42}
43
44impl CursorConfig {
45 /// Creates a new CursorConfig with default settings.
46 pub fn new() -> Self {
47 Self::default()
48 }
49
50 /// Sets read-uncommitted isolation.
51 pub fn set_read_uncommitted(
52 &mut self,
53 read_uncommitted: bool,
54 ) -> &mut Self {
55 self.read_uncommitted = read_uncommitted;
56 self
57 }
58
59 /// Builder-style method to set read_uncommitted.
60 pub fn with_read_uncommitted(mut self, read_uncommitted: bool) -> Self {
61 self.read_uncommitted = read_uncommitted;
62 self
63 }
64
65 /// Creates a CursorConfig for read-uncommitted isolation.
66 pub fn read_uncommitted() -> Self {
67 Self::new().with_read_uncommitted(true)
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_new_defaults_to_no_read_uncommitted() {
77 let config = CursorConfig::new();
78 assert!(!config.read_uncommitted);
79 }
80
81 #[test]
82 fn test_set_read_uncommitted() {
83 let mut config = CursorConfig::new();
84 config.set_read_uncommitted(true);
85 assert!(config.read_uncommitted);
86 }
87
88 #[test]
89 fn test_with_read_uncommitted() {
90 let config = CursorConfig::new().with_read_uncommitted(true);
91 assert!(config.read_uncommitted);
92 }
93
94 #[test]
95 fn test_read_uncommitted_factory() {
96 let config = CursorConfig::read_uncommitted();
97 assert!(config.read_uncommitted);
98 }
99
100 #[test]
101 fn test_default() {
102 let config = CursorConfig::default();
103 assert!(!config.read_uncommitted);
104 }
105
106 #[test]
107 fn test_clone_eq() {
108 let a = CursorConfig::read_uncommitted();
109 let b = a.clone();
110 assert_eq!(a, b);
111
112 let c = CursorConfig::new();
113 assert_ne!(a, c);
114 }
115
116 #[test]
117 fn test_debug_format_mentions_field() {
118 let config = CursorConfig::read_uncommitted();
119 let debug = format!("{:?}", config);
120 assert!(debug.contains("read_uncommitted"));
121 }
122}