assembly_data/fdb/query/
mod.rs

1//! ## Query the database
2use std::num::ParseIntError;
3
4use super::{
5    common::{Context, Value, ValueType},
6    core::Field,
7};
8use assembly_core::displaydoc::Display;
9use hsieh_hash::digest;
10use thiserror::Error;
11
12/// A struct that can act as a PK filter
13///
14/// This structure works much like a pre-implemented closure
15/// for use in a `filter` function. It contains the hash of
16/// a value and uses that to check whether the fields match.
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    /// Check `other` against the filter
29    pub fn filter<C: Context>(&self, other: &Value<C>) -> bool
30    where
31        Field: PartialEq<Value<C>>,
32    {
33        &self.value == other
34    }
35}
36
37#[derive(Error, Debug, Display)]
38#[allow(clippy::upper_case_acronyms)]
39/// Errors when creating filters at runtime
40pub enum PKFilterError {
41    /// Unsupported Type {0:?}
42    UnsupportedType(ValueType),
43    /// Key Error
44    KeyError(#[from] ParseIntError),
45}
46
47/// Create a text PK filter
48pub fn text_pk_filter(key: String) -> Result<PrimaryKeyFilter, PKFilterError> {
49    let hash_value = digest(key.as_bytes());
50    let value = Field::Text(key);
51    Ok(PrimaryKeyFilter { hash_value, value })
52}
53
54/// Create an integer PK filter
55pub fn integer_pk_filter(key: String) -> Result<PrimaryKeyFilter, PKFilterError> {
56    let value: i32 = key.parse().map_err(PKFilterError::KeyError)?;
57    let hash_value = u32::from_ne_bytes(value.to_ne_bytes());
58    Ok(PrimaryKeyFilter {
59        hash_value,
60        value: Field::Integer(value),
61    })
62}
63
64/// Create a PK filter from a string
65pub fn pk_filter<T: Into<String>>(
66    key: T,
67    field_type: ValueType,
68) -> Result<PrimaryKeyFilter, PKFilterError> {
69    match field_type {
70        ValueType::Text => text_pk_filter(key.into()),
71        ValueType::Integer => integer_pk_filter(key.into()),
72        _ => Err(PKFilterError::UnsupportedType(field_type)),
73    }
74}