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