Skip to content

Commit

Permalink
Handle additional subgraph types BigDecimal and Bytes in codegen (#89)
Browse files Browse the repository at this point in the history
* Handle additional subgraph types BigDecimal and Bytes

* Use bigint and Decimal array transformers
  • Loading branch information
nikugogoi authored and prathamesh0 committed Dec 23, 2021
1 parent 184fd2e commit 3a49031
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 42 deletions.
113 changes: 101 additions & 12 deletions packages/codegen/src/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ export class Entity {
// Add subgraph entity specific columns.
entityObject = this._addSubgraphColumns(subgraphTypeDefs, entityObject, def);

// Add decimalTransformer column option if required.
this._addDecimalTransformerOption(entityObject);

// Add bigintTransformer column option if required.
this._addBigIntTransformerOption(entityObject);

Expand Down Expand Up @@ -282,32 +285,118 @@ export class Entity {
}

_addBigIntTransformerOption (entityObject: any): void {
let importObject = entityObject.imports.find((element: any) => {
return element.from === '@vulcanize/util';
});

entityObject.columns.forEach((column: any) => {
// Implement bigintTransformer for bigint types.
if (['bigint', 'bigint[]'].includes(column.tsType)) {
// Implement bigintTransformer for bigint type.
if (column.tsType === 'bigint') {
column.columnOptions.push(
{
option: 'transformer',
value: 'bigintTransformer'
}
);

const importObject = entityObject.imports.find((element: any) => {
return element.from === '@vulcanize/util';
});

if (importObject) {
importObject.toImport.add('bigintTransformer');
} else {
entityObject.imports.push(
{
toImport: new Set(['bigintTransformer']),
from: '@vulcanize/util'
}
);
importObject = {
toImport: new Set(['bigintTransformer']),
from: '@vulcanize/util'
};

entityObject.imports.push(importObject);
}
}

// Implement bigintArrayTransformer for array of bigint type.
if (column.tsType === 'bigint[]') {
column.columnOptions.push(
{
option: 'transformer',
value: 'bigintArrayTransformer'
}
);

if (importObject) {
importObject.toImport.add('bigintArrayTransformer');
} else {
importObject = {
toImport: new Set(['bigintArrayTransformer']),
from: '@vulcanize/util'
};

entityObject.imports.push(importObject);
}
}
});
}

_addDecimalTransformerOption (entityObject: any): void {
let importObject = entityObject.imports.find((element: any) => {
return element.from === '@vulcanize/util';
});

let isDecimalRequired = false;

entityObject.columns.forEach((column: any) => {
// Implement decimalTransformer for Decimal type.
if (column.tsType === 'Decimal') {
isDecimalRequired = true;

column.columnOptions.push(
{
option: 'transformer',
value: 'decimalTransformer'
}
);

if (importObject) {
importObject.toImport.add('decimalTransformer');
} else {
importObject = {
toImport: new Set(['decimalTransformer']),
from: '@vulcanize/util'
};

entityObject.imports.push(importObject);
}
}

// Implement decimalArrayTransformer for array of Decimal type.
if (column.tsType === 'Decimal[]') {
isDecimalRequired = true;

column.columnOptions.push(
{
option: 'transformer',
value: 'decimalArrayTransformer'
}
);

if (importObject) {
importObject.toImport.add('decimalArrayTransformer');
} else {
importObject = {
toImport: new Set(['decimalArrayTransformer']),
from: '@vulcanize/util'
};

entityObject.imports.push(importObject);
}
}
});

if (isDecimalRequired) {
entityObject.imports.push(
{
toImport: new Set(['Decimal']),
from: 'decimal.js'
}
);
}
}

_addSubgraphColumns (subgraphTypeDefs: any, entityObject: any, def: any): any {
Expand Down
37 changes: 24 additions & 13 deletions packages/codegen/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,18 @@ export class Schema {
});
this._composer.addSchemaMustHaveType(typeComposer);

// Create a scalar type composer to add the scalar BigDecimal in the schema composer.
typeComposer = this._composer.createScalarTC({
name: 'BigDecimal'
});
this._composer.addSchemaMustHaveType(typeComposer);

// Create a scalar type composer to add the scalar Bytes in the schema composer.
typeComposer = this._composer.createScalarTC({
name: 'Bytes'
});
this._composer.addSchemaMustHaveType(typeComposer);

// Create a type composer to add the type Proof in the schema composer.
typeComposer = this._composer.createObjectTC({
name: 'Proof',
Expand Down Expand Up @@ -243,19 +255,10 @@ export class Schema {
}
});
this._composer.addSchemaMustHaveType(typeComposer);
}

/**
* Adds types 'ResultEvent' and 'WatchedEvent' to the schema.
*/
_addEventsRelatedTypes (): void {
let typeComposer;

// Create Ethereum types.
// Create the Block type.
const blockName = 'Block';
typeComposer = this._composer.createObjectTC({
name: blockName,
name: '_Block_',
fields: {
cid: 'String!',
hash: 'String!',
Expand All @@ -265,9 +268,17 @@ export class Schema {
}
});
this._composer.addSchemaMustHaveType(typeComposer);
}

/**
* Adds types 'ResultEvent' and 'WatchedEvent' to the schema.
*/
_addEventsRelatedTypes (): void {
let typeComposer;

// Create Ethereum types.
// Create the Transaction type.
const transactionName = 'Transaction';
const transactionName = '_Transaction_';
typeComposer = this._composer.createObjectTC({
name: transactionName,
fields: {
Expand All @@ -285,7 +296,7 @@ export class Schema {
name: resultEventName,
fields: {
// Get type composer object for 'blockName' type from the schema composer.
block: () => this._composer.getOTC(blockName).NonNull,
block: () => this._composer.getOTC('_Block_').NonNull,
tx: () => this._composer.getOTC(transactionName).NonNull,
contract: 'String!',
eventIndex: 'Int!',
Expand Down Expand Up @@ -326,7 +337,7 @@ export class Schema {
const typeComposer = this._composer.createObjectTC({
name: 'ResultIPLDBlock',
fields: {
block: () => this._composer.getOTC('Block').NonNull,
block: () => this._composer.getOTC('_Block_').NonNull,
contractAddress: 'String!',
cid: 'String!',
kind: 'String!',
Expand Down
4 changes: 1 addition & 3 deletions packages/codegen/src/templates/database-template.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ import { IPLDBlock } from './entity/IPLDBlock';

{{#each queries as | query |}}
import { {{query.entityName}} } from './entity/{{query.entityName}}';
{{#unless @last}}

{{/unless}}
{{/each}}

export class Database implements IPLDDatabaseInterface {
_config: ConnectionOptions;
_conn!: Connection;
Expand Down
15 changes: 1 addition & 14 deletions packages/codegen/src/utils/subgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ import fs from 'fs';

import { loadFilesSync } from '@graphql-tools/load-files';

const SCALAR_MAPPING: any = {
BigDecimal: 'String',
Bytes: 'String'
};

export function parseSubgraphSchema (subgraphPath: string): any {
const subgraphSchemaPath = path.join(path.resolve(subgraphPath), '/schema.graphql');

Expand Down Expand Up @@ -51,15 +46,7 @@ export function getFieldType (typeNode: any): { typeName: string, array: boolean

function parseType (typeNode: any): any {
// Check if 'NamedType' is reached.
if (typeNode.kind === 'NamedType') {
const typeName: string = typeNode.name.value;

// TODO Handle extra types provided by the graph.
// Replace unknown scalars using SCALAR_MAPPING.
if (typeName in SCALAR_MAPPING) {
typeNode.name.value = SCALAR_MAPPING[typeName];
}
} else {
if (typeNode.kind !== 'NamedType') {
typeNode.type = parseType(typeNode.type);
}

Expand Down
3 changes: 3 additions & 0 deletions packages/codegen/src/utils/type-mappings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ _tsToPg.set('string', 'varchar');
_tsToPg.set('number', 'integer');
_tsToPg.set('bigint', 'numeric');
_tsToPg.set('boolean', 'boolean');
_tsToPg.set('Decimal', 'numeric');

// Graphql to Typescript type-mapping.
_gqlToTs.set('String', 'string');
_gqlToTs.set('Int', 'number');
_gqlToTs.set('BigInt', 'bigint');
_gqlToTs.set('Boolean', 'boolean');
_gqlToTs.set('BigDecimal', 'Decimal');
_gqlToTs.set('Bytes', 'string');

function getTsForSol (solType: string): string | undefined {
return _solToTs.get(solType);
Expand Down

0 comments on commit 3a49031

Please sign in to comment.