use crate::config::{RestApiConfig, SqliteSourceConfig, TableKeyConfig};
use drasi_plugin_sdk::prelude::*;
use utoipa::OpenApi;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
#[schema(as = source::sqlite::SqliteSourceConfig)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct SqliteSourceConfigDto {
#[serde(default)]
#[schema(value_type = Option<ConfigValueString>)]
pub path: Option<ConfigValue<String>>,
#[serde(default)]
pub tables: Option<Vec<String>>,
#[serde(default)]
#[schema(value_type = Vec<source::sqlite::TableKeyConfig>)]
pub table_keys: Vec<TableKeyConfigDto>,
#[serde(default)]
#[schema(value_type = Option<source::sqlite::RestApiConfig>)]
pub rest_api: Option<RestApiConfigDto>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
#[schema(as = source::sqlite::RestApiConfig)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct RestApiConfigDto {
#[serde(default = "default_rest_host")]
#[schema(value_type = ConfigValueString)]
pub host: ConfigValue<String>,
#[serde(default = "default_rest_port")]
#[schema(value_type = ConfigValueU16)]
pub port: ConfigValue<u16>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
#[schema(as = source::sqlite::TableKeyConfig)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct TableKeyConfigDto {
pub table: String,
pub key_columns: Vec<String>,
}
impl From<&TableKeyConfig> for TableKeyConfigDto {
fn from(tk: &TableKeyConfig) -> Self {
Self {
table: tk.table.clone(),
key_columns: tk.key_columns.clone(),
}
}
}
impl From<&RestApiConfig> for RestApiConfigDto {
fn from(config: &RestApiConfig) -> Self {
Self {
host: ConfigValue::Static(config.host.clone()),
port: ConfigValue::Static(config.port),
}
}
}
impl From<&SqliteSourceConfig> for SqliteSourceConfigDto {
fn from(config: &SqliteSourceConfig) -> Self {
Self {
path: config.path.as_ref().map(|p| ConfigValue::Static(p.clone())),
tables: config.tables.clone(),
table_keys: config
.table_keys
.iter()
.map(TableKeyConfigDto::from)
.collect(),
rest_api: config.rest_api.as_ref().map(RestApiConfigDto::from),
}
}
}
fn default_rest_host() -> ConfigValue<String> {
ConfigValue::Static("0.0.0.0".to_string())
}
fn default_rest_port() -> ConfigValue<u16> {
ConfigValue::Static(8080)
}
#[derive(OpenApi)]
#[openapi(components(schemas(SqliteSourceConfigDto, RestApiConfigDto, TableKeyConfigDto,)))]
struct SqliteSourceSchemas;
pub struct SqliteSourceDescriptor;
#[async_trait]
impl SourcePluginDescriptor for SqliteSourceDescriptor {
fn kind(&self) -> &str {
"sqlite"
}
fn config_version(&self) -> &str {
"1.0.0"
}
fn config_schema_name(&self) -> &str {
"source.sqlite.SqliteSourceConfig"
}
fn config_schema_json(&self) -> String {
let api = SqliteSourceSchemas::openapi();
serde_json::to_string(
&api.components
.as_ref()
.expect("OpenAPI components missing")
.schemas,
)
.expect("Failed to serialize config schema")
}
async fn create_source(
&self,
id: &str,
config_json: &serde_json::Value,
auto_start: bool,
) -> anyhow::Result<Box<dyn drasi_lib::sources::Source>> {
let dto: SqliteSourceConfigDto = serde_json::from_value(config_json.clone())?;
let mapper = DtoMapper::new();
let path = match &dto.path {
Some(cv) => Some(mapper.resolve_string(cv).await?),
None => None,
};
let rest_api = match &dto.rest_api {
Some(rest_dto) => Some(RestApiConfig {
host: mapper.resolve_string(&rest_dto.host).await?,
port: mapper.resolve_typed(&rest_dto.port).await?,
}),
None => None,
};
let table_keys = dto
.table_keys
.iter()
.map(|tk| TableKeyConfig {
table: tk.table.clone(),
key_columns: tk.key_columns.clone(),
})
.collect();
let config = SqliteSourceConfig {
path,
tables: dto.tables,
table_keys,
rest_api,
..Default::default()
};
let mut builder = crate::SqliteSourceBuilder::new(id);
if let Some(p) = &config.path {
builder = builder.with_path(p);
}
if let Some(tables) = config.tables {
builder = builder.with_tables(tables);
}
if !config.table_keys.is_empty() {
builder = builder.with_table_keys(config.table_keys);
}
if let Some(rest) = config.rest_api {
builder = builder.with_rest_api(rest);
}
builder = builder.auto_start(auto_start);
let mut source = builder.build()?;
source.base.set_raw_config(config_json.clone());
Ok(Box::new(source))
}
}