2017-08-05 23 views
0

使用Facebook的参考图书馆,我发现了一种方法破解泛型类型是这样的:如何使用模式语言创建泛型?

type PagedResource<Query, Item> = (pagedQuery: PagedQuery<Query>) => PagedResponse<Item> 
​ 
interface PagedQuery<Query> { 
    query: Query; 
    take: number; 
    skip: number; 
} 
​ 
interface PagedResponse<Item> { 
    items: Array<Item>; 
    total: number; 
} 

function pagedResource({type, resolve, args}) { 
    return { 
    type: pagedType(type), 
    args: Object.assign(args, { 
     page: { type: new GraphQLNonNull(pageQueryType()) } 
    }), 
    resolve 
    }; 
    function pageQueryType() { 
    return new GraphQLInputObjectType({ 
     name: 'PageQuery', 
     fields: { 
     skip: { type: new GraphQLNonNull(GraphQLInt) }, 
     take: { type: new GraphQLNonNull(GraphQLInt) } 
     } 
    }); 
    } 
    function pagedType(type) { 
    return new GraphQLObjectType({ 
     name: 'Paged' + type.toString(), 
     fields: { 
     items: { type: new GraphQLNonNull(new GraphQLList(type)) }, 
     total: { type: new GraphQLNonNull(GraphQLInt) } 
     } 
    }); 
    } 
} 

但我喜欢如何与阿波罗服务器,我可以声明创建模式。所以问题是,你们如何利用模式语言来创建泛型类型?

回答

1

您可以创建一个接口或联合,实现了类似的结果。我认为this article在解释如何正确实现接口和联合方面做得很好。您的模式将如下所示:

type Query { 
    pagedQuery(page: PageInput!): PagedResult 
} 

input PageInput { 
    skip: Int! 
    take: Int! 
} 

type PagedResult { 
    items: [Pageable!]! 
    total: Int 
} 

# Regular type definitions for Bar, Foo, Baz types... 

union Pageable = Bar | Foo | Baz 

您还需要为联合定义resolveType方法。随着graphql-tools,这是通过解析器完成:

const resolvers = { 
    Query: { ... }, 
    Pageable { 
    __resolveType: (obj) => { 
     // resolve logic here, needs to return a string specifying type 
     // i.e. if (obj.__typename == 'Foo') return 'Foo' 
    } 
    } 
} 

__resolveType需要被解决的业务对象,因为它是第一个参数(你给GraphQL解决通常是您的原DB结果)。你需要在这里应用一些逻辑来找出所有不同的Pageable类型,我们正在处理哪一个。对于大多数ORM,您只需在您正在使用的模型实例中添加某种typename字段,并且只需要resolveType即可返回该字段。

编辑:正如您所指出的那样,这种方法的缺点是项目中返回的类型不再对客户端透明 - 客户端必须知道返回的是哪种类型,并指定内嵌片段如... on Foo内的items。当然,您的客户仍然需要了解返回的类型,否则他们不会知道要请求的字段。

我想象你想要的方式创建泛型是不可能的时候声明式生成模式。为了让您的架构以与当前相同的方式工作,您需要咬紧牙关,并在定义Foo时定义PagedFoo,定义Bar等时定义PagedBar

我能想到的唯一的另一种选择是结合这两种方法。以编程方式创建您的“基础”模式。您只需使用pagedResource函数在根查询下定义分页查询。然后,您可以使用graphql/utilities中的printSchema将其转换为可与其余类型定义连接的字符串。在您的类型定义,您可以使用extend关键字建立在任何基础架构中已经声明的类型的,像这样的:

extend Query { 
    nonPaginatedQuery: Result 
} 

如果你走这条路线,你可以跳过传递resolve功能pagedResource或者在你的程序定义的类型上定义任何解析器,并且只使用你通常传递给buildExecutableSchema的解析器对象。

+0

这是否意味着客户需要弄清楚返回哪种类型? – Birowsky

+0

是的,客户端将不得不使用内联片段。不知道是否有一种很好的方式来执行您正在尝试完成的任务,而无需编程生成模式。看到我的编辑一些额外的想法。 –

+0

欣赏努力 – Birowsky

0

您可以使用graphql-tools创建声明性模式。

检查这个tutorial,这是非常好的

+0

找不到如何在教程中创建泛型。你能解决提供的例子吗? – Birowsky