use super::now_micros;
use crate::catalog::schema::{ColumnDef, TableSchema};
use crate::catalog::types::ColumnType;
use crate::catalog::{
ASSERTION_AUDIT_TABLE, AUTHZ_AUDIT_TABLE, Catalog, EVENT_OUTBOX_TABLE, LIFECYCLE_OUTBOX_TABLE,
REACTIVE_PROCESSOR_CHECKPOINTS_TABLE, REACTIVE_PROCESSOR_DLQ_TABLE,
REACTIVE_PROCESSOR_REGISTRY_TABLE, SYSTEM_SCOPE_ID, namespace_key,
};
use crate::error::AedbError;
pub(super) fn ensure_internal_audit_schema_for_upsert(
catalog: &mut Catalog,
project_id: &str,
scope_id: &str,
table_name: &str,
) -> Result<(), AedbError> {
if project_id == crate::catalog::SYSTEM_PROJECT_ID
&& scope_id == SYSTEM_SCOPE_ID
&& table_name == ASSERTION_AUDIT_TABLE
{
ensure_assertion_audit_schema(catalog)?;
} else if project_id == crate::catalog::SYSTEM_PROJECT_ID
&& scope_id == SYSTEM_SCOPE_ID
&& table_name == LIFECYCLE_OUTBOX_TABLE
{
ensure_lifecycle_outbox_schema(catalog)?;
} else if project_id == crate::catalog::SYSTEM_PROJECT_ID
&& scope_id == SYSTEM_SCOPE_ID
&& table_name == EVENT_OUTBOX_TABLE
{
ensure_event_outbox_schema(catalog)?;
} else if project_id == crate::catalog::SYSTEM_PROJECT_ID
&& scope_id == SYSTEM_SCOPE_ID
&& table_name == REACTIVE_PROCESSOR_CHECKPOINTS_TABLE
{
ensure_reactive_processor_checkpoints_schema(catalog)?;
} else if project_id == crate::catalog::SYSTEM_PROJECT_ID
&& scope_id == SYSTEM_SCOPE_ID
&& table_name == REACTIVE_PROCESSOR_REGISTRY_TABLE
{
ensure_reactive_processor_registry_schema(catalog)?;
} else if project_id == crate::catalog::SYSTEM_PROJECT_ID
&& scope_id == SYSTEM_SCOPE_ID
&& table_name == REACTIVE_PROCESSOR_DLQ_TABLE
{
ensure_reactive_processor_dead_letter_schema(catalog)?;
}
Ok(())
}
pub(super) fn ensure_authz_audit_schema(catalog: &mut Catalog) -> Result<(), AedbError> {
ensure_system_project_scope(catalog);
let key = (
namespace_key(crate::catalog::SYSTEM_PROJECT_ID, SYSTEM_SCOPE_ID),
AUTHZ_AUDIT_TABLE.to_string(),
);
if catalog.tables.contains_key(&key) {
return Ok(());
}
catalog.tables.insert(
key,
TableSchema {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
table_name: AUTHZ_AUDIT_TABLE.to_string(),
owner_id: Some("system".to_string()),
columns: vec![
ColumnDef {
name: "seq".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "ts_micros".to_string(),
col_type: ColumnType::Timestamp,
nullable: false,
},
ColumnDef {
name: "action".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "actor_id".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "target_caller_id".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "permission".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "project_id".to_string(),
col_type: ColumnType::Text,
nullable: true,
},
ColumnDef {
name: "scope_id".to_string(),
col_type: ColumnType::Text,
nullable: true,
},
ColumnDef {
name: "table_name".to_string(),
col_type: ColumnType::Text,
nullable: true,
},
ColumnDef {
name: "delegable".to_string(),
col_type: ColumnType::Boolean,
nullable: false,
},
ColumnDef {
name: "resource_type".to_string(),
col_type: ColumnType::Text,
nullable: true,
},
ColumnDef {
name: "resource_id".to_string(),
col_type: ColumnType::Text,
nullable: true,
},
ColumnDef {
name: "metadata".to_string(),
col_type: ColumnType::Text,
nullable: true,
},
],
primary_key: vec!["seq".to_string()],
constraints: Vec::new(),
foreign_keys: Vec::new(),
},
);
Ok(())
}
fn ensure_assertion_audit_schema(catalog: &mut Catalog) -> Result<(), AedbError> {
ensure_system_project_scope(catalog);
let key = (
namespace_key(crate::catalog::SYSTEM_PROJECT_ID, SYSTEM_SCOPE_ID),
ASSERTION_AUDIT_TABLE.to_string(),
);
if catalog.tables.contains_key(&key) {
return Ok(());
}
catalog.tables.insert(
key,
TableSchema {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
table_name: ASSERTION_AUDIT_TABLE.to_string(),
owner_id: Some("system".to_string()),
columns: vec![
ColumnDef {
name: "seq".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "ts_micros".to_string(),
col_type: ColumnType::Timestamp,
nullable: false,
},
ColumnDef {
name: "caller_id".to_string(),
col_type: ColumnType::Text,
nullable: true,
},
ColumnDef {
name: "assertion_index".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "assertion".to_string(),
col_type: ColumnType::Json,
nullable: false,
},
ColumnDef {
name: "actual".to_string(),
col_type: ColumnType::Json,
nullable: false,
},
ColumnDef {
name: "error".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
],
primary_key: vec!["seq".to_string()],
constraints: vec![],
foreign_keys: vec![],
},
);
Ok(())
}
fn ensure_lifecycle_outbox_schema(catalog: &mut Catalog) -> Result<(), AedbError> {
ensure_system_project_scope(catalog);
let key = (
namespace_key(crate::catalog::SYSTEM_PROJECT_ID, SYSTEM_SCOPE_ID),
LIFECYCLE_OUTBOX_TABLE.to_string(),
);
if catalog.tables.contains_key(&key) {
return Ok(());
}
catalog.tables.insert(
key,
TableSchema {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
table_name: LIFECYCLE_OUTBOX_TABLE.to_string(),
owner_id: Some("system".to_string()),
columns: vec![
ColumnDef {
name: "commit_seq".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "ts_micros".to_string(),
col_type: ColumnType::Timestamp,
nullable: false,
},
ColumnDef {
name: "event_count".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "events".to_string(),
col_type: ColumnType::Json,
nullable: false,
},
],
primary_key: vec!["commit_seq".to_string()],
constraints: vec![],
foreign_keys: vec![],
},
);
Ok(())
}
pub(super) fn ensure_event_outbox_schema(catalog: &mut Catalog) -> Result<(), AedbError> {
ensure_system_project_scope(catalog);
let key = (
namespace_key(crate::catalog::SYSTEM_PROJECT_ID, SYSTEM_SCOPE_ID),
EVENT_OUTBOX_TABLE.to_string(),
);
if catalog.tables.contains_key(&key) {
return Ok(());
}
catalog.tables.insert(
key,
TableSchema {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
table_name: EVENT_OUTBOX_TABLE.to_string(),
owner_id: Some("system".to_string()),
columns: vec![
ColumnDef {
name: "commit_seq".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "ts_micros".to_string(),
col_type: ColumnType::Timestamp,
nullable: false,
},
ColumnDef {
name: "project_id".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "scope_id".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "topic".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "event_key".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "payload".to_string(),
col_type: ColumnType::Json,
nullable: false,
},
],
primary_key: vec![
"commit_seq".to_string(),
"topic".to_string(),
"event_key".to_string(),
],
constraints: vec![],
foreign_keys: vec![],
},
);
Ok(())
}
fn ensure_reactive_processor_checkpoints_schema(catalog: &mut Catalog) -> Result<(), AedbError> {
ensure_system_project_scope(catalog);
let key = (
namespace_key(crate::catalog::SYSTEM_PROJECT_ID, SYSTEM_SCOPE_ID),
REACTIVE_PROCESSOR_CHECKPOINTS_TABLE.to_string(),
);
if catalog.tables.contains_key(&key) {
return Ok(());
}
catalog.tables.insert(
key,
TableSchema {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
table_name: REACTIVE_PROCESSOR_CHECKPOINTS_TABLE.to_string(),
owner_id: Some("system".to_string()),
columns: vec![
ColumnDef {
name: "processor_name".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "checkpoint_seq".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "updated_at_micros".to_string(),
col_type: ColumnType::Timestamp,
nullable: false,
},
],
primary_key: vec!["processor_name".to_string()],
constraints: vec![],
foreign_keys: vec![],
},
);
Ok(())
}
fn ensure_reactive_processor_registry_schema(catalog: &mut Catalog) -> Result<(), AedbError> {
ensure_system_project_scope(catalog);
let key = (
namespace_key(crate::catalog::SYSTEM_PROJECT_ID, SYSTEM_SCOPE_ID),
REACTIVE_PROCESSOR_REGISTRY_TABLE.to_string(),
);
if catalog.tables.contains_key(&key) {
return Ok(());
}
catalog.tables.insert(
key,
TableSchema {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
table_name: REACTIVE_PROCESSOR_REGISTRY_TABLE.to_string(),
owner_id: Some("system".to_string()),
columns: vec![
ColumnDef {
name: "processor_name".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "options_json".to_string(),
col_type: ColumnType::Json,
nullable: false,
},
ColumnDef {
name: "enabled".to_string(),
col_type: ColumnType::Boolean,
nullable: false,
},
ColumnDef {
name: "updated_at_micros".to_string(),
col_type: ColumnType::Timestamp,
nullable: false,
},
],
primary_key: vec!["processor_name".to_string()],
constraints: vec![],
foreign_keys: vec![],
},
);
Ok(())
}
fn ensure_reactive_processor_dead_letter_schema(catalog: &mut Catalog) -> Result<(), AedbError> {
ensure_system_project_scope(catalog);
let key = (
namespace_key(crate::catalog::SYSTEM_PROJECT_ID, SYSTEM_SCOPE_ID),
REACTIVE_PROCESSOR_DLQ_TABLE.to_string(),
);
if catalog.tables.contains_key(&key) {
return Ok(());
}
catalog.tables.insert(
key,
TableSchema {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
table_name: REACTIVE_PROCESSOR_DLQ_TABLE.to_string(),
owner_id: Some("system".to_string()),
columns: vec![
ColumnDef {
name: "processor_name".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "commit_seq".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "topic".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "event_key".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "payload_json".to_string(),
col_type: ColumnType::Json,
nullable: false,
},
ColumnDef {
name: "error".to_string(),
col_type: ColumnType::Text,
nullable: false,
},
ColumnDef {
name: "attempts".to_string(),
col_type: ColumnType::Integer,
nullable: false,
},
ColumnDef {
name: "failed_at_micros".to_string(),
col_type: ColumnType::Timestamp,
nullable: false,
},
],
primary_key: vec![
"processor_name".to_string(),
"commit_seq".to_string(),
"event_key".to_string(),
],
constraints: vec![],
foreign_keys: vec![],
},
);
Ok(())
}
fn ensure_system_project_scope(catalog: &mut Catalog) {
if !catalog
.projects
.contains_key(crate::catalog::SYSTEM_PROJECT_ID)
{
catalog.projects.insert(
crate::catalog::SYSTEM_PROJECT_ID.to_string(),
crate::catalog::project::ProjectMeta {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
created_at_micros: now_micros(),
owner_id: Some("system".to_string()),
},
);
}
if !catalog.scopes.contains_key(&(
crate::catalog::SYSTEM_PROJECT_ID.to_string(),
SYSTEM_SCOPE_ID.to_string(),
)) {
catalog.scopes.insert(
(
crate::catalog::SYSTEM_PROJECT_ID.to_string(),
SYSTEM_SCOPE_ID.to_string(),
),
crate::catalog::project::ScopeMeta {
project_id: crate::catalog::SYSTEM_PROJECT_ID.to_string(),
scope_id: SYSTEM_SCOPE_ID.to_string(),
created_at_micros: now_micros(),
owner_id: Some("system".to_string()),
},
);
}
}