Handle additional subgraph types BigDecimal and Bytes in codegen (#89)

* Handle additional subgraph types BigDecimal and Bytes

* Use bigint and Decimal array transformers
This commit is contained in:
nikugogoi 2021-12-23 09:21:42 +05:30 committed by nabarun
parent 18f73e57c0
commit 2a204d8a32
5 changed files with 130 additions and 42 deletions

View File

@ -244,6 +244,9 @@ export class Entity {
// Add subgraph entity specific columns. // Add subgraph entity specific columns.
entityObject = this._addSubgraphColumns(subgraphTypeDefs, entityObject, def); entityObject = this._addSubgraphColumns(subgraphTypeDefs, entityObject, def);
// Add decimalTransformer column option if required.
this._addDecimalTransformerOption(entityObject);
// Add bigintTransformer column option if required. // Add bigintTransformer column option if required.
this._addBigIntTransformerOption(entityObject); this._addBigIntTransformerOption(entityObject);
@ -282,9 +285,13 @@ export class Entity {
} }
_addBigIntTransformerOption (entityObject: any): void { _addBigIntTransformerOption (entityObject: any): void {
let importObject = entityObject.imports.find((element: any) => {
return element.from === '@vulcanize/util';
});
entityObject.columns.forEach((column: any) => { entityObject.columns.forEach((column: any) => {
// Implement bigintTransformer for bigint types. // Implement bigintTransformer for bigint type.
if (['bigint', 'bigint[]'].includes(column.tsType)) { if (column.tsType === 'bigint') {
column.columnOptions.push( column.columnOptions.push(
{ {
option: 'transformer', option: 'transformer',
@ -292,24 +299,106 @@ export class Entity {
} }
); );
const importObject = entityObject.imports.find((element: any) => {
return element.from === '@vulcanize/util';
});
if (importObject) { if (importObject) {
importObject.toImport.add('bigintTransformer'); importObject.toImport.add('bigintTransformer');
} else { } else {
entityObject.imports.push( importObject = {
{ toImport: new Set(['bigintTransformer']),
toImport: new Set(['bigintTransformer']), from: '@vulcanize/util'
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 { _addSubgraphColumns (subgraphTypeDefs: any, entityObject: any, def: any): any {
def.fields.forEach((field: any) => { def.fields.forEach((field: any) => {
if (field.directives.some((directive: any) => directive.name.value === 'derivedFrom')) { if (field.directives.some((directive: any) => directive.name.value === 'derivedFrom')) {

View File

@ -198,6 +198,18 @@ export class Schema {
}); });
this._composer.addSchemaMustHaveType(typeComposer); 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. // Create a type composer to add the type Proof in the schema composer.
typeComposer = this._composer.createObjectTC({ typeComposer = this._composer.createObjectTC({
name: 'Proof', name: 'Proof',
@ -243,19 +255,10 @@ export class Schema {
} }
}); });
this._composer.addSchemaMustHaveType(typeComposer); this._composer.addSchemaMustHaveType(typeComposer);
}
/**
* Adds types 'ResultEvent' and 'WatchedEvent' to the schema.
*/
_addEventsRelatedTypes (): void {
let typeComposer;
// Create Ethereum types.
// Create the Block type. // Create the Block type.
const blockName = 'Block';
typeComposer = this._composer.createObjectTC({ typeComposer = this._composer.createObjectTC({
name: blockName, name: '_Block_',
fields: { fields: {
cid: 'String!', cid: 'String!',
hash: 'String!', hash: 'String!',
@ -265,9 +268,17 @@ export class Schema {
} }
}); });
this._composer.addSchemaMustHaveType(typeComposer); this._composer.addSchemaMustHaveType(typeComposer);
}
/**
* Adds types 'ResultEvent' and 'WatchedEvent' to the schema.
*/
_addEventsRelatedTypes (): void {
let typeComposer;
// Create Ethereum types.
// Create the Transaction type. // Create the Transaction type.
const transactionName = 'Transaction'; const transactionName = '_Transaction_';
typeComposer = this._composer.createObjectTC({ typeComposer = this._composer.createObjectTC({
name: transactionName, name: transactionName,
fields: { fields: {
@ -285,7 +296,7 @@ export class Schema {
name: resultEventName, name: resultEventName,
fields: { fields: {
// Get type composer object for 'blockName' type from the schema composer. // 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, tx: () => this._composer.getOTC(transactionName).NonNull,
contract: 'String!', contract: 'String!',
eventIndex: 'Int!', eventIndex: 'Int!',
@ -326,7 +337,7 @@ export class Schema {
const typeComposer = this._composer.createObjectTC({ const typeComposer = this._composer.createObjectTC({
name: 'ResultIPLDBlock', name: 'ResultIPLDBlock',
fields: { fields: {
block: () => this._composer.getOTC('Block').NonNull, block: () => this._composer.getOTC('_Block_').NonNull,
contractAddress: 'String!', contractAddress: 'String!',
cid: 'String!', cid: 'String!',
kind: 'String!', kind: 'String!',

View File

@ -17,10 +17,8 @@ import { IPLDBlock } from './entity/IPLDBlock';
{{#each queries as | query |}} {{#each queries as | query |}}
import { {{query.entityName}} } from './entity/{{query.entityName}}'; import { {{query.entityName}} } from './entity/{{query.entityName}}';
{{#unless @last}}
{{/unless}}
{{/each}} {{/each}}
export class Database implements IPLDDatabaseInterface { export class Database implements IPLDDatabaseInterface {
_config: ConnectionOptions; _config: ConnectionOptions;
_conn!: Connection; _conn!: Connection;

View File

@ -4,11 +4,6 @@ import fs from 'fs';
import { loadFilesSync } from '@graphql-tools/load-files'; import { loadFilesSync } from '@graphql-tools/load-files';
const SCALAR_MAPPING: any = {
BigDecimal: 'String',
Bytes: 'String'
};
export function parseSubgraphSchema (subgraphPath: string): any { export function parseSubgraphSchema (subgraphPath: string): any {
const subgraphSchemaPath = path.join(path.resolve(subgraphPath), '/schema.graphql'); const subgraphSchemaPath = path.join(path.resolve(subgraphPath), '/schema.graphql');
@ -51,15 +46,7 @@ export function getFieldType (typeNode: any): { typeName: string, array: boolean
function parseType (typeNode: any): any { function parseType (typeNode: any): any {
// Check if 'NamedType' is reached. // Check if 'NamedType' is reached.
if (typeNode.kind === 'NamedType') { 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 {
typeNode.type = parseType(typeNode.type); typeNode.type = parseType(typeNode.type);
} }

View File

@ -33,12 +33,15 @@ _tsToPg.set('string', 'varchar');
_tsToPg.set('number', 'integer'); _tsToPg.set('number', 'integer');
_tsToPg.set('bigint', 'numeric'); _tsToPg.set('bigint', 'numeric');
_tsToPg.set('boolean', 'boolean'); _tsToPg.set('boolean', 'boolean');
_tsToPg.set('Decimal', 'numeric');
// Graphql to Typescript type-mapping. // Graphql to Typescript type-mapping.
_gqlToTs.set('String', 'string'); _gqlToTs.set('String', 'string');
_gqlToTs.set('Int', 'number'); _gqlToTs.set('Int', 'number');
_gqlToTs.set('BigInt', 'bigint'); _gqlToTs.set('BigInt', 'bigint');
_gqlToTs.set('Boolean', 'boolean'); _gqlToTs.set('Boolean', 'boolean');
_gqlToTs.set('BigDecimal', 'Decimal');
_gqlToTs.set('Bytes', 'string');
function getTsForSol (solType: string): string | undefined { function getTsForSol (solType: string): string | undefined {
return _solToTs.get(solType); return _solToTs.get(solType);