pub struct MapHandle<'a, T = StoreEntry> { /* private fields */ }Expand description
A draft-time builder for populating a map entry in the Store.
Returned by Pipeline::map and Store::define_map. Methods are
chainable so nested structures can be built in a single expression.
Nested arrays and maps are added via insert_array
and insert_map and return child handles
borrowing from this one.
Implementations§
Source§impl<'a> MapHandle<'a, StoreEntry>
impl<'a> MapHandle<'a, StoreEntry>
Sourcepub fn insert_array<K: Into<String>>(
&mut self,
key: K,
) -> Result<ArrayHandle<'_, StoreEntry>, StoreError>
pub fn insert_array<K: Into<String>>( &mut self, key: K, ) -> Result<ArrayHandle<'_, StoreEntry>, StoreError>
Inserts a new nested array entry under key and returns a
child handle borrowing from this one to populate it.
Sourcepub fn insert_map<K: Into<String>>(
&mut self,
key: K,
) -> Result<MapHandle<'_, StoreEntry>, StoreError>
pub fn insert_map<K: Into<String>>( &mut self, key: K, ) -> Result<MapHandle<'_, StoreEntry>, StoreError>
Inserts a new nested map entry under key and returns a child
handle borrowing from this one to populate it.
Sourcepub fn with_array<K: Into<String>, F: FnOnce(&mut ArrayHandle<'_, StoreEntry>) -> Result<(), StoreError>>(
&mut self,
key: K,
body: F,
) -> Result<(), StoreError>
pub fn with_array<K: Into<String>, F: FnOnce(&mut ArrayHandle<'_, StoreEntry>) -> Result<(), StoreError>>( &mut self, key: K, body: F, ) -> Result<(), StoreError>
Inserts a nested array under key and hands it to a closure
for population. Useful when the nested structure would
otherwise force awkward temporaries.
Examples found in repository?
32fn write_grouped_data(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
33 store.with_map("by_severity", |groups| {
34 groups.with_array("high", |arr| {
35 arr.push("INC-001")?.push("INC-004")?;
36 Ok(())
37 })?;
38
39 groups.with_array("medium", |arr| {
40 arr.push("INC-002")?;
41 Ok(())
42 })?;
43
44 groups.with_array("low", |arr| {
45 arr.push("INC-003")?.push("INC-005")?.push("INC-006")?;
46 Ok(())
47 })?;
48
49 Ok(())
50 })?;
51
52 Ok(())
53}
54
55fn write_nested_config(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
56 store.with_map("pipeline_config", |cfg| {
57 cfg.insert("name", "signin_analysis")?;
58
59 cfg.with_map("source", |src| {
60 src.insert("type", "kql")?
61 .insert("workspace", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")?;
62
63 src.with_map("options", |opts| {
64 opts.insert("timeout_secs", 30i64)?
65 .insert("max_rows", 10_000i64)?;
66 Ok(())
67 })?;
68
69 Ok(())
70 })?;
71
72 cfg.with_array("outputs", |outputs| {
73 let mut o = outputs.push_map()?;
74 o.insert("format", "json")?
75 .insert("path", "/tmp/results.json")?;
76
77 let mut o = outputs.push_map()?;
78 o.insert("format", "csv")?
79 .insert("path", "/tmp/results.csv")?;
80
81 Ok(())
82 })?;
83
84 Ok(())
85 })?;
86
87 Ok(())
88}More examples
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 let mut store = Store::new();
11
12 // --- Chainable push ---
13 // push() accepts V: Into<StoreEntry>. The blanket impl
14 // `From<T: Into<Value>> for StoreEntry` means primitives work directly.
15 let mut arr = store.define_array("numbers")?.push(1)?.push(2)?.push(3)?;
16
17 let items = store.get("numbers")?.as_array()?;
18 println!("numbers: len={}", items.len());
19 assert_eq!(items.len(), 3);
20
21 // --- Chainable insert ---
22 // insert() accepts K: Into<String> and V: Into<StoreEntry>.
23 let mut map = store.define_map("config")?;
24 map.insert("host", "localhost")?
25 .insert("port", 8080i64)?
26 .insert("debug", true)?;
27
28 let host = store.get("config")?.get_key("host")?.get_value()?;
29 println!("config.host = {host:?}");
30
31 // --- Closure API on Store ---
32 // with_array scopes the handle so you don't need an explicit drop.
33 store.with_array("tags", |arr| {
34 arr.push("rust")?.push("pipeline")?.push("store")?;
35 Ok(())
36 })?;
37
38 let tags = store.get("tags")?.as_array()?;
39 println!("tags: len={}", tags.len());
40
41 store.with_map("metadata", |map| {
42 map.insert("version", "0.1.0")?.insert("stable", false)?;
43 Ok(())
44 })?;
45
46 let version = store.get("metadata")?.get_key("version")?.get_value()?;
47 println!("metadata.version = {version:?}");
48
49 // --- Nested construction via MapHandle closures ---
50 // with_array and with_map on MapHandle let you build nested structures
51 // without manually managing sub-handles.
52 store.with_map("server", |map| {
53 map.insert("name", "prod-01")?;
54
55 map.with_array("ports", |arr| {
56 arr.push(80)?.push(443)?;
57 Ok(())
58 })?;
59
60 map.with_map("tls", |tls| {
61 tls.insert("enabled", true)?
62 .insert("cert_path", "/etc/ssl/cert.pem")?;
63 Ok(())
64 })?;
65
66 Ok(())
67 })?;
68
69 let tls_enabled = store
70 .get("server")?
71 .get_key("tls")?
72 .get_key("enabled")?
73 .get_value()?;
74 println!("server.tls.enabled = {tls_enabled:?}");
75
76 // --- push_map on ArrayHandle ---
77 // Builds an array of maps — the most common pattern for tabular results.
78 let mut arr = store.define_array("users")?;
79 {
80 let mut user = arr.push_map()?;
81 user.insert("name", "Alice")?.insert("role", "admin")?;
82 }
83 {
84 let mut user = arr.push_map()?;
85 user.insert("name", "Bob")?.insert("role", "viewer")?;
86 }
87
88 let bob_role = store
89 .get("users")?
90 .get_index(1)?
91 .get_key("role")?
92 .get_value()?;
93 println!("users[1].role = {bob_role:?}");
94 assert_eq!(bob_role, &Value::Text("viewer".into()));
95
96 println!("store_collections: ok");
97 Ok(())
98}Sourcepub fn with_map<K: Into<String>, F: FnOnce(&mut MapHandle<'_, StoreEntry>) -> Result<(), StoreError>>(
&mut self,
key: K,
body: F,
) -> Result<(), StoreError>
pub fn with_map<K: Into<String>, F: FnOnce(&mut MapHandle<'_, StoreEntry>) -> Result<(), StoreError>>( &mut self, key: K, body: F, ) -> Result<(), StoreError>
Inserts a nested map under key and hands it to a closure for
population.
Examples found in repository?
55fn write_nested_config(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
56 store.with_map("pipeline_config", |cfg| {
57 cfg.insert("name", "signin_analysis")?;
58
59 cfg.with_map("source", |src| {
60 src.insert("type", "kql")?
61 .insert("workspace", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")?;
62
63 src.with_map("options", |opts| {
64 opts.insert("timeout_secs", 30i64)?
65 .insert("max_rows", 10_000i64)?;
66 Ok(())
67 })?;
68
69 Ok(())
70 })?;
71
72 cfg.with_array("outputs", |outputs| {
73 let mut o = outputs.push_map()?;
74 o.insert("format", "json")?
75 .insert("path", "/tmp/results.json")?;
76
77 let mut o = outputs.push_map()?;
78 o.insert("format", "csv")?
79 .insert("path", "/tmp/results.csv")?;
80
81 Ok(())
82 })?;
83
84 Ok(())
85 })?;
86
87 Ok(())
88}More examples
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 let mut store = Store::new();
11
12 // --- Chainable push ---
13 // push() accepts V: Into<StoreEntry>. The blanket impl
14 // `From<T: Into<Value>> for StoreEntry` means primitives work directly.
15 let mut arr = store.define_array("numbers")?.push(1)?.push(2)?.push(3)?;
16
17 let items = store.get("numbers")?.as_array()?;
18 println!("numbers: len={}", items.len());
19 assert_eq!(items.len(), 3);
20
21 // --- Chainable insert ---
22 // insert() accepts K: Into<String> and V: Into<StoreEntry>.
23 let mut map = store.define_map("config")?;
24 map.insert("host", "localhost")?
25 .insert("port", 8080i64)?
26 .insert("debug", true)?;
27
28 let host = store.get("config")?.get_key("host")?.get_value()?;
29 println!("config.host = {host:?}");
30
31 // --- Closure API on Store ---
32 // with_array scopes the handle so you don't need an explicit drop.
33 store.with_array("tags", |arr| {
34 arr.push("rust")?.push("pipeline")?.push("store")?;
35 Ok(())
36 })?;
37
38 let tags = store.get("tags")?.as_array()?;
39 println!("tags: len={}", tags.len());
40
41 store.with_map("metadata", |map| {
42 map.insert("version", "0.1.0")?.insert("stable", false)?;
43 Ok(())
44 })?;
45
46 let version = store.get("metadata")?.get_key("version")?.get_value()?;
47 println!("metadata.version = {version:?}");
48
49 // --- Nested construction via MapHandle closures ---
50 // with_array and with_map on MapHandle let you build nested structures
51 // without manually managing sub-handles.
52 store.with_map("server", |map| {
53 map.insert("name", "prod-01")?;
54
55 map.with_array("ports", |arr| {
56 arr.push(80)?.push(443)?;
57 Ok(())
58 })?;
59
60 map.with_map("tls", |tls| {
61 tls.insert("enabled", true)?
62 .insert("cert_path", "/etc/ssl/cert.pem")?;
63 Ok(())
64 })?;
65
66 Ok(())
67 })?;
68
69 let tls_enabled = store
70 .get("server")?
71 .get_key("tls")?
72 .get_key("enabled")?
73 .get_value()?;
74 println!("server.tls.enabled = {tls_enabled:?}");
75
76 // --- push_map on ArrayHandle ---
77 // Builds an array of maps — the most common pattern for tabular results.
78 let mut arr = store.define_array("users")?;
79 {
80 let mut user = arr.push_map()?;
81 user.insert("name", "Alice")?.insert("role", "admin")?;
82 }
83 {
84 let mut user = arr.push_map()?;
85 user.insert("name", "Bob")?.insert("role", "viewer")?;
86 }
87
88 let bob_role = store
89 .get("users")?
90 .get_index(1)?
91 .get_key("role")?
92 .get_value()?;
93 println!("users[1].role = {bob_role:?}");
94 assert_eq!(bob_role, &Value::Text("viewer".into()));
95
96 println!("store_collections: ok");
97 Ok(())
98}Source§impl<'a, T> MapHandle<'a, Vec<T>>
impl<'a, T> MapHandle<'a, Vec<T>>
Sourcepub fn insert_array<K: Into<String>>(
&mut self,
key: K,
) -> Result<ArrayHandle<'_, T>, StoreError>
pub fn insert_array<K: Into<String>>( &mut self, key: K, ) -> Result<ArrayHandle<'_, T>, StoreError>
Inserts a new inner Vec<T> under key and returns a child
array handle for populating it.
Source§impl<'a, T> MapHandle<'a, HashMap<String, T>>
impl<'a, T> MapHandle<'a, HashMap<String, T>>
Sourcepub fn insert_map<K: Into<String>>(
&mut self,
key: K,
) -> Result<MapHandle<'_, T>, StoreError>
pub fn insert_map<K: Into<String>>( &mut self, key: K, ) -> Result<MapHandle<'_, T>, StoreError>
Inserts a new inner HashMap<String, T> under key and
returns a child map handle for populating it.
Source§impl<'a, T> MapHandle<'a, T>
impl<'a, T> MapHandle<'a, T>
Sourcepub fn new<N: Into<String>>(name: N, data: &'a mut HashMap<String, T>) -> Self
pub fn new<N: Into<String>>(name: N, data: &'a mut HashMap<String, T>) -> Self
Wraps a mutable map in a handle under the given display name.
Intended for extension code; user code obtains handles through
Pipeline::map or Store::define_map.
Sourcepub fn insert<V: Into<T>, K: Into<String>>(
&mut self,
key: K,
value: V,
) -> Result<&mut Self, StoreError>
pub fn insert<V: Into<T>, K: Into<String>>( &mut self, key: K, value: V, ) -> Result<&mut Self, StoreError>
Inserts a key/value pair into the map. Returns a mutable reference for chaining. An existing entry under the same key is overwritten.
Examples found in repository?
10fn write_query_results(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
11 store.with_array("rows", |rows| {
12 // Row 1 — all fields inserted via chaining, no .into() needed.
13 let mut row = rows.push_map()?;
14 row.insert("user", "alice@contoso.com")?
15 .insert("ip", "10.0.0.1")?
16 .insert("status", "Success")?
17 .insert("attempts", 1i64)?;
18
19 // Row 2
20 let mut row = rows.push_map()?;
21 row.insert("user", "bob@contoso.com")?
22 .insert("ip", "192.168.1.50")?
23 .insert("status", "Failure")?
24 .insert("attempts", 3i64)?;
25
26 Ok(())
27 })?;
28
29 Ok(())
30}
31
32fn write_grouped_data(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
33 store.with_map("by_severity", |groups| {
34 groups.with_array("high", |arr| {
35 arr.push("INC-001")?.push("INC-004")?;
36 Ok(())
37 })?;
38
39 groups.with_array("medium", |arr| {
40 arr.push("INC-002")?;
41 Ok(())
42 })?;
43
44 groups.with_array("low", |arr| {
45 arr.push("INC-003")?.push("INC-005")?.push("INC-006")?;
46 Ok(())
47 })?;
48
49 Ok(())
50 })?;
51
52 Ok(())
53}
54
55fn write_nested_config(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
56 store.with_map("pipeline_config", |cfg| {
57 cfg.insert("name", "signin_analysis")?;
58
59 cfg.with_map("source", |src| {
60 src.insert("type", "kql")?
61 .insert("workspace", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")?;
62
63 src.with_map("options", |opts| {
64 opts.insert("timeout_secs", 30i64)?
65 .insert("max_rows", 10_000i64)?;
66 Ok(())
67 })?;
68
69 Ok(())
70 })?;
71
72 cfg.with_array("outputs", |outputs| {
73 let mut o = outputs.push_map()?;
74 o.insert("format", "json")?
75 .insert("path", "/tmp/results.json")?;
76
77 let mut o = outputs.push_map()?;
78 o.insert("format", "csv")?
79 .insert("path", "/tmp/results.csv")?;
80
81 Ok(())
82 })?;
83
84 Ok(())
85 })?;
86
87 Ok(())
88}More examples
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 let mut store = Store::new();
11
12 // --- Chainable push ---
13 // push() accepts V: Into<StoreEntry>. The blanket impl
14 // `From<T: Into<Value>> for StoreEntry` means primitives work directly.
15 let mut arr = store.define_array("numbers")?.push(1)?.push(2)?.push(3)?;
16
17 let items = store.get("numbers")?.as_array()?;
18 println!("numbers: len={}", items.len());
19 assert_eq!(items.len(), 3);
20
21 // --- Chainable insert ---
22 // insert() accepts K: Into<String> and V: Into<StoreEntry>.
23 let mut map = store.define_map("config")?;
24 map.insert("host", "localhost")?
25 .insert("port", 8080i64)?
26 .insert("debug", true)?;
27
28 let host = store.get("config")?.get_key("host")?.get_value()?;
29 println!("config.host = {host:?}");
30
31 // --- Closure API on Store ---
32 // with_array scopes the handle so you don't need an explicit drop.
33 store.with_array("tags", |arr| {
34 arr.push("rust")?.push("pipeline")?.push("store")?;
35 Ok(())
36 })?;
37
38 let tags = store.get("tags")?.as_array()?;
39 println!("tags: len={}", tags.len());
40
41 store.with_map("metadata", |map| {
42 map.insert("version", "0.1.0")?.insert("stable", false)?;
43 Ok(())
44 })?;
45
46 let version = store.get("metadata")?.get_key("version")?.get_value()?;
47 println!("metadata.version = {version:?}");
48
49 // --- Nested construction via MapHandle closures ---
50 // with_array and with_map on MapHandle let you build nested structures
51 // without manually managing sub-handles.
52 store.with_map("server", |map| {
53 map.insert("name", "prod-01")?;
54
55 map.with_array("ports", |arr| {
56 arr.push(80)?.push(443)?;
57 Ok(())
58 })?;
59
60 map.with_map("tls", |tls| {
61 tls.insert("enabled", true)?
62 .insert("cert_path", "/etc/ssl/cert.pem")?;
63 Ok(())
64 })?;
65
66 Ok(())
67 })?;
68
69 let tls_enabled = store
70 .get("server")?
71 .get_key("tls")?
72 .get_key("enabled")?
73 .get_value()?;
74 println!("server.tls.enabled = {tls_enabled:?}");
75
76 // --- push_map on ArrayHandle ---
77 // Builds an array of maps — the most common pattern for tabular results.
78 let mut arr = store.define_array("users")?;
79 {
80 let mut user = arr.push_map()?;
81 user.insert("name", "Alice")?.insert("role", "admin")?;
82 }
83 {
84 let mut user = arr.push_map()?;
85 user.insert("name", "Bob")?.insert("role", "viewer")?;
86 }
87
88 let bob_role = store
89 .get("users")?
90 .get_index(1)?
91 .get_key("role")?
92 .get_value()?;
93 println!("users[1].role = {bob_role:?}");
94 assert_eq!(bob_role, &Value::Text("viewer".into()));
95
96 println!("store_collections: ok");
97 Ok(())
98}11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // ── Basic iter_map: iterate over key-value pairs ──
13 println!("=== Basic iter_map ===");
14 {
15 let mut pipe = Pipeline::default();
16 pipe.map("config")?
17 .insert("host", "localhost")?
18 .insert("port", "8080")?
19 .insert("protocol", "https")?;
20
21 pipe.iter_map(
22 "read_config",
23 IterSource::map("config"),
24 |key, value, body| {
25 body.step::<SetVar>(
26 "capture_key",
27 params!(
28 "name" => "current_key",
29 "value" => Param::reference(key),
30 ),
31 )?;
32 body.step::<SetVar>(
33 "capture_value",
34 params!(
35 "name" => "current_value",
36 "value" => Param::reference(value),
37 ),
38 )?;
39 Ok(())
40 },
41 )?;
42
43 pipe.hook(Logger::new().writer(std::io::stdout()));
44 pipe.hook(Timeout::new(Duration::from_secs(5)));
45
46 let complete = pipe.compile()?.run().wait()?;
47 complete.debug();
48 }
49
50 // ── iter_map with parent variable references ──
51 println!("\n=== iter_map referencing parent vars ===");
52 {
53 let mut pipe = Pipeline::default();
54 pipe.var("env", "production")?;
55 pipe.map("settings")?
56 .insert("db_host", "db.example.com")?
57 .insert("cache_host", "cache.example.com")?;
58
59 pipe.iter_map(
60 "apply_env",
61 IterSource::map("settings"),
62 |key, value, body| {
63 body.step::<SetVar>(
64 "label",
65 params!(
66 "name" => "entry",
67 "value" => Param::template(vec![
68 Param::reference("env"),
69 Param::literal("."),
70 Param::reference(key),
71 Param::literal("="),
72 Param::reference(value),
73 ]),
74 ),
75 )?;
76 Ok(())
77 },
78 )?;
79
80 let complete = pipe.compile()?.run().wait()?;
81 complete.debug();
82 }
83
84 // ── iter_map followed by regular steps ──
85 println!("\n=== iter_map then regular steps ===");
86 {
87 let mut pipe = Pipeline::default();
88 pipe.var("status", "ready")?;
89 pipe.map("headers")?
90 .insert("content-type", "application/json")?
91 .insert("accept", "text/html")?;
92
93 pipe.iter_map(
94 "scan_headers",
95 IterSource::map("headers"),
96 |_key, value, body| {
97 body.step::<SetVar>(
98 "save",
99 params!(
100 "name" => "last_header",
101 "value" => Param::reference(value),
102 ),
103 )?;
104 Ok(())
105 },
106 )?;
107
108 // Regular step after the iteration
109 pipe.step::<SetVar>(
110 "finalize",
111 params!(
112 "name" => "done",
113 "value" => Param::reference("status"),
114 ),
115 )?;
116
117 pipe.returns(
118 "result",
119 params!(
120 "status" => Param::reference("done"),
121 ),
122 )?;
123
124 let complete = pipe.compile()?.run().wait()?;
125 complete.debug();
126 }
127
128 // ── Error: iter_map with unresolved source ──
129 println!("\n=== iter_map unresolved source ===");
130 {
131 let mut pipe = Pipeline::default();
132
133 pipe.iter_map("loop", IterSource::map("missing"), |_, _, _| Ok(()))?;
134
135 match pipe.compile() {
136 Err(e) => println!(" Caught: {}", e),
137 Ok(_) => println!(" ERROR: should have failed!"),
138 }
139 }
140
141 // ── Error: iter_map body references unknown variable ──
142 println!("\n=== iter_map unresolved body reference ===");
143 {
144 let mut pipe = Pipeline::default();
145 pipe.map("data")?.insert("k", "v")?;
146
147 pipe.iter_map("loop", IterSource::map("data"), |_, _, body| {
148 body.step::<SetVar>(
149 "bad",
150 params!(
151 "name" => "out",
152 "value" => Param::reference("phantom"),
153 ),
154 )?;
155 Ok(())
156 })?;
157
158 match pipe.compile() {
159 Err(e) => println!(" Caught: {}", e),
160 Ok(_) => println!(" ERROR: should have failed!"),
161 }
162 }
163
164 Ok(())
165}