[英]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
,而不是enum
、 union
或interface
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.