use crate::db::schema::{
AcceptedSchemaSnapshot, FieldId, PersistedFieldKind, PersistedFieldOrigin,
PersistedFieldSnapshot, SchemaFieldDefault, SchemaFieldSlot, SchemaFieldWritePolicy,
};
use crate::model::field::{FieldStorageDecode, LeafCodec};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) enum SchemaDdlFieldAdditionCandidateError {
Duplicate,
RequiredWithoutDefault,
}
pub(in crate::db) fn resolve_sql_ddl_field_addition_name_candidate(
accepted_before: &AcceptedSchemaSnapshot,
name: &str,
) -> Result<(), SchemaDdlFieldAdditionCandidateError> {
if accepted_before
.persisted_snapshot()
.fields()
.iter()
.any(|field| field.name() == name)
{
return Err(SchemaDdlFieldAdditionCandidateError::Duplicate);
}
Ok(())
}
pub(in crate::db) fn build_sql_ddl_field_addition_candidate(
accepted_before: &AcceptedSchemaSnapshot,
name: String,
kind: PersistedFieldKind,
nullable: bool,
default: SchemaFieldDefault,
storage_decode: FieldStorageDecode,
leaf_codec: LeafCodec,
) -> Result<PersistedFieldSnapshot, SchemaDdlFieldAdditionCandidateError> {
resolve_sql_ddl_field_addition_name_candidate(accepted_before, name.as_str())?;
if !nullable && default.is_none() {
return Err(SchemaDdlFieldAdditionCandidateError::RequiredWithoutDefault);
}
Ok(PersistedFieldSnapshot::new_with_write_policy_and_origin(
next_sql_ddl_field_id(accepted_before),
name,
next_sql_ddl_field_slot(accepted_before),
kind,
Vec::new(),
nullable,
default,
SchemaFieldWritePolicy::from_model_policies(None, None),
PersistedFieldOrigin::SqlDdl,
storage_decode,
leaf_codec,
))
}
fn next_sql_ddl_field_id(accepted_before: &AcceptedSchemaSnapshot) -> FieldId {
let snapshot = accepted_before.persisted_snapshot();
let next = snapshot
.fields()
.iter()
.map(|field| field.id().get())
.chain(
snapshot
.row_layout()
.retired_field_slots()
.iter()
.map(|(field_id, _)| field_id.get()),
)
.max()
.unwrap_or(0)
.checked_add(1)
.expect("accepted field IDs should not be exhausted");
FieldId::new(next)
}
fn next_sql_ddl_field_slot(accepted_before: &AcceptedSchemaSnapshot) -> SchemaFieldSlot {
accepted_before
.persisted_snapshot()
.row_layout()
.next_unallocated_slot()
}