atmosphere_core/bind.rs
1//! Bind Module for Atmosphere SQL Framework
2//!
3//! This module provides functionality to bind values to SQL queries in a type-safe and efficient
4//! manner. It includes traits and implementations that facilitate the binding of parameters to
5//! various SQL query types, ensuring that the queries are correctly formatted and executed against
6//! the database.
7//!
8//! Key components of this module include the `Bindable` trait, which abstracts over different
9//! types of queries, allowing for flexible and dynamic binding of values, and the `Bind` trait,
10//! which provides an interface for binding columns to SQL queries in the context of a specific
11//! table.
12//!
13//! # Types
14//!
15//! - `BindError`: An error related to binding operations, such as unknown column errors.
16//! - `Bindable`: A trait for abstracting over different query types, providing a method to dynamically bind values.
17//! - `Bind`: A trait for binding columns to SQL queries, specific to table entities.
18//!
19//! The module plays a crucial role in the framework, enabling developers to write database
20//! interactions that are both expressive and resilient to errors like incorrect parameter types or
21//! missing values.
22
23use crate::{Column, Result, Table};
24use miette::Diagnostic;
25use sqlx::database::Database;
26use sqlx::query::QueryAs;
27use sqlx::{Encode, QueryBuilder, Type};
28use thiserror::Error;
29
30/// Enumerates errors that can occur during the binding of values to SQL queries.
31///
32/// This enum covers various issues that might arise when binding parameters, such as referencing
33/// unknown columns.
34#[derive(Debug, Diagnostic, Error)]
35#[non_exhaustive]
36pub enum BindError {
37 /// Represents an error where a specified column is unknown or not found.
38 #[error("unknown column: {0}")]
39 #[diagnostic(code(atmosphere::bind::unknown))]
40 Unknown(&'static str),
41}
42
43type Query<'q, DB> = sqlx::query::Query<'q, DB, <DB as Database>::Arguments<'q>>;
44
45/// Trait for dynamic binding of values.
46///
47/// `Bindable` provides an abstraction over different types of SQL queries, such as
48/// `sqlx::query::Query` and `sqlx::query::QueryAs`, allowing for flexible and dynamic binding of
49/// values. It is designed to work with various query types and enables the binding of values with
50/// different types and constraints.
51pub trait Bindable<'q> {
52 /// Binds a value to the query. The value must be compatible with the `atmosphere::Driver`.
53 fn dyn_bind<T: 'q + Send + Encode<'q, crate::Driver> + Type<crate::Driver>>(
54 self,
55 value: T,
56 ) -> Self;
57}
58
59impl<'q> Bindable<'q> for Query<'q, crate::Driver> {
60 fn dyn_bind<T: 'q + Send + Encode<'q, crate::Driver> + Type<crate::Driver>>(
61 self,
62 value: T,
63 ) -> Self {
64 self.bind(value)
65 }
66}
67
68impl<'q, E> Bindable<'q>
69 for QueryAs<'q, crate::Driver, E, <crate::Driver as Database>::Arguments<'q>>
70{
71 fn dyn_bind<T: 'q + Send + Encode<'q, crate::Driver> + Type<crate::Driver>>(
72 self,
73 value: T,
74 ) -> Self {
75 self.bind(value)
76 }
77}
78
79impl<'q> Bindable<'q> for QueryBuilder<'q, crate::Driver> {
80 fn dyn_bind<T: 'q + Send + Encode<'q, crate::Driver> + Type<crate::Driver>>(
81 mut self,
82 value: T,
83 ) -> Self {
84 self.push_bind(value);
85 self
86 }
87}
88
89/// Trait for binding columns to SQL queries in the context of a specific table.
90///
91/// This trait should be implemented by table entities to enable the binding of their columns to
92/// SQL queries. It provides a method to bind a single column, ensuring that the query correctly
93/// reflects the structure and constraints of the table.
94pub trait Bind: Table {
95 /// Binds a single column of the implementing table entity to a given query.
96 fn bind<'q, Q: Bindable<'q>>(&'q self, c: &'q Column<Self>, query: Q) -> Result<Q>;
97}