Skip to main content

rust_query/
lib.rs

1#![allow(private_bounds, private_interfaces, clippy::type_complexity)]
2#![doc = include_str!("../README.md")]
3#![cfg_attr(not(docsrs), cfg(feature = "base0"))]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6extern crate self as rust_query;
7
8#[macro_use]
9extern crate static_assertions;
10
11#[cfg(doc)]
12#[doc = include_str!("_guide.md")]
13pub mod _guide {}
14// mod ast;
15mod async_db;
16mod db;
17mod error;
18mod joinable;
19mod lazy;
20mod lower;
21mod migrate;
22mod mutable;
23#[cfg(feature = "__mutants")]
24mod mutants;
25mod pool;
26mod query;
27mod rows;
28mod schema;
29mod scoped_transaction;
30mod select;
31mod transaction;
32mod value;
33mod writable;
34
35use private::Reader;
36use schema::from_macro::TypBuilder;
37use std::fmt::Debug;
38use std::ops::Deref;
39
40pub use async_db::DatabaseAsync;
41pub use db::TableRow;
42pub use error::Conflict;
43pub use lazy::Lazy;
44pub use mutable::Mutable;
45pub use scoped_transaction::TransactionScope;
46pub use select::{IntoSelect, Select};
47pub use transaction::{Database, Transaction, TransactionWeak};
48pub use value::aggregate::aggregate;
49pub use value::from_expr::FromExpr;
50pub use value::{Expr, into_expr::IntoExpr, optional::optional};
51
52/// Derive [derive@Select] to create a new `*Select` struct.
53///
54/// This `*Select` struct will implement the [IntoSelect] trait and can be used
55/// with [args::Query::into_iter], [Transaction::query_one] etc.
56///
57/// Usage can also be nested.
58///
59/// ```
60/// #[rust_query::migration::schema(Schema)]
61/// pub mod vN {
62///     pub struct Thing {
63///         pub details: rust_query::TableRow<Details>,
64///         pub beta: f64,
65///         pub seconds: i64,
66///     }
67///     pub struct Details {
68///         pub name: String,
69///     }
70/// }
71/// use v0::*;
72/// use rust_query::{Table, Select, Transaction};
73///
74/// #[derive(Select)]
75/// struct MyData {
76///     seconds: i64,
77///     is_it_real: bool,
78///     name: String,
79///     other: OtherData
80/// }
81///
82/// #[derive(Select)]
83/// struct OtherData {
84///     alpha: f64,
85///     beta: f64,
86/// }
87///
88/// fn do_query(db: &Transaction<Schema>) -> Vec<MyData> {
89///     db.query(|rows| {
90///         let thing = rows.join(Thing);
91///
92///         rows.into_vec(MyDataSelect {
93///             seconds: &thing.seconds,
94///             is_it_real: thing.seconds.lt(100),
95///             name: &thing.details.name,
96///             other: OtherDataSelect {
97///                 alpha: thing.beta.add(2.0),
98///                 beta: &thing.beta,
99///             },
100///         })
101///     })
102/// }
103/// # fn main() {}
104/// ```
105pub use rust_query_macros::Select;
106
107/// Use in combination with `#[rust_query(From = Thing)]` to specify which tables
108/// this struct should implement [trait@FromExpr] for.
109///
110/// The implementation of [trait@FromExpr] will initialize every field from the column with
111/// the corresponding name. It is also possible to change the type of each field
112/// as long as the new field type implements [trait@FromExpr].
113///
114/// ```
115/// # use rust_query::migration::schema;
116/// # use rust_query::{TableRow, FromExpr};
117/// #[schema(Example)]
118/// pub mod vN {
119///     pub struct User {
120///         pub name: String,
121///         pub score: i64,
122///         pub best_game: Option<rust_query::TableRow<Game>>,
123///     }
124///     pub struct Game;
125/// }
126///
127/// #[derive(FromExpr)]
128/// #[rust_query(From = v0::User)]
129/// struct MyUserFields {
130///     name: String,
131///     best_game: Option<TableRow<v0::Game>>,
132/// }
133/// # fn main() {}
134/// ```
135pub use rust_query_macros::FromExpr;
136
137use crate::error::FromConflict;
138
139/// Types that are used as closure arguments.
140///
141/// You generally don't need to import these types.
142pub mod args {
143    pub use crate::query::{OrderBy, Query};
144    pub use crate::rows::Rows;
145    pub use crate::value::aggregate::Aggregate;
146    pub use crate::value::optional::Optional;
147}
148
149/// Types to declare schemas and migrations.
150///
151/// A good starting point is too look at [crate::migration::schema].
152pub mod migration {
153    pub use crate::migrate::{
154        Migrator,
155        config::{Config, ForeignKeys, Synchronous},
156        migration::{Migrated, MigratedOptional, TransactionMigrate},
157    };
158    #[cfg(feature = "dev")]
159    pub use crate::schema::dev::hash_schema;
160
161    #[doc = include_str!("schema/_schema.md")]
162    pub use rust_query_macros::schema;
163}
164
165/// These items are only exposed for use by the proc macros.
166/// Direct use is unsupported.
167#[doc(hidden)]
168pub mod private {
169
170    pub use crate::joinable::{IntoJoinable, Joinable};
171    pub use crate::migrate::{
172        Schema, SchemaMigration, TableTypBuilder,
173        migration::{Migrateable, SchemaBuilder},
174        with_test_renderer,
175    };
176    pub use crate::query::get_plan;
177    pub use crate::schema::from_macro::{SchemaType, TypBuilder};
178    pub use crate::schema::tokenizer::{Token, get_token};
179    pub use crate::value::{DbTyp, adhoc_expr, new_column, unique_from_joinable};
180    pub use crate::writable::Reader;
181
182    // pub trait Apply {
183    //     type Out<T: MigrateTyp>;
184    // }
185
186    // pub struct AsNormal;
187    // impl Apply for AsNormal {
188    //     type Out<T: MigrateTyp> = T;
189    // }
190
191    // struct AsExpr<'x, S>(PhantomData<(&'x (), S)>);
192    // impl<'x, S> Apply for AsExpr<'x, S> {
193    //     type Out<T: MigrateTyp> = crate::Expr<'x, S, T::ExprTyp>;
194    // }
195
196    // struct AsLazy<'x>(PhantomData<&'x ()>);
197    // impl<'x> Apply for AsLazy<'x> {
198    //     type Out<T: MigrateTyp> = T::Lazy<'x>;
199    // }
200
201    pub mod doctest_aggregate {
202        #[crate::migration::schema(M)]
203        pub mod vN {
204            pub struct Val {
205                pub x: i64,
206            }
207        }
208        pub use crate::aggregate;
209        pub use v0::*;
210
211        #[cfg_attr(false, mutants::skip)]
212        pub fn get_txn(f: impl Send + FnOnce(&mut crate::Transaction<M>)) {
213            crate::Database::new(rust_query::migration::Config::open_in_memory())
214                .transaction_mut_ok(f)
215        }
216    }
217
218    pub mod doctest {
219        use crate::{Database, Transaction, migrate::config::Config, migration};
220
221        #[migration::schema(Empty)]
222        pub mod vN {
223            pub struct User {
224                #[unique]
225                pub name: String,
226            }
227        }
228        pub use v0::*;
229
230        #[cfg_attr(false, mutants::skip)]
231        pub fn get_txn(f: impl Send + FnOnce(&'static mut Transaction<Empty>)) {
232            let db = Database::new(Config::open_in_memory());
233            db.transaction_mut_ok(|txn| {
234                txn.insert(User {
235                    name: "Alice".to_owned(),
236                })
237                .unwrap();
238                f(txn)
239            })
240        }
241    }
242}
243
244/// This trait is implemented for all table types as generated by the [crate::migration::schema] macro.
245///
246/// **You can not implement this trait yourself!**
247pub trait Table: Sized + 'static {
248    #[doc(hidden)]
249    type Ext2<'t>;
250
251    #[doc(hidden)]
252    fn covariant_ext<'x, 't>(val: &'x Self::Ext2<'static>) -> &'x Self::Ext2<'t>;
253
254    #[doc(hidden)]
255    fn build_ext2<'t>(val: &Expr<'t, Self::Schema, TableRow<Self>>) -> Self::Ext2<'t>;
256
257    /// The schema that this table is a part of.
258    type Schema;
259
260    #[doc(hidden)]
261    /// The table that this table can be migrated from.
262    type MigrateFrom: Table;
263
264    /// The type of conflict that can result from inserting a row in this table.
265    /// This is the same type that is used for row updates too.
266    type Conflict: FromConflict + Debug;
267    /// The type of error when a delete fails due to a foreign key constraint.
268    type Referer;
269
270    #[doc(hidden)]
271    type Mutable: Deref;
272    #[doc(hidden)]
273    type Lazy<'t>;
274
275    #[doc(hidden)]
276    fn read(&self, f: &mut Reader);
277
278    #[doc(hidden)]
279    type Select;
280
281    #[doc(hidden)]
282    fn into_select(
283        val: Expr<'_, Self::Schema, TableRow<Self>>,
284    ) -> Select<'_, Self::Schema, Self::Select>;
285
286    #[doc(hidden)]
287    fn select_mutable(select: Self::Select) -> Self::Mutable;
288
289    #[doc(hidden)]
290    fn select_lazy<'t>(select: Self::Select) -> Self::Lazy<'t>;
291
292    #[doc(hidden)]
293    fn mutable_as_unique(val: &mut Self::Mutable) -> &mut <Self::Mutable as Deref>::Target;
294
295    #[doc(hidden)]
296    fn mutable_into_insert(val: Self::Mutable) -> Self
297    where
298        Self: Sized;
299
300    #[doc(hidden)]
301    fn get_referer_unchecked() -> Self::Referer;
302
303    #[doc(hidden)]
304    fn typs(f: &mut TypBuilder<Self::Schema>);
305
306    #[doc(hidden)]
307    const SPAN: (usize, usize);
308
309    #[doc(hidden)]
310    const ID: &'static str;
311    #[doc(hidden)]
312    const NAME: &'static str;
313}
314
315#[test]
316#[cfg(feature = "jiff-02")]
317fn compile_tests() {
318    let t = trybuild::TestCases::new();
319    t.compile_fail("tests/compile/*.rs");
320}