11import { beforeEach , describe , expect , it , vi } from "vitest" ;
22
33import {
4+ buildEnsIndexerStackInfo ,
5+ buildIndexingMetadataContextInitialized ,
6+ buildIndexingMetadataContextUninitialized ,
47 deserializeCrossChainIndexingStatusSnapshot ,
5- serializeEnsIndexerPublicConfig ,
8+ deserializeIndexingMetadataContext ,
9+ type EnsDbPublicConfig ,
10+ serializeIndexingMetadataContext ,
611} from "@ensnode/ensnode-sdk" ;
712
813import * as ensDbClientMock from "./ensdb-client.mock" ;
914import { EnsDbReader } from "./ensdb-reader" ;
1015
16+ const executeMock = vi . fn ( ) ;
1117const whereMock = vi . fn ( async ( ) => [ ] as Array < { value : unknown } > ) ;
1218const fromMock = vi . fn ( ( ) => ( { where : whereMock } ) ) ;
1319const selectMock = vi . fn ( ( ) => ( { from : fromMock } ) ) ;
14- const drizzleClientMock = { select : selectMock } as any ;
20+ const drizzleClientMock = { select : selectMock , execute : executeMock } as any ;
1521
1622vi . mock ( "drizzle-orm/node-postgres" , ( ) => ( {
1723 drizzle : vi . fn ( ( ) => drizzleClientMock ) ,
@@ -29,59 +35,125 @@ describe("EnsDbReader", () => {
2935 whereMock . mockClear ( ) ;
3036 fromMock . mockClear ( ) ;
3137 selectMock . mockClear ( ) ;
38+ executeMock . mockClear ( ) ;
3239 } ) ;
3340
34- describe ( "getEnsDbVersion" , ( ) => {
35- it ( "returns undefined when no record exists" , async ( ) => {
36- const ensDbClient = createEnsDbReader ( ) ;
37- const { ensNodeSchema } = ensDbClient ;
41+ describe ( "getters" , ( ) => {
42+ it ( "returns the ensDb drizzle client" , ( ) => {
43+ const ensDbReader = createEnsDbReader ( ) ;
44+ expect ( ensDbReader . ensDb ) . toBe ( drizzleClientMock ) ;
45+ } ) ;
3846
39- await expect ( ensDbClient . getEnsDbVersion ( ) ) . resolves . toBeUndefined ( ) ;
47+ it ( "returns the ensIndexerSchema" , ( ) => {
48+ const ensDbReader = createEnsDbReader ( ) ;
49+ expect ( ensDbReader . ensIndexerSchema ) . toBeDefined ( ) ;
50+ } ) ;
4051
41- expect ( selectMock ) . toHaveBeenCalledTimes ( 1 ) ;
42- expect ( fromMock ) . toHaveBeenCalledWith ( ensNodeSchema . metadata ) ;
52+ it ( "returns the ensIndexerSchemaName" , ( ) => {
53+ const ensDbReader = createEnsDbReader ( ) ;
54+ expect ( ensDbReader . ensIndexerSchemaName ) . toBe ( ensDbClientMock . ensIndexerSchemaName ) ;
4355 } ) ;
4456
45- it ( "returns value when one record exists" , async ( ) => {
46- selectResult . current = [ { value : "0.1.0" } ] ;
57+ it ( "returns the ensNodeSchema" , ( ) => {
58+ const ensDbReader = createEnsDbReader ( ) ;
59+ expect ( ensDbReader . ensNodeSchema ) . toBeDefined ( ) ;
60+ } ) ;
61+ } ) ;
4762
48- await expect ( createEnsDbReader ( ) . getEnsDbVersion ( ) ) . resolves . toBe ( "0.1.0" ) ;
63+ describe ( "buildEnsDbPublicConfig" , ( ) => {
64+ it ( "returns version info with the postgresql version" , async ( ) => {
65+ executeMock . mockResolvedValueOnce ( {
66+ rows : [
67+ {
68+ version : "PostgreSQL 17.4 (Ubuntu 17.4-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu" ,
69+ } ,
70+ ] ,
71+ } ) ;
72+
73+ const result = await createEnsDbReader ( ) . buildEnsDbPublicConfig ( ) ;
74+
75+ expect ( result ) . toStrictEqual ( {
76+ versionInfo : {
77+ postgresql : "17.4" ,
78+ } ,
79+ } satisfies EnsDbPublicConfig ) ;
80+ expect ( executeMock ) . toHaveBeenCalledWith ( "SELECT version();" ) ;
4981 } ) ;
5082
51- // This scenario should be impossible due to the primary key constraint on
52- // the ('ensIndexerSchemaName', 'key') columns of the 'ensnode_metadata' table.
53- it ( "throws when multiple records exist" , async ( ) => {
54- selectResult . current = [ { value : "0.1.0" } , { value : "0.1.1" } ] ;
83+ it ( "throws when execute returns no rows" , async ( ) => {
84+ executeMock . mockResolvedValueOnce ( { rows : [ ] } ) ;
5585
56- await expect ( createEnsDbReader ( ) . getEnsDbVersion ( ) ) . rejects . toThrowError ( / e n s d b _ v e r s i o n / i) ;
86+ await expect ( createEnsDbReader ( ) . buildEnsDbPublicConfig ( ) ) . rejects . toThrow (
87+ / F a i l e d t o g e t P o s t g r e S Q L v e r s i o n / ,
88+ ) ;
5789 } ) ;
58- } ) ;
5990
60- describe ( "getEnsIndexerPublicConfig" , ( ) => {
61- it ( "returns undefined when no record exists" , async ( ) => {
62- await expect ( createEnsDbReader ( ) . getEnsIndexerPublicConfig ( ) ) . resolves . toBeUndefined ( ) ;
91+ it ( "throws when execute returns an invalid version string" , async ( ) => {
92+ executeMock . mockResolvedValueOnce ( {
93+ rows : [ { version : "invalid version string" } ] ,
94+ } ) ;
95+
96+ await expect ( createEnsDbReader ( ) . buildEnsDbPublicConfig ( ) ) . rejects . toThrow (
97+ / F a i l e d t o g e t P o s t g r e S Q L v e r s i o n / ,
98+ ) ;
6399 } ) ;
64100
65- it ( "deserializes the stored config" , async ( ) => {
66- const serializedConfig = serializeEnsIndexerPublicConfig ( ensDbClientMock . publicConfig ) ;
67- selectResult . current = [ { value : serializedConfig } ] ;
101+ it ( "propagates errors from execute" , async ( ) => {
102+ executeMock . mockRejectedValueOnce ( new Error ( "Connection refused" ) ) ;
68103
69- await expect ( createEnsDbReader ( ) . getEnsIndexerPublicConfig ( ) ) . resolves . toStrictEqual (
70- ensDbClientMock . publicConfig ,
104+ await expect ( createEnsDbReader ( ) . buildEnsDbPublicConfig ( ) ) . rejects . toThrow (
105+ "Connection refused" ,
71106 ) ;
72107 } ) ;
73108 } ) ;
74109
75- describe ( "getIndexingStatusSnapshot" , ( ) => {
76- it ( "deserializes the stored indexing status snapshot" , async ( ) => {
77- selectResult . current = [ { value : ensDbClientMock . serializedSnapshot } ] ;
110+ describe ( "getIndexingMetadataContext" , ( ) => {
111+ it ( "returns an uninitialized context when no record exists" , async ( ) => {
112+ const ensDbReader = createEnsDbReader ( ) ;
113+ const { ensNodeSchema } = ensDbReader ;
114+
115+ const result = await ensDbReader . getIndexingMetadataContext ( ) ;
78116
79- const expected = deserializeCrossChainIndexingStatusSnapshot (
117+ expect ( result ) . toStrictEqual ( buildIndexingMetadataContextUninitialized ( ) ) ;
118+ expect ( selectMock ) . toHaveBeenCalledTimes ( 1 ) ;
119+ expect ( fromMock ) . toHaveBeenCalledWith ( ensNodeSchema . metadata ) ;
120+ expect ( whereMock ) . toHaveBeenCalled ( ) ;
121+ } ) ;
122+
123+ it ( "returns the deserialized initialized context when one record exists" , async ( ) => {
124+ const indexingStatus = deserializeCrossChainIndexingStatusSnapshot (
80125 ensDbClientMock . serializedSnapshot ,
81126 ) ;
127+ const ensDbPublicConfig : EnsDbPublicConfig = {
128+ versionInfo : { postgresql : "17.4" } ,
129+ } ;
130+ const ensRainbowPublicConfig = {
131+ serverLabelSet : { labelSetId : "subgraph" , highestLabelSetVersion : 0 } ,
132+ versionInfo : { ensRainbow : "1.9.0" } ,
133+ } ;
134+ const stackInfo = buildEnsIndexerStackInfo (
135+ ensDbPublicConfig ,
136+ ensDbClientMock . publicConfig ,
137+ ensRainbowPublicConfig ,
138+ ) ;
139+ const context = buildIndexingMetadataContextInitialized ( indexingStatus , stackInfo ) ;
140+ const serialized = serializeIndexingMetadataContext ( context ) ;
141+
142+ selectResult . current = [ { value : serialized } ] ;
143+
144+ const result = await createEnsDbReader ( ) . getIndexingMetadataContext ( ) ;
145+
146+ const expected = deserializeIndexingMetadataContext ( serialized ) ;
147+ expect ( result ) . toStrictEqual ( expected ) ;
148+ } ) ;
149+
150+ // This scenario should be impossible due to the primary key constraint on
151+ // the ('ensIndexerSchemaName', 'key') columns of the 'ensnode_metadata' table.
152+ it ( "throws when multiple records exist" , async ( ) => {
153+ selectResult . current = [ { value : "value1" } , { value : "value2" } ] ;
82154
83- await expect ( createEnsDbReader ( ) . getIndexingStatusSnapshot ( ) ) . resolves . toStrictEqual (
84- expected ,
155+ await expect ( createEnsDbReader ( ) . getIndexingMetadataContext ( ) ) . rejects . toThrow (
156+ / T h e r e m u s t b e e x a c t l y o n e E N S N o d e M e t a d a t a r e c o r d / ,
85157 ) ;
86158 } ) ;
87159 } ) ;
0 commit comments