Adding block height to all db models

This commit is contained in:
Chris Troutner
2026-06-03 12:07:53 -07:00
parent 638207a8e1
commit d885ffcd26
6 changed files with 30 additions and 68 deletions
+11 -1
View File
@@ -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 txs `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
+2 -4
View File
@@ -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
}
+3 -19
View File
@@ -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
})
}
+3 -19
View File
@@ -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
})
}
+5 -12
View File
@@ -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()
+6 -13
View File
@@ -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()