turso_orm/query/
update.rs1use std::marker::PhantomData;
13
14use turso_orm_driver::ConnectionTrait;
15use turso_sql::{Build, Expr, IntoCondition, Returning, Statement, Value};
16
17use crate::entity::{
18 ActiveModelTrait, ActiveValue, EntityTrait, FromQueryResult, IdenStatic, Iterable,
19};
20use crate::query::select::pk_condition;
21use crate::{DbErr, Result};
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub struct UpdateResult {
26 pub rows_affected: u64,
28}
29
30#[derive(Clone, Debug)]
32pub struct UpdateOne<A: ActiveModelTrait> {
33 model: A,
35}
36
37impl<A: ActiveModelTrait> UpdateOne<A> {
38 pub(crate) fn new(model: A) -> Self {
40 Self { model }
41 }
42
43 fn statement(&self) -> Result<Option<turso_sql::Update>> {
49 let pk = self
50 .model
51 .get_primary_key_value()
52 .ok_or(DbErr::PrimaryKeyNotSet)?;
53 let mut update = turso_sql::Query::update().table(<A::Entity as EntityTrait>::TABLE_NAME);
54 let mut any = false;
55 for c in <<A::Entity as EntityTrait>::Column as Iterable>::iter() {
56 if let ActiveValue::Set(v) = self.model.get(c) {
57 update = update.value(c.as_str(), Expr::val(v));
58 any = true;
59 }
60 }
61 if !any {
62 return Ok(None);
63 }
64 update = update
65 .and_where(pk_condition::<A::Entity>(pk))
66 .returning(Returning::All);
67 Ok(Some(update))
68 }
69
70 pub async fn exec<C: ConnectionTrait>(
82 self,
83 db: &C,
84 ) -> Result<<A::Entity as EntityTrait>::Model> {
85 if let Some(update) = self.statement()? {
86 let row = db
87 .query_one(update.to_statement())
88 .await?
89 .ok_or(DbErr::RecordNotUpdated)?;
90 <A::Entity as EntityTrait>::Model::from_query_result(&row, "")
91 } else {
92 let pk = self
93 .model
94 .get_primary_key_value()
95 .ok_or(DbErr::PrimaryKeyNotSet)?;
96 crate::query::Select::<A::Entity>::new()
97 .filter_by_pk(pk)
98 .one(db)
99 .await?
100 .ok_or(DbErr::RecordNotUpdated)
101 }
102 }
103}
104
105#[derive(Clone, Debug)]
107pub struct UpdateMany<E: EntityTrait> {
108 query: turso_sql::Update,
110 _e: PhantomData<E>,
112}
113
114impl<E: EntityTrait> UpdateMany<E> {
115 pub(crate) fn new() -> Self {
117 Self {
118 query: turso_sql::Query::update().table(E::TABLE_NAME),
119 _e: PhantomData,
120 }
121 }
122
123 #[must_use]
125 pub fn col_expr(mut self, column: E::Column, value: impl Into<Expr>) -> Self {
126 self.query = self.query.value(column.as_str(), value);
127 self
128 }
129
130 #[must_use]
132 pub fn col(self, column: E::Column, value: impl Into<Value>) -> Self {
133 self.col_expr(column, Expr::val(value))
134 }
135
136 #[must_use]
138 pub fn set<A: ActiveModelTrait<Entity = E>>(mut self, model: &A) -> Self {
139 for c in E::Column::iter() {
140 if let ActiveValue::Set(v) = model.get(c) {
141 self.query = self.query.value(c.as_str(), Expr::val(v));
142 }
143 }
144 self
145 }
146
147 #[must_use]
149 pub fn filter(mut self, cond: impl IntoCondition) -> Self {
150 self.query = self.query.and_where(cond);
151 self
152 }
153
154 pub fn build(&self) -> Statement {
156 self.query.to_statement()
157 }
158
159 pub async fn exec<C: ConnectionTrait>(self, db: &C) -> Result<UpdateResult> {
165 if !self.query.has_sets() {
166 return Ok(UpdateResult { rows_affected: 0 });
167 }
168 let result = db.execute(self.build()).await?;
169 Ok(UpdateResult {
170 rows_affected: result.rows_affected,
171 })
172 }
173
174 pub async fn exec_with_returning<C: ConnectionTrait>(
183 mut self,
184 db: &C,
185 ) -> Result<Vec<E::Model>> {
186 if !self.query.has_sets() {
187 return Ok(Vec::new());
188 }
189 self.query = self.query.returning(Returning::All);
190 db.query_all(self.build())
191 .await?
192 .iter()
193 .map(|r| E::Model::from_query_result(r, ""))
194 .collect()
195 }
196}