@arkiv-network/sdk 0.1.1-dev.0 → 0.1.3-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -10
- package/dist/chains/index.d.ts +25 -25
- package/dist/chains/index.d.ts.map +1 -1
- package/dist/index.cjs +30 -9
- package/dist/index.js +30 -16
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +22 -8
- package/src/accounts/index.ts +1 -0
- package/src/actions/public/buildQuery.ts +6 -0
- package/src/actions/public/getBlockTiming.ts +20 -0
- package/src/actions/public/getEntity.ts +18 -0
- package/src/actions/public/getEntityCount.ts +10 -0
- package/src/actions/public/query.ts +13 -0
- package/src/actions/public/subscribeEntityEvents.ts +105 -0
- package/src/actions/wallet/changeOwnership.ts +40 -0
- package/src/actions/wallet/createEntity.ts +45 -0
- package/src/actions/wallet/deleteEntity.ts +39 -0
- package/src/actions/wallet/extendEntity.ts +41 -0
- package/src/actions/wallet/mutateEntities.ts +100 -0
- package/src/actions/wallet/updateEntity.ts +47 -0
- package/src/chains/index.ts +3 -0
- package/src/chains/kaolin.ts +26 -0
- package/src/chains/localhost.ts +14 -0
- package/src/chains/marketplace.ts +26 -0
- package/src/clients/baseClient.ts +9 -0
- package/src/clients/createPublicClient.test.ts +22 -0
- package/src/clients/createPublicClient.ts +65 -0
- package/src/clients/createWalletClient.test.ts +23 -0
- package/src/clients/createWalletClient.ts +70 -0
- package/src/clients/decorators/arkivPublic.ts +203 -0
- package/src/clients/decorators/arkivWallet.ts +250 -0
- package/src/consts.ts +2 -0
- package/src/index.ts +21 -0
- package/src/query/engine.test.ts +288 -0
- package/src/query/engine.ts +112 -0
- package/src/query/errors.ts +23 -0
- package/src/query/index.ts +4 -0
- package/src/query/predicate.test.ts +418 -0
- package/src/query/predicate.ts +140 -0
- package/src/query/queryBuilder.test.ts +537 -0
- package/src/query/queryBuilder.ts +209 -0
- package/src/query/queryResult.test.ts +270 -0
- package/src/query/queryResult.ts +61 -0
- package/src/types/attributes.ts +4 -0
- package/src/types/entity.ts +36 -0
- package/src/types/events.ts +34 -0
- package/src/types/index.ts +4 -0
- package/src/types/mimeTypes.ts +27 -0
- package/src/types/rpcSchema.ts +61 -0
- package/src/types/txParams.ts +15 -0
- package/src/utils/arkivTransactions.ts +100 -0
- package/src/utils/compression.test.ts +32 -0
- package/src/utils/compression.ts +99 -0
- package/src/utils/entities.ts +23 -0
- package/src/utils/expirationTime.ts +13 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/payload.ts +9 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, jest, test } from "bun:test"
|
|
2
|
+
import type { ArkivClient } from "../clients/baseClient"
|
|
3
|
+
import { Entity } from "../types/entity"
|
|
4
|
+
import * as entitiesUtils from "../utils/entities"
|
|
5
|
+
import * as engine from "./engine"
|
|
6
|
+
import { and, eq, gt, gte, neq, or } from "./predicate"
|
|
7
|
+
import { QueryBuilder } from "./queryBuilder"
|
|
8
|
+
|
|
9
|
+
describe("QueryBuilder", () => {
|
|
10
|
+
let mockClient: ArkivClient
|
|
11
|
+
let mockProcessQuery: any
|
|
12
|
+
let mockEntityFromRpcResult: any
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
// Create a mock client
|
|
16
|
+
mockClient = {
|
|
17
|
+
request: jest.fn(),
|
|
18
|
+
} as unknown as ArkivClient
|
|
19
|
+
|
|
20
|
+
// Spy on the functions instead of mocking the module
|
|
21
|
+
mockProcessQuery = jest.spyOn(engine, "processQuery")
|
|
22
|
+
mockEntityFromRpcResult = jest.spyOn(entitiesUtils, "entityFromRpcResult")
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
// Restore all spies to prevent test interference
|
|
27
|
+
jest.restoreAllMocks()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test("creates QueryBuilder with empty predicates", () => {
|
|
31
|
+
const builder = new QueryBuilder(mockClient)
|
|
32
|
+
expect(builder).toBeDefined()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe("where() method", () => {
|
|
36
|
+
test("adds single predicate", async () => {
|
|
37
|
+
mockProcessQuery.mockResolvedValue({
|
|
38
|
+
data: [],
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const builder = new QueryBuilder(mockClient)
|
|
42
|
+
await builder.where(eq("name", "test")).fetch()
|
|
43
|
+
|
|
44
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
45
|
+
predicates: [eq("name", "test")],
|
|
46
|
+
limit: undefined,
|
|
47
|
+
offset: undefined,
|
|
48
|
+
ownedBy: undefined,
|
|
49
|
+
validBeforeBlock: undefined,
|
|
50
|
+
withAttributes: undefined,
|
|
51
|
+
withMetadata: undefined,
|
|
52
|
+
withPayload: undefined,
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test("adds multiple predicates as array", async () => {
|
|
57
|
+
mockProcessQuery.mockResolvedValue({
|
|
58
|
+
data: [],
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const builder = new QueryBuilder(mockClient)
|
|
62
|
+
const predicates = [eq("name", "test"), gt("age", 18)]
|
|
63
|
+
await builder.where(predicates).fetch()
|
|
64
|
+
|
|
65
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
66
|
+
predicates: predicates,
|
|
67
|
+
limit: undefined,
|
|
68
|
+
offset: undefined,
|
|
69
|
+
ownedBy: undefined,
|
|
70
|
+
validBeforeBlock: undefined,
|
|
71
|
+
withAttributes: undefined,
|
|
72
|
+
withMetadata: undefined,
|
|
73
|
+
withPayload: undefined,
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test("chains multiple where() calls", async () => {
|
|
78
|
+
mockProcessQuery.mockResolvedValue({
|
|
79
|
+
data: [],
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const builder = new QueryBuilder(mockClient)
|
|
83
|
+
await builder
|
|
84
|
+
.where(eq("name", "test"))
|
|
85
|
+
.where(gt("age", 18))
|
|
86
|
+
.where([neq("status", "inactive"), eq("verified", 1)])
|
|
87
|
+
.fetch()
|
|
88
|
+
|
|
89
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
90
|
+
predicates: [
|
|
91
|
+
eq("name", "test"),
|
|
92
|
+
gt("age", 18),
|
|
93
|
+
neq("status", "inactive"),
|
|
94
|
+
eq("verified", 1),
|
|
95
|
+
],
|
|
96
|
+
limit: undefined,
|
|
97
|
+
offset: undefined,
|
|
98
|
+
ownedBy: undefined,
|
|
99
|
+
validBeforeBlock: undefined,
|
|
100
|
+
withAttributes: undefined,
|
|
101
|
+
withMetadata: undefined,
|
|
102
|
+
withPayload: undefined,
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test("handles complex predicates with or/and", async () => {
|
|
107
|
+
mockProcessQuery.mockResolvedValue({
|
|
108
|
+
data: [],
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const builder = new QueryBuilder(mockClient)
|
|
112
|
+
const complexPredicate = or([eq("type", "admin"), eq("type", "moderator")])
|
|
113
|
+
await builder.where(complexPredicate).fetch()
|
|
114
|
+
|
|
115
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
116
|
+
predicates: [complexPredicate],
|
|
117
|
+
limit: undefined,
|
|
118
|
+
offset: undefined,
|
|
119
|
+
ownedBy: undefined,
|
|
120
|
+
validBeforeBlock: undefined,
|
|
121
|
+
withAttributes: undefined,
|
|
122
|
+
withMetadata: undefined,
|
|
123
|
+
withPayload: undefined,
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test("handles nested or/and predicates", async () => {
|
|
128
|
+
mockProcessQuery.mockResolvedValue({
|
|
129
|
+
data: [],
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
const builder = new QueryBuilder(mockClient)
|
|
133
|
+
const nestedPredicate = and([
|
|
134
|
+
eq("active", 1),
|
|
135
|
+
or([eq("role", "admin"), eq("role", "moderator")]),
|
|
136
|
+
])
|
|
137
|
+
await builder.where(nestedPredicate).fetch()
|
|
138
|
+
|
|
139
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
140
|
+
predicates: [nestedPredicate],
|
|
141
|
+
limit: undefined,
|
|
142
|
+
offset: undefined,
|
|
143
|
+
ownedBy: undefined,
|
|
144
|
+
validBeforeBlock: undefined,
|
|
145
|
+
withAttributes: undefined,
|
|
146
|
+
withMetadata: undefined,
|
|
147
|
+
withPayload: undefined,
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe("builder methods chain correctly", () => {
|
|
153
|
+
test("ownedBy() sets owner", async () => {
|
|
154
|
+
mockProcessQuery.mockResolvedValue({
|
|
155
|
+
data: [],
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const builder = new QueryBuilder(mockClient)
|
|
159
|
+
const owner = "0x1234567890123456789012345678901234567890" as const
|
|
160
|
+
await builder.ownedBy(owner).fetch()
|
|
161
|
+
|
|
162
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
163
|
+
predicates: [],
|
|
164
|
+
limit: undefined,
|
|
165
|
+
offset: undefined,
|
|
166
|
+
ownedBy: owner,
|
|
167
|
+
validBeforeBlock: undefined,
|
|
168
|
+
withAttributes: undefined,
|
|
169
|
+
withMetadata: undefined,
|
|
170
|
+
withPayload: undefined,
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test("limit() sets limit", async () => {
|
|
175
|
+
mockProcessQuery.mockResolvedValue({
|
|
176
|
+
data: [],
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const builder = new QueryBuilder(mockClient)
|
|
180
|
+
await builder.limit(10).fetch()
|
|
181
|
+
|
|
182
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
183
|
+
predicates: [],
|
|
184
|
+
limit: 10,
|
|
185
|
+
offset: undefined,
|
|
186
|
+
ownedBy: undefined,
|
|
187
|
+
validBeforeBlock: undefined,
|
|
188
|
+
withAttributes: undefined,
|
|
189
|
+
withMetadata: undefined,
|
|
190
|
+
withPayload: undefined,
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
test("cursor() sets cursor", async () => {
|
|
195
|
+
mockProcessQuery.mockResolvedValue({
|
|
196
|
+
data: [],
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
const builder = new QueryBuilder(mockClient)
|
|
200
|
+
await builder.cursor("0xABC123").fetch()
|
|
201
|
+
|
|
202
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
203
|
+
predicates: [],
|
|
204
|
+
limit: undefined,
|
|
205
|
+
cursor: "0xABC123",
|
|
206
|
+
ownedBy: undefined,
|
|
207
|
+
validAtBlock: undefined,
|
|
208
|
+
withAttributes: undefined,
|
|
209
|
+
withMetadata: undefined,
|
|
210
|
+
withPayload: undefined,
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
test("withAttributes() sets withAttributes to true by default", async () => {
|
|
215
|
+
mockProcessQuery.mockResolvedValue({
|
|
216
|
+
data: [],
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
const builder = new QueryBuilder(mockClient)
|
|
220
|
+
await builder.withAttributes().fetch()
|
|
221
|
+
|
|
222
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
223
|
+
predicates: [],
|
|
224
|
+
limit: undefined,
|
|
225
|
+
offset: undefined,
|
|
226
|
+
ownedBy: undefined,
|
|
227
|
+
validBeforeBlock: undefined,
|
|
228
|
+
withAttributes: true,
|
|
229
|
+
withMetadata: undefined,
|
|
230
|
+
withPayload: undefined,
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
test("withAttributes(false) sets withAttributes to false", async () => {
|
|
235
|
+
mockProcessQuery.mockResolvedValue({
|
|
236
|
+
data: [],
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
const builder = new QueryBuilder(mockClient)
|
|
240
|
+
await builder.withAttributes(false).fetch()
|
|
241
|
+
|
|
242
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
243
|
+
predicates: [],
|
|
244
|
+
limit: undefined,
|
|
245
|
+
cursor: undefined,
|
|
246
|
+
ownedBy: undefined,
|
|
247
|
+
validBeforeBlock: undefined,
|
|
248
|
+
withAttributes: false,
|
|
249
|
+
withMetadata: undefined,
|
|
250
|
+
withPayload: undefined,
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test("withMetadata() sets withMetadata to true by default", async () => {
|
|
255
|
+
mockProcessQuery.mockResolvedValue({
|
|
256
|
+
data: [],
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
const builder = new QueryBuilder(mockClient)
|
|
260
|
+
await builder.withMetadata().fetch()
|
|
261
|
+
|
|
262
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
263
|
+
predicates: [],
|
|
264
|
+
limit: undefined,
|
|
265
|
+
cursor: undefined,
|
|
266
|
+
ownedBy: undefined,
|
|
267
|
+
validAtBlock: undefined,
|
|
268
|
+
withAttributes: undefined,
|
|
269
|
+
withMetadata: true,
|
|
270
|
+
withPayload: undefined,
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
test("withMetadata(false) sets withMetadata to false", async () => {
|
|
275
|
+
mockProcessQuery.mockResolvedValue({
|
|
276
|
+
data: [],
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
const builder = new QueryBuilder(mockClient)
|
|
280
|
+
await builder.withMetadata(false).fetch()
|
|
281
|
+
|
|
282
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
283
|
+
predicates: [],
|
|
284
|
+
limit: undefined,
|
|
285
|
+
cursor: undefined,
|
|
286
|
+
ownedBy: undefined,
|
|
287
|
+
validAtBlock: undefined,
|
|
288
|
+
withAttributes: undefined,
|
|
289
|
+
withMetadata: false,
|
|
290
|
+
withPayload: undefined,
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
test("withPayload() sets withPayload to true by default", async () => {
|
|
295
|
+
mockProcessQuery.mockResolvedValue({
|
|
296
|
+
data: [],
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
const builder = new QueryBuilder(mockClient)
|
|
300
|
+
await builder.withPayload().fetch()
|
|
301
|
+
|
|
302
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
303
|
+
predicates: [],
|
|
304
|
+
limit: undefined,
|
|
305
|
+
cursor: undefined,
|
|
306
|
+
ownedBy: undefined,
|
|
307
|
+
validAtBlock: undefined,
|
|
308
|
+
withAttributes: undefined,
|
|
309
|
+
withMetadata: undefined,
|
|
310
|
+
withPayload: true,
|
|
311
|
+
})
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
test("withPayload(false) sets withPayload to false", async () => {
|
|
315
|
+
mockProcessQuery.mockResolvedValue({
|
|
316
|
+
data: [],
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
const builder = new QueryBuilder(mockClient)
|
|
320
|
+
await builder.withPayload(false).fetch()
|
|
321
|
+
|
|
322
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
323
|
+
predicates: [],
|
|
324
|
+
limit: undefined,
|
|
325
|
+
cursor: undefined,
|
|
326
|
+
ownedBy: undefined,
|
|
327
|
+
validAtBlock: undefined,
|
|
328
|
+
withAttributes: undefined,
|
|
329
|
+
withMetadata: undefined,
|
|
330
|
+
withPayload: false,
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
test("all methods chain together correctly", async () => {
|
|
335
|
+
mockProcessQuery.mockResolvedValue({
|
|
336
|
+
data: [],
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
const builder = new QueryBuilder(mockClient)
|
|
340
|
+
const owner = "0x1234567890123456789012345678901234567890" as const
|
|
341
|
+
await builder
|
|
342
|
+
.where(eq("name", "test"))
|
|
343
|
+
.where(gte("age", 18))
|
|
344
|
+
.ownedBy(owner)
|
|
345
|
+
.limit(10)
|
|
346
|
+
.cursor("0xABC123")
|
|
347
|
+
.withAttributes(true)
|
|
348
|
+
.withMetadata(true)
|
|
349
|
+
.withPayload(true)
|
|
350
|
+
.fetch()
|
|
351
|
+
|
|
352
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
353
|
+
predicates: [eq("name", "test"), gte("age", 18)],
|
|
354
|
+
limit: 10,
|
|
355
|
+
cursor: "0xABC123",
|
|
356
|
+
ownedBy: owner,
|
|
357
|
+
validAtBlock: undefined,
|
|
358
|
+
withAttributes: true,
|
|
359
|
+
withMetadata: true,
|
|
360
|
+
withPayload: true,
|
|
361
|
+
})
|
|
362
|
+
})
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
describe("fetch() method", () => {
|
|
366
|
+
test("calls processQuery and entityFromRpcResult", async () => {
|
|
367
|
+
const mockQueryResult = {
|
|
368
|
+
data: [
|
|
369
|
+
{ key: "0xabc" as const, value: "encodedData1" },
|
|
370
|
+
{ key: "0xdef" as const, value: "encodedData2" },
|
|
371
|
+
],
|
|
372
|
+
}
|
|
373
|
+
const mockEntity1 = new Entity(
|
|
374
|
+
"0xabc" as const,
|
|
375
|
+
"application/json" as const,
|
|
376
|
+
"0x123" as const,
|
|
377
|
+
1000n,
|
|
378
|
+
new Uint8Array(),
|
|
379
|
+
[],
|
|
380
|
+
)
|
|
381
|
+
const mockEntity2 = new Entity(
|
|
382
|
+
"0xdef" as const,
|
|
383
|
+
"application/json" as const,
|
|
384
|
+
"0x456" as const,
|
|
385
|
+
2000n,
|
|
386
|
+
new Uint8Array(),
|
|
387
|
+
[],
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
mockProcessQuery.mockResolvedValue(mockQueryResult)
|
|
391
|
+
mockEntityFromRpcResult.mockResolvedValueOnce(mockEntity1).mockResolvedValueOnce(mockEntity2)
|
|
392
|
+
|
|
393
|
+
const builder = new QueryBuilder(mockClient)
|
|
394
|
+
const result = await builder.where(eq("name", "test")).fetch()
|
|
395
|
+
|
|
396
|
+
expect(mockProcessQuery).toHaveBeenCalled()
|
|
397
|
+
expect(mockEntityFromRpcResult).toHaveBeenCalled()
|
|
398
|
+
expect(mockEntityFromRpcResult).toHaveBeenCalledWith({ key: "0xabc", value: "encodedData1" })
|
|
399
|
+
expect(mockEntityFromRpcResult).toHaveBeenCalledWith({ key: "0xdef", value: "encodedData2" })
|
|
400
|
+
expect(result.entities).toHaveLength(2)
|
|
401
|
+
expect(result.entities[0]).toBe(mockEntity1)
|
|
402
|
+
expect(result.entities[1]).toBe(mockEntity2)
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
test("returns QueryResult with correct properties", async () => {
|
|
406
|
+
mockProcessQuery.mockResolvedValue({
|
|
407
|
+
data: [],
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
const builder = new QueryBuilder(mockClient)
|
|
411
|
+
const result = await builder.limit(10).cursor("0xABC123").fetch()
|
|
412
|
+
|
|
413
|
+
expect(result).toBeDefined()
|
|
414
|
+
expect(result.entities).toEqual([])
|
|
415
|
+
})
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
describe("count() method", () => {
|
|
419
|
+
test("calls processQuery and returns count", async () => {
|
|
420
|
+
const mockQueryResult = {
|
|
421
|
+
data: [
|
|
422
|
+
{ key: "0xabc", value: "data1" },
|
|
423
|
+
{ key: "0xdef", value: "data2" },
|
|
424
|
+
{ key: "0xghi", value: "data3" },
|
|
425
|
+
],
|
|
426
|
+
}
|
|
427
|
+
mockProcessQuery.mockResolvedValue(mockQueryResult)
|
|
428
|
+
|
|
429
|
+
const builder = new QueryBuilder(mockClient)
|
|
430
|
+
const count = await builder.where(eq("status", "active")).count()
|
|
431
|
+
|
|
432
|
+
expect(mockProcessQuery).toHaveBeenCalled()
|
|
433
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
434
|
+
predicates: [eq("status", "active")],
|
|
435
|
+
limit: undefined,
|
|
436
|
+
cursor: undefined,
|
|
437
|
+
ownedBy: undefined,
|
|
438
|
+
validAtBlock: undefined,
|
|
439
|
+
withAttributes: false,
|
|
440
|
+
withMetadata: false,
|
|
441
|
+
withPayload: false,
|
|
442
|
+
})
|
|
443
|
+
expect(count as number).toEqual(3 as number)
|
|
444
|
+
// Verify entityFromRpcResult is NOT called for count()
|
|
445
|
+
expect(mockEntityFromRpcResult).not.toHaveBeenCalled()
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
test("returns 0 for empty results", async () => {
|
|
449
|
+
mockProcessQuery.mockResolvedValue({
|
|
450
|
+
data: [],
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
const builder = new QueryBuilder(mockClient)
|
|
454
|
+
const count = await builder.count()
|
|
455
|
+
|
|
456
|
+
expect(count as number).toEqual(0 as number)
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
test("count() uses all builder parameters", async () => {
|
|
460
|
+
mockProcessQuery.mockResolvedValue({
|
|
461
|
+
data: [],
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
const builder = new QueryBuilder(mockClient)
|
|
465
|
+
const owner = "0x1234567890123456789012345678901234567890" as const
|
|
466
|
+
await builder
|
|
467
|
+
.where([eq("active", 1), gte("score", 100)])
|
|
468
|
+
.ownedBy(owner)
|
|
469
|
+
.limit(50)
|
|
470
|
+
.cursor("0xABC123")
|
|
471
|
+
.validAtBlock(123n)
|
|
472
|
+
.count()
|
|
473
|
+
|
|
474
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(mockClient, {
|
|
475
|
+
predicates: [eq("active", 1), gte("score", 100)],
|
|
476
|
+
limit: 50,
|
|
477
|
+
cursor: "0xABC123",
|
|
478
|
+
ownedBy: owner,
|
|
479
|
+
validAtBlock: 123n,
|
|
480
|
+
withAttributes: false,
|
|
481
|
+
withMetadata: false,
|
|
482
|
+
withPayload: false,
|
|
483
|
+
})
|
|
484
|
+
})
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
describe("predicate types", () => {
|
|
488
|
+
test("passes string values correctly", async () => {
|
|
489
|
+
mockProcessQuery.mockResolvedValue({
|
|
490
|
+
data: [],
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
const builder = new QueryBuilder(mockClient)
|
|
494
|
+
await builder.where(eq("name", "john")).fetch()
|
|
495
|
+
|
|
496
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(
|
|
497
|
+
mockClient,
|
|
498
|
+
expect.objectContaining({
|
|
499
|
+
predicates: [eq("name", "john")],
|
|
500
|
+
}),
|
|
501
|
+
)
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
test("passes numeric values correctly", async () => {
|
|
505
|
+
mockProcessQuery.mockResolvedValue({
|
|
506
|
+
data: [],
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
const builder = new QueryBuilder(mockClient)
|
|
510
|
+
await builder.where(gt("age", 25)).fetch()
|
|
511
|
+
|
|
512
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(
|
|
513
|
+
mockClient,
|
|
514
|
+
expect.objectContaining({
|
|
515
|
+
predicates: [gt("age", 25)],
|
|
516
|
+
}),
|
|
517
|
+
)
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
test("passes mixed predicates correctly", async () => {
|
|
521
|
+
mockProcessQuery.mockResolvedValue({
|
|
522
|
+
data: [],
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
const builder = new QueryBuilder(mockClient)
|
|
526
|
+
const predicates = [eq("name", "john"), gt("age", 25), neq("status", "inactive")]
|
|
527
|
+
await builder.where(predicates).fetch()
|
|
528
|
+
|
|
529
|
+
expect(mockProcessQuery).toHaveBeenCalledWith(
|
|
530
|
+
mockClient,
|
|
531
|
+
expect.objectContaining({
|
|
532
|
+
predicates: predicates,
|
|
533
|
+
}),
|
|
534
|
+
)
|
|
535
|
+
})
|
|
536
|
+
})
|
|
537
|
+
})
|