reifydb_routine/function/rql/
fingerprint.rs1use bumpalo::Bump;
5use reifydb_core::value::column::{Column, columns::Columns, data::ColumnData};
6use reifydb_rql::{
7 ast::parse_str,
8 fingerprint::{request::fingerprint_request, statement::fingerprint_statement},
9};
10use reifydb_type::value::r#type::Type;
11
12use crate::function::{Function, FunctionCapability, FunctionContext, FunctionInfo, error::FunctionError};
13
14pub struct RqlFingerprint {
15 info: FunctionInfo,
16}
17
18impl Default for RqlFingerprint {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl RqlFingerprint {
25 pub fn new() -> Self {
26 Self {
27 info: FunctionInfo::new("rql::fingerprint"),
28 }
29 }
30}
31
32impl Function for RqlFingerprint {
33 fn info(&self) -> &FunctionInfo {
34 &self.info
35 }
36
37 fn capabilities(&self) -> &[FunctionCapability] {
38 &[FunctionCapability::Scalar]
39 }
40
41 fn return_type(&self, _input_types: &[Type]) -> Type {
42 Type::Utf8
43 }
44
45 fn execute(&self, ctx: &FunctionContext, args: &Columns) -> Result<Columns, FunctionError> {
46 if args.len() != 1 {
47 return Err(FunctionError::ArityMismatch {
48 function: ctx.fragment.clone(),
49 expected: 1,
50 actual: args.len(),
51 });
52 }
53
54 let column = &args[0];
55 let (data, bitvec) = column.data().unwrap_option();
56 let row_count = data.len();
57
58 match data {
59 ColumnData::Utf8 {
60 container,
61 ..
62 } => {
63 let mut result_data = Vec::with_capacity(row_count);
64 let mut result_bitvec = Vec::with_capacity(row_count);
65
66 for i in 0..row_count {
67 if container.is_defined(i) {
68 let query = &container[i];
69 let bump = Bump::new();
70 let stmts = parse_str(&bump, query).map_err(|e| {
71 FunctionError::ExecutionFailed {
72 function: ctx.fragment.clone(),
73 reason: format!("{e}"),
74 }
75 })?;
76 let fps: Vec<_> =
77 stmts.iter().map(|s| fingerprint_statement(s)).collect();
78 let req = fingerprint_request(&fps);
79 result_data.push(req.to_hex());
80 result_bitvec.push(true);
81 } else {
82 result_data.push(String::new());
83 result_bitvec.push(false);
84 }
85 }
86
87 let inner_data = ColumnData::utf8_with_bitvec(result_data, result_bitvec);
88 let final_data = match bitvec {
89 Some(bv) => ColumnData::Option {
90 inner: Box::new(inner_data),
91 bitvec: bv.clone(),
92 },
93 None => inner_data,
94 };
95
96 Ok(Columns::new(vec![Column::new(ctx.fragment.clone(), final_data)]))
97 }
98 other => Err(FunctionError::InvalidArgumentType {
99 function: ctx.fragment.clone(),
100 argument_index: 0,
101 expected: vec![Type::Utf8],
102 actual: other.get_type(),
103 }),
104 }
105 }
106}