Skip to main content

toolu_orm_query/
relational_builder.rs

1//! Type-state `RelationalQuery` built on [`RelationalSelectBuilder`](crate::select::RelationalSelectBuilder).
2//!
3//! # Public API
4//!
5//! - [`RelationalQuery`]
6
7use std::marker::PhantomData;
8
9use toolu_orm_core::relational_row::{parse_json_array_of_arrays, parse_json_single_array};
10
11use crate::select::relational::RelationalSelectBuilder;
12use crate::tuple_append::TupleAppend;
13
14/// Relational query with result shape in `T` (tuple that grows with each relation).
15pub struct RelationalQuery<T> {
16  builder: RelationalSelectBuilder,
17  _marker: PhantomData<T>,
18}
19
20impl<T> RelationalQuery<T> {
21  /// Inner SQL builder.
22  pub fn inner_builder(&self) -> &RelationalSelectBuilder {
23    &self.builder
24  }
25
26  /// Postgres SQL.
27  pub fn to_sql_postgres(&self) -> String {
28    self.builder.to_sql_postgres()
29  }
30
31  /// SQLite SQL.
32  pub fn to_sql_sqlite(&self) -> String {
33    self.builder.to_sql_sqlite()
34  }
35
36  /// Active dialect SQL.
37  pub fn to_sql(&self) -> String {
38    self.builder.to_sql()
39  }
40
41  /// Parse a has-many JSON column (`json_agg` / `json_group_array` shape).
42  ///
43  /// # Errors
44  ///
45  /// Forwards [`toolu_orm_core::relational_row::parse_json_array_of_arrays`] errors.
46  pub fn parse_many_column(
47    json: &str,
48  ) -> Result<Vec<Vec<serde_json::Value>>, toolu_orm_core::error::DbCoreError> {
49    parse_json_array_of_arrays(json)
50  }
51
52  /// Parse a has-one / belongs-to JSON column (`json_build_array` / null).
53  ///
54  /// # Errors
55  ///
56  /// Forwards [`toolu_orm_core::relational_row::parse_json_single_array`] errors.
57  pub fn parse_one_column(
58    json: &str,
59  ) -> Result<Vec<serde_json::Value>, toolu_orm_core::error::DbCoreError> {
60    parse_json_single_array(json)
61  }
62}
63
64impl<Base> RelationalQuery<(Base,)> {
65  /// Start a query; base row type is wrapped in a 1-tuple.
66  pub fn new(table: &str, columns: &[&str]) -> Self {
67    Self {
68      builder: RelationalSelectBuilder::new(table, columns),
69      _marker: PhantomData,
70    }
71  }
72}
73
74impl<T> RelationalQuery<T> {
75  /// Add has-many; appends `Vec<R>`.
76  pub fn with_many<R>(
77    self,
78    field_name: &str,
79    target_table: &str,
80    local_key: &str,
81    foreign_key_on_target: &str,
82    target_columns: &[&str],
83  ) -> RelationalQuery<<T as TupleAppend<Vec<R>>>::Output>
84  where
85    T: TupleAppend<Vec<R>>,
86  {
87    RelationalQuery {
88      builder: self.builder.with_many(
89        field_name,
90        target_table,
91        local_key,
92        foreign_key_on_target,
93        target_columns,
94      ),
95      _marker: PhantomData,
96    }
97  }
98
99  /// Add belongs-to / has-one; appends `Option<R>`.
100  pub fn with_one<R>(
101    self,
102    field_name: &str,
103    target_table: &str,
104    local_key: &str,
105    foreign_key_on_target: &str,
106    target_columns: &[&str],
107  ) -> RelationalQuery<<T as TupleAppend<Option<R>>>::Output>
108  where
109    T: TupleAppend<Option<R>>,
110  {
111    RelationalQuery {
112      builder: self.builder.with_one(
113        field_name,
114        target_table,
115        local_key,
116        foreign_key_on_target,
117        target_columns,
118      ),
119      _marker: PhantomData,
120    }
121  }
122}