Skip to main content

surql_parser/upstream/sql/statements/define/config/
graphql.rs

1use crate::upstream::fmt::EscapeKwFreeIdent;
2use surrealdb_types::{SqlFormat, ToSql};
3#[derive(Clone, Debug, Default, PartialEq, Eq)]
4#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
5pub struct GraphQLConfig {
6	pub tables: TablesConfig,
7	pub functions: FunctionsConfig,
8	pub depth_limit: Option<u32>,
9	pub complexity_limit: Option<u32>,
10	pub introspection: IntrospectionConfig,
11}
12impl From<GraphQLConfig> for crate::compat::catalog::GraphQLConfig {
13	fn from(v: GraphQLConfig) -> Self {
14		crate::compat::catalog::GraphQLConfig {
15			tables: v.tables.into(),
16			functions: v.functions.into(),
17			depth_limit: v.depth_limit,
18			complexity_limit: v.complexity_limit,
19			introspection: v.introspection.into(),
20		}
21	}
22}
23impl From<crate::compat::catalog::GraphQLConfig> for GraphQLConfig {
24	fn from(v: crate::compat::catalog::GraphQLConfig) -> Self {
25		GraphQLConfig {
26			tables: v.tables.into(),
27			functions: v.functions.into(),
28			depth_limit: v.depth_limit,
29			complexity_limit: v.complexity_limit,
30			introspection: v.introspection.into(),
31		}
32	}
33}
34#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Hash)]
35#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
36pub enum TablesConfig {
37	#[default]
38	None,
39	Auto,
40	Include(
41		#[cfg_attr(
42            feature = "arbitrary",
43            arbitrary(with = crate::upstream::sql::arbitrary::atleast_one)
44        )]
45		Vec<TableConfig>,
46	),
47	Exclude(
48		#[cfg_attr(
49            feature = "arbitrary",
50            arbitrary(with = crate::upstream::sql::arbitrary::atleast_one)
51        )]
52		Vec<TableConfig>,
53	),
54}
55impl From<TablesConfig> for crate::compat::catalog::GraphQLTablesConfig {
56	fn from(v: TablesConfig) -> Self {
57		match v {
58			TablesConfig::None => Self::None,
59			TablesConfig::Auto => Self::Auto,
60			TablesConfig::Include(cs) => {
61				Self::Include(cs.into_iter().map(|t| t.name.into()).collect())
62			}
63			TablesConfig::Exclude(cs) => {
64				Self::Exclude(cs.into_iter().map(|t| t.name.into()).collect())
65			}
66		}
67	}
68}
69impl From<crate::compat::catalog::GraphQLTablesConfig> for TablesConfig {
70	fn from(v: crate::compat::catalog::GraphQLTablesConfig) -> Self {
71		match v {
72			crate::compat::catalog::GraphQLTablesConfig::None => Self::None,
73			crate::compat::catalog::GraphQLTablesConfig::Auto => Self::Auto,
74			crate::compat::catalog::GraphQLTablesConfig::Include(cs) => Self::Include(
75				cs.into_iter()
76					.map(|t| TableConfig {
77						name: t.to_string(),
78					})
79					.collect(),
80			),
81			crate::compat::catalog::GraphQLTablesConfig::Exclude(cs) => Self::Exclude(
82				cs.into_iter()
83					.map(|t| TableConfig {
84						name: t.to_string(),
85					})
86					.collect(),
87			),
88		}
89	}
90}
91#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
92#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
93pub struct TableConfig {
94	pub name: String,
95}
96#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Hash)]
97#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
98pub enum FunctionsConfig {
99	#[default]
100	None,
101	Auto,
102	#[cfg_attr(feature = "arbitrary", arbitrary(skip))]
103	Include(Vec<String>),
104	#[cfg_attr(feature = "arbitrary", arbitrary(skip))]
105	Exclude(Vec<String>),
106}
107/// Controls whether GraphQL schema introspection is enabled.
108///
109/// When set to `None`, introspection queries (`__schema`, `__type`, etc.) are disabled,
110/// preventing clients from discovering the schema structure. This is useful in production
111/// to avoid leaking table/field names to unauthorized users.
112///
113/// Defaults to `Auto` (introspection enabled).
114#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Hash)]
115#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
116pub enum IntrospectionConfig {
117	#[default]
118	Auto,
119	None,
120}
121impl From<IntrospectionConfig> for crate::compat::catalog::GraphQLIntrospectionConfig {
122	fn from(v: IntrospectionConfig) -> Self {
123		match v {
124			IntrospectionConfig::Auto => Self::Auto,
125			IntrospectionConfig::None => Self::None,
126		}
127	}
128}
129impl From<crate::compat::catalog::GraphQLIntrospectionConfig> for IntrospectionConfig {
130	fn from(v: crate::compat::catalog::GraphQLIntrospectionConfig) -> Self {
131		match v {
132			crate::compat::catalog::GraphQLIntrospectionConfig::Auto => Self::Auto,
133			crate::compat::catalog::GraphQLIntrospectionConfig::None => Self::None,
134		}
135	}
136}
137impl ToSql for IntrospectionConfig {
138	fn fmt_sql(&self, f: &mut String, _fmt: SqlFormat) {
139		match self {
140			IntrospectionConfig::Auto => f.push_str("AUTO"),
141			IntrospectionConfig::None => f.push_str("NONE"),
142		}
143	}
144}
145impl ToSql for GraphQLConfig {
146	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
147		f.push_str("GRAPHQL");
148		f.push_str(" TABLES ");
149		self.tables.fmt_sql(f, fmt);
150		f.push_str(" FUNCTIONS ");
151		self.functions.fmt_sql(f, fmt);
152		if let Some(depth) = self.depth_limit {
153			f.push_str(&format!(" DEPTH {depth}"));
154		}
155		if let Some(complexity) = self.complexity_limit {
156			f.push_str(&format!(" COMPLEXITY {complexity}"));
157		}
158		if matches!(self.introspection, IntrospectionConfig::None) {
159			f.push_str(" INTROSPECTION ");
160			self.introspection.fmt_sql(f, fmt);
161		}
162	}
163}
164impl From<FunctionsConfig> for crate::compat::catalog::GraphQLFunctionsConfig {
165	fn from(v: FunctionsConfig) -> Self {
166		match v {
167			FunctionsConfig::None => Self::None,
168			FunctionsConfig::Auto => Self::Auto,
169			FunctionsConfig::Include(cs) => Self::Include(cs),
170			FunctionsConfig::Exclude(cs) => Self::Exclude(cs),
171		}
172	}
173}
174impl From<crate::compat::catalog::GraphQLFunctionsConfig> for FunctionsConfig {
175	fn from(v: crate::compat::catalog::GraphQLFunctionsConfig) -> Self {
176		match v {
177			crate::compat::catalog::GraphQLFunctionsConfig::None => Self::None,
178			crate::compat::catalog::GraphQLFunctionsConfig::Auto => Self::Auto,
179			crate::compat::catalog::GraphQLFunctionsConfig::Include(cs) => Self::Include(cs),
180			crate::compat::catalog::GraphQLFunctionsConfig::Exclude(cs) => Self::Exclude(cs),
181		}
182	}
183}
184impl ToSql for TablesConfig {
185	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
186		match self {
187			TablesConfig::Auto => f.push_str("AUTO"),
188			TablesConfig::None => f.push_str("NONE"),
189			TablesConfig::Include(cs) => {
190				f.push_str("INCLUDE ");
191				for (i, table) in cs.iter().enumerate() {
192					if i > 0 {
193						f.push_str(", ");
194					}
195					table.fmt_sql(f, fmt);
196				}
197			}
198			TablesConfig::Exclude(cs) => {
199				f.push_str("EXCLUDE ");
200				for (i, table) in cs.iter().enumerate() {
201					if i > 0 {
202						f.push_str(", ");
203					}
204					table.fmt_sql(f, fmt);
205				}
206			}
207		}
208	}
209}
210impl ToSql for TableConfig {
211	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
212		EscapeKwFreeIdent(&self.name).fmt_sql(f, fmt);
213	}
214}
215impl ToSql for FunctionsConfig {
216	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
217		match self {
218			FunctionsConfig::Auto => f.push_str("AUTO"),
219			FunctionsConfig::None => f.push_str("NONE"),
220			FunctionsConfig::Include(cs) => {
221				f.push_str("INCLUDE [");
222				for (i, func) in cs.iter().enumerate() {
223					if i > 0 {
224						f.push_str(", ");
225					}
226					func.fmt_sql(f, fmt);
227				}
228				f.push(']');
229			}
230			FunctionsConfig::Exclude(cs) => {
231				f.push_str("EXCLUDE [");
232				for (i, func) in cs.iter().enumerate() {
233					if i > 0 {
234						f.push_str(", ");
235					}
236					func.fmt_sql(f, fmt);
237				}
238				f.push(']');
239			}
240		}
241	}
242}