supabase_rust_gftd/
lib.rs

1//! Supabase Rust Client Library
2//!
3//! A Rust client library for Supabase, providing access to Supabase services including
4//! database, auth, storage, and realtime subscriptions.
5//!
6//! This is a wrapper around individual Supabase component crates that provides
7//! a unified and convenient API that matches the JavaScript supabase-js client.
8
9// 各コンポーネントクレートの再エクスポート
10pub use supabase_rust_auth as auth;
11pub use supabase_rust_postgrest as postgrest;
12// pub use supabase_rust_storage as storage;
13// pub use supabase_rust_realtime as realtime;
14// pub use supabase_rust_functions as functions;
15
16// 内部モジュール
17mod config;
18mod error;
19
20// 公開エクスポート
21pub use config::ClientOptions;
22pub use error::{Error, Result};
23
24use reqwest::Client;
25// 使われていないインポートを削除
26// use reqwest::header::{HeaderMap, HeaderValue, HeaderName};
27// use serde::{Serialize, Deserialize};
28// use serde_json::Value;
29// use std::collections::HashMap;
30// use thiserror::Error;
31// use url::Url;
32// use serde_json::json;
33// use std::sync::Arc;
34// use std::sync::atomic::{AtomicBool, Ordering};
35use serde::Serialize;
36
37/// The main entry point for the Supabase Rust client
38pub struct Supabase {
39    /// The base URL for the Supabase project
40    pub url: String,
41    /// The anonymous API key for the Supabase project
42    pub key: String,
43    /// HTTP client used for requests
44    pub http_client: Client,
45    /// Auth client for user management and authentication
46    pub auth: auth::Auth,
47    /// Client options
48    pub options: config::ClientOptions,
49}
50
51impl Supabase {
52    /// Create a new Supabase client
53    ///
54    /// # Arguments
55    ///
56    /// * `supabase_url` - The base URL for your Supabase project
57    /// * `supabase_key` - The anonymous API key for your Supabase project
58    ///
59    /// # Example
60    ///
61    /// ```
62    /// use supabase_rust::Supabase;
63    ///
64    /// let supabase = Supabase::new("https://your-project-url.supabase.co", "your-anon-key");
65    /// ```
66    pub fn new(supabase_url: &str, supabase_key: &str) -> Self {
67        Self::new_with_options(supabase_url, supabase_key, ClientOptions::default())
68    }
69
70    /// Create a new Supabase client with custom options
71    ///
72    /// # Arguments
73    ///
74    /// * `supabase_url` - The base URL for your Supabase project
75    /// * `supabase_key` - The anonymous API key for your Supabase project
76    /// * `options` - Custom client options
77    ///
78    /// # Example
79    ///
80    /// ```
81    /// use supabase_rust::{Supabase, ClientOptions};
82    ///
83    /// let options = ClientOptions::default().with_auto_refresh_token(true);
84    /// let supabase = Supabase::new_with_options(
85    ///     "https://your-project-url.supabase.co",
86    ///     "your-anon-key",
87    ///     options
88    /// );
89    /// ```
90    pub fn new_with_options(supabase_url: &str, supabase_key: &str, options: ClientOptions) -> Self {
91        let http_client = Client::new();
92        
93        let auth_options = auth::AuthOptions {
94            auto_refresh_token: options.auto_refresh_token,
95            persist_session: options.persist_session,
96            detect_session_in_url: options.detect_session_in_url,
97        };
98        
99        let auth = auth::Auth::new(supabase_url, supabase_key, http_client.clone(), auth_options);
100        
101        Self {
102            url: supabase_url.to_string(),
103            key: supabase_key.to_string(),
104            http_client,
105            auth,
106            options,
107        }
108    }
109    
110    /// Get a reference to the auth client for user management and authentication
111    pub fn auth(&self) -> &auth::Auth {
112        &self.auth
113    }
114    
115    /// Create a new PostgrestClient for database operations on a specific table or view
116    ///
117    /// # Arguments
118    ///
119    /// * `table` - The name of the table or view
120    ///
121    /// # Example
122    ///
123    /// ```
124    /// use supabase_rust::Supabase;
125    ///
126    /// let supabase = Supabase::new("https://your-project-url.supabase.co", "your-anon-key");
127    /// let query = supabase.from("users");
128    /// ```
129    pub fn from(&self, table: &str) -> postgrest::PostgrestClient {
130        postgrest::PostgrestClient::new(
131            &self.url,
132            &self.key,
133            table,
134            self.http_client.clone(),
135        )
136    }
137    
138    /// Create a client for the Storage API
139    pub fn storage(&self) -> /* storage::StorageClient */ () {
140        /* storage::StorageClient::new(&self.url, &self.key, self.http_client.clone()) */
141        // Storage client is temporarily disabled until the crate is published
142        panic!("Storage client is not available in this version")
143    }
144    
145    /// Create a client for the Realtime API
146    pub fn realtime(&self) -> /* realtime::RealtimeClient */ () {
147        /* realtime::RealtimeClient::new(&self.url, &self.key) */
148        // Realtime client is temporarily disabled until the crate is published
149        panic!("Realtime client is not available in this version")
150    }
151    
152    /// Create a client for the Edge Functions API
153    pub fn functions(&self) -> /* functions::FunctionsClient */ () {
154        /* functions::FunctionsClient::new(&self.url, &self.key, self.http_client.clone()) */
155        // Functions client is temporarily disabled until the crate is published
156        panic!("Functions client is not available in this version")
157    }
158    
159    /// Execute a Postgres function via RPC
160    ///
161    /// # Arguments
162    ///
163    /// * `function_name` - The name of the function to call
164    /// * `params` - Parameters to pass to the function
165    ///
166    /// # Example
167    ///
168    /// ```
169    /// use supabase_rust::Supabase;
170    /// use serde_json::json;
171    ///
172    /// let supabase = Supabase::new("https://your-project-url.supabase.co", "your-anon-key");
173    /// let result = supabase.rpc("calculate_total", json!({"user_id": 123}));
174    /// ```
175    pub fn rpc(&self, function_name: &str, params: serde_json::Value) -> postgrest::PostgrestClient {
176        postgrest::PostgrestClient::rpc(
177            &self.url,
178            &self.key,
179            function_name,
180            params,
181            self.http_client.clone()
182        )
183    }
184}
185
186/// A convenience module for common imports
187pub mod prelude {
188    pub use crate::Supabase;
189    pub use crate::error::{Error, Result};
190    pub use crate::config::ClientOptions;
191    pub use crate::postgrest::{IsolationLevel, TransactionMode};
192}
193
194/// フィルター演算子
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
196#[serde(rename_all = "lowercase")]
197pub enum FilterOperator {
198    /// 等しい
199    Eq,
200    /// 等しくない
201    Neq,
202    /// より大きい
203    Gt,
204    /// より大きいか等しい
205    Gte,
206    /// より小さい
207    Lt,
208    /// より小さいか等しい
209    Lte,
210    /// 含む
211    In,
212    /// 含まない
213    NotIn,
214    /// 近い値(配列内の値に対して)
215    ContainedBy,
216    /// 含む(配列が対象の値を含む)
217    Contains,
218    /// 完全に含む(配列が対象の配列のすべての要素を含む)
219    ContainedByArray,
220    /// LIKE演算子(ワイルドカード検索)
221    Like,
222    /// ILIKE演算子(大文字小文字を区別しないワイルドカード検索)
223    ILike,
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229    use wiremock::{MockServer, Mock, ResponseTemplate};
230    use wiremock::matchers::{method, path, query_param};
231    use serde_json::json;
232    
233    #[tokio::test]
234    async fn test_integration() {
235        let mock_server = MockServer::start().await;
236        
237        // Auth モックエンドポイント
238        Mock::given(method("POST"))
239            .and(path("/auth/v1/token"))
240            .respond_with(ResponseTemplate::new(200)
241                .set_body_json(json!({
242                    "access_token": "test_token",
243                    "refresh_token": "test_refresh",
244                    "expires_in": 3600,
245                    "token_type": "bearer",
246                    "user": {
247                        "id": "1234",
248                        "email": "test@example.com"
249                    }
250                }))
251            )
252            .mount(&mock_server)
253            .await;
254        
255        // Database モックエンドポイント
256        Mock::given(method("GET"))
257            .and(path("/rest/v1/users"))
258            .respond_with(ResponseTemplate::new(200)
259                .set_body_json(json!([
260                    { "id": 1, "name": "Test User" }
261                ]))
262            )
263            .mount(&mock_server)
264            .await;
265        
266        // Storage モックエンドポイント
267        Mock::given(method("GET"))
268            .and(path("/storage/v1/bucket"))
269            .respond_with(ResponseTemplate::new(200)
270                .set_body_json(json!([
271                    { "id": "test-bucket", "name": "test-bucket", "public": true, "owner": "owner", "created_at": "2023-01-01", "updated_at": "2023-01-01" }
272                ]))
273            )
274            .mount(&mock_server)
275            .await;
276        
277        let supabase = Supabase::new(&mock_server.uri(), "test_key");
278        
279        // Database操作のテスト
280        let users: Vec<serde_json::Value> = supabase
281            .from("users")
282            .select("*")
283            .execute()
284            .await
285            .unwrap();
286        
287        assert_eq!(users.len(), 1);
288        assert_eq!(users[0]["name"], "Test User");
289        
290        // Storageバケット一覧取得のテスト
291        let buckets = supabase.storage().list_buckets().await.unwrap();
292        
293        assert_eq!(buckets.len(), 1);
294        assert_eq!(buckets[0].name, "test-bucket");
295    }
296}