# fn delete
If you are using Event Sourcing we assume you believe in immutability and keeping a long term audit history.
Deleting data from the Database goes against these principles.
Therefore `es-entity` does not provide a way to actually delete data.
It is however possible to configure a soft delete option by marking `delete = soft` on the `EsRepo`.
This will omit entities that have been flagged as deleted from all queries,
and also generate `_include_deleted` query variants:
```rust,ignore
fn find_by_<column>_include_deleted
fn maybe_find_by_<column>_include_deleted
fn list_by_<column>_include_deleted
fn list_for_<column>_by_<cursor>_include_deleted
```
If you don't need the `_include_deleted` query variants, use `delete = "soft_without_queries"` instead:
```rust,ignore
#[es_repo(entity = "User", columns(name = "String"), delete = "soft_without_queries")]
```
As a prerequisite the `index` table must include a `deleted` column:
```sql
CREATE TABLE users (
id UUID PRIMARY KEY,
name VARCHAR NOT NULL,
-- deleted will be set to 'TRUE' when `delete` is called.
deleted BOOL DEFAULT false,
created_at TIMESTAMPTZ NOT NULL
);
```
```rust
# extern crate es_entity;
# extern crate sqlx;
# extern crate serde;
# extern crate tokio;
# extern crate anyhow;
# use serde::{Deserialize, Serialize};
# es_entity::entity_id! { UserId }
# impl IntoEvents<UserEvent> for NewUser {
# fn into_events(self) -> EntityEvents<UserEvent> {
# EntityEvents::init(
# self.id,
# [UserEvent::Initialized {
# id: self.id,
# name: self.name,
# }],
# )
# }
# }
# impl TryFromEvents<UserEvent> for User {
# fn try_from_events(events: EntityEvents<UserEvent>) -> Result<Self, EntityHydrationError> {
# Ok(User { id: events.id().clone(), name: "Delyth".to_string(), events })
# }
# }
# pub struct NewUser { id: UserId, name: String }
use es_entity::*;
#[derive(EsEvent, Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[es_event(id = "UserId")]
pub enum UserEvent {
Initialized { id: UserId, name: String },
Deleted
}
#[derive(EsEntity)]
pub struct User {
pub id: UserId,
name: String,
events: EntityEvents<UserEvent>,
}
impl User {
fn delete(&mut self) -> Idempotent<()> {
idempotency_guard!(
self.events.iter_all(),
already_applied: UserEvent::Deleted
);
self.events.push(UserEvent::Deleted);
Idempotent::Executed(())
}
}
#[derive(EsRepo)]
#[es_repo(
entity = "User",
columns(name = "String"),
delete = "soft",
)]
pub struct Users {
pool: sqlx::PgPool
}
# async fn init_pool() -> anyhow::Result<sqlx::PgPool> {
# let pg_con = format!("postgres://user:password@localhost:5432/pg");
# Ok(sqlx::PgPool::connect(&pg_con).await?)
# }
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let users = Users { pool: init_pool().await? };
let new_user = NewUser { id: UserId::new(), name: "Delyth".to_string() };
let mut user = users.create(new_user).await?;
let found_user = users.maybe_find_by_name("Delyth").await?;
assert!(found_user.is_some());
if user.delete().did_execute() {
users.delete(user).await?;
}
let found_user = users.maybe_find_by_name("Delyth").await?;
assert!(found_user.is_none());
let found_user = users.maybe_find_by_name_include_deleted("Delyth").await?;
assert!(found_user.is_some());
# sqlx::query!(r#"
# WITH deleted_users AS (
# DELETE FROM user_events
# WHERE id IN (SELECT id FROM users WHERE deleted = true)
# RETURNING id
# )
# DELETE FROM users WHERE deleted = true"#
# ).execute(users.pool()).await?;
Ok(())
}
```