pub(crate) mod api;
pub(crate) mod defaults;
use std::borrow::Cow;
use anyhow::{Result, bail};
use reblessive::tree::Stk;
use crate::catalog::base::Base;
use crate::catalog::providers::{DatabaseProvider, RootProvider};
use crate::catalog::{ConfigDefinition, Error};
use crate::ctx::FrozenContext;
use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::expr::statements::define::DefineKind;
use crate::expr::statements::define::config::{ConfigInner, DefineConfigStatement};
use crate::iam::{Action, ConfigKind, ResourceKind};
use crate::key::schema::{DbConfigKey, RootConfigKey};
use crate::val::Value;
pub(crate) async fn config_inner_compute(
this: &ConfigInner,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> Result<ConfigDefinition> {
Ok(match this {
ConfigInner::GraphQL(g) => ConfigDefinition::GraphQL(g.clone()),
ConfigInner::Api(a) => {
ConfigDefinition::Api(crate::legacy::api_config_compute(a, stk, ctx, opt, doc).await?)
}
ConfigInner::Default(d) => ConfigDefinition::Default(
crate::legacy::default_config_compute(d, stk, ctx, opt, doc).await?,
),
})
}
pub(crate) async fn define_config_statement_compute(
this: &DefineConfigStatement,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> Result<Value> {
let kind = this.inner.kind();
let base = config_kind_base(&kind);
ctx.is_allowed(opt, Action::Edit, ResourceKind::Config(kind), base.clone().into())?;
let txn = ctx.tx();
let cg = match &this.inner {
ConfigInner::GraphQL(_) => "graphql",
ConfigInner::Api(_) => "api",
ConfigInner::Default(_) => "default",
};
match base {
Base::Root => {
if txn.expect_root_config(cg).await.is_ok() {
match this.kind {
DefineKind::Default => {
if !opt.import {
bail!(Error::CgAlreadyExists {
name: cg.to_string(),
});
}
}
DefineKind::Overwrite => {}
DefineKind::IfNotExists => return Ok(Value::None),
}
}
let key = RootConfigKey {
ty: Cow::Borrowed(cg),
};
let store =
crate::legacy::config_inner_compute(&this.inner, stk, ctx, opt, doc).await?;
txn.replace_key(&key, &store.to_stored()).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 this.kind {
DefineKind::Default => {
if !opt.import {
bail!(Error::CgAlreadyExists {
name: cg.to_string(),
});
}
}
DefineKind::Overwrite => {}
DefineKind::IfNotExists => return Ok(Value::None),
}
}
let key = DbConfigKey {
ns,
db,
ty: Cow::Borrowed(cg),
};
let store =
crate::legacy::config_inner_compute(&this.inner, stk, ctx, opt, doc).await?;
txn.replace_key(&key, &store.to_stored()).await?;
txn.clear_cache();
}
}
Ok(Value::None)
}
pub(crate) fn config_kind_base(kind: &ConfigKind) -> Base {
match kind {
ConfigKind::Default => Base::Root,
ConfigKind::GraphQL | ConfigKind::Api => Base::Db,
}
}