pgx_sql_entity_graph/
control_file.rs1use super::{SqlGraphEntity, SqlGraphIdentifier, ToSql};
18use core::convert::TryFrom;
19use std::collections::HashMap;
20
21#[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
33pub struct ControlFile {
34 pub comment: String,
35 pub default_version: String,
36 pub module_pathname: Option<String>,
37 pub relocatable: bool,
38 pub superuser: bool,
39 pub schema: Option<String>,
40}
41
42impl ControlFile {
43 pub fn from_str(input: &str) -> Result<Self, ControlFileError> {
54 let mut temp = HashMap::new();
55 for line in input.lines() {
56 let parts: Vec<&str> = line.split('=').collect();
57
58 if parts.len() != 2 {
59 continue;
60 }
61
62 let (k, v) = (parts.get(0).unwrap().trim(), parts.get(1).unwrap().trim());
63
64 let v = v.trim_start_matches('\'');
65 let v = v.trim_end_matches('\'');
66
67 temp.insert(k, v);
68 }
69 Ok(ControlFile {
70 comment: temp
71 .get("comment")
72 .ok_or(ControlFileError::MissingField { field: "comment" })?
73 .to_string(),
74 default_version: temp
75 .get("default_version")
76 .ok_or(ControlFileError::MissingField { field: "default_version" })?
77 .to_string(),
78 module_pathname: temp.get("module_pathname").map(|v| v.to_string()),
79 relocatable: temp
80 .get("relocatable")
81 .ok_or(ControlFileError::MissingField { field: "relocatable" })?
82 == &"true",
83 superuser: temp
84 .get("superuser")
85 .ok_or(ControlFileError::MissingField { field: "superuser" })?
86 == &"true",
87 schema: temp.get("schema").map(|v| v.to_string()),
88 })
89 }
90}
91
92impl From<ControlFile> for SqlGraphEntity {
93 fn from(val: ControlFile) -> Self {
94 SqlGraphEntity::ExtensionRoot(val)
95 }
96}
97
98#[derive(Debug, Clone)]
100pub enum ControlFileError {
101 MissingField { field: &'static str },
102}
103
104impl std::fmt::Display for ControlFileError {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 match self {
107 ControlFileError::MissingField { field } => {
108 write!(f, "Missing field in control file! Please add `{}`.", field)?;
109 }
110 };
111 Ok(())
112 }
113}
114
115impl std::error::Error for ControlFileError {}
116
117impl TryFrom<&str> for ControlFile {
118 type Error = ControlFileError;
119
120 fn try_from(input: &str) -> Result<Self, Self::Error> {
121 Self::from_str(input)
122 }
123}
124
125impl ToSql for ControlFile {
126 fn to_sql(&self, _context: &super::PgxSql) -> eyre::Result<String> {
127 let sql = format!(
128 "\
129 /* \n\
130 This file is auto generated by pgx.\n\
131 \n\
132 The ordering of items is not stable, it is driven by a dependency graph.\n\
133 */\
134 "
135 );
136 Ok(sql)
137 }
138}
139
140impl SqlGraphIdentifier for ControlFile {
141 fn dot_identifier(&self) -> String {
142 format!("extension root")
143 }
144 fn rust_identifier(&self) -> String {
145 format!("root")
146 }
147
148 fn file(&self) -> Option<&'static str> {
149 None
150 }
151
152 fn line(&self) -> Option<u32> {
153 None
154 }
155}