use selene_core::{
DbString, HnswIndexConfig, IvfIndexConfig, SchemaChange, SchemaPropertyIndexKind,
SchemaVectorIndexKind,
};
use smallvec::SmallVec;
use crate::core_provider::sections::SchemaEntityKind;
use crate::graph::{
CompositePropertyIndexEntry, PropertyIndexEntry, SeleneGraph, TextIndexEntry, VectorIndexEntry,
};
use crate::typed_index::TypedIndex;
use crate::typed_index::TypedIndexKind;
use crate::vector_index::{VectorIndex, VectorIndexKind};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(super) enum PendingIndex {
Create {
entity: SchemaEntityKind,
label: DbString,
property: DbString,
kind: TypedIndexKind,
name: Option<DbString>,
},
Drop {
entity: SchemaEntityKind,
label: DbString,
property: DbString,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(super) enum PendingCompositeIndex {
Create {
label: DbString,
properties: SmallVec<[DbString; 4]>,
kinds: SmallVec<[TypedIndexKind; 4]>,
name: Option<DbString>,
},
Drop {
label: DbString,
properties: SmallVec<[DbString; 4]>,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(super) enum PendingVectorIndex {
Create {
label: DbString,
property: DbString,
kind: VectorIndexKind,
dimension: u32,
hnsw_config: Option<HnswIndexConfig>,
ivf_config: Option<IvfIndexConfig>,
name: Option<DbString>,
},
Drop {
label: DbString,
property: DbString,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(super) enum PendingTextIndex {
Create {
label: DbString,
property: DbString,
name: Option<DbString>,
},
Drop {
label: DbString,
property: DbString,
},
}
pub(super) fn pending_property_index_change(change: &SchemaChange) -> Option<PendingIndex> {
match change {
SchemaChange::PropertyIndexCreated {
label,
property,
kind,
} => Some(PendingIndex::Create {
entity: SchemaEntityKind::Node,
label: label.clone(),
property: property.clone(),
kind: typed_kind_from(*kind),
name: None,
}),
SchemaChange::PropertyIndexCreatedNamed {
label,
property,
kind,
name,
} => Some(PendingIndex::Create {
entity: SchemaEntityKind::Node,
label: label.clone(),
property: property.clone(),
kind: typed_kind_from(*kind),
name: name.clone(),
}),
SchemaChange::PropertyIndexDropped { label, property } => Some(PendingIndex::Drop {
entity: SchemaEntityKind::Node,
label: label.clone(),
property: property.clone(),
}),
SchemaChange::EdgePropertyIndexCreated {
label,
property,
kind,
name,
} => Some(PendingIndex::Create {
entity: SchemaEntityKind::Edge,
label: label.clone(),
property: property.clone(),
kind: typed_kind_from(*kind),
name: name.clone(),
}),
SchemaChange::EdgePropertyIndexDropped { label, property } => Some(PendingIndex::Drop {
entity: SchemaEntityKind::Edge,
label: label.clone(),
property: property.clone(),
}),
_ => None,
}
}
pub(super) fn replay_property_index_changes(
graph: &mut SeleneGraph,
changes: &[PendingIndex],
) -> crate::GraphResult<()> {
for change in changes {
match change {
PendingIndex::Create {
entity,
label,
property,
kind,
name,
} => {
let target = match entity {
SchemaEntityKind::Node => &mut graph.property_index,
SchemaEntityKind::Edge => &mut graph.edge_property_index,
};
target.insert(
(label.clone(), property.clone()),
PropertyIndexEntry::new(TypedIndex::new(*kind), name.clone()),
);
}
PendingIndex::Drop {
entity,
label,
property,
} => {
let target = match entity {
SchemaEntityKind::Node => &mut graph.property_index,
SchemaEntityKind::Edge => &mut graph.edge_property_index,
};
target.remove(&(label.clone(), property.clone()));
}
}
}
Ok(())
}
pub(super) fn pending_composite_property_index_change(
change: &SchemaChange,
) -> Option<PendingCompositeIndex> {
match change {
SchemaChange::CompositePropertyIndexCreated {
label,
properties,
kinds,
name,
} => Some(PendingCompositeIndex::Create {
label: label.clone(),
properties: properties.clone(),
kinds: kinds.iter().copied().map(typed_kind_from).collect(),
name: name.clone(),
}),
SchemaChange::CompositePropertyIndexDropped { label, properties } => {
Some(PendingCompositeIndex::Drop {
label: label.clone(),
properties: properties.clone(),
})
}
_ => None,
}
}
pub(super) fn replay_composite_property_index_changes(
graph: &mut SeleneGraph,
changes: &[PendingCompositeIndex],
) -> crate::GraphResult<()> {
for change in changes {
match change {
PendingCompositeIndex::Create {
label,
properties,
kinds,
name,
} => {
let key = crate::graph::composite_property_key(properties);
graph.composite_property_index.insert(
(label.clone(), key),
CompositePropertyIndexEntry::new(
crate::CompositeTypedIndex::new(kinds.clone()),
properties.clone(),
name.clone(),
),
);
}
PendingCompositeIndex::Drop { label, properties } => {
let key = crate::graph::composite_property_key(properties);
graph.composite_property_index.remove(&(label.clone(), key));
}
}
}
Ok(())
}
pub(super) fn pending_vector_index_change(change: &SchemaChange) -> Option<PendingVectorIndex> {
match change {
SchemaChange::VectorIndexCreated {
label,
property,
kind,
dimension,
name,
hnsw_config,
ivf_config,
} => Some(PendingVectorIndex::Create {
label: label.clone(),
property: property.clone(),
kind: vector_kind_from(*kind),
dimension: *dimension,
hnsw_config: *hnsw_config,
ivf_config: *ivf_config,
name: name.clone(),
}),
SchemaChange::VectorIndexDropped { label, property } => Some(PendingVectorIndex::Drop {
label: label.clone(),
property: property.clone(),
}),
_ => None,
}
}
pub(super) fn replay_vector_index_changes(
graph: &mut SeleneGraph,
changes: &[PendingVectorIndex],
) -> crate::GraphResult<()> {
for change in changes {
match change {
PendingVectorIndex::Create {
label,
property,
kind,
dimension,
hnsw_config,
ivf_config,
name,
} => {
graph.vector_index.insert(
(label.clone(), property.clone()),
VectorIndexEntry::new(
VectorIndex::new_with_configs(
*kind,
*dimension,
*hnsw_config,
*ivf_config,
)?,
name.clone(),
),
);
}
PendingVectorIndex::Drop { label, property } => {
graph
.vector_index
.remove(&(label.clone(), property.clone()));
}
}
}
Ok(())
}
pub(super) fn pending_text_index_change(change: &SchemaChange) -> Option<PendingTextIndex> {
match change {
SchemaChange::TextIndexCreated {
label,
property,
name,
} => Some(PendingTextIndex::Create {
label: label.clone(),
property: property.clone(),
name: name.clone(),
}),
SchemaChange::TextIndexDropped { label, property } => Some(PendingTextIndex::Drop {
label: label.clone(),
property: property.clone(),
}),
_ => None,
}
}
pub(super) fn replay_text_index_changes(
graph: &mut SeleneGraph,
changes: &[PendingTextIndex],
) -> crate::GraphResult<()> {
for change in changes {
match change {
PendingTextIndex::Create {
label,
property,
name,
} => {
graph.text_index.insert(
(label.clone(), property.clone()),
TextIndexEntry::new(
crate::TextIndex::empty(label.clone(), property.clone()),
name.clone(),
),
);
}
PendingTextIndex::Drop { label, property } => {
graph.text_index.remove(&(label.clone(), property.clone()));
}
}
}
Ok(())
}
pub(super) const fn typed_kind_from(kind: SchemaPropertyIndexKind) -> TypedIndexKind {
match kind {
SchemaPropertyIndexKind::Bool => TypedIndexKind::Bool,
SchemaPropertyIndexKind::I64 => TypedIndexKind::I64,
SchemaPropertyIndexKind::U64 => TypedIndexKind::U64,
SchemaPropertyIndexKind::I128 => TypedIndexKind::I128,
SchemaPropertyIndexKind::U128 => TypedIndexKind::U128,
SchemaPropertyIndexKind::Decimal => TypedIndexKind::Decimal,
SchemaPropertyIndexKind::F32 => TypedIndexKind::F32,
SchemaPropertyIndexKind::F64 => TypedIndexKind::F64,
SchemaPropertyIndexKind::String => TypedIndexKind::String,
SchemaPropertyIndexKind::Date => TypedIndexKind::Date,
SchemaPropertyIndexKind::LocalDateTime => TypedIndexKind::LocalDateTime,
SchemaPropertyIndexKind::ZonedDateTime => TypedIndexKind::ZonedDateTime,
SchemaPropertyIndexKind::LocalTime => TypedIndexKind::LocalTime,
SchemaPropertyIndexKind::ZonedTime => TypedIndexKind::ZonedTime,
SchemaPropertyIndexKind::Duration => TypedIndexKind::Duration,
SchemaPropertyIndexKind::Uuid => TypedIndexKind::Uuid,
}
}
pub(super) const fn vector_kind_from(kind: SchemaVectorIndexKind) -> VectorIndexKind {
match kind {
SchemaVectorIndexKind::Flat => VectorIndexKind::Flat,
SchemaVectorIndexKind::HnswSquaredEuclidean => VectorIndexKind::HnswSquaredEuclidean,
SchemaVectorIndexKind::HnswCosine => VectorIndexKind::HnswCosine,
SchemaVectorIndexKind::HnswNegativeInnerProduct => {
VectorIndexKind::HnswNegativeInnerProduct
}
SchemaVectorIndexKind::IvfSquaredEuclidean => VectorIndexKind::IvfSquaredEuclidean,
SchemaVectorIndexKind::IvfCosine => VectorIndexKind::IvfCosine,
SchemaVectorIndexKind::IvfNegativeInnerProduct => VectorIndexKind::IvfNegativeInnerProduct,
SchemaVectorIndexKind::TurboQuantCosine => VectorIndexKind::TurboQuantCosine,
}
}