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/strong-candles-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostream": patch
---

Dedup keys were taking multiple tags, that was not according to NIP-01 behaviour.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
exports.up = async function (knex) {
await knex.raw(`
WITH ranked AS (
SELECT
id,
row_number() OVER (
PARTITION BY event_pubkey, event_kind, jsonb_build_array(COALESCE(event_deduplication->>0, ''))
ORDER BY event_created_at DESC, event_id ASC
) AS row_rank
FROM events
WHERE event_kind >= 30000
AND event_kind < 40000
)
DELETE FROM events AS e
USING ranked AS r
WHERE e.id = r.id
AND r.row_rank > 1;
`)

await knex.raw(`
UPDATE events
SET event_deduplication = jsonb_build_array(COALESCE(event_deduplication->>0, ''))
WHERE event_kind >= 30000
AND event_kind < 40000
AND event_deduplication IS DISTINCT FROM jsonb_build_array(COALESCE(event_deduplication->>0, ''));
`)
}

exports.down = async function () {
// Irreversible data migration.
}
4 changes: 2 additions & 2 deletions src/services/event-import-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ const enrichEventMetadata = (event: Event): Event => {
}

if (isParameterizedReplaceableEvent(event)) {
const [, ...deduplication] = event.tags.find((tag) => tag.length >= 2 && tag[0] === EventTags.Deduplication) ?? [
const [, deduplication] = event.tags.find((tag) => tag.length >= 2 && tag[0] === EventTags.Deduplication) ?? [
null,
'',
]
enriched = { ...enriched, [EventDeduplicationMetadataKey]: deduplication }
enriched = { ...enriched, [EventDeduplicationMetadataKey]: deduplication ? [deduplication] : [''] }
}

return enriched as Event
Expand Down
40 changes: 39 additions & 1 deletion test/unit/services/event-import-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { join } from 'path'
import fs from 'fs'
import os from 'os'

import { EventImportLineError, EventImportService, EventImportStats } from '../../../src/services/event-import-service'
import {
createEventBatchPersister,
EventImportLineError,
EventImportService,
EventImportStats,
} from '../../../src/services/event-import-service'
import { EventDeduplicationMetadataKey, EventKinds, EventTags } from '../../../src/constants/base'
import { Event } from '../../../src/@types/event'
import { expect } from 'chai'
import { getEvents } from '../data/events'
Expand Down Expand Up @@ -170,4 +176,36 @@ describe('EventImportService', () => {
expect(lineErrors.length).to.equal(0)
}
})

it('normalizes parameterized replaceable deduplication to first d tag value', async () => {
const parameterizedEvent: Event = {
id: 'a'.repeat(64),
pubkey: 'b'.repeat(64),
created_at: 1,
kind: EventKinds.PARAMETERIZED_REPLACEABLE_FIRST,
tags: [[EventTags.Deduplication, 'one', 'two']],
content: 'hello',
sig: 'c'.repeat(128),
}

let upsertedEvents: Event[] = []

const eventRepository = {
create: async () => 0,
createMany: async () => 0,
upsert: async () => 0,
upsertMany: async (events: Event[]) => {
upsertedEvents = events
return events.length
},
deleteByPubkeyAndIds: async () => 0,
} as any

const persistBatch = createEventBatchPersister(eventRepository)
const inserted = await persistBatch([parameterizedEvent])

expect(inserted).to.equal(1)
expect(upsertedEvents).to.have.length(1)
expect((upsertedEvents[0] as any)[EventDeduplicationMetadataKey]).to.deep.equal(['one'])
})
})
Loading