assembly_fdb/
query.rs

1//! ## Query the database
2use std::num::ParseIntError;
3
4use assembly_fdb_core::{
5    value::{owned::Field, Context, Value, ValueType},
6    FdbHash,
7};
8use displaydoc::Display;
9use thiserror::Error;
10
11/// A struct that can act as a PK filter
12///
13/// This structure works much like a pre-implemented closure
14/// for use in a `filter` function. It contains the hash of
15/// a value and uses that to check whether the fields match.
16#[derive(Debug, Clone)]
17pub struct PrimaryKeyFilter {
18    hash_value: u32,
19    value: Field,
20}
21
22impl PrimaryKeyFilter {
23    /// Get the contained hash
24    pub fn hash(&self) -> u32 {
25        self.hash_value
26    }
27
28    /// Get the value used for exact comparison
29    pub fn original(&self) -> &Field {
30        &self.value
31    }
32
33    /// Check `other` against the filter
34    pub fn filter<C: Context>(&self, other: &Value<C>) -> bool
35    where
36        Field: PartialEq<Value<C>>,
37    {
38        &self.value == other
39    }
40
41    /// Create an integer PK hash
42    pub fn integer(value: i32) -> Self {
43        Self {
44            hash_value: FdbHash::hash(&value),
45            value: Field::Integer(value),
46        }
47    }
48
49    /// Create an integer PK hash
50    pub fn bigint(value: i64) -> Self {
51        Self {
52            hash_value: FdbHash::hash(&value),
53            value: Field::BigInt(value),
54        }
55    }
56
57    /// Create a text PK hash
58    pub fn text(value: String) -> Self {
59        Self {
60            hash_value: FdbHash::hash(&value),
61            value: Field::Text(value),
62        }
63    }
64}
65
66#[derive(Error, Debug, Display)]
67#[allow(clippy::upper_case_acronyms)]
68/// Errors when creating filters at runtime
69pub enum PKFilterError {
70    /// Unsupported Type {0:?}
71    UnsupportedType(ValueType),
72    /// Key Error
73    KeyError(#[from] ParseIntError),
74}
75
76/// Create a text PK filter
77pub fn text_pk_filter(key: String) -> Result<PrimaryKeyFilter, PKFilterError> {
78    Ok(PrimaryKeyFilter::text(key))
79}
80
81/// Create an integer PK filter
82pub fn integer_pk_filter(key: &str) -> Result<PrimaryKeyFilter, PKFilterError> {
83    let value: i32 = key.parse().map_err(PKFilterError::KeyError)?;
84    Ok(PrimaryKeyFilter::integer(value))
85}
86
87/// Create a bigint PK filter
88pub fn bigint_pk_filter(key: &str) -> Result<PrimaryKeyFilter, PKFilterError> {
89    let value: i64 = key.parse().map_err(PKFilterError::KeyError)?;
90    Ok(PrimaryKeyFilter::bigint(value))
91}
92
93/// Create a PK filter from a string
94pub fn pk_filter<T: Into<String>>(
95    key: T,
96    field_type: ValueType,
97) -> Result<PrimaryKeyFilter, PKFilterError> {
98    match field_type {
99        ValueType::Text => text_pk_filter(key.into()),
100        ValueType::Integer => integer_pk_filter(key.into().as_ref()),
101        ValueType::BigInt => bigint_pk_filter(key.into().as_ref()),
102        _ => Err(PKFilterError::UnsupportedType(field_type)),
103    }
104}