diff --git a/scripts/db-export.test.ts b/scripts/db-export.test.ts new file mode 100644 index 00000000..939537d5 --- /dev/null +++ b/scripts/db-export.test.ts @@ -0,0 +1,94 @@ +import { assertEquals, assertThrows } from '@std/assert'; +import { buildFilter } from './db-export.ts'; + +Deno.test('buildFilter should return an empty filter when no arguments are provided', () => { + const filter = buildFilter({}); + assertEquals(Object.keys(filter).length, 0); +}); + +Deno.test('buildFilter should correctly handle valid authors', () => { + const filter = buildFilter({ + authors: ['a'.repeat(64)], + }); + + assertEquals(filter.authors, ['a'.repeat(64)]); +}); + +Deno.test('buildFilter throws on invalid author pubkey', () => { + assertThrows( + () => { + buildFilter({ + authors: ['invalid_pubkey'], + }); + }, + Error, + 'ERROR: Invalid pubkey invalid_pubkey supplied.', + ); +}); + +Deno.test('buildFilter should correctly handle valid ids', () => { + const filter = buildFilter({ + ids: ['b'.repeat(64)], + }); + + assertEquals(filter.ids, ['b'.repeat(64)]); +}); + +Deno.test('buildFilter should throw on invalid event IDs', () => { + assertThrows( + () => { + buildFilter({ + ids: ['invalid_id'], + }); + }, + Error, + 'ERROR: Invalid event ID invalid_id supplied.', + ); +}); + +Deno.test('buildFilter should correctly handle tag shortcuts', () => { + const filter = buildFilter({ + d: 'value1', + e: 'a'.repeat(64), + p: 'b'.repeat(64), + }); + + assertEquals(filter['#d'], ['value1']); + assertEquals(filter['#e'], ['a'.repeat(64)]); + assertEquals(filter['#p'], ['b'.repeat(64)]); +}); + +Deno.test('buildFilter should correctly handle since and until args', () => { + const filter = buildFilter({ + since: 1000, + until: 2000, + }); + + assertEquals(filter.since, 1000); + assertEquals(filter.until, 2000); +}); + +Deno.test('buildFilter should correctly handle search field', () => { + const filter = buildFilter({ + search: 'search_term', + }); + + assertEquals(filter.search, 'search_term'); +}); + +Deno.test('buildFilter should correctly handle tag k-v pairs', () => { + const filter = buildFilter({ + tags: ['tag1=value1', 'tag2=value2'], + }); + + assertEquals(filter['#tag1'], ['value1']); + assertEquals(filter['#tag2'], ['value2']); +}); + +Deno.test('buildFilter should correctly handle limit specifier', () => { + const filter = buildFilter({ + limit: 10, + }); + + assertEquals(filter.limit, 10); +}); diff --git a/scripts/db-export.ts b/scripts/db-export.ts index 1120a190..71939105 100644 --- a/scripts/db-export.ts +++ b/scripts/db-export.ts @@ -2,8 +2,6 @@ import { Storages } from '@/storages.ts'; import { NostrFilter } from '@nostrify/nostrify'; import { Command, InvalidOptionArgumentError } from 'commander'; -const store = await Storages.db(); - interface ExportFilter { authors?: string[]; ids?: string[]; @@ -47,11 +45,11 @@ function die(code: number, ...args: any[]) { function tagFilterShortcut(name: 'd' | 'e' | 'p', value: string) { const val = [value]; - if (findInvalid(val)) die(1, `ERROR: Invalid value supplied for ${name}-tag.`); + if (findInvalid(val)) throw new Error(`ERROR: Invalid value supplied for ${name}-tag.`); return val; } -async function exportEvents(args: ExportFilter) { +export function buildFilter(args: ExportFilter) { const filter: NostrFilter = {}; const { authors, ids, kinds, d, e, limit, p, search, since, until, tags } = args; if (since) { @@ -62,18 +60,19 @@ async function exportEvents(args: ExportFilter) { } if (authors && authors.length) { const invalid = findInvalid(authors); - if (invalid) die(1, `ERROR: Invalid pubkey ${invalid} supplied.`); + if (invalid) throw new Error(`ERROR: Invalid pubkey ${invalid} supplied.`); filter.authors = authors; } if (ids) { const invalid = findInvalid(ids); - if (invalid) die(1, `ERROR: Invalid event ID ${invalid} supplied.`); + if (invalid) throw new Error(`ERROR: Invalid event ID ${invalid} supplied.`); + filter.ids = ids; } if (kinds && kinds.length) { filter.kinds = kinds; } if (d) { - filter['#d'] = tagFilterShortcut('d', d); + filter['#d'] = [d]; } if (e) { filter['#e'] = tagFilterShortcut('e', e); @@ -94,6 +93,19 @@ async function exportEvents(args: ExportFilter) { } } + return filter; +} + +async function exportEvents(args: ExportFilter) { + const store = await Storages.db(); + + let filter: NostrFilter = {}; + try { + filter = buildFilter(args); + } catch (e) { + die(1, e.message || e.toString()); + } + let count = 0; for await (const msg of store.req([filter])) { if (msg[0] === 'EOSE') { @@ -144,5 +156,3 @@ if (import.meta.main) { await exporter.parseAsync(Deno.args, { from: 'user' }); } - -Deno.exit();