ggetrs_string/
functions.rs

1use std::io::Cursor;
2
3use anyhow::Result;
4use polars_core::prelude::*;
5use polars_io::prelude::*;
6use reqwest::blocking::Client;
7use serde_json::Value;
8
9use crate::cli::{
10    StringFunctionalAnnotationArgs, StringFunctionalEnrichmentArgs, StringHomologyArgs,
11    StringInteractionsArgs, StringMappingArgs, StringNetworkArgs, StringPpiEnrichmentArgs,
12};
13
14fn string_api(url_extension: &str, data: &Value) -> Result<DataFrame> {
15    let url = format!("https://string-db.org/api/json/{url_extension}");
16    let response = Client::new().post(&url).form(data).send()?.text()?;
17    let file = Cursor::new(response);
18    let table = JsonReader::new(file).finish()?;
19    Ok(table)
20}
21
22fn string_api_tsv(url_extension: &str, data: &Value) -> Result<DataFrame> {
23    let url = format!("https://string-db.org/api/tsv/{url_extension}");
24    let response = Client::new().post(&url).form(data).send()?.text()?;
25    let file = Cursor::new(response);
26    let table = CsvReadOptions::default()
27        .with_parse_options(CsvParseOptions::default().with_separator(b'\t'))
28        .with_has_header(true)
29        .into_reader_with_file_handle(file)
30        .finish()?;
31    Ok(table)
32}
33
34pub fn string_network(args: &StringNetworkArgs) -> Result<DataFrame> {
35    let data = args.build_post();
36    string_api("network", &data)
37}
38
39pub fn string_homology(args: &StringHomologyArgs) -> Result<DataFrame> {
40    let data = args.build_post();
41    string_api("homology", &data)
42}
43
44pub fn string_mapping(args: &StringMappingArgs) -> Result<DataFrame> {
45    let data = args.build_post();
46    string_api("get_string_ids", &data)
47}
48
49pub fn string_interactions(args: &StringInteractionsArgs) -> Result<DataFrame> {
50    let data = args.build_post();
51    string_api("interaction_partners", &data)
52}
53
54pub fn string_enrichment(args: &StringFunctionalEnrichmentArgs) -> Result<DataFrame> {
55    let data = args.build_post();
56    string_api_tsv("enrichment", &data)
57}
58
59pub fn string_annotations(args: &StringFunctionalAnnotationArgs) -> Result<DataFrame> {
60    let data = args.build_post();
61    string_api_tsv("functional_annotation", &data)
62}
63
64pub fn string_ppi_enrichment(args: &StringPpiEnrichmentArgs) -> Result<DataFrame> {
65    let data = args.build_post();
66    string_api("ppi_enrichment", &data)
67}
68
69#[cfg(test)]
70mod testing {
71    use super::*;
72
73    fn identifiers() -> Vec<String> {
74        vec!["RFX3".to_string(), "RFX2".to_string()]
75    }
76
77    #[test]
78    fn test_string_network() -> Result<()> {
79        let args = StringNetworkArgs::builder()
80            .identifiers(identifiers())
81            .build();
82        let network = string_network(&args)?;
83        let expected_column_names = vec![
84            "stringId_A",
85            "stringId_B",
86            "preferredName_A",
87            "preferredName_B",
88            "ncbiTaxonId",
89            "score",
90            "nscore",
91            "fscore",
92            "pscore",
93            "ascore",
94            "escore",
95            "dscore",
96            "tscore",
97        ];
98        assert_eq!(network.get_column_names(), expected_column_names);
99        Ok(())
100    }
101
102    #[test]
103    fn test_string_homology() -> Result<()> {
104        let args = StringHomologyArgs::builder()
105            .identifiers(identifiers())
106            .build();
107        let homology = string_homology(&args)?;
108        let expected_column_names = vec![
109            "ncbiTaxonId_A",
110            "stringId_A",
111            "ncbiTaxonId_B",
112            "stringId_B",
113            "bitscore",
114        ];
115        assert_eq!(homology.get_column_names(), expected_column_names);
116        Ok(())
117    }
118
119    #[test]
120    fn test_string_map_ids() -> Result<()> {
121        let args = StringMappingArgs::builder()
122            .identifiers(identifiers())
123            .build();
124        let mapping = string_mapping(&args)?;
125        let expected_column_names = vec![
126            "queryIndex",
127            "queryItem",
128            "stringId",
129            "ncbiTaxonId",
130            "taxonName",
131            "preferredName",
132            "annotation",
133        ];
134        assert_eq!(mapping.get_column_names(), expected_column_names);
135        Ok(())
136    }
137
138    #[test]
139    fn test_string_interactions() -> Result<()> {
140        let args = StringInteractionsArgs::builder()
141            .identifiers(identifiers())
142            .build();
143        let interactions = string_interactions(&args)?;
144        let expected_column_names = vec![
145            "stringId_A",
146            "stringId_B",
147            "preferredName_A",
148            "preferredName_B",
149            "ncbiTaxonId",
150            "score",
151            "nscore",
152            "fscore",
153            "pscore",
154            "ascore",
155            "escore",
156            "dscore",
157            "tscore",
158        ];
159        assert_eq!(interactions.get_column_names(), expected_column_names);
160        Ok(())
161    }
162
163    #[test]
164    fn test_string_enrichment() -> Result<()> {
165        let args = StringFunctionalEnrichmentArgs::builder()
166            .identifiers(identifiers())
167            .build();
168        let enrichment = string_enrichment(&args)?;
169        let expected_column_names = vec![
170            "category",
171            "term",
172            "number_of_genes",
173            "number_of_genes_in_background",
174            "ncbiTaxonId",
175            "inputGenes",
176            "preferredNames",
177            "p_value",
178            "fdr",
179            "description",
180        ];
181        assert_eq!(enrichment.get_column_names(), expected_column_names);
182        Ok(())
183    }
184
185    #[test]
186    fn test_string_annotations() -> Result<()> {
187        let args = StringFunctionalAnnotationArgs::builder()
188            .identifiers(identifiers())
189            .build();
190        let annotations = string_annotations(&args)?;
191        let expected_column_names = vec![
192            "category",
193            "term",
194            "number_of_genes",
195            "ratio_in_set",
196            "ncbiTaxonId",
197            "inputGenes",
198            "preferredNames",
199            "description",
200        ];
201        assert_eq!(annotations.get_column_names(), expected_column_names);
202        Ok(())
203    }
204
205    #[test]
206    fn test_string_ppi_enrichment() -> Result<()> {
207        let args = StringPpiEnrichmentArgs::builder()
208            .identifiers(identifiers())
209            .build();
210        let enrichment = string_ppi_enrichment(&args)?;
211        let expected_column_names = vec![
212            "number_of_nodes",
213            "number_of_edges",
214            "average_node_degree",
215            "local_clustering_coefficient",
216            "expected_number_of_edges",
217            "p_value",
218        ];
219        assert_eq!(enrichment.get_column_names(), expected_column_names);
220        Ok(())
221    }
222}