Skip to content

Commit 62735aa

Browse files
hopeyenfordN
authored andcommitted
indexer-common,-cli: add cost models delete
1 parent 670f8fc commit 62735aa

File tree

8 files changed

+242
-1
lines changed

8 files changed

+242
-1
lines changed

packages/indexer-cli/src/__tests__/references/indexer-cost.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ Manage costing for subgraphs
33
indexer cost set variables Update cost model variables
44
indexer cost set model Update a cost model
55
indexer cost get Get cost models and/or variables for one or all subgraphs
6+
indexer cost delete Remove one or many cost models
67
indexer cost Manage costing for subgraphs

packages/indexer-cli/src/__tests__/references/indexer-help.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Manage indexer configuration
1515
indexer cost set variables Update cost model variables
1616
indexer cost set model Update a cost model
1717
indexer cost get Get cost models and/or variables for one or all subgraphs
18+
indexer cost delete Remove one or many cost models
1819
indexer cost Manage costing for subgraphs
1920
indexer connect Connect to indexer management API
2021
indexer allocations reallocate Reallocate to subgraph deployment

packages/indexer-cli/src/__tests__/references/indexer.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Manage indexer configuration
1616
indexer cost set model Update a cost model
1717
indexer cost get Get cost models and/or variables for one or all subgraphs
1818
indexer cost Manage costing for subgraphs
19+
indexer cost delete Remove one or many cost models
1920
indexer connect Connect to indexer management API
2021
indexer allocations reallocate Reallocate to subgraph deployment
2122
indexer allocations get List one or more allocations
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { GluegunToolbox } from 'gluegun'
2+
import chalk from 'chalk'
3+
4+
import { loadValidatedConfig } from '../../../config'
5+
import { createIndexerManagementClient } from '../../../client'
6+
import { fixParameters } from '../../../command-helpers'
7+
import { costModels, deleteCostModels, parseDeploymentID } from '../../../cost'
8+
import { CostModelAttributes } from '@graphprotocol/indexer-common'
9+
10+
const HELP = `
11+
${chalk.bold('graph indexer cost delete')} [options] all
12+
${chalk.bold('graph indexer cost delete')} [options] global
13+
${chalk.bold('graph indexer cost delete')} [options] <deployment-id>
14+
15+
${chalk.dim('Options:')}
16+
17+
-h, --help Show usage information
18+
-o, --output table|json|yaml Choose the output format: table (default), JSON, or YAML
19+
`
20+
21+
module.exports = {
22+
name: 'delete',
23+
alias: [],
24+
description: 'Remove one or many cost models',
25+
run: async (toolbox: GluegunToolbox) => {
26+
const { print, parameters } = toolbox
27+
28+
const { h, help, o, output } = parameters.options
29+
const [rawDeployment] = fixParameters(parameters, { h, help }) || []
30+
const outputFormat = o || output || 'table'
31+
32+
if (help || h) {
33+
print.info(HELP)
34+
return
35+
}
36+
37+
if (!['json', 'yaml', 'table'].includes(outputFormat)) {
38+
print.error(`Invalid output format "${outputFormat}"`)
39+
process.exitCode = 1
40+
return
41+
}
42+
43+
try {
44+
const config = loadValidatedConfig()
45+
// Create indexer API client
46+
const client = await createIndexerManagementClient({ url: config.api })
47+
const deployment = parseDeploymentID(rawDeployment)
48+
switch (deployment) {
49+
case 'all': {
50+
const deployments: string[] = (await costModels(client))
51+
.filter((model): model is CostModelAttributes => !!model.deployment)
52+
.map(model => model.deployment.toString())
53+
54+
const numberDeleted = await deleteCostModels(client, deployments)
55+
print.success(
56+
`Deleted ${numberDeleted} cost model(s) for: \n${deployments.join('\n')}`,
57+
)
58+
break
59+
}
60+
case 'global': {
61+
await deleteCostModels(client, [deployment])
62+
print.success(`Deleted cost model for ${deployment}`)
63+
break
64+
}
65+
default: {
66+
await deleteCostModels(client, [deployment.bytes32])
67+
print.success(`Deleted cost model for ${rawDeployment}`)
68+
}
69+
}
70+
} catch (error) {
71+
print.error(error.toString())
72+
process.exitCode = 1
73+
return
74+
}
75+
},
76+
}

packages/indexer-cli/src/cost.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,28 @@ export const setCostModel = async (
269269

270270
return costModelFromGraphQL(result.data.setCostModel)
271271
}
272+
273+
export const deleteCostModels = async (
274+
client: IndexerManagementClient,
275+
deployments: string[],
276+
): Promise<number> => {
277+
const result = await client
278+
.mutation(
279+
gql`
280+
mutation deleteCostModels($deployments: [String!]!) {
281+
deleteCostModels(deployments: $deployments) {
282+
deployment
283+
model
284+
variables
285+
}
286+
}
287+
`,
288+
{ deployments },
289+
)
290+
.toPromise()
291+
292+
if (result.error) {
293+
throw result.error
294+
}
295+
return result.data.deleteCostModels
296+
}

packages/indexer-common/src/indexer-management/__tests__/resolvers/cost-models.ts

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ const SET_COST_MODEL_MUTATION = gql`
3535
}
3636
`
3737

38+
const DELETE_COST_MODELS_MUTATION = gql`
39+
mutation deleteCostModels($deployments: [String!]!) {
40+
deleteCostModels(deployments: $deployments) {
41+
deployment
42+
model
43+
variables
44+
}
45+
}
46+
`
47+
3848
const GET_COST_MODEL_QUERY = gql`
3949
query costModel($deployment: String!) {
4050
costModel(deployment: $deployment) {
@@ -202,7 +212,7 @@ describe('Cost models', () => {
202212
).resolves.toHaveProperty('data.setCostModel', expected)
203213
})
204214

205-
test('Set and get global cost model', async () => {
215+
test('Set, get, and delete global cost model', async () => {
206216
const input = {
207217
deployment: 'global',
208218
model: 'default => 0.00025;',
@@ -238,6 +248,24 @@ describe('Cost models', () => {
238248
})
239249
.toPromise(),
240250
).resolves.toHaveProperty('data.costModel', expected)
251+
252+
//Delete global cost model
253+
await expect(
254+
client
255+
.mutation(DELETE_COST_MODELS_MUTATION, {
256+
deployments: [input.deployment],
257+
})
258+
.toPromise(),
259+
).resolves.toHaveProperty('data.deleteCostModels', 1)
260+
261+
//Check non-existent without global cost model
262+
await expect(
263+
client
264+
.query(GET_COST_MODEL_QUERY, {
265+
deployment: 'blah',
266+
})
267+
.toPromise(),
268+
).resolves.toHaveProperty('data.costModel', null)
241269
})
242270

243271
test('Update existing cost model', async () => {
@@ -479,6 +507,99 @@ describe('Cost models', () => {
479507
[input],
480508
)
481509
})
510+
511+
test('Delete one cost model', async () => {
512+
const inputs = [
513+
{
514+
deployment: '0x0000000000000000000000000000000000000000000000000000000000000000',
515+
model: 'query { votes } => 10 * $n;',
516+
variables: JSON.stringify({ n: 100 }),
517+
},
518+
{
519+
deployment: '0x1111111111111111111111111111111111111111111111111111111111111111',
520+
model: 'query { proposals } => 30 * $n;',
521+
variables: JSON.stringify({ n: 10 }),
522+
},
523+
]
524+
525+
for (const input of inputs) {
526+
await client.mutation(SET_COST_MODEL_MUTATION, { costModel: input }).toPromise()
527+
}
528+
529+
for (const input of inputs) {
530+
await expect(
531+
client.query(GET_COST_MODEL_QUERY, { deployment: input.deployment }).toPromise(),
532+
).resolves.toHaveProperty('data.costModel', input)
533+
}
534+
535+
for (const input of inputs) {
536+
await expect(
537+
client
538+
.mutation(DELETE_COST_MODELS_MUTATION, { deployments: [input.deployment] })
539+
.toPromise(),
540+
).resolves.toHaveProperty('data.deleteCostModels', 1)
541+
}
542+
})
543+
544+
test('Delete all costs model', async () => {
545+
const inputs = [
546+
{
547+
deployment: '0x0000000000000000000000000000000000000000000000000000000000000000',
548+
model: 'query { votes } => 10 * $n;',
549+
variables: JSON.stringify({ n: 100 }),
550+
},
551+
{
552+
deployment: '0x1111111111111111111111111111111111111111111111111111111111111111',
553+
model: 'query { proposals } => 30 * $n;',
554+
variables: JSON.stringify({ n: 10 }),
555+
},
556+
]
557+
558+
for (const input of inputs) {
559+
await client.mutation(SET_COST_MODEL_MUTATION, { costModel: input }).toPromise()
560+
}
561+
562+
for (const input of inputs) {
563+
await expect(
564+
client.query(GET_COST_MODEL_QUERY, { deployment: input.deployment }).toPromise(),
565+
).resolves.toHaveProperty('data.costModel', input)
566+
}
567+
568+
await expect(
569+
client
570+
.mutation(DELETE_COST_MODELS_MUTATION, {
571+
deployments: inputs.map((d) => d.deployment),
572+
})
573+
.toPromise(),
574+
).resolves.toHaveProperty('data.deleteCostModels', 2)
575+
})
576+
577+
test('Delete global costs model', async () => {
578+
const inputs = [
579+
{
580+
deployment: 'global',
581+
model: 'default => 0.00025;',
582+
variables: JSON.stringify({ n: 100 }),
583+
},
584+
{
585+
deployment: '0x0000000000000000000000000000000000000000000000000000000000000000',
586+
model: 'query { votes } => 10 * $n;',
587+
variables: JSON.stringify({ n: 100 }),
588+
},
589+
]
590+
591+
for (const input of inputs) {
592+
await client.mutation(SET_COST_MODEL_MUTATION, { costModel: input }).toPromise()
593+
}
594+
595+
await expect(
596+
client
597+
.mutation(DELETE_COST_MODELS_MUTATION, {
598+
deployments: inputs.map((d) => d.deployment),
599+
})
600+
.toPromise(),
601+
).resolves.toHaveProperty('data.deleteCostModels', 2)
602+
})
482603
})
483604

484605
describe('Feature: Inject $DAI variable', () => {

packages/indexer-common/src/indexer-management/client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ const SCHEMA_SDL = gql`
399399
deleteIndexingRules(identifiers: [String!]!): Boolean!
400400
401401
setCostModel(costModel: CostModelInput!): CostModel!
402+
deleteCostModels(deployments: [String!]!): Int!
402403
403404
storeDisputes(disputes: [POIDisputeInput!]!): [POIDispute!]
404405
deleteDisputes(allocationIDs: [String!]!): Int!

packages/indexer-common/src/indexer-management/resolvers/cost-models.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,19 @@ export default {
139139

140140
return (await model.save()).toGraphQL()
141141
},
142+
143+
deleteCostModels: async (
144+
{ deployments }: { deployments: string[] },
145+
{ models }: IndexerManagementResolverContext,
146+
): Promise<number> => {
147+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
148+
return await models.CostModel.sequelize!.transaction(async (transaction) => {
149+
return await models.CostModel.destroy({
150+
where: {
151+
deployment: deployments,
152+
},
153+
transaction,
154+
})
155+
})
156+
},
142157
}

0 commit comments

Comments
 (0)