coven_merge/
audience_sql.rs1use crate::Audience;
5use coven_foundation::id_source::CircleId;
6use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, Value, ValueRef};
7use rusqlite::ToSql;
8
9impl std::fmt::Display for Audience {
10 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11 match self {
12 Self::Store => f.write_str("store"),
13 Self::Circle(circle) => std::fmt::Display::fmt(circle, f),
14 }
15 }
16}
17
18impl std::str::FromStr for Audience {
19 type Err = InvalidAudience;
20 fn from_str(text: &str) -> Result<Self, Self::Err> {
23 if text == "store" {
24 return Ok(Self::Store);
25 }
26 coven_foundation::id_source::canonical_uuid(text)
27 .map(|id| Self::Circle(CircleId(id)))
28 .map_err(|_not_canonical| InvalidAudience)
29 }
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
34#[error("not an audience: `store` or a circle's canonical id")]
35pub struct InvalidAudience;
36
37impl From<&Audience> for Value {
38 fn from(audience: &Audience) -> Self {
39 Self::Text(audience.to_string())
40 }
41}
42
43impl ToSql for Audience {
44 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
45 Ok(ToSqlOutput::Owned(self.into()))
46 }
47}
48
49impl FromSql for Audience {
50 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
51 value.as_str()?.parse().map_err(|error| FromSqlError::Other(Box::new(error)))
52 }
53}
54
55#[cfg(test)]
56#[path = "audience_sql_tests.rs"]
57mod tests;