Atmosphere is a lightweight SQL framework designed for sustainable, database-reliant systems. It leverages Rust's powerful type and macro systems to derive SQL schemas from your rust struct definitions into an advanced trait system.
- SQL schema derivation from Rust structs.
- Advanced trait system for query generation.
- Automated database code testing with
atmosphere::testing - ORM-like CRUD traits.
- Code reusability across API layers using generics.
- Compile-time introspection for type-safe schema generation.
use atmosphere::prelude::*;
#[table(schema = "public", name = "user")]
struct User {
#[sql(pk)]
id: i32,
name: String,
#[sql(unique)]
email: String,
}
#[table(schema = "public", name = "post")]
struct Post {
#[sql(pk)]
id: i32,
#[sql(fk -> User, rename = "author_id")]
author: i32,
#[sql(unique)]
title: String,
}
#[tokio::main]
async fn main() -> sqlx::Result<()> {
let pool = atmosphere::Pool::connect(&std::env::var("DATABASE_URL").unwrap()).await?;
// CRUD operations
let user = User { id: 0, name: "demo".to_owned(), email: "[email protected]".to_owned(), };
user.save(&pool).await?;
user.delete(&pool).await?;
user.create(&pool).await?;
// Field Queries
assert_eq!(
User::read(&pool, &0).await?,
User::find_by_email(&pool, "[email protected]").await?.unwrap()
);
// Relationships
Post { id: 0, author: 0, title: "test".to_owned() }
.save(&pool)
.await?;
Post::find_by_author(&pool, &0).await?;
Post::delete_by_author(&pool, &0).await?;
// Inter-Table Operations
Post { id: 1, author: 0, title: "test1".to_owned() }
.author(&pool).await?;
user.posts(&pool).await?;
user.delete_posts(&pool).await?;
Ok(())
}Atmosphere introspects the User and Post structs at compile time and
generates const available type information about the schema into the Table
trait.
- Advanced SQL Trait System (
Table,Column,Relation..) - SQL Field Attributes (
#[sql(pk)],#[sql(fk -> Model)]and so on) - SQL Query Generation
- Automated Integration Testing
- Attribute Macro (
#[table])
- Transaction Support
- Getting Database Agnostic
- Hook into query execution using
atmosphere::hooks - Errors using
miette - Combined Primary and Foreign Keys
- Postgres Composite Types
- Support Custom Types
- Runtime Inspection
- Provide Application Utils
- Stabilize Traits
- Stabilize Query Generation
- Table Lenses (subsets / views)
-
validatorsupport - Auto Timestamping
- Virtual Columns using (
#[virtual = "<sql>"]) - Soft Delete Support
- Attribute Macro (
#[query]) - Custom queries
- Generate GraphQL + HTTP Servers?
- Generate Graphs
Given a struct Model that derives its atmosphere schema using #[table]:
use atmosphere::prelude::*;
#[table(schema = "public", name = "model")]
struct Model {
#[sql(pk)]
id: i32,
a: String,
#[sql(unique)]
b: String,
}Atmosphere is able to derive and generate the following queries:
Model::create
Model::read: read aModelby its primary key, returning aModel.Model::find: find aModelby its primary key, returning anOption<Model>.Model::read_all: read allModels, returning aVec<Model>.Model::reload
Model::updateModel::upsert
Model::deleteModel::delete_by
Each struct field that is marked with #[sql(unique)] becomes queryable.
In the above example b was marked as unique so atmosphere implements:
Model::find_by_b: find aModelby itsbfield, returning anOption<Model>.Model::delete_by_b: delete aModelby itsbfield.
Given that a model contains fields are marked as a foreign key / point to
another atmosphere::Table atmosphere β for example:
#[table(schema = "public", name = "submodel")]
struct Submodel {
#[sql(pk)]
id: i32,
#[sql(fk -> Model)]
super: i32,
}Atmosphere is able to generate utility queries to move across Table boundaries:
Model::submodelsModel::delete_submodelsSubmodel::modelSubmodel::find_by_modelSubmodel::delete_by_model
Note that the function names contain
modelandsubmodelβ they are derived from the respective struct names.
Several databases support a JSON (and often JSONB) type, for which sqlx has native support through #[sqlx(json)] and #[sqlx(json(nullable))].
Since atmosphere only needs to know whether the column is JSON and to stay forward-compatible with future changes to sqlx's attribute, we use the following syntax:
#[table(schema = "public", name = "submodel")]
struct Submodel {
#[sql(pk)]
id: i32,
#[sql(json)]
#[sqlx(json)]
data: HashMap<String, u64>,
#[sql(json)]
#[sqlx(json(nullable))]
optional_data: Option<HashMap<String, String>>,
}You can also manually handle the JSON support using the following (it will mean accessing the inner type through .as_ref() or .0):
use sqlx::types::Json;
#[table(schema = "public", name = "submodel")]
struct Submodel {
#[sql(pk)]
id: i32,
data: Json<HashMap<String, u64>>,
optional_data: Option<Json<HashMap<String, String>>>,
}We welcome contributions! Please see our contribution guidelines for more details.
Atmosphere is licensed under Apache 2.0.
