Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/quick-bats-teach.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphprotocol/graph-cli': minor
'@graphprotocol/graph-ts': minor
---

Add support for subgraph datasource and associated types.
12 changes: 7 additions & 5 deletions packages/cli/src/codegen/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,14 @@ export default class SchemaCodeGenerator {
];
}

generateTypes(): Array<tsCodegen.Class> {
generateTypes(generateStoreMethods = true): Array<tsCodegen.Class> {
return this.schema.ast.definitions
.map(def => {
if (this._isEntityTypeDefinition(def)) {
schemaCodeGeneratorDebug.extend('generateTypes')(
`Generating entity type for ${def.name.value}`,
);
return this._generateEntityType(def);
return this._generateEntityType(def, generateStoreMethods);
}
})
.filter(Boolean) as Array<tsCodegen.Class>;
Expand Down Expand Up @@ -157,7 +157,7 @@ export default class SchemaCodeGenerator {
return def.kind === 'InterfaceTypeDefinition';
}

_generateEntityType(def: ObjectTypeDefinitionNode) {
_generateEntityType(def: ObjectTypeDefinitionNode, generateStoreMethods = true) {
const name = def.name.value;
const klass = tsCodegen.klass(name, { export: true, extends: 'Entity' });
const fields = def.fields;
Expand All @@ -166,8 +166,10 @@ export default class SchemaCodeGenerator {
// Generate and add a constructor
klass.addMethod(this._generateConstructor(name, fields));

// Generate and add save() and getById() methods
this._generateStoreMethods(name, idField).forEach(method => klass.addMethod(method));
if (generateStoreMethods) {
// Generate and add save() and getById() methods
this._generateStoreMethods(name, idField).forEach(method => klass.addMethod(method));
}

// Generate and add entity field getters and setters
def.fields
Expand Down
14 changes: 13 additions & 1 deletion packages/cli/src/commands/codegen.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path';
import { Args, Command, Flags } from '@oclif/core';
import * as DataSourcesExtractor from '../command-helpers/data-sources';
import { DEFAULT_IPFS_URL } from '../command-helpers/ipfs';
import { assertGraphTsVersion, assertManifestApiVersion } from '../command-helpers/version';
import debug from '../debug';
import Protocol from '../protocols';
Expand Down Expand Up @@ -38,6 +39,11 @@ export default class CodegenCommand extends Command {
summary: 'Generate Float Subgraph Uncrashable helper file.',
char: 'u',
}),
ipfs: Flags.string({
summary: 'IPFS node to use for fetching subgraph data.',
char: 'i',
default: DEFAULT_IPFS_URL,
}),
'uncrashable-config': Flags.file({
summary: 'Directory for uncrashable config.',
aliases: ['uc'],
Expand All @@ -54,6 +60,7 @@ export default class CodegenCommand extends Command {
'output-dir': outputDir,
'skip-migrations': skipMigrations,
watch,
ipfs,
uncrashable,
'uncrashable-config': uncrashableConfig,
},
Expand All @@ -62,6 +69,7 @@ export default class CodegenCommand extends Command {
codegenDebug('Initialized codegen manifest: %o', manifest);

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

const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest);

protocol = Protocol.fromDataSources(dataSourcesAndTemplates);
subgraphSources = dataSourcesAndTemplates
.filter((ds: any) => ds.kind == 'subgraph')
.map((ds: any) => ds.source.address);
} catch (e) {
this.error(e, { exit: 1 });
}
Expand All @@ -85,7 +95,9 @@ export default class CodegenCommand extends Command {
skipMigrations,
protocol,
uncrashable,
subgraphSources,
uncrashableConfig: uncrashableConfig || 'uncrashable-config.yaml',
ipfsUrl: ipfs,
});

// Watch working directory for file updates or additions, trigger
Expand Down
28 changes: 26 additions & 2 deletions packages/cli/src/protocols/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as NearManifestScaffold from './near/scaffold/manifest';
import * as NearMappingScaffold from './near/scaffold/mapping';
import NearSubgraph from './near/subgraph';
import { SubgraphOptions } from './subgraph';
import SubgraphDS from './subgraph/subgraph';
import * as SubstreamsManifestScaffold from './substreams/scaffold/manifest';
import SubstreamsSubgraph from './substreams/subgraph';

Expand All @@ -43,6 +44,7 @@ export default class Protocol {
* some other places use datasource object
*/
const name = typeof datasource === 'string' ? datasource : datasource.kind;
protocolDebug('Initializing protocol with datasource %O', datasource);
this.name = Protocol.normalizeName(name)!;
protocolDebug('Initializing protocol %s', this.name);

Expand All @@ -59,6 +61,9 @@ export default class Protocol {
case 'near':
this.config = nearProtocol;
break;
case 'subgraph':
this.config = subgraphProtocol;
break;
case 'substreams':
this.config = substreamsProtocol;

Expand All @@ -85,6 +90,7 @@ export default class Protocol {
near: ['near'],
cosmos: ['cosmos'],
substreams: ['substreams'],
subgraph: ['subgraph'],
}) as immutable.Collection<ProtocolName, string[]>;
}

Expand Down Expand Up @@ -140,14 +146,16 @@ export default class Protocol {
'uni-3', // Juno testnet
],
substreams: ['mainnet'],
subgraph: ['mainnet'],
}) as immutable.Map<
| 'arweave'
| 'ethereum'
| 'near'
| 'cosmos'
| 'substreams'
// this is temporary, until we have a better way to handle substreams triggers
| 'substreams/triggers',
| 'substreams/triggers'
| 'subgraph',
immutable.List<string>
>;
}
Expand Down Expand Up @@ -234,7 +242,8 @@ export type ProtocolName =
| 'near'
| 'cosmos'
| 'substreams'
| 'substreams/triggers';
| 'substreams/triggers'
| 'subgraph';

export interface ProtocolConfig {
displayName: string;
Expand Down Expand Up @@ -290,6 +299,21 @@ const ethereumProtocol: ProtocolConfig = {
mappingScaffold: EthereumMappingScaffold,
};

const subgraphProtocol: ProtocolConfig = {
displayName: 'Subgraph',
abi: EthereumABI,
contract: undefined,
getTemplateCodeGen: undefined,
getTypeGenerator(options) {
return new EthereumTypeGenerator(options);
},
getSubgraph(options) {
return new SubgraphDS(options);
},
manifestScaffold: undefined,
mappingScaffold: undefined,
};

const nearProtocol: ProtocolConfig = {
displayName: 'NEAR',
abi: undefined,
Expand Down
65 changes: 65 additions & 0 deletions packages/cli/src/protocols/subgraph/manifest.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Each referenced type's in any of the types below must be listed
# here either as `scalar` or `type` for the validation code to work
# properly.
#
# That's why `String` is listed as a scalar even though it's built-in
# GraphQL basic types.
scalar String
scalar File
scalar BigInt
scalar Boolean
scalar JSON

type SubgraphManifest {
specVersion: String!
features: [String!]
schema: Schema!
description: String
repository: String
graft: Graft
dataSources: [DataSource!]!
indexerHints: IndexerHints
}

type Schema {
file: File!
}

type DataSource {
kind: String!
name: String!
network: String
context: JSON
source: ContractSource!
mapping: ContractMapping!
}

type ContractSource {
address: String!
startBlock: BigInt
}

type ContractMapping {
kind: String
apiVersion: String!
language: String!
file: File!
abis: [ContractABI!]!
entities: [String!]!
handlers: [EntityHandler!]
}

type ContractABI {
name: String!
file: File!
}

type EntityHandler {
handler: String!
entity: String!
}

type Graft {
base: String!
block: BigInt!
}
8 changes: 8 additions & 0 deletions packages/cli/src/protocols/subgraph/scaffold/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const source = ({ spkgPath }: { spkgPath?: string }) => `
package:
moduleName: graph_out
file: ${spkgPath || 'substreams-eth-block-meta-v0.1.0.spkg'}`;

export const mapping = () => `
apiVersion: 0.0.5
kind: substreams/graph-entities`;
22 changes: 22 additions & 0 deletions packages/cli/src/protocols/subgraph/subgraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import immutable from 'immutable';
import { Subgraph, SubgraphOptions } from '../subgraph';

export default class SubgraphDS implements Subgraph {
public manifest: SubgraphOptions['manifest'];
public resolveFile: SubgraphOptions['resolveFile'];
public protocol: SubgraphOptions['protocol'];

constructor(options: SubgraphOptions) {
this.manifest = options.manifest;
this.resolveFile = options.resolveFile;
this.protocol = options.protocol;
}

validateManifest() {
return immutable.List();
}

handlerTypes() {
return immutable.List([]);
}
}
9 changes: 9 additions & 0 deletions packages/cli/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,13 @@ export default class Schema {
const ast = graphql.parse(document);
return new Schema(filename, document, ast);
}

static async loadFromString(filename: string, document: string) {
try {
const ast = graphql.parse(document);
return new Schema(filename, document, ast);
} catch (e) {
throw new Error(`Failed to load schema from string: ${e.message}`);
}
}
}
Loading
Loading