Skip to main content

ankurah_core/
query_value.rs

1//! Query substitution values for FFI bindings.
2//!
3//! UniFFI doesn't support variadic arguments or generic iterators, so we provide
4//! a concrete enum type for query parameter substitution.
5//!
6//! TODO: Investigate if there's a better approach in future UniFFI versions.
7//! Ideally we'd accept something closer to `impl Into<ankql::ast::Expr>` directly.
8
9use ankurah_proto::EntityId;
10
11/// Value type for query parameter substitution in FFI contexts.
12///
13/// Used with `fetch()`, `query()`, etc. to fill in `?` placeholders:
14/// ```ignore
15/// ops.fetch(ctx, "name = ?", vec![QueryValue::String("Alice".into())])
16/// ```
17#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
18#[derive(Debug, Clone)]
19pub enum QueryValue {
20    /// String value
21    String(String),
22    /// 64-bit integer
23    Int(i64),
24    /// 64-bit float
25    Float(f64),
26    /// Boolean
27    Bool(bool),
28    /// Entity ID (as base64 string for FFI compatibility)
29    EntityId(String),
30}
31
32impl TryFrom<QueryValue> for ankql::ast::Expr {
33    type Error = ankql::error::ParseError;
34
35    fn try_from(value: QueryValue) -> Result<Self, Self::Error> {
36        use ankql::ast::{Expr, Literal};
37
38        Ok(match value {
39            QueryValue::String(s) => Expr::Literal(Literal::String(s)),
40            QueryValue::Int(i) => Expr::Literal(Literal::I64(i)),
41            QueryValue::Float(f) => Expr::Literal(Literal::F64(f)),
42            QueryValue::Bool(b) => Expr::Literal(Literal::Bool(b)),
43            QueryValue::EntityId(s) => {
44                let id = EntityId::from_base64(&s)
45                    .map_err(|e| ankql::error::ParseError::InvalidPredicate(format!("Invalid EntityId: {}", e)))?;
46                Expr::Literal(Literal::EntityId(id.to_ulid()))
47            }
48        })
49    }
50}
51
52// Convenience conversions for Rust usage
53impl From<String> for QueryValue {
54    fn from(s: String) -> Self { QueryValue::String(s) }
55}
56
57impl From<&str> for QueryValue {
58    fn from(s: &str) -> Self { QueryValue::String(s.to_string()) }
59}
60
61impl From<i64> for QueryValue {
62    fn from(i: i64) -> Self { QueryValue::Int(i) }
63}
64
65impl From<i32> for QueryValue {
66    fn from(i: i32) -> Self { QueryValue::Int(i as i64) }
67}
68
69impl From<f64> for QueryValue {
70    fn from(f: f64) -> Self { QueryValue::Float(f) }
71}
72
73impl From<bool> for QueryValue {
74    fn from(b: bool) -> Self { QueryValue::Bool(b) }
75}
76
77impl From<EntityId> for QueryValue {
78    fn from(id: EntityId) -> Self { QueryValue::EntityId(id.to_base64()) }
79}