Skip to content

Commit f32ea01

Browse files
committed
fix(db): handle missing is_listed column
1 parent 6eb2f10 commit f32ea01

File tree

1 file changed

+96
-20
lines changed

1 file changed

+96
-20
lines changed

server/utils/validators.ts

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,35 @@ import { getUnlistedActiveValidatorAddresses, isKnownValidatorProfile } from './
1515

1616
export const getStoredValidatorsId = () => useDrizzle().select({ id: tables.validators.id }).from(tables.validators).execute().then(r => r.map(v => v.id))
1717
export const getStoredValidatorsAddress = () => useDrizzle().select({ address: tables.validators.address }).from(tables.validators).execute().then(r => r.map(v => v.address))
18-
export const getStoredValidatorsListState = () => useDrizzle().select({ address: tables.validators.address, isListed: tables.validators.isListed }).from(tables.validators).execute()
18+
19+
function isMissingIsListedColumnError(error: unknown) {
20+
const message = String(error)
21+
return message.includes('is_listed')
22+
&& (message.includes('no such column') || message.includes('has no column named'))
23+
}
24+
25+
let hasWarnedMissingIsListedColumn = false
26+
27+
export async function getStoredValidatorsListState() {
28+
try {
29+
return await useDrizzle()
30+
.select({ address: tables.validators.address, isListed: tables.validators.isListed })
31+
.from(tables.validators)
32+
.execute()
33+
}
34+
catch (error) {
35+
if (!isMissingIsListedColumnError(error))
36+
throw error
37+
38+
if (!hasWarnedMissingIsListedColumn) {
39+
hasWarnedMissingIsListedColumn = true
40+
consola.warn('`validators.is_listed` column is missing, using backwards-compatible fallback until migration is applied')
41+
}
42+
43+
const addresses = await getStoredValidatorsAddress()
44+
return addresses.map(address => ({ address, isListed: null }))
45+
}
46+
}
1947

2048
const validators = new Map<string, number>()
2149

@@ -68,25 +96,57 @@ export async function storeValidator(address: string, rest: ValidatorJSON = defa
6896
consola.info(`${upsert ? 'Updating' : 'Storing'} validator ${address}`)
6997

7098
const brandingParameters = await handleValidatorLogo(address, rest)
99+
const valuesWithoutListState = { ...rest, ...brandingParameters }
100+
const valuesWithListState = { ...valuesWithoutListState, isListed }
101+
71102
try {
72103
if (validatorId) {
73104
await useDrizzle()
74105
.update(tables.validators)
75-
.set({ ...rest, ...brandingParameters, isListed })
106+
.set(valuesWithListState)
76107
.where(eq(tables.validators.id, validatorId))
77108
.execute()
78109
}
79110
else {
80111
validatorId = await useDrizzle()
81112
.insert(tables.validators)
82-
.values({ ...rest, address, ...brandingParameters, isListed })
113+
.values({ ...valuesWithListState, address })
83114
.returning()
84115
.get()
85116
.then(r => r.id)
86117
}
87118
}
88119
catch (e) {
89-
consola.error(`There was an error while writing ${address} into the database`, e)
120+
if (!isMissingIsListedColumnError(e)) {
121+
consola.error(`There was an error while writing ${address} into the database`, e)
122+
}
123+
else {
124+
if (!hasWarnedMissingIsListedColumn) {
125+
hasWarnedMissingIsListedColumn = true
126+
consola.warn('`validators.is_listed` column is missing, storing validators without list state until migration is applied')
127+
}
128+
129+
try {
130+
if (validatorId) {
131+
await useDrizzle()
132+
.update(tables.validators)
133+
.set(valuesWithoutListState)
134+
.where(eq(tables.validators.id, validatorId))
135+
.execute()
136+
}
137+
else {
138+
validatorId = await useDrizzle()
139+
.insert(tables.validators)
140+
.values({ ...valuesWithoutListState, address })
141+
.returning()
142+
.get()
143+
.then(r => r.id)
144+
}
145+
}
146+
catch (fallbackError) {
147+
consola.error(`There was an error while writing ${address} into the database`, fallbackError)
148+
}
149+
}
90150
}
91151

92152
validators.set(address, validatorId!)
@@ -96,22 +156,38 @@ export async function storeValidator(address: string, rest: ValidatorJSON = defa
96156
export async function markValidatorsAsUnlisted(addresses: string[]) {
97157
await Promise.all(addresses.map(async (address) => {
98158
const brandingParameters = await handleValidatorLogo(address, defaultValidatorJSON)
99-
await useDrizzle()
100-
.update(tables.validators)
101-
.set({
102-
name: 'Unknown validator',
103-
description: null,
104-
fee: null,
105-
payoutType: PayoutType.None,
106-
payoutSchedule: '',
107-
isMaintainedByNimiq: false,
108-
website: null,
109-
contact: null,
110-
isListed: false,
111-
...brandingParameters,
112-
})
113-
.where(eq(tables.validators.address, address))
114-
.execute()
159+
const valuesWithoutListState = {
160+
name: 'Unknown validator',
161+
description: null,
162+
fee: null,
163+
payoutType: PayoutType.None,
164+
payoutSchedule: '',
165+
isMaintainedByNimiq: false,
166+
website: null,
167+
contact: null,
168+
...brandingParameters,
169+
}
170+
171+
try {
172+
await useDrizzle()
173+
.update(tables.validators)
174+
.set({
175+
...valuesWithoutListState,
176+
isListed: false,
177+
})
178+
.where(eq(tables.validators.address, address))
179+
.execute()
180+
}
181+
catch (error) {
182+
if (!isMissingIsListedColumnError(error))
183+
throw error
184+
185+
await useDrizzle()
186+
.update(tables.validators)
187+
.set(valuesWithoutListState)
188+
.where(eq(tables.validators.address, address))
189+
.execute()
190+
}
115191
}))
116192
}
117193

0 commit comments

Comments
 (0)