diff --git a/README.md b/README.md index d7eaf7b..f74a9f6 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,193 @@ - [ ] All Admin - [x] Database support (CRUD operations with fluent query builder) -### Quickstart -Add the following dependency to your toml file: -``` +## Quickstart + +Add the following dependency to your `Cargo.toml`: +```toml [dependencies] -supabase_rust = "0.1.0" +supabase-rust = "0.1.2" +tokio = { version = "1", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +``` + +### Client Initialization + +You can initialize the client with explicit values or via environment variables: + +```rust +use supabase_rust::Supabase; + +// Option 1: Using environment variables +// Set SUPABASE_URL, SUPABASE_API_KEY, and optionally SUPABASE_JWT_SECRET +let client = Supabase::new(None, None, None); + +// Option 2: Explicit configuration +let client = Supabase::new( + Some("https://your-project.supabase.co"), + Some("your-api-key"), + Some("your-jwt-secret"), +); +``` + +## Usage + +### Authentication + +```rust +use supabase_rust::Supabase; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Supabase::new(None, None, None); + + // Sign up a new user + let response = client + .signup_email_password("user@example.com", "password123") + .await?; + + // Sign in with email and password + let response = client + .sign_in_password("user@example.com", "password123") + .await?; + + // Parse the response to get tokens + let json: serde_json::Value = response.json().await?; + let access_token = json["access_token"].as_str().unwrap(); + let refresh_token = json["refresh_token"].as_str().unwrap(); + + // Refresh an access token + let response = client.refresh_token(refresh_token).await?; + + // Validate a JWT token + let claims = client.jwt_valid(access_token).await?; + println!("User email: {}", claims.email); + + Ok(()) +} ``` -You can initialize the two configuration keys either inline in the intialization or via environment variables (`SUPABASE_API_KEY` and `SUPABASE_URL`). +### Database Operations + +The library provides a fluent query builder for PostgREST database operations: + +```rust +use supabase_rust::Supabase; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +struct User { + id: i64, + name: String, + email: String, + status: String, +} + +#[derive(Debug, Serialize)] +struct NewUser { + name: String, + email: String, + status: String, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Supabase::new(None, None, None); + + // SELECT: Get all users + let response = client + .from("users") + .select("*") + .execute() + .await?; + let users: Vec = response.json().await?; + + // SELECT: Get specific columns with filters + let response = client + .from("users") + .select("id,name,email") + .eq("status", "active") + .order("name") + .limit(10) + .execute() + .await?; + + // INSERT: Create a new record + let new_user = NewUser { + name: "John Doe".to_string(), + email: "john@example.com".to_string(), + status: "active".to_string(), + }; + let response = client + .from("users") + .insert(&new_user) + .execute() + .await?; + + // UPDATE: Modify existing records + let updates = serde_json::json!({ + "status": "inactive" + }); + let response = client + .from("users") + .update(&updates) + .eq("id", "123") + .execute() + .await?; + + // DELETE: Remove records + let response = client + .from("users") + .delete() + .eq("id", "123") + .execute() + .await?; + + Ok(()) +} +``` + +### Available Filter Methods + +| Method | Description | PostgREST Equivalent | +|--------|-------------|---------------------| +| `eq(col, val)` | Equal | `col=eq.val` | +| `neq(col, val)` | Not equal | `col=neq.val` | +| `gt(col, val)` | Greater than | `col=gt.val` | +| `gte(col, val)` | Greater than or equal | `col=gte.val` | +| `lt(col, val)` | Less than | `col=lt.val` | +| `lte(col, val)` | Less than or equal | `col=lte.val` | +| `like(col, pattern)` | Pattern match (use `*` as wildcard) | `col=like.pattern` | +| `ilike(col, pattern)` | Case-insensitive pattern match | `col=ilike.pattern` | +| `in_(col, &[vals])` | Value in list | `col=in.(v1,v2,v3)` | +| `is_null(col)` | Is null | `col=is.null` | +| `not_null(col)` | Is not null | `col=not.is.null` | + +### Query Modifiers + +| Method | Description | +|--------|-------------| +| `order(col)` | Order by column (use `col.desc` for descending) | +| `limit(n)` | Limit number of rows | +| `offset(n)` | Skip first n rows | + +### Combining Filters + +Filters can be chained to create complex queries: + +```rust +let response = client + .from("products") + .select("id,name,price,category") + .gte("price", "10") + .lte("price", "100") + .neq("status", "discontinued") + .in_("category", &["electronics", "accessories"]) + .order("price.desc") + .limit(20) + .execute() + .await?; +``` ## Tips The Supabase team has an outline of their OpenAPI specs over in [this yaml file](https://github.com/supabase/gotrue/blob/master/openapi.yaml).