supabase_client_query/
select.rs1use std::marker::PhantomData;
2
3use serde::de::DeserializeOwned;
4
5use supabase_client_core::SupabaseResponse;
6
7use crate::backend::QueryBackend;
8use crate::csv_select::CsvSelectBuilder;
9use crate::filter::Filterable;
10use crate::geojson_select::GeoJsonSelectBuilder;
11use crate::modifier::Modifiable;
12use crate::sql::{ExplainOptions, FilterCondition, ParamStore, SqlParts};
13
14pub struct SelectBuilder<T> {
16 pub(crate) backend: QueryBackend,
17 pub(crate) parts: SqlParts,
18 pub(crate) params: ParamStore,
19 pub(crate) _marker: PhantomData<T>,
20}
21
22impl<T> Filterable for SelectBuilder<T> {
23 fn filters_mut(&mut self) -> &mut Vec<FilterCondition> {
24 &mut self.parts.filters
25 }
26 fn params_mut(&mut self) -> &mut ParamStore {
27 &mut self.params
28 }
29}
30
31impl<T> Modifiable for SelectBuilder<T> {
32 fn parts_mut(&mut self) -> &mut SqlParts {
33 &mut self.parts
34 }
35}
36
37impl<T> SelectBuilder<T> {
38 pub fn schema(mut self, schema: &str) -> Self {
40 self.parts.schema_override = Some(schema.to_string());
41 self
42 }
43
44 pub fn explain(mut self) -> Self {
46 self.parts.explain = Some(ExplainOptions::default());
47 self
48 }
49
50 pub fn explain_with(mut self, options: ExplainOptions) -> Self {
52 self.parts.explain = Some(options);
53 self
54 }
55
56 pub fn head(mut self) -> Self {
58 self.parts.head = true;
59 self
60 }
61
62 pub fn csv(self) -> CsvSelectBuilder {
65 CsvSelectBuilder {
66 backend: self.backend,
67 parts: self.parts,
68 params: self.params,
69 }
70 }
71
72 pub fn geojson(self) -> GeoJsonSelectBuilder {
75 GeoJsonSelectBuilder {
76 backend: self.backend,
77 parts: self.parts,
78 params: self.params,
79 }
80 }
81}
82
83#[cfg(not(feature = "direct-sql"))]
85impl<T> SelectBuilder<T>
86where
87 T: DeserializeOwned + Send,
88{
89 pub async fn execute(self) -> SupabaseResponse<T> {
91 let QueryBackend::Rest { ref http, ref base_url, ref api_key, ref schema } = self.backend;
92 let method = if self.parts.head {
93 reqwest::Method::HEAD
94 } else {
95 reqwest::Method::GET
96 };
97 let (url, headers) = match crate::postgrest::build_postgrest_select(
98 base_url, &self.parts, &self.params,
99 ) {
100 Ok(r) => r,
101 Err(e) => return SupabaseResponse::error(
102 supabase_client_core::SupabaseError::QueryBuilder(e),
103 ),
104 };
105 crate::postgrest_execute::execute_rest(
106 http, method, &url, headers, None, api_key, schema, &self.parts,
107 ).await
108 }
109}
110
111#[cfg(feature = "direct-sql")]
113impl<T> SelectBuilder<T>
114where
115 T: DeserializeOwned + Send + Unpin + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
116{
117 pub async fn execute(self) -> SupabaseResponse<T> {
119 match &self.backend {
120 QueryBackend::Rest { http, base_url, api_key, schema } => {
121 let method = if self.parts.head {
122 reqwest::Method::HEAD
123 } else {
124 reqwest::Method::GET
125 };
126 let (url, headers) = match crate::postgrest::build_postgrest_select(
127 base_url, &self.parts, &self.params,
128 ) {
129 Ok(r) => r,
130 Err(e) => return SupabaseResponse::error(
131 supabase_client_core::SupabaseError::QueryBuilder(e),
132 ),
133 };
134 crate::postgrest_execute::execute_rest(
135 http, method, &url, headers, None, api_key, schema, &self.parts,
136 ).await
137 }
138 QueryBackend::DirectSql { pool } => {
139 crate::execute::execute_typed::<T>(pool, &self.parts, &self.params).await
140 }
141 }
142 }
143}