@arkiv-network/sdk
Version:
TypeScript client library for Arkiv's blockchains interactions
96 lines (82 loc) • 3.73 kB
text/typescript
import { describe, expect, it, vi } from "bun:test"
import type { ArkivClient } from "../../clients/baseClient"
import { asc, desc } from "../../query/order"
import { i32, str } from "../../schema"
import type { RpcEntity } from "../../types/rpcSchema"
import { query } from "./query"
const KEY = `0x${"ab".repeat(32)}` as const
/** A client whose `arkiv_query` serves one page holding `data`. */
function makeClient(data: RpcEntity[]) {
const request = vi.fn(async () => ({ data, blockNumber: "0x1" }))
return { client: { request } as unknown as ArkivClient, request }
}
/** The query string the first `arkiv_query` call sent. */
function sentQuery(request: ReturnType<typeof makeClient>["request"]) {
const [[call]] = request.mock.calls as unknown as [[{ params: [string] }]]
return call.params[0]
}
/** The RPC `select` object the first `arkiv_query` call sent. */
function sentSelect(request: ReturnType<typeof makeClient>["request"]) {
const [[call]] = request.mock.calls as unknown as [[{ params: [string, { select: unknown }] }]]
return call.params[1].select
}
describe("query", () => {
const entity: RpcEntity = {
key: KEY,
attributes: [
{ name: "name", type: "str", value: "build" },
{ name: "runs", type: "i32", value: 3 },
],
}
it("returns the same flat rows select() does, attributes by name", async () => {
const { client, request } = makeClient([entity])
const page = await query(client, "type = str('execution')", {
select: { $key: true, name: true, technology: true },
})
expect(sentSelect(request)).toMatchObject({
key: true,
attributes: { name: true, technology: true },
})
expect(page.entities).toEqual([{ $key: KEY, name: str("build"), technology: undefined }])
expect(page.blockNumber).toBe(1n)
})
it("reads every field and the attributes map when nothing is selected", async () => {
const { client } = makeClient([entity])
const page = await query(client, "type = str('execution')")
expect(page.entities[0]?.$key).toBe(KEY)
expect(page.entities[0]?.$attributes).toEqual({ name: str("build"), runs: i32(3) })
})
it("rejects a selection that asks for nothing before sending it", async () => {
const { client, request } = makeClient([])
await expect(query(client, "a = i32(1)", { select: { $key: false } })).rejects.toThrow(
/at least one field/,
)
expect(request).not.toHaveBeenCalled()
})
it("sends orderBy as the query's ORDER BY clause", async () => {
const { client, request } = makeClient([])
await query(client, "a = i32(1)", { orderBy: desc("score", "dec") })
expect(sentQuery(request)).toBe("a = i32(1) ORDER BY score:dec DESC")
})
it("sorts a system attribute by its fixed type", async () => {
const { client, request } = makeClient([])
await query(client, "a = i32(1)", { orderBy: asc("$expiresAt") })
expect(sentQuery(request)).toBe("a = i32(1) ORDER BY $expiresAt:u64 ASC")
})
it("needs a type for a user attribute, at compile time and before sending", async () => {
const { client, request } = makeClient([])
// @ts-expect-error - there is no schema to take score's type from
await expect(query(client, "a = i32(1)", { orderBy: desc("score") })).rejects.toThrow(
/needs its type/,
)
expect(request).not.toHaveBeenCalled()
})
it("checks a key built by hand before sending", async () => {
const { client, request } = makeClient([])
const key = { kind: "order", name: "score", type: "dec", direction: "up" }
await expect(query(client, "a = i32(1)", { orderBy: key as never })).rejects.toThrow(
/"asc" or "desc"/,
)
expect(request).not.toHaveBeenCalled()
})
})