Experiments in applying Entity-Component-System patterns to durable data storage APIs.
1use tracing::warn;
2
3use crate::{component, Component};
4
5#[derive(Debug)]
6pub struct DynComponent<'a>(
7 pub(crate) &'a str,
8 pub(crate) rusqlite::types::ToSqlOutput<'a>,
9);
10
11impl<'a> DynComponent<'a> {
12 pub fn name(&'a self) -> &'a str {
13 self.0
14 }
15
16 pub fn into_typed<C: Component>(self) -> Result<C, component::StorageError> {
17 C::from_rusqlite(&self.1)
18 }
19
20 pub fn as_typed<C: Component>(&self) -> Result<C, component::StorageError> {
21 C::from_rusqlite(&self.1)
22 }
23
24 pub fn from_typed<C: Component + 'a>(c: &'a C) -> Result<Self, component::StorageError> {
25 Ok(Self(C::component_name(), C::to_rusqlite(c)?))
26 }
27
28 pub fn as_json(&self) -> Option<serde_json::value::Value> {
29 use rusqlite::types::{ToSqlOutput, Value, ValueRef};
30
31 match self.1 {
32 ToSqlOutput::Borrowed(ValueRef::Text(s)) => serde_json::from_slice(s).ok(),
33 ToSqlOutput::Owned(Value::Text(ref s)) => serde_json::from_slice(s.as_bytes()).ok(),
34 ToSqlOutput::Owned(Value::Null) | ToSqlOutput::Borrowed(ValueRef::Null) => {
35 Some(serde_json::Value::Null)
36 }
37 ToSqlOutput::Owned(ref o) => {
38 warn!(r#type = ?o.data_type(), "DynComponent::as_json unsupported");
39 None
40 }
41 ToSqlOutput::Borrowed(ref b) => {
42 warn!(r#type = ?b.data_type(), "DynComponent::as_json unsupported");
43 None
44 }
45 ref x => {
46 warn!(value = ?x, "DynComponent::as_json unsupported");
47 None
48 }
49 }
50 }
51}