Skip to content

Commit 24e4d3b

Browse files
konardclaude
andcommitted
Fix Rust code formatting and add changelog fragment
- Run cargo fmt --all to fix formatting issues - Add changelog.d/per-language-cicd.md for Rust versioning 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent f475cc3 commit 24e4d3b

File tree

11 files changed

+152
-72
lines changed

11 files changed

+152
-72
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
### Added
2+
- Initial Rust translation of the links-client library
3+
- Full API parity with TypeScript implementation (ILinks, LinkDBService, RecursiveLinks)
4+
- Per-language CI/CD workflow with cross-platform testing
5+
- AuthStorageService and MenuStorageService implementations
6+
- Comprehensive test suite and examples

rust/examples/basic_usage.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Basic usage example for the Links Client library
22
3-
use links_client::{ILinks, LinkConstants};
43
use links_client::services::link_db_service::Link;
4+
use links_client::{ILinks, LinkConstants};
55

66
#[tokio::main]
77
async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -45,24 +45,32 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
4545
// Iterate over all links
4646
println!("\nIterating over all links:");
4747
links
48-
.each(None, Some(|link: &Link| {
49-
println!(" Link {}: {} -> {}", link.id, link.source, link.target);
50-
LinkConstants::Continue
51-
}))
48+
.each(
49+
None,
50+
Some(|link: &Link| {
51+
println!(" Link {}: {} -> {}", link.id, link.source, link.target);
52+
LinkConstants::Continue
53+
}),
54+
)
5255
.await?;
5356

5457
// Update the link
5558
println!("\nUpdating link to (source: 10, target: 20)...");
56-
links.update(Some(&[link_id]), &[10, 20], None::<fn(_)>).await?;
59+
links
60+
.update(Some(&[link_id]), &[10, 20], None::<fn(_)>)
61+
.await?;
5762
println!("Link updated");
5863

5964
// Iterate again to see the change
6065
println!("\nLinks after update:");
6166
links
62-
.each(None, Some(|link: &Link| {
63-
println!(" Link {}: {} -> {}", link.id, link.source, link.target);
64-
LinkConstants::Continue
65-
}))
67+
.each(
68+
None,
69+
Some(|link: &Link| {
70+
println!(" Link {}: {} -> {}", link.id, link.source, link.target);
71+
LinkConstants::Continue
72+
}),
73+
)
6674
.await?;
6775

6876
// Delete the link

rust/src/api/ilinks.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,21 @@ mod tests {
307307
fn test_filter_links() {
308308
let links = ILinks::new(None).unwrap();
309309
let all_links = vec![
310-
Link { id: 1, source: 2, target: 3 },
311-
Link { id: 2, source: 4, target: 5 },
312-
Link { id: 3, source: 2, target: 6 },
310+
Link {
311+
id: 1,
312+
source: 2,
313+
target: 3,
314+
},
315+
Link {
316+
id: 2,
317+
source: 4,
318+
target: 5,
319+
},
320+
Link {
321+
id: 3,
322+
source: 2,
323+
target: 6,
324+
},
313325
];
314326

315327
// Filter by ID

rust/src/api/recursive_links.rs

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,19 @@ impl RecursiveLinks {
6666
/// Get links where the given link is the source
6767
pub async fn get_children(&self, parent_id: u64) -> Result<Vec<Link>, RecursiveLinksError> {
6868
let all_links = self.db.read_all_links().await?;
69-
Ok(all_links.into_iter().filter(|l| l.source == parent_id).collect())
69+
Ok(all_links
70+
.into_iter()
71+
.filter(|l| l.source == parent_id)
72+
.collect())
7073
}
7174

7275
/// Get links where the given link is the target
7376
pub async fn get_parents(&self, child_id: u64) -> Result<Vec<Link>, RecursiveLinksError> {
7477
let all_links = self.db.read_all_links().await?;
75-
Ok(all_links.into_iter().filter(|l| l.target == child_id).collect())
78+
Ok(all_links
79+
.into_iter()
80+
.filter(|l| l.target == child_id)
81+
.collect())
7682
}
7783

7884
/// Build a tree starting from the given root link
@@ -120,20 +126,12 @@ impl RecursiveLinks {
120126
}
121127

122128
/// Create a link
123-
pub async fn create_link(
124-
&self,
125-
source: u64,
126-
target: u64,
127-
) -> Result<Link, RecursiveLinksError> {
129+
pub async fn create_link(&self, source: u64, target: u64) -> Result<Link, RecursiveLinksError> {
128130
Ok(self.db.create_link(source, target).await?)
129131
}
130132

131133
/// Delete a link and optionally all its children
132-
pub async fn delete_link(
133-
&self,
134-
id: u64,
135-
recursive: bool,
136-
) -> Result<bool, RecursiveLinksError> {
134+
pub async fn delete_link(&self, id: u64, recursive: bool) -> Result<bool, RecursiveLinksError> {
137135
if recursive {
138136
self.delete_link_impl(id).await?;
139137
} else {
@@ -209,20 +207,34 @@ mod tests {
209207
let links = RecursiveLinks::new(None);
210208

211209
let tree = LinkNode {
212-
link: Link { id: 1, source: 0, target: 0 },
210+
link: Link {
211+
id: 1,
212+
source: 0,
213+
target: 0,
214+
},
213215
children: vec![
214216
LinkNode {
215-
link: Link { id: 2, source: 1, target: 0 },
217+
link: Link {
218+
id: 2,
219+
source: 1,
220+
target: 0,
221+
},
216222
children: vec![],
217223
},
218224
LinkNode {
219-
link: Link { id: 3, source: 1, target: 0 },
220-
children: vec![
221-
LinkNode {
222-
link: Link { id: 4, source: 3, target: 0 },
223-
children: vec![],
225+
link: Link {
226+
id: 3,
227+
source: 1,
228+
target: 0,
229+
},
230+
children: vec![LinkNode {
231+
link: Link {
232+
id: 4,
233+
source: 3,
234+
target: 0,
224235
},
225-
],
236+
children: vec![],
237+
}],
226238
},
227239
],
228240
};
@@ -235,13 +247,19 @@ mod tests {
235247
let links = RecursiveLinks::new(None);
236248

237249
let tree = LinkNode {
238-
link: Link { id: 1, source: 0, target: 0 },
239-
children: vec![
240-
LinkNode {
241-
link: Link { id: 2, source: 1, target: 0 },
242-
children: vec![],
250+
link: Link {
251+
id: 1,
252+
source: 0,
253+
target: 0,
254+
},
255+
children: vec![LinkNode {
256+
link: Link {
257+
id: 2,
258+
source: 1,
259+
target: 0,
243260
},
244-
],
261+
children: vec![],
262+
}],
245263
};
246264

247265
let flattened = links.flatten_tree(&tree);

rust/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ pub mod utils;
3131

3232
pub use api::ilinks::{ILinks, LinkConstants};
3333
pub use api::recursive_links::RecursiveLinks;
34-
pub use services::link_db_service::LinkDBService;
3534
pub use services::auth_storage_service::AuthStorageService;
35+
pub use services::link_db_service::LinkDBService;
3636
pub use services::menu_storage_service::MenuStorageService;

rust/src/services/auth_storage_service.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::path::PathBuf;
55
use thiserror::Error;
66
use tracing::{debug, error};
77

8-
use super::link_db_service::{LinkDBService, LinkDBError};
8+
use super::link_db_service::{LinkDBError, LinkDBService};
99

1010
/// Errors that can occur when using AuthStorageService
1111
#[derive(Error, Debug)]

rust/src/services/link_db_service.rs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
use std::env;
44
use std::path::PathBuf;
55
use std::process::Stdio;
6-
use tokio::process::Command;
76
use thiserror::Error;
7+
use tokio::process::Command;
88
use tracing::{debug, error, warn};
99

1010
/// Errors that can occur when using LinkDBService
@@ -72,7 +72,11 @@ impl LinkDBService {
7272
after: bool,
7373
trace: bool,
7474
) -> Result<String, LinkDBError> {
75-
let mut args = vec![query.to_string(), "--db".to_string(), self.db_path.to_string_lossy().to_string()];
75+
let mut args = vec![
76+
query.to_string(),
77+
"--db".to_string(),
78+
self.db_path.to_string_lossy().to_string(),
79+
];
7680

7781
if before {
7882
args.push("--before".to_string());
@@ -169,7 +173,9 @@ impl LinkDBService {
169173
/// * `target` - Target link ID
170174
pub async fn create_link(&self, source: u64, target: u64) -> Result<Link, LinkDBError> {
171175
let query = format!("() (({} {}))", source, target);
172-
let output = self.execute_query(&query, false, true, false, false).await?;
176+
let output = self
177+
.execute_query(&query, false, true, false, false)
178+
.await?;
173179

174180
let re = regex_lite::Regex::new(r"\((\d+):\s+(\d+)\s+(\d+)\)").unwrap();
175181
if let Some(caps) = re.captures(&output) {
@@ -184,7 +190,9 @@ impl LinkDBService {
184190
}
185191
}
186192

187-
Err(LinkDBError::ParseError("Failed to parse created link".to_string()))
193+
Err(LinkDBError::ParseError(
194+
"Failed to parse created link".to_string(),
195+
))
188196
}
189197

190198
/// Read all links from database
@@ -197,7 +205,9 @@ impl LinkDBService {
197205
/// Read a specific link by ID
198206
pub async fn read_link(&self, id: u64) -> Result<Option<Link>, LinkDBError> {
199207
let query = format!("((({}:$s $t)) (({}:$s $t)))", id, id);
200-
let output = self.execute_query(&query, false, false, true, false).await?;
208+
let output = self
209+
.execute_query(&query, false, false, true, false)
210+
.await?;
201211
let links = self.parse_links(&output);
202212
Ok(links.into_iter().next())
203213
}
@@ -215,8 +225,12 @@ impl LinkDBService {
215225
new_source: u64,
216226
new_target: u64,
217227
) -> Result<Link, LinkDBError> {
218-
let query = format!("((({}:$s $t)) (({}: {} {})))", id, id, new_source, new_target);
219-
self.execute_query(&query, false, true, false, false).await?;
228+
let query = format!(
229+
"((({}:$s $t)) (({}: {} {})))",
230+
id, id, new_source, new_target
231+
);
232+
self.execute_query(&query, false, true, false, false)
233+
.await?;
220234

221235
Ok(Link {
222236
id,
@@ -228,7 +242,8 @@ impl LinkDBService {
228242
/// Delete a link
229243
pub async fn delete_link(&self, id: u64) -> Result<bool, LinkDBError> {
230244
let query = format!("((({}:$s $t)) ())", id);
231-
self.execute_query(&query, false, true, false, false).await?;
245+
self.execute_query(&query, false, true, false, false)
246+
.await?;
232247
Ok(true)
233248
}
234249

@@ -246,7 +261,10 @@ impl LinkDBService {
246261
/// Get all menu items
247262
pub async fn get_all_menu_items(&self) -> Result<Vec<Link>, LinkDBError> {
248263
let all_links = self.read_all_links().await?;
249-
Ok(all_links.into_iter().filter(|link| link.target == 1000).collect())
264+
Ok(all_links
265+
.into_iter()
266+
.filter(|link| link.target == 1000)
267+
.collect())
250268
}
251269

252270
/// Delete menu item
@@ -276,8 +294,22 @@ mod tests {
276294
let links = service.parse_links(output);
277295

278296
assert_eq!(links.len(), 2);
279-
assert_eq!(links[0], Link { id: 1, source: 2, target: 3 });
280-
assert_eq!(links[1], Link { id: 4, source: 5, target: 6 });
297+
assert_eq!(
298+
links[0],
299+
Link {
300+
id: 1,
301+
source: 2,
302+
target: 3
303+
}
304+
);
305+
assert_eq!(
306+
links[1],
307+
Link {
308+
id: 4,
309+
source: 5,
310+
target: 6
311+
}
312+
);
281313
}
282314

283315
#[test]

rust/src/services/menu_storage_service.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::path::PathBuf;
44
use thiserror::Error;
55
use tracing::{debug, error};
66

7-
use super::link_db_service::{LinkDBService, LinkDBError};
7+
use super::link_db_service::{LinkDBError, LinkDBService};
88

99
/// Errors that can occur when using MenuStorageService
1010
#[derive(Error, Debug)]

rust/src/services/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! Service modules for the Links Client library
22
3-
pub mod link_db_service;
43
pub mod auth_storage_service;
4+
pub mod link_db_service;
55
pub mod menu_storage_service;
66

7-
pub use link_db_service::LinkDBService;
87
pub use auth_storage_service::AuthStorageService;
8+
pub use link_db_service::LinkDBService;
99
pub use menu_storage_service::MenuStorageService;

rust/src/utils/logger.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ pub fn init_logger() {
1212
.with_max_level(Level::INFO)
1313
.finish();
1414

15-
tracing::subscriber::set_global_default(subscriber)
16-
.expect("setting default subscriber failed");
15+
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
1716
}
1817

1918
/// Initialize the logger with debug level logging
@@ -22,6 +21,5 @@ pub fn init_debug_logger() {
2221
.with_max_level(Level::DEBUG)
2322
.finish();
2423

25-
tracing::subscriber::set_global_default(subscriber)
26-
.expect("setting default subscriber failed");
24+
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
2725
}

0 commit comments

Comments
 (0)