Fix Order and Filters
This commit is contained in:
parent
ab9fe76494
commit
d15bf891db
|
@ -220,27 +220,11 @@ impl NostrSqlite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_event(&self, event: &Event) -> Result<bool, Error> {
|
async fn check_event_replaceble(&self, event: &Event) -> Result<bool, Error> {
|
||||||
let event = event.clone();
|
if event.is_replaceable() {
|
||||||
|
|
||||||
let id = event.id.to_string();
|
|
||||||
let kind = event.kind.as_u64();
|
|
||||||
let pubkey = event.pubkey.to_string();
|
let pubkey = event.pubkey.to_string();
|
||||||
let content = event.content.to_string();
|
let kind = event.kind.as_u64();
|
||||||
let created_at = event.created_at.as_i64();
|
let created_at = event.created_at.as_i64();
|
||||||
let tags = serde_json::to_string(&event.tags).unwrap();
|
|
||||||
let sig = event.sig.to_string();
|
|
||||||
|
|
||||||
let ids: Vec<String> = event.event_ids().map(|eid| eid.to_string()).collect();
|
|
||||||
|
|
||||||
if self.event_is_too_old(&event) {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if event.is_ephemeral() {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
let Ok(connection) = self.get_connection().await else {
|
let Ok(connection) = self.get_connection().await else {
|
||||||
return Err(Error::internal_with_message("Unable to get DB connection"));
|
return Err(Error::internal_with_message("Unable to get DB connection"));
|
||||||
};
|
};
|
||||||
|
@ -248,9 +232,7 @@ impl NostrSqlite {
|
||||||
let Ok(event_saved) = connection
|
let Ok(event_saved) = connection
|
||||||
.interact(move |conn| -> Result<bool, Error> {
|
.interact(move |conn| -> Result<bool, Error> {
|
||||||
let tx = conn.transaction().unwrap();
|
let tx = conn.transaction().unwrap();
|
||||||
|
log::debug!("new event is replaceable - searching for previously stored event");
|
||||||
if event.is_replaceable() {
|
|
||||||
dbg!("new event is replaceable - searching for previously stored event");
|
|
||||||
let (sql, values) = Query::select()
|
let (sql, values) = Query::select()
|
||||||
.from(EventsTable::Table)
|
.from(EventsTable::Table)
|
||||||
.columns([EventsTable::EventId])
|
.columns([EventsTable::EventId])
|
||||||
|
@ -262,22 +244,89 @@ impl NostrSqlite {
|
||||||
|
|
||||||
if let Ok(res) = tx.execute(sql.as_str(), &*values.as_params()) {
|
if let Ok(res) = tx.execute(sql.as_str(), &*values.as_params()) {
|
||||||
if res > 0 {
|
if res > 0 {
|
||||||
return Ok(true);
|
log::debug!("deleting older replaceable event from events table");
|
||||||
|
let (sql, values) = Query::delete()
|
||||||
|
.from_table(EventsTable::Table)
|
||||||
|
.and_where(
|
||||||
|
sea_query::Expr::col((EventsTable::Table, EventsTable::Kind))
|
||||||
|
.eq(kind),
|
||||||
|
)
|
||||||
|
.and_where(
|
||||||
|
sea_query::Expr::col((EventsTable::Table, EventsTable::Pubkey))
|
||||||
|
.eq(&pubkey),
|
||||||
|
)
|
||||||
|
.and_where(
|
||||||
|
sea_query::Expr::col((
|
||||||
|
EventsTable::Table,
|
||||||
|
EventsTable::EventId,
|
||||||
|
))
|
||||||
|
.not_in_subquery(
|
||||||
|
Query::select()
|
||||||
|
.from(EventsTable::Table)
|
||||||
|
.column(EventsTable::EventId)
|
||||||
|
.and_where(
|
||||||
|
sea_query::Expr::col(EventsTable::Kind).eq(kind),
|
||||||
|
)
|
||||||
|
.and_where(
|
||||||
|
sea_query::Expr::col(EventsTable::Pubkey)
|
||||||
|
.eq(&pubkey),
|
||||||
|
)
|
||||||
|
.order_by(
|
||||||
|
EventsTable::CreatedAt,
|
||||||
|
sea_query::Order::Desc,
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
.to_owned(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.build_rusqlite(SqliteQueryBuilder);
|
||||||
|
|
||||||
|
if let Ok(results) = tx.execute(sql.as_str(), &*values.as_params()) {
|
||||||
|
if results > 0 {
|
||||||
|
log::info!(
|
||||||
|
"removed {} older replaceable kind {} events for author: {:?}",
|
||||||
|
results,
|
||||||
|
kind,
|
||||||
|
pubkey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tx.commit().unwrap();
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
else {
|
||||||
|
return Err(Error::internal_with_message("Failed to execute query"));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_event_parametrized_replaceble(&self, event: &Event) -> Result<bool, Error> {
|
||||||
if event.is_parameterized_replaceable() {
|
if event.is_parameterized_replaceable() {
|
||||||
dbg!(
|
let identifier = match event.identifier() {
|
||||||
|
Some(id) => id.to_string(),
|
||||||
|
None => return Ok(true),
|
||||||
|
};
|
||||||
|
let pubkey = event.pubkey.to_string();
|
||||||
|
let kind = event.kind.as_u64();
|
||||||
|
let created_at = event.created_at.as_i64();
|
||||||
|
|
||||||
|
let Ok(connection) = self.get_connection().await else {
|
||||||
|
return Err(Error::internal_with_message("Unable to get DB connection"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(event_saved) = connection
|
||||||
|
.interact(move |conn| -> Result<bool, Error> {
|
||||||
|
let tx = conn.transaction().unwrap();
|
||||||
|
log::debug!(
|
||||||
"new event is parametrized replaceable - searching for previously stored event"
|
"new event is parametrized replaceable - searching for previously stored event"
|
||||||
);
|
);
|
||||||
let d_tags: Vec<String> = event
|
|
||||||
.tags
|
|
||||||
.iter()
|
|
||||||
.filter(|tag| tag.kind() == nostr::TagKind::D)
|
|
||||||
.map(|tag| tag.clone().to_vec()[1].clone())
|
|
||||||
.collect();
|
|
||||||
let (sql, values) = Query::select()
|
let (sql, values) = Query::select()
|
||||||
.from(EventsTable::Table)
|
.from(EventsTable::Table)
|
||||||
.column((EventsTable::Table, EventsTable::EventId))
|
.column((EventsTable::Table, EventsTable::EventId))
|
||||||
|
@ -296,7 +345,7 @@ impl NostrSqlite {
|
||||||
.and_where(sea_query::Expr::col((TagsTable::Table, TagsTable::Tag)).eq("d"))
|
.and_where(sea_query::Expr::col((TagsTable::Table, TagsTable::Tag)).eq("d"))
|
||||||
.and_where(
|
.and_where(
|
||||||
sea_query::Expr::col((TagsTable::Table, TagsTable::Value))
|
sea_query::Expr::col((TagsTable::Table, TagsTable::Value))
|
||||||
.eq(d_tags[0].to_string()),
|
.eq(&identifier),
|
||||||
)
|
)
|
||||||
.and_where(
|
.and_where(
|
||||||
sea_query::Expr::col((EventsTable::Table, EventsTable::CreatedAt))
|
sea_query::Expr::col((EventsTable::Table, EventsTable::CreatedAt))
|
||||||
|
@ -305,63 +354,18 @@ impl NostrSqlite {
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.build_rusqlite(SqliteQueryBuilder);
|
.build_rusqlite(SqliteQueryBuilder);
|
||||||
|
|
||||||
if let Ok(results) = tx.execute(sql.as_str(), &*values.as_params()) {
|
|
||||||
if results > 0 {
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert replaceble event
|
|
||||||
if event.is_replaceable() {
|
|
||||||
dbg!("deleting older replaceable event from events table");
|
|
||||||
let (sql, values) = Query::delete()
|
|
||||||
.from_table(EventsTable::Table)
|
|
||||||
.and_where(
|
|
||||||
sea_query::Expr::col((EventsTable::Table, EventsTable::Kind)).eq(kind),
|
|
||||||
)
|
|
||||||
.and_where(
|
|
||||||
sea_query::Expr::col((EventsTable::Table, EventsTable::Pubkey))
|
|
||||||
.eq(&pubkey),
|
|
||||||
)
|
|
||||||
.and_where(
|
|
||||||
sea_query::Expr::col((EventsTable::Table, EventsTable::EventId))
|
|
||||||
.not_in_subquery(
|
|
||||||
Query::select()
|
|
||||||
.from(EventsTable::Table)
|
|
||||||
.column(EventsTable::EventId)
|
|
||||||
.and_where(sea_query::Expr::col(EventsTable::Kind).eq(kind))
|
|
||||||
.and_where(
|
|
||||||
sea_query::Expr::col(EventsTable::Pubkey).eq(&pubkey),
|
|
||||||
)
|
|
||||||
.order_by(EventsTable::CreatedAt, sea_query::Order::Desc)
|
|
||||||
.limit(1)
|
|
||||||
.to_owned(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.build_rusqlite(SqliteQueryBuilder);
|
|
||||||
|
|
||||||
if let Ok(results) = tx.execute(sql.as_str(), &*values.as_params()) {
|
if let Ok(results) = tx.execute(sql.as_str(), &*values.as_params()) {
|
||||||
if results > 0 {
|
if results > 0 {
|
||||||
log::info!(
|
log::info!(
|
||||||
"removed {} older replaceable kind {} events for author: {:?}",
|
"deleting older parametrized replaceable event from events table"
|
||||||
results,
|
|
||||||
event.kind.as_u32(),
|
|
||||||
event.pubkey.to_string()
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert parametrized replaceble event
|
|
||||||
if event.is_parameterized_replaceable() {
|
|
||||||
dbg!("deleting older parametrized replaceable event from events table");
|
|
||||||
log::info!("deleting older parametrized replaceable event from events table");
|
|
||||||
let d_tag = event.identifier();
|
|
||||||
let (sql, values) = Query::delete()
|
let (sql, values) = Query::delete()
|
||||||
.from_table(EventsTable::Table)
|
.from_table(EventsTable::Table)
|
||||||
.and_where(
|
.and_where(
|
||||||
sea_query::Expr::col((EventsTable::Table, EventsTable::EventId))
|
sea_query::Expr::col((
|
||||||
|
EventsTable::Table,
|
||||||
|
EventsTable::EventId,
|
||||||
|
))
|
||||||
.in_subquery(
|
.in_subquery(
|
||||||
Query::select()
|
Query::select()
|
||||||
.from(EventsTable::Table)
|
.from(EventsTable::Table)
|
||||||
|
@ -400,7 +404,7 @@ impl NostrSqlite {
|
||||||
TagsTable::Table,
|
TagsTable::Table,
|
||||||
TagsTable::Value,
|
TagsTable::Value,
|
||||||
))
|
))
|
||||||
.eq(d_tag),
|
.eq(&identifier),
|
||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
),
|
),
|
||||||
|
@ -409,10 +413,60 @@ impl NostrSqlite {
|
||||||
|
|
||||||
if let Ok(results) = tx.execute(sql.as_str(), &*values.as_params()) {
|
if let Ok(results) = tx.execute(sql.as_str(), &*values.as_params()) {
|
||||||
if results > 0 {
|
if results > 0 {
|
||||||
log::info!("removed {} older parameterized replaceable kind {} events for author: {:?}", results, event.kind, event.pubkey);
|
log::info!("removed {} older parameterized replaceable kind {} events for author: {:?}", results, kind, &pubkey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tx.commit().unwrap();
|
||||||
|
Ok(false)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
else {
|
||||||
|
return Err(Error::internal_with_message("Failed to execute query"));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn save_event(&self, event: &Event) -> Result<bool, Error> {
|
||||||
|
let event = event.clone();
|
||||||
|
|
||||||
|
let id = event.id.to_string();
|
||||||
|
let kind = event.kind.as_u64();
|
||||||
|
let pubkey = event.pubkey.to_string();
|
||||||
|
let content = event.content.to_string();
|
||||||
|
let created_at = event.created_at.as_i64();
|
||||||
|
let tags = serde_json::to_string(&event.tags).unwrap();
|
||||||
|
let sig = event.sig.to_string();
|
||||||
|
|
||||||
|
let ids: Vec<String> = event.event_ids().map(|eid| eid.to_string()).collect();
|
||||||
|
|
||||||
|
if self.event_is_too_old(&event) {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.is_ephemeral() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(connection) = self.get_connection().await else {
|
||||||
|
return Err(Error::internal_with_message("Unable to get DB connection"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(res) = self.check_event_replaceble(&event).await else {
|
||||||
|
return Err(Error::internal_with_message("Unable to get DB connection"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(res) = self.check_event_parametrized_replaceble(&event).await else {
|
||||||
|
return Err(Error::internal_with_message("Unable to get DB connection"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(event_saved) = connection
|
||||||
|
.interact(move |conn| -> Result<bool, Error> {
|
||||||
|
let tx = conn.transaction().unwrap();
|
||||||
|
|
||||||
if event.kind == nostr::Kind::EventDeletion {
|
if event.kind == nostr::Kind::EventDeletion {
|
||||||
// Delete from Events
|
// Delete from Events
|
||||||
|
@ -524,7 +578,8 @@ impl NostrSqlite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await else {
|
.await
|
||||||
|
else {
|
||||||
return Err(Error::internal_with_message("Failed to execute query"));
|
return Err(Error::internal_with_message("Failed to execute query"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -917,11 +972,7 @@ impl NostrSqlite {
|
||||||
query
|
query
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_filters_query(
|
fn get_filters_query(&self, filters: Vec<Filter>) -> Option<sea_query::SelectStatement> {
|
||||||
&self,
|
|
||||||
filters: Vec<Filter>,
|
|
||||||
order: SqOrder,
|
|
||||||
) -> Option<sea_query::SelectStatement> {
|
|
||||||
filters
|
filters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|filter| {
|
.map(|filter| {
|
||||||
|
@ -957,13 +1008,15 @@ impl NostrSqlite {
|
||||||
Order::Asc => SqOrder::Asc,
|
Order::Asc => SqOrder::Asc,
|
||||||
Order::Desc => SqOrder::Desc,
|
Order::Desc => SqOrder::Desc,
|
||||||
};
|
};
|
||||||
let Some(sql_statement) = self.get_filters_query(filters, sq_order) else {
|
let Some(mut sql_statement) = self.get_filters_query(filters) else {
|
||||||
return Err(Error::internal_with_message("Failed to build SQL Query"));
|
return Err(Error::internal_with_message("Failed to build SQL Query"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(query_result) = connection
|
let Ok(query_result) = connection
|
||||||
.interact(move |conn| -> Result<Vec<Event>, Error> {
|
.interact(move |conn| -> Result<Vec<Event>, Error> {
|
||||||
let (sql, values) = sql_statement.build_rusqlite(SqliteQueryBuilder);
|
let (sql, values) = sql_statement
|
||||||
|
.order_by(EventsTable::CreatedAt, sq_order.to_owned())
|
||||||
|
.build_rusqlite(SqliteQueryBuilder);
|
||||||
|
|
||||||
let mut stmt = conn.prepare(sql.as_str()).unwrap();
|
let mut stmt = conn.prepare(sql.as_str()).unwrap();
|
||||||
let mut rows = stmt.query(&*values.as_params()).unwrap();
|
let mut rows = stmt.query(&*values.as_params()).unwrap();
|
||||||
|
@ -989,7 +1042,7 @@ impl NostrSqlite {
|
||||||
return Err(Error::internal_with_message("Unable to get DB connection"));
|
return Err(Error::internal_with_message("Unable to get DB connection"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(mut sql_statement) = self.get_filters_query(filters, SqOrder::Desc) else {
|
let Some(mut sql_statement) = self.get_filters_query(filters) else {
|
||||||
return Err(Error::internal_with_message("Failed to build SQL Query"));
|
return Err(Error::internal_with_message("Failed to build SQL Query"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1039,7 +1092,7 @@ impl NostrSqlite {
|
||||||
Order::Desc => SqOrder::Desc,
|
Order::Desc => SqOrder::Desc,
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(mut sql_statement) = self.get_filters_query(filters, sq_order) else {
|
let Some(mut sql_statement) = self.get_filters_query(filters) else {
|
||||||
return Err(Error::internal_with_message("Failed to build SQL Query"));
|
return Err(Error::internal_with_message("Failed to build SQL Query"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1048,6 +1101,7 @@ impl NostrSqlite {
|
||||||
let (sql, values) = sql_statement
|
let (sql, values) = sql_statement
|
||||||
.clear_selects()
|
.clear_selects()
|
||||||
.column(EventsTable::EventId)
|
.column(EventsTable::EventId)
|
||||||
|
.order_by(EventsTable::CreatedAt, sq_order.to_owned())
|
||||||
.build_rusqlite(SqliteQueryBuilder);
|
.build_rusqlite(SqliteQueryBuilder);
|
||||||
|
|
||||||
let mut stmt = conn.prepare(sql.as_str()).unwrap();
|
let mut stmt = conn.prepare(sql.as_str()).unwrap();
|
||||||
|
@ -1257,7 +1311,6 @@ impl Noose for NostrSqlite {
|
||||||
) -> Result<Vec<nostr::RelayMessage>, Error> {
|
) -> Result<Vec<nostr::RelayMessage>, Error> {
|
||||||
match self.query(subscription.filters, Order::Desc).await {
|
match self.query(subscription.filters, Order::Desc).await {
|
||||||
Ok(events) => {
|
Ok(events) => {
|
||||||
|
|
||||||
let relay_messages: Vec<RelayMessage> = events
|
let relay_messages: Vec<RelayMessage> = events
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|event| nostr::RelayMessage::event(subscription.id.clone(), event))
|
.map(|event| nostr::RelayMessage::event(subscription.id.clone(), event))
|
||||||
|
@ -1362,8 +1415,6 @@ mod tests {
|
||||||
// Get status of seen event
|
// Get status of seen event
|
||||||
let result = db.get_event_seen_on_relays(event.id).await.unwrap();
|
let result = db.get_event_seen_on_relays(event.id).await.unwrap();
|
||||||
|
|
||||||
dbg!(result);
|
|
||||||
|
|
||||||
// Get event by id
|
// Get event by id
|
||||||
let eid = event.id;
|
let eid = event.id;
|
||||||
let result = db.get_event_by_id(eid).await.unwrap();
|
let result = db.get_event_by_id(eid).await.unwrap();
|
||||||
|
@ -1478,4 +1529,39 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(result.len(), 2);
|
assert_eq!(result.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn save_parametrized_replaceable_event() {
|
||||||
|
let config = Arc::new(ServiceConfig::new());
|
||||||
|
let db = NostrSqlite::new(config).await;
|
||||||
|
|
||||||
|
let keys = nostr::Keys::generate();
|
||||||
|
let d_tag = nostr::Tag::Identifier("test".to_string());
|
||||||
|
let event = nostr::EventBuilder::new(nostr::Kind::CategorizedPeopleList, "", vec![d_tag])
|
||||||
|
.to_event(&keys)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let result = db.save_event(&event).await.unwrap();
|
||||||
|
|
||||||
|
let filter_0 = nostr::Filter::new()
|
||||||
|
.kinds(vec![nostr::Kind::ContactList])
|
||||||
|
.authors(vec![event.pubkey]);
|
||||||
|
let filter_1 = nostr::Filter::new()
|
||||||
|
.kinds(vec![nostr::Kind::MuteList])
|
||||||
|
.authors(vec![event.pubkey]);
|
||||||
|
let filter_2 = nostr::Filter::new()
|
||||||
|
.kinds(vec![nostr::Kind::CategorizedPeopleList])
|
||||||
|
.authors(vec![event.pubkey])
|
||||||
|
.identifiers(vec!["test".to_string()]);
|
||||||
|
let filter_3 = nostr::Filter::new()
|
||||||
|
.kinds(vec![nostr::Kind::ApplicationSpecificData])
|
||||||
|
.authors(vec![event.pubkey])
|
||||||
|
.identifiers(vec!["app-config".to_string()]);
|
||||||
|
let result = db
|
||||||
|
.query(vec![filter_0, filter_1, filter_2, filter_3], Order::Desc)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.len(), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue