reifydb_routine/function/rql/
fingerprint.rs1use bumpalo::Bump;
5use reifydb_core::value::column::{ColumnWithName, buffer::ColumnBuffer, columns::Columns};
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::routine::{Function, FunctionKind, Routine, RoutineInfo, context::FunctionContext, error::RoutineError};
13
14pub struct RqlFingerprint {
15 info: RoutineInfo,
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: RoutineInfo::new("rql::fingerprint"),
28 }
29 }
30}
31
32impl<'a> Routine<FunctionContext<'a>> for RqlFingerprint {
33 fn info(&self) -> &RoutineInfo {
34 &self.info
35 }
36
37 fn return_type(&self, _input_types: &[Type]) -> Type {
38 Type::Utf8
39 }
40
41 fn execute(&self, ctx: &mut FunctionContext<'a>, args: &Columns) -> Result<Columns, RoutineError> {
42 if args.len() != 1 {
43 return Err(RoutineError::FunctionArityMismatch {
44 function: ctx.fragment.clone(),
45 expected: 1,
46 actual: args.len(),
47 });
48 }
49
50 let column = &args[0];
51 let (data, bitvec) = column.unwrap_option();
52 let row_count = data.len();
53
54 match data {
55 ColumnBuffer::Utf8 {
56 container,
57 ..
58 } => {
59 let mut result_data = Vec::with_capacity(row_count);
60 let mut result_bitvec = Vec::with_capacity(row_count);
61
62 for i in 0..row_count {
63 if container.is_defined(i) {
64 let query = container.get(i).unwrap();
65 let bump = Bump::new();
66 let stmts = parse_str(&bump, query).map_err(|e| {
67 RoutineError::FunctionExecutionFailed {
68 function: ctx.fragment.clone(),
69 reason: format!("{e}"),
70 }
71 })?;
72 let fps: Vec<_> =
73 stmts.iter().map(|s| fingerprint_statement(s)).collect();
74 let req = fingerprint_request(&fps);
75 result_data.push(req.to_hex());
76 result_bitvec.push(true);
77 } else {
78 result_data.push(String::new());
79 result_bitvec.push(false);
80 }
81 }
82
83 let inner_data = ColumnBuffer::utf8_with_bitvec(result_data, result_bitvec);
84 let final_data = match bitvec {
85 Some(bv) => ColumnBuffer::Option {
86 inner: Box::new(inner_data),
87 bitvec: bv.clone(),
88 },
89 None => inner_data,
90 };
91
92 Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), final_data)]))
93 }
94 other => Err(RoutineError::FunctionInvalidArgumentType {
95 function: ctx.fragment.clone(),
96 argument_index: 0,
97 expected: vec![Type::Utf8],
98 actual: other.get_type(),
99 }),
100 }
101 }
102}
103
104impl Function for RqlFingerprint {
105 fn kinds(&self) -> &[FunctionKind] {
106 &[FunctionKind::Scalar]
107 }
108}