pub mod api;
pub mod defaults;
use anyhow::{Result, bail};
use api::ApiConfig;
use defaults::DefaultConfig;
use reblessive::tree::Stk;
use crate::catalog::base::Base;
use crate::catalog::providers::{DatabaseProvider, RootProvider};
use crate::catalog::{ConfigDefinition, GraphQLConfig};
use crate::ctx::FrozenContext;
use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::expr::Value;
use crate::expr::statements::define::DefineKind;
use crate::iam::{Action, ConfigKind, ResourceKind};
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) struct DefineConfigStatement {
pub kind: DefineKind,
pub inner: ConfigInner,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) enum ConfigInner {
GraphQL(GraphQLConfig),
Api(ApiConfig),
Default(DefaultConfig),
}
impl ConfigInner {
pub(crate) fn kind(&self) -> ConfigKind {
match self {
ConfigInner::Default(_) => ConfigKind::Default,
ConfigInner::GraphQL(_) => ConfigKind::GraphQL,
ConfigInner::Api(_) => ConfigKind::Api,
}
}
pub(crate) async fn compute(
&self,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> Result<ConfigDefinition> {
Ok(match self {
ConfigInner::GraphQL(g) => ConfigDefinition::GraphQL(g.clone()),
ConfigInner::Api(a) => ConfigDefinition::Api(a.compute(stk, ctx, opt, doc).await?),
ConfigInner::Default(d) => {
ConfigDefinition::Default(d.compute(stk, ctx, opt, doc).await?)
}
})
}
}
impl DefineConfigStatement {
pub(crate) async fn compute(
&self,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> Result<Value> {
let kind = self.inner.kind();
let base = kind.base();
ctx.is_allowed(opt, Action::Edit, ResourceKind::Config(kind), base.clone().into())?;
let txn = ctx.tx();
let cg = match &self.inner {
ConfigInner::GraphQL(_) => "graphql",
ConfigInner::Api(_) => "api",
ConfigInner::Default(_) => "default",
};
match base {
Base::Root => {
if txn.expect_root_config(cg).await.is_ok() {
match self.kind {
DefineKind::Default => {
if !opt.import {
bail!(Error::CgAlreadyExists {
name: cg.to_string(),
});
}
}
DefineKind::Overwrite => {}
DefineKind::IfNotExists => return Ok(Value::None),
}
}
let key = crate::key::root::root_config::new(cg);
let store = self.inner.compute(stk, ctx, opt, doc).await?;
txn.replace(&key, &store).await?;
txn.clear_cache();
}
Base::Ns => {
fail!("defining config on a namespace is not supported");
}
Base::Db => {
let (ns, db) = ctx.get_ns_db_ids(opt).await?;
if txn.expect_db_config(ns, db, cg).await.is_ok() {
match self.kind {
DefineKind::Default => {
if !opt.import {
bail!(Error::CgAlreadyExists {
name: cg.to_string(),
});
}
}
DefineKind::Overwrite => {}
DefineKind::IfNotExists => return Ok(Value::None),
}
}
let key = crate::key::database::cg::new(ns, db, cg);
let store = self.inner.compute(stk, ctx, opt, doc).await?;
txn.replace(&key, &store).await?;
txn.clear_cache();
}
}
Ok(Value::None)
}
}