mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo.git
synced 2026-09-21 16:52:01 -07:00
Order GET /topics by most recent post
By coder.
This commit is contained in:
@@ -373,7 +373,7 @@ async function loadTopicsWithPosts (world) {
|
||||
{ key: 'bitcoin:post-200', room: 'bitcoin', txid: 'post-200', type: 'post', blockHeight: 200 },
|
||||
{ key: 'bitcoin:addr-f', room: 'bitcoin', addr: 'addr-f', type: 'follow', unfollow: false },
|
||||
{ key: 'cash:post-250', room: 'cash', txid: 'post-250', type: 'post', blockHeight: 250 },
|
||||
{ key: 'dev:post-100', room: 'dev', txid: 'post-100', type: 'post', blockHeight: 100 },
|
||||
{ key: 'dev:post-400', room: 'dev', txid: 'post-400', type: 'post', blockHeight: 400 },
|
||||
{ key: 'lone:addr-f', room: 'lone', addr: 'addr-f', type: 'follow', unfollow: false }
|
||||
]
|
||||
|
||||
@@ -381,7 +381,7 @@ async function loadTopicsWithPosts (world) {
|
||||
'post-300': { addr: 'addr-a', text: 'hello bitcoin', seen: 1, blockHeight: 300 },
|
||||
'post-200': { addr: 'addr-b', text: 'bitcoin again', seen: 2, blockHeight: 200 },
|
||||
'post-250': { addr: 'addr-a', text: 'cash rules', seen: 3, blockHeight: 250 },
|
||||
'post-100': { addr: 'addr-c', text: 'dev stuff', seen: 4, blockHeight: 100 }
|
||||
'post-400': { addr: 'addr-c', text: 'dev stuff', seen: 4, blockHeight: 400 }
|
||||
}
|
||||
|
||||
for (const entry of roomEntries) {
|
||||
@@ -868,6 +868,17 @@ const handlers = [
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'response lists topics in order',
|
||||
pattern: /^the response lists topics in order (<expected_order>)$/,
|
||||
run (m, example, world) {
|
||||
const expected = resolveParam(m[1], example).split(',').map((s) => s.trim())
|
||||
const actual = world.getLastResponse().topics.map((t) => t.room)
|
||||
if (expected.join(',') !== actual.join(',')) {
|
||||
throw new Error(`Expected topics ${expected.join(',')}, got ${actual.join(',')}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'request topic posts',
|
||||
pattern: /^the client requests \/topics\/([^/]+)\/posts(?: with limit (<limit>) and offset (<offset>))?$/,
|
||||
|
||||
@@ -42,21 +42,31 @@ class TopicQuery {
|
||||
}
|
||||
|
||||
async listTopics () {
|
||||
const counts = new Map()
|
||||
const topics = new Map()
|
||||
|
||||
for await (const [key, value] of this.roomsDb.iterator()) {
|
||||
const room = this.roomFromKey(key, value)
|
||||
if (!counts.has(room)) {
|
||||
counts.set(room, 0)
|
||||
if (!topics.has(room)) {
|
||||
topics.set(room, { postCount: 0, lastHeight: 0 })
|
||||
}
|
||||
const topic = topics.get(room)
|
||||
if (value?.type === 'post') {
|
||||
counts.set(room, counts.get(room) + 1)
|
||||
topic.postCount++
|
||||
const height = value?.blockHeight ?? 0
|
||||
if (height > topic.lastHeight) {
|
||||
topic.lastHeight = height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(counts.entries())
|
||||
.map(([room, postCount]) => ({ room, postCount }))
|
||||
.sort((a, b) => a.room.localeCompare(b.room))
|
||||
return Array.from(topics.entries())
|
||||
.map(([room, { postCount, lastHeight }]) => ({ room, postCount, lastHeight }))
|
||||
.sort((a, b) => {
|
||||
if (b.lastHeight !== a.lastHeight) {
|
||||
return b.lastHeight - a.lastHeight
|
||||
}
|
||||
return a.room.localeCompare(b.room)
|
||||
})
|
||||
}
|
||||
|
||||
async getTopicPostTxids (room, { limit, offset }) {
|
||||
|
||||
@@ -86,7 +86,7 @@ function fixtureGen () {
|
||||
}
|
||||
}
|
||||
|
||||
test('listTopics conserves post counts and returns rooms sorted by name', async () => {
|
||||
test('listTopics conserves post counts and returns rooms sorted by most recent post', async () => {
|
||||
await forAll(
|
||||
fixtureGen(),
|
||||
async ({ entries, rooms }) => {
|
||||
@@ -97,8 +97,18 @@ test('listTopics conserves post counts and returns rooms sorted by name', async
|
||||
const totalPosts = topics.reduce((sum, t) => sum + t.postCount, 0)
|
||||
if (totalPosts !== postEntries.length) return false
|
||||
|
||||
const expectedRooms = [...new Set(entries.map((e) => e.value.room))].sort((a, b) => a.localeCompare(b))
|
||||
if (JSON.stringify(topics.map((t) => t.room)) !== JSON.stringify(expectedRooms)) return false
|
||||
const expectedTopics = [...new Set(entries.map((e) => e.value.room))]
|
||||
.map((room) => {
|
||||
const heights = entries
|
||||
.filter((e) => e.value.room === room && e.value.type === 'post')
|
||||
.map((e) => e.value.blockHeight ?? 0)
|
||||
return { room, lastHeight: heights.length ? Math.max(...heights) : 0 }
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (b.lastHeight !== a.lastHeight) return b.lastHeight - a.lastHeight
|
||||
return a.room.localeCompare(b.room)
|
||||
})
|
||||
if (JSON.stringify(topics.map((t) => t.room)) !== JSON.stringify(expectedTopics.map((t) => t.room))) return false
|
||||
|
||||
for (const topic of topics) {
|
||||
const roomPosts = postEntries.filter((e) => e.value.room === topic.room).length
|
||||
|
||||
@@ -108,23 +108,26 @@ describe('#TopicQuery', () => {
|
||||
const result = await uut.listTopics()
|
||||
|
||||
assert.deepEqual(result, [
|
||||
{ room: 'bitcoin', postCount: 2 },
|
||||
{ room: 'cash', postCount: 1 },
|
||||
{ room: 'dev', postCount: 1 },
|
||||
{ room: 'lone', postCount: 0 }
|
||||
{ room: 'bitcoin', postCount: 2, lastHeight: 300 },
|
||||
{ room: 'cash', postCount: 1, lastHeight: 250 },
|
||||
{ room: 'dev', postCount: 1, lastHeight: 100 },
|
||||
{ room: 'lone', postCount: 0, lastHeight: 0 }
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort topics by room name', async () => {
|
||||
it('should sort topics by most recent post descending', async () => {
|
||||
async function * mockRooms () {
|
||||
yield ['zoo:post-1', { room: 'zoo', txid: 'post-1', type: 'post', blockHeight: 1 }]
|
||||
yield ['alpha:post-1', { room: 'alpha', txid: 'post-1', type: 'post', blockHeight: 1 }]
|
||||
yield ['alpha:post-1', { room: 'alpha', txid: 'post-1', type: 'post', blockHeight: 2 }]
|
||||
}
|
||||
roomsDb.iterator.returns(mockRooms())
|
||||
|
||||
const result = await uut.listTopics()
|
||||
|
||||
assert.deepEqual(result.map((t) => t.room), ['alpha', 'zoo'])
|
||||
assert.deepEqual(result.map((t) => ({ room: t.room, lastHeight: t.lastHeight })), [
|
||||
{ room: 'alpha', lastHeight: 2 },
|
||||
{ room: 'zoo', lastHeight: 1 }
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user