use tracing::debug;
use crate::bridge::envelope::Response;
use crate::data::executor::core_loop::CoreLoop;
use crate::data::executor::handlers::point::apply_put::PointPutParams;
use crate::data::executor::task::ExecutionTask;
use crate::engine::document::store::surrogate_to_doc_id;
use nodedb_types::Surrogate;
pub(in crate::data::executor) struct PointInsertParams<'a> {
pub task: &'a ExecutionTask,
pub tid: u64,
pub collection: &'a str,
pub document_id: &'a str,
pub surrogate: Surrogate,
pub value: &'a [u8],
pub if_absent: bool,
}
impl CoreLoop {
pub(in crate::data::executor) fn execute_point_insert(
&mut self,
p: PointInsertParams<'_>,
) -> Response {
let PointInsertParams {
task,
tid,
collection,
document_id,
surrogate,
value,
if_absent,
} = p;
let row_key = surrogate_to_doc_id(surrogate);
let row_key = row_key.as_str();
debug!(
core = self.core_id,
%collection, %document_id, if_absent,
"point insert"
);
let txn = match self.sparse.begin_write() {
Ok(t) => t,
Err(e) => return self.response_error(task, e),
};
let database_id = task.request.database_id.as_u64();
let bitemporal = self.is_bitemporal(database_id, tid, collection);
let exists_result = if bitemporal {
self.sparse
.versioned_exists_current_in_txn(&txn, database_id, tid, collection, row_key)
} else {
self.sparse
.exists_in_txn(&txn, database_id, tid, collection, row_key)
};
match exists_result {
Ok(true) => {
if if_absent {
return self.response_ok(task);
}
return self.response_error(
task,
crate::Error::RejectedConstraint {
collection: collection.to_string(),
constraint: "unique".to_string(),
detail: format!(
"duplicate key value '{document_id}' violates primary-key \
uniqueness on '{collection}'"
),
},
);
}
Ok(false) => {}
Err(e) => return self.response_error(task, e),
}
let outcome = match self.apply_point_put(
&txn,
PointPutParams {
database_id: task.request.database_id.as_u64(),
tid,
collection,
document_id: row_key,
surrogate,
value,
index_text: true,
user_roles: &task.request.user_roles,
enforce: true,
wal_lsn: task.wal_lsn(),
},
) {
Ok(o) => o,
Err(e) => return self.response_error(task, e),
};
if let Err(e) = txn.commit() {
return self.response_error(
task,
crate::Error::Storage {
engine: "sparse".into(),
detail: format!("commit: {e}"),
},
);
}
self.checkpoint_coordinator.mark_dirty("sparse", 1);
self.note_surrogate_write_lsn(task, tid, collection, surrogate.as_u32());
if let Some(lsn) = task.wal_lsn() {
let mut tuples = outcome.secondary_index_added;
tuples.extend(outcome.secondary_index_removed);
tuples.extend(outcome.bitemporal_index_tuples);
self.note_index_write_values(
task.request.database_id,
crate::types::TenantId::new(tid),
collection,
&tuples,
lsn,
);
}
self.emit_put_event(task, tid, collection, row_key, value, None);
self.response_ok(task)
}
}