use bytemuck::TransparentWrapperAlloc as _; use derive_more::Into; use pyo3::prelude::*; use segment::json_path::JsonPath; use segment::types::{Filter, Payload, VectorNameBuf}; use shard::operations::point_ops::{PointIdsList, PointInsertOperationsInternal, UpdateMode}; use shard::operations::*; use crate::*; #[pyclass(name = "UpdateOperation", from_py_object)] #[derive(Clone, Debug, Into)] pub struct PyUpdateOperation(CollectionUpdateOperations); #[pymethods] impl PyUpdateOperation { #[staticmethod] #[pyo3(signature = (points, condition=None, update_mode=None))] pub fn upsert_points( points: Vec, condition: Option, update_mode: Option, ) -> Self { let points = PointInsertOperationsInternal::PointsList(PyPoint::peel_vec(points)); let update_mode = update_mode.map(UpdateMode::from); let operation = match (condition, update_mode) { // If condition or non-default update_mode is provided, use conditional upsert (Some(condition), mode) => point_ops::PointOperations::UpsertPointsConditional( point_ops::ConditionalInsertOperationInternal { points_op: points, condition: Filter::from(condition), update_mode: mode, }, ), (None, Some(mode)) => point_ops::PointOperations::UpsertPointsConditional( point_ops::ConditionalInsertOperationInternal { points_op: points, condition: Filter::default(), update_mode: Some(mode), }, ), // Default case: regular upsert (None, None) => point_ops::PointOperations::UpsertPoints(points), }; Self(CollectionUpdateOperations::PointOperation(operation)) } #[staticmethod] pub fn delete_points(point_ids: Vec) -> Self { let operation = point_ops::PointOperations::DeletePoints { ids: PyPointId::peel_vec(point_ids), }; Self(CollectionUpdateOperations::PointOperation(operation)) } #[staticmethod] pub fn delete_points_by_filter(filter: PyFilter) -> Self { let operation = point_ops::PointOperations::DeletePointsByFilter(Filter::from(filter)); Self(CollectionUpdateOperations::PointOperation(operation)) } #[staticmethod] #[pyo3(signature = (point_vectors, condition=None))] pub fn update_vectors(point_vectors: Vec, condition: Option) -> Self { let operation = vector_ops::VectorOperations::UpdateVectors(vector_ops::UpdateVectorsOp { points: PyPointVectors::peel_vec(point_vectors), update_filter: condition.map(Filter::from), }); Self(CollectionUpdateOperations::VectorOperation(operation)) } #[staticmethod] pub fn delete_vectors(point_ids: Vec, vector_names: Vec) -> Self { let operation = vector_ops::VectorOperations::DeleteVectors( PointIdsList::from(PyPointId::peel_vec(point_ids)), vector_names, ); Self(CollectionUpdateOperations::VectorOperation(operation)) } #[staticmethod] pub fn delete_vectors_by_filter(filter: PyFilter, vector_names: Vec) -> Self { let operation = vector_ops::VectorOperations::DeleteVectorsByFilter(Filter::from(filter), vector_names); Self(CollectionUpdateOperations::VectorOperation(operation)) } #[staticmethod] #[pyo3(signature = (point_ids, payload, key=None))] pub fn set_payload( point_ids: Vec, payload: PyPayload, key: Option, ) -> Self { let operation = payload_ops::PayloadOps::SetPayload(payload_ops::SetPayloadOp { payload: Payload::from(payload), points: Some(PyPointId::peel_vec(point_ids)), filter: None, key: key.map(JsonPath::from), }); Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] #[pyo3(signature = (filter, payload, key=None))] pub fn set_payload_by_filter( filter: PyFilter, payload: PyPayload, key: Option, ) -> Self { let operation = payload_ops::PayloadOps::SetPayload(payload_ops::SetPayloadOp { payload: Payload::from(payload), points: None, filter: Some(Filter::from(filter)), key: key.map(JsonPath::from), }); Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] pub fn delete_payload(point_ids: Vec, keys: Vec) -> Self { let operation = payload_ops::PayloadOps::DeletePayload(payload_ops::DeletePayloadOp { keys: PyJsonPath::peel_vec(keys), points: Some(PyPointId::peel_vec(point_ids)), filter: None, }); Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] pub fn delete_payload_by_filter(filter: PyFilter, keys: Vec) -> Self { let operation = payload_ops::PayloadOps::DeletePayload(payload_ops::DeletePayloadOp { keys: PyJsonPath::peel_vec(keys), points: None, filter: Some(Filter::from(filter)), }); Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] pub fn clear_payload(point_ids: Vec) -> Self { let operation = payload_ops::PayloadOps::ClearPayload { points: PyPointId::peel_vec(point_ids), }; Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] pub fn clear_payload_by_filter(filter: PyFilter) -> Self { let operation = payload_ops::PayloadOps::ClearPayloadByFilter(Filter::from(filter)); Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] #[pyo3(signature = (point_ids, payload, key=None))] pub fn overwrite_payload( point_ids: Vec, payload: PyPayload, key: Option, ) -> Self { let operation = payload_ops::PayloadOps::OverwritePayload(payload_ops::SetPayloadOp { payload: Payload::from(payload), points: Some(PyPointId::peel_vec(point_ids)), filter: None, key: key.map(JsonPath::from), }); Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] #[pyo3(signature = (filter, payload, key=None))] pub fn overwrite_payload_by_filter( filter: PyFilter, payload: PyPayload, key: Option, ) -> Self { let operation = payload_ops::PayloadOps::OverwritePayload(payload_ops::SetPayloadOp { payload: Payload::from(payload), points: None, filter: Some(Filter::from(filter)), key: key.map(JsonPath::from), }); Self(CollectionUpdateOperations::PayloadOperation(operation)) } #[staticmethod] pub fn create_field_index(field_name: PyJsonPath, schema: PyPayloadFieldSchema) -> Self { let operation = FieldIndexOperations::CreateIndex(CreateIndex { field_name: JsonPath::from(field_name), field_schema: Some(PayloadFieldSchema::from(schema)), }); Self(CollectionUpdateOperations::FieldIndexOperation(operation)) } #[staticmethod] pub fn delete_field_index(field_name: PyJsonPath) -> Self { let operation = FieldIndexOperations::DeleteIndex(JsonPath::from(field_name)); Self(CollectionUpdateOperations::FieldIndexOperation(operation)) } } /// Defines the mode of the upsert operation #[pyclass(name = "UpdateMode", eq, eq_int, from_py_object)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum PyUpdateMode { /// Default mode - insert new points, update existing points #[default] Upsert = 0, /// Only insert new points, do not update existing points InsertOnly = 1, /// Only update existing points, do not insert new points UpdateOnly = 2, } impl From for UpdateMode { fn from(mode: PyUpdateMode) -> Self { match mode { PyUpdateMode::Upsert => UpdateMode::Upsert, PyUpdateMode::InsertOnly => UpdateMode::InsertOnly, PyUpdateMode::UpdateOnly => UpdateMode::UpdateOnly, } } }