use super::{
alteration::SequenceDefinitionContext, lifecycle::SequenceLifecycleContext,
role_ownership::SequenceRoleOwnershipContext,
};
use crate::catalog::security::table_inquiry::TablePrivilegeContext;
use crate::row_locks::binding::{bind_relation, RelationBinding};
use uqa_core::RelationIdentity;
use uqa_sql::{
ast::{AlterSequence, RelationPersistence},
catalog::resolution::RelationResolution,
SQLError,
};
pub trait SequenceCommandCatalog {
fn resolve_visible_relation(&self, name: &str) -> Result<RelationResolution, SQLError>;
fn sequence_persistence(&self, relation: &RelationIdentity) -> RelationPersistence;
}
pub struct SequenceAlterContext<'a> {
pub catalog: &'a dyn SequenceCommandCatalog,
pub authority: TablePrivilegeContext<'a>,
pub definition: SequenceDefinitionContext<'a>,
pub roles: SequenceRoleOwnershipContext<'a>,
pub lifecycle: SequenceLifecycleContext<'a>,
}
pub fn alter_sequence(
context: &SequenceAlterContext<'_>,
alter: &AlterSequence,
) -> Result<bool, SQLError> {
let Some(binding) = bind_alter_sequence(context, alter)? else {
return Ok(false);
};
if let Some(role_owner) = alter.role_owner.as_ref() {
super::role_ownership::alter_sequence_role_owner(
&context.roles,
&binding.name,
&binding.value.relation,
role_owner,
)?;
return Ok(true);
}
let persistence = context
.catalog
.sequence_persistence(&binding.value.relation);
if alter.lifecycle != uqa_sql::ast::SequenceLifecycle::Unchanged {
super::lifecycle::alter_sequence_lifecycle(
&context.lifecycle,
&binding.name,
&binding.value.relation,
persistence,
alter,
)?;
return Ok(true);
}
super::alteration::alter_sequence_definition(
&context.definition,
&binding.name,
&binding.value.relation,
persistence,
alter,
)
}
struct SequenceAlterTarget {
relation: RelationIdentity,
kind: &'static str,
}
fn bind_alter_sequence(
context: &SequenceAlterContext<'_>,
alter: &AlterSequence,
) -> Result<Option<RelationBinding<SequenceAlterTarget>>, SQLError> {
bind_relation(
context.roles.writer,
uqa_sql::schema::sequences::actions::sequence_alter_lock_mode(alter).into(),
false,
|| {
let Some((name, kind)) =
uqa_sql::schema::sequences::lifecycle::sequence_alter_relation(
context.catalog.resolve_visible_relation(&alter.name)?,
alter,
)?
else {
return Ok(None);
};
if alter.role_owner.is_some() {
uqa_sql::schema::sequences::actions::validate_sequence_role_owner_shape(alter)?;
}
let relation = RelationIdentity::from_legacy_name(&name).map_err(|error| {
SQLError::Internal(format!("resolve sequence `{name}`: {error}"))
})?;
Ok(Some(RelationBinding {
name,
object_id: context.roles.metadata.object_id(&relation),
value: SequenceAlterTarget { relation, kind },
}))
},
|binding| {
let target = &binding.value;
crate::schema::relation_alteration::validate_relation_alter_authority(
&context.authority,
&context.lifecycle.creation,
&target.relation,
target.kind,
matches!(
alter.lifecycle,
uqa_sql::ast::SequenceLifecycle::RenameTo { .. }
),
)?;
uqa_sql::schema::sequences::lifecycle::validate_sequence_alter_kind(
alter,
target.kind,
&target.relation.name,
)
},
)
}