Skip to main content

systemprompt_database/models/
query.rs

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