use schemars::JsonSchema;
use serde::Deserialize;
use serde::de::IgnoredAny;
use super::de::{Located, Loose, Map, UnknownKeys};
use crate::dates::{WeekNumbering, WeekStart};
type JsonMap = serde_json::Map<String, serde_json::Value>;
pub type FormatOptions = Located<Loose<Option<Map<Loose<JsonMap>>>>>;
pub type DispatchList = Located<Loose<Vec<Loose<Dispatch>>>>;
#[derive(Deserialize, JsonSchema)]
#[schemars(title = "DRE project", deny_unknown_fields)]
pub struct ProjectFile {
#[schemars(required, length(min = 1))]
pub name: Option<Located<Loose<String>>>,
pub meta: Option<Located<Loose<JsonMap>>>,
pub default_profile: Option<Located<Loose<String>>>,
#[schemars(schema_with = "output_ref")]
#[serde(default)]
pub default_output: Option<IgnoredAny>,
#[schemars(schema_with = "format_options")]
#[serde(default)]
pub format_options: Option<FormatOptions>,
pub default_set: Option<Located<Loose<String>>>,
#[schemars(schema_with = "any_map")]
#[serde(default)]
pub vars: Option<Located<Loose<Option<JsonMap>>>>,
#[schemars(range(min = 1), extend("default" = 10000))]
pub run_query_max_rows: Option<Located<Loose<u64>>>,
#[schemars(range(min = 0), extend("default" = 200))]
pub lookup_inline_max_rows: Option<Located<Loose<u64>>>,
pub dispatch: Option<DispatchList>,
#[schemars(extend("default" = true))]
pub mask_secrets: Option<Located<Loose<bool>>>,
#[schemars(extend("default" = true))]
pub mask_row_values: Option<Located<Loose<bool>>>,
pub timezone: Option<Located<Loose<String>>>,
pub locale: Option<Located<Loose<String>>>,
#[schemars(extend("default" = "monday"))]
pub week_start: Option<Located<Loose<WeekStart>>>,
#[schemars(extend("default" = "iso"))]
pub week_numbering: Option<Located<Loose<WeekNumbering>>>,
pub reports: Option<Located<Loose<Folder>>>,
pub flags: Option<Located<Loose<Flags>>>,
pub target_path: Option<Located<Loose<String>>>,
#[schemars(schema_with = "super::dependencies::plugins")]
#[serde(default)]
pub plugins: Option<IgnoredAny>,
#[schemars(schema_with = "sources_ref")]
#[serde(default)]
pub sources: Option<IgnoredAny>,
#[schemars(skip)]
pub target: Option<Located<IgnoredAny>>,
#[schemars(skip)]
pub destinations: Option<Located<IgnoredAny>>,
#[schemars(skip)]
pub formats: Option<Located<IgnoredAny>>,
#[serde(rename = "$unknown", default)]
#[schemars(skip)]
pub unknown: UnknownKeys,
}
#[derive(Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct Flags {
#[schemars(range(min = 1), extend("default" = 60))]
pub http_timeout: Option<Located<Loose<u64>>>,
#[schemars(range(min = 1), extend("default" = 1))]
pub keep_runs: Option<Located<Loose<u64>>>,
#[schemars(schema_with = "duration")]
#[serde(default)]
pub run_timeout: Option<Located<Loose<serde_json::Value>>>,
#[serde(rename = "$unknown", default)]
#[schemars(skip)]
pub unknown: UnknownKeys,
}
#[derive(Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields, inline)]
pub struct Dispatch {
#[schemars(required)]
pub macro_namespace: Option<Loose<String>>,
#[schemars(required, length(min = 1))]
pub search_order: Option<Loose<Vec<Loose<String>>>>,
}
#[derive(Deserialize, JsonSchema)]
#[schemars(rename = "folder", extend("additionalProperties" = {"$ref": "#/$defs/folder"}))]
pub struct Folder {
#[serde(rename = "+meta")]
pub meta: Option<Located<Loose<JsonMap>>>,
#[serde(rename = "+tags")]
pub tags: Option<Located<Loose<Vec<String>>>>,
#[serde(rename = "+output")]
#[serde(default)]
#[schemars(schema_with = "output_ref")]
pub output: Option<Located<Loose<JsonMap>>>,
#[serde(rename = "+profile")]
pub profile: Option<Located<Loose<String>>>,
#[serde(rename = "+schedule")]
#[schemars(skip)]
pub schedule: Option<Located<IgnoredAny>>,
#[serde(rename = "+vars")]
#[serde(default)]
#[schemars(schema_with = "any_map")]
pub vars: Option<Located<Loose<JsonMap>>>,
#[serde(rename = "+timezone")]
pub timezone: Option<Located<Loose<String>>>,
#[serde(rename = "+locale")]
pub locale: Option<Located<Loose<String>>>,
#[serde(rename = "$unknown", default)]
#[schemars(skip)]
pub rest: Map<Located<Loose<Folder>>>,
}
impl Folder {
pub fn sets_anything(&self) -> bool {
self.tags.is_some()
|| self.meta.is_some()
|| self.output.is_some()
|| self.profile.is_some()
|| self.schedule.is_some()
|| self.vars.is_some()
|| self.timezone.is_some()
|| self.locale.is_some()
|| self.rest.iter().any(|(k, _)| k.value.starts_with('+'))
}
}
fn output_ref(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({"$ref": "report.schema.json#/$defs/output"})
}
pub(super) fn sources_ref(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({"$ref": "sources.schema.json#/properties/sources"})
}
fn duration(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({
"oneOf": [
{"type": "string", "pattern": "^\\s*[0-9]+(\\.[0-9]+)?\\s*(ms|s|m|h)?\\s*$"},
{"type": "number", "minimum": 0}
]
})
}
fn any_map(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({"type": "object", "additionalProperties": true})
}
fn format_options(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({"type": "object", "additionalProperties": {"type": "object"}})
}