2017-08-05 25 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