Skip to content

Commit e62b29d

Browse files
committed
Generate type for source subgraph schema
1 parent 5c831cf commit e62b29d

File tree

6 files changed

+123
-5
lines changed

6 files changed

+123
-5
lines changed

packages/cli/src/commands/codegen.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import path from 'path';
22
import { Args, Command, Flags } from '@oclif/core';
33
import * as DataSourcesExtractor from '../command-helpers/data-sources';
4+
import { DEFAULT_IPFS_URL } from '../command-helpers/ipfs';
45
import { assertGraphTsVersion, assertManifestApiVersion } from '../command-helpers/version';
56
import debug from '../debug';
67
import Protocol from '../protocols';
@@ -38,6 +39,11 @@ export default class CodegenCommand extends Command {
3839
summary: 'Generate Float Subgraph Uncrashable helper file.',
3940
char: 'u',
4041
}),
42+
ipfs: Flags.string({
43+
summary: 'Upload build results to an IPFS node.',
44+
char: 'i',
45+
default: DEFAULT_IPFS_URL,
46+
}),
4147
'uncrashable-config': Flags.file({
4248
summary: 'Directory for uncrashable config.',
4349
aliases: ['uc'],
@@ -54,6 +60,7 @@ export default class CodegenCommand extends Command {
5460
'output-dir': outputDir,
5561
'skip-migrations': skipMigrations,
5662
watch,
63+
ipfs,
5764
uncrashable,
5865
'uncrashable-config': uncrashableConfig,
5966
},
@@ -62,6 +69,7 @@ export default class CodegenCommand extends Command {
6269
codegenDebug('Initialized codegen manifest: %o', manifest);
6370

6471
let protocol;
72+
let subgraphSources;
6573
try {
6674
// Checks to make sure codegen doesn't run against
6775
// older subgraphs (both apiVersion and graph-ts version).
@@ -73,8 +81,10 @@ export default class CodegenCommand extends Command {
7381
await assertGraphTsVersion(path.dirname(manifest), '0.25.0');
7482

7583
const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest);
76-
7784
protocol = Protocol.fromDataSources(dataSourcesAndTemplates);
85+
subgraphSources = dataSourcesAndTemplates
86+
.filter((ds: any) => ds.kind == 'subgraph')
87+
.map((ds: any) => ds.source.address);
7888
} catch (e) {
7989
this.error(e, { exit: 1 });
8090
}
@@ -85,7 +95,9 @@ export default class CodegenCommand extends Command {
8595
skipMigrations,
8696
protocol,
8797
uncrashable,
98+
subgraphSources,
8899
uncrashableConfig: uncrashableConfig || 'uncrashable-config.yaml',
100+
ipfsUrl: ipfs,
89101
});
90102

91103
// Watch working directory for file updates or additions, trigger

packages/cli/src/compiler/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export default class Compiler {
7676

7777
if (!globalsLib) {
7878
throw Error(
79-
'Could not locate `@graphprotocol/graph-ts` package in parent directories of subgraph manifest.',
79+
`Could not locate @graphprotocol/graph-ts package in parent directories of subgraph manifest. ${this.libsDirs}`,
8080
);
8181
}
8282

packages/cli/src/schema.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import fs from 'fs-extra';
22
import * as graphql from 'graphql/language';
33
import type { DocumentNode } from 'graphql/language';
44
import SchemaCodeGenerator from './codegen/schema';
5+
import debug from './debug';
6+
7+
const schemaDebug = debug('graph-cli:type-generator');
58

69
export default class Schema {
710
constructor(
@@ -23,4 +26,15 @@ export default class Schema {
2326
const ast = graphql.parse(document);
2427
return new Schema(filename, document, ast);
2528
}
29+
30+
static async loadFromString(filename: string, document: string) {
31+
try {
32+
const ast = graphql.parse(document);
33+
schemaDebug('Loaded schema from string');
34+
return new Schema(filename, document, ast);
35+
} catch (e) {
36+
schemaDebug('Failed to load schema from string: %s', e.message);
37+
throw new Error(`Failed to load schema from string: ${e.message}`);
38+
}
39+
}
2640
}

packages/cli/src/type-generator.ts

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ import fs from 'fs-extra';
33
import * as toolbox from 'gluegun';
44
import * as graphql from 'graphql/language';
55
import immutable from 'immutable';
6+
import { create } from 'ipfs-http-client';
7+
import yaml from 'js-yaml';
68
import prettier from 'prettier';
79
// @ts-expect-error TODO: type out if necessary
810
import uncrashable from '@float-capital/float-subgraph-uncrashable/src/Index.bs.js';
911
import DataSourceTemplateCodeGenerator from './codegen/template';
1012
import { GENERATED_FILE_NOTE, ModuleImports } from './codegen/typescript';
13+
import { appendApiVersionForGraph } from './command-helpers/compiler';
1114
import { displayPath } from './command-helpers/fs';
1215
import { Spinner, step, withSpinner } from './command-helpers/spinner';
16+
import { GRAPH_CLI_SHARED_HEADERS } from './constants';
1317
import debug from './debug';
1418
import { applyMigrations } from './migrations';
1519
import Protocol from './protocols';
@@ -28,6 +32,8 @@ export interface TypeGeneratorOptions {
2832
skipMigrations?: boolean;
2933
uncrashable: boolean;
3034
uncrashableConfig: string;
35+
subgraphSources: string[];
36+
ipfsUrl: string;
3137
}
3238

3339
export default class TypeGenerator {
@@ -65,6 +71,11 @@ export default class TypeGenerator {
6571
return;
6672
}
6773

74+
if (this.options.subgraphSources.length > 0) {
75+
typeGenDebug.extend('generateTypes')('Subgraph uses subgraph datasources.');
76+
toolbox.print.success('Subgraph uses subgraph datasources.');
77+
}
78+
6879
try {
6980
if (!this.options.skipMigrations && this.options.subgraphManifest) {
7081
await applyMigrations({
@@ -93,6 +104,30 @@ export default class TypeGenerator {
93104
typeGenDebug.extend('generateTypes')('Generating types for schema');
94105
await this.generateTypesForSchema(schema);
95106

107+
if (this.options.subgraphSources.length > 0) {
108+
const ipfsClient = create({
109+
url: appendApiVersionForGraph(this.options.ipfsUrl.toString()),
110+
headers: {
111+
...GRAPH_CLI_SHARED_HEADERS,
112+
},
113+
});
114+
115+
await Promise.all(
116+
this.options.subgraphSources.map(async manifest => {
117+
const subgraphSchemaFile = await this.loadSubgraphSchemaFromIPFS(ipfsClient, manifest);
118+
119+
const subgraphSchema = await Schema.loadFromString(
120+
`js${manifest}.graphql`,
121+
subgraphSchemaFile,
122+
);
123+
typeGenDebug.extend('generateTypes')(
124+
`Generating types for subgraph datasource ${manifest}`,
125+
);
126+
await this.generateTypesForSchema(subgraphSchema, `subgraph-${manifest}.ts`);
127+
}),
128+
);
129+
}
130+
96131
toolbox.print.success('\nTypes generated successfully\n');
97132

98133
if (this.options.uncrashable && this.options.uncrashableConfig) {
@@ -105,6 +140,37 @@ export default class TypeGenerator {
105140
}
106141
}
107142

143+
async loadSubgraphSchemaFromIPFS(ipfsClient: any, manifest: string) {
144+
typeGenDebug.extend('loadSubgraphSchemaFromIPFS')(`Loading schema from IPFS ${manifest}`);
145+
try {
146+
const manifestBuffer = ipfsClient.cat(manifest);
147+
let manifestFile = '';
148+
for await (const chunk of manifestBuffer) {
149+
manifestFile += Buffer.from(chunk).toString('utf8'); // Explicitly convert each chunk to UTF-8
150+
}
151+
152+
const manifestYaml: any = yaml.safeLoad(manifestFile);
153+
let schema = manifestYaml.schema.file['/'];
154+
155+
if (schema.startsWith('/ipfs/')) {
156+
schema = schema.slice(6);
157+
}
158+
159+
const schemaBuffer = ipfsClient.cat(schema);
160+
let schemaFile = '';
161+
for await (const chunk of schemaBuffer) {
162+
schemaFile += Buffer.from(chunk).toString('utf8'); // Explicitly convert each chunk to UTF-8
163+
}
164+
return schemaFile;
165+
} catch (e) {
166+
typeGenDebug.extend('loadSubgraphSchemaFromIPFS')(
167+
`Failed to load schema from IPFS ${manifest}`,
168+
);
169+
typeGenDebug.extend('loadSubgraphSchemaFromIPFS')(e);
170+
throw Error(`Failed to load schema from IPFS ${manifest}`);
171+
}
172+
}
173+
108174
async generateUncrashableEntities(graphSchema: any) {
109175
const ast = graphql.parse(graphSchema.document);
110176
const entityDefinitions = ast['definitions'];
@@ -160,7 +226,11 @@ export default class TypeGenerator {
160226
);
161227
}
162228

163-
async generateTypesForSchema(schema: any) {
229+
async generateTypesForSchema(
230+
schema: any,
231+
fileName = 'schema.ts', // Default file name
232+
outputDir: string = this.options.outputDir, // Default output directory
233+
) {
164234
return await withSpinner(
165235
`Generate types for GraphQL schema`,
166236
`Failed to generate types for GraphQL schema`,
@@ -180,7 +250,7 @@ export default class TypeGenerator {
180250
},
181251
);
182252

183-
const outputFile = path.join(this.options.outputDir, 'schema.ts');
253+
const outputFile = path.join(outputDir, fileName); // Use provided outputDir and fileName
184254
step(spinner, 'Write types to', displayPath(outputFile));
185255
await fs.mkdirs(path.dirname(outputFile));
186256
await fs.writeFile(outputFile, code);

packages/cli/tests/cli/validation/subgraph-data-source/subgraph.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ dataSources:
77
- kind: subgraph
88
name: ExampleSubgraph
99
source:
10-
address: "QmHASH"
10+
address: "QmbPZENDFo1HQcocaporuVGn7fXpGgba1hUX5TFbBv69tZ"
1111
startBlock: 0
1212
mapping:
1313
kind: entity

packages/ts/common/collections.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,28 @@ export class Entity extends TypedMap<string, Value> {
458458
}
459459
}
460460

461+
/**
462+
* Common representation for entity triggers, this wraps the entity
463+
* and has fields for the operation type and the entity type.
464+
*/
465+
export class EntityTrigger {
466+
constructor(
467+
public entityOp: u32,
468+
public entityType: string,
469+
public entity: Entity,
470+
) {}
471+
}
472+
473+
/**
474+
* Enum for entity operations.
475+
* Create, Modify, Remove
476+
*/
477+
export enum EntityOp {
478+
Create,
479+
Modify,
480+
Remove,
481+
}
482+
461483
/**
462484
* The result of an operation, with a corresponding value and error type.
463485
*/

0 commit comments

Comments
 (0)