drasi_source_sqlite/
descriptor.rs1use crate::config::{RestApiConfig, SqliteSourceConfig, TableKeyConfig};
18use drasi_plugin_sdk::prelude::*;
19use utoipa::OpenApi;
20
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
25#[schema(as = source::sqlite::SqliteSourceConfig)]
26#[serde(rename_all = "camelCase", deny_unknown_fields)]
27pub struct SqliteSourceConfigDto {
28 #[serde(default)]
30 #[schema(value_type = Option<ConfigValueString>)]
31 pub path: Option<ConfigValue<String>>,
32
33 #[serde(default)]
35 pub tables: Option<Vec<String>>,
36
37 #[serde(default)]
39 #[schema(value_type = Vec<source::sqlite::TableKeyConfig>)]
40 pub table_keys: Vec<TableKeyConfigDto>,
41
42 #[serde(default)]
44 #[schema(value_type = Option<source::sqlite::RestApiConfig>)]
45 pub rest_api: Option<RestApiConfigDto>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
50#[schema(as = source::sqlite::RestApiConfig)]
51#[serde(rename_all = "camelCase", deny_unknown_fields)]
52pub struct RestApiConfigDto {
53 #[serde(default = "default_rest_host")]
55 #[schema(value_type = ConfigValueString)]
56 pub host: ConfigValue<String>,
57
58 #[serde(default = "default_rest_port")]
60 #[schema(value_type = ConfigValueU16)]
61 pub port: ConfigValue<u16>,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
66#[schema(as = source::sqlite::TableKeyConfig)]
67#[serde(rename_all = "camelCase", deny_unknown_fields)]
68pub struct TableKeyConfigDto {
69 pub table: String,
70 pub key_columns: Vec<String>,
71}
72
73impl From<&TableKeyConfig> for TableKeyConfigDto {
76 fn from(tk: &TableKeyConfig) -> Self {
77 Self {
78 table: tk.table.clone(),
79 key_columns: tk.key_columns.clone(),
80 }
81 }
82}
83
84impl From<&RestApiConfig> for RestApiConfigDto {
85 fn from(config: &RestApiConfig) -> Self {
86 Self {
87 host: ConfigValue::Static(config.host.clone()),
88 port: ConfigValue::Static(config.port),
89 }
90 }
91}
92
93impl From<&SqliteSourceConfig> for SqliteSourceConfigDto {
94 fn from(config: &SqliteSourceConfig) -> Self {
95 Self {
96 path: config.path.as_ref().map(|p| ConfigValue::Static(p.clone())),
97 tables: config.tables.clone(),
98 table_keys: config
99 .table_keys
100 .iter()
101 .map(TableKeyConfigDto::from)
102 .collect(),
103 rest_api: config.rest_api.as_ref().map(RestApiConfigDto::from),
104 }
105 }
106}
107
108fn default_rest_host() -> ConfigValue<String> {
109 ConfigValue::Static("0.0.0.0".to_string())
110}
111
112fn default_rest_port() -> ConfigValue<u16> {
113 ConfigValue::Static(8080)
114}
115
116#[derive(OpenApi)]
119#[openapi(components(schemas(SqliteSourceConfigDto, RestApiConfigDto, TableKeyConfigDto,)))]
120struct SqliteSourceSchemas;
121
122pub struct SqliteSourceDescriptor;
126
127#[async_trait]
128impl SourcePluginDescriptor for SqliteSourceDescriptor {
129 fn kind(&self) -> &str {
130 "sqlite"
131 }
132
133 fn config_version(&self) -> &str {
134 "1.0.0"
135 }
136
137 fn config_schema_name(&self) -> &str {
138 "source.sqlite.SqliteSourceConfig"
139 }
140
141 fn config_schema_json(&self) -> String {
142 let api = SqliteSourceSchemas::openapi();
143 serde_json::to_string(
144 &api.components
145 .as_ref()
146 .expect("OpenAPI components missing")
147 .schemas,
148 )
149 .expect("Failed to serialize config schema")
150 }
151
152 async fn create_source(
153 &self,
154 id: &str,
155 config_json: &serde_json::Value,
156 auto_start: bool,
157 ) -> anyhow::Result<Box<dyn drasi_lib::sources::Source>> {
158 let dto: SqliteSourceConfigDto = serde_json::from_value(config_json.clone())?;
159 let mapper = DtoMapper::new();
160
161 let path = match &dto.path {
162 Some(cv) => Some(mapper.resolve_string(cv).await?),
163 None => None,
164 };
165
166 let rest_api = match &dto.rest_api {
167 Some(rest_dto) => Some(RestApiConfig {
168 host: mapper.resolve_string(&rest_dto.host).await?,
169 port: mapper.resolve_typed(&rest_dto.port).await?,
170 }),
171 None => None,
172 };
173
174 let table_keys = dto
175 .table_keys
176 .iter()
177 .map(|tk| TableKeyConfig {
178 table: tk.table.clone(),
179 key_columns: tk.key_columns.clone(),
180 })
181 .collect();
182
183 let config = SqliteSourceConfig {
184 path,
185 tables: dto.tables,
186 table_keys,
187 rest_api,
188 ..Default::default()
189 };
190
191 let mut builder = crate::SqliteSourceBuilder::new(id);
192 if let Some(p) = &config.path {
193 builder = builder.with_path(p);
194 }
195 if let Some(tables) = config.tables {
196 builder = builder.with_tables(tables);
197 }
198 if !config.table_keys.is_empty() {
199 builder = builder.with_table_keys(config.table_keys);
200 }
201 if let Some(rest) = config.rest_api {
202 builder = builder.with_rest_api(rest);
203 }
204 builder = builder.auto_start(auto_start);
205
206 let mut source = builder.build()?;
207 source.base.set_raw_config(config_json.clone());
208
209 Ok(Box::new(source))
210 }
211}