Skip to main content

systemprompt_database/models/
query.rs

1use anyhow::Result;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use sqlx::postgres::PgRow;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Copy)]
8pub struct DatabaseQuery {
9    postgres: &'static str,
10}
11
12impl DatabaseQuery {
13    #[must_use]
14    pub const fn new(query: &'static str) -> Self {
15        Self { postgres: query }
16    }
17
18    #[must_use]
19    pub const fn postgres(&self) -> &str {
20        self.postgres
21    }
22}
23
24pub trait QuerySelector: Sync {
25    fn select_query(&self) -> &str;
26}
27
28impl QuerySelector for &str {
29    fn select_query(&self) -> &str {
30        self
31    }
32}
33
34impl QuerySelector for String {
35    fn select_query(&self) -> &str {
36        self.as_str()
37    }
38}
39
40impl QuerySelector for DatabaseQuery {
41    fn select_query(&self) -> &str {
42        self.postgres()
43    }
44}
45
46pub trait FromDatabaseRow: Sized {
47    fn from_postgres_row(row: &PgRow) -> Result<Self>;
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct QueryResult {
52    pub columns: Vec<String>,
53    pub rows: Vec<QueryRow>,
54    pub row_count: usize,
55    pub execution_time_ms: u64,
56}
57
58// JSON: dynamic query result rows — column shape unknown at compile time
59pub type QueryRow = HashMap<String, Value>;
60
61impl QueryResult {
62    #[must_use]
63    pub const fn new() -> Self {
64        Self {
65            columns: vec![],
66            rows: vec![],
67            row_count: 0,
68            execution_time_ms: 0,
69        }
70    }
71
72    #[must_use]
73    pub fn is_empty(&self) -> bool {
74        self.rows.is_empty()
75    }
76
77    #[must_use]
78    pub fn first(&self) -> Option<&QueryRow> {
79        self.rows.first()
80    }
81}
82
83impl Default for QueryResult {
84    fn default() -> Self {
85        Self::new()
86    }
87}