Skip to content

Commit

Permalink
feat: order index by ordinal, height, rarity
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelcr committed Feb 23, 2023
1 parent 41f9207 commit aba47af
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 3 deletions.
4 changes: 2 additions & 2 deletions migrations/1676395230930_inscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ export function up(pgm: MigrationBuilder): void {
'UNIQUE(inscription_id)'
);
pgm.createIndex('inscriptions', ['sat_ordinal']);
pgm.createIndex('inscriptions', [{ name: 'block_height', sort: 'DESC' }]);
pgm.createIndex('inscriptions', ['sat_rarity']);
pgm.createIndex('inscriptions', ['block_height']);
pgm.createIndex('inscriptions', ['block_hash']);
pgm.createIndex('inscriptions', ['address']);
pgm.createIndex('inscriptions', ['mime_type']);
pgm.createIndex('inscriptions', ['sat_rarity']);
}
6 changes: 6 additions & 0 deletions src/api/routes/inscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
BlockHashParam,
MimeTypeParam,
SatoshiRarityParam,
InscriptionsOrderByParam,
OrderParam,
} from '../types';
import {
DEFAULT_API_LIMIT,
Expand Down Expand Up @@ -47,6 +49,8 @@ export const InscriptionRoutes: FastifyPluginCallback<
rarity: Type.Optional(SatoshiRarityParam),
offset: Type.Optional(OffsetParam),
limit: Type.Optional(LimitParam),
order_by: Type.Optional(InscriptionsOrderByParam),
order: Type.Optional(OrderParam),
}),
response: {
200: PaginatedResponse(InscriptionResponse),
Expand All @@ -69,6 +73,8 @@ export const InscriptionRoutes: FastifyPluginCallback<
sat_rarity: request.query.rarity,
limit,
offset,
order_by: request.query.order_by ?? 'block_height',
order: request.query.order ?? 'desc',
});
await reply.send({
limit,
Expand Down
8 changes: 8 additions & 0 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export const OffsetParam = Type.Integer({ minimum: 0 });

export const LimitParam = Type.Integer({ minimum: 1, maximum: 20 });

export const InscriptionsOrderByParam = Type.Enum({
block_height: 'block_height',
ordinal: 'ordinal',
rarity: 'rarity',
});

export const OrderParam = Type.Enum({ asc: 'asc', desc: 'desc' });

export const PaginatedResponse = <T extends TSchema>(type: T) =>
Type.Object({
limit: Type.Integer(),
Expand Down
13 changes: 12 additions & 1 deletion src/pg/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,20 @@ export class PgStore extends BasePgStore {
address?: string;
mime_type?: string[];
sat_rarity?: string;
order_by: string;
order: string;
limit: number;
offset: number;
}): Promise<DbPaginatedResult<DbInscription>> {
// Sanitize ordering args because we'll use `unsafe` to concatenate them into the query.
let orderBy = 'block_height';
if (args.order_by === 'ordinal') orderBy = 'sat_ordinal';
if (args.order_by === 'rarity') {
orderBy =
"ARRAY_POSITION(ARRAY['common','uncommon','rare','epic','legendary','mythic'], sat_rarity)";
}
const order = args.order === 'asc' ? 'ASC' : 'DESC';

const results = await this.sql<({ total: number } & DbInscription)[]>`
SELECT ${this.sql(INSCRIPTIONS_COLUMNS)}, COUNT(*) OVER() as total
FROM inscriptions
Expand All @@ -99,7 +110,7 @@ export class PgStore extends BasePgStore {
? this.sql`AND mime_type IN ${this.sql(args.mime_type)}`
: this.sql``
}
ORDER BY block_height DESC
ORDER BY ${this.sql.unsafe(orderBy)} ${this.sql.unsafe(order)}
LIMIT ${args.limit}
OFFSET ${args.offset}
`;
Expand Down
246 changes: 246 additions & 0 deletions tests/inscriptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,252 @@ describe('/inscriptions', () => {
expect(responseJson2.results[0]).toStrictEqual(result2);
});

test('index sorted by sat rarity', async () => {
await db.insertInscription({
values: {
inscription_id: 'ff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79i0',
offset: 0,
block_height: 775796,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '0xff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79',
address: 'bc1p3rfd76c37af87e23g4z6tts0zu52u6frjh92m9uq5evxy0sr7hvslly59y',
sat_ordinal: 1914287520444193,
sat_point: '0xff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79:0:0',
sat_rarity: 'uncommon',
fee: 151788,
mime_type: 'text/plain',
content_type: 'text/plain;charset=utf-8',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});
await db.insertInscription({
values: {
inscription_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0',
offset: 0,
block_height: 775617,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc',
address: 'bc1p3cyx5e2hgh53w7kpxcvm8s4kkega9gv5wfw7c4qxsvxl0u8x834qf0u2td',
sat_ordinal: 257418248345364,
sat_point: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0:0',
sat_rarity: 'epic',
fee: 151788,
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});
await db.insertInscription({
values: {
inscription_id: '9354c1484574b55d883a1e7ed8d02c8f9055558eb4901c4c1cb9c0f46e5f97f4i0',
offset: 0,
block_height: 0,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a9ff',
tx_id: '0x9354c1484574b55d883a1e7ed8d02c8f9055558eb4901c4c1cb9c0f46e5f97f4',
address: 'bc1p5jme0kgadawdf7f7jns6kl82p7gd5n2sy5jdty08fjcjt2qazxvqmfqej8',
sat_ordinal: 0,
sat_point: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0:0',
sat_rarity: 'mythic',
fee: 151788,
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});

const response1 = await fastify.inject({
method: 'GET',
url: '/inscriptions?order_by=rarity&order=asc',
});
expect(response1.statusCode).toBe(200);
const responseJson1 = response1.json();
expect(responseJson1.total).toBe(3);
expect(responseJson1.results[0].sat_rarity).toStrictEqual('uncommon');
expect(responseJson1.results[1].sat_rarity).toStrictEqual('epic');
expect(responseJson1.results[2].sat_rarity).toStrictEqual('mythic');

const response2 = await fastify.inject({
method: 'GET',
url: '/inscriptions?order_by=rarity&order=desc',
});
expect(response2.statusCode).toBe(200);
const responseJson2 = response2.json();
expect(responseJson2.total).toBe(3);
expect(responseJson2.results[0].sat_rarity).toStrictEqual('mythic');
expect(responseJson2.results[1].sat_rarity).toStrictEqual('epic');
expect(responseJson2.results[2].sat_rarity).toStrictEqual('uncommon');
});

test('index sorted by sat ordinal', async () => {
await db.insertInscription({
values: {
inscription_id: 'ff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79i0',
offset: 0,
block_height: 775796,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '0xff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79',
address: 'bc1p3rfd76c37af87e23g4z6tts0zu52u6frjh92m9uq5evxy0sr7hvslly59y',
sat_ordinal: 50000,
sat_point: '0xff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79:0:0',
sat_rarity: 'uncommon',
fee: 151788,
mime_type: 'text/plain',
content_type: 'text/plain;charset=utf-8',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});
await db.insertInscription({
values: {
inscription_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0',
offset: 0,
block_height: 775617,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc',
address: 'bc1p3cyx5e2hgh53w7kpxcvm8s4kkega9gv5wfw7c4qxsvxl0u8x834qf0u2td',
sat_ordinal: 50200,
sat_point: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0:0',
sat_rarity: 'epic',
fee: 151788,
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});
await db.insertInscription({
values: {
inscription_id: '9354c1484574b55d883a1e7ed8d02c8f9055558eb4901c4c1cb9c0f46e5f97f4i0',
offset: 0,
block_height: 0,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a9ff',
tx_id: '0x9354c1484574b55d883a1e7ed8d02c8f9055558eb4901c4c1cb9c0f46e5f97f4',
address: 'bc1p5jme0kgadawdf7f7jns6kl82p7gd5n2sy5jdty08fjcjt2qazxvqmfqej8',
sat_ordinal: 0,
sat_point: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0:0',
sat_rarity: 'mythic',
fee: 151788,
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});

const response1 = await fastify.inject({
method: 'GET',
url: '/inscriptions?order_by=ordinal&order=asc',
});
expect(response1.statusCode).toBe(200);
const responseJson1 = response1.json();
expect(responseJson1.total).toBe(3);
expect(responseJson1.results[0].sat_ordinal).toStrictEqual('0');
expect(responseJson1.results[1].sat_ordinal).toStrictEqual('50000');
expect(responseJson1.results[2].sat_ordinal).toStrictEqual('50200');

const response2 = await fastify.inject({
method: 'GET',
url: '/inscriptions?order_by=ordinal&order=desc',
});
expect(response2.statusCode).toBe(200);
const responseJson2 = response2.json();
expect(responseJson2.total).toBe(3);
expect(responseJson2.results[0].sat_ordinal).toStrictEqual('50200');
expect(responseJson2.results[1].sat_ordinal).toStrictEqual('50000');
expect(responseJson2.results[2].sat_ordinal).toStrictEqual('0');
});

test('index sorted by block height', async () => {
await db.insertInscription({
values: {
inscription_id: 'ff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79i0',
offset: 0,
block_height: 775796,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '0xff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79',
address: 'bc1p3rfd76c37af87e23g4z6tts0zu52u6frjh92m9uq5evxy0sr7hvslly59y',
sat_ordinal: 50000,
sat_point: '0xff4503ab9048d6d0ff4e23def81b614d5270d341ce993992e93902ceb0d4ed79:0:0',
sat_rarity: 'uncommon',
fee: 151788,
mime_type: 'text/plain',
content_type: 'text/plain;charset=utf-8',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});
await db.insertInscription({
values: {
inscription_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0',
offset: 0,
block_height: 775617,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc',
address: 'bc1p3cyx5e2hgh53w7kpxcvm8s4kkega9gv5wfw7c4qxsvxl0u8x834qf0u2td',
sat_ordinal: 50200,
sat_point: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0:0',
sat_rarity: 'epic',
fee: 151788,
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});
await db.insertInscription({
values: {
inscription_id: '9354c1484574b55d883a1e7ed8d02c8f9055558eb4901c4c1cb9c0f46e5f97f4i0',
offset: 0,
block_height: 0,
block_hash: '0x00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a9ff',
tx_id: '0x9354c1484574b55d883a1e7ed8d02c8f9055558eb4901c4c1cb9c0f46e5f97f4',
address: 'bc1p5jme0kgadawdf7f7jns6kl82p7gd5n2sy5jdty08fjcjt2qazxvqmfqej8',
sat_ordinal: 0,
sat_point: '0x38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0:0',
sat_rarity: 'mythic',
fee: 151788,
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
content: '0x48656C6C6F',
timestamp: 1676913207,
},
});

const response1 = await fastify.inject({
method: 'GET',
url: '/inscriptions?order_by=block_height&order=asc',
});
expect(response1.statusCode).toBe(200);
const responseJson1 = response1.json();
expect(responseJson1.total).toBe(3);
expect(responseJson1.results[0].block_height).toStrictEqual(0);
expect(responseJson1.results[1].block_height).toStrictEqual(775617);
expect(responseJson1.results[2].block_height).toStrictEqual(775796);

const response2 = await fastify.inject({
method: 'GET',
url: '/inscriptions?order_by=block_height&order=desc',
});
expect(response2.statusCode).toBe(200);
const responseJson2 = response2.json();
expect(responseJson2.total).toBe(3);
expect(responseJson2.results[0].block_height).toStrictEqual(775796);
expect(responseJson2.results[1].block_height).toStrictEqual(775617);
expect(responseJson2.results[2].block_height).toStrictEqual(0);
});

test('returns not found for invalid inscriptions', async () => {
const response = await fastify.inject({
method: 'GET',
Expand Down

0 comments on commit aba47af

Please sign in to comment.