1use crate::core::case::{CaseTree, Entity, Payload};
2use crate::db::context::Context;
3use crate::regex;
4use crate::util::regex::get_match;
5use odbc_api::Nullability;
6use std::borrow::Cow;
7use std::collections::BTreeMap;
8
9pub struct Catalog {
10 directives: CaseTree,
11 objects: CaseTree,
12 columns: CaseTree,
13 keywords: CaseTree,
14}
15
16impl Catalog {
18 pub fn new() -> Self {
19 let directives = CaseTree::new(Cow::default());
20 let objects = CaseTree::new(Cow::default());
21 let columns = CaseTree::new(Cow::default());
22 let keywords = CaseTree::new(Cow::default());
23 Self { directives, objects, columns, keywords }
24 }
25
26 pub fn insert_directive(
27 &mut self,
28 verb: Cow<str>,
29 noun: Cow<str>,
30 ) {
31 if let Some(child) = self.directives.insert_child(&[], verb.clone()) {
32 child.set_entity(Entity::Keyword);
33 }
34 if let Some(child) = self.directives.insert_child(&[verb], noun) {
35 child.set_entity(Entity::Keyword);
36 }
37 }
38
39 pub fn insert_database(
40 &mut self,
41 database: Cow<str>,
42 schema: Cow<str>,
43 ) {
44 self.objects.insert_child(&[database], schema);
45 }
46
47 pub fn insert_table(
48 &mut self,
49 database: Cow<str>,
50 schema: Cow<str>,
51 table: Cow<str>,
52 ) {
53 self.objects.insert_child(&[database, schema], table);
54 }
55
56 pub fn insert_column(
57 &mut self,
58 database: Cow<str>,
59 schema: Cow<str>,
60 table: Cow<str>,
61 column: Cow<str>,
62 dtype: Cow<str>,
63 null: Nullability,
64 index: usize,
65 ) {
66 if let Some(child) = self.columns.insert_child(&[database.clone(), schema.clone()], column.clone()) {
67 child.set_payload(dtype.clone(), null, index);
68 }
69 if let Some(child) = self.objects.insert_child(&[database, schema, table], column) {
70 child.set_payload(dtype, null, index);
71 }
72 }
73
74 pub fn insert_procedure(
75 &mut self,
76 database: Cow<str>,
77 schema: Cow<str>,
78 procedure: Cow<str>,
79 ) {
80 if let Some(child) = self.objects.insert_child(&[database, schema], procedure) {
81 child.set_entity(Entity::Procedure);
82 }
83 }
84
85 pub fn insert_keyword(&mut self, keyword: Cow<str>) {
86 if let Some(child) = self.keywords.insert_child(&[], keyword) {
87 child.set_entity(Entity::Keyword);
88 }
89 }
90
91 pub fn insert_function(&mut self, function: Cow<str>) {
92 if let Some(child) = self.keywords.insert_child(&[], function) {
93 child.set_entity(Entity::Function);
94 }
95 }
96
97 pub fn complete_line(&self, context: Context, line: &str, pos: usize) -> (usize, Vec<String>) {
98 let verb_regex = regex!(r"^(:\w*)$");
99 let noun_regex = regex!(r"^(:\w+)\s+(\w*)$");
100 let context = context.to_lowercase();
101 let line = line[..pos].to_lowercase();
102 if line.starts_with(":") {
103 if let Some(captures) = verb_regex.captures(&line) {
104 let verb = get_match(&captures, 1);
106 let verbs = self.directives.get_values(&[]);
107 let candidates = Self::select_candidates(verbs, verb);
108 return (0, candidates);
109 } else if let Some(captures) = noun_regex.captures(&line) {
110 let verb = get_match(&captures, 1);
112 let noun = get_match(&captures, 2);
113 let offset = get_offset(&line, noun);
114 let nouns = self.directives.get_values(&[verb]);
115 let candidates = Self::select_candidates(nouns, noun);
116 return (offset, candidates);
117 }
118 }
119 if let Some((start, stub)) = line.rsplit_once(char::is_whitespace) {
120 let start = start.len() + 1;
122 let (offset, candidates) = self.complete_stub(context, stub);
123 (start + offset, candidates)
124 } else {
125 let (offset, candidates) = self.complete_stub(context, &line);
127 (offset, candidates)
128 }
129 }
130
131 fn complete_stub(&self, context: Context, stub: &str) -> (usize, Vec<String>) {
132 let quad_regex = regex!(r"\b(\w+)\.(\w+)\.(\w+)\.(\w*)$");
133 let triple_regex = regex!(r"\b(\w+)\.(\w+)\.(\w*)$");
134 let double_regex = regex!(r"\b(\w+)\.(\w*)$");
135 let single_regex = regex!(r"\b(\w*)$");
136 let (database, schema) = context.as_str();
137 if let Some(captures) = quad_regex.captures(&stub) {
138 let arg1 = get_match(&captures, 1);
139 let arg2 = get_match(&captures, 2);
140 let arg3 = get_match(&captures, 3);
141 let arg4 = get_match(&captures, 4);
142 let offset = get_offset(&stub, arg4);
143 let candidates = if let Some(columns) = self.objects.get_child(&[arg1, arg2, arg3]) {
144 let columns = columns.get_values(&[]);
146 Self::select_candidates(columns, arg4)
147 } else {
148 Vec::new()
150 };
151 (offset, candidates)
152 } else if let Some(captures) = triple_regex.captures(&stub) {
153 let arg1 = get_match(&captures, 1);
154 let arg2 = get_match(&captures, 2);
155 let arg3 = get_match(&captures, 3);
156 let offset = get_offset(&stub, arg3);
157 let candidates = if let Some(tables) = self.objects.get_child(&[arg1, arg2]) {
158 let tables = tables.get_values(&[]);
160 Self::select_candidates(tables, arg3)
161 } else if let Some(columns) = self.objects.get_child(&[database, arg1, arg2]) {
162 let columns = columns.get_values(&[]);
164 Self::select_candidates(columns, arg3)
165 } else {
166 Vec::new()
168 };
169 (offset, candidates)
170 } else if let Some(captures) = double_regex.captures(&stub) {
171 let arg1 = get_match(&captures, 1);
172 let arg2 = get_match(&captures, 2);
173 let offset = get_offset(&stub, arg2);
174 let candidates = if let Some(schemas) = self.objects.get_child(&[arg1]) {
175 let schemas = schemas.get_values(&[]);
177 Self::select_candidates(schemas, arg2)
178 } else if let Some(tables) = self.objects.get_child(&[database, arg1]) {
179 let tables = tables.get_values(&[]);
181 Self::select_candidates(tables, arg2)
182 } else if let Some(columns) = self.objects.get_child(&[database, schema, arg1]) {
183 let columns = columns.get_values(&[]);
185 Self::select_candidates(columns, arg2)
186 } else {
187 let columns = self.columns.get_values(&[database, schema]);
189 Self::select_candidates(columns, arg2)
190 };
191 (offset, candidates)
192 } else if let Some(captures) = single_regex.captures(&stub) {
193 let arg = get_match(&captures, 1);
195 let offset = get_offset(&stub, arg);
196 let chained = self.objects.get_values(&[])
197 .chain(self.objects.get_values(&[database]))
198 .chain(self.objects.get_values(&[database, schema]))
199 .chain(self.columns.get_values(&[database, schema]))
200 .chain(self.keywords.get_values(&[]));
201 let candidates = Self::select_candidates(chained, arg);
202 (offset, candidates)
203 } else {
204 (0, Vec::new())
206 }
207 }
208
209 fn select_candidates<'a, I>(keywords: I, stub: &str) -> Vec<String> where
210 I: Iterator<Item = (&'a String, (&'a String, Entity))>
211 {
212 let candidates = keywords
213 .filter(|(k, _)| k.starts_with(stub))
214 .map(|(k, (v1, v2))| (k.to_string(), (v1.to_string(), v2)))
215 .collect::<BTreeMap<_, _>>();
216 if candidates.len() == 1 {
217 candidates.into_iter().map(Self::append_suffix).collect()
218 } else {
219 let prefix = Self::generate_prefix(&candidates);
220 candidates.into_iter().map(|c| Self::replace_prefix(c, &prefix)).collect()
221 }
222 }
223
224 fn generate_prefix(candidates: &BTreeMap<String, (String, Entity)>) -> String {
225 let filter = |(c1, c2): &(char, char)| c1 == c2;
226 let choose = |(c1, c2): (char, char)| if c1.is_uppercase() { c1 } else { c2 };
227 let mut candidates = candidates.iter();
228 if let Some((key, (value, _))) = candidates.next() {
229 let search = key.to_string();
230 let mut replace = value.to_string();
231 for (key, (value, _)) in candidates {
232 let common = search.chars().zip(key.chars()).take_while(filter).count();
233 let value = &value[0..common];
234 replace = replace.chars().zip(value.chars()).map(choose).collect();
235 }
236 replace
237 } else {
238 String::new()
239 }
240 }
241
242 fn replace_prefix(candidate: (String, (String, Entity)), prefix: &str) -> String {
243 let (_, (mut value, _)) = candidate;
244 let length = prefix.len();
245 value.replace_range(0..length, prefix);
246 value
247 }
248
249 fn append_suffix(candidate: (String, (String, Entity))) -> String {
250 match candidate {
251 (_, (value, Entity::Default)) => value,
252 (_, (value, Entity::Procedure)) => value + "(",
253 (_, (value, Entity::Keyword)) => value + " ",
254 (_, (value, Entity::Function)) => value + "(",
255 }
256 }
257
258 pub fn get_databases(&self, context: Context) -> Vec<(&str, &str, &str)> {
259 let mut values = BTreeMap::new();
260 if let Some(database) = &context.database {
261 for (database_key, database_node) in self.objects.get_nodes(Entity::Default) {
262 let active = if database_node.as_str().eq_ignore_ascii_case(database) { "Y" } else { "" };
263 if context.schema.is_some() {
264 for (schema_key, schema_node) in database_node.get_nodes(Entity::Default) {
265 values.insert((database_key, schema_key.as_str()), (
266 database_node.as_str(),
267 schema_node.as_str(),
268 active,
269 ));
270 }
271 } else {
272 values.insert((database_key, ""), (database_node.as_str(), "", active));
273 }
274 }
275 }
276 values.into_values().collect()
277 }
278
279 pub fn get_tables(&self, context: Context, line: &str) -> Vec<(&str, &str, &str)> {
280 let (database, schema) = context.as_str();
281 let mut split = line.split_terminator('.');
282 if let Some(arg1) = split.next() {
283 if let Some(arg2) = split.next() {
284 if context.database.is_some() && context.schema.is_some() {
285 self.inner_tables(arg1, arg2, Entity::Default).unwrap_or_default()
286 } else {
287 Vec::new()
288 }
289 } else {
290 if context.database.is_some() && let Some(values) = self.inner_tables(arg1, schema, Entity::Default) {
291 values
292 } else if context.schema.is_some() && let Some(values) = self.inner_tables(database, arg1, Entity::Default) {
293 values
294 } else {
295 Vec::new()
296 }
297 }
298 } else {
299 self.inner_tables(database, schema, Entity::Default).unwrap_or_default()
300 }
301 }
302
303 pub fn get_columns(
304 &self,
305 context: Context,
306 line: &str,
307 ) -> Vec<(&str, &str, &str, &str, Option<&Payload>)> {
308 let (database, schema) = context.as_str();
309 let mut split = line.split_terminator('.');
310 if let Some(arg1) = split.next() {
311 if let Some(arg2) = split.next() {
312 if let Some(arg3) = split.next() {
313 if context.database.is_some() && context.schema.is_some() {
314 self.inner_columns(arg1, arg2, arg3).unwrap_or_default()
315 } else {
316 Vec::new()
317 }
318 } else {
319 if context.database.is_some() && context.schema.is_some() && let Some(values) = self.inner_columns(arg1, arg2, "") {
320 values
321 } else if context.database.is_some() && let Some(values) = self.inner_columns(arg1, schema, arg2) {
322 values
323 } else if context.schema.is_some() && let Some(values) = self.inner_columns(database, arg1, arg2) {
324 values
325 } else {
326 Vec::new()
327 }
328 }
329 } else {
330 if context.database.is_some() && let Some(values) = self.inner_columns(arg1, schema, "") {
331 values
332 } else if context.schema.is_some() && let Some(values) = self.inner_columns(database, arg1, "") {
333 values
334 } else if let Some(values) = self.inner_columns(database, schema, arg1) {
335 values
336 } else {
337 Vec::new()
338 }
339 }
340 } else {
341 self.inner_columns(database, schema, "").unwrap_or_default()
342 }
343 }
344
345 pub fn get_procedures(&self, context: Context, line: &str) -> Vec<(&str, &str, &str)> {
346 let (database, schema) = context.as_str();
347 let mut split = line.split_terminator('.');
348 if let Some(arg1) = split.next() {
349 if let Some(arg2) = split.next() {
350 if context.database.is_some() && context.schema.is_some() {
351 self.inner_tables(arg1, arg2, Entity::Procedure).unwrap_or_default()
352 } else {
353 Vec::new()
354 }
355 } else {
356 if context.database.is_some() && let Some(values) = self.inner_tables(arg1, schema, Entity::Procedure) {
357 values
358 } else if context.schema.is_some() && let Some(values) = self.inner_tables(database, arg1, Entity::Procedure) {
359 values
360 } else {
361 Vec::new()
362 }
363 }
364 } else {
365 self.inner_tables(database, schema, Entity::Procedure).unwrap_or_default()
366 }
367 }
368
369 fn inner_tables(
370 &self,
371 database: &str,
372 schema: &str,
373 entity: Entity,
374 ) -> Option<Vec<(&str, &str, &str)>> {
375 let database = database.to_lowercase();
376 let schema = schema.to_lowercase();
377 if let Some(database_node) = self.objects.get_child(&[&database]) {
378 if let Some(schema_node) = database_node.get_child(&[&schema]) {
379 let mut values = BTreeMap::new();
380 let database_name = if !database.is_empty() { database_node.as_str() } else { "" };
381 let schema_name = if !schema.is_empty() { schema_node.as_str() } else { "" };
382 for (table_key, table_node) in schema_node.get_nodes(entity) {
383 values.insert(table_key, (database_name, schema_name, table_node.as_str()));
384 }
385 let values = values.into_values().collect();
386 return Some(values);
387 }
388 }
389 None
390 }
391
392 fn inner_columns(
393 &self,
394 database: &str,
395 schema: &str,
396 table: &str,
397 ) -> Option<Vec<(&str, &str, &str, &str, Option<&Payload>)>> {
398 let database = database.to_lowercase();
399 let schema = schema.to_lowercase();
400 if let Some(database_node) = self.objects.get_child(&[&database]) {
401 if let Some(schema_node) = database_node.get_child(&[&schema]) {
402 let mut values = BTreeMap::new();
403 let database_name = if !database.is_empty() { database_node.as_str() } else { "" };
404 let schema_name = if !schema.is_empty() { schema_node.as_str() } else { "" };
405 for (table_key, table_node) in schema_node.get_nodes(Entity::Default) {
406 if table.is_empty() || table_node.as_str().eq_ignore_ascii_case(table) {
407 for (column_key, column_node) in table_node.get_nodes(Entity::Default) {
408 let payload = column_node.get_payload();
409 let index = payload.map(|p| p.index).unwrap_or_default();
410 values.insert((table_key, index, column_key), (
411 database_name,
412 schema_name,
413 table_node.as_str(),
414 column_node.as_str(),
415 payload,
416 ));
417 }
418 }
419 }
420 let values = values.into_values().collect();
421 return Some(values);
422 }
423 }
424 None
425 }
426
427 pub fn get_keywords(&self) -> Vec<&str> {
428 let mut values = BTreeMap::new();
429 for (key, node) in self.keywords.get_nodes(Entity::Keyword) {
430 values.insert(key, node.as_str());
431 }
432 values.into_values().collect()
433 }
434
435 pub fn get_functions(&self) -> Vec<&str> {
436 let mut values = BTreeMap::new();
437 for (key, node) in self.keywords.get_nodes(Entity::Function) {
438 values.insert(key, node.as_str());
439 }
440 values.into_values().collect()
441 }
442}
443
444fn get_offset(stub: &str, token: &str) -> usize {
445 stub
446 .len()
447 .checked_sub(token.len())
448 .unwrap_or_default()
449}
450
451#[cfg(test)]
453pub mod tests {
454 use crate::core::case::Payload;
455 use crate::core::catalog::Catalog;
456 use crate::db::context::Context;
457 use crate::{cow_str, str_vec};
458 use odbc_api::Nullability;
459 use odbc_api::Nullability::{NoNulls, Nullable};
460 use pretty_assertions::assert_eq;
461 use std::borrow::Cow;
462
463 #[test]
464 fn test_directive_at_start_is_completed() {
465 let catalog = create_catalog(Model::TSQL);
467 assert_eq!(complete_line(&catalog, (None, None), ":"), (0, str_vec![
468 ":format",
469 ":show",
470 ]));
471 assert_eq!(complete_line(&catalog, (None, None), ":FOr"), (0, str_vec![
472 ":format ",
473 ]));
474 assert_eq!(complete_line(&catalog, (None, None), ":ZZz"), (0, str_vec![]));
475 }
476
477 #[test]
478 fn test_directive_and_noun_is_completed() {
479 let catalog = create_catalog(Model::TSQL);
481 assert_eq!(complete_line(&catalog, (None, None), ":FOrmat "), (8, str_vec![
482 "flatten",
483 "table",
484 ]));
485 assert_eq!(complete_line(&catalog, (None, None), ":FOrmat TAb"), (8, str_vec![
486 "table ",
487 ]));
488 assert_eq!(complete_line(&catalog, (None, None), ":FOrmat ZZz"), (8, str_vec![]));
489 }
490
491 #[test]
492 fn test_directive_in_middle_not_completed() {
493 let catalog = create_catalog(Model::TSQL);
495 assert_eq!(complete_line(&catalog, (None, None), "SELECT :"), (7, str_vec![]));
496 assert_eq!(complete_line(&catalog, (None, None), "SELECT :FOr"), (8, str_vec![]));
497 assert_eq!(complete_line(&catalog, (None, None), "SELECT :ZZz"), (8, str_vec![]));
498 }
499
500 #[test]
501 fn test_single_keyword_is_completed() {
502 let catalog = create_catalog(Model::TSQL);
504 assert_eq!(complete_line(&catalog, (Some("ARchive"), Some("MAin")), "<A"), (1, str_vec![
505 "ABS",
506 "ADD",
507 "ALTER",
508 "AND",
509 "Announce", "Appendix", "Archive", "Article", "AS",
514 "Author", "Available", ]));
517 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<A"), (1, str_vec![
518 "ABS",
519 "Account", "Active", "ADD",
522 "Address", "Admin", "Advertise", "ALTER",
526 "Amount", "AND",
528 "Archive", "AS",
530 ]));
531 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("MAin")), "<A"), (1, str_vec![
532 "ABS",
533 "ADD",
534 "ALTER",
535 "AND",
536 "Archive", "AS",
538 ]));
539 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<SEl"), (1, str_vec![
540 "SELECT ",
541 ]));
542 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<COu"), (1, str_vec![
543 "COUNT(",
544 ]));
545 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ADv"), (1, str_vec![
546 "Advertise(", ]));
548 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ARch"), (1, str_vec![
549 "Archive", ]));
551 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ADm"), (1, str_vec![
552 "Admin", ]));
554 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<PEr"), (1, str_vec![
555 "Person", ]));
557 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<FOre"), (1, str_vec![
558 "Forename", ]));
560 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ZZz"), (1, str_vec![]));
561 }
562
563 #[test]
564 fn test_database_schema_is_completed() {
565 let catalog = create_catalog(Model::TSQL);
567 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness."), (10, str_vec![
568 "Admin", "Main", ]));
571 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.A"), (10, str_vec![
572 "Admin", ]));
574 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.SEl"), (10, str_vec![]));
575 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.COu"), (10, str_vec![]));
576 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.ADv"), (10, str_vec![]));
577 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.ARch"), (10, str_vec![]));
578 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.ADm"), (10, str_vec![
579 "Admin", ]));
581 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.PEr"), (10, str_vec![]));
582 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.FOre"), (10, str_vec![]));
583 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.ZZz"), (10, str_vec![]));
584 }
585
586 #[test]
587 fn test_schema_table_is_completed() {
588 let catalog = create_catalog(Model::TSQL);
590 assert_eq!(complete_line(&catalog, (Some("ARchive"), Some("UNknown")), "<MAin."), (6, str_vec![
591 "Announce", "Article", "Journal", ]));
595 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin."), (6, str_vec![
596 "Account", "Advertise", "Person", "Recruit", ]));
601 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<MAin."), (6, str_vec![]));
602 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.SEl"), (6, str_vec![]));
603 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.COu"), (6, str_vec![]));
604 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ADv"), (6, str_vec![
605 "Advertise(", ]));
607 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ARch"), (6, str_vec![]));
608 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ADm"), (6, str_vec![]));
609 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.PEr"), (6, str_vec![
610 "Person", ]));
612 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.FOre"), (6, str_vec![]));
613 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ZZz"), (6, str_vec![]));
614 }
615
616 #[test]
617 fn test_database_schema_table_is_completed() {
618 let catalog = create_catalog(Model::TSQL);
620 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin."), (15, str_vec![
621 "Account", "Advertise", "Person", "Recruit", ]));
626 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.A"), (15, str_vec![
627 "Account", "Advertise", ]));
630 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.SEl"), (15, str_vec![]));
631 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.COu"), (15, str_vec![]));
632 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ADv"), (15, str_vec![
633 "Advertise(", ]));
635 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ARch"), (15, str_vec![]));
636 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ADm"), (15, str_vec![]));
637 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.PEr"), (15, str_vec![
638 "Person", ]));
640 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.FOre"), (15, str_vec![]));
641 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ZZz"), (15, str_vec![]));
642 }
643
644 #[test]
645 fn test_table_column_is_completed() {
646 let catalog = create_catalog(Model::TSQL);
648 assert_eq!(complete_line(&catalog, (Some("ARchive"), Some("MAin")), "<ARticle.A"), (9, str_vec![
649 "Appendix", "Author", ]));
652 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.A"), (9, str_vec![
653 "Active", "Amount", ]));
656 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("MAin")), "<ACcount.A"), (9, str_vec![]));
657 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.SEl"), (9, str_vec![]));
658 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.COu"), (9, str_vec![]));
659 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.ADv"), (9, str_vec![]));
660 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.ARch"), (9, str_vec![]));
661 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.ADm"), (9, str_vec![]));
662 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.PEr"), (9, str_vec![]));
663 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.FOre"), (9, str_vec![]));
664 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<ACcount.ZZz"), (9, str_vec![]));
665 }
666
667 #[test]
668 fn test_schema_table_column_is_completed() {
669 let catalog = create_catalog(Model::TSQL);
671 assert_eq!(complete_line(&catalog, (Some("ARchive"), Some("UNknown")), "<MAin.ACcount.A"), (14, str_vec![]));
672 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.A"), (14, str_vec![
673 "Active", "Amount", ]));
676 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<MAin.ACcount.A"), (14, str_vec![]));
677 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.SEl"), (14, str_vec![]));
678 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.COu"), (14, str_vec![]));
679 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.ADv"), (14, str_vec![]));
680 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.ARch"), (14, str_vec![]));
681 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.ADm"), (14, str_vec![]));
682 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.PEr"), (14, str_vec![]));
683 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.FOre"), (14, str_vec![]));
684 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("UNknown")), "<MAin.ACcount.ZZz"), (14, str_vec![]));
685 }
686
687 #[test]
688 fn test_database_schema_table_column_is_completed() {
689 let catalog = create_catalog(Model::TSQL);
691 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount."), (23, str_vec![
692 "Active", "Amount", "Branch", "Company", ]));
697 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.A"), (23, str_vec![
698 "Active", "Amount", ]));
701 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.SEl"), (23, str_vec![]));
702 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.COu"), (23, str_vec![]));
703 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.ADv"), (23, str_vec![]));
704 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.ARch"), (23, str_vec![]));
705 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.ADm"), (23, str_vec![]));
706 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.PEr"), (23, str_vec![]));
707 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.FOre"), (23, str_vec![]));
708 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("UNknown")), "<BUsiness.MAin.ACcount.ZZz"), (23, str_vec![]));
709 }
710
711 #[test]
712 fn test_unknown_column_is_completed() {
713 let catalog = create_catalog(Model::TSQL);
715 assert_eq!(complete_line(&catalog, (Some("ARchive"), Some("MAin")), "<UNknown.A"), (9, str_vec![
716 "Appendix", "Author", "Available", ]));
720 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.A"), (9, str_vec![
721 "Active", "Address", "Amount", ]));
725 assert_eq!(complete_line(&catalog, (Some("UNknown"), Some("MAin")), "<UNknown.A"), (9, str_vec![]));
726 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.SEl"), (9, str_vec![]));
727 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.COu"), (9, str_vec![]));
728 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.ADv"), (9, str_vec![]));
729 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.ARch"), (9, str_vec![]));
730 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.ADm"), (9, str_vec![]));
731 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.PEr"), (9, str_vec![]));
732 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.FOre"), (9, str_vec![
733 "Forename", ]));
735 assert_eq!(complete_line(&catalog, (Some("BUsiness"), Some("MAin")), "<UNknown.ZZz"), (9, str_vec![]));
736 }
737
738 #[test]
739 fn test_prefix_is_replaced_on_completion() {
740 let mut catalog = Catalog::new();
741 catalog.insert_keyword(cow_str!("ACTION"));
742 catalog.insert_keyword(cow_str!("Activate"));
743 catalog.insert_keyword(cow_str!("Active"));
744 catalog.insert_keyword(cow_str!("Passive"));
745 assert_eq!(complete_line(&catalog, (None, None), "<AC"), (1, str_vec!(
746 "ACTION",
747 "ACTIvate",
748 "ACTIve",
749 )));
750 }
751
752 #[test]
753 fn test_databases_are_returned_for_show_with_tsql_model() {
754 let catalog = create_catalog(Model::TSQL);
755 assert_eq!(catalog.get_databases(Context::new(Some("ARchive"), Some("UNknown"))), vec![
756 ("Archive", "Main", "Y"),
757 ("Business", "Admin", ""),
758 ("Business", "Main", ""),
759 ]);
760 assert_eq!(catalog.get_databases(Context::new(Some("BUsiness"), Some("UNknown"))), vec![
761 ("Archive", "Main", ""),
762 ("Business", "Admin", "Y"),
763 ("Business", "Main", "Y"),
764 ]);
765 assert_eq!(catalog.get_databases(Context::new(Some("UNknown"), Some("UNknown"))), vec![
766 ("Archive", "Main", ""),
767 ("Business", "Admin", ""),
768 ("Business", "Main", ""),
769 ]);
770 }
771
772 #[test]
773 fn test_databases_are_returned_for_show_with_mysql_model() {
774 let catalog = create_catalog(Model::MySQL);
775 assert_eq!(catalog.get_databases(Context::new(Some("ARchive"), None)), vec![
776 ("Archive", "", "Y"),
777 ("Business", "", ""),
778 ]);
779 assert_eq!(catalog.get_databases(Context::new(Some("BUsiness"), None)), vec![
780 ("Archive", "", ""),
781 ("Business", "", "Y"),
782 ]);
783 assert_eq!(catalog.get_databases(Context::new(Some("UNknown"), None)), vec![
784 ("Archive", "", ""),
785 ("Business", "", ""),
786 ]);
787 }
788
789 #[test]
790 fn test_databases_are_returned_for_show_with_sqlite_model() {
791 let catalog = create_catalog(Model::Sqlite);
792 assert_eq!(catalog.get_databases(Context::default()).is_empty(), true);
793 }
794
795 #[test]
796 fn test_tables_are_returned_for_show_with_tsql_model() {
797 let catalog = create_catalog(Model::TSQL);
798 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), Some("MAin")), ""), vec![
799 ("Business", "Main", "Account"),
800 ("Business", "Main", "Person"),
801 ]);
802 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), Some("MAin")), "ADmin"), vec![
803 ("Business", "Admin", "Server"),
804 ]);
805 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), Some("MAin")), "ARchive"), vec![
806 ("Archive", "Main", "Article"),
807 ("Archive", "Main", "Journal"),
808 ]);
809 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), Some("MAin")), "ARchive.MAin"), vec![
810 ("Archive", "Main", "Article"),
811 ("Archive", "Main", "Journal"),
812 ]);
813 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), Some("MAin")), "UNknown").is_empty(), true);
814 }
815
816 #[test]
817 fn test_tables_are_returned_for_show_with_mysql_model() {
818 let catalog = create_catalog(Model::MySQL);
819 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), None), ""), vec![
820 ("Business", "", "Account"),
821 ("Business", "", "Person"),
822 ]);
823 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), None), "ARchive"), vec![
824 ("Archive", "", "Article"),
825 ("Archive", "", "Journal"),
826 ]);
827 assert_eq!(catalog.get_tables(Context::new(Some("BUsiness"), None), "UNknown").is_empty(), true);
828 }
829
830 #[test]
831 fn test_tables_are_returned_for_show_with_sqlite_model() {
832 let catalog = create_catalog(Model::Sqlite);
833 assert_eq!(catalog.get_tables(Context::default(), ""), vec![
834 ("", "", "Account"),
835 ("", "", "Person"),
836 ]);
837 assert_eq!(catalog.get_tables(Context::default(), "UNknown").is_empty(), true);
838 }
839
840 #[test]
841 fn test_columns_are_returned_for_show_with_tsql_model() {
842 let catalog = create_catalog(Model::TSQL);
843 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), ""), vec![
844 ("Business", "Main", "Account", "Company", "VARCHAR(20)", NoNulls, 1),
845 ("Business", "Main", "Account", "Branch", "VARCHAR(20)", NoNulls, 2),
846 ("Business", "Main", "Account", "Amount", "DECIMAL(10, 2)", NoNulls, 3),
847 ("Business", "Main", "Account", "Active", "BIT", NoNulls, 4),
848 ("Business", "Main", "Person", "Forename", "VARCHAR(20)", NoNulls, 1),
849 ("Business", "Main", "Person", "Surname", "VARCHAR(20)", NoNulls, 2),
850 ("Business", "Main", "Person", "Address", "VARCHAR(20)", Nullable, 3),
851 ("Business", "Main", "Person", "Birthday", "DATE", Nullable, 4),
852 ]);
853 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "PErson"), vec![
854 ("Business", "Main", "Person", "Forename", "VARCHAR(20)", NoNulls, 1),
855 ("Business", "Main", "Person", "Surname", "VARCHAR(20)", NoNulls, 2),
856 ("Business", "Main", "Person", "Address", "VARCHAR(20)", Nullable, 3),
857 ("Business", "Main", "Person", "Birthday", "DATE", Nullable, 4),
858 ]);
859 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "ADmin"), vec![
860 ("Business", "Admin", "Server", "Name", "VARCHAR(20)", NoNulls, 1),
861 ("Business", "Admin", "Server", "Location", "VARCHAR(20)", NoNulls, 2),
862 ("Business", "Admin", "Server", "Hardware", "VARCHAR(20)", NoNulls, 3),
863 ]);
864 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "ADmin.SErver"), vec![
865 ("Business", "Admin", "Server", "Name", "VARCHAR(20)", NoNulls, 1),
866 ("Business", "Admin", "Server", "Location", "VARCHAR(20)", NoNulls, 2),
867 ("Business", "Admin", "Server", "Hardware", "VARCHAR(20)", NoNulls, 3),
868 ]);
869 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "ARchive"), vec![
870 ("Archive", "Main", "Article", "Journal", "INTEGER", NoNulls, 1),
871 ("Archive", "Main", "Article", "Date", "DATE", NoNulls, 2),
872 ("Archive", "Main", "Article", "Author", "VARCHAR(20)", NoNulls, 3),
873 ("Archive", "Main", "Article", "Text", "VARCHAR(4000)", NoNulls, 4),
874 ("Archive", "Main", "Article", "Appendix", "VARCHAR(4000)", Nullable, 5),
875 ("Archive", "Main", "Journal", "Country", "INTEGER", NoNulls, 1),
876 ("Archive", "Main", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2),
877 ("Archive", "Main", "Journal", "Available", "BIT", NoNulls, 3),
878 ]);
879 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "ARchive.JOurnal"), vec![
880 ("Archive", "Main", "Journal", "Country", "INTEGER", NoNulls, 1),
881 ("Archive", "Main", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2),
882 ("Archive", "Main", "Journal", "Available", "BIT", NoNulls, 3),
883 ]);
884 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "ARchive.MAin"), vec![
885 ("Archive", "Main", "Article", "Journal", "INTEGER", NoNulls, 1),
886 ("Archive", "Main", "Article", "Date", "DATE", NoNulls, 2),
887 ("Archive", "Main", "Article", "Author", "VARCHAR(20)", NoNulls, 3),
888 ("Archive", "Main", "Article", "Text", "VARCHAR(4000)", NoNulls, 4),
889 ("Archive", "Main", "Article", "Appendix", "VARCHAR(4000)", Nullable, 5),
890 ("Archive", "Main", "Journal", "Country", "INTEGER", NoNulls, 1),
891 ("Archive", "Main", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2),
892 ("Archive", "Main", "Journal", "Available", "BIT", NoNulls, 3),
893 ]);
894 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "ARchive.MAin.JOurnal"), vec![
895 ("Archive", "Main", "Journal", "Country", "INTEGER", NoNulls, 1),
896 ("Archive", "Main", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2),
897 ("Archive", "Main", "Journal", "Available", "BIT", NoNulls, 3),
898 ]);
899 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), Some("MAin")), "UNknown").is_empty(), true);
900 }
901
902 #[test]
903 fn test_columns_are_returned_for_show_with_mysql_model() {
904 let catalog = create_catalog(Model::MySQL);
905 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), None), ""), vec![
906 ("Business", "", "Account", "Company", "VARCHAR(20)", NoNulls, 1),
907 ("Business", "", "Account", "Branch", "VARCHAR(20)", NoNulls, 2),
908 ("Business", "", "Account", "Amount", "DECIMAL(10, 2)", NoNulls, 3),
909 ("Business", "", "Account", "Active", "BIT", NoNulls, 4),
910 ("Business", "", "Person", "Forename", "VARCHAR(20)", NoNulls, 1),
911 ("Business", "", "Person", "Surname", "VARCHAR(20)", NoNulls, 2),
912 ("Business", "", "Person", "Address", "VARCHAR(20)", Nullable, 3),
913 ("Business", "", "Person", "Birthday", "DATE", Nullable, 4),
914 ]);
915 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), None), "PErson"), vec![
916 ("Business", "", "Person", "Forename", "VARCHAR(20)", NoNulls, 1),
917 ("Business", "", "Person", "Surname", "VARCHAR(20)", NoNulls, 2),
918 ("Business", "", "Person", "Address", "VARCHAR(20)", Nullable, 3),
919 ("Business", "", "Person", "Birthday", "DATE", Nullable, 4),
920 ]);
921 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), None), "ARchive"), vec![
922 ("Archive", "", "Article", "Journal", "INTEGER", NoNulls, 1),
923 ("Archive", "", "Article", "Date", "DATE", NoNulls, 2),
924 ("Archive", "", "Article", "Author", "VARCHAR(20)", NoNulls, 3),
925 ("Archive", "", "Article", "Text", "VARCHAR(4000)", NoNulls, 4),
926 ("Archive", "", "Article", "Appendix", "VARCHAR(4000)", Nullable, 5),
927 ("Archive", "", "Journal", "Country", "INTEGER", NoNulls, 1),
928 ("Archive", "", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2),
929 ("Archive", "", "Journal", "Available", "BIT", NoNulls, 3),
930 ]);
931 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), None), "ARchive.JOurnal"), vec![
932 ("Archive", "", "Journal", "Country", "INTEGER", NoNulls, 1),
933 ("Archive", "", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2),
934 ("Archive", "", "Journal", "Available", "BIT", NoNulls, 3),
935 ]);
936 assert_eq!(get_columns(&catalog, Context::new(Some("BUsiness"), None), "UNknown").is_empty(), true);
937 }
938
939 #[test]
940 fn test_columns_are_returned_for_show_with_sqlite_model() {
941 let catalog = create_catalog(Model::Sqlite);
942 assert_eq!(get_columns(&catalog, Context::default(), ""), vec![
943 ("", "", "Account", "Company", "VARCHAR(20)", NoNulls, 1),
944 ("", "", "Account", "Branch", "VARCHAR(20)", NoNulls, 2),
945 ("", "", "Account", "Amount", "DECIMAL(10, 2)", NoNulls, 3),
946 ("", "", "Account", "Active", "BIT", NoNulls, 4),
947 ("", "", "Person", "Forename", "VARCHAR(20)", NoNulls, 1),
948 ("", "", "Person", "Surname", "VARCHAR(20)", NoNulls, 2),
949 ("", "", "Person", "Address", "VARCHAR(20)", Nullable, 3),
950 ("", "", "Person", "Birthday", "DATE", Nullable, 4),
951 ]);
952 assert_eq!(get_columns(&catalog, Context::default(), "PErson"), vec![
953 ("", "", "Person", "Forename", "VARCHAR(20)", NoNulls, 1),
954 ("", "", "Person", "Surname", "VARCHAR(20)", NoNulls, 2),
955 ("", "", "Person", "Address", "VARCHAR(20)", Nullable, 3),
956 ("", "", "Person", "Birthday", "DATE", Nullable, 4),
957 ]);
958 assert_eq!(get_columns(&catalog, Context::default(), "UNknown").is_empty(), true);
959 }
960
961 #[test]
962 fn test_procedures_are_returned_for_show_with_tsql_model() {
963 let catalog = create_catalog(Model::TSQL);
964 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), Some("MAin")), ""), vec![
965 ("Business", "Main", "Advertise"),
966 ("Business", "Main", "Recruit"),
967 ]);
968 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), Some("MAin")), "ADmin"), vec![
969 ("Business", "Admin", "Activate"),
970 ]);
971 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), Some("MAin")), "ARchive"), vec![
972 ("Archive", "Main", "Announce"),
973 ]);
974 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), Some("MAin")), "ARchive.MAin"), vec![
975 ("Archive", "Main", "Announce"),
976 ]);
977 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), Some("MAin")), "UNknown").is_empty(), true);
978 }
979
980 #[test]
981 fn test_procedures_are_returned_for_show_with_mysql_model() {
982 let catalog = create_catalog(Model::MySQL);
983 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), None), ""), vec![
984 ("Business", "", "Advertise"),
985 ("Business", "", "Recruit"),
986 ]);
987 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), None), "ARchive"), vec![
988 ("Archive", "", "Announce"),
989 ]);
990 assert_eq!(catalog.get_procedures(Context::new(Some("BUsiness"), None), "UNknown").is_empty(), true);
991 }
992
993 #[test]
994 fn test_procedures_are_returned_for_show_with_sqlite_model() {
995 let catalog = create_catalog(Model::Sqlite);
996 assert_eq!(catalog.get_procedures(Context::default(), ""), vec![
997 ("", "", "Advertise"),
998 ("", "", "Recruit"),
999 ]);
1000 assert_eq!(catalog.get_procedures(Context::default(), "UNknown").is_empty(), true);
1001 }
1002
1003 #[test]
1004 fn test_keywords_are_returned_for_show() {
1005 let catalog = create_catalog(Model::TSQL);
1006 assert_eq!(catalog.get_keywords(), vec![
1007 "ADD",
1008 "ALTER",
1009 "AND",
1010 "AS",
1011 "SELECT",
1012 "SET",
1013 ]);
1014 }
1015
1016 #[test]
1017 fn test_functions_are_returned_for_show() {
1018 let catalog = create_catalog(Model::TSQL);
1019 assert_eq!(catalog.get_functions(), vec![
1020 "ABS",
1021 "COUNT",
1022 ]);
1023 }
1024
1025 fn complete_line(
1026 catalog: &Catalog,
1027 context: (Option<&str>, Option<&str>),
1028 line: &str,
1029 ) -> (usize, Vec<String>) {
1030 let (database, schema) = context;
1031 let context = Context::new(database, schema);
1032 catalog.complete_line(context, line, line.len())
1033 }
1034
1035 fn get_columns<'a>(
1036 catalog: &'a Catalog,
1037 context: Context,
1038 line: &str,
1039 ) -> Vec<(&'a str, &'a str, &'a str, &'a str, &'a str, Nullability, usize)> {
1040 let mut transformed = Vec::new();
1041 for (database, schema, table, column, payload) in catalog.get_columns(context, line) {
1042 if let Some(payload) = payload {
1043 let Payload { dtype, null, index } = payload;
1044 transformed.push((database, schema, table, column, dtype.as_str(), *null, *index));
1045 }
1046 }
1047 transformed
1048 }
1049
1050 enum Model {
1051 Sqlite,
1052 MySQL,
1053 TSQL,
1054 }
1055
1056 impl Model {
1057 fn includes_database(&self) -> bool {
1058 match self {
1059 Self::Sqlite => false,
1060 Self::MySQL => true,
1061 Self::TSQL => true,
1062 }
1063 }
1064
1065 fn includes_schema(&self) -> bool {
1066 match self {
1067 Self::Sqlite => false,
1068 Self::MySQL => false,
1069 Self::TSQL => true,
1070 }
1071 }
1072 }
1073
1074 fn create_catalog(model: Model) -> Catalog {
1075 let mut catalog = Catalog::new();
1077 insert_directive(&mut catalog, ":format", "table");
1078 insert_directive(&mut catalog, ":format", "flatten");
1079 insert_directive(&mut catalog, ":show", "databases");
1080 insert_directive(&mut catalog, ":show", "tables");
1081 insert_directive(&mut catalog, ":show", "columns");
1082 insert_directive(&mut catalog, ":show", "procedures");
1083 insert_directive(&mut catalog, ":show", "keywords");
1084 insert_directive(&mut catalog, ":show", "functions");
1085 if model.includes_database() {
1086 if model.includes_schema() {
1087 insert_database(&mut catalog, "Archive", "Main");
1089 insert_table(&mut catalog, "Archive", "Main", "Article");
1090 insert_column(&mut catalog, "Archive", "Main", "Article", "Journal", "INTEGER", NoNulls, 1);
1091 insert_column(&mut catalog, "Archive", "Main", "Article", "Date", "DATE", NoNulls, 2);
1092 insert_column(&mut catalog, "Archive", "Main", "Article", "Author", "VARCHAR(20)", NoNulls, 3);
1093 insert_column(&mut catalog, "Archive", "Main", "Article", "Text", "VARCHAR(4000)", NoNulls, 4);
1094 insert_column(&mut catalog, "Archive", "Main", "Article", "Appendix", "VARCHAR(4000)", Nullable, 5);
1095 insert_table(&mut catalog, "Archive", "Main", "Journal");
1096 insert_column(&mut catalog, "Archive", "Main", "Journal", "Country", "INTEGER", NoNulls, 1);
1097 insert_column(&mut catalog, "Archive", "Main", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2);
1098 insert_column(&mut catalog, "Archive", "Main", "Journal", "Available", "BIT", NoNulls, 3);
1099 insert_procedure(&mut catalog, "Archive", "Main", "Announce");
1100 insert_database(&mut catalog, "Business", "Admin");
1102 insert_table(&mut catalog, "Business", "Admin", "Server");
1103 insert_column(&mut catalog, "Business", "Admin", "Server", "Name", "VARCHAR(20)", NoNulls, 1);
1104 insert_column(&mut catalog, "Business", "Admin", "Server", "Location", "VARCHAR(20)", NoNulls, 2);
1105 insert_column(&mut catalog, "Business", "Admin", "Server", "Hardware", "VARCHAR(20)", NoNulls, 3);
1106 insert_procedure(&mut catalog, "Business", "Admin", "Activate");
1107 insert_database(&mut catalog, "Business", "Main");
1108 insert_table(&mut catalog, "Business", "Main", "Account");
1109 insert_column(&mut catalog, "Business", "Main", "Account", "Company", "VARCHAR(20)", NoNulls, 1);
1110 insert_column(&mut catalog, "Business", "Main", "Account", "Branch", "VARCHAR(20)", NoNulls, 2);
1111 insert_column(&mut catalog, "Business", "Main", "Account", "Amount", "DECIMAL(10, 2)", NoNulls, 3);
1112 insert_column(&mut catalog, "Business", "Main", "Account", "Active", "BIT", NoNulls, 4);
1113 insert_table(&mut catalog, "Business", "Main", "Person");
1114 insert_column(&mut catalog, "Business", "Main", "Person", "Forename", "VARCHAR(20)", NoNulls, 1);
1115 insert_column(&mut catalog, "Business", "Main", "Person", "Surname", "VARCHAR(20)", NoNulls, 2);
1116 insert_column(&mut catalog, "Business", "Main", "Person", "Address", "VARCHAR(20)", Nullable, 3);
1117 insert_column(&mut catalog, "Business", "Main", "Person", "Birthday", "DATE", Nullable, 4);
1118 insert_procedure(&mut catalog, "Business", "Main", "Advertise");
1119 insert_procedure(&mut catalog, "Business", "Main", "Recruit");
1120 } else {
1121 insert_database(&mut catalog, "Archive", "");
1123 insert_table(&mut catalog, "Archive", "", "Article");
1124 insert_column(&mut catalog, "Archive", "", "Article", "Journal", "INTEGER", NoNulls, 1);
1125 insert_column(&mut catalog, "Archive", "", "Article", "Date", "DATE", NoNulls, 2);
1126 insert_column(&mut catalog, "Archive", "", "Article", "Author", "VARCHAR(20)", NoNulls, 3);
1127 insert_column(&mut catalog, "Archive", "", "Article", "Text", "VARCHAR(4000)", NoNulls, 4);
1128 insert_column(&mut catalog, "Archive", "", "Article", "Appendix", "VARCHAR(4000)", Nullable, 5);
1129 insert_table(&mut catalog, "Archive", "", "Journal");
1130 insert_column(&mut catalog, "Archive", "", "Journal", "Country", "INTEGER", NoNulls, 1);
1131 insert_column(&mut catalog, "Archive", "", "Journal", "Price", "DECIMAL(10, 2)", NoNulls, 2);
1132 insert_column(&mut catalog, "Archive", "", "Journal", "Available", "BIT", NoNulls, 3);
1133 insert_procedure(&mut catalog, "Archive", "", "Announce");
1134 insert_database(&mut catalog, "Business", "");
1136 insert_table(&mut catalog, "Business", "", "Account");
1137 insert_column(&mut catalog, "Business", "", "Account", "Company", "VARCHAR(20)", NoNulls, 1);
1138 insert_column(&mut catalog, "Business", "", "Account", "Branch", "VARCHAR(20)", NoNulls, 2);
1139 insert_column(&mut catalog, "Business", "", "Account", "Amount", "DECIMAL(10, 2)", NoNulls, 3);
1140 insert_column(&mut catalog, "Business", "", "Account", "Active", "BIT", NoNulls, 4);
1141 insert_table(&mut catalog, "Business", "", "Person");
1142 insert_column(&mut catalog, "Business", "", "Person", "Forename", "VARCHAR(20)", NoNulls, 1);
1143 insert_column(&mut catalog, "Business", "", "Person", "Surname", "VARCHAR(20)", NoNulls, 2);
1144 insert_column(&mut catalog, "Business", "", "Person", "Address", "VARCHAR(20)", Nullable, 3);
1145 insert_column(&mut catalog, "Business", "", "Person", "Birthday", "DATE", Nullable, 4);
1146 insert_procedure(&mut catalog, "Business", "", "Advertise");
1147 insert_procedure(&mut catalog, "Business", "", "Recruit");
1148 }
1149 } else {
1150 insert_table(&mut catalog, "", "", "Account");
1152 insert_column(&mut catalog, "", "", "Account", "Company", "VARCHAR(20)", NoNulls, 1);
1153 insert_column(&mut catalog, "", "", "Account", "Branch", "VARCHAR(20)", NoNulls, 2);
1154 insert_column(&mut catalog, "", "", "Account", "Amount", "DECIMAL(10, 2)", NoNulls, 3);
1155 insert_column(&mut catalog, "", "", "Account", "Active", "BIT", NoNulls, 4);
1156 insert_table(&mut catalog, "", "", "Person");
1157 insert_column(&mut catalog, "", "", "Person", "Forename", "VARCHAR(20)", NoNulls, 1);
1158 insert_column(&mut catalog, "", "", "Person", "Surname", "VARCHAR(20)", NoNulls, 2);
1159 insert_column(&mut catalog, "", "", "Person", "Address", "VARCHAR(20)", Nullable, 3);
1160 insert_column(&mut catalog, "", "", "Person", "Birthday", "DATE", Nullable, 4);
1161 insert_procedure(&mut catalog, "", "", "Advertise");
1162 insert_procedure(&mut catalog, "", "", "Recruit");
1163 }
1164 insert_keyword(&mut catalog, "ADD");
1166 insert_keyword(&mut catalog, "ALTER");
1167 insert_keyword(&mut catalog, "AND");
1168 insert_keyword(&mut catalog, "AS");
1169 insert_keyword(&mut catalog, "SELECT");
1170 insert_keyword(&mut catalog, "SET");
1171 insert_function(&mut catalog, "ABS");
1173 insert_function(&mut catalog, "COUNT");
1174 catalog
1175 }
1176
1177 fn insert_directive(
1178 catalog: &mut Catalog,
1179 verb: &str,
1180 noun: &str,
1181 ) {
1182 catalog.insert_directive(
1183 Cow::Borrowed(verb),
1184 Cow::Borrowed(noun),
1185 );
1186 }
1187
1188 fn insert_database(
1189 catalog: &mut Catalog,
1190 database: &str,
1191 schema: &str,
1192 ) {
1193 catalog.insert_database(
1194 Cow::Borrowed(database),
1195 Cow::Borrowed(schema),
1196 );
1197 }
1198
1199 fn insert_table(
1200 catalog: &mut Catalog,
1201 database: &str,
1202 schema: &str,
1203 table: &str,
1204 ) {
1205 catalog.insert_table(
1206 Cow::Borrowed(database),
1207 Cow::Borrowed(schema),
1208 Cow::Borrowed(table),
1209 );
1210 }
1211
1212 fn insert_column(
1213 catalog: &mut Catalog,
1214 database: &str,
1215 schema: &str,
1216 table: &str,
1217 column: &str,
1218 dtype: &str,
1219 null: Nullability,
1220 index: usize,
1221 ) {
1222 catalog.insert_column(
1223 Cow::Borrowed(database),
1224 Cow::Borrowed(schema),
1225 Cow::Borrowed(table),
1226 Cow::Borrowed(column),
1227 Cow::Borrowed(dtype),
1228 null,
1229 index,
1230 );
1231 }
1232
1233 fn insert_procedure(
1234 catalog: &mut Catalog,
1235 database: &str,
1236 schema: &str,
1237 procedure: &str,
1238 ) {
1239 catalog.insert_procedure(
1240 Cow::Borrowed(database),
1241 Cow::Borrowed(schema),
1242 Cow::Borrowed(procedure),
1243 );
1244 }
1245
1246 fn insert_keyword(catalog: &mut Catalog, keyword: &str) {
1247 catalog.insert_keyword(Cow::Borrowed(keyword));
1248 }
1249
1250 fn insert_function(catalog: &mut Catalog, function: &str) {
1251 catalog.insert_function(Cow::Borrowed(function));
1252 }
1253}