use crate::{
db::schema::{
AcceptedCompositeCatalog, AcceptedEnumCatalog, AcceptedFieldKind, AcceptedSchemaRevision,
AcceptedSchemaSnapshot, AcceptedValueAdmissionContract, AcceptedValueCatalogHandle,
AcceptedValueContract, FieldId, PersistedNestedLeafSnapshot, PersistedRelationEdgeSnapshot,
RowLayoutVersion, SchemaFieldSlot, SchemaFieldWritePolicy, SchemaHistoricalFill,
SchemaInsertDefault, enum_catalog::EnumCatalogBuildError,
},
error::InternalError,
model::{
entity::EntityModel,
field::{FieldModel, FieldStorageDecode, LeafCodec},
},
};
#[cfg(test)]
use std::cell::Cell;
#[cfg(test)]
thread_local! {
static GENERATED_COMPATIBLE_ROW_LAYOUT_PROOFS: Cell<u64> = const { Cell::new(0) };
}
#[cfg(test)]
pub(in crate::db) fn reset_generated_compatible_row_layout_proof_count_for_tests() {
GENERATED_COMPATIBLE_ROW_LAYOUT_PROOFS.with(|proofs| proofs.set(0));
}
#[cfg(test)]
pub(in crate::db) fn generated_compatible_row_layout_proof_count_for_tests() -> u64 {
GENERATED_COMPATIBLE_ROW_LAYOUT_PROOFS.with(Cell::get)
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) enum AcceptedInsertOmissionPolicy {
NullIfMissing,
DefaultIfMissing,
Required,
}
pub(in crate::db) const fn accepted_insert_field_is_omittable(
omission_policy: AcceptedInsertOmissionPolicy,
write_policy: SchemaFieldWritePolicy,
) -> bool {
!matches!(omission_policy, AcceptedInsertOmissionPolicy::Required)
|| write_policy.insert_generation().is_some()
|| write_policy.write_management().is_some()
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct AcceptedRowLayoutRuntimeField<'a> {
field_id: FieldId,
name: &'a str,
slot: SchemaFieldSlot,
kind: &'a AcceptedFieldKind,
nested_leaves: &'a [PersistedNestedLeafSnapshot],
nullable: bool,
introduced_in_layout: RowLayoutVersion,
insert_default: &'a SchemaInsertDefault,
historical_fill: &'a SchemaHistoricalFill,
write_policy: SchemaFieldWritePolicy,
storage_decode: FieldStorageDecode,
leaf_codec: LeafCodec,
insert_omission_policy: AcceptedInsertOmissionPolicy,
generated: bool,
}
impl<'a> AcceptedRowLayoutRuntimeField<'a> {
#[must_use]
pub(in crate::db) const fn field_id(&self) -> FieldId {
self.field_id
}
#[must_use]
pub(in crate::db) const fn name(&self) -> &'a str {
self.name
}
#[must_use]
pub(in crate::db) const fn slot(&self) -> SchemaFieldSlot {
self.slot
}
#[must_use]
pub(in crate::db) const fn kind(&self) -> &'a AcceptedFieldKind {
self.kind
}
#[cfg(test)]
#[must_use]
pub(in crate::db) const fn nested_leaves(&self) -> &'a [PersistedNestedLeafSnapshot] {
self.nested_leaves
}
#[cfg(test)]
#[must_use]
pub(in crate::db) const fn nullable(&self) -> bool {
self.nullable
}
#[must_use]
pub(in crate::db) const fn introduced_in_layout(&self) -> RowLayoutVersion {
self.introduced_in_layout
}
#[must_use]
pub(in crate::db) const fn insert_default(&self) -> &'a SchemaInsertDefault {
self.insert_default
}
#[must_use]
pub(in crate::db) const fn historical_fill(&self) -> &'a SchemaHistoricalFill {
self.historical_fill
}
#[must_use]
pub(in crate::db) const fn write_policy(&self) -> SchemaFieldWritePolicy {
self.write_policy
}
#[must_use]
pub(in crate::db) const fn insert_omission_policy(&self) -> AcceptedInsertOmissionPolicy {
self.insert_omission_policy
}
#[must_use]
pub(in crate::db) const fn generated(&self) -> bool {
self.generated
}
#[must_use]
pub(in crate::db) const fn decode_contract(&self) -> AcceptedFieldDecodeContract<'a> {
AcceptedFieldDecodeContract::new(
self.name,
self.kind,
self.nullable,
self.storage_decode,
self.leaf_codec,
)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct AcceptedFieldDecodeContract<'a> {
field_name: &'a str,
kind: &'a AcceptedFieldKind,
nullable: bool,
storage_decode: FieldStorageDecode,
leaf_codec: LeafCodec,
}
impl<'a> AcceptedFieldDecodeContract<'a> {
#[must_use]
pub(in crate::db) const fn new(
field_name: &'a str,
kind: &'a AcceptedFieldKind,
nullable: bool,
storage_decode: FieldStorageDecode,
leaf_codec: LeafCodec,
) -> Self {
Self {
field_name,
kind,
nullable,
storage_decode,
leaf_codec,
}
}
#[must_use]
pub(in crate::db) const fn field_name(&self) -> &'a str {
self.field_name
}
#[must_use]
pub(in crate::db) const fn kind(&self) -> &'a AcceptedFieldKind {
self.kind
}
#[must_use]
pub(in crate::db) const fn nullable(&self) -> bool {
self.nullable
}
#[must_use]
pub(in crate::db) const fn storage_decode(&self) -> FieldStorageDecode {
self.storage_decode
}
#[must_use]
pub(in crate::db) const fn leaf_codec(&self) -> LeafCodec {
self.leaf_codec
}
#[must_use]
pub(in crate::db) fn uses_canonical_value_wire(&self) -> bool {
self.kind.requires_canonical_value_wire()
|| matches!(self.storage_decode, FieldStorageDecode::CatalogValue)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct AcceptedFieldPersistenceContract<'a> {
field: AcceptedFieldDecodeContract<'a>,
admission_contract: AcceptedValueAdmissionContract<'a>,
}
impl<'a> AcceptedFieldPersistenceContract<'a> {
pub(in crate::db) fn new(
value_catalog: &'a AcceptedValueCatalogHandle,
field: AcceptedFieldDecodeContract<'a>,
) -> Result<Self, EnumCatalogBuildError> {
let value_contract = AcceptedValueContract::from_accepted_field(
value_catalog,
field.kind(),
field.storage_decode(),
)?;
Ok(Self {
field,
admission_contract: AcceptedValueAdmissionContract::owned(
value_catalog,
value_contract,
field.nullable(),
),
})
}
#[cfg(test)]
pub(in crate::db) fn new_for_tests(
value_catalog: &'a AcceptedValueCatalogHandle,
field: AcceptedFieldDecodeContract<'a>,
) -> Result<Self, EnumCatalogBuildError> {
Self::new(value_catalog, field)
}
#[must_use]
pub(in crate::db) const fn field(&self) -> AcceptedFieldDecodeContract<'a> {
self.field
}
#[must_use]
pub(in crate::db) const fn admission_contract(&self) -> &AcceptedValueAdmissionContract<'a> {
&self.admission_contract
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct OwnedAcceptedFieldDecodeContract {
field_name: String,
kind: AcceptedFieldKind,
nullable: bool,
storage_decode: FieldStorageDecode,
leaf_codec: LeafCodec,
write_policy: SchemaFieldWritePolicy,
insert_omission_policy: AcceptedInsertOmissionPolicy,
introduced_in_layout: RowLayoutVersion,
insert_default: SchemaInsertDefault,
historical_fill: SchemaHistoricalFill,
generated: bool,
}
impl OwnedAcceptedFieldDecodeContract {
#[must_use]
fn from_runtime_field(field: &AcceptedRowLayoutRuntimeField<'_>) -> Self {
let contract = field.decode_contract();
Self {
field_name: contract.field_name().to_string(),
kind: contract.kind().clone(),
nullable: contract.nullable(),
storage_decode: contract.storage_decode(),
leaf_codec: contract.leaf_codec(),
write_policy: field.write_policy(),
insert_omission_policy: field.insert_omission_policy(),
introduced_in_layout: field.introduced_in_layout(),
insert_default: field.insert_default().clone(),
historical_fill: field.historical_fill().clone(),
generated: field.generated(),
}
}
#[must_use]
pub(in crate::db) const fn decode_contract(&self) -> AcceptedFieldDecodeContract<'_> {
AcceptedFieldDecodeContract::new(
self.field_name.as_str(),
&self.kind,
self.nullable,
self.storage_decode,
self.leaf_codec,
)
}
#[must_use]
pub(in crate::db) const fn insert_omission_policy(&self) -> AcceptedInsertOmissionPolicy {
self.insert_omission_policy
}
#[must_use]
pub(in crate::db) const fn write_policy(&self) -> SchemaFieldWritePolicy {
self.write_policy
}
#[must_use]
pub(in crate::db) const fn introduced_in_layout(&self) -> RowLayoutVersion {
self.introduced_in_layout
}
#[must_use]
pub(in crate::db) const fn insert_default(&self) -> &SchemaInsertDefault {
&self.insert_default
}
#[must_use]
pub(in crate::db) const fn historical_fill(&self) -> &SchemaHistoricalFill {
&self.historical_fill
}
#[must_use]
pub(in crate::db) const fn field_name(&self) -> &str {
self.field_name.as_str()
}
#[must_use]
pub(in crate::db) const fn kind(&self) -> &AcceptedFieldKind {
&self.kind
}
#[must_use]
pub(in crate::db) const fn generated(&self) -> bool {
self.generated
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct OwnedAcceptedRelationEdgeContract {
name: String,
physical_generation: u64,
target_path: String,
local_field_slots: Vec<usize>,
}
impl OwnedAcceptedRelationEdgeContract {
fn from_runtime_relation_edge(
relation: &PersistedRelationEdgeSnapshot,
fields: &[AcceptedRowLayoutRuntimeField<'_>],
) -> Result<Self, InternalError> {
let mut local_field_slots = Vec::with_capacity(relation.local_field_ids().len());
for field_id in relation.local_field_ids() {
let Some(field) = fields.iter().find(|field| field.field_id() == *field_id) else {
return Err(InternalError::store_invariant());
};
local_field_slots.push(usize::from(field.slot().get()));
}
Ok(Self {
name: relation.name().to_string(),
physical_generation: relation.physical_generation(),
target_path: relation.target_path().to_string(),
local_field_slots,
})
}
#[must_use]
pub(in crate::db) const fn name(&self) -> &str {
self.name.as_str()
}
#[must_use]
pub(in crate::db) const fn physical_generation(&self) -> u64 {
self.physical_generation
}
#[must_use]
pub(in crate::db) const fn target_path(&self) -> &str {
self.target_path.as_str()
}
#[must_use]
pub(in crate::db) const fn local_field_slots(&self) -> &[usize] {
self.local_field_slots.as_slice()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct AcceptedRowDecodeContract {
current_layout_version: RowLayoutVersion,
history_floor: RowLayoutVersion,
required_slot_count: usize,
primary_key_slot_index: usize,
primary_key_slot_indices: Vec<usize>,
fields_by_slot: Vec<Option<OwnedAcceptedFieldDecodeContract>>,
relation_edges: Vec<OwnedAcceptedRelationEdgeContract>,
value_catalog: AcceptedValueCatalogHandle,
}
impl AcceptedRowDecodeContract {
fn from_runtime_contract(
descriptor: &AcceptedRowLayoutRuntimeContract<'_>,
value_catalog: AcceptedValueCatalogHandle,
) -> Self {
let mut fields_by_slot = vec![None; descriptor.required_slot_count()];
for field in descriptor.fields() {
fields_by_slot[usize::from(field.slot().get())] =
Some(OwnedAcceptedFieldDecodeContract::from_runtime_field(field));
}
Self {
current_layout_version: descriptor.current_layout_version(),
history_floor: descriptor.history_floor(),
required_slot_count: descriptor.required_slot_count(),
primary_key_slot_index: descriptor.first_primary_key_slot_index(),
primary_key_slot_indices: descriptor.primary_key_slot_indices().to_vec(),
fields_by_slot,
relation_edges: descriptor.relation_edges().to_vec(),
value_catalog,
}
}
#[cfg(test)]
pub(in crate::db) fn from_model_proposal_for_test(model: &'static EntityModel) -> Self {
let proposal = crate::db::schema::compiled_schema_proposal_for_model(model);
let (catalog, composite_catalog) =
crate::db::schema::build_initial_accepted_catalogs_for_tests(&[model])
.expect("model proposal catalogs should build for tests");
let snapshot = proposal
.initial_persisted_schema_snapshot_with_catalogs(&catalog, &composite_catalog)
.expect("model proposal should resolve through its test catalogs");
let accepted = AcceptedSchemaSnapshot::try_new(snapshot)
.expect("model proposal should produce an accepted test schema");
let (descriptor, _) = AcceptedRowLayoutRuntimeContract::from_generated_compatible_schema(
&accepted,
model,
&catalog,
&composite_catalog,
)
.expect("accepted test schema should match its model proposal");
let catalog = AcceptedValueCatalogHandle::new_for_tests(
catalog,
composite_catalog,
AcceptedSchemaRevision::INITIAL,
);
descriptor.row_decode_contract(catalog)
}
#[must_use]
pub(in crate::db) const fn required_slot_count(&self) -> usize {
self.required_slot_count
}
#[must_use]
pub(in crate::db) const fn current_layout_version(&self) -> RowLayoutVersion {
self.current_layout_version
}
pub(in crate::db) fn expected_slot_count(
&self,
version: RowLayoutVersion,
) -> Result<usize, InternalError> {
if version < self.history_floor || version > self.current_layout_version {
return Err(InternalError::persisted_row_layout_outside_accepted_window());
}
Ok(self
.fields_by_slot
.iter()
.filter_map(Option::as_ref)
.filter(|field| field.introduced_in_layout() <= version)
.count())
}
#[must_use]
pub(in crate::db) const fn first_primary_key_slot_index(&self) -> usize {
self.primary_key_slot_index
}
#[must_use]
pub(in crate::db) const fn primary_key_slot_indices(&self) -> &[usize] {
self.primary_key_slot_indices.as_slice()
}
#[must_use]
pub(in crate::db) const fn relation_edges(&self) -> &[OwnedAcceptedRelationEdgeContract] {
self.relation_edges.as_slice()
}
#[must_use]
pub(in crate::db) fn enum_catalog(&self) -> &AcceptedEnumCatalog {
self.value_catalog.enum_catalog()
}
#[must_use]
pub(in crate::db) const fn value_catalog_handle(&self) -> &AcceptedValueCatalogHandle {
&self.value_catalog
}
#[must_use]
pub(in crate::db) const fn accepted_schema_revision(&self) -> AcceptedSchemaRevision {
self.value_catalog.revision()
}
#[must_use]
pub(in crate::db) fn field_for_slot(
&self,
slot: usize,
) -> Option<&OwnedAcceptedFieldDecodeContract> {
self.fields_by_slot.get(slot)?.as_ref()
}
pub(in crate::db) fn required_field_for_slot(
&self,
entity_path: &str,
slot: usize,
) -> Result<&OwnedAcceptedFieldDecodeContract, InternalError> {
self.field_for_slot(slot).ok_or_else(|| {
InternalError::persisted_row_slot_lookup_out_of_bounds(entity_path, slot)
})
}
pub(in crate::db) fn required_field_persistence_contract(
&self,
entity_path: &str,
slot: usize,
) -> Result<AcceptedFieldPersistenceContract<'_>, InternalError> {
let field = self.required_field_for_slot(entity_path, slot)?;
AcceptedFieldPersistenceContract::new(self.value_catalog_handle(), field.decode_contract())
.map_err(|_| InternalError::persisted_row_field_encode_internal(field.field_name()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct AcceptedGeneratedRowCompatibilityProof {
required_slot_count: usize,
primary_key_slot_index: usize,
}
impl AcceptedGeneratedRowCompatibilityProof {
#[must_use]
#[cfg(test)]
pub(in crate::db) const fn required_slot_count(self) -> usize {
self.required_slot_count
}
#[must_use]
#[cfg(test)]
pub(in crate::db) const fn first_primary_key_slot_index(self) -> usize {
self.primary_key_slot_index
}
}
#[derive(Debug, Eq, PartialEq)]
pub(in crate::db) struct AcceptedRowLayoutRuntimeContract<'a> {
current_layout_version: RowLayoutVersion,
history_floor: RowLayoutVersion,
required_slot_count: usize,
primary_key_names: Vec<&'a str>,
primary_key_kinds: Vec<&'a AcceptedFieldKind>,
primary_key_slot_indices: Vec<usize>,
fields: Vec<AcceptedRowLayoutRuntimeField<'a>>,
relation_edges: Vec<OwnedAcceptedRelationEdgeContract>,
}
impl<'a> AcceptedRowLayoutRuntimeContract<'a> {
pub(in crate::db) fn from_accepted_schema(
accepted: &'a AcceptedSchemaSnapshot,
) -> Result<Self, InternalError> {
let snapshot = accepted.persisted_snapshot();
let row_layout = snapshot.row_layout();
let mut required_slot_count = 0usize;
let mut fields = Vec::with_capacity(snapshot.fields().len());
for field in snapshot.fields() {
let Some(slot) = row_layout.slot_for_field(field.id()) else {
return Err(InternalError::store_invariant());
};
let slot_end = usize::from(slot.get()).saturating_add(1);
required_slot_count = required_slot_count.max(slot_end);
fields.push(AcceptedRowLayoutRuntimeField {
field_id: field.id(),
name: field.name(),
slot,
kind: field.kind(),
nested_leaves: field.nested_leaves(),
nullable: field.nullable(),
introduced_in_layout: field.introduced_in_layout(),
insert_default: field.insert_default(),
historical_fill: field.historical_fill(),
write_policy: field.write_policy(),
storage_decode: field.storage_decode(),
leaf_codec: field.leaf_codec(),
insert_omission_policy: accepted_insert_omission_policy(
field.nullable(),
field.insert_default(),
),
generated: field.generated(),
});
}
let mut primary_key_names = Vec::with_capacity(snapshot.primary_key_field_ids().len());
let mut primary_key_kinds = Vec::with_capacity(snapshot.primary_key_field_ids().len());
let mut primary_key_slot_indices =
Vec::with_capacity(snapshot.primary_key_field_ids().len());
for primary_key_field_id in snapshot.primary_key_field_ids() {
let Some(primary_key_field) = fields
.iter()
.find(|field| field.field_id() == *primary_key_field_id)
else {
return Err(InternalError::store_invariant());
};
primary_key_names.push(primary_key_field.name());
primary_key_kinds.push(primary_key_field.kind());
primary_key_slot_indices.push(usize::from(primary_key_field.slot().get()));
}
let relation_edges = snapshot
.relations()
.iter()
.map(|relation| {
OwnedAcceptedRelationEdgeContract::from_runtime_relation_edge(relation, &fields)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Self {
current_layout_version: row_layout.current_version(),
history_floor: row_layout.history_floor(),
required_slot_count,
primary_key_names,
primary_key_kinds,
primary_key_slot_indices,
fields,
relation_edges,
})
}
pub(in crate::db) fn from_generated_compatible_schema(
accepted: &'a AcceptedSchemaSnapshot,
model: &'static EntityModel,
enum_catalog: &AcceptedEnumCatalog,
composite_catalog: &AcceptedCompositeCatalog,
) -> Result<(Self, AcceptedGeneratedRowCompatibilityProof), InternalError> {
#[cfg(test)]
GENERATED_COMPATIBLE_ROW_LAYOUT_PROOFS
.with(|proofs| proofs.set(proofs.get().saturating_add(1)));
let descriptor = Self::from_accepted_schema(accepted)?;
let row_proof = descriptor.generated_row_compatibility_proof_for_model_with_catalogs(
model,
enum_catalog,
composite_catalog,
)?;
Ok((descriptor, row_proof))
}
#[must_use]
pub(in crate::db) const fn current_layout_version(&self) -> RowLayoutVersion {
self.current_layout_version
}
#[must_use]
pub(in crate::db) const fn history_floor(&self) -> RowLayoutVersion {
self.history_floor
}
#[must_use]
pub(in crate::db) const fn required_slot_count(&self) -> usize {
self.required_slot_count
}
#[must_use]
pub(in crate::db) const fn primary_key_names(&self) -> &[&'a str] {
self.primary_key_names.as_slice()
}
#[must_use]
#[cfg(any(test, feature = "sql"))]
pub(in crate::db) fn is_primary_key_field_name(&self, field_name: &str) -> bool {
self.primary_key_names.contains(&field_name)
}
#[must_use]
#[cfg(feature = "sql")]
pub(in crate::db) fn first_primary_key_kind(&self) -> &'a AcceptedFieldKind {
self.primary_key_kinds[0]
}
#[cfg(any(test, feature = "sql"))]
#[must_use]
pub(in crate::db) const fn primary_key_kinds(&self) -> &[&'a AcceptedFieldKind] {
self.primary_key_kinds.as_slice()
}
#[must_use]
pub(in crate::db) fn first_primary_key_slot_index(&self) -> usize {
self.primary_key_slot_indices[0]
}
#[must_use]
pub(in crate::db) const fn primary_key_slot_indices(&self) -> &[usize] {
self.primary_key_slot_indices.as_slice()
}
#[must_use]
pub(in crate::db) const fn relation_edges(&self) -> &[OwnedAcceptedRelationEdgeContract] {
self.relation_edges.as_slice()
}
#[must_use]
pub(in crate::db) const fn fields(&self) -> &[AcceptedRowLayoutRuntimeField<'a>] {
self.fields.as_slice()
}
#[cfg(test)]
#[must_use]
pub(in crate::db) fn field_for_slot(
&self,
slot: SchemaFieldSlot,
) -> Option<&AcceptedRowLayoutRuntimeField<'a>> {
self.fields.iter().find(|field| field.slot() == slot)
}
#[must_use]
pub(in crate::db) fn field_for_slot_index(
&self,
slot: usize,
) -> Option<&AcceptedRowLayoutRuntimeField<'a>> {
self.fields
.iter()
.find(|field| usize::from(field.slot().get()) == slot)
}
#[cfg(test)]
#[must_use]
pub(in crate::db) fn field_for_id(
&self,
field_id: FieldId,
) -> Option<&AcceptedRowLayoutRuntimeField<'a>> {
self.fields
.iter()
.find(|field| field.field_id() == field_id)
}
#[must_use]
pub(in crate::db) fn field_by_name(
&self,
name: &str,
) -> Option<&AcceptedRowLayoutRuntimeField<'a>> {
self.fields.iter().find(|field| field.name() == name)
}
#[must_use]
pub(in crate::db) fn field_slot_index_by_name(&self, name: &str) -> Option<usize> {
self.field_by_name(name)
.map(|field| usize::from(field.slot().get()))
}
#[must_use]
pub(in crate::db) fn row_decode_contract(
&self,
value_catalog: AcceptedValueCatalogHandle,
) -> AcceptedRowDecodeContract {
AcceptedRowDecodeContract::from_runtime_contract(self, value_catalog)
}
#[cfg(test)]
pub(in crate::db) fn generated_row_compatibility_proof_for_model(
&self,
model: &'static EntityModel,
) -> Result<AcceptedGeneratedRowCompatibilityProof, InternalError> {
let (enum_catalog, composite_catalog) =
crate::db::schema::build_initial_accepted_catalogs_for_tests(&[model])
.map_err(|()| InternalError::store_invariant())?;
self.generated_row_compatibility_proof_for_model_with_catalogs(
model,
&enum_catalog,
&composite_catalog,
)
}
fn generated_row_compatibility_proof_for_model_with_catalogs(
&self,
model: &'static EntityModel,
enum_catalog: &AcceptedEnumCatalog,
composite_catalog: &AcceptedCompositeCatalog,
) -> Result<AcceptedGeneratedRowCompatibilityProof, InternalError> {
let generated_primary_key_names = model
.primary_key_model()
.fields()
.iter()
.map(FieldModel::name)
.collect::<Vec<_>>();
if self.primary_key_names() != generated_primary_key_names.as_slice() {
return Err(InternalError::store_invariant());
}
if self.required_slot_count() < model.fields().len() {
return Err(InternalError::store_invariant());
}
for (generated_slot, field) in model.fields().iter().enumerate() {
let Some(accepted_field) = self.field_by_name(field.name()) else {
return Err(InternalError::store_invariant());
};
let accepted_slot = usize::from(accepted_field.slot().get());
if accepted_slot != generated_slot {
return Err(InternalError::store_invariant());
}
ensure_generated_field_decode_contract_compatible(
accepted_field,
field,
enum_catalog,
composite_catalog,
)?;
}
for slot in model.fields().len()..self.required_slot_count() {
let Some(extra_field) = self.field_for_slot_index(slot) else {
continue;
};
if extra_field.generated() {
return Err(InternalError::store_invariant());
}
}
Ok(AcceptedGeneratedRowCompatibilityProof {
required_slot_count: self.required_slot_count(),
primary_key_slot_index: self.first_primary_key_slot_index(),
})
}
}
fn ensure_generated_field_decode_contract_compatible(
accepted_field: &AcceptedRowLayoutRuntimeField<'_>,
generated_field: &FieldModel,
enum_catalog: &AcceptedEnumCatalog,
composite_catalog: &AcceptedCompositeCatalog,
) -> Result<(), InternalError> {
let accepted_contract = accepted_field.decode_contract();
if !accepted_contract.kind().matches_generated_storage_shape(
generated_field.kind(),
enum_catalog,
composite_catalog,
) {
return Err(InternalError::store_invariant());
}
if accepted_contract.nullable() != generated_field.nullable() {
return Err(InternalError::store_invariant());
}
if accepted_contract.storage_decode() != generated_field.storage_decode() {
return Err(InternalError::store_invariant());
}
if accepted_contract.leaf_codec() != generated_field.leaf_codec() {
return Err(InternalError::store_invariant());
}
Ok(())
}
const fn accepted_insert_omission_policy(
nullable: bool,
default: &SchemaInsertDefault,
) -> AcceptedInsertOmissionPolicy {
match (nullable, default) {
(true, SchemaInsertDefault::None) => AcceptedInsertOmissionPolicy::NullIfMissing,
(false, SchemaInsertDefault::None) => AcceptedInsertOmissionPolicy::Required,
(_, SchemaInsertDefault::SlotPayload(_)) => AcceptedInsertOmissionPolicy::DefaultIfMissing,
}
}
#[cfg(test)]
mod tests;