ormlitex_core/model.rs
1/// A model is a struct that represents a row in a relational database table.
2/// Using the `[derive(ormlitex::Model)]` macro, it will acquire the following traits:
3///
4/// - `ormlitex::Model`, giving it direct database access, e.g. `insert`, `update_all_fields`, etc.
5/// - `ormlitex::HasModelBuilder`, letting it build partials, so you can insert or update some
6/// fields instead of all of them at once, e.g. `model.name("John").update()`
7/// - `ormlitex::TableMeta`, which you typically don't use directly, but provides table metadata
8/// (e.g. table name)
9///
10use crate::Result;
11use crate::SelectQueryBuilder;
12use futures::future::BoxFuture;
13
14/// A struct that is `Insertable` is expected to have same fields as the model, excluding fields
15/// that have sane defaults at the database level. Concretely, if you have a Person struct:
16/// #[derive(ormlitex::Model)]
17/// struct Person {
18/// id: i32,
19/// name: String,
20/// age: i32,
21/// }
22///
23/// Then the `Insertable` struct looks like:
24/// struct InsertPerson {
25/// name: String,
26/// age: i32,
27/// }
28pub trait Insertable<DB>
29 where
30 Self: Sized + Send + Sync,
31 DB: sqlx::Database,
32{
33 type Model;
34 fn insert<'e, A>(self, conn: A) -> BoxFuture<'e, Result<Self::Model>>
35 where
36 A: 'e + Send + sqlx::Acquire<'e, Database=DB>;
37}
38
39/// A struct that implements `ModelBuilder` implements the builder pattern for a model.
40pub trait ModelBuilder<'a, DB>
41 where
42 Self: Sized + Send + Sync,
43 DB: sqlx::Database,
44{
45 type Model;
46
47 fn insert<'e: 'a, E>(self, db: E) -> BoxFuture<'a, Result<Self::Model>>
48 where
49 E: 'e + sqlx::Executor<'e, Database=DB>;
50
51 fn update<'e: 'a, E>(self, db: E) -> BoxFuture<'a, Result<Self::Model>>
52 where
53 E: 'e + sqlx::Executor<'e, Database=DB>;
54
55 /// Build the model, don't insert or update it.
56 fn build(self) -> Self::Model;
57}
58
59pub trait HasModelBuilder<'slf, DB>
60 where
61 DB: sqlx::Database,
62 Self: Sized + TableMeta,
63{
64 type ModelBuilder: ModelBuilder<'slf, DB>;
65
66 /// Create a builder-pattern object to update one or more columns.
67 /// You can also use `update_all_fields` to update all columns.
68 fn update_partial(&'slf self) -> Self::ModelBuilder;
69
70 fn builder() -> Self::ModelBuilder;
71}
72
73/// The core trait. a struct that implements `Model` can also implement `HasModelBuilder`, (and is required to implement `Insertable`)
74pub trait Model<DB>
75 where
76 DB: sqlx::Database,
77 Self: Sized + TableMeta,
78{
79 /// Insert the model into the database.
80 fn insert<'a, A>(self, conn: A) -> crate::insert::Insertion<'a, A, Self, DB>
81 where
82 A: 'a + Send + sqlx::Acquire<'a, Database=DB>,
83 Self: Send;
84
85 /// `Model` objects can't track what fields are updated, so this method will update all fields.
86 /// If you want to update only some fields, use `update_partial` instead.
87 fn update_all_fields<'e, E>(self, db: E) -> BoxFuture<'e, Result<Self>>
88 where
89 E: 'e + Send + sqlx::Executor<'e, Database=DB>;
90
91 fn delete<'e, E>(self, db: E) -> BoxFuture<'e, Result<()>>
92 where
93 E: 'e + sqlx::Executor<'e, Database=DB>;
94
95 /// Get by primary key.
96 fn fetch_one<'e, 'a, Arg, E>(id: Arg, db: E) -> BoxFuture<'e, Result<Self>>
97 where
98 'a: 'e,
99 E: 'e + sqlx::Executor<'e, Database=DB>,
100 Arg: 'a + Send + sqlx::Encode<'a, DB> + sqlx::Type<DB>;
101
102 /// If query building isn't meeting your needs, use this method to query the table using raw SQL.
103 fn query(
104 query: &str,
105 ) -> sqlx::query::QueryAs<DB, Self, <DB as sqlx::database::HasArguments>::Arguments>;
106
107 /// Create a `SelectQueryBuilder` to build a query.
108 fn select<'args>() -> SelectQueryBuilder<'args, DB, Self>;
109}
110
111pub trait TableMeta {
112 fn table_name() -> &'static str;
113 fn table_columns() -> &'static [&'static str];
114 fn primary_key() -> Option<&'static str>;
115}