nostrdb

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

commit eb469b526aaf467533f35bc9b36aeeea6bf0aac9
parent 61d66748fb19d9b351be4c06f4741264363c8e5f
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 20 Jul 2023 14:17:55 -0700

json: support tag parsing

Also greatly simplify the iterator so you can quickly pull out string
values.

Diffstat:
Mnostrdb.c | 61+++++++++++++++++++++++++++++++++++++++----------------------
Mnostrdb.h | 20++++++++++++++++----
Mtest.c | 42+++++++++++++++++++++++++++++++-----------
3 files changed, 86 insertions(+), 37 deletions(-)

diff --git a/nostrdb.c b/nostrdb.c @@ -177,20 +177,40 @@ static inline int toksize(jsmntok_t *tok) { return tok->end - tok->start; } +// Push a json array into an ndb tag ["p", "abcd..."] -> struct ndb_tag static inline int -build_tag_from_json_tokens(struct ndb_json_parser *p, jsmntok_t *tag) { - printf("tag %.*s %d\n", toksize(tag), p->json + tag->start, tag->type); +ndb_builder_tag_from_json_array(struct ndb_json_parser *p, jsmntok_t *array) { + jsmntok_t *str_tok; + const char *str; + + if (array->size == 0) + return 0; + + if (!ndb_builder_new_tag(&p->builder)) + return 0; + + for (int i = 0; i < array->size; i++) { + str_tok = &array[i+1]; + str = p->json + str_tok->start; + + if (!ndb_builder_push_tag_str(&p->builder, str, toksize(str_tok))) + return 0; + } return 1; } +// Push json tags into ndb data +// [["t", "hashtag"], ["p", "abcde..."]] -> struct ndb_tags static inline int ndb_builder_process_json_tags(struct ndb_json_parser *p, jsmntok_t *array) { jsmntok_t *tag = array; - printf("json_tags %.*s %d\n", toksize(tag), p->json + tag->start, tag->type); + + if (array->size == 0) + return 1; for (int i = 0; i < array->size; i++) { - if (!build_tag_from_json_tokens(p, &tag[i+1])) + if (!ndb_builder_tag_from_json_array(p, &tag[i+1])) return 0; tag += array->size; } @@ -289,26 +309,23 @@ ndb_builder_set_kind(struct ndb_builder *builder, uint32_t kind) { } int -ndb_builder_add_tag(struct ndb_builder *builder, const char **strs, uint16_t num_strs) { - int i; - union packed_str pstr; - const char *str; - struct ndb_tag tag; - +ndb_builder_new_tag(struct ndb_builder *builder) { builder->note->tags.count++; - tag.count = num_strs; + struct ndb_tag tag = {0}; + builder->current_tag = (struct ndb_tag *)builder->note_cur.p; + return cursor_push_tag(&builder->note_cur, &tag); +} - if (!cursor_push_tag(&builder->note_cur, &tag)) +/// Push an element to the current tag +/// +/// Basic idea is to call ndb_builder_new_tag +inline int +ndb_builder_push_tag_str(struct ndb_builder *builder, const char *str, int len) { + union packed_str pstr; + if (!ndb_builder_make_string(builder, str, len, &pstr)) return 0; - - for (i = 0; i < num_strs; i++) { - str = strs[i]; - if (!ndb_builder_make_string(builder, str, strlen(str), &pstr)) - return 0; - if (!cursor_push_u32(&builder->note_cur, pstr.offset)) - return 0; - } - + if (!cursor_push_u32(&builder->note_cur, pstr.offset)) + return 0; + builder->current_tag->count++; return 1; } - diff --git a/nostrdb.h b/nostrdb.h @@ -55,6 +55,7 @@ struct ndb_builder { struct cursor strings; struct cursor str_indices; struct ndb_note *note; + struct ndb_tag *current_tag; }; struct ndb_iterator { @@ -74,7 +75,8 @@ void ndb_builder_set_signature(struct ndb_builder *builder, unsigned char *signa void ndb_builder_set_pubkey(struct ndb_builder *builder, unsigned char *pubkey); void ndb_builder_set_id(struct ndb_builder *builder, unsigned char *id); void ndb_builder_set_kind(struct ndb_builder *builder, uint32_t kind); -int ndb_builder_add_tag(struct ndb_builder *builder, const char **strs, uint16_t num_strs); +int ndb_builder_new_tag(struct ndb_builder *builder); +int ndb_builder_push_tag_str(struct ndb_builder *builder, const char *str, int len); // BYE BUILDER static inline int @@ -83,13 +85,23 @@ ndb_str_is_packed(union packed_str str) { } static inline const char * -ndb_note_string(struct ndb_note *note, union packed_str *str) { +ndb_note_str(struct ndb_note *note, union packed_str *str) { if (ndb_str_is_packed(*str)) return str->packed.str; return ((const char *)note) + note->strings + str->offset; } +static inline const char * +ndb_tag_str(struct ndb_note *note, struct ndb_tag *tag, int ind) { + return ndb_note_str(note, &tag->strs[ind]); +} + +static inline const char * +ndb_iter_tag_str(struct ndb_iterator *iter, int ind) { + return ndb_tag_str(iter->note, iter->tag, ind); +} + static inline unsigned char * ndb_note_id(struct ndb_note *note) { return note->id; @@ -112,7 +124,7 @@ ndb_note_created_at(struct ndb_note *note) { static inline const char * ndb_note_content(struct ndb_note *note) { - return ndb_note_string(note, &note->content); + return ndb_note_str(note, &note->content); } static inline struct ndb_note * @@ -156,7 +168,7 @@ ndb_note_tag_index(struct ndb_note *note, struct ndb_tag *tag, int index) { return 0; } - return ndb_note_string(note, &tag->strs[index]); + return ndb_note_str(note, &tag->strs[index]); } static inline int diff --git a/test.c b/test.c @@ -22,10 +22,7 @@ static void test_basic_event() { unsigned char sig[64]; memset(sig, 3, 64); - const char *hex_pk = "5d9b81b2d4d5609c5565286fc3b511dc6b9a1b3d7d1174310c624d61d1f82bb9"; - const char *tag[] = { "p", hex_pk }; - const char *word_tag[] = { "word", "words", "w" }; ok = ndb_builder_new(b, buf, sizeof(buf)); assert(ok); @@ -39,8 +36,15 @@ static void test_basic_event() { ndb_builder_set_id(b, id); assert(ok); ndb_builder_set_pubkey(b, pubkey); assert(ok); ndb_builder_set_signature(b, sig); assert(ok); - ok = ndb_builder_add_tag(b, tag, ARRAY_SIZE(tag)); assert(ok); - ok = ndb_builder_add_tag(b, word_tag, ARRAY_SIZE(word_tag)); assert(ok); + + ok = ndb_builder_new_tag(b); assert(ok); + ok = ndb_builder_push_tag_str(b, "p", 1); assert(ok); + ok = ndb_builder_push_tag_str(b, hex_pk, 64); assert(ok); + + ok = ndb_builder_new_tag(b); assert(ok); + ok = ndb_builder_push_tag_str(b, "word", 4); assert(ok); + ok = ndb_builder_push_tag_str(b, "words", 5); assert(ok); + ok = ndb_builder_push_tag_str(b, "w", 1); assert(ok); ok = ndb_builder_finalize(b, &note); assert(ok); @@ -53,8 +57,8 @@ static void test_basic_event() { ok = ndb_tags_iterate_start(note, it); assert(ok); assert(it->tag->count == 2); - const char *p = ndb_note_string(note, &it->tag->strs[0]); - const char *hpk = ndb_note_string(note, &it->tag->strs[1]); + const char *p = ndb_iter_tag_str(it, 0); + const char *hpk = ndb_iter_tag_str(it, 1); assert(hpk); assert(!ndb_str_is_packed(it->tag->strs[1])); assert(!strcmp(hpk, hex_pk)); @@ -63,9 +67,9 @@ static void test_basic_event() { ok = ndb_tags_iterate_next(it); assert(ok); assert(it->tag->count == 3); - assert(!strcmp(ndb_note_string(note, &it->tag->strs[0]), "word")); - assert(!strcmp(ndb_note_string(note, &it->tag->strs[1]), "words")); - assert(!strcmp(ndb_note_string(note, &it->tag->strs[2]), "w")); + assert(!strcmp(ndb_iter_tag_str(it, 0), "word")); + assert(!strcmp(ndb_iter_tag_str(it, 1), "words")); + assert(!strcmp(ndb_iter_tag_str(it, 2), "w")); ok = ndb_tags_iterate_next(it); assert(!ok); @@ -98,16 +102,32 @@ static void test_parse_json() { #define HEX_ID "5004a081e397c6da9dc2f2d6b3134006a9d0e8c1b46689d9fe150bb2f21a204d" #define HEX_PK "b169f596968917a1abeb4234d3cf3aa9baee2112e58998d17c6db416ad33fe40" static const char *json = - "{\"id\": \"" HEX_ID "\",\"pubkey\": \"" HEX_PK "\",\"created_at\": 1689836342,\"kind\": 1,\"tags\": [[\"p\",\"" HEX_ID "\"], [\"word\", \"words\"]],\"content\": \"共通語\",\"sig\": \"e4d528651311d567f461d7be916c37cbf2b4d530e672f29f15f353291ed6df60c665928e67d2f18861c5ca88\"}"; + "{\"id\": \"" HEX_ID "\",\"pubkey\": \"" HEX_PK "\",\"created_at\": 1689836342,\"kind\": 1,\"tags\": [[\"p\",\"" HEX_ID "\"], [\"word\", \"words\", \"w\"]],\"content\": \"共通語\",\"sig\": \"e4d528651311d567f461d7be916c37cbf2b4d530e672f29f15f353291ed6df60c665928e67d2f18861c5ca88\"}"; + int ok; ndb_note_from_json(json, strlen(json), &note, buffer, sizeof(buffer)); const char *content = ndb_note_content(note); unsigned char *id = ndb_note_id(note); + hex_encode(id, 32, hex_id, sizeof(hex_id)); assert(!strcmp(content, "共通語")); assert(!strcmp(HEX_ID, hex_id)); + + assert(note->tags.count == 2); + + struct ndb_iterator iter, *it = &iter; + ok = ndb_tags_iterate_start(note, it); assert(ok); + assert(it->tag->count == 2); + assert(!strcmp(ndb_iter_tag_str(it, 0), "p")); + assert(!strcmp(ndb_iter_tag_str(it, 1), HEX_ID)); + + ok = ndb_tags_iterate_next(it); assert(ok); + assert(it->tag->count == 3); + assert(!strcmp(ndb_iter_tag_str(it, 0), "word")); + assert(!strcmp(ndb_iter_tag_str(it, 1), "words")); + assert(!strcmp(ndb_iter_tag_str(it, 2), "w")); } int main(int argc, const char *argv[]) {