Skip to main content

gaman_core/clarifier/
model.rs

1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4use crate::operations::Operation;
5use crate::states::types::EntityKind;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum Severity {
10    Fatal,
11    Warning,
12    Suggestion,
13}
14
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16#[serde(tag = "type", rename_all = "snake_case")]
17pub enum ClarificationKind {
18    RenameTable {
19        old: String,
20        candidates: Vec<String>,
21    },
22    RenameColumn {
23        table: String,
24        old: String,
25        candidates: Vec<String>,
26    },
27    RenameEnumValue {
28        enum_name: String,
29        old: String,
30        candidates: Vec<String>,
31    },
32    NotNullAdd {
33        table: String,
34        column: String,
35        col_type: String,
36    },
37    NotNullChange {
38        table: String,
39        column: String,
40    },
41    TypeCast {
42        table: String,
43        column: String,
44        from: String,
45        to: String,
46    },
47    UnknownType {
48        table: String,
49        column: String,
50        type_name: String,
51        suggested: Vec<String>,
52    },
53    OpaqueEntity {
54        kind: EntityKind,
55        name: String,
56    },
57    UnmanagedTableOptions {
58        table: String,
59    },
60}
61
62#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
63pub struct Clarification {
64    pub id: String,
65    pub severity: Severity,
66    pub kind: ClarificationKind,
67}
68
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
70#[serde(tag = "type", content = "value", rename_all = "snake_case")]
71pub enum Answer {
72    RenameTo(String),
73    RenameNo,
74    NotNullDefault(String),
75    NotNullNullable,
76    NotNullManual,
77    TypeCast(String),
78    TypeCastImplicit,
79    UseType(String),
80    KeepType,
81    AcceptRisk,
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85pub struct Decision {
86    pub clarification_id: String,
87    pub answer: Answer,
88}
89
90#[derive(Debug, Clone)]
91pub enum ClarifyResult {
92    NeedsInput(Vec<Clarification>),
93    Resolved(Vec<Operation>),
94}
95
96#[derive(Debug, Error, PartialEq)]
97pub enum ClarifyError {
98    #[error("decision references unknown clarification '{0}'")]
99    UnknownDecision(String),
100    #[error("decision for '{id}' has an answer incompatible with the clarification kind")]
101    InvalidAnswer { id: String },
102    #[error("decision for '{id}' chose '{chosen}' which is not a valid candidate")]
103    InvalidCandidate { id: String, chosen: String },
104    #[error("duplicate decision for clarification '{0}'")]
105    DuplicateDecision(String),
106    #[error("multiple rename decisions target '{target}' in {scope}")]
107    ConflictingRenameTarget { scope: String, target: String },
108    #[error("decision for '{id}' requires a non-empty value")]
109    EmptyInput { id: String },
110}
111
112#[derive(Debug, Error)]
113pub enum PromptError {
114    #[error("I/O error: {0}")]
115    Io(#[from] std::io::Error),
116    #[error("{0}")]
117    #[allow(dead_code)]
118    Other(String),
119}
120
121pub trait PromptEngine {
122    fn prompt(&self, clarifications: &[Clarification]) -> Result<Vec<Decision>, PromptError>;
123}