Skip to main content

drasi_bootstrap_sqlite/
descriptor.rs

1// Copyright 2025 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! SQLite bootstrap plugin descriptor and configuration DTOs.
16
17use crate::{SqliteBootstrapProvider, TableKeyConfig};
18use drasi_plugin_sdk::prelude::*;
19use utoipa::OpenApi;
20
21// ── DTO types ────────────────────────────────────────────────────────────────
22
23/// SQLite bootstrap configuration DTO.
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
25#[schema(as = bootstrap::sqlite::SqliteBootstrapConfig)]
26#[serde(rename_all = "camelCase", deny_unknown_fields)]
27pub struct SqliteBootstrapConfigDto {
28    /// SQLite file path. Omit or set to null for an in-memory database (bootstrap will be skipped).
29    #[serde(default)]
30    #[schema(value_type = Option<ConfigValueString>)]
31    pub path: Option<ConfigValue<String>>,
32
33    /// Optional table allow-list. Omit or set to null for all user tables.
34    #[serde(default)]
35    pub tables: Option<Vec<String>>,
36
37    /// Optional explicit key config for element ID generation.
38    #[serde(default)]
39    #[schema(value_type = Vec<bootstrap::sqlite::TableKeyConfig>)]
40    pub table_keys: Vec<TableKeyConfigDto>,
41}
42
43/// Table key configuration DTO.
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
45#[schema(as = bootstrap::sqlite::TableKeyConfig)]
46#[serde(rename_all = "camelCase", deny_unknown_fields)]
47pub struct TableKeyConfigDto {
48    pub table: String,
49    pub key_columns: Vec<String>,
50}
51
52// ── OpenAPI schema ───────────────────────────────────────────────────────────
53
54#[derive(OpenApi)]
55#[openapi(components(schemas(SqliteBootstrapConfigDto, TableKeyConfigDto,)))]
56struct SqliteBootstrapSchemas;
57
58// ── Descriptor ───────────────────────────────────────────────────────────────
59
60/// Plugin descriptor for the SQLite bootstrap provider.
61pub struct SqliteBootstrapDescriptor;
62
63#[async_trait]
64impl BootstrapPluginDescriptor for SqliteBootstrapDescriptor {
65    fn kind(&self) -> &str {
66        "sqlite"
67    }
68
69    fn config_version(&self) -> &str {
70        "1.0.0"
71    }
72
73    fn config_schema_name(&self) -> &str {
74        "bootstrap.sqlite.SqliteBootstrapConfig"
75    }
76
77    fn config_schema_json(&self) -> String {
78        let api = SqliteBootstrapSchemas::openapi();
79        serde_json::to_string(
80            &api.components
81                .as_ref()
82                .expect("OpenAPI components missing")
83                .schemas,
84        )
85        .expect("Failed to serialize config schema")
86    }
87
88    async fn create_bootstrap_provider(
89        &self,
90        config_json: &serde_json::Value,
91        _source_config_json: &serde_json::Value,
92    ) -> anyhow::Result<Box<dyn drasi_lib::bootstrap::BootstrapProvider>> {
93        let dto: SqliteBootstrapConfigDto = serde_json::from_value(config_json.clone())?;
94        let mapper = DtoMapper::new();
95
96        let mut builder = SqliteBootstrapProvider::builder();
97
98        if let Some(path_cv) = &dto.path {
99            builder = builder.with_path(mapper.resolve_string(path_cv).await?);
100        }
101
102        if let Some(tables) = dto.tables {
103            builder = builder.with_tables(tables);
104        }
105
106        let table_keys = dto
107            .table_keys
108            .into_iter()
109            .map(|tk| TableKeyConfig {
110                table: tk.table,
111                key_columns: tk.key_columns,
112            })
113            .collect::<Vec<_>>();
114
115        if !table_keys.is_empty() {
116            builder = builder.with_table_keys(table_keys);
117        }
118
119        Ok(Box::new(builder.build()))
120    }
121}