teo_parser/search/
search_availability.rs

1use crate::ast::arith_expr::ArithExpr;
2use crate::availability::Availability;
3use crate::ast::config::Config;
4use crate::ast::literals::EnumVariantLiteral;
5use crate::ast::namespace::Namespace;
6use crate::ast::schema::Schema;
7use crate::ast::source::Source;
8use crate::traits::named_identifiable::NamedIdentifiable;
9
10pub(crate) fn search_availability(schema: &Schema, source: &Source, namespace_path: &Vec<&str>) -> Availability {
11    if namespace_path.len() == 0 {
12        find_source_availability(schema, source)
13    } else {
14        if let Some(namespace) = source.find_child_namespace_by_string_path(namespace_path) {
15            find_namespace_availability(namespace, schema, source)
16        } else {
17            Availability::no_database()
18        }
19    }
20}
21
22pub(crate) fn find_source_availability(schema: &Schema, source: &Source) -> Availability {
23    if source.builtin {
24        return Availability::default(); // just pretend to be all
25    }
26    let connector = find_source_connector(schema, source);
27    let retval = find_availability_in_connector(connector);
28    retval
29}
30
31pub(crate) fn find_source_connector<'a>(schema: &'a Schema, source: &'a Source) -> Option<&'a Config> {
32    if let Some(connector) = source.get_connector() {
33        Some(connector)
34    } else {
35        source.imports().iter().find_map(|import| {
36            if let Some(source) = schema.source_at_path(&import.file_path) {
37                source.get_connector()
38            } else {
39                None
40            }
41        })
42    }
43}
44
45pub(crate) fn find_availability_in_connector(connector: Option<&Config>) -> Availability {
46    if let Some(connector) = connector {
47        if let Some(provider) = connector.items().iter().find(|(key, _)| {
48            if let Some(key) = key.named_key_without_resolving() {
49                key == "provider"
50            } else {
51                false
52            }
53        }) {
54            if let Some(enum_variant_literal) = provider.1.kind.as_enum_variant_literal() {
55                availability_from_enum_variant_literal(enum_variant_literal)
56            } else if let Some(unit) = provider.1.kind.as_unit() {
57                if let Some(enum_variant_literal) = unit.expressions().next().unwrap().kind.as_enum_variant_literal() {
58                    availability_from_enum_variant_literal(enum_variant_literal)
59                } else {
60                    Availability::no_database()
61                }
62            } else if let Some(arith) = provider.1.kind.as_arith_expr() {
63                match arith {
64                    ArithExpr::Expression(e) => {
65                        if let Some(unit) = e.kind.as_unit() {
66                            if let Some(enum_variant_literal) = unit.expressions().next().unwrap().kind.as_enum_variant_literal() {
67                                availability_from_enum_variant_literal(enum_variant_literal)
68                            } else {
69                                Availability::no_database()
70                            }
71                        } else if let Some(e) = e.kind.as_enum_variant_literal() {
72                            availability_from_enum_variant_literal(e)
73                        } else {
74                            Availability::no_database()
75                        }
76                    }
77                    _ => Availability::no_database(),
78                }
79            } else {
80                Availability::no_database()
81            }
82        } else {
83            Availability::no_database()
84        }
85    } else {
86        Availability::no_database()
87    }
88}
89
90pub(crate) fn find_namespace_availability(namespace: &Namespace, schema: &Schema, source: &Source) -> Availability {
91    if source.builtin {
92        return Availability::default(); // just pretend to be all
93    }
94    let connector = find_namespace_connector(namespace, schema, source);
95    find_availability_in_connector(connector)
96}
97
98pub(crate) fn find_namespace_connector<'a>(namespace: &'a Namespace, schema: &'a Schema, source: &'a Source) -> Option<&'a Config> {
99    // Namespace
100    // Imported files same namespace
101    // Parent namespace
102    // Imported files parent namespace
103    // Source file
104    // Imported source files
105    if let Some(connector) = namespace.get_connector() {
106        Some(connector)
107    } else {
108        let connector = source.imports().iter().find_map(|import| {
109            if let Some(source) = schema.source_at_path(&import.file_path) {
110                if let Some(namespace) = source.find_child_namespace_by_string_path(&namespace.str_path()) {
111                    namespace.get_connector()
112                } else {
113                    None
114                }
115            } else {
116                None
117            }
118        });
119        if let Some(connector) = connector {
120            return Some(connector);
121        }
122        let mut parent_namespace = source.parent_namespace_for_namespace(namespace);
123        loop {
124            if parent_namespace.is_some() {
125                if let Some(connector) = parent_namespace.unwrap().get_connector() {
126                    return Some(connector);
127                } else {
128                    let connector = source.imports().iter().find_map(|import| {
129                        if let Some(source) = schema.source_at_path(&import.file_path) {
130                            if let Some(namespace) = source.find_child_namespace_by_string_path(&namespace.str_path()) {
131                                namespace.get_connector()
132                            } else {
133                                None
134                            }
135                        } else {
136                            None
137                        }
138                    });
139                    if let Some(connector) = connector {
140                        return Some(connector);
141                    }
142                }
143                parent_namespace = source.parent_namespace_for_namespace(parent_namespace.unwrap());
144            } else {
145                break
146            }
147        }
148        return find_source_connector(schema, source);
149    }
150}
151
152fn availability_from_enum_variant_literal(e: &EnumVariantLiteral) -> Availability {
153    match e.identifier().name() {
154        "mongo" => Availability::mongo(),
155        "mysql" => Availability::mysql(),
156        "postgres" => Availability::postgres(),
157        "sqlite" => Availability::sqlite(),
158        _ => Availability::no_database(),
159    }
160}