bq_rs/
api.rs

1use crate::query::{request::QueryRequest, response::QueryResponse};
2use ureq::Request;
3
4pub struct Client {
5    host: String,
6    token: String,
7}
8
9pub enum ContentType {
10    Json(serde_json::Value),
11    None,
12}
13
14impl Client {
15    pub fn bq_client(token: String, project_id: &str) -> Self {
16        Self {
17            token,
18            host: format!(
19                "https://bigquery.googleapis.com/bigquery/v2/projects/{}",
20                project_id
21            ),
22        }
23    }
24
25    pub fn endpoint(&self, request: Request, body: ContentType) -> ureq::Response {
26        let request = request.set("AUTHORIZATION", &format!("Bearer {}", &self.token));
27
28        let response = match body {
29            ContentType::Json(data) => request.send_json(data),
30            ContentType::None => request.call(),
31        };
32
33        Self::handle_error(response)
34    }
35
36    /// <https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/getQueryResults>
37    pub fn jobs_query_results(&self, job_id: &str, location: &str) -> QueryResponse {
38        let response = self.endpoint(
39            ureq::get(&format!("{}/queries/{}", &self.host, job_id)).query("location", location),
40            ContentType::None,
41        );
42
43        response.into_json().unwrap()
44    }
45
46    /// <https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query>
47    /// the rows data is returned as a protobuf
48    pub fn jobs_query(&self, request: QueryRequest) -> QueryResponse {
49        let response = self.endpoint(
50            ureq::post(&format!("{}/queries", &self.host)),
51            ContentType::Json(serde_json::to_value(request).unwrap()),
52        );
53
54        let response: QueryResponse = response.into_json().unwrap();
55
56        response.retry(self)
57    }
58
59    pub fn tables_list(&self, dataset_id: &str) -> ureq::Response {
60        self.endpoint(
61            ureq::get(&format!("{}/datasets/{}/tables", &self.host, dataset_id)),
62            ContentType::None,
63        )
64    }
65
66    fn handle_error(result: Result<ureq::Response, ureq::Error>) -> ureq::Response {
67        match result {
68            Ok(r) => r,
69            Err(e) => {
70                let header = e.to_string();
71                let Some(response) = e.into_response() else {
72                    panic!("{:#?}", &header);
73                };
74
75                panic!("{}\n{}", header, response.into_string().unwrap());
76            }
77        }
78    }
79}