commit 095f5b71970a72690edcfa12c815812e9e9ef8d8
parent a8f8fabdc2f1eebe939622000c030639b4b6d51f
Author: William Casarin <jb55@jb55.com>
Date: Wed, 7 Feb 2024 16:32:06 -0800
add ndb_query support
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
6 files changed, 101 insertions(+), 8 deletions(-)
diff --git a/src/bindings.rs b/src/bindings.rs
@@ -1,4 +1,4 @@
-/* automatically generated by rust-bindgen 0.69.1 */
+/* automatically generated by rust-bindgen 0.69.2 */
#[repr(C)]
#[derive(Default)]
@@ -4685,6 +4685,7 @@ fn bindgen_test_layout_ndb_block_iterator() {
#[derive(Debug, Copy, Clone)]
pub struct ndb_query_result {
pub note: *mut ndb_note,
+ pub note_size: u64,
pub note_id: u64,
}
#[test]
@@ -4693,7 +4694,7 @@ fn bindgen_test_layout_ndb_query_result() {
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<ndb_query_result>(),
- 16usize,
+ 24usize,
concat!("Size of: ", stringify!(ndb_query_result))
);
assert_eq!(
@@ -4712,12 +4713,22 @@ fn bindgen_test_layout_ndb_query_result() {
)
);
assert_eq!(
- unsafe { ::std::ptr::addr_of!((*ptr).note_id) as usize - ptr as usize },
+ unsafe { ::std::ptr::addr_of!((*ptr).note_size) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(ndb_query_result),
"::",
+ stringify!(note_size)
+ )
+ );
+ assert_eq!(
+ unsafe { ::std::ptr::addr_of!((*ptr).note_id) as usize - ptr as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(ndb_query_result),
+ "::",
stringify!(note_id)
)
);
diff --git a/src/error.rs b/src/error.rs
@@ -5,6 +5,7 @@ pub enum Error {
DbOpenFailed,
NotFound,
DecodeError,
+ QueryError,
NoteProcessFailed,
TransactionFailed,
SubscriptionError,
@@ -15,6 +16,7 @@ impl fmt::Display for Error {
let s = match self {
Error::DbOpenFailed => "Open failed",
Error::NotFound => "Not found",
+ Error::QueryError => "Query failed",
Error::DecodeError => "Decode error",
Error::NoteProcessFailed => "Note process failed",
Error::TransactionFailed => "Transaction failed",
diff --git a/src/filter.rs b/src/filter.rs
@@ -1,12 +1,11 @@
use crate::bindings;
use crate::Note;
use std::ffi::CString;
-use std::marker::PhantomPinned;
use std::os::raw::c_char;
use std::ptr::null_mut;
use tracing::debug;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct Filter {
pub data: bindings::ndb_filter,
}
diff --git a/src/lib.rs b/src/lib.rs
@@ -15,6 +15,7 @@ mod filter;
mod ndb;
mod note;
mod profile;
+mod query;
mod result;
mod subscription;
mod transaction;
@@ -26,6 +27,7 @@ pub use filter::Filter;
pub use ndb::Ndb;
pub use note::Note;
pub use profile::ProfileRecord;
+pub use query::QueryResult;
pub use result::Result;
pub use subscription::Subscription;
pub use transaction::Transaction;
diff --git a/src/ndb.rs b/src/ndb.rs
@@ -3,7 +3,8 @@ use std::ffi::CString;
use std::ptr;
use crate::{
- bindings, Blocks, Config, Error, Filter, Note, ProfileRecord, Result, Subscription, Transaction,
+ bindings, Blocks, Config, Error, Filter, Note, ProfileRecord, QueryResult, Result,
+ Subscription, Transaction,
};
use std::fs;
use std::os::raw::c_int;
@@ -81,6 +82,36 @@ impl Ndb {
Ok(())
}
+ pub fn query<'a>(
+ &self,
+ txn: &'a Transaction,
+ filters: Vec<Filter>,
+ max_results: i32,
+ ) -> Result<Vec<QueryResult<'a>>> {
+ let mut ndb_filters: Vec<bindings::ndb_filter> = filters.iter().map(|a| a.data).collect();
+ let mut out: Vec<bindings::ndb_query_result> = vec![];
+ let mut returned: i32 = 0;
+ out.reserve_exact(max_results as usize);
+ let res = unsafe {
+ bindings::ndb_query(
+ txn.as_mut_ptr(),
+ ndb_filters.as_mut_ptr(),
+ ndb_filters.len() as i32,
+ out.as_mut_ptr(),
+ max_results,
+ &mut returned as *mut i32,
+ )
+ };
+ if res == 1 {
+ unsafe {
+ out.set_len(returned as usize);
+ };
+ Ok(out.iter().map(|r| QueryResult::new(r, txn)).collect())
+ } else {
+ Err(Error::QueryError)
+ }
+ }
+
pub fn subscribe(&self, filters: Vec<Filter>) -> Result<Subscription> {
unsafe {
let mut ndb_filters: Vec<bindings::ndb_filter> =
@@ -103,7 +134,7 @@ impl Ndb {
vec.reserve_exact(max_notes as usize);
let sub_id = sub.id;
- let res = unsafe {
+ unsafe {
let res = bindings::ndb_poll_for_notes(
self.as_ptr(),
sub_id,
@@ -255,10 +286,36 @@ mod tests {
}
#[tokio::test]
+ async fn query_works() {
+ let db = "target/testdbs/query";
+ test_util::cleanup_db(&db);
+
+ {
+ let ndb = Ndb::new(db, &Config::new()).expect("ndb");
+
+ let mut filter = Filter::new();
+ filter.kinds(vec![1]);
+
+ let filters = vec![filter];
+ let sub = ndb.subscribe(filters.clone()).expect("sub_id");
+ let waiter = ndb.wait_for_notes(&sub, 1);
+ ndb.process_event(r#"["EVENT","b",{"id": "702555e52e82cc24ad517ba78c21879f6e47a7c0692b9b20df147916ae8731a3","pubkey": "32bf915904bfde2d136ba45dde32c88f4aca863783999faea2e847a8fafd2f15","created_at": 1702675561,"kind": 1,"tags": [],"content": "hello, world","sig": "2275c5f5417abfd644b7bc74f0388d70feb5d08b6f90fa18655dda5c95d013bfbc5258ea77c05b7e40e0ee51d8a2efa931dc7a0ec1db4c0a94519762c6625675"}]"#).expect("process ok");
+ let res = waiter.await.expect("await ok");
+ assert_eq!(res, vec![1]);
+ let txn = Transaction::new(&ndb).expect("txn");
+ let res = ndb.query(&txn, filters, 1).expect("query ok");
+ assert_eq!(res.len(), 1);
+ assert_eq!(
+ hex::encode(res[0].note.id()),
+ "702555e52e82cc24ad517ba78c21879f6e47a7c0692b9b20df147916ae8731a3"
+ );
+ }
+ }
+
+ #[tokio::test]
async fn subscribe_event_works() {
let db = "target/testdbs/subscribe";
test_util::cleanup_db(&db);
- tracing_subscriber::fmt::init();
{
let ndb = Ndb::new(db, &Config::new()).expect("ndb");
diff --git a/src/query.rs b/src/query.rs
@@ -0,0 +1,22 @@
+use crate::{bindings, Note, Transaction};
+
+pub struct QueryResult<'a> {
+ pub note: Note<'a>,
+ pub note_size: u64,
+ pub note_key: u64,
+}
+
+impl<'a> QueryResult<'a> {
+ pub fn new(result: &bindings::ndb_query_result, txn: &'a Transaction) -> Self {
+ QueryResult {
+ note: Note::new_transactional(
+ result.note,
+ result.note_size as usize,
+ result.note_id,
+ txn,
+ ),
+ note_size: result.note_size,
+ note_key: result.note_id,
+ }
+ }
+}