create and delete

main
Ziyang Hu 1 year ago
parent 662c59c967
commit 57a326918d

@ -135,10 +135,11 @@ limit_option = {":limit" ~ expr}
offset_option = {":offset" ~ expr}
sort_option = {(":sort" | ":order") ~ (sort_arg ~ ",")* ~ sort_arg }
relation_option = {relation_op ~ (compound_ident | underscore_ident) ~ table_schema?}
relation_op = _{relation_create | relation_replace | relation_insert | relation_put | relation_update | relation_rm | relation_ensure_not | relation_ensure }
relation_op = _{relation_create | relation_replace | relation_insert | relation_put | relation_update | relation_rm | relation_delete | relation_ensure_not | relation_ensure }
relation_create = {":create"}
relation_replace = {":replace"}
relation_insert = {":insert"}
relation_delete = {":delete"}
relation_put = {":put"}
relation_update = {":update"}
relation_rm = {":rm"}

@ -105,6 +105,9 @@ impl Display for QueryOutOptions {
RelationOp::Rm => {
write!(f, ":rm ")?;
}
RelationOp::Delete => {
write!(f, ":delete ")?;
}
RelationOp::Ensure => {
write!(f, ":ensure ")?;
}
@ -184,6 +187,7 @@ pub(crate) enum RelationOp {
Insert,
Update,
Rm,
Delete,
Ensure,
EnsureNot,
}

@ -320,6 +320,7 @@ pub(crate) fn parse_query(
Rule::relation_insert => RelationOp::Insert,
Rule::relation_update => RelationOp::Update,
Rule::relation_rm => RelationOp::Rm,
Rule::relation_delete => RelationOp::Delete,
Rule::relation_ensure => RelationOp::Ensure,
Rule::relation_ensure_not => RelationOp::EnsureNot,
_ => unreachable!(),

@ -44,7 +44,7 @@ impl<'a> SessionTx<'a> {
pub(crate) fn execute_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item=Tuple>,
res_iter: impl Iterator<Item = Tuple>,
op: RelationOp,
meta: &InputRelationHandle,
headers: &[Symbol],
@ -132,7 +132,7 @@ impl<'a> SessionTx<'a> {
} = meta;
match op {
RelationOp::Rm => self.remove_from_relation(
RelationOp::Rm | RelationOp::Delete => self.remove_from_relation(
db,
res_iter,
headers,
@ -144,6 +144,7 @@ impl<'a> SessionTx<'a> {
&mut relation_store,
metadata,
key_bindings,
op == RelationOp::Delete,
*span,
)?,
RelationOp::Ensure => self.ensure_in_relation(
@ -178,7 +179,8 @@ impl<'a> SessionTx<'a> {
key_bindings,
*span,
)?,
RelationOp::Create | RelationOp::Replace | RelationOp::Put | RelationOp::Insert => self.put_into_relation(
RelationOp::Create | RelationOp::Replace | RelationOp::Put | RelationOp::Insert => self
.put_into_relation(
db,
res_iter,
headers,
@ -202,7 +204,7 @@ impl<'a> SessionTx<'a> {
fn put_into_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item=Tuple>,
res_iter: impl Iterator<Item = Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
callback_targets: &BTreeSet<SmartString<LazyCompact>>,
@ -270,8 +272,16 @@ impl<'a> SessionTx<'a> {
.map(|ex| ex.extract_data(&tuple, cur_vld))
.try_collect()?;
let key = relation_store.encode_key_for_store(&extracted, span)?;
if is_insert {
if relation_store.exists(self, &extracted[..relation_store.metadata.keys.len()])? {
let already_exists = if relation_store.is_temp {
self.temp_store_tx.exists(&key, true)?
} else {
self.store_tx.exists(&key, true)?
};
if already_exists {
bail!(TransactAssertionFailure {
relation: relation_store.name.to_string(),
key: extracted,
@ -280,7 +290,6 @@ impl<'a> SessionTx<'a> {
}
}
let key = relation_store.encode_key_for_store(&extracted, span)?;
let val = relation_store.encode_val_for_store(&extracted, span)?;
if need_to_collect
@ -508,7 +517,7 @@ impl<'a> SessionTx<'a> {
fn update_in_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item=Tuple>,
res_iter: impl Iterator<Item = Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
callback_targets: &BTreeSet<SmartString<LazyCompact>>,
@ -782,7 +791,7 @@ impl<'a> SessionTx<'a> {
fn ensure_not_in_relation(
&mut self,
res_iter: impl Iterator<Item=Tuple>,
res_iter: impl Iterator<Item = Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
relation_store: &mut RelationHandle,
@ -829,7 +838,7 @@ impl<'a> SessionTx<'a> {
fn ensure_in_relation(
&mut self,
res_iter: impl Iterator<Item=Tuple>,
res_iter: impl Iterator<Item = Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
relation_store: &mut RelationHandle,
@ -899,7 +908,7 @@ impl<'a> SessionTx<'a> {
fn remove_from_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item=Tuple>,
res_iter: impl Iterator<Item = Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
callback_targets: &BTreeSet<SmartString<LazyCompact>>,
@ -909,6 +918,7 @@ impl<'a> SessionTx<'a> {
relation_store: &mut RelationHandle,
metadata: &StoredRelationMetadata,
key_bindings: &[Symbol],
check_exists: bool,
span: SourceSpan,
) -> Result<()> {
let is_callback_target = callback_targets.contains(&relation_store.name);
@ -944,6 +954,20 @@ impl<'a> SessionTx<'a> {
.map(|ex| ex.extract_data(&tuple, cur_vld))
.try_collect()?;
let key = relation_store.encode_key_for_store(&extracted, span)?;
if check_exists {
let exists = if relation_store.is_temp {
self.temp_store_tx.exists(&key, false)?
} else {
self.store_tx.exists(&key, false)?
};
if !exists {
bail!(TransactAssertionFailure {
relation: relation_store.name.to_string(),
key: extracted,
notice: "key does not exists in database".to_string()
});
}
}
if need_to_collect || has_indices || has_hnsw_indices || has_fts_indices {
if let Some(existing) = self.store_tx.get(&key, false)? {
let mut tup = extracted.clone();

@ -1377,8 +1377,10 @@ impl<'s, S: Storage<'s>> Db<S> {
StoreRelationNotFoundError(meta.name.to_string())
);
existing
.ensure_compatible(meta, *op == RelationOp::Rm || *op == RelationOp::Update)?;
existing.ensure_compatible(
meta,
*op == RelationOp::Rm || *op == RelationOp::Delete || *op == RelationOp::Update,
)?;
}
};

@ -1168,23 +1168,54 @@ fn multi_index_vec() {
#[test]
fn ensure_not() {
let db = DbInstance::new("mem", "", "").unwrap();
db.run_script(r"
db.run_script(
r"
%ignore_error { :create id_alloc{id: Int => next_id: Int, last_id: Int}}
%ignore_error {
?[id, next_id, last_id] <- [[0, 1, 1000]];
:ensure_not id_alloc{id => next_id, last_id}
}
", Default::default()).unwrap();
",
Default::default(),
)
.unwrap();
}
#[test]
fn insertion() {
let db = DbInstance::new("mem", "", "").unwrap();
db.run_script(r":create a {x => y}", Default::default()).unwrap();
assert!(db.run_script(r"?[x, y] <- [[1, 2]] :insert a {x => y}", Default::default())
db.run_script(r":create a {x => y}", Default::default())
.unwrap();
assert!(db
.run_script(
r"?[x, y] <- [[1, 2]] :insert a {x => y}",
Default::default()
)
.is_ok());
assert!(db.run_script(r"?[x, y] <- [[1, 3]] :insert a {x => y}", Default::default())
assert!(db
.run_script(
r"?[x, y] <- [[1, 3]] :insert a {x => y}",
Default::default()
)
.is_err());
}
#[test]
fn deletion() {
let db = DbInstance::new("mem", "", "").unwrap();
db.run_script(r":create a {x => y}", Default::default())
.unwrap();
assert!(db
.run_script(r"?[x] <- [[1]] :delete a {x}", Default::default())
.is_err());
assert!(db
.run_script(
r"?[x, y] <- [[1, 2]] :insert a {x => y}",
Default::default()
)
.is_ok());
db
.run_script(r"?[x] <- [[1]] :delete a {x}", Default::default()).unwrap();
}
#[test]

Loading…
Cancel
Save