繁体   English   中英

使用带有 typegraphql 的非标准类型 (BigNumber)

[英]Using a non-standard type (BigNumber) with typegraphql

我有一个ethers.js BigNumber ,我使用 TypeORM 作为numeric类型存储在 Postgresql DB 中。 我正在尝试使其与 Typegraphql 一起使用,但出现错误: CannotDetermineGraphQLTypeError: Cannot determine GraphQL output type for 'amount' of 'Transfer' class. Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper output value? CannotDetermineGraphQLTypeError: Cannot determine GraphQL output type for 'amount' of 'Transfer' class. Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper output value?

@ObjectType()
@Entity()
export class Transfer extends BaseEntity {
  @Field()
  @Column({
    type: "numeric",
    precision: 78,
    scale: 0,
    transformer: new BigNumberTransformer()
  })
  amount!: BigNumber
}

我创建了一个BigNumberTransformer ,正如这篇中篇文章中所推荐的那样:

export class BigNumberTransformer implements ValueTransformer {
  to(num: BigNumber): string {
    return num.toString();
  }

  from(num: string): BigNumber {
    return BigNumber.from(num);
  }
}

您必须创建一个自定义标量( BigNumber.ts ):

import { Kind, GraphQLError, GraphQLScalarType } from "graphql";
import { BigNumber } from "ethers";

export const GraphQLBigNumber: GraphQLScalarType = new GraphQLScalarType({
  name: "BigNumber",

  description:
    "A field whose value is a valid BigNumber which safely allows mathematical operations on numbers of any magnitude",

  serialize(value) {
    if (value === null) return value;
    else return BigNumber.from(value.toString()).toString();
  },

  parseValue(value) {
    if (value === null) return value;
    else return BigNumber.from(value.toString());
  },

  parseLiteral(ast) {
    if (ast.kind !== Kind.STRING && ast.kind !== Kind.Int) {
      throw new GraphQLError(
        `Can only validate strings or ints as BigNumbers but got a: ${ast.kind}`
      );
    }

    if (ast.value === null) return ast.value;
    else return BigNumber.from(value.toString());
  },

  extensions: {
    codegenScalarType: "BigNumber | string | number",
  },
});

然后你可以在你的字段装饰器中使用它:

// ...
import { GraphQLBigNumber } from "./BigNumber";

@ObjectType()
@Entity()
export class Transfer extends BaseEntity {
  @Field(() => GraphQLBigNumber) // Here!
  @Column({
    type: "numeric",
    precision: 78,
    scale: 0,
    transformer: new BigNumberTransformer(),
  })
  amount!: BigNumber;
}

或者,您可以声明反射属性类型和标量之间的关联以自动 map 它(不需要显式类型注释:):

@ObjectType()
@Entity()
export class Transfer extends BaseEntity {
  @Field() // Magic goes here - no type annotation!
  @Column({
    type: "numeric",
    precision: 78,
    scale: 0,
    transformer: new BigNumberTransformer(),
  })
  amount!: BigNumber;
}

您需要做的就是在buildSchema选项中注册关联 map:

import { buildSchema } from "type-graphql";
import { BigNumber } from "ethers";
import { GraphQLBigNumber } from "./BigNumber";

const schema = await buildSchema({
  resolvers,
  scalarsMap: [{ type: BigNumber, scalar: GraphQLBigNumber }],
});

但是,您必须知道,这仅在 TypeScript 反射机制可以处理时才有效。 所以我们的 class 属性类型必须是class ,而不是enumunioninterface

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM