Skip to main content

akar_function/scalar/
schema.rs

1use crate::registry::*;
2use akar_common::types::Value;
3
4// ==================== Schema Functions ====================
5
6/// Evaluate a schema function: OFFSET, ID, START_NODE, END_NODE, LABEL.
7pub(crate) fn evaluate_schema(op: SchemaOp, args: &[Value]) -> Result<Value, String> {
8    if args.is_empty() {
9        return Err(format!("Schema function {:?} requires an argument", op));
10    }
11
12    match op {
13        SchemaOp::Offset => {
14            // OFFSET(v) → returns the internal offset (row number) of a node/rel ID
15            match &args[0] {
16                Value::InternalID(id) => Ok(Value::Int64(id.offset as i64)),
17                Value::Struct(entries) => {
18                    // Try to extract offset from a struct with "_id" field
19                    for (k, v) in entries {
20                        if k == "_id" {
21                            if let Value::InternalID(inner) = v {
22                                return Ok(Value::Int64(inner.offset as i64));
23                            }
24                        }
25                    }
26                    Err("OFFSET: argument struct has no _id field".into())
27                }
28                other => Err(format!(
29                    "OFFSET requires a node/rel value, got {:?}",
30                    other.logical_type()
31                )),
32            }
33        }
34        SchemaOp::Id => {
35            // ID(v) → returns the InternalID (offset + table_id)
36            match &args[0] {
37                Value::InternalID(id) => Ok(Value::InternalID(*id)),
38                Value::Struct(entries) => {
39                    // Try to extract id from a struct with "_id" field
40                    for (k, v) in entries {
41                        if k == "_id" {
42                            return Ok(v.clone());
43                        }
44                    }
45                    Err("ID: argument struct has no _id field".into())
46                }
47                other => Err(format!("ID requires a node/rel value, got {:?}", other.logical_type())),
48            }
49        }
50        SchemaOp::StartNode => {
51            // START_NODE(r) → returns the source node of a relationship
52            match &args[0] {
53                Value::Struct(entries) => {
54                    for (k, v) in entries {
55                        if k == "_src" {
56                            return Ok(v.clone());
57                        }
58                    }
59                    Err("START_NODE: rel struct has no _src field".into())
60                }
61                other => Err(format!(
62                    "START_NODE requires a relationship value, got {:?}",
63                    other.logical_type()
64                )),
65            }
66        }
67        SchemaOp::EndNode => {
68            // END_NODE(r) → returns the target node of a relationship
69            match &args[0] {
70                Value::Struct(entries) => {
71                    for (k, v) in entries {
72                        if k == "_dst" {
73                            return Ok(v.clone());
74                        }
75                    }
76                    Err("END_NODE: rel struct has no _dst field".into())
77                }
78                other => Err(format!(
79                    "END_NODE requires a relationship value, got {:?}",
80                    other.logical_type()
81                )),
82            }
83        }
84        SchemaOp::Label => {
85            // LABEL(v) → returns the table/label name as a string
86            match &args[0] {
87                Value::String(s) => Ok(Value::String(s.clone())),
88                Value::Struct(entries) => {
89                    // Try _label field first
90                    for (k, v) in entries {
91                        if k == "_label" {
92                            return Ok(v.clone());
93                        }
94                    }
95                    // Fallback: try _id and look up by table_id
96                    for (k, v) in entries {
97                        if k == "_id" {
98                            if let Value::InternalID(id) = v {
99                                return Ok(Value::String(format!("Table({})", id.table_id)));
100                            }
101                        }
102                    }
103                    Err("LABEL: argument struct has no _label field".into())
104                }
105                Value::InternalID(id) => Ok(Value::String(format!("Table({})", id.table_id))),
106                other => Err(format!(
107                    "LABEL requires a node/rel/string value, got {:?}",
108                    other.logical_type()
109                )),
110            }
111        }
112        SchemaOp::Cost => {
113            let path = &args[0];
114            match path {
115                Value::Struct(fields) => {
116                    for (k, v) in fields {
117                        if k == "_cost" || k == "cost" {
118                            return Ok(v.clone());
119                        }
120                    }
121                    Ok(Value::Double(0.0))
122                }
123                _ => Ok(Value::Double(0.0)),
124            }
125        }
126        SchemaOp::RowId => match &args[0] {
127            Value::InternalID(id) => Ok(Value::UInt64(id.offset)),
128            Value::Struct(entries) => {
129                for (k, v) in entries {
130                    if k == "_id" || k == "id" {
131                        if let Value::InternalID(id) = v {
132                            return Ok(Value::UInt64(id.offset));
133                        }
134                    }
135                }
136                Ok(Value::UInt64(0))
137            }
138            _ => Ok(Value::UInt64(0)),
139        },
140    }
141}