mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Working backend delete
This commit is contained in:
parent
a1ac6d1cae
commit
764695db4a
|
@ -17,9 +17,8 @@ mod sqlite_be;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct IdEntry {
|
struct IdEntry {
|
||||||
// FIXME: This should be u64, but sqlite uses i32 ...
|
// FIXME: This should be u64, but sqlite uses i64 ...
|
||||||
// Should we use a bigint pk and just be done?
|
id: i64,
|
||||||
id: i32,
|
|
||||||
data: String,
|
data: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +32,7 @@ pub enum BackendType {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum BackendError {
|
pub enum BackendError {
|
||||||
EmptyRequest,
|
EmptyRequest,
|
||||||
|
EntryMissingId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
|
@ -67,7 +67,7 @@ pub trait BackendReadTransaction {
|
||||||
// Do a final optimise of the filter
|
// Do a final optimise of the filter
|
||||||
let filt = filt.optimise();
|
let filt = filt.optimise();
|
||||||
|
|
||||||
let mut raw_entries: Vec<String> = Vec::new();
|
let mut raw_entries: Vec<IdEntry> = Vec::new();
|
||||||
{
|
{
|
||||||
// Actually do a search now!
|
// Actually do a search now!
|
||||||
// let conn = self.pool.get().unwrap();
|
// let conn = self.pool.get().unwrap();
|
||||||
|
@ -87,19 +87,18 @@ pub trait BackendReadTransaction {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
for row in id2entry_iter {
|
for row in id2entry_iter {
|
||||||
audit_log!(au, "raw entry: {:?}", row);
|
audit_log!(au, "raw entry: {:?}", row);
|
||||||
// FIXME: Handle this properly.
|
// FIXME: Handle possible errors correctly.
|
||||||
raw_entries.push(row.unwrap().data);
|
raw_entries.push(row.unwrap());
|
||||||
}
|
}
|
||||||
// Rollback, we should have done nothing.
|
|
||||||
// conn.execute("ROLLBACK TRANSACTION", NO_PARAMS).unwrap();
|
|
||||||
}
|
}
|
||||||
// Do other things
|
// Do other things
|
||||||
// Now, de-serialise the raw_entries back to entries
|
// Now, de-serialise the raw_entries back to entries, and populate their ID's
|
||||||
let entries: Vec<Entry> = raw_entries
|
let entries: Vec<Entry> = raw_entries
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|val| {
|
.filter_map(|id_ent| {
|
||||||
// TODO: Should we do better than unwrap?
|
// TODO: Should we do better than unwrap?
|
||||||
let e: Entry = serde_json::from_str(val.as_str()).unwrap();
|
let mut e: Entry = serde_json::from_str(id_ent.data.as_str()).unwrap();
|
||||||
|
e.id = Some(id_ent.id);
|
||||||
if filt.entry_match_no_index(&e) {
|
if filt.entry_match_no_index(&e) {
|
||||||
Some(e)
|
Some(e)
|
||||||
} else {
|
} else {
|
||||||
|
@ -206,6 +205,18 @@ impl BackendWriteTransaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_id2entry_max_id(&self) -> i64 {
|
||||||
|
let mut stmt = self.conn.prepare("SELECT MAX(id) as id_max FROM id2entry").unwrap();
|
||||||
|
assert!(stmt.exists(NO_PARAMS).unwrap());
|
||||||
|
|
||||||
|
let i: Option<i64> = stmt.query_row(NO_PARAMS, |row| row.get(0))
|
||||||
|
.expect("failed to execute");
|
||||||
|
match i {
|
||||||
|
Some(e) => e,
|
||||||
|
None => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create(&self, au: &mut AuditScope, entries: &Vec<Entry>) -> Result<(), BackendError> {
|
pub fn create(&self, au: &mut AuditScope, entries: &Vec<Entry>) -> Result<(), BackendError> {
|
||||||
audit_segment!(au, || {
|
audit_segment!(au, || {
|
||||||
// Start be audit timer
|
// Start be audit timer
|
||||||
|
@ -220,11 +231,18 @@ impl BackendWriteTransaction {
|
||||||
// we do this outside the txn to avoid blocking needlessly.
|
// we do this outside the txn to avoid blocking needlessly.
|
||||||
// However, it could be pointless due to the extra string allocs ...
|
// However, it could be pointless due to the extra string allocs ...
|
||||||
|
|
||||||
let ser_entries: Vec<String> = entries
|
// Get the max id from the db. We store this ourselves to avoid max().
|
||||||
|
let mut id_max = self.get_id2entry_max_id();
|
||||||
|
|
||||||
|
let ser_entries: Vec<IdEntry> = entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|val| {
|
.map(|val| {
|
||||||
// TODO: Should we do better than unwrap?
|
// TODO: Should we do better than unwrap?
|
||||||
serde_json::to_string(&val).unwrap()
|
id_max = id_max + 1;
|
||||||
|
IdEntry {
|
||||||
|
id: id_max,
|
||||||
|
data: serde_json::to_string(&val).unwrap(),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -237,10 +255,11 @@ impl BackendWriteTransaction {
|
||||||
|
|
||||||
// write them all
|
// write them all
|
||||||
for ser_entry in ser_entries {
|
for ser_entry in ser_entries {
|
||||||
|
// TODO: Prepared statement.
|
||||||
self.conn
|
self.conn
|
||||||
.execute(
|
.execute(
|
||||||
"INSERT INTO id2entry (data) VALUES (?1)",
|
"INSERT INTO id2entry (id, data) VALUES (?1, ?2)",
|
||||||
&[&ser_entry as &ToSql],
|
&[&ser_entry.id as &ToSql, &ser_entry.data as &ToSql],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -254,20 +273,56 @@ impl BackendWriteTransaction {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modify() {
|
pub fn modify() -> Result<(), BackendError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete() {
|
pub fn delete(&self, au: &mut AuditScope, entries: &Vec<Entry>) -> Result<(), BackendError> {
|
||||||
unimplemented!()
|
// Perform a search for the entries --> This is a problem for the caller
|
||||||
|
|
||||||
|
if entries.is_empty() {
|
||||||
|
// TODO: Better error
|
||||||
|
// End the timer
|
||||||
|
return Err(BackendError::EmptyRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backup() {
|
// Assert the Id's exist on the entry.
|
||||||
|
let id_list: Vec<i64> = entries.iter()
|
||||||
|
.filter_map(|entry| {
|
||||||
|
entry.id
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Simple: If the list of id's is not the same as the input list, we are missing id's
|
||||||
|
if entries.len() != id_list.len() {
|
||||||
|
return Err(BackendError::EntryMissingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Now, given the list of id's, delete them.
|
||||||
|
{
|
||||||
|
// SQL doesn't say if the thing "does or does not exist anymore". As a result,
|
||||||
|
// two deletes is a safe and valid operation. Given how we allocate ID's we are
|
||||||
|
// probably okay with this.
|
||||||
|
|
||||||
|
// TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT.
|
||||||
|
let mut stmt = self.conn.prepare("DELETE FROM id2entry WHERE id = :id").unwrap();
|
||||||
|
|
||||||
|
id_list.iter().for_each(|id| {
|
||||||
|
stmt.execute(&[id]).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backup() -> Result<(), BackendError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should this be offline only?
|
// Should this be offline only?
|
||||||
pub fn restore() {
|
pub fn restore() -> Result<(), BackendError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +341,7 @@ impl BackendWriteTransaction {
|
||||||
|
|
||||||
// ===== inner helpers =====
|
// ===== inner helpers =====
|
||||||
// Some of these are not self due to use in new()
|
// Some of these are not self due to use in new()
|
||||||
fn get_db_version_key(&self, key: &str) -> i32 {
|
fn get_db_version_key(&self, key: &str) -> i64 {
|
||||||
match self.conn.query_row_named(
|
match self.conn.query_row_named(
|
||||||
"SELECT version FROM db_version WHERE id = :id",
|
"SELECT version FROM db_version WHERE id = :id",
|
||||||
&[(":id", &key)],
|
&[(":id", &key)],
|
||||||
|
@ -458,6 +513,14 @@ mod tests {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! entry_exists {
|
||||||
|
($audit:expr, $be:expr, $ent:expr) => {{
|
||||||
|
let filt = $ent.filter_from_attrs(&vec![String::from("userid")]).unwrap();
|
||||||
|
let entries = $be.search($audit, &filt).unwrap();
|
||||||
|
entries.first().is_some()
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_simple_create() {
|
fn test_simple_create() {
|
||||||
run_test!(|audit: &mut AuditScope, be: &BackendWriteTransaction| {
|
run_test!(|audit: &mut AuditScope, be: &BackendWriteTransaction| {
|
||||||
|
@ -470,17 +533,12 @@ mod tests {
|
||||||
let mut e: Entry = Entry::new();
|
let mut e: Entry = Entry::new();
|
||||||
e.add_ava(String::from("userid"), String::from("william"));
|
e.add_ava(String::from("userid"), String::from("william"));
|
||||||
|
|
||||||
let single_result = be.create(audit, &vec![e]);
|
let single_result = be.create(audit, &vec![e.clone()]);
|
||||||
|
|
||||||
assert!(single_result.is_ok());
|
assert!(single_result.is_ok());
|
||||||
|
|
||||||
// Construct a filter
|
// Construct a filter
|
||||||
let filt = Filter::Pres(String::from("userid"));
|
assert!(entry_exists!(audit, be, e));
|
||||||
let entries = be.search(audit, &filt).unwrap();
|
|
||||||
|
|
||||||
// There should only be one entry so is this enough?
|
|
||||||
assert!(entries.first().is_some());
|
|
||||||
// Later we could check consistency of the entry saved ...
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,6 +560,57 @@ mod tests {
|
||||||
fn test_simple_delete() {
|
fn test_simple_delete() {
|
||||||
run_test!(|audit: &mut AuditScope, be: &BackendWriteTransaction| {
|
run_test!(|audit: &mut AuditScope, be: &BackendWriteTransaction| {
|
||||||
audit_log!(audit, "Simple Delete");
|
audit_log!(audit, "Simple Delete");
|
||||||
|
|
||||||
|
// First create some entries (3?)
|
||||||
|
let mut e1: Entry = Entry::new();
|
||||||
|
e1.add_ava(String::from("userid"), String::from("william"));
|
||||||
|
|
||||||
|
let mut e2: Entry = Entry::new();
|
||||||
|
e2.add_ava(String::from("userid"), String::from("alice"));
|
||||||
|
|
||||||
|
let mut e3: Entry = Entry::new();
|
||||||
|
e3.add_ava(String::from("userid"), String::from("lucy"));
|
||||||
|
|
||||||
|
assert!(be.create(audit, &vec![e1.clone(), e2.clone(), e3.clone()]).is_ok());
|
||||||
|
assert!(entry_exists!(audit, be, e1));
|
||||||
|
assert!(entry_exists!(audit, be, e2));
|
||||||
|
assert!(entry_exists!(audit, be, e3));
|
||||||
|
|
||||||
|
|
||||||
|
// You need to now retrieve the entries back out to get the entry id's
|
||||||
|
let mut results = be.search(audit, &Filter::Pres(String::from("userid"))).unwrap();
|
||||||
|
|
||||||
|
// Get these out to usable entries.
|
||||||
|
let r1 = results.remove(0);
|
||||||
|
let r2 = results.remove(0);
|
||||||
|
let r3 = results.remove(0);
|
||||||
|
|
||||||
|
// Delete one
|
||||||
|
assert!(be.delete(audit, &vec![r1.clone()]).is_ok());
|
||||||
|
assert!(! entry_exists!(audit, be, r1));
|
||||||
|
|
||||||
|
// delete none (no match filter)
|
||||||
|
assert!(be.delete(audit, &vec![]).is_err());
|
||||||
|
|
||||||
|
// Delete with no id
|
||||||
|
let mut e4: Entry = Entry::new();
|
||||||
|
e4.add_ava(String::from("userid"), String::from("amy"));
|
||||||
|
|
||||||
|
assert!(be.delete(audit, &vec![e4.clone()]).is_err());
|
||||||
|
|
||||||
|
assert!(entry_exists!(audit, be, r2));
|
||||||
|
assert!(entry_exists!(audit, be, r3));
|
||||||
|
|
||||||
|
// delete batch
|
||||||
|
assert!(be.delete(audit, &vec![r2.clone(), r3.clone()]).is_ok());
|
||||||
|
|
||||||
|
assert!(! entry_exists!(audit, be, r2));
|
||||||
|
assert!(! entry_exists!(audit, be, r3));
|
||||||
|
|
||||||
|
// delete none (no entries left)
|
||||||
|
// see fn delete for why this is ok, not err
|
||||||
|
assert!(be.delete(audit, &vec![r2.clone(), r3.clone()]).is_ok());
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ pub static JSON_ANONYMOUS_V1: &'static str = r#"{
|
||||||
"name": ["anonymous"],
|
"name": ["anonymous"],
|
||||||
"uuid": ["00000000-0000-0000-0000-ffffffffffff"],
|
"uuid": ["00000000-0000-0000-0000-ffffffffffff"],
|
||||||
"description": ["Anonymous access account."],
|
"description": ["Anonymous access account."],
|
||||||
"version": ["1"]
|
"version": ["1"],
|
||||||
|
"displayname": ["Anonymous"]
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
|
|
|
@ -93,14 +93,18 @@ impl<'a> Iterator for EntryAvasMut<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a BE concept, so move it there!
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
|
pub id: Option<i64>,
|
||||||
attrs: BTreeMap<String, Vec<String>>,
|
attrs: BTreeMap<String, Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Entry {
|
Entry {
|
||||||
|
// This means NEVER COMMITED
|
||||||
|
id: None,
|
||||||
attrs: BTreeMap::new(),
|
attrs: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,6 +226,7 @@ impl Entry {
|
||||||
Entry {
|
Entry {
|
||||||
// For now, we do a straight move, and we sort the incoming data
|
// For now, we do a straight move, and we sort the incoming data
|
||||||
// sets so that BST works.
|
// sets so that BST works.
|
||||||
|
id: None,
|
||||||
attrs: e
|
attrs: e
|
||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -250,6 +255,7 @@ impl Entry {
|
||||||
impl Clone for Entry {
|
impl Clone for Entry {
|
||||||
fn clone(&self) -> Entry {
|
fn clone(&self) -> Entry {
|
||||||
Entry {
|
Entry {
|
||||||
|
id: self.id,
|
||||||
attrs: self.attrs.clone(),
|
attrs: self.attrs.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ pub enum SchemaError {
|
||||||
InvalidClass,
|
InvalidClass,
|
||||||
// FIXME: Is there a way to say what we are missing on error?
|
// FIXME: Is there a way to say what we are missing on error?
|
||||||
// Yes, add a string on the enum.
|
// Yes, add a string on the enum.
|
||||||
MissingMustAttribute,
|
MissingMustAttribute(String),
|
||||||
InvalidAttribute,
|
InvalidAttribute,
|
||||||
InvalidAttributeSyntax,
|
InvalidAttributeSyntax,
|
||||||
EmptyFilter,
|
EmptyFilter,
|
||||||
|
@ -17,4 +17,6 @@ pub enum OperationError {
|
||||||
SchemaViolation,
|
SchemaViolation,
|
||||||
Plugin,
|
Plugin,
|
||||||
FilterGeneration,
|
FilterGeneration,
|
||||||
|
InvalidDBState,
|
||||||
|
InvalidRequestState,
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,3 +136,23 @@ impl ExistsEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DeleteEvent {
|
||||||
|
pub filter: Filter,
|
||||||
|
pub internal: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message for DeleteEvent {
|
||||||
|
type Result = Result<OpResult, OperationError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeleteEvent {
|
||||||
|
pub fn new_internal(filter: Filter) -> Self {
|
||||||
|
DeleteEvent {
|
||||||
|
filter: filter,
|
||||||
|
internal: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -910,7 +910,9 @@ impl SchemaInner {
|
||||||
for (attr_name, _attr) in must {
|
for (attr_name, _attr) in must {
|
||||||
let avas = entry.get_ava(&attr_name);
|
let avas = entry.get_ava(&attr_name);
|
||||||
if avas.is_none() {
|
if avas.is_none() {
|
||||||
return Err(SchemaError::MissingMustAttribute);
|
return Err(SchemaError::MissingMustAttribute(
|
||||||
|
String::from(attr_name)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1373,7 +1375,7 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
schema.validate_entry(&e_attr_invalid),
|
schema.validate_entry(&e_attr_invalid),
|
||||||
Err(SchemaError::MissingMustAttribute)
|
Err(SchemaError::MissingMustAttribute(String::from("system")))
|
||||||
);
|
);
|
||||||
|
|
||||||
let e_attr_invalid_may: Entry = serde_json::from_str(
|
let e_attr_invalid_may: Entry = serde_json::from_str(
|
||||||
|
|
|
@ -12,7 +12,7 @@ use be::{
|
||||||
use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1};
|
use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1};
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use error::OperationError;
|
use error::OperationError;
|
||||||
use event::{CreateEvent, ExistsEvent, OpResult, SearchEvent, SearchResult};
|
use event::{CreateEvent, ExistsEvent, OpResult, SearchEvent, SearchResult, DeleteEvent};
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use log::EventLog;
|
use log::EventLog;
|
||||||
use plugins::Plugins;
|
use plugins::Plugins;
|
||||||
|
@ -139,7 +139,7 @@ pub trait QueryServerReadTransaction {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_search(&self, _au: &mut AuditScope, _filter: Filter) -> Result<(), ()> {
|
fn internal_search(&self, _au: &mut AuditScope, _filter: Filter) -> Result<Vec<Entry>, OperationError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,10 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
if acc.is_ok() {
|
if acc.is_ok() {
|
||||||
self.schema
|
self.schema
|
||||||
.validate_entry(e)
|
.validate_entry(e)
|
||||||
.map_err(|_| OperationError::SchemaViolation)
|
.map_err(|err| {
|
||||||
|
audit_log!(au, "Schema Violation: {:?}", err);
|
||||||
|
OperationError::SchemaViolation
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
@ -284,6 +287,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|e| match e {
|
.map_err(|e| match e {
|
||||||
BackendError::EmptyRequest => OperationError::EmptyRequest,
|
BackendError::EmptyRequest => OperationError::EmptyRequest,
|
||||||
|
BackendError::EntryMissingId => OperationError::InvalidRequestState,
|
||||||
});
|
});
|
||||||
au.append_scope(audit_be);
|
au.append_scope(audit_be);
|
||||||
|
|
||||||
|
@ -304,6 +308,41 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn delete(&self, au: &mut AuditScope, ce: &DeleteEvent) -> Result<(), OperationError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are where searches and other actions are actually implemented. This
|
||||||
|
// is the "internal" version, where we define the event as being internal
|
||||||
|
// only, allowing certain plugin by passes etc.
|
||||||
|
|
||||||
|
pub fn internal_create(
|
||||||
|
&self,
|
||||||
|
audit: &mut AuditScope,
|
||||||
|
entries: Vec<Entry>,
|
||||||
|
) -> Result<(), OperationError> {
|
||||||
|
// Start the audit scope
|
||||||
|
let mut audit_int = AuditScope::new("internal_create");
|
||||||
|
// Create the CreateEvent
|
||||||
|
let ce = CreateEvent::new_internal(entries);
|
||||||
|
let res = self.create(&mut audit_int, &ce);
|
||||||
|
audit.append_scope(audit_int);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn internal_delete(
|
||||||
|
&self,
|
||||||
|
audit: &mut AuditScope,
|
||||||
|
filter: Filter
|
||||||
|
) -> Result<(), OperationError> {
|
||||||
|
let mut audit_int = AuditScope::new("internal_delete");
|
||||||
|
let de = DeleteEvent::new_internal(filter);
|
||||||
|
let res = self.delete(&mut audit_int, &de);
|
||||||
|
audit.append_scope(audit_int);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
// internal server operation types.
|
// internal server operation types.
|
||||||
// These just wrap the fn create/search etc, but they allow
|
// These just wrap the fn create/search etc, but they allow
|
||||||
// creating the needed create event with the correct internal flags
|
// creating the needed create event with the correct internal flags
|
||||||
|
@ -370,14 +409,21 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Does it exist? (TODO: Should be search, not exists ...)
|
// Does it exist? (TODO: Should be search, not exists ...)
|
||||||
match self.internal_exists(audit, filt) {
|
match self.internal_search(audit, filt.clone()) {
|
||||||
Ok(true) => {
|
Ok(results) => {
|
||||||
// it exists. We need to ensure the content now.
|
if results.len() == 0 {
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
Ok(false) => {
|
|
||||||
// It does not exist. Create it.
|
// It does not exist. Create it.
|
||||||
self.internal_create(audit, vec![e])
|
self.internal_create(audit, vec![e])
|
||||||
|
} else if results.len() == 1 {
|
||||||
|
// it exists. To guarantee content exactly as is, we compare if it's identical.
|
||||||
|
if e != results[0] {
|
||||||
|
self.internal_delete(audit, filt);
|
||||||
|
self.internal_create(audit, vec![e]);
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(OperationError::InvalidDBState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// An error occured. pass it back up.
|
// An error occured. pass it back up.
|
||||||
|
@ -386,24 +432,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are where searches and other actions are actually implemented. This
|
|
||||||
// is the "internal" version, where we define the event as being internal
|
|
||||||
// only, allowing certain plugin by passes etc.
|
|
||||||
|
|
||||||
pub fn internal_create(
|
|
||||||
&self,
|
|
||||||
audit: &mut AuditScope,
|
|
||||||
entries: Vec<Entry>,
|
|
||||||
) -> Result<(), OperationError> {
|
|
||||||
// Start the audit scope
|
|
||||||
let mut audit_int = AuditScope::new("internal_create");
|
|
||||||
// Create the CreateEvent
|
|
||||||
let ce = CreateEvent::new_internal(entries);
|
|
||||||
let res = self.create(&mut audit_int, &ce);
|
|
||||||
audit.append_scope(audit_int);
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is idempotent
|
// This function is idempotent
|
||||||
pub fn initialise(&self, audit: &mut AuditScope) -> Result<(), OperationError> {
|
pub fn initialise(&self, audit: &mut AuditScope) -> Result<(), OperationError> {
|
||||||
// First, check the system_info object. This stores some server information
|
// First, check the system_info object. This stores some server information
|
||||||
|
@ -414,6 +442,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
self.internal_assert_or_create(audit, e)
|
self.internal_assert_or_create(audit, e)
|
||||||
});
|
});
|
||||||
audit.append_scope(audit_si);
|
audit.append_scope(audit_si);
|
||||||
|
assert!(res.is_ok());
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -425,6 +454,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
self.internal_migrate_or_create(audit, e)
|
self.internal_migrate_or_create(audit, e)
|
||||||
});
|
});
|
||||||
audit.append_scope(audit_an);
|
audit.append_scope(audit_an);
|
||||||
|
assert!(res.is_ok());
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue