Skip to main content

valence_core/
connection.rs

1//! Connection cardinality, delete semantics, and id helpers for generated models.
2
3use std::fmt;
4
5use crate::error::{Error, Result};
6use crate::RecordId;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Cardinality {
10    HasOne,
11    HasMany,
12    ManyToMany,
13}
14
15impl fmt::Display for Cardinality {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        match self {
18            Cardinality::HasOne => write!(f, "HasOne"),
19            Cardinality::HasMany => write!(f, "HasMany"),
20            Cardinality::ManyToMany => write!(f, "ManyToMany"),
21        }
22    }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum OnDelete {
27    Cascade,
28    SetNull,
29    Restrict,
30}
31
32impl fmt::Display for OnDelete {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        match self {
35            OnDelete::Cascade => write!(f, "Cascade"),
36            OnDelete::SetNull => write!(f, "SetNull"),
37            OnDelete::Restrict => write!(f, "Restrict"),
38        }
39    }
40}
41
42pub fn id_from_model<T>(model: &T) -> Result<String>
43where
44    T: IdHolder,
45{
46    let r = model
47        .record_id()
48        .ok_or_else(|| Error::Validation("Model has no id (new/unsaved record)".into()))?;
49    extract_id_from_record(r)
50}
51
52pub trait IdHolder {
53    fn record_id(&self) -> Option<&RecordId>;
54}
55
56pub fn extract_id_from_record(r: &RecordId) -> Result<String> {
57    Ok(r.id().to_string())
58}
59
60pub fn extract_id_from_record_display(s: &str) -> Result<String> {
61    let id = s.split_once(':').map_or(s, |(_, id_part)| id_part).trim();
62    let id = id
63        .trim_start_matches(['⟨', '‹', '«'])
64        .trim_end_matches(['⟩', '›', '»']);
65    if id.is_empty() {
66        return Err(Error::Validation(format!(
67            "Invalid record id string: could not extract ID from {s:?}"
68        )));
69    }
70    Ok(id.to_string())
71}
72
73pub fn extract_id_from_select_value(v: &serde_json::Value) -> Result<String> {
74    if let Ok(rid) = serde_json::from_value::<RecordId>(v.clone()) {
75        return extract_id_from_record(&rid);
76    }
77    match v {
78        serde_json::Value::String(s) => extract_id_from_record_display(s),
79        serde_json::Value::Number(n) => Ok(n.to_string()),
80        serde_json::Value::Bool(b) => Ok(b.to_string()),
81        _ => Err(Error::Internal(format!(
82            "unexpected id value in query row: {v}"
83        ))),
84    }
85}