1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
use std::process::exit;
use teo_parser::ast::reference_space::ReferenceSpace;
use teo_parser::ast::schema::Schema;
use teo_parser::ast::span::Span;
use teo_parser::diagnostics::diagnostics::{Diagnostics, DiagnosticsError};
use teo_parser::diagnostics::printer::print_diagnostics;
use teo_parser::traits::has_availability::HasAvailability;
use teo_parser::traits::identifiable::Identifiable;
use teo_parser::traits::info_provider::InfoProvider;
use teo_parser::traits::named_identifiable::NamedIdentifiable;
use teo_parser::traits::node_trait::NodeTrait;
use crate::namespace::Namespace;
use teo_result::Result;
use crate::schema::load::load_client::load_client;
use crate::schema::load::load_connector::load_connector;
use crate::schema::load::load_database_information::load_database_information;
use crate::schema::load::load_debug::load_debug;
use crate::schema::load::load_entity::load_entity;
use crate::schema::load::load_enum::load_enum;
use crate::schema::load::load_handler::load_handler;
use crate::schema::load::load_handler_group::load_handler_group;
use crate::schema::load::load_interface::load_interface;
use crate::schema::load::load_model::load_model;
use crate::schema::load::load_model_opposite_relations::load_model_opposite_relations;
use crate::schema::load::load_server::load_server;
use crate::schema::load::load_test::load_test;
use crate::schema::load::load_use_middlewares::load_use_middlewares;

pub async fn load_schema(main_namespace: &mut Namespace, schema: &Schema, ignores_loading: bool) -> Result<()> {

    // diagnostics for schema loading
    let mut diagnostics = Diagnostics::new();

    // some of these are just load from schema, while some are validate and load

    // setup namespaces, this is used for recursively setting database information
    for namespace in schema.namespaces() {
        let _ = main_namespace.namespace_mut_or_create_at_path(&namespace.str_path());
    }

    // load server
    let mut server_loaded = false;
    if let Some(server) = schema.server() {
        if server.is_available() {
            load_server(main_namespace, schema, server, &mut diagnostics)?;
            server_loaded = true;
        }
    }
    if !server_loaded {
        let source = schema.main_source();
        diagnostics.insert(DiagnosticsError::new(Span::default(), "server config is not found", source.file_path.clone()));
    }

    // load connectors
    for connector in schema.connectors() {
        if connector.is_available() {
            load_connector(main_namespace, schema, connector, &mut diagnostics)?;
        }
    }

    // setting up database information
    load_database_information(main_namespace);

    // load debug
    if let Some(debug) = schema.debug() {
        if debug.is_available() {
            load_debug(main_namespace, schema, debug, &mut diagnostics)?;
        }
    }

    // load test
    if let Some(test) = schema.debug() {
        if test.is_available() {
            load_test(main_namespace, schema, test, &mut diagnostics)?;
        }
    }

    // load entities
    for entity in schema.entities() {
        if entity.is_available() {
            load_entity(main_namespace, schema, entity, &mut diagnostics)?;
        }
    }

    // load clients
    for debug in schema.clients() {
        if debug.is_available() {
            load_client(main_namespace, schema, debug, &mut diagnostics)?;
        }
    }

    if !ignores_loading {

        // validate decorator declarations
        for decorator_declaration in schema.decorator_declarations() {
            let dest_namespace = main_namespace.namespace_mut_or_create_at_path(&decorator_declaration.namespace_str_path());
            match decorator_declaration.decorator_class {
                ReferenceSpace::EnumDecorator => if dest_namespace.enum_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "enum decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::EnumMemberDecorator => if dest_namespace.enum_member_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "enum member decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::ModelDecorator => if dest_namespace.model_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "model decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::ModelFieldDecorator => if dest_namespace.model_field_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "model field decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::ModelRelationDecorator => if dest_namespace.model_relation_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "model relation decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::ModelPropertyDecorator => if dest_namespace.model_property_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "model property decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::InterfaceDecorator => if dest_namespace.interface_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "interface decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::InterfaceFieldDecorator => if dest_namespace.interface_field_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "interface field decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                ReferenceSpace::HandlerDecorator => if dest_namespace.handler_decorators.get(decorator_declaration.identifier().name()).is_none() {
                    diagnostics.insert(DiagnosticsError::new(decorator_declaration.identifier().span(), "handler decorator implementation is not found", schema.source(decorator_declaration.source_id()).unwrap().file_path.clone()))
                },
                _ => (),
            }
        }

        // validate pipeline item declarations
        for pipeline_item_declaration in schema.pipeline_item_declarations() {
            let dest_namespace = main_namespace.namespace_mut_or_create_at_path(&pipeline_item_declaration.namespace_str_path());
            if dest_namespace.pipeline_items.get(pipeline_item_declaration.identifier().name()).is_none() {
                diagnostics.insert(DiagnosticsError::new(pipeline_item_declaration.identifier().span(), "pipeline item implementation is not found", schema.source(pipeline_item_declaration.source_id()).unwrap().file_path.clone()))
            }
        }

        // validate struct declarations
        for struct_declaration in schema.struct_declarations() {
            let dest_namespace = main_namespace.namespace_mut_or_create_at_path(&struct_declaration.namespace_str_path());
            if let Some(struct_implementation) = dest_namespace.structs.get(struct_declaration.identifier().name()) {
                for function_declaration in struct_declaration.function_declarations() {
                    if function_declaration.r#static {
                        if struct_implementation.static_functions.get(function_declaration.identifier().name()).is_none() {
                            diagnostics.insert(DiagnosticsError::new(function_declaration.identifier().span(), "function implementation is not found", schema.source(struct_declaration.source_id()).unwrap().file_path.clone()));
                        }
                    } else {
                        if struct_implementation.functions.get(function_declaration.identifier().name()).is_none() {
                            diagnostics.insert(DiagnosticsError::new(function_declaration.identifier().span(), "function implementation is not found", schema.source(struct_declaration.source_id()).unwrap().file_path.clone()));
                        }
                    }
                }
            } else {
                diagnostics.insert(DiagnosticsError::new(struct_declaration.identifier().span(), "struct implementation is not found", schema.source(struct_declaration.source_id()).unwrap().file_path.clone()))
            }
        }

        // validate handlers
        for handler_declaration in schema.handler_declarations() {
            let dest_namespace = main_namespace.namespace_mut_or_create_at_path(&handler_declaration.namespace_str_path());
            if dest_namespace.handlers.get(handler_declaration.identifier().name()).is_none() {
                diagnostics.insert(DiagnosticsError::new(handler_declaration.identifier().span(), "handler implementation is not found", schema.source(handler_declaration.source_id()).unwrap().file_path.clone()));
            }
        }

        // validate handler groups
        for handler_group_declaration in schema.handler_group_declarations() {
            let dest_namespace = main_namespace.namespace_mut_or_create_at_path(&handler_group_declaration.namespace_str_path());
            if dest_namespace.handler_groups.get(handler_group_declaration.identifier().name()).is_none() {
                diagnostics.insert(DiagnosticsError::new(handler_group_declaration.identifier().span(), "handler group implementation is not found", schema.source(handler_group_declaration.source_id()).unwrap().file_path.clone()));
            }
            if let Some(group) = dest_namespace.handler_groups.get_mut(handler_group_declaration.identifier().name()) {
                for handler_declaration in handler_group_declaration.handler_declarations() {
                    if group.handlers.get(handler_declaration.name()).is_none() {
                        diagnostics.insert(DiagnosticsError::new(handler_declaration.identifier().span(), "handler implementation is not found", schema.source(handler_group_declaration.source_id()).unwrap().file_path.clone()));
                    }
                }
            }
        }

        // validate middleware declarations
        for middleware_declaration in schema.middleware_declarations() {
            let dest_namespace = main_namespace.namespace_mut_or_create_at_path(&middleware_declaration.namespace_str_path());
            if dest_namespace.middlewares.get(middleware_declaration.identifier().name()).is_none() {
                diagnostics.insert(DiagnosticsError::new(middleware_declaration.identifier().span(), "middleware implementation is not found", schema.source(middleware_declaration.source_id()).unwrap().file_path.clone()))
            }
        }

        // load middlewares
        load_use_middlewares(main_namespace, schema).await?;
    }

    // load enums
    for enum_declaration in schema.enums() {
        if enum_declaration.is_available() {
            load_enum(main_namespace, schema, enum_declaration, &mut diagnostics)?;
        }
    }

    // load interfaces
    for interface_declaration in schema.interfaces() {
        if interface_declaration.is_available() {
            load_interface(main_namespace, schema, interface_declaration, &mut diagnostics)?;
        }
    }

    // load models
    for model_declaration in schema.models() {
        let database = main_namespace.namespace_mut_or_create_at_path(&model_declaration.namespace_str_path()).database;
        if database.is_some() && model_declaration.is_available() {
            load_model(main_namespace, schema, model_declaration, &mut diagnostics)?;
        }
    }
    // load model opposite relations
    load_model_opposite_relations(main_namespace);

    // load handlers
    for handler_declaration in schema.handler_declarations() {
        load_handler(main_namespace, schema, handler_declaration, &mut diagnostics)?;
    }

    // load handler groups
    for handler_group_declaration in schema.handler_group_declarations() {
        load_handler_group(main_namespace, schema, handler_group_declaration, &mut diagnostics)?;
    }

    // load data set
    for data_set_declaration in schema.data_sets() {

    }

    // diagnostics
    if !ignores_loading {
        print_diagnostics(&diagnostics, true);
        if diagnostics.has_errors() {
            exit(1);
        }
    }

    Ok(())
}