nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

commit ab100d9e70018fb8984f13d308154a79c21c0df8
parent 0d52aac1f203a648013d993675aec375d9227381
Author: William Casarin <jb55@jb55.com>
Date:   Sun,  3 Nov 2024 07:18:28 -0800

add ndb_filter_eq

filter equality testing. this works because field elements are sorted

Changelog-Added: Add ndb_filter_eq for filter equality testing
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/nostrdb.c | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/nostrdb.h | 4++++
Mtest.c | 28++++++++++++++++++++++++++++
3 files changed, 111 insertions(+), 0 deletions(-)

diff --git a/src/nostrdb.c b/src/nostrdb.c @@ -1154,6 +1154,62 @@ static void sort_filter_elements(struct ndb_filter *filter, els->elements[i] -= (uint64_t)filter->data_buf.start; } +static int ndb_filter_field_eq(struct ndb_filter *a_filt, + struct ndb_filter_elements *a_field, + struct ndb_filter *b_filt, + struct ndb_filter_elements *b_field) +{ + int i; + const char *a_str, *b_str; + unsigned char *a_id, *b_id; + uint64_t a_int, b_int; + + if (a_field->count != b_field->count) + return 0; + + if (a_field->field.type != b_field->field.type) { + ndb_debug("UNUSUAL: field types do not match in ndb_filter_field_eq\n"); + return 0; + } + + if (a_field->field.elem_type != b_field->field.elem_type) { + ndb_debug("UNUSUAL: field element types do not match in ndb_filter_field_eq\n"); + return 0; + } + + if (a_field->field.elem_type == NDB_ELEMENT_UNKNOWN) { + ndb_debug("UNUSUAL: field element types are unknown\n"); + return 0; + } + + for (i = 0; i < a_field->count; i++) { + switch (a_field->field.elem_type) { + case NDB_ELEMENT_UNKNOWN: + return 0; + case NDB_ELEMENT_STRING: + a_str = ndb_filter_get_string_element(a_filt, a_field, i); + b_str = ndb_filter_get_string_element(b_filt, b_field, i); + if (strcmp(a_str, b_str)) + return 0; + break; + case NDB_ELEMENT_ID: + a_id = ndb_filter_get_id_element(a_filt, a_field, i); + b_id = ndb_filter_get_id_element(b_filt, b_field, i); + if (memcmp(a_id, b_id, 32)) + return 0; + break; + case NDB_ELEMENT_INT: + a_int = ndb_filter_get_int_element(a_field, i); + b_int = ndb_filter_get_int_element(b_field, i); + if (a_int != b_int) + return 0; + break; + } + } + + return 1; +} + void ndb_filter_end_field(struct ndb_filter *filter) { int cur_offset; @@ -2616,6 +2672,29 @@ ndb_filter_find_elements(struct ndb_filter *filter, enum ndb_filter_fieldtype ty return NULL; } +int ndb_filter_eq(struct ndb_filter *a, struct ndb_filter *b) +{ + int i; + struct ndb_filter_elements *a_els, *b_els; + + if (a->num_elements != b->num_elements) + return 0; + + for (i = 0; i < a->num_elements; i++) { + a_els = ndb_filter_get_elements(a, i); + b_els = ndb_filter_find_elements(b, a_els->field.type); + + if (b_els == NULL) + return 0; + + if (!ndb_filter_field_eq(a, a_els, b, b_els)) + return 0; + } + + return 1; +} + + static uint64_t * ndb_filter_get_elem(struct ndb_filter *filter, enum ndb_filter_fieldtype typ) { diff --git a/src/nostrdb.h b/src/nostrdb.h @@ -257,6 +257,9 @@ struct ndb_filter { int current; // struct ndb_filter_elements offsets into elem_buf + // + // TODO(jb55): this should probably be called fields. elements are + // the things within fields int elements[NDB_NUM_FILTERS]; }; @@ -492,6 +495,7 @@ int ndb_filter_init(struct ndb_filter *); int ndb_filter_add_id_element(struct ndb_filter *, const unsigned char *id); int ndb_filter_add_int_element(struct ndb_filter *, uint64_t integer); int ndb_filter_add_str_element(struct ndb_filter *, const char *str); +int ndb_filter_eq(struct ndb_filter *, struct ndb_filter *); // filters from json int ndb_filter_from_json(const char *, int len, struct ndb_filter *filter, unsigned char *buf, int bufsize); diff --git a/test.c b/test.c @@ -1662,8 +1662,36 @@ static void test_weird_note_corruption() { ndb_destroy(ndb); } +static void test_filter_eq() { + struct ndb_filter filter, *f = &filter; + struct ndb_filter filter2, *f2 = &filter2; + + ndb_filter_init(f); + assert(ndb_filter_start_field(f, NDB_FILTER_UNTIL)); + assert(ndb_filter_add_int_element(f, 42)); + ndb_filter_end_field(f); + assert(ndb_filter_start_field(f, NDB_FILTER_KINDS)); + assert(ndb_filter_add_int_element(f, 1)); + assert(ndb_filter_add_int_element(f, 2)); + ndb_filter_end_field(f); + ndb_filter_end(f); + + ndb_filter_init(f2); + assert(ndb_filter_start_field(f2, NDB_FILTER_KINDS)); + assert(ndb_filter_add_int_element(f2, 2)); + assert(ndb_filter_add_int_element(f2, 1)); + ndb_filter_end_field(f2); + assert(ndb_filter_start_field(f2, NDB_FILTER_UNTIL)); + assert(ndb_filter_add_int_element(f2, 42)); + ndb_filter_end_field(f2); + ndb_filter_end(f2); + + assert(ndb_filter_eq(f, f2)); +} + int main(int argc, const char *argv[]) { test_parse_filter_json(); + test_filter_eq(); test_filter_json(); test_bech32_parsing(); test_single_url_parsing();