dre_core/config/
project.rs1use schemars::JsonSchema;
9use serde::Deserialize;
10use serde::de::IgnoredAny;
11
12use super::de::{Located, Loose, Map, UnknownKeys};
13use crate::dates::{WeekNumbering, WeekStart};
14
15type JsonMap = serde_json::Map<String, serde_json::Value>;
16pub type FormatOptions = Located<Loose<Option<Map<Loose<JsonMap>>>>>;
18pub type DispatchList = Located<Loose<Vec<Loose<Dispatch>>>>;
20
21#[derive(Deserialize, JsonSchema)]
23#[schemars(title = "DRE project", deny_unknown_fields)]
24pub struct ProjectFile {
25 #[schemars(required, length(min = 1))]
27 pub name: Option<Located<Loose<String>>>,
28 pub meta: Option<Located<Loose<JsonMap>>>,
30 pub default_profile: Option<Located<Loose<String>>>,
32 #[schemars(schema_with = "output_ref")]
34 #[serde(default)]
35 pub default_output: Option<IgnoredAny>,
36 #[schemars(schema_with = "format_options")]
38 #[serde(default)]
39 pub format_options: Option<FormatOptions>,
40 pub default_set: Option<Located<Loose<String>>>,
42 #[schemars(schema_with = "any_map")]
44 #[serde(default)]
45 pub vars: Option<Located<Loose<Option<JsonMap>>>>,
46 #[schemars(range(min = 1), extend("default" = 10000))]
48 pub run_query_max_rows: Option<Located<Loose<u64>>>,
49 #[schemars(range(min = 0), extend("default" = 200))]
51 pub lookup_inline_max_rows: Option<Located<Loose<u64>>>,
52 pub dispatch: Option<DispatchList>,
54 #[schemars(extend("default" = true))]
56 pub mask_secrets: Option<Located<Loose<bool>>>,
57 pub timezone: Option<Located<Loose<String>>>,
59 pub locale: Option<Located<Loose<String>>>,
61 #[schemars(extend("default" = "monday"))]
63 pub week_start: Option<Located<Loose<WeekStart>>>,
64 #[schemars(extend("default" = "iso"))]
66 pub week_numbering: Option<Located<Loose<WeekNumbering>>>,
67 pub reports: Option<Located<Loose<Folder>>>,
69 pub flags: Option<Located<Loose<Flags>>>,
71 pub target_path: Option<Located<Loose<String>>>,
73 #[schemars(schema_with = "super::dependencies::plugins")]
75 #[serde(default)]
76 pub plugins: Option<IgnoredAny>,
77 #[schemars(schema_with = "sources_ref")]
79 #[serde(default)]
80 pub sources: Option<IgnoredAny>,
81 #[schemars(skip)]
83 pub target: Option<Located<IgnoredAny>>,
84 #[schemars(skip)]
86 pub destinations: Option<Located<IgnoredAny>>,
87 #[schemars(skip)]
88 pub formats: Option<Located<IgnoredAny>>,
89 #[serde(rename = "$unknown", default)]
90 #[schemars(skip)]
91 pub unknown: UnknownKeys,
92}
93
94#[derive(Deserialize, JsonSchema)]
96#[schemars(deny_unknown_fields)]
97pub struct Flags {
98 #[schemars(range(min = 1), extend("default" = 60))]
100 pub http_timeout: Option<Located<Loose<u64>>>,
101 #[schemars(range(min = 1), extend("default" = 1))]
103 pub keep_runs: Option<Located<Loose<u64>>>,
104 #[schemars(schema_with = "duration")]
106 #[serde(default)]
107 pub run_timeout: Option<Located<Loose<serde_json::Value>>>,
108 #[serde(rename = "$unknown", default)]
109 #[schemars(skip)]
110 pub unknown: UnknownKeys,
111}
112
113#[derive(Deserialize, JsonSchema)]
115#[schemars(deny_unknown_fields, inline)]
116pub struct Dispatch {
117 #[schemars(required)]
119 pub macro_namespace: Option<Loose<String>>,
120 #[schemars(required, length(min = 1))]
122 pub search_order: Option<Loose<Vec<Loose<String>>>>,
123}
124
125#[derive(Deserialize, JsonSchema)]
127#[schemars(rename = "folder", extend("additionalProperties" = {"$ref": "#/$defs/folder"}))]
128pub struct Folder {
129 #[serde(rename = "+meta")]
131 pub meta: Option<Located<Loose<JsonMap>>>,
132 #[serde(rename = "+tags")]
134 pub tags: Option<Located<Loose<Vec<String>>>>,
135 #[serde(rename = "+output")]
137 #[serde(default)]
138 #[schemars(schema_with = "output_ref")]
139 pub output: Option<Located<Loose<JsonMap>>>,
140 #[serde(rename = "+profile")]
142 pub profile: Option<Located<Loose<String>>>,
143 #[serde(rename = "+schedule")]
145 #[schemars(skip)]
146 pub schedule: Option<Located<IgnoredAny>>,
147 #[serde(rename = "+vars")]
149 #[serde(default)]
150 #[schemars(schema_with = "any_map")]
151 pub vars: Option<Located<Loose<JsonMap>>>,
152 #[serde(rename = "+timezone")]
154 pub timezone: Option<Located<Loose<String>>>,
155 #[serde(rename = "+locale")]
157 pub locale: Option<Located<Loose<String>>>,
158 #[serde(rename = "$unknown", default)]
160 #[schemars(skip)]
161 pub rest: Map<Located<Loose<Folder>>>,
162}
163
164impl Folder {
165 pub fn sets_anything(&self) -> bool {
168 self.tags.is_some()
169 || self.meta.is_some()
170 || self.output.is_some()
171 || self.profile.is_some()
172 || self.schedule.is_some()
173 || self.vars.is_some()
174 || self.timezone.is_some()
175 || self.locale.is_some()
176 || self.rest.iter().any(|(k, _)| k.value.starts_with('+'))
177 }
178}
179
180fn output_ref(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
181 schemars::json_schema!({"$ref": "report.schema.json#/$defs/output"})
182}
183
184pub(super) fn sources_ref(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
185 schemars::json_schema!({"$ref": "sources.schema.json#/properties/sources"})
186}
187
188fn duration(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
189 schemars::json_schema!({
190 "oneOf": [
191 {"type": "string", "pattern": "^\\s*[0-9]+(\\.[0-9]+)?\\s*(ms|s|m|h)?\\s*$"},
192 {"type": "number", "minimum": 0}
193 ]
194 })
195}
196
197fn any_map(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
198 schemars::json_schema!({"type": "object", "additionalProperties": true})
199}
200
201fn format_options(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
202 schemars::json_schema!({"type": "object", "additionalProperties": {"type": "object"}})
203}