Skip to main content

qa_spec/spec/
question.rs

1use crate::expr::Expr;
2use crate::store::StoreTarget;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6/// Supported question data types.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
8#[serde(rename_all = "snake_case")]
9pub enum QuestionType {
10    String,
11    Boolean,
12    Integer,
13    Number,
14    Enum,
15    List,
16}
17
18/// Constraints that can be enforced per question.
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
20pub struct Constraint {
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub pattern: Option<String>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub min: Option<f64>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub max: Option<f64>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub min_len: Option<usize>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub max_len: Option<usize>,
31}
32
33/// Definition of a single question inside a form.
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
35pub struct QuestionSpec {
36    pub id: String,
37    #[serde(rename = "type")]
38    pub kind: QuestionType,
39    pub title: String,
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub description: Option<String>,
42    #[serde(default)]
43    pub required: bool,
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub choices: Option<Vec<String>>,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub default_value: Option<String>,
48    #[serde(default)]
49    pub secret: bool,
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub visible_if: Option<Expr>,
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub constraint: Option<Constraint>,
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub list: Option<ListSpec>,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub computed: Option<Expr>,
58    #[serde(default)]
59    pub policy: QuestionPolicy,
60    #[serde(default)]
61    pub computed_overridable: bool,
62}
63
64/// Per-question overrides for progress behavior.
65#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
66pub struct QuestionPolicy {
67    #[serde(default, skip_serializing_if = "Vec::is_empty")]
68    pub skip_if_present_in: Vec<StoreTarget>,
69    #[serde(default)]
70    pub editable_if_from_default: bool,
71}
72
73/// Definition of a repeatable list whose entries reuse question definitions.
74#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
75pub struct ListSpec {
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub min_items: Option<usize>,
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub max_items: Option<usize>,
80    #[serde(default, skip_serializing_if = "Vec::is_empty")]
81    pub fields: Vec<QuestionSpec>,
82}