{"id":50599018,"url":"https://github.com/vbasky/somnia","last_synced_at":"2026-06-05T17:00:14.624Z","repository":{"id":362685481,"uuid":"1260406945","full_name":"vbasky/somnia","owner":"vbasky","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-05T13:58:20.000Z","size":0,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-05T14:06:41.079Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vbasky.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-05T13:11:36.000Z","updated_at":"2026-06-05T13:44:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vbasky/somnia","commit_stats":null,"previous_names":["vbasky/somnia"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/vbasky/somnia","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vbasky%2Fsomnia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vbasky%2Fsomnia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vbasky%2Fsomnia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vbasky%2Fsomnia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vbasky","download_url":"https://codeload.github.com/vbasky/somnia/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vbasky%2Fsomnia/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33951162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-05T17:00:12.788Z","updated_at":"2026-06-05T17:00:14.613Z","avatar_url":"https://github.com/vbasky.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# somnia\n\n[![crates.io](https://img.shields.io/crates/v/somnia.svg)](https://crates.io/crates/somnia)\n[![docs.rs](https://img.shields.io/docsrs/somnia)](https://docs.rs/somnia)\n[![CI](https://github.com/vbasky/somnia/actions/workflows/ci.yml/badge.svg)](https://github.com/vbasky/somnia/actions/workflows/ci.yml)\n[![MSRV](https://img.shields.io/badge/MSRV-1.95-blue.svg)](#status)\n[![license](https://img.shields.io/crates/l/somnia.svg)](#license)\n\n**A type-safe [SurrealDB](https://surrealdb.com) ORM for Rust** — a typed query\nbuilder, a `#[derive(SurrealRecord)]` macro, schema generation, and Diesel-style\nmigrations.\n\n\u003e *somnia* — Latin for \"dreams\". SurrealDB is *surreal* (dreamlike); somnia is\n\u003e where your Rust types dream in SurrealQL.\n\n```toml\n[dependencies]\nsomnia = \"0.1\"\n```\n\n---\n\n## Why\n\nWriting SurrealQL as hand-spliced strings is error-prone: typo'd table names,\nunescaped values, record-link mistakes, and projection drift. `somnia` lets your\nRust types describe the schema once and gives you:\n\n- **Typed query building** — `Post::table().select(...).filter(Post::title().eq(\"hello\"))`\n- **`#[derive(SurrealRecord)]`** — typed column accessors, table metadata, and\n  schema DDL generated from the struct.\n- **Schema as code** — `up()` / `down()` emit `DEFINE TABLE` / `DEFINE FIELD` /\n  `REMOVE TABLE` from the Rust type.\n- **Diesel-style migrations** — a `Migrator` that applies `up.surql` /\n  reverts `down.surql` from timestamped folders, with applied-state tracking.\n\n`somnia` **inlines literals** (with proper escaping) rather than relying on bind\nparameters — `to_surrealql()` returns a ready-to-run statement string, which keeps\ngenerated queries transparent and easy to log.\n\n## Quick start\n\n### Define a record\n\n```rust\nuse somnia::{SurrealRecord, Thing};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Debug, Clone, Serialize, Deserialize, SurrealRecord)]\n#[table(\"post\")]\nstruct Post {\n    #[field(thing)]\n    id: Thing\u003cPost\u003e,\n    title: String,\n    body: String,\n    published_at: Option\u003cString\u003e,\n}\n```\n\n### Build queries\n\n```rust\nuse somnia::{col, field, ident, RecordLink, Returning};\n\n// SELECT with typed columns + function-wrapped projections\nlet sql = Post::table()\n    .project(vec![\n        field(\"record::id(id)\", \"id\"),\n        col(\"title\"),\n        field(\"type::string(published_at)\", \"published_at\"),\n    ])\n    .filter(Post::published_at().ne(None))\n    .order_desc(ident(\"published_at\"))\n    .limit(20)\n    .to_surrealql();\n\n// CREATE … with record links\nlet create = Post::table()\n    .create()\n    .record(\"post-1\".to_string())\n    .set_lit(\"title\", \"Hello, world\".to_string())\n    .set_expr(\"author\", RecordLink::new(\"author\", \"bob\".to_string()))\n    .set_raw(\"published_at\", \"time::now()\")\n    .returning(Returning::After)\n    .to_surrealql();\n\n// UPDATE / DELETE with RETURN variants\nlet del = Post::table()\n    .delete()\n    .filter(ident(\"id\").eq_expr(RecordLink::new(\"post\", \"post-1\".to_string())))\n    .returning(Returning::Before)\n    .to_surrealql();\n```\n\nFor SurrealQL that isn't modeled as typed nodes (lambdas, `IF/THEN/ELSE`,\n`string::*` chains), use the `Raw(...)` / `field(\"…raw…\", \"alias\")` escape hatch —\nthe builder still owns the statement structure, table names, and record links.\n\n### Schema as code\n\n`#[derive(SurrealRecord)]` also implements `SurrealSchema`:\n\n```rust\nuse somnia::SurrealSchema;\n\n#[derive(Debug, Clone, Serialize, Deserialize, SurrealRecord)]\n#[table(\"comment\")]\nstruct Comment {\n    #[field(thing)] id: Thing\u003cComment\u003e,\n    #[field(record = \"post\")] post: serde_json::Value,\n    body: String,\n    #[field(ty = \"datetime\", default = \"time::now()\")] created_at: String,\n}\n\nComment::up();   // DEFINE TABLE … ; DEFINE FIELD … ;\nComment::down(); // REMOVE TABLE IF EXISTS comment;\n```\n\nField attributes: `#[field(thing)]` (record id), `record = \"table\"`\n(`record\u003ctable\u003e`), `default = \"…\"`, `value = \"…\"`, `ty = \"…\"` (full type\noverride), `flexible`, `name = \"…\"`, `skip`. Table attributes:\n`#[table(\"name\")]`, `#[table(\"name\", schemaless, permissions = \"NONE\")]`.\n\n### Migrations\n\nLay out migrations Diesel-style — one timestamped folder per migration with\n`up.surql` and `down.surql`:\n\n```bash\nmigrations/\n  2025-01-01-000000_create_posts/\n    up.surql\n    down.surql\n  2025-01-01-000100_seed_defaults/\n    up.surql\n    down.surql\n```\n\n```rust\nuse somnia::SomniaClient;\n\nlet client = SomniaClient::connect(\"ws://localhost:8000\", \"root\", \"root\", \"ns\", \"db\").await?;\nlet migrator = client.migrator(\"migrations\");\n\nmigrator.run().await?;          // apply all pending up.surql in order\nmigrator.revert_last().await?;  // run the latest down.surql\nfor m in migrator.status().await? {\n    println!(\"{} {}\", if m.applied { \"✓\" } else { \" \" }, m.id);\n}\n```\n\nApplied migrations are tracked in a `_somnia_migrations` table, so re-running only\napplies what's pending.\n\n## Crates\n\n| Crate | Description |\n| ------- | ------------- |\n| [`somnia`](crates/somnia) | Umbrella crate: client, migrator, re-exports. Start here. |\n| [`somnia-core`](crates/somnia-core) | Query builder, expression tree, `SurrealRecord`/`SurrealSchema` traits. |\n| [`somnia-derive`](crates/somnia-derive) | `#[derive(SurrealRecord)]` proc-macro. |\n| [`somnia-cli`](crates/somnia-cli) | Diesel-cli-style migration runner (the `somnia` binary). |\n\n## CLI\n\nA standalone migration runner, modeled on `diesel-cli`:\n\n```bash\ncargo install somnia-cli            # installs the `somnia` binary\n\nsomnia migration generate create_posts   # scaffold a timestamped up/down folder\nsomnia migration run                      # apply all pending migrations\nsomnia migration revert                   # revert the latest\nsomnia migration redo                     # revert + re-apply the latest\nsomnia migration list                     # show applied / pending\n```\n\nConnection settings are read from flags or environment variables (`--help` for\nthe full list).\n\n## Status\n\n`0.1.x` — early but tested against SurrealDB 3.x (query builder, derive, schema\ngeneration, and migrator all covered by integration tests that run on an\nin-memory engine). The API may evolve before `1.0`.\n\n**MSRV:** Rust **1.95** (set by the SurrealDB 3.x dependency tree). Bumping the\nminimum supported Rust version is treated as a minor-version change.\n\n## License\n\nLicensed under the [Apache License, Version 2.0](LICENSE).\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\nlicensed as above, without any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvbasky%2Fsomnia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvbasky%2Fsomnia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvbasky%2Fsomnia/lists"}