Skip to main content

systemprompt_database/models/
query.rs

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