Skip to main content

systemprompt_database/models/
query.rs

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