Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/generic-tags-empty-values.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostream": patch
---

Allow generic tag filters to match empty string tag values.
2 changes: 1 addition & 1 deletion src/schemas/filter-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const filterSchema = z
until: createdAtSchema.optional(),
limit: z.number().int().min(0).optional(),
})
.catchall(z.array(z.string().min(1).max(1024)))
.catchall(z.array(z.string().max(1024)))
.superRefine((data, ctx) => {
for (const key of Object.keys(data)) {
if (!knownFilterKeys.has(key) && !isGenericTagQuery(key)) {
Expand Down
12 changes: 12 additions & 0 deletions test/unit/repositories/event-repository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,18 @@ describe('EventRepository', () => {
)
})
})

describe('#d', () => {
it('selects events by empty #d tag value', () => {
const filters = [{ '#d': [''] }]

const query = repository.findByFilters(filters).toString()

expect(query).to.equal(
'select "events".* from "events" left join "event_tags" on "events"."event_id" = "event_tags"."event_id" where (event_tags.tag_name = \'d\' AND event_tags.tag_value = \'\') order by "event_created_at" asc, "event_id" asc limit 500',
)
})
})
})

describe('2 filters', () => {
Expand Down
14 changes: 11 additions & 3 deletions test/unit/schemas/filter-schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ describe('NIP-01', () => {
expect(result.value).to.deep.equal(filter)
})

it('accepts empty strings in generic tag filters', () => {
const filterWithEmptyTagValue = {
'#d': [''],
}

const result = validateSchema(filterSchema)(filterWithEmptyTagValue)

expect(result.error).to.be.undefined
expect(result.value).to.deep.equal(filterWithEmptyTagValue)
})

const cases = {
ids: [{ message: 'must be an array', transform: assocPath(['ids'], null) }],
prefixOrId: [
Expand Down Expand Up @@ -103,23 +114,20 @@ describe('NIP-01', () => {
message: 'length must be less than or equal to 1024 characters long',
transform: assocPath(['#e', 0], 'f'.repeat(1024 + 1)),
},
{ message: 'is not allowed to be empty', transform: assocPath(['#e', 0], '') },
],
'#p': [{ message: 'must be an array', transform: assocPath(['#p'], null) }],
'#p[0]': [
{
message: 'length must be less than or equal to 1024 characters long',
transform: assocPath(['#p', 0], 'f'.repeat(1024 + 1)),
},
{ message: 'is not allowed to be empty', transform: assocPath(['#p', 0], '') },
],
'#r': [{ message: 'must be an array', transform: assocPath(['#r'], null) }],
'#r[0]': [
{
message: 'length must be less than or equal to 1024 characters long',
transform: assocPath(['#r', 0], 'f'.repeat(1024 + 1)),
},
{ message: 'is not allowed to be empty', transform: assocPath(['#r', 0], '') },
],
}

Expand Down
19 changes: 19 additions & 0 deletions test/unit/utils/event.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,25 @@ describe('NIP-01', () => {

describe('NIP-12', () => {
let event: Event

describe('#d filter', () => {
beforeEach(() => {
event = {
id: 'cf8de9db67a1d7203512d1d81e6190f5e53abfdc0ac90275f67172b65a5b09a0',
pubkey: 'e8b487c079b0f67c695ae6c4c2552a47f38adfa2533cc5926bd2c102942fdcb7',
created_at: 1645030752,
kind: EventKinds.PARAMETERIZED_REPLACEABLE_FIRST,
tags: [['d', '']],
content: 'empty d tag',
sig: '53d12018d036092794366283eca36df4e0cabd014b6e91bbf684c8bb9bbbe9dedafa77b6b928587e11e05e036227598dded8713e8da17d55076e12242b361542',
}
})

it('returns true if #d filter contains an empty tag value in the event', () => {
expect(isEventMatchingFilter({ '#d': [''] })(event)).to.be.true
})
})

describe('#r filter', () => {
beforeEach(() => {
event = {
Expand Down
Loading