# WowSQL Rust SDK
Official Rust client for [WowSQL](https://wowsql.com) — PostgreSQL backend-as-a-service with project auth, object storage, and schema management.
**Crate:** `wowsql` · **Edition:** 2021 · **Rust:** 1.70+ recommended
[](https://opensource.org/licenses/MIT)
---
## Table of contents
1. [Installation](#installation)
2. [Quick start](#quick-start)
3. [Concepts & API keys](#concepts--api-keys)
4. [Database: `WOWSQLClient`](#database-wowsqlclient)
5. [Table & `QueryBuilder`](#table--querybuilder)
6. [Authentication: `AuthClient`](#authentication-authclient)
7. [Storage: `StorageClient`](#storage-storageclient)
8. [Schema: `SchemaClient`](#schema-schemaclient)
9. [Models & enums](#models--enums)
10. [Errors](#errors)
11. [Features](#features-cargo)
12. [Examples](#examples)
13. [Links](#links)
---
## Installation
`Cargo.toml`:
```toml
[dependencies]
wowsql = "1.3"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
serde_json = "1"
```
Async methods are `async` and return `Result<_, wowsql::WOWSQLError>` (or specialized storage/schema errors where noted).
---
## Quick start
```rust
use serde_json::{json, Value};
use wowsql::WOWSQLClient;
#[tokio::main]
async fn main() -> Result<(), wowsql::WOWSQLError> {
let client = WOWSQLClient::new(
"https://your-project.wowsql.com",
std::env::var("WOWSQL_SERVICE_KEY").unwrap().as_str(),
)?;
let res = client
.table("posts")
.select(&["id", "title"])
.eq("published", json!(true))
.limit(10)
.execute::<Value>()
.await?;
println!("rows: {}", res.count);
Ok(())
}
```
---
## Concepts & API keys
| Anonymous | `wowsql_anon_…` | Client-side auth; limited DB access |
| Service role | `wowsql_service_…` | **Server only** — full DB, storage, **schema DDL** |
- `SchemaClient` **must** use a **service role** key.
- End-user JWTs from `AuthClient` are for your app session — use **API keys** for `WOWSQLClient` / `StorageClient` from backends (same model as other official SDKs).
---
## Database: `WOWSQLClient`
### Construction
```rust
use wowsql::WOWSQLClient;
// Simple
let client = WOWSQLClient::new(project_url, api_key)?;
// Builder
let client = WOWSQLClient::builder(project_url, api_key)
.base_domain("wowsql.com")
.secure(true)
.timeout(30)
.verify_ssl(true)
.build()?;
```
### Methods
| `table(&self, name: &str) -> Table` | `Table` | Query/CRUD for one table. |
| `list_tables(&self).await` | `Vec<String>` | |
| `get_table_schema(&self, name).await` | `TableSchema` | |
| `query<T: DeserializeOwned>(&self, sql).await` | `Vec<T>` | Raw SQL helper when enabled. |
| `health(&self).await` | `serde_json::Value` | |
| `close(self)` | — | |
---
## Table & `QueryBuilder`
### `Table`
| `select(&[&str]) -> QueryBuilder` | Starts builder. |
| `filter(column, FilterOperator, value, logical_op?)` | |
| `get() -> QueryBuilder` | Empty select pipeline. |
| `get_by_id(id).await` | `serde_json::Value` |
| `create` / `insert` | `CreateResponse` |
| `bulk_insert(records).await` | `serde_json::Value` |
| `upsert(data, on_conflict).await` | `serde_json::Value` |
| `update(id, data).await` | `UpdateResponse` |
| `delete(id).await` | `DeleteResponse` |
| `eq`, `neq`, `gt`, `gte`, `lt`, `lte` | `QueryBuilder` |
| `order_by(column, SortDirection)` | `QueryBuilder` |
| `count().await` | `usize` |
| `paginate(page, per_page).await` | `PaginatedResponse<T>` |
| `where()` | `QueryBuilder` (named `r#where` in Rust) |
### `QueryBuilder` (owned / consuming)
Chain: `select`, `filter`, `eq`, …, `group_by`, `having`, `order_by` / `order`, `order_by_multiple`, `limit`, `offset`.
**Terminal (consume `self`):**
- `execute::<T>()`, `get::<T>()`
- `first::<T>()`, `single::<T>()`
- `count()`
- `paginate::<T>(page, per_page)`
**Mutations on builder:** `create`, `insert`, `update`, `delete` (when supported by implementation).
### `FilterOperator` & `SortDirection`
`FilterOperator`: `Eq`, `Neq`, `Gt`, `Gte`, `Lt`, `Lte`, `Like`, `IsNull`, `In`, `NotIn`, `Between`, `NotBetween`, `IsNot`.
`SortDirection`: `Asc`, `Desc`.
---
## Authentication: `AuthClient`
```rust
use wowsql::{AuthClient, AuthClientBuilder, MemoryTokenStorage, TokenStorage};
use std::sync::Arc;
let auth = AuthClient::builder(project_url, anon_key)
.base_domain("wowsql.com")
.timeout(30)
.token_storage(Arc::new(MemoryTokenStorage::new()))
.build()?;
```
### `TokenStorage` trait
`Send + Sync`: `get_access_token`, `get_refresh_token`, `set_tokens`, `clear`.
### Methods (async unless noted)
| `sign_up(email, password, full_name, user_metadata).await` | `AuthResponse` |
| `sign_in(email, password).await` | `AuthResponse` |
| `get_user(access_token?).await` | `AuthUser` |
| `get_oauth_authorization_url(provider, redirect_uri?).await` | `HashMap<String, Value>` |
| `exchange_oauth_callback(provider, code, redirect_uri?).await` | `AuthResponse` |
| `forgot_password`, `reset_password` | `HashMap<String, Value>` |
| `send_otp`, `verify_otp`, `send_magic_link`, `verify_email`, `resend_verification` | mixed |
| `logout`, `refresh_token`, `change_password` | mixed |
| `update_user(options: Value).await` | `AuthUser` |
| `get_session()` | `Option<AuthSession>` |
| `set_session`, `clear_session` | |
---
## Storage: `StorageClient`
```rust
use wowsql::StorageClient;
let storage = StorageClient::builder(project_url, api_key)
.base_domain("wowsql.com")
.timeout(60)
.build()?;
```
| `create_bucket(name, options?).await` | `StorageBucket` |
| `list_buckets().await` | `Vec<StorageBucket>` |
| `get_bucket(name).await` | `StorageBucket` |
| `update_bucket(name, options).await` | `StorageBucket` |
| `delete_bucket(name).await` | `serde_json::Value` |
| `upload(bucket, data: &[u8], path?, file_name?).await` | `FileUploadResult` |
| `upload_from_path(path, bucket, remote_path?).await` | `FileUploadResult` |
| `list_files(bucket, options?).await` | `Vec<StorageFile>` |
| `download(bucket, path).await` | `Vec<u8>` |
| `download_to_file(bucket, path, local_path).await` | `()` |
| `delete_file(bucket, path).await` | `serde_json::Value` |
| `get_public_url(bucket, path)` | `String` |
| `get_stats().await` | `StorageStats` |
| `get_quota().await` | `StorageQuota` |
---
## Schema: `SchemaClient`
**Requires service role key.**
```rust
use wowsql::{SchemaClient, ColumnDefinition};
let schema = SchemaClient::builder(project_url, service_key)
.base_domain("wowsql.com")
.build()?;
schema
.create_table(
"items",
vec![
ColumnDefinition::new("id", "SERIAL").auto_increment(true),
ColumnDefinition::new("name", "TEXT").not_null(true),
],
Some("id"),
None,
)
.await?;
```
| `create_table` | `SchemaResponse` |
| `alter_table` | `SchemaResponse` |
| `drop_table` | `SchemaResponse` |
| `execute_sql` | `SchemaResponse` |
| `add_column`, `drop_column`, `rename_column`, `modify_column` | `SchemaResponse` |
| `create_index` | `SchemaResponse` |
| `list_tables().await` | `Vec<String>` |
| `get_table_schema(name).await` | `TableSchema` |
Helpers: `ColumnDefinition`, `CreateTableRequest`, `AlterTableRequest`, `IndexDefinition`, `RenameColumn`, `SchemaResponse`.
---
## Models & enums
Exported from `wowsql::models`: `QueryResponse`, `CreateResponse`, `UpdateResponse`, `DeleteResponse`, `PaginatedResponse`, `TableSchema`, `ColumnInfo`, `FilterExpression`, `HavingFilter`, `OrderByItem`, `AuthUser`, `AuthSession`, `AuthResponse`, `OAuthAuthorizationResponse`, `StorageBucket`, `StorageFile`, `StorageQuota`, `StorageStats`, `FileUploadResult`, etc.
---
## Errors
- `WOWSQLError` — main error type; `new`, `from_response`, `is_authentication`, `is_not_found`, `is_rate_limit`.
- `StorageError`, `StorageLimitExceededError`
- `SchemaPermissionError`
`From` conversions exist for `reqwest::Error` and storage/schema errors where implemented.
Use `?` in async functions or match on `e` for status / body.
---
## Features (Cargo)
Default features match `Cargo.toml`. Add `serde` types in your app for typed rows; SDK uses `serde_json::Value` in many places.
---
## Examples
### Paginated list
```rust
let page = client
.table("orders")
.select(&["id", "total"])
.gte("total", json!(10))
.order_by("id", wowsql::SortDirection::Desc)
.paginate::<Value>(1, 20)
.await?;
```
### Auth sign-in
```rust
let session = auth.sign_in("a@b.com", "secret").await?.session.unwrap();
auth.set_session(&session.access_token, &session.refresh_token);
```
---
## Links
- [Documentation](https://wowsql.com/docs)
- [Website](https://wowsql.com)
**License:** MIT