Feat: Include record ID in live queries notifications. (#2950)
Co-authored-by: Tobie Morgan Hitchcock <tobie@surrealdb.com>
This commit is contained in:
parent
218fa83c10
commit
be24734048
5 changed files with 21 additions and 10 deletions
|
@ -33,6 +33,8 @@ pub struct Notification {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
/// The CREATE / UPDATE / DELETE action which caused this notification
|
/// The CREATE / UPDATE / DELETE action which caused this notification
|
||||||
pub action: Action,
|
pub action: Action,
|
||||||
|
/// The id of the document to which this notification has been made
|
||||||
|
pub record: Value,
|
||||||
/// The resulting notification content, usually the altered record content
|
/// The resulting notification content, usually the altered record content
|
||||||
pub result: Value,
|
pub result: Value,
|
||||||
}
|
}
|
||||||
|
@ -42,6 +44,7 @@ impl Display for Notification {
|
||||||
let obj: Object = map! {
|
let obj: Object = map! {
|
||||||
"id".to_string() => self.id.to_string().into(),
|
"id".to_string() => self.id.to_string().into(),
|
||||||
"action".to_string() => self.action.to_string().into(),
|
"action".to_string() => self.action.to_string().into(),
|
||||||
|
"record".to_string() => self.record.clone(),
|
||||||
"result".to_string() => self.result.clone(),
|
"result".to_string() => self.result.clone(),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
|
@ -51,10 +54,11 @@ impl Display for Notification {
|
||||||
|
|
||||||
impl Notification {
|
impl Notification {
|
||||||
/// Construct a new notification
|
/// Construct a new notification
|
||||||
pub const fn new(id: Uuid, action: Action, result: Value) -> Self {
|
pub const fn new(id: Uuid, action: Action, record: Value, result: Value) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
action,
|
action,
|
||||||
|
record,
|
||||||
result,
|
result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +67,6 @@ impl Notification {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl FuzzyEq for Notification {
|
impl FuzzyEq for Notification {
|
||||||
fn fuzzy_eq(&self, other: &Self) -> bool {
|
fn fuzzy_eq(&self, other: &Self) -> bool {
|
||||||
self.action == other.action && self.result == other.result
|
self.action == other.action && self.record == other.record && self.result == other.result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,9 @@ impl Document {
|
||||||
} else {
|
} else {
|
||||||
Value::from("UPDATE")
|
Value::from("UPDATE")
|
||||||
};
|
};
|
||||||
|
// Get the record if of this docunent
|
||||||
|
let rid = self.id.as_ref().unwrap();
|
||||||
|
// Get the current and initial docs
|
||||||
let current = self.current.doc.as_arc();
|
let current = self.current.doc.as_arc();
|
||||||
let initial = self.initial.doc.as_arc();
|
let initial = self.initial.doc.as_arc();
|
||||||
// Check if this is a delete statement
|
// Check if this is a delete statement
|
||||||
|
@ -119,6 +122,7 @@ impl Document {
|
||||||
chn.send(Notification {
|
chn.send(Notification {
|
||||||
id: lv.id,
|
id: lv.id,
|
||||||
action: Action::Delete,
|
action: Action::Delete,
|
||||||
|
record: Value::Thing(rid.as_ref().clone()),
|
||||||
result: {
|
result: {
|
||||||
// Ensure futures are run
|
// Ensure futures are run
|
||||||
let lqopt: &Options = &lqopt.new_with_futures(true);
|
let lqopt: &Options = &lqopt.new_with_futures(true);
|
||||||
|
@ -141,6 +145,7 @@ impl Document {
|
||||||
chn.send(Notification {
|
chn.send(Notification {
|
||||||
id: lv.id,
|
id: lv.id,
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
|
record: Value::Thing(rid.as_ref().clone()),
|
||||||
result: self.pluck(stk, &lqctx, &lqopt, &lq).await?,
|
result: self.pluck(stk, &lqctx, &lqopt, &lq).await?,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -153,6 +158,7 @@ impl Document {
|
||||||
chn.send(Notification {
|
chn.send(Notification {
|
||||||
id: lv.id,
|
id: lv.id,
|
||||||
action: Action::Update,
|
action: Action::Update,
|
||||||
|
record: Value::Thing(rid.as_ref().clone()),
|
||||||
result: self.pluck(stk, &lqctx, &lqopt, &lq).await?,
|
result: self.pluck(stk, &lqctx, &lqopt, &lq).await?,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -162,6 +162,7 @@ mod tests {
|
||||||
use crate::kvs::Datastore;
|
use crate::kvs::Datastore;
|
||||||
use crate::kvs::LockType::Optimistic;
|
use crate::kvs::LockType::Optimistic;
|
||||||
use crate::kvs::TransactionType::Write;
|
use crate::kvs::TransactionType::Write;
|
||||||
|
use crate::sql::Thing;
|
||||||
use crate::sql::Value;
|
use crate::sql::Value;
|
||||||
use crate::syn::Parse;
|
use crate::syn::Parse;
|
||||||
|
|
||||||
|
@ -202,15 +203,14 @@ mod tests {
|
||||||
tx.cancel().await.unwrap();
|
tx.cancel().await.unwrap();
|
||||||
|
|
||||||
// Initiate a Create record
|
// Initiate a Create record
|
||||||
let create_statement = format!("CREATE {}:test_true SET condition = true", tb);
|
let create_statement = format!("CREATE {tb}:test_true SET condition = true");
|
||||||
let create_response = &mut dbs.execute(&create_statement, &ses, None).await.unwrap();
|
let create_response = &mut dbs.execute(&create_statement, &ses, None).await.unwrap();
|
||||||
assert_eq!(create_response.len(), 1);
|
assert_eq!(create_response.len(), 1);
|
||||||
let expected_record = Value::parse(&format!(
|
let expected_record = Value::parse(&format!(
|
||||||
"[{{
|
"[{{
|
||||||
id: {}:test_true,
|
id: {tb}:test_true,
|
||||||
condition: true,
|
condition: true,
|
||||||
}}]",
|
}}]"
|
||||||
tb
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let tmp = create_response.remove(0).result.unwrap();
|
let tmp = create_response.remove(0).result.unwrap();
|
||||||
|
@ -231,12 +231,12 @@ mod tests {
|
||||||
Notification::new(
|
Notification::new(
|
||||||
live_id,
|
live_id,
|
||||||
Action::Create,
|
Action::Create,
|
||||||
|
Value::Thing(Thing::from((tb, "test_true"))),
|
||||||
Value::parse(&format!(
|
Value::parse(&format!(
|
||||||
"{{
|
"{{
|
||||||
id: {}:test_true,
|
id: {tb}:test_true,
|
||||||
condition: true,
|
condition: true,
|
||||||
}}",
|
}}"
|
||||||
tb
|
|
||||||
),),
|
),),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -416,6 +416,7 @@ async fn delete_filtered_live_notification() -> Result<(), Error> {
|
||||||
Notification::new(
|
Notification::new(
|
||||||
live_id,
|
live_id,
|
||||||
Action::Delete,
|
Action::Delete,
|
||||||
|
Value::Thing(Thing::from(("person", "test_true"))),
|
||||||
Value::parse(
|
Value::parse(
|
||||||
"{
|
"{
|
||||||
id: person:test_true,
|
id: person:test_true,
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn is_notification(msg: &serde_json::Value) -> bool {
|
||||||
.as_object()
|
.as_object()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.keys()
|
.keys()
|
||||||
.all(|k| ["id", "action", "result"].contains(&k.as_str()))
|
.all(|k| ["id", "action", "record", "result"].contains(&k.as_str()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the given message is a notification from LQ and comes from the given LQ ID.
|
/// Check if the given message is a notification from LQ and comes from the given LQ ID.
|
||||||
|
|
Loading…
Reference in a new issue