commit aa0015725bc01def0528dd8babfb192da86cb52d
parent 60a5cecddce56036be2d0a950ae7ab819117a90c
Author: Silas Brack <silasbrack@gmail.com>
Date: Wed, 22 Apr 2026 13:20:05 +0200
feat: generate Rust types from Trailbase schema
- Add scripts/generate-types.sh using quicktype
- Generated types in src/trailbase_types.rs
- Import generated types in trailbase.rs
- Add quicktype to dev shell
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat:
8 files changed, 145 insertions(+), 17 deletions(-)
diff --git a/flake.nix b/flake.nix
@@ -165,6 +165,7 @@
cargo-watch
cargo-edit
rust-analyzer
+ quicktype
# Backend
(pkgs.callPackage ./trailbase.nix { })
diff --git a/schemas/category.json b/schemas/category.json
@@ -0,0 +1,15 @@
+{
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id"
+ ],
+ "title": "category",
+ "type": "object"
+}
diff --git a/schemas/news_item.json b/schemas/news_item.json
@@ -0,0 +1,37 @@
+{
+ "properties": {
+ "author": {
+ "type": "string"
+ },
+ "created_by": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "language": {
+ "type": "string"
+ },
+ "published": {
+ "type": "string"
+ },
+ "text": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "title",
+ "text",
+ "published",
+ "language"
+ ],
+ "title": "news_item",
+ "type": "object"
+}
diff --git a/schemas/news_item_category.json b/schemas/news_item_category.json
@@ -0,0 +1,20 @@
+{
+ "properties": {
+ "category_id": {
+ "type": "integer"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "news_item_id": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "id",
+ "news_item_id",
+ "category_id"
+ ],
+ "title": "news_item_category",
+ "type": "object"
+}
diff --git a/scripts/generate-types.sh b/scripts/generate-types.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+SCHEMA_DIR="$PROJECT_DIR/schemas"
+OUTPUT_FILE="$PROJECT_DIR/src/trailbase_types.rs"
+
+mkdir -p "$SCHEMA_DIR"
+
+echo "Exporting schemas from Trailbase..."
+
+# Export schemas for each table (filter out non-JSON lines)
+tables=(news_item category news_item_category)
+for table in "${tables[@]}"; do
+ trail schema "$table" --mode select 2>/dev/null | grep -v "^Rust\|^Run " > "$SCHEMA_DIR/${table}.json"
+ echo " - $table"
+done
+
+echo "Generating Rust types with quicktype..."
+
+# Generate all types in one file using --src-lang schema
+quicktype \
+ --src-lang schema \
+ --lang rust \
+ --visibility public \
+ --derive-debug \
+ --density dense \
+ --src "$SCHEMA_DIR/news_item.json" \
+ --src "$SCHEMA_DIR/category.json" \
+ --src "$SCHEMA_DIR/news_item_category.json" \
+ --out "$OUTPUT_FILE"
+
+# Add Clone derive to all structs
+sed -i 's/#\[derive(Debug, Serialize, Deserialize)\]/#[derive(Debug, Clone, Serialize, Deserialize)]/g' "$OUTPUT_FILE"
+
+# Remove the example comments and add our module doc
+sed -i '1,/^use serde/{ /^use serde/!d }' "$OUTPUT_FILE"
+sed -i '1i //! Auto-generated types from Trailbase schema.\n//! Run `./scripts/generate-types.sh` to regenerate.\n' "$OUTPUT_FILE"
+
+echo "Generated $OUTPUT_FILE"
diff --git a/src/main.rs b/src/main.rs
@@ -15,6 +15,7 @@ mod routes;
mod state;
mod templates;
mod trailbase;
+mod trailbase_types;
use config::Config;
use state::AppState;
diff --git a/src/trailbase.rs b/src/trailbase.rs
@@ -2,6 +2,7 @@ use reqwest::Client;
use serde::{Deserialize, Serialize};
use crate::config::Config;
+pub use crate::trailbase_types::{Category, NewsItem, NewsItemCategory};
#[derive(Clone)]
pub struct TrailbaseClient {
@@ -10,23 +11,6 @@ pub struct TrailbaseClient {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct NewsItem {
- pub id: i64,
- pub title: String,
- pub text: String,
- pub published: String,
- pub url: Option<String>,
- pub author: Option<String>,
- pub language: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Category {
- pub id: i64,
- pub name: Option<String>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResult {
pub title: String,
pub text: String,
diff --git a/src/trailbase_types.rs b/src/trailbase_types.rs
@@ -0,0 +1,29 @@
+//! Auto-generated types from Trailbase schema.
+//! Run `./scripts/generate-types.sh` to regenerate.
+
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct NewsItem {
+ pub author: Option<String>,
+ pub created_by: Option<String>,
+ pub id: i64,
+ pub language: String,
+ pub published: String,
+ pub text: String,
+ pub title: String,
+ pub url: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Category {
+ pub id: i64,
+ pub name: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct NewsItemCategory {
+ pub category_id: i64,
+ pub id: i64,
+ pub news_item_id: i64,
+}