blob: c32bf0d466bd2f8451e6e38de85c87ad0b1d02a5 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
//! Root-owned connection catalog and credential vault. These are control
//! authorities, never model history, and their public revisions are independent.
pub mod access;
mod catalog;
mod changes;
pub mod connection_test;
mod database;
mod effect_snapshot;
pub mod language;
pub use effect_snapshot::ConnectionObservation;
pub mod model_catalog;
pub mod model_fetch;
pub mod network;
pub mod oauth;
pub mod onboarding;
pub mod plugin_authorization;
mod plugin_credentials;
mod policy;
pub mod pricing;
pub mod projection;
pub mod public_catalog;
mod vault;
pub use maka_event_log::connection::BoxFuture;
use maka_event_log::{StoreError, connection::OwnedConnection, root::RootOwner};
use sqlx::{Connection, SqliteConnection};
use std::sync::Arc;
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("invalid configuration: {0}")]
Invalid(String),
#[error("unsupported configuration database")]
UnsupportedDatabase,
#[error("configuration commit outcome is unknown")]
CommitUnknown,
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Sqlx(#[from] sqlx::Error),
#[error(transparent)]
Migration(#[from] sqlx::migrate::MigrateError),
#[error(transparent)]
Store(StoreError),
#[error(transparent)]
Json(#[from] serde_json::Error),
}
pub type Result<T> = std::result::Result<T, ConfigError>;
impl From<StoreError> for ConfigError {
fn from(error: StoreError) -> Self {
match error {
StoreError::OperationUnknown | StoreError::CommitUnknown(_) => Self::CommitUnknown,
StoreError::UnsupportedDatabase => Self::UnsupportedDatabase,
StoreError::Sqlx(error) => Self::Sqlx(error),
StoreError::Migration(error) => Self::Migration(error),
StoreError::Io(error) => Self::Io(error),
error => Self::Store(error),
}
}
}
pub(crate) enum TransactionMode {
Deferred,
Immediate,
}
pub struct ConfigurationStore {
connection: OwnedConnection,
}
impl ConfigurationStore {
pub async fn for_root(owner: Arc<RootOwner>) -> Result<Self> {
owner.validate_current()?;
let connection = database::open(owner).await?;
Ok(Self { connection })
}
pub(crate) async fn transaction<T: Send + 'static>(
&self,
mode: TransactionMode,
operation: impl for<'c> FnOnce(&'c mut SqliteConnection) -> BoxFuture<'c, Result<T>>
+ Send
+ 'static,
) -> Result<T> {
self.connection
.run(move |connection| {
Box::pin(async move {
let mut tx = connection
.begin_with(match mode {
TransactionMode::Deferred => "BEGIN",
TransactionMode::Immediate => "BEGIN IMMEDIATE",
})
.await?;
match operation(&mut tx).await {
Ok(value) => Ok(tx
.commit()
.await
.map(|()| value)
.map_err(|_| ConfigError::CommitUnknown)),
Err(error) => {
// Finish rollback before the next accepted job can run.
tx.rollback().await?;
Ok(Err(error))
}
}
})
})
.await?
}
pub async fn shutdown(&self) -> Result<()> {
self.connection.shutdown().await?;
Ok(())
}
pub async fn close(self) -> Result<()> {
self.connection.close().await?;
Ok(())
}
}