{"id":17859244,"url":"https://github.com/kanarus/qjack","last_synced_at":"2025-09-04T18:03:33.631Z","repository":{"id":163556595,"uuid":"638897230","full_name":"kanarus/qjack","owner":"kanarus","description":"ergonomic sqlx wrapper for nightly Rust","archived":false,"fork":false,"pushed_at":"2023-05-22T12:43:34.000Z","size":97,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-04T18:02:12.053Z","etag":null,"topics":["async","await","mysql","postgres","postgresql","rust","sql","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kanarus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2023-05-10T10:39:23.000Z","updated_at":"2023-10-10T10:35:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"ef6cb068-0395-4a46-8660-88741e2c6387","html_url":"https://github.com/kanarus/qjack","commit_stats":null,"previous_names":["kana-rus/qjack"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kanarus/qjack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanarus%2Fqjack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanarus%2Fqjack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanarus%2Fqjack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanarus%2Fqjack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kanarus","download_url":"https://codeload.github.com/kanarus/qjack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanarus%2Fqjack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273649440,"owners_count":25143634,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"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":["async","await","mysql","postgres","postgresql","rust","sql","sqlite"],"created_at":"2024-10-28T06:42:04.741Z","updated_at":"2025-09-04T18:03:33.596Z","avatar_url":"https://github.com/kanarus.png","language":"Rust","readme":"\u003ch1 align=\"center\"\u003eqjack\u003c/h1\u003e\n\n## ergonomic sqlx wrapper for *nightly* Rust\n- nightly only\n- macro free\n- available DB：PostgreSQL, MySQL, SQLite\n- available runtime：`tokio`, `async-std`\n\n\u003cimg align=\"right\" alt=\"qjack build check status\" src=\"https://github.com/kana-rus/qjack/actions/workflows/check.yaml/badge.svg\"/\u003e\n\n\u003cbr/\u003e\n\n## Sample; How to use\n```toml\n[dependencies]\nqjack = { version = \"0.1\", features = [\"rt_tokio\", \"db_postgres\"] }\ntokio = { version = \"1\", features = [\"macros\"] }\n```\n\u003cbr/\u003e\n\npart of [`sample/src/bin/friends.rs`](https://github.com/kana-rus/qjack/tree/main/sample/src/bin/friends.rs)\n```rust\n#[derive(Model, Debug)]\nstruct Friend {\n    id:       i32,\n    name:     String,\n    password: String,\n}\n\nimpl Friend {\n    async fn create_table_if_not_exists() -\u003e Result\u003c()\u003e {\n        q(\"CREATE TABLE IF NOT EXISTS friends (\n            id SERIAL PRIMARY KEY,\n            name VARCHAR(32) NOT NULL,\n            password VARCHAR(64) NOT NULL\n        )\").await?; Ok(())\n    }\n\n    async fn find_by_id(id: i32) -\u003e Result\u003cSelf\u003e {\n        q(Self::one(\"\n            SELECT id, name, password FROM friends\n            WHERE id = $1\n        \"), id).await\n    }\n\n    async fn search_by_password(password: \u0026str) -\u003e Result\u003cOption\u003cSelf\u003e\u003e {\n        q(Self::optional(\"\n            SELECT id, name, password FROM friends\n            WHERE password = $1\n        \"), password).await\n    }\n\n    async fn find_all_with_limit_by_name_like(like: \u0026str, limit: i32) -\u003e Result\u003cVec\u003cFriend\u003e\u003e {\n        q(Self::all(\"\n            SELECT id, name, password FROM friends\n            WHERE name LIKE $1\n            LIMIT $2\n        \"), like, limit).await\n    }\n\n    async fn create_many(name_passwords: impl IntoIterator\u003cItem = (String, String)\u003e) -\u003e Result\u003c()\u003e {\n        let mut name_passwords = name_passwords.into_iter();\n\n        let mut insert = String::from(\"INSERT INTO friends (name, password) VALUES\");\n        if let Some((first_name, first_password)) = name_passwords.next() {\n            insert.push_str(\u0026format!(\" ('{first_name}', '{first_password}')\"))\n        } else {return Ok(())}\n        for (name, password) in name_passwords {\n            insert.push_str(\u0026format!(\", ('{name}', '{password}')\"))\n        }\n\n        q(\u0026*insert).await?; Ok(())\n    }\n}\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c()\u003e {\n    q.jack(\"postgres://qjack:password@postgres:5432/db\")\n        .max_connections(42)\n        .await?;\n    println!(\"Hi, jacked!\");\n\n    Friend::create_table_if_not_exists().await?;\n\n    // ...\n```\n\u003cbr/\u003e\n\npart of [`sample/src/bin/transfer.rs`](https://github.com/kana-rus/qjack/tree/main/sample/src/bin/transfer.rs)\n```rust\n#[derive(Model, Debug)]\nstruct Account {\n    id:      i64,\n    name:    String,\n    balance: i64,\n}\n\nimpl Account {\n    async fn create_table_if_not_exists() -\u003e Result\u003c()\u003e {\n        q(\"CREATE TABLE IF NOT EXISTS accounts (\n            id BIGSERIAL PRIMARY KEY,\n            name VARCHAR(32) NOT NULL,\n            balance INT8 DEFAULT 0\n        )\").await?; Ok(())\n    }\n\n    async fn create_new(name: \u0026str) -\u003e Result\u003cSelf\u003e {\n        let created = q(Self::one(\"\n            INSERT INTO accounts\n            (name, balance) VALUES ($1, $2)\n            RETURNING id, name, balance\n        \"), name, 0).await?;\n\n        Ok(created)\n    }\n\n    async fn gets_income(\u0026mut self, income: i64) -\u003e Result\u003c()\u003e {\n        q(\"UPDATE accounts\n            SET balance = balance + $1\n            WHERE id = $2\n        \", income, \u0026self.id).await?;\n\n        self.balance += income;\n\n        Ok(())\n    }\n\n    // transaction is unsafe in current version\n    async unsafe fn transfer_to(\n        \u0026mut self,\n        payee: \u0026mut Account,\n        ammount: i64\n    ) -\u003e Result\u003c()\u003e {\n        q.transaction(|mut x| async {\n            if let Err(e) = x(\"\n                UPDATE accounts\n                SET balance = balance - $1\n                WHERE id = $2\n            \", \u0026ammount, \u0026self.id).await {\n                eprintln!(\"Failed to subtract balance: {e}\");\n                return x.rollback().await\n            }\n\n            if let Err(e) = x(\"\n                UPDATE accounts\n                SET balance = balance + $1\n                WHERE id = $2\n            \", \u0026ammount, \u0026payee.id).await {\n                eprintln!(\"Failed to add balance: {e}\");\n                return x.rollback().await\n            }\n\n            self.balance  -= ammount;\n            payee.balance += ammount;\n\n            x.commit().await\n        }).await\n    }\n}\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c()\u003e {\n    q.jack(\"postgres://qjack:password@postgres:5432/db\").await?;\n\n    // ...\n```\n\n\u003cbr/\u003e\n\n## `q` magic\n\n```rust\nq.jack(\"DB_URL\") /* config */ .await?\n```\ncreates connection pool in background. All queries must be performed after this.\n\n\u003cbr/\u003e\n\n```rust\nq.transaction(|mut x| async {\n    /*\n        returns\n            x.rollback().await\n        or\n            x.commit().await\n    */\n}).await?\n```\nperforms a transaction. This is **`unsafe`** in current version.\n\n\u003cbr/\u003e\n\n```rust\nq(\"query string\" /* , params, ... */ ).await?\n```\nexecutes a non-fetch query. This returns `QueryResult`.\n\n\u003cbr/\u003e\n\n```rust\nq( M::one(\"query string\") /* , params, ... */ ).await?\n```\n```rust\nq( M::all(\"query string\") /* , params, ... */ ).await?\n```\n```rust\nq( M::optional(\"query string\") /* , params, ... */ ).await?\n```\nexecutes a fetch query. Return type：\n\n- `one` → `M`\n- `all` → `Vec\u003cM\u003e`\n- `optional` → `Option\u003cM\u003e`\n\n( Here `M` means a struct that impls `Model` )\n\n\u003cbr/\u003e\n\n## LICENSE\n`qjack` is licensed under MIT LICENSE ([LICENSE](https://github.com/kana-rus/qjack/blob/main/LICENSE) or [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT))","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanarus%2Fqjack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkanarus%2Fqjack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanarus%2Fqjack/lists"}