pgx_utils/sql_entity_graph/
mod.rs1pub(crate) mod aggregate;
18pub(crate) mod control_file;
19pub(crate) mod extension_sql;
20pub(crate) mod mapping;
21pub mod metadata;
22pub(crate) mod pg_extern;
23pub(crate) mod pg_trigger;
24pub(crate) mod pgx_attribute;
25pub(crate) mod pgx_sql;
26pub(crate) mod positioning_ref;
27pub(crate) mod postgres_enum;
28pub(crate) mod postgres_hash;
29pub(crate) mod postgres_ord;
30pub(crate) mod postgres_type;
31pub(crate) mod schema;
32pub(crate) mod to_sql;
33pub(crate) mod used_type;
34
35pub use aggregate::entity::{AggregateTypeEntity, PgAggregateEntity};
36pub use aggregate::{
37 AggregateType, AggregateTypeList, FinalizeModify, ParallelOption, PgAggregate,
38};
39pub use control_file::ControlFile;
40pub use extension_sql::entity::{ExtensionSqlEntity, SqlDeclaredEntity};
41pub use extension_sql::{ExtensionSql, ExtensionSqlFile, SqlDeclared};
42pub use mapping::{RustSourceOnlySqlMapping, RustSqlMapping};
43pub use pg_extern::entity::{
44 PgExternArgumentEntity, PgExternEntity, PgExternReturnEntity, PgExternReturnEntityIteratedItem,
45 PgOperatorEntity,
46};
47pub use pg_extern::{NameMacro, PgExtern, PgExternArgument, PgOperator};
48pub use pg_trigger::attribute::PgTriggerAttribute;
49pub use pg_trigger::entity::PgTriggerEntity;
50pub use pg_trigger::PgTrigger;
51pub use pgx_sql::{PgxSql, RustToSqlMapping};
52pub use positioning_ref::PositioningRef;
53pub use postgres_enum::entity::PostgresEnumEntity;
54pub use postgres_enum::PostgresEnum;
55pub use postgres_hash::entity::PostgresHashEntity;
56pub use postgres_hash::PostgresHash;
57pub use postgres_ord::entity::PostgresOrdEntity;
58pub use postgres_ord::PostgresOrd;
59pub use postgres_type::entity::PostgresTypeEntity;
60pub use postgres_type::PostgresType;
61pub use schema::entity::SchemaEntity;
62pub use schema::Schema;
63pub use to_sql::entity::ToSqlConfigEntity;
64pub use to_sql::{ToSql, ToSqlConfig};
65pub use used_type::{UsedType, UsedTypeEntity};
66
67pub use crate::ExternArgs;
68
69pub trait SqlGraphIdentifier {
71 fn dot_identifier(&self) -> String;
77
78 fn rust_identifier(&self) -> String;
83
84 fn file(&self) -> Option<&'static str>;
85
86 fn line(&self) -> Option<u32>;
87}
88
89#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
91pub enum SqlGraphEntity {
92 ExtensionRoot(ControlFile),
93 Schema(SchemaEntity),
94 CustomSql(ExtensionSqlEntity),
95 Function(PgExternEntity),
96 Type(PostgresTypeEntity),
97 BuiltinType(String),
98 Enum(PostgresEnumEntity),
99 Ord(PostgresOrdEntity),
100 Hash(PostgresHashEntity),
101 Aggregate(PgAggregateEntity),
102 Trigger(PgTriggerEntity),
103}
104
105impl SqlGraphEntity {
106 pub fn sql_anchor_comment(&self) -> String {
107 let maybe_file_and_line = if let (Some(file), Some(line)) = (self.file(), self.line()) {
108 format!("-- {file}:{line}\n", file = file, line = line)
109 } else {
110 String::default()
111 };
112 format!(
113 "\
114 {maybe_file_and_line}\
115 -- {rust_identifier}\
116 ",
117 maybe_file_and_line = maybe_file_and_line,
118 rust_identifier = self.rust_identifier(),
119 )
120 }
121}
122
123impl SqlGraphIdentifier for SqlGraphEntity {
124 fn dot_identifier(&self) -> String {
125 match self {
126 SqlGraphEntity::Schema(item) => item.dot_identifier(),
127 SqlGraphEntity::CustomSql(item) => item.dot_identifier(),
128 SqlGraphEntity::Function(item) => item.dot_identifier(),
129 SqlGraphEntity::Type(item) => item.dot_identifier(),
130 SqlGraphEntity::BuiltinType(item) => format!("preexisting type {}", item),
131 SqlGraphEntity::Enum(item) => item.dot_identifier(),
132 SqlGraphEntity::Ord(item) => item.dot_identifier(),
133 SqlGraphEntity::Hash(item) => item.dot_identifier(),
134 SqlGraphEntity::Aggregate(item) => item.dot_identifier(),
135 SqlGraphEntity::Trigger(item) => item.dot_identifier(),
136 SqlGraphEntity::ExtensionRoot(item) => item.dot_identifier(),
137 }
138 }
139
140 fn rust_identifier(&self) -> String {
141 match self {
142 SqlGraphEntity::Schema(item) => item.rust_identifier(),
143 SqlGraphEntity::CustomSql(item) => item.rust_identifier(),
144 SqlGraphEntity::Function(item) => item.rust_identifier(),
145 SqlGraphEntity::Type(item) => item.rust_identifier(),
146 SqlGraphEntity::BuiltinType(item) => item.to_string(),
147 SqlGraphEntity::Enum(item) => item.rust_identifier(),
148 SqlGraphEntity::Ord(item) => item.rust_identifier(),
149 SqlGraphEntity::Hash(item) => item.rust_identifier(),
150 SqlGraphEntity::Aggregate(item) => item.rust_identifier(),
151 SqlGraphEntity::Trigger(item) => item.rust_identifier(),
152 SqlGraphEntity::ExtensionRoot(item) => item.rust_identifier(),
153 }
154 }
155
156 fn file(&self) -> Option<&'static str> {
157 match self {
158 SqlGraphEntity::Schema(item) => item.file(),
159 SqlGraphEntity::CustomSql(item) => item.file(),
160 SqlGraphEntity::Function(item) => item.file(),
161 SqlGraphEntity::Type(item) => item.file(),
162 SqlGraphEntity::BuiltinType(_item) => None,
163 SqlGraphEntity::Enum(item) => item.file(),
164 SqlGraphEntity::Ord(item) => item.file(),
165 SqlGraphEntity::Hash(item) => item.file(),
166 SqlGraphEntity::Aggregate(item) => item.file(),
167 SqlGraphEntity::Trigger(item) => item.file(),
168 SqlGraphEntity::ExtensionRoot(item) => item.file(),
169 }
170 }
171
172 fn line(&self) -> Option<u32> {
173 match self {
174 SqlGraphEntity::Schema(item) => item.line(),
175 SqlGraphEntity::CustomSql(item) => item.line(),
176 SqlGraphEntity::Function(item) => item.line(),
177 SqlGraphEntity::Type(item) => item.line(),
178 SqlGraphEntity::BuiltinType(_item) => None,
179 SqlGraphEntity::Enum(item) => item.line(),
180 SqlGraphEntity::Ord(item) => item.line(),
181 SqlGraphEntity::Hash(item) => item.line(),
182 SqlGraphEntity::Aggregate(item) => item.line(),
183 SqlGraphEntity::Trigger(item) => item.line(),
184 SqlGraphEntity::ExtensionRoot(item) => item.line(),
185 }
186 }
187}
188
189impl ToSql for SqlGraphEntity {
190 #[tracing::instrument(level = "debug", skip(self, context), fields(identifier = %self.rust_identifier()))]
191 fn to_sql(&self, context: &PgxSql) -> eyre::Result<String> {
192 match self {
193 SqlGraphEntity::Schema(item) => {
194 if item.name != "public" && item.name != "pg_catalog" {
195 item.to_sql(context)
196 } else {
197 Ok(String::default())
198 }
199 }
200 SqlGraphEntity::CustomSql(item) => item.to_sql(context),
201 SqlGraphEntity::Function(item) => {
202 if let Some(result) = item.to_sql_config.to_sql(self, context) {
203 return result;
204 }
205 if context.graph.neighbors_undirected(context.externs.get(item).unwrap().clone()).any(|neighbor| {
206 let neighbor_item = &context.graph[neighbor];
207 match neighbor_item {
208 SqlGraphEntity::Type(PostgresTypeEntity { in_fn, in_fn_module_path, out_fn, out_fn_module_path, .. }) => {
209 let is_in_fn = item.full_path.starts_with(in_fn_module_path) && item.full_path.ends_with(in_fn);
210 if is_in_fn {
211 tracing::trace!(r#type = %neighbor_item.dot_identifier(), "Skipping, is an in_fn.");
212 }
213 let is_out_fn = item.full_path.starts_with(out_fn_module_path) && item.full_path.ends_with(out_fn);
214 if is_out_fn {
215 tracing::trace!(r#type = %neighbor_item.dot_identifier(), "Skipping, is an out_fn.");
216 }
217 is_in_fn || is_out_fn
218 },
219 _ => false,
220 }
221 }) {
222 Ok(String::default())
223 } else {
224 item.to_sql(context)
225 }
226 }
227 SqlGraphEntity::Type(item) => {
228 item.to_sql_config.to_sql(self, context).unwrap_or_else(|| item.to_sql(context))
229 }
230 SqlGraphEntity::BuiltinType(_) => Ok(String::default()),
231 SqlGraphEntity::Enum(item) => {
232 item.to_sql_config.to_sql(self, context).unwrap_or_else(|| item.to_sql(context))
233 }
234 SqlGraphEntity::Ord(item) => {
235 item.to_sql_config.to_sql(self, context).unwrap_or_else(|| item.to_sql(context))
236 }
237 SqlGraphEntity::Hash(item) => {
238 item.to_sql_config.to_sql(self, context).unwrap_or_else(|| item.to_sql(context))
239 }
240 SqlGraphEntity::Aggregate(item) => {
241 item.to_sql_config.to_sql(self, context).unwrap_or_else(|| item.to_sql(context))
242 }
243 SqlGraphEntity::Trigger(item) => {
244 item.to_sql_config.to_sql(self, context).unwrap_or_else(|| item.to_sql(context))
245 }
246 SqlGraphEntity::ExtensionRoot(item) => item.to_sql(context),
247 }
248 }
249}