diff --git a/README.md b/README.md index 3212fbb..c3267ff 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Default port: **5021** All indexer data is exposed under `/level/*` with CRUD routes per entity (`post`, `like`, `name`, `profile`, `status`, etc.) plus: - `GET /profile/recent` — paginated list of profiles, sorted by block height (newest first) +- `GET /posts/recent` — paginated list of posts, sorted by block height (newest first) - `POST /level/backup` — zip database snapshot - `POST /level/restore` — restore from snapshot (exits process) - `GET /health` — health check @@ -39,7 +40,16 @@ curl -sS "http://localhost:5021/profile/recent" curl -sS "http://localhost:5021/profile/recent?limit=50&offset=50" ``` -Query parameters: `limit` (default `100`, max `100`), `offset` (default `0`). Block height comes from the profile tx’s `ptx` record. +Query parameters: `limit` (default `100`, max `100`), `offset` (default `0`). Block height is read from the stored profile document (`blockHeight` field, set at indexing time). + +### List recent posts + +```bash +curl -sS "http://localhost:5021/posts/recent" +curl -sS "http://localhost:5021/posts/recent?limit=50&offset=50" +``` + +Same query parameters as `/profile/recent`. ## Tests diff --git a/src/adapters/index.js b/src/adapters/index.js index f2adfe2..9b62a61 100644 --- a/src/adapters/index.js +++ b/src/adapters/index.js @@ -20,12 +20,10 @@ class Adapters { this.level = level this.dbBackup = new DbBackup(level) this.profileQuery = new ProfileQuery({ - profilesDb: level.profilesDb, - ptxsDb: level.ptxsDb + profilesDb: level.profilesDb }) this.postQuery = new PostQuery({ - postsDb: level.postsDb, - ptxsDb: level.ptxsDb + postsDb: level.postsDb }) return true } diff --git a/src/adapters/post-query.js b/src/adapters/post-query.js index fb0a03a..90d97d0 100644 --- a/src/adapters/post-query.js +++ b/src/adapters/post-query.js @@ -1,43 +1,27 @@ /* - Adapter for scanning posts and resolving block height from ptx records. + Adapter for scanning posts with stored block height. */ class PostQuery { constructor (localConfig = {}) { - const { postsDb, ptxsDb } = localConfig + const { postsDb } = localConfig if (!postsDb) { throw new Error('postsDb required when instantiating PostQuery adapter.') } - if (!ptxsDb) { - throw new Error('ptxsDb required when instantiating PostQuery adapter.') - } this.postsDb = postsDb - this.ptxsDb = ptxsDb this.scanPostsWithBlockHeight = this.scanPostsWithBlockHeight.bind(this) } - async getBlockHeightForTxid (txid) { - if (!txid) return 0 - try { - const ptx = await this.ptxsDb.get(txid) - const height = ptx && ptx.blockHeight - return typeof height === 'number' ? height : parseInt(height, 10) || 0 - } catch (err) { - return 0 - } - } - async scanPostsWithBlockHeight () { const posts = [] for await (const [txid, post] of this.postsDb.iterator()) { - const blockHeight = await this.getBlockHeightForTxid(txid) posts.push({ txid, addr: post.addr, text: post.text, seen: post.seen, - blockHeight + blockHeight: post.blockHeight ?? 0 }) } diff --git a/src/adapters/profile-query.js b/src/adapters/profile-query.js index 5700443..647ce53 100644 --- a/src/adapters/profile-query.js +++ b/src/adapters/profile-query.js @@ -1,43 +1,27 @@ /* - Adapter for scanning profiles and resolving block height from ptx records. + Adapter for scanning profiles with stored block height. */ class ProfileQuery { constructor (localConfig = {}) { - const { profilesDb, ptxsDb } = localConfig + const { profilesDb } = localConfig if (!profilesDb) { throw new Error('profilesDb required when instantiating ProfileQuery adapter.') } - if (!ptxsDb) { - throw new Error('ptxsDb required when instantiating ProfileQuery adapter.') - } this.profilesDb = profilesDb - this.ptxsDb = ptxsDb this.scanProfilesWithBlockHeight = this.scanProfilesWithBlockHeight.bind(this) } - async getBlockHeightForTxid (txid) { - if (!txid) return 0 - try { - const ptx = await this.ptxsDb.get(txid) - const height = ptx && ptx.blockHeight - return typeof height === 'number' ? height : parseInt(height, 10) || 0 - } catch (err) { - return 0 - } - } - async scanProfilesWithBlockHeight () { const profiles = [] for await (const [addr, profile] of this.profilesDb.iterator()) { - const blockHeight = await this.getBlockHeightForTxid(profile.txid) profiles.push({ addr, text: profile.text, txid: profile.txid, seen: profile.seen, - blockHeight + blockHeight: profile.blockHeight ?? 0 }) } diff --git a/test/unit/adapters/post-query.unit.js b/test/unit/adapters/post-query.unit.js index 3a4992e..7fade6d 100644 --- a/test/unit/adapters/post-query.unit.js +++ b/test/unit/adapters/post-query.unit.js @@ -6,29 +6,23 @@ describe('#PostQuery', () => { let uut let sandbox let postsDb - let ptxsDb beforeEach(() => { sandbox = sinon.createSandbox() postsDb = { iterator: sandbox.stub() } - ptxsDb = { - get: sandbox.stub() - } - uut = new PostQuery({ postsDb, ptxsDb }) + uut = new PostQuery({ postsDb }) }) afterEach(() => sandbox.restore()) - it('should scan posts and attach block height from ptx', async () => { + it('should scan posts and read block height from stored document', async () => { async function * mockIterator () { - yield ['tx1', { addr: 'addr1', text: 'hello', seen: 1000 }] - yield ['tx2', { addr: 'addr2', text: 'world', seen: 2000 }] + yield ['tx1', { addr: 'addr1', text: 'hello', seen: 1000, blockHeight: 600100 }] + yield ['tx2', { addr: 'addr2', text: 'world', seen: 2000, blockHeight: 600200 }] } postsDb.iterator.returns(mockIterator()) - ptxsDb.get.withArgs('tx1').resolves({ blockHeight: 600100 }) - ptxsDb.get.withArgs('tx2').resolves({ blockHeight: 600200 }) const result = await uut.scanPostsWithBlockHeight() @@ -39,12 +33,11 @@ describe('#PostQuery', () => { assert.equal(result[1].blockHeight, 600200) }) - it('should use block height 0 when ptx is missing', async () => { + it('should use block height 0 when field is missing', async () => { async function * mockIterator () { yield ['tx-missing', { addr: 'addr1', text: 'hi', seen: 1000 }] } postsDb.iterator.returns(mockIterator()) - ptxsDb.get.rejects(new Error('not found')) const result = await uut.scanPostsWithBlockHeight() diff --git a/test/unit/adapters/profile-query.unit.js b/test/unit/adapters/profile-query.unit.js index 22c3c6f..121e8ee 100644 --- a/test/unit/adapters/profile-query.unit.js +++ b/test/unit/adapters/profile-query.unit.js @@ -6,29 +6,23 @@ describe('#ProfileQuery', () => { let uut let sandbox let profilesDb - let ptxsDb beforeEach(() => { sandbox = sinon.createSandbox() profilesDb = { iterator: sandbox.stub() } - ptxsDb = { - get: sandbox.stub() - } - uut = new ProfileQuery({ profilesDb, ptxsDb }) + uut = new ProfileQuery({ profilesDb }) }) afterEach(() => sandbox.restore()) - it('should scan profiles and attach block height from ptx', async () => { + it('should scan profiles and read block height from stored document', async () => { async function * mockIterator () { - yield ['addr1', { text: 'hi', txid: 'tx1', seen: 1000 }] - yield ['addr2', { text: 'bye', txid: 'tx2', seen: 2000 }] + yield ['addr1', { text: 'hi', txid: 'tx1', seen: 1000, blockHeight: 600100 }] + yield ['addr2', { text: 'bye', txid: 'tx2', seen: 2000, blockHeight: 600200 }] } profilesDb.iterator.returns(mockIterator()) - ptxsDb.get.withArgs('tx1').resolves({ blockHeight: 600100 }) - ptxsDb.get.withArgs('tx2').resolves({ blockHeight: 600200 }) const result = await uut.scanProfilesWithBlockHeight() @@ -37,12 +31,11 @@ describe('#ProfileQuery', () => { assert.equal(result[1].blockHeight, 600200) }) - it('should use block height 0 when ptx is missing', async () => { + it('should use block height 0 when field is missing', async () => { async function * mockIterator () { - yield ['addr1', { text: 'hi', txid: 'tx-missing', seen: 1000 }] + yield ['addr1', { text: 'hi', txid: 'tx1', seen: 1000 }] } profilesDb.iterator.returns(mockIterator()) - ptxsDb.get.rejects(new Error('not found')) const result = await uut.scanProfilesWithBlockHeight()