From bce282a6d4a31ae9ceb9f0f8978223388289383d Mon Sep 17 00:00:00 2001 From: dcodesdev <101001810+dcodesdev@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:42:12 +0300 Subject: [PATCH 1/4] New Example: Snippet Sharing --- axum/code-snippet-sharing-app/Cargo.toml | 15 ++ axum/code-snippet-sharing-app/README.md | 58 ++++++ axum/code-snippet-sharing-app/src/main.rs | 227 ++++++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 axum/code-snippet-sharing-app/Cargo.toml create mode 100644 axum/code-snippet-sharing-app/README.md create mode 100644 axum/code-snippet-sharing-app/src/main.rs diff --git a/axum/code-snippet-sharing-app/Cargo.toml b/axum/code-snippet-sharing-app/Cargo.toml new file mode 100644 index 00000000..47a7e1a0 --- /dev/null +++ b/axum/code-snippet-sharing-app/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "code-snippet-share" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = "0.8" +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } +shuttle-axum = "0.57.0" +shuttle-runtime = "0.57.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +uuid = { version = "1.0", features = ["v4", "serde"] } +chrono = { version = "0.4", features = ["serde"] } +nanoid = "0.4" diff --git a/axum/code-snippet-sharing-app/README.md b/axum/code-snippet-sharing-app/README.md new file mode 100644 index 00000000..a54e0982 --- /dev/null +++ b/axum/code-snippet-sharing-app/README.md @@ -0,0 +1,58 @@ +# Code Snippet Share API + +A lightweight API for sharing code snippets, built with **Rust**, **Axum**, and **Shuttle**. This hands-on tutorial demonstrates how to build, deploy, and manage a snippet-sharing service in the cloud. + +--- + +## Features + +- Create, list, view, and delete code snippets. +- Public and private snippet support. +- Tracks view count for each snippet. +- Filter snippets by programming language. +- Lightweight in-memory storage (ideal for tutorials and demos). + +--- + +## Tech Stack + +- **Rust** - Fast, safe, and expressive. +- **Axum** - Web framework for building async HTTP APIs. +- **Shuttle** - Rust serverless hosting platform. + +--- + +## Getting Started + +### Prerequisites + +- Rust (stable) +- Cargo +- Shuttle CLI: [Install Shuttle](https://docs.shuttle.dev/getting-started/installation) + +### Run Locally + +```bash +shuttle run +``` + +The API will start on `http://127.0.0.1:8000` + +### Deploy to Shuttle + +```bash +shuttle deploy +``` + +Your service will be live with a public URL provided by Shuttle. + +### Project Structure + +```bash +. +├── Cargo.lock +├── Cargo.toml +├── README.md +└── src + └── main.rs +``` diff --git a/axum/code-snippet-sharing-app/src/main.rs b/axum/code-snippet-sharing-app/src/main.rs new file mode 100644 index 00000000..5fa41a4c --- /dev/null +++ b/axum/code-snippet-sharing-app/src/main.rs @@ -0,0 +1,227 @@ +use chrono::{DateTime, Duration, Utc}; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use shuttle_axum::axum::{ + extract::{Path, Query, State}, + http::StatusCode, + response::Json, + routing::{get, post}, + Router, +}; +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct Snippet { + id: String, + content: String, + language: String, + title: Option, + description: Option, + created_at: DateTime, + expires_at: Option>, + view_count: u32, + is_public: bool, +} + +#[derive(Deserialize)] +struct CreateSnippet { + content: String, + language: String, + title: Option, + description: Option, + expires_in_hours: Option, + is_public: Option, +} + +#[derive(Deserialize)] +struct ListQuery { + language: Option, + limit: Option, +} + +#[derive(Serialize)] +struct SnippetFull { + id: String, + title: Option, + description: Option, + language: String, + created_at: DateTime, + expires_at: Option>, + view_count: u32, + char_count: usize, + content: String, +} + +#[derive(Serialize)] +struct SnippetInfo { + id: String, + title: Option, + description: Option, + language: String, + created_at: DateTime, + expires_at: Option>, + view_count: u32, + char_count: usize, +} + +#[derive(Serialize)] +struct CreateSnippetResponse { + id: String, + url: String, +} + +type SnippetStore = Arc>>; + +// Generate a short, URL-friendly ID +fn generate_snippet_id() -> String { + nanoid::nanoid!(8) // Generates 8-character ID like "V1StGXR8" +} + +async fn health() -> Json { + Json(json!({ + "status": "healthy", + "service": "code-snippet-share", + "timestamp": Utc::now() + })) +} + +async fn create_snippet( + State(store): State, + Json(payload): Json, +) -> Result<(StatusCode, Json), StatusCode> { + let id = generate_snippet_id(); + let now = Utc::now(); + + // Calculate expiration time if specified + let expires_at = payload + .expires_in_hours + .map(|hours| now + Duration::hours(hours)); + + let snippet = Snippet { + id: id.clone(), + content: payload.content, + language: payload.language, + title: payload.title, + description: payload.description, + created_at: now, + expires_at, + view_count: 0, + is_public: payload.is_public.unwrap_or(true), + }; + + let mut snippets = store.lock().unwrap(); + snippets.insert(id.clone(), snippet); + + let response = CreateSnippetResponse { + id: id.clone(), + url: format!("/snippets/{}", id), + }; + + Ok((StatusCode::CREATED, Json(response))) +} + +async fn get_snippet_full( + State(store): State, + Path(id): Path, +) -> Result, StatusCode> { + let mut snippets = store.lock().unwrap(); + + match snippets.get_mut(&id) { + Some(snippet) => { + if let Some(expires_at) = snippet.expires_at { + if Utc::now() > expires_at { + snippets.remove(&id); + return Err(StatusCode::NOT_FOUND); + } + } + + snippet.view_count += 1; + + let full = SnippetFull { + id: snippet.id.clone(), + title: snippet.title.clone(), + description: snippet.description.clone(), + language: snippet.language.clone(), + created_at: snippet.created_at, + expires_at: snippet.expires_at, + view_count: snippet.view_count, + char_count: snippet.content.len(), + content: snippet.content.clone(), + }; + + Ok(Json(full)) + } + None => Err(StatusCode::NOT_FOUND), + } +} + +async fn list_snippets( + State(store): State, + Query(params): Query, +) -> Json> { + let snippets = store.lock().unwrap(); + let now = Utc::now(); + + let mut snippet_infos: Vec = snippets + .values() + .filter(|snippet| { + // Only show public, non-expired snippets + snippet.is_public + && snippet.expires_at.is_none_or(|exp| now <= exp) + && params + .language + .as_ref() + .is_none_or(|lang| &snippet.language == lang) + }) + .map(|snippet| SnippetInfo { + id: snippet.id.clone(), + title: snippet.title.clone(), + description: snippet.description.clone(), + language: snippet.language.clone(), + created_at: snippet.created_at, + expires_at: snippet.expires_at, + view_count: snippet.view_count, + char_count: snippet.content.len(), + }) + .collect(); + + // Sort by creation date (newest first) + snippet_infos.sort_by(|a, b| b.created_at.cmp(&a.created_at)); + + // Limit results + let limit = params.limit.unwrap_or(20).min(100); + snippet_infos.truncate(limit); + + Json(snippet_infos) +} + +async fn delete_snippet( + State(store): State, + Path(id): Path, +) -> Result { + let mut snippets = store.lock().unwrap(); + + match snippets.remove(&id) { + Some(_) => Ok(StatusCode::NO_CONTENT), + None => Err(StatusCode::NOT_FOUND), + } +} + +#[shuttle_runtime::main] +async fn main() -> shuttle_axum::ShuttleAxum { + // Initialize the in-memory store + let store: SnippetStore = Arc::new(Mutex::new(HashMap::new())); + + // Build the router + let router = Router::new() + .route("/health", get(health)) + .route("/snippets", post(create_snippet).get(list_snippets)) + .route( + "/snippets/{id}", + get(get_snippet_full).delete(delete_snippet), + ) + .with_state(store); + + Ok(router.into()) +} From 82b11a6daac246cad502940e3540ffdcb5ab29d8 Mon Sep 17 00:00:00 2001 From: dcodesdev <101001810+dcodesdev@users.noreply.github.com> Date: Mon, 15 Sep 2025 21:20:10 +0300 Subject: [PATCH 2/4] shared db added --- axum/code-snippet-sharing-app/Cargo.toml | 9 +- .../20240101000000_create_snippets_table.sql | 16 ++ axum/code-snippet-sharing-app/src/main.rs | 239 +++++++++++------- 3 files changed, 176 insertions(+), 88 deletions(-) create mode 100644 axum/code-snippet-sharing-app/migrations/20240101000000_create_snippets_table.sql diff --git a/axum/code-snippet-sharing-app/Cargo.toml b/axum/code-snippet-sharing-app/Cargo.toml index 47a7e1a0..74fc7c30 100644 --- a/axum/code-snippet-sharing-app/Cargo.toml +++ b/axum/code-snippet-sharing-app/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "code-snippet-share" +name = "code-snippet-sharing-app" version = "0.1.0" edition = "2021" @@ -8,8 +8,15 @@ axum = "0.8" tokio = { version = "1", features = ["macros", "rt-multi-thread"] } shuttle-axum = "0.57.0" shuttle-runtime = "0.57.0" +shuttle-shared-db = { version = "0.57.0", features = ["postgres", "sqlx"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "1.0", features = ["v4", "serde"] } chrono = { version = "0.4", features = ["serde"] } nanoid = "0.4" +sqlx = { version = "0.8", features = [ + "runtime-tokio-rustls", + "postgres", + "chrono", + "uuid", +] } diff --git a/axum/code-snippet-sharing-app/migrations/20240101000000_create_snippets_table.sql b/axum/code-snippet-sharing-app/migrations/20240101000000_create_snippets_table.sql new file mode 100644 index 00000000..0f8e60f6 --- /dev/null +++ b/axum/code-snippet-sharing-app/migrations/20240101000000_create_snippets_table.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS snippets ( + id VARCHAR PRIMARY KEY NOT NULL, + content TEXT NOT NULL, + language VARCHAR NOT NULL, + title VARCHAR, + description TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + expires_at TIMESTAMPTZ, + view_count INTEGER NOT NULL DEFAULT 0, + is_public BOOLEAN NOT NULL DEFAULT true +); + +CREATE INDEX IF NOT EXISTS idx_snippets_created_at ON snippets(created_at DESC); +CREATE INDEX IF NOT EXISTS idx_snippets_language ON snippets(language); +CREATE INDEX IF NOT EXISTS idx_snippets_is_public ON snippets(is_public); +CREATE INDEX IF NOT EXISTS idx_snippets_expires_at ON snippets(expires_at); \ No newline at end of file diff --git a/axum/code-snippet-sharing-app/src/main.rs b/axum/code-snippet-sharing-app/src/main.rs index 5fa41a4c..9345f26a 100644 --- a/axum/code-snippet-sharing-app/src/main.rs +++ b/axum/code-snippet-sharing-app/src/main.rs @@ -8,10 +8,9 @@ use shuttle_axum::axum::{ routing::{get, post}, Router, }; -use std::collections::HashMap; -use std::sync::{Arc, Mutex}; +use sqlx::PgPool; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] struct Snippet { id: String, content: String, @@ -20,7 +19,7 @@ struct Snippet { description: Option, created_at: DateTime, expires_at: Option>, - view_count: u32, + view_count: i32, is_public: bool, } @@ -48,7 +47,7 @@ struct SnippetFull { language: String, created_at: DateTime, expires_at: Option>, - view_count: u32, + view_count: i32, char_count: usize, content: String, } @@ -61,8 +60,8 @@ struct SnippetInfo { language: String, created_at: DateTime, expires_at: Option>, - view_count: u32, - char_count: usize, + view_count: i32, + char_count: i32, } #[derive(Serialize)] @@ -71,8 +70,6 @@ struct CreateSnippetResponse { url: String, } -type SnippetStore = Arc>>; - // Generate a short, URL-friendly ID fn generate_snippet_id() -> String { nanoid::nanoid!(8) // Generates 8-character ID like "V1StGXR8" @@ -87,7 +84,7 @@ async fn health() -> Json { } async fn create_snippet( - State(store): State, + State(pool): State, Json(payload): Json, ) -> Result<(StatusCode, Json), StatusCode> { let id = generate_snippet_id(); @@ -98,120 +95,188 @@ async fn create_snippet( .expires_in_hours .map(|hours| now + Duration::hours(hours)); - let snippet = Snippet { - id: id.clone(), - content: payload.content, - language: payload.language, - title: payload.title, - description: payload.description, - created_at: now, + let result = sqlx::query!( + r#" + INSERT INTO snippets (id, content, language, title, description, created_at, expires_at, view_count, is_public) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) + "#, + id, + payload.content, + payload.language, + payload.title, + payload.description, + now, expires_at, - view_count: 0, - is_public: payload.is_public.unwrap_or(true), - }; - - let mut snippets = store.lock().unwrap(); - snippets.insert(id.clone(), snippet); - - let response = CreateSnippetResponse { - id: id.clone(), - url: format!("/snippets/{}", id), - }; + 0i32, + payload.is_public.unwrap_or(true) + ) + .execute(&pool) + .await; - Ok((StatusCode::CREATED, Json(response))) + match result { + Ok(_) => { + let response = CreateSnippetResponse { + id: id.clone(), + url: format!("/snippets/{}", id), + }; + Ok((StatusCode::CREATED, Json(response))) + } + Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR), + } } async fn get_snippet_full( - State(store): State, + State(pool): State, Path(id): Path, ) -> Result, StatusCode> { - let mut snippets = store.lock().unwrap(); - - match snippets.get_mut(&id) { - Some(snippet) => { - if let Some(expires_at) = snippet.expires_at { - if Utc::now() > expires_at { - snippets.remove(&id); - return Err(StatusCode::NOT_FOUND); - } - } + let now = Utc::now(); + + // First, check if snippet exists and is not expired + let snippet = sqlx::query_as!( + Snippet, + r#" + SELECT id, content, language, title, description, created_at, expires_at, view_count, is_public + FROM snippets + WHERE id = $1 AND (expires_at IS NULL OR expires_at > $2) + "#, + id, + now + ) + .fetch_optional(&pool) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - snippet.view_count += 1; + match snippet { + Some(mut snippet) => { + // Increment view count + let result = sqlx::query!( + "UPDATE snippets SET view_count = view_count + 1 WHERE id = $1", + id + ) + .execute(&pool) + .await; + + if result.is_ok() { + snippet.view_count += 1; + } let full = SnippetFull { - id: snippet.id.clone(), - title: snippet.title.clone(), - description: snippet.description.clone(), - language: snippet.language.clone(), + id: snippet.id, + title: snippet.title, + description: snippet.description, + language: snippet.language, created_at: snippet.created_at, expires_at: snippet.expires_at, view_count: snippet.view_count, char_count: snippet.content.len(), - content: snippet.content.clone(), + content: snippet.content, }; Ok(Json(full)) } - None => Err(StatusCode::NOT_FOUND), + None => { + // Clean up expired snippets + let _ = sqlx::query!( + "DELETE FROM snippets WHERE expires_at IS NOT NULL AND expires_at <= $1", + now + ) + .execute(&pool) + .await; + + Err(StatusCode::NOT_FOUND) + } } } async fn list_snippets( - State(store): State, + State(pool): State, Query(params): Query, ) -> Json> { - let snippets = store.lock().unwrap(); let now = Utc::now(); + let limit = params.limit.unwrap_or(20).min(100) as i64; - let mut snippet_infos: Vec = snippets - .values() - .filter(|snippet| { - // Only show public, non-expired snippets - snippet.is_public - && snippet.expires_at.is_none_or(|exp| now <= exp) - && params - .language - .as_ref() - .is_none_or(|lang| &snippet.language == lang) - }) - .map(|snippet| SnippetInfo { - id: snippet.id.clone(), - title: snippet.title.clone(), - description: snippet.description.clone(), - language: snippet.language.clone(), - created_at: snippet.created_at, - expires_at: snippet.expires_at, - view_count: snippet.view_count, - char_count: snippet.content.len(), - }) - .collect(); - - // Sort by creation date (newest first) - snippet_infos.sort_by(|a, b| b.created_at.cmp(&a.created_at)); - - // Limit results - let limit = params.limit.unwrap_or(20).min(100); - snippet_infos.truncate(limit); + let query = match params.language { + Some(language) => { + sqlx::query_as!( + SnippetInfo, + r#" + SELECT + id, + title, + description, + language, + created_at, + expires_at, + view_count, + LENGTH(content) as "char_count!" + FROM snippets + WHERE is_public = true + AND (expires_at IS NULL OR expires_at > $1) + AND language = $2 + ORDER BY created_at DESC + LIMIT $3 + "#, + now, + language, + limit + ) + .fetch_all(&pool) + .await + } + None => { + sqlx::query_as!( + SnippetInfo, + r#" + SELECT + id, + title, + description, + language, + created_at, + expires_at, + view_count, + LENGTH(content) as "char_count!" + FROM snippets + WHERE is_public = true + AND (expires_at IS NULL OR expires_at > $1) + ORDER BY created_at DESC + LIMIT $2 + "#, + now, + limit + ) + .fetch_all(&pool) + .await + } + }; + let snippet_infos = query.unwrap_or_else(|_| vec![]); Json(snippet_infos) } async fn delete_snippet( - State(store): State, + State(pool): State, Path(id): Path, ) -> Result { - let mut snippets = store.lock().unwrap(); + let result = sqlx::query!("DELETE FROM snippets WHERE id = $1", id) + .execute(&pool) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - match snippets.remove(&id) { - Some(_) => Ok(StatusCode::NO_CONTENT), - None => Err(StatusCode::NOT_FOUND), + if result.rows_affected() > 0 { + Ok(StatusCode::NO_CONTENT) + } else { + Err(StatusCode::NOT_FOUND) } } #[shuttle_runtime::main] -async fn main() -> shuttle_axum::ShuttleAxum { - // Initialize the in-memory store - let store: SnippetStore = Arc::new(Mutex::new(HashMap::new())); +async fn main(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_axum::ShuttleAxum { + // Run database migrations + sqlx::migrate!() + .run(&pool) + .await + .expect("Failed to run migrations"); // Build the router let router = Router::new() @@ -221,7 +286,7 @@ async fn main() -> shuttle_axum::ShuttleAxum { "/snippets/{id}", get(get_snippet_full).delete(delete_snippet), ) - .with_state(store); + .with_state(pool); Ok(router.into()) } From b204e78739daa8ef1abd5a617c90577ad5376a2e Mon Sep 17 00:00:00 2001 From: dcodesdev <101001810+dcodesdev@users.noreply.github.com> Date: Mon, 15 Sep 2025 21:23:23 +0300 Subject: [PATCH 3/4] Templates.toml updated --- templates.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates.toml b/templates.toml index 6798b9ba..20ff33b0 100644 --- a/templates.toml +++ b/templates.toml @@ -248,6 +248,13 @@ path = "axum/turso" use_cases = ["Web app", "Storage"] tags = ["turso", "axum", "database", "libsql", "sqlite"] +[templates.axum-code-snippet-sharing-app] +title = "Code Snippet Sharing" +description = "Share and manage code snippets with expiration and view tracking" +path = "axum/code-snippet-sharing-app" +use_cases = ["Web app", "Storage"] +tags = ["axum", "postgres", "database"] + [templates.axum-websocket] title = "Websockets" description = "Health monitoring service using websockets" From 10fde38d04ed8b4a3b7c5a7ce6dc7409aa6aa3be Mon Sep 17 00:00:00 2001 From: dcodesdev <101001810+dcodesdev@users.noreply.github.com> Date: Mon, 15 Sep 2025 21:32:24 +0300 Subject: [PATCH 4/4] sqlx queries --- ...acf5ddf9c87a872574afeb20289627a897e7a.json | 14 ++++ ...e8ad247d633fa8a073bdc0c6648089b5b0d4e.json | 66 +++++++++++++++++ ...130ff18e38de22b685489bb6f8eb0abacf281.json | 14 ++++ ...6eb431b51deb808b8b92c547acca53bb6fe55.json | 22 ++++++ ...6138694ecbe8df8f3618210232ad45d3d7a0c.json | 14 ++++ ...afd5c04ba143a352ab0dcea6cfe980721cd5f.json | 71 +++++++++++++++++++ ...30e58455d4f915bc0a0c481ce77a1aff2828c.json | 65 +++++++++++++++++ 7 files changed, 266 insertions(+) create mode 100644 axum/code-snippet-sharing-app/.sqlx/query-40f717379ce15156cabe7bd200bacf5ddf9c87a872574afeb20289627a897e7a.json create mode 100644 axum/code-snippet-sharing-app/.sqlx/query-49969fd63526646bb069216573be8ad247d633fa8a073bdc0c6648089b5b0d4e.json create mode 100644 axum/code-snippet-sharing-app/.sqlx/query-4d8ecc221df32f11c2b6143999f130ff18e38de22b685489bb6f8eb0abacf281.json create mode 100644 axum/code-snippet-sharing-app/.sqlx/query-89b5d73a044dbac1f3463535b7d6eb431b51deb808b8b92c547acca53bb6fe55.json create mode 100644 axum/code-snippet-sharing-app/.sqlx/query-9bed2880002e53cc7187b8b68256138694ecbe8df8f3618210232ad45d3d7a0c.json create mode 100644 axum/code-snippet-sharing-app/.sqlx/query-a409ebc9ab67f4cbd9daa9e0209afd5c04ba143a352ab0dcea6cfe980721cd5f.json create mode 100644 axum/code-snippet-sharing-app/.sqlx/query-b8207efb0a5e77f676e17f0c68e30e58455d4f915bc0a0c481ce77a1aff2828c.json diff --git a/axum/code-snippet-sharing-app/.sqlx/query-40f717379ce15156cabe7bd200bacf5ddf9c87a872574afeb20289627a897e7a.json b/axum/code-snippet-sharing-app/.sqlx/query-40f717379ce15156cabe7bd200bacf5ddf9c87a872574afeb20289627a897e7a.json new file mode 100644 index 00000000..61f62aa5 --- /dev/null +++ b/axum/code-snippet-sharing-app/.sqlx/query-40f717379ce15156cabe7bd200bacf5ddf9c87a872574afeb20289627a897e7a.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM snippets WHERE expires_at IS NOT NULL AND expires_at <= $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Timestamptz" + ] + }, + "nullable": [] + }, + "hash": "40f717379ce15156cabe7bd200bacf5ddf9c87a872574afeb20289627a897e7a" +} diff --git a/axum/code-snippet-sharing-app/.sqlx/query-49969fd63526646bb069216573be8ad247d633fa8a073bdc0c6648089b5b0d4e.json b/axum/code-snippet-sharing-app/.sqlx/query-49969fd63526646bb069216573be8ad247d633fa8a073bdc0c6648089b5b0d4e.json new file mode 100644 index 00000000..9303ddfc --- /dev/null +++ b/axum/code-snippet-sharing-app/.sqlx/query-49969fd63526646bb069216573be8ad247d633fa8a073bdc0c6648089b5b0d4e.json @@ -0,0 +1,66 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id,\n title,\n description,\n language,\n created_at,\n expires_at,\n view_count,\n LENGTH(content) as \"char_count!\"\n FROM snippets\n WHERE is_public = true\n AND (expires_at IS NULL OR expires_at > $1)\n AND language = $2\n ORDER BY created_at DESC\n LIMIT $3\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "language", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "expires_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 6, + "name": "view_count", + "type_info": "Int4" + }, + { + "ordinal": 7, + "name": "char_count!", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Timestamptz", + "Text", + "Int8" + ] + }, + "nullable": [ + false, + true, + true, + false, + false, + true, + false, + null + ] + }, + "hash": "49969fd63526646bb069216573be8ad247d633fa8a073bdc0c6648089b5b0d4e" +} diff --git a/axum/code-snippet-sharing-app/.sqlx/query-4d8ecc221df32f11c2b6143999f130ff18e38de22b685489bb6f8eb0abacf281.json b/axum/code-snippet-sharing-app/.sqlx/query-4d8ecc221df32f11c2b6143999f130ff18e38de22b685489bb6f8eb0abacf281.json new file mode 100644 index 00000000..76897346 --- /dev/null +++ b/axum/code-snippet-sharing-app/.sqlx/query-4d8ecc221df32f11c2b6143999f130ff18e38de22b685489bb6f8eb0abacf281.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE snippets SET view_count = view_count + 1 WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "4d8ecc221df32f11c2b6143999f130ff18e38de22b685489bb6f8eb0abacf281" +} diff --git a/axum/code-snippet-sharing-app/.sqlx/query-89b5d73a044dbac1f3463535b7d6eb431b51deb808b8b92c547acca53bb6fe55.json b/axum/code-snippet-sharing-app/.sqlx/query-89b5d73a044dbac1f3463535b7d6eb431b51deb808b8b92c547acca53bb6fe55.json new file mode 100644 index 00000000..b79fed91 --- /dev/null +++ b/axum/code-snippet-sharing-app/.sqlx/query-89b5d73a044dbac1f3463535b7d6eb431b51deb808b8b92c547acca53bb6fe55.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO snippets (id, content, language, title, description, created_at, expires_at, view_count, is_public)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Varchar", + "Varchar", + "Text", + "Timestamptz", + "Timestamptz", + "Int4", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "89b5d73a044dbac1f3463535b7d6eb431b51deb808b8b92c547acca53bb6fe55" +} diff --git a/axum/code-snippet-sharing-app/.sqlx/query-9bed2880002e53cc7187b8b68256138694ecbe8df8f3618210232ad45d3d7a0c.json b/axum/code-snippet-sharing-app/.sqlx/query-9bed2880002e53cc7187b8b68256138694ecbe8df8f3618210232ad45d3d7a0c.json new file mode 100644 index 00000000..eaff4244 --- /dev/null +++ b/axum/code-snippet-sharing-app/.sqlx/query-9bed2880002e53cc7187b8b68256138694ecbe8df8f3618210232ad45d3d7a0c.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM snippets WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "9bed2880002e53cc7187b8b68256138694ecbe8df8f3618210232ad45d3d7a0c" +} diff --git a/axum/code-snippet-sharing-app/.sqlx/query-a409ebc9ab67f4cbd9daa9e0209afd5c04ba143a352ab0dcea6cfe980721cd5f.json b/axum/code-snippet-sharing-app/.sqlx/query-a409ebc9ab67f4cbd9daa9e0209afd5c04ba143a352ab0dcea6cfe980721cd5f.json new file mode 100644 index 00000000..20fa0d1b --- /dev/null +++ b/axum/code-snippet-sharing-app/.sqlx/query-a409ebc9ab67f4cbd9daa9e0209afd5c04ba143a352ab0dcea6cfe980721cd5f.json @@ -0,0 +1,71 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT id, content, language, title, description, created_at, expires_at, view_count, is_public\n FROM snippets\n WHERE id = $1 AND (expires_at IS NULL OR expires_at > $2)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "content", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "language", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 6, + "name": "expires_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 7, + "name": "view_count", + "type_info": "Int4" + }, + { + "ordinal": 8, + "name": "is_public", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Timestamptz" + ] + }, + "nullable": [ + false, + false, + false, + true, + true, + false, + true, + false, + false + ] + }, + "hash": "a409ebc9ab67f4cbd9daa9e0209afd5c04ba143a352ab0dcea6cfe980721cd5f" +} diff --git a/axum/code-snippet-sharing-app/.sqlx/query-b8207efb0a5e77f676e17f0c68e30e58455d4f915bc0a0c481ce77a1aff2828c.json b/axum/code-snippet-sharing-app/.sqlx/query-b8207efb0a5e77f676e17f0c68e30e58455d4f915bc0a0c481ce77a1aff2828c.json new file mode 100644 index 00000000..1f79bb19 --- /dev/null +++ b/axum/code-snippet-sharing-app/.sqlx/query-b8207efb0a5e77f676e17f0c68e30e58455d4f915bc0a0c481ce77a1aff2828c.json @@ -0,0 +1,65 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id,\n title,\n description,\n language,\n created_at,\n expires_at,\n view_count,\n LENGTH(content) as \"char_count!\"\n FROM snippets\n WHERE is_public = true\n AND (expires_at IS NULL OR expires_at > $1)\n ORDER BY created_at DESC\n LIMIT $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "language", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "expires_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 6, + "name": "view_count", + "type_info": "Int4" + }, + { + "ordinal": 7, + "name": "char_count!", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Timestamptz", + "Int8" + ] + }, + "nullable": [ + false, + true, + true, + false, + false, + true, + false, + null + ] + }, + "hash": "b8207efb0a5e77f676e17f0c68e30e58455d4f915bc0a0c481ce77a1aff2828c" +}