use surrealdb_strand::Strand;
use surrealdb_types::{SqlFormat, ToSql};
use crate::fmt::EscapeKwFreeIdent;
use crate::val::TableName;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct GraphQLConfig {
pub tables: TablesConfig,
pub functions: FunctionsConfig,
pub depth_limit: Option<u32>,
pub complexity_limit: Option<u32>,
pub introspection: IntrospectionConfig,
}
impl From<GraphQLConfig> for crate::catalog::GraphQLConfig {
fn from(v: GraphQLConfig) -> Self {
crate::catalog::GraphQLConfig {
tables: v.tables.into(),
functions: v.functions.into(),
depth_limit: v.depth_limit,
complexity_limit: v.complexity_limit,
introspection: v.introspection.into(),
}
}
}
impl From<crate::catalog::GraphQLConfig> for GraphQLConfig {
fn from(v: crate::catalog::GraphQLConfig) -> Self {
GraphQLConfig {
tables: v.tables.into(),
functions: v.functions.into(),
depth_limit: v.depth_limit,
complexity_limit: v.complexity_limit,
introspection: v.introspection.into(),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum TablesConfig {
#[default]
None,
Auto,
Include(
#[cfg_attr(feature = "arbitrary", arbitrary(with = crate::sql::arbitrary::atleast_one))]
Vec<TableConfig>,
),
Exclude(
#[cfg_attr(feature = "arbitrary", arbitrary(with = crate::sql::arbitrary::atleast_one))]
Vec<TableConfig>,
),
}
impl From<TablesConfig> for crate::catalog::GraphQLTablesConfig {
fn from(v: TablesConfig) -> Self {
match v {
TablesConfig::None => Self::None,
TablesConfig::Auto => Self::Auto,
TablesConfig::Include(cs) => Self::Include(cs.into_iter().map(|t| t.name).collect()),
TablesConfig::Exclude(cs) => Self::Exclude(cs.into_iter().map(|t| t.name).collect()),
}
}
}
impl From<crate::catalog::GraphQLTablesConfig> for TablesConfig {
fn from(v: crate::catalog::GraphQLTablesConfig) -> Self {
match v {
crate::catalog::GraphQLTablesConfig::None => Self::None,
crate::catalog::GraphQLTablesConfig::Auto => Self::Auto,
crate::catalog::GraphQLTablesConfig::Include(cs) => Self::Include(
cs.into_iter()
.map(|t| TableConfig {
name: t,
})
.collect(),
),
crate::catalog::GraphQLTablesConfig::Exclude(cs) => Self::Exclude(
cs.into_iter()
.map(|t| TableConfig {
name: t,
})
.collect(),
),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct TableConfig {
pub name: TableName,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum FunctionsConfig {
#[default]
None,
Auto,
#[cfg_attr(feature = "arbitrary", arbitrary(skip))]
Include(Vec<Strand>),
#[cfg_attr(feature = "arbitrary", arbitrary(skip))]
Exclude(Vec<Strand>),
}
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum IntrospectionConfig {
#[default]
Auto,
None,
}
impl From<IntrospectionConfig> for crate::catalog::GraphQLIntrospectionConfig {
fn from(v: IntrospectionConfig) -> Self {
match v {
IntrospectionConfig::Auto => Self::Auto,
IntrospectionConfig::None => Self::None,
}
}
}
impl From<crate::catalog::GraphQLIntrospectionConfig> for IntrospectionConfig {
fn from(v: crate::catalog::GraphQLIntrospectionConfig) -> Self {
match v {
crate::catalog::GraphQLIntrospectionConfig::Auto => Self::Auto,
crate::catalog::GraphQLIntrospectionConfig::None => Self::None,
}
}
}
impl ToSql for IntrospectionConfig {
fn fmt_sql(&self, f: &mut String, _fmt: SqlFormat) {
match self {
IntrospectionConfig::Auto => f.push_str("AUTO"),
IntrospectionConfig::None => f.push_str("NONE"),
}
}
}
impl ToSql for GraphQLConfig {
fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
f.push_str("GRAPHQL");
f.push_str(" TABLES ");
self.tables.fmt_sql(f, fmt);
f.push_str(" FUNCTIONS ");
self.functions.fmt_sql(f, fmt);
if let Some(depth) = self.depth_limit {
f.push_str(&format!(" DEPTH {depth}"));
}
if let Some(complexity) = self.complexity_limit {
f.push_str(&format!(" COMPLEXITY {complexity}"));
}
if matches!(self.introspection, IntrospectionConfig::None) {
f.push_str(" INTROSPECTION ");
self.introspection.fmt_sql(f, fmt);
}
}
}
impl From<FunctionsConfig> for crate::catalog::GraphQLFunctionsConfig {
fn from(v: FunctionsConfig) -> Self {
match v {
FunctionsConfig::None => Self::None,
FunctionsConfig::Auto => Self::Auto,
FunctionsConfig::Include(cs) => Self::Include(cs),
FunctionsConfig::Exclude(cs) => Self::Exclude(cs),
}
}
}
impl From<crate::catalog::GraphQLFunctionsConfig> for FunctionsConfig {
fn from(v: crate::catalog::GraphQLFunctionsConfig) -> Self {
match v {
crate::catalog::GraphQLFunctionsConfig::None => Self::None,
crate::catalog::GraphQLFunctionsConfig::Auto => Self::Auto,
crate::catalog::GraphQLFunctionsConfig::Include(cs) => Self::Include(cs),
crate::catalog::GraphQLFunctionsConfig::Exclude(cs) => Self::Exclude(cs),
}
}
}
impl ToSql for TablesConfig {
fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
match self {
TablesConfig::Auto => f.push_str("AUTO"),
TablesConfig::None => f.push_str("NONE"),
TablesConfig::Include(cs) => {
f.push_str("INCLUDE ");
for (i, table) in cs.iter().enumerate() {
if i > 0 {
f.push_str(", ");
}
table.fmt_sql(f, fmt);
}
}
TablesConfig::Exclude(cs) => {
f.push_str("EXCLUDE ");
for (i, table) in cs.iter().enumerate() {
if i > 0 {
f.push_str(", ");
}
table.fmt_sql(f, fmt);
}
}
}
}
}
impl ToSql for TableConfig {
fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
EscapeKwFreeIdent(self.name.as_str()).fmt_sql(f, fmt);
}
}
impl ToSql for FunctionsConfig {
fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
match self {
FunctionsConfig::Auto => f.push_str("AUTO"),
FunctionsConfig::None => f.push_str("NONE"),
FunctionsConfig::Include(cs) => {
f.push_str("INCLUDE ");
fmt_function_name_list(f, fmt, cs);
}
FunctionsConfig::Exclude(cs) => {
f.push_str("EXCLUDE ");
fmt_function_name_list(f, fmt, cs);
}
}
}
}
fn fmt_function_name_list(f: &mut String, fmt: SqlFormat, names: &[Strand]) {
for (i, name) in names.iter().enumerate() {
if i > 0 {
f.push_str(", ");
}
f.push_str("fn::");
let mut first = true;
for segment in name.as_str().split("::") {
if !first {
f.push_str("::");
}
first = false;
EscapeKwFreeIdent(segment).fmt_sql(f, fmt);
}
}
}