diff options
| author | soryu <soryu@soryu.co> | 2025-12-23 02:14:58 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2025-12-23 14:47:18 +0000 |
| commit | a32dc56d2e5447ef8988cb98b8686476cc94e70c (patch) | |
| tree | 61307503c4af82103cea2360fe95d3ea324968d6 /makima/src/db/models.rs | |
| parent | 73649d135efccda7e446775db773e21b458de202 (diff) | |
| download | soryu-a32dc56d2e5447ef8988cb98b8686476cc94e70c.tar.gz soryu-a32dc56d2e5447ef8988cb98b8686476cc94e70c.zip | |
Add Postgres for persistence and File cabinet
Migrations are local only currently, and must be run manually by setting POSTGRES_CONNECTION_URI
Diffstat (limited to 'makima/src/db/models.rs')
| -rw-r--r-- | makima/src/db/models.rs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs new file mode 100644 index 0000000..45b0e53 --- /dev/null +++ b/makima/src/db/models.rs @@ -0,0 +1,101 @@ +//! Database models for the files table. + +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use sqlx::FromRow; +use utoipa::ToSchema; +use uuid::Uuid; + +/// TranscriptEntry stored in JSONB - matches frontend TranscriptEntry +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct TranscriptEntry { + pub id: String, + pub speaker: String, + pub start: f32, + pub end: f32, + pub text: String, + pub is_final: bool, +} + +/// File record from the database. +#[derive(Debug, Clone, FromRow, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct File { + pub id: Uuid, + pub owner_id: Uuid, + pub name: String, + pub description: Option<String>, + #[sqlx(json)] + pub transcript: Vec<TranscriptEntry>, + pub location: Option<String>, + pub created_at: DateTime<Utc>, + pub updated_at: DateTime<Utc>, +} + +/// Request payload for creating a new file. +#[derive(Debug, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct CreateFileRequest { + /// Name of the file (auto-generated if not provided) + pub name: Option<String>, + /// Optional description + pub description: Option<String>, + /// Transcript entries + pub transcript: Vec<TranscriptEntry>, + /// Storage location (e.g., s3://bucket/path) - not used yet + pub location: Option<String>, +} + +/// Request payload for updating an existing file. +#[derive(Debug, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct UpdateFileRequest { + /// New name (optional) + pub name: Option<String>, + /// New description (optional) + pub description: Option<String>, + /// New transcript (optional) + pub transcript: Option<Vec<TranscriptEntry>>, +} + +/// Response for file list endpoint. +#[derive(Debug, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct FileListResponse { + pub files: Vec<FileSummary>, + pub total: i64, +} + +/// Summary of a file for list views (excludes full transcript). +#[derive(Debug, Clone, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct FileSummary { + pub id: Uuid, + pub name: String, + pub description: Option<String>, + pub transcript_count: usize, + /// Duration derived from last transcript end time + pub duration: Option<f32>, + pub created_at: DateTime<Utc>, + pub updated_at: DateTime<Utc>, +} + +impl From<File> for FileSummary { + fn from(file: File) -> Self { + let duration = file + .transcript + .iter() + .map(|t| t.end) + .fold(0.0_f32, f32::max); + Self { + id: file.id, + name: file.name, + description: file.description, + transcript_count: file.transcript.len(), + duration: if duration > 0.0 { Some(duration) } else { None }, + created_at: file.created_at, + updated_at: file.updated_at, + } + } +} |
