Line data Source code
1 : //! Relations created during a shell session, published as a descriptor entry of the catalog.
2 :
3 : use dashql_core_session::catalog_changes::{derive_catalog_change, qualify_catalog_changes, CatalogChangeOptions, CatalogNameDefaults};
4 : use dashql_core::catalog::{Catalog, CatalogEntryId, CatalogLayer};
5 : use dashql_core::script::Script;
6 :
7 : const SESSION_SCHEMA: &str = "public";
8 :
9 : /// The relations of successful DDL statements
10 : pub struct SessionRelationCatalog {
11 : /// The script that analyzes the successful queries
12 : parser_script: Script,
13 : /// The descriptor entry with the relations
14 : entry_id: CatalogEntryId,
15 : /// How the queries are turned into catalog changes
16 : options: CatalogChangeOptions,
17 : /// The names that qualify unqualified relations
18 : defaults: CatalogNameDefaults,
19 : }
20 :
21 : impl SessionRelationCatalog {
22 5 : pub fn new(catalog: &Catalog) -> Self {
23 5 : Self {
24 5 : parser_script: Script::new(catalog),
25 5 : entry_id: catalog.allocate_entry_id(),
26 5 : // The relations live as long as the session, temporary ones included
27 5 : options: CatalogChangeOptions { include_temporary: true },
28 5 : defaults: CatalogNameDefaults {
29 5 : database_name: String::new(),
30 5 : schema_name: SESSION_SCHEMA.to_string(),
31 5 : },
32 5 : }
33 5 : }
34 :
35 : /// Remove the published relations from the catalog
36 5 : pub fn detach(&self, catalog: &mut Catalog) {
37 5 : catalog.drop_script(self.parser_script.catalog_entry_id());
38 5 : let _ = catalog.drop_descriptor(self.entry_id);
39 5 : }
40 :
41 : /// Track the relation of a query that succeeded. Errors of the local analysis leave
42 : /// the catalog as it is, the remote engine may accept syntax that the local analyzer does not understand.
43 13 : pub fn apply_successful_query(&mut self, query: &str, catalog: &mut Catalog) {
44 13 : self.parser_script.replace_text(query);
45 13 : if self.parser_script.analyze(catalog, true).is_err() {
46 0 : return;
47 13 : }
48 13 : let Some(analyzed) = self.parser_script.analyzed.clone() else {
49 0 : return;
50 : };
51 13 : let parsed = &analyzed.parsed;
52 13 : if !parsed.errors.is_empty() || !parsed.scanned.errors.is_empty() || parsed.statements.len() != 1 {
53 1 : return;
54 12 : }
55 12 : if let Some(change) = derive_catalog_change(&analyzed, 0, &self.options) {
56 11 : let mut changes = [change];
57 11 : qualify_catalog_changes(&mut changes, &self.defaults);
58 11 : let _ = catalog.apply_catalog_changes(self.entry_id, CatalogLayer::EXECUTED, &changes);
59 11 : }
60 13 : }
61 : }
|