nodedb_sql/resolver/
text_column.rs1use nodedb_types::text_search::TextColumnFault;
6
7use super::columns::ResolvedTable;
8use crate::error::{Result, SqlError};
9use crate::types::SqlDataType;
10
11impl ResolvedTable {
12 pub fn check_text_column(&self, function: &str, column: &str) -> Result<()> {
15 let fault = match self.info.columns.iter().find(|c| c.name == column) {
16 Some(c) if c.data_type == SqlDataType::String => return Ok(()),
17 Some(c) => TextColumnFault::NotText {
18 data_type: c
19 .raw_type
20 .clone()
21 .unwrap_or_else(|| format!("{:?}", c.data_type)),
22 },
23 None if self.info.open_schema => return Ok(()),
24 None => TextColumnFault::Undeclared,
25 };
26 Err(SqlError::TextColumn {
27 function: function.to_owned(),
28 collection: self.name.clone(),
29 column: column.to_owned(),
30 fault,
31 })
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use crate::types::{CollectionInfo, ColumnInfo, EngineType};
39
40 fn column(name: &str, data_type: SqlDataType, raw: &str) -> ColumnInfo {
41 ColumnInfo {
42 name: name.into(),
43 data_type,
44 nullable: true,
45 is_primary_key: false,
46 default: None,
47 raw_type: Some(raw.into()),
48 int_width: None,
49 float_width: None,
50 }
51 }
52
53 fn strict() -> ResolvedTable {
54 let info = CollectionInfo {
55 name: "articles".into(),
56 engine: EngineType::DocumentStrict,
57 columns: vec![
58 column("title", SqlDataType::String, "TEXT"),
59 column("views", SqlDataType::Int64, "INT"),
60 ],
61 primary_key: None,
62 has_auto_tier: false,
63 indexes: Vec::new(),
64 bitemporal: false,
65 primary: nodedb_types::PrimaryEngine::Document,
66 vector_primary: None,
67 partition_strategy: nodedb_types::PartitionStrategy::CollectionHomed,
68 open_schema: false,
69 };
70 ResolvedTable {
71 name: "articles".into(),
72 alias: None,
73 info,
74 }
75 }
76
77 #[test]
78 fn a_text_column_is_accepted() {
79 assert_eq!(strict().check_text_column("text_match", "title"), Ok(()));
80 }
81
82 #[test]
83 fn an_int_column_is_not_text() {
84 let err = strict().check_text_column("bm25_score", "views");
85 assert_eq!(
86 err,
87 Err(SqlError::TextColumn {
88 function: "bm25_score".into(),
89 collection: "articles".into(),
90 column: "views".into(),
91 fault: TextColumnFault::NotText {
92 data_type: "INT".into()
93 },
94 })
95 );
96 }
97
98 #[test]
99 fn an_undeclared_column_names_the_collection() {
100 let Err(SqlError::TextColumn {
101 collection, fault, ..
102 }) = strict().check_text_column("text_match", "ghost")
103 else {
104 panic!("expected a TextColumn error");
105 };
106 assert_eq!(collection, "articles");
107 assert_eq!(fault, TextColumnFault::Undeclared);
108 }
109
110 #[test]
111 fn an_open_schema_collection_accepts_any_name() {
112 let mut table = strict();
113 table.info.open_schema = true;
114 assert_eq!(table.check_text_column("text_match", "ghost"), Ok(()));
115 }
116}