#[derive(Debug, Clone, Copy)]
pub struct Comments;
#[derive(Debug, Clone, PartialEq)]
pub struct Comment {
pub id: i32,
pub post_id: i32,
pub user_id: Option<i32>,
pub body: String,
pub created_at: chrono::NaiveDateTime,
pub rel: Rel,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Rel {
pub post: Option<Box<super::posts::Post>>,
pub user: Option<Box<super::users::User>>,
}
impl keelson_exec::FromRow for Comment {
fn from_row(row: &mut keelson_exec::Row) -> Result<Self, keelson_exec::ExecError> {
Ok(Comment {
id: row.take("id")?,
post_id: row.take("post_id")?,
user_id: row.take("user_id")?,
body: row.take("body")?,
created_at: row.take("created_at")?,
rel: Rel::default(),
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Setter {
pub id: keelson_models::Set<i32>,
pub post_id: keelson_models::Set<i32>,
pub user_id: keelson_models::Set<i32>,
pub body: keelson_models::Set<String>,
pub created_at: keelson_models::Set<chrono::NaiveDateTime>,
}
pub fn table() -> Comments {
Comments
}
pub fn id() -> keelson_models::Column<i32> {
keelson_models::Column::new("comments", "id")
}
pub fn post_id() -> keelson_models::Column<i32> {
keelson_models::Column::new("comments", "post_id")
}
pub fn user_id() -> keelson_models::Column<i32> {
keelson_models::Column::new("comments", "user_id")
}
pub fn body() -> keelson_models::Column<String> {
keelson_models::Column::new("comments", "body")
}
pub fn created_at() -> keelson_models::Column<chrono::NaiveDateTime> {
keelson_models::Column::new("comments", "created_at")
}
#[allow(clippy::type_complexity)]
fn all_columns() -> (
keelson_models::Column<i32>,
keelson_models::Column<i32>,
keelson_models::Column<i32>,
keelson_models::Column<String>,
keelson_models::Column<chrono::NaiveDateTime>,
) {
(id(), post_id(), user_id(), body(), created_at())
}
impl keelson_models::View for Comments {
type Row = Comment;
type Select = keelson_mysql::SelectQuery;
fn base_select() -> Self::Select {
keelson_mysql::select((
keelson_mysql::select::columns(all_columns()),
keelson_mysql::select::from(keelson_mysql::quote("comments")),
))
}
}
impl keelson_models::Table for Comments {
type Pk = i32;
type Setter = Setter;
type Insert = keelson_mysql::InsertQuery;
type Update = keelson_mysql::UpdateQuery;
type Delete = keelson_mysql::DeleteQuery;
fn insert_query(s: Setter) -> Self::Insert {
let mut cols: Vec<&'static str> = Vec::new();
let mut vals: Vec<keelson_core::expr::Expr> = Vec::new();
s.id.push_into("id", &mut cols, &mut vals);
s.post_id.push_into("post_id", &mut cols, &mut vals);
s.user_id.push_into("user_id", &mut cols, &mut vals);
s.body.push_into("body", &mut cols, &mut vals);
s.created_at.push_into("created_at", &mut cols, &mut vals);
let mut q = keelson_mysql::insert(
keelson_mysql::insert::into(keelson_mysql::quote("comments")).columns(cols),
);
if !vals.is_empty() {
q.apply(keelson_mysql::insert::values(vals));
}
q
}
fn update_query() -> Self::Update {
keelson_mysql::update(
keelson_mysql::update::table(keelson_mysql::quote("comments")),
)
}
fn apply_setter(s: Setter, q: &mut Self::Update) {
if let Some(v) = s.id.into_expr() {
q.apply(keelson_mysql::update::set_col("id").to(v));
}
if let Some(v) = s.post_id.into_expr() {
q.apply(keelson_mysql::update::set_col("post_id").to(v));
}
if let Some(v) = s.user_id.into_expr() {
q.apply(keelson_mysql::update::set_col("user_id").to(v));
}
if let Some(v) = s.body.into_expr() {
q.apply(keelson_mysql::update::set_col("body").to(v));
}
if let Some(v) = s.created_at.into_expr() {
q.apply(keelson_mysql::update::set_col("created_at").to(v));
}
}
fn delete_query() -> Self::Delete {
keelson_mysql::delete(
keelson_mysql::delete::from(keelson_mysql::quote("comments")),
)
}
fn pk(row: &Comment) -> Self::Pk {
row.id
}
}
impl Comments {
pub fn query(
self,
mods: impl keelson_core::Mod<keelson_models::ModelSelect<Comments>>,
) -> keelson_models::ModelSelect<Comments> {
keelson_models::ModelTable::<Comments>::new().query(mods)
}
pub fn insert(self, setter: Setter) -> Insert {
Insert { setter, mods: Vec::new() }
}
pub fn update(
self,
setter: Setter,
mods: impl keelson_core::Mod<keelson_models::ModelUpdate<Comments>>,
) -> Update {
Update(keelson_models::ModelTable::<Comments>::new().update(setter, mods))
}
pub fn delete(
self,
mods: impl keelson_core::Mod<keelson_models::ModelDelete<Comments>>,
) -> Delete {
Delete(keelson_models::ModelTable::<Comments>::new().delete(mods))
}
}
pub struct Insert {
setter: Setter,
#[allow(clippy::type_complexity)]
mods: Vec<Box<dyn FnOnce(&mut keelson_mysql::InsertQuery) + Send>>,
}
impl std::fmt::Debug for Insert {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Insert")
.field("setter", &self.setter)
.field("mods", &self.mods.len())
.finish()
}
}
impl Insert {
#[must_use]
pub fn with(
mut self,
mods: impl keelson_core::Mod<keelson_mysql::InsertQuery> + Send + 'static,
) -> Self {
self.mods.push(Box::new(move |q| mods.apply(q)));
self
}
pub async fn one(
self,
db: &dyn keelson_exec::Executor,
) -> Result<Comment, keelson_exec::ExecError> {
use keelson_exec::Execute as _;
let Insert { mut setter, mods } = self;
<Comments as keelson_models::Table>::before_insert(db, &mut setter).await?;
let k0 = match &setter.id {
keelson_models::Set::Value(v) => Some(*v),
_ => None,
};
let mut q = <Comments as keelson_models::Table>::insert_query(setter);
for m in mods {
m(&mut q);
}
let done = q.execute(db).await?;
let k0: i32 = k0
.or_else(|| {
done
.last_insert_id
.and_then(|id| {
<i32 as std::convert::TryFrom<i64>>::try_from(id).ok()
})
})
.ok_or_else(|| keelson_exec::ExecError::other(
"comments: the INSERT set no `id` and MySQL reported no last_insert_id, so the inserted row cannot be read back",
))?;
let row: Comment = by_pk(k0).fetch_one(db).await?;
<Comments as keelson_models::Table>::after_insert(db, std::slice::from_ref(&row))
.await?;
Ok(row)
}
pub async fn exec(
self,
db: &dyn keelson_exec::Executor,
) -> Result<keelson_exec::ExecResult, keelson_exec::ExecError> {
use keelson_exec::Execute as _;
let Insert { mut setter, mods } = self;
<Comments as keelson_models::Table>::before_insert(db, &mut setter).await?;
let mut q = <Comments as keelson_models::Table>::insert_query(setter);
for m in mods {
m(&mut q);
}
let done = q.execute(db).await?;
<Comments as keelson_models::Table>::after_insert(db, &[]).await?;
Ok(done)
}
}
pub fn by_pk(k0: i32) -> keelson_mysql::SelectQuery {
keelson_mysql::select((
keelson_mysql::select::columns(all_columns()),
keelson_mysql::select::from(keelson_mysql::quote("comments")),
id().eq(k0),
))
}
#[derive(Debug)]
pub struct Update(keelson_models::ModelUpdate<Comments>);
impl Update {
pub fn apply(&mut self, mods: impl keelson_core::Mod<keelson_mysql::UpdateQuery>) {
self.0.apply(mods);
}
pub async fn exec(
self,
db: &dyn keelson_exec::Executor,
) -> Result<keelson_exec::ExecResult, keelson_exec::ExecError> {
self.0.exec(db).await
}
}
#[derive(Debug)]
pub struct Delete(keelson_models::ModelDelete<Comments>);
impl Delete {
pub fn apply(&mut self, mods: impl keelson_core::Mod<keelson_mysql::DeleteQuery>) {
self.0.apply(mods);
}
pub async fn exec(
self,
db: &dyn keelson_exec::Executor,
) -> Result<keelson_exec::ExecResult, keelson_exec::ExecError> {
self.0.exec(db).await
}
}
pub mod preload {
pub fn post() -> impl keelson_core::Mod<
keelson_models::ModelSelect<super::Comments>,
> {
keelson_core::mod_fn(|q: &mut keelson_models::ModelSelect<super::Comments>| {
use keelson_mysql::Chain as _;
use keelson_mysql::Mod as _;
(
keelson_mysql::select::left_join(keelson_mysql::quote("posts"))
.on(
keelson_mysql::quote(("posts", "id"))
.eq(keelson_mysql::quote(("comments", "post_id"))),
),
keelson_mysql::select::preload_columns((
keelson_mysql::quote(("posts", "id")).as_("post.id"),
keelson_mysql::quote(("posts", "user_id")).as_("post.user_id"),
keelson_mysql::quote(("posts", "title")).as_("post.title"),
keelson_mysql::quote(("posts", "status")).as_("post.status"),
keelson_mysql::quote(("posts", "views")).as_("post.views"),
keelson_mysql::quote(("posts", "published_at"))
.as_("post.published_at"),
)),
)
.apply(q);
q.add_mapper_mod(
keelson_models::mapper_mod(|row, parent: &mut super::Comment| {
parent.rel.post = post_from_preload(row)?.map(Box::new);
Ok(())
}),
);
})
}
pub fn post_from_preload(
row: &mut keelson_exec::Row,
) -> Result<Option<super::super::posts::Post>, keelson_exec::ExecError> {
if matches!(row.value("post.id"), None | Some(keelson_mysql::Value::Null)) {
return Ok(None);
}
Ok(
Some(super::super::posts::Post {
id: row.take("post.id")?,
user_id: row.take("post.user_id")?,
title: row.take("post.title")?,
status: row.take("post.status")?,
views: row.take("post.views")?,
published_at: row.take("post.published_at")?,
rel: super::super::posts::Rel::default(),
}),
)
}
pub fn user() -> impl keelson_core::Mod<
keelson_models::ModelSelect<super::Comments>,
> {
keelson_core::mod_fn(|q: &mut keelson_models::ModelSelect<super::Comments>| {
use keelson_mysql::Chain as _;
use keelson_mysql::Mod as _;
(
keelson_mysql::select::left_join(keelson_mysql::quote("users"))
.on(
keelson_mysql::quote(("users", "id"))
.eq(keelson_mysql::quote(("comments", "user_id"))),
),
keelson_mysql::select::preload_columns((
keelson_mysql::quote(("users", "id")).as_("user.id"),
keelson_mysql::quote(("users", "name")).as_("user.name"),
keelson_mysql::quote(("users", "email")).as_("user.email"),
keelson_mysql::quote(("users", "age")).as_("user.age"),
keelson_mysql::quote(("users", "is_active")).as_("user.is_active"),
keelson_mysql::quote(("users", "created_at")).as_("user.created_at"),
)),
)
.apply(q);
q.add_mapper_mod(
keelson_models::mapper_mod(|row, parent: &mut super::Comment| {
parent.rel.user = user_from_preload(row)?.map(Box::new);
Ok(())
}),
);
})
}
pub fn user_from_preload(
row: &mut keelson_exec::Row,
) -> Result<Option<super::super::users::User>, keelson_exec::ExecError> {
if matches!(row.value("user.id"), None | Some(keelson_mysql::Value::Null)) {
return Ok(None);
}
Ok(
Some(super::super::users::User {
id: row.take("user.id")?,
name: row.take("user.name")?,
email: row.take("user.email")?,
age: row.take("user.age")?,
is_active: row.take("user.is_active")?,
created_at: row.take("user.created_at")?,
rel: super::super::users::Rel::default(),
}),
)
}
}
pub mod then_load {
pub fn post() -> keelson_models::ThenLoad<
super::Comments,
super::super::posts::Posts,
i32,
> {
keelson_models::ThenLoad::new(
|rows: &[super::Comment]| rows.iter().map(|r| r.post_id).collect(),
|keys, q| keelson_core::Mod::apply(super::super::posts::id().in_(keys), q),
|rows: &mut [super::Comment], related| {
keelson_models::attach_to_one(
rows,
related,
|r| r.post_id,
|c| c.id,
|r, c| {
r.rel.post = c.map(Box::new);
},
);
},
)
}
pub fn user() -> keelson_models::ThenLoad<
super::Comments,
super::super::users::Users,
i32,
> {
keelson_models::ThenLoad::new(
|rows: &[super::Comment]| rows.iter().filter_map(|r| r.user_id).collect(),
|keys, q| keelson_core::Mod::apply(super::super::users::id().in_(keys), q),
|rows: &mut [super::Comment], related| {
keelson_models::attach_to_one(
rows,
related,
|r| r.user_id,
|c| Some(c.id),
|r, c| {
r.rel.user = c.map(Box::new);
},
);
},
)
}
}