-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce new composition printer / implementation
This forks from the newly updated schema printer. However, the goal of this printer is to print the FINAL composition, rather than the schema for a single federated service. By peeking at the existing annotations in the `extensions` on the composed `GraphQLSchema`, the composition printer can gather important metadata like type and field ownership which is then annotated in the final SDL.
- Loading branch information
1 parent
c415707
commit 0e1c6d1
Showing
2 changed files
with
761 additions
and
0 deletions.
There are no files selected for viewing
265 changes: 265 additions & 0 deletions
265
packages/apollo-federation/src/service/__tests__/printComposedSdl.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
import { lexicographicSortSchema } from 'graphql'; | ||
import { fixtures } from 'apollo-federation-integration-testsuite'; | ||
import { composeAndValidate } from '../../composition'; | ||
import { printComposedSdl } from '../printComposedSdl'; | ||
|
||
describe('printComposedSdl', () => { | ||
const { schema, errors } = composeAndValidate(fixtures); | ||
const sorted = lexicographicSortSchema(schema); | ||
|
||
it('composes without errors', () => { | ||
expect(errors).toHaveLength(0); | ||
}); | ||
|
||
it('prints a fully composed schema correctly', () => { | ||
expect(printComposedSdl(sorted, fixtures)).toMatchInlineSnapshot(` | ||
"schema | ||
@graph(name: \\"accounts\\", url: \\"undefined\\") | ||
@graph(name: \\"books\\", url: \\"undefined\\") | ||
@graph(name: \\"documents\\", url: \\"undefined\\") | ||
@graph(name: \\"inventory\\", url: \\"undefined\\") | ||
@graph(name: \\"product\\", url: \\"undefined\\") | ||
@graph(name: \\"reviews\\", url: \\"undefined\\") | ||
@composedGraph(version: 1) | ||
{ | ||
query: Query | ||
mutation: Mutation | ||
} | ||
directive @stream on FIELD | ||
directive @transform(from: String!) on FIELD | ||
type Query { | ||
body: Body! @resolve(graph: \\"documents\\") | ||
book(isbn: String!): Book @resolve(graph: \\"books\\") | ||
books: [Book] @resolve(graph: \\"books\\") | ||
library(id: ID!): Library @resolve(graph: \\"books\\") | ||
me: User @resolve(graph: \\"accounts\\") | ||
product(upc: String!): Product @resolve(graph: \\"product\\") | ||
topCars(first: Int = 5): [Car] @resolve(graph: \\"product\\") | ||
topProducts(first: Int = 5): [Product] @resolve(graph: \\"product\\") | ||
topReviews(first: Int = 5): [Review] @resolve(graph: \\"reviews\\") | ||
user(id: ID!): User @resolve(graph: \\"accounts\\") | ||
vehicle(id: String!): Vehicle @resolve(graph: \\"product\\") | ||
} | ||
union Body = Image | Text | ||
type Image { | ||
attributes: ImageAttributes! | ||
name: String! | ||
} | ||
type ImageAttributes { | ||
url: String! | ||
} | ||
type Text { | ||
attributes: TextAttributes! | ||
name: String! | ||
} | ||
type TextAttributes { | ||
bold: Boolean | ||
text: String | ||
} | ||
type Book implements Product | ||
@owner(graph: \\"books\\") | ||
@key(fields: \\"isbn\\", graph: \\"books\\") | ||
@key(fields: \\"isbn\\", graph: \\"inventory\\") | ||
@key(fields: \\"isbn\\", graph: \\"product\\") | ||
@key(fields: \\"isbn\\", graph: \\"reviews\\") | ||
{ | ||
details: ProductDetailsBook @resolve(graph: \\"product\\") | ||
inStock: Boolean @resolve(graph: \\"inventory\\") | ||
isbn: String! | ||
isCheckedOut: Boolean @resolve(graph: \\"inventory\\") | ||
metadata: [MetadataOrError] | ||
name(delimeter: String = \\" \\"): String @resolve(graph: \\"product\\") @requires(fields: \\"title year\\") | ||
price: String @resolve(graph: \\"product\\") | ||
relatedReviews: [Review!]! @resolve(graph: \\"reviews\\") @requires(fields: \\"similarBooks { isbn }\\") | ||
reviews: [Review] @resolve(graph: \\"reviews\\") | ||
similarBooks: [Book]! | ||
sku: String! @resolve(graph: \\"product\\") | ||
title: String | ||
upc: String! @resolve(graph: \\"product\\") | ||
year: Int | ||
} | ||
interface Product { | ||
details: ProductDetails | ||
inStock: Boolean | ||
name: String | ||
price: String | ||
reviews: [Review] | ||
sku: String! | ||
upc: String! | ||
} | ||
interface ProductDetails { | ||
country: String | ||
} | ||
type Review | ||
@owner(graph: \\"reviews\\") | ||
@key(fields: \\"id\\", graph: \\"reviews\\") | ||
{ | ||
author: User @provides(fields: \\"username\\") | ||
body(format: Boolean = false): String | ||
id: ID! | ||
metadata: [MetadataOrError] | ||
product: Product | ||
} | ||
type User | ||
@owner(graph: \\"accounts\\") | ||
@key(fields: \\"id\\", graph: \\"accounts\\") | ||
@key(fields: \\"id\\", graph: \\"inventory\\") | ||
@key(fields: \\"id\\", graph: \\"product\\") | ||
@key(fields: \\"id\\", graph: \\"reviews\\") | ||
{ | ||
account: AccountType | ||
birthDate(locale: String): String | ||
goodAddress: Boolean @resolve(graph: \\"reviews\\") @requires(fields: \\"metadata { address }\\") | ||
goodDescription: Boolean @resolve(graph: \\"inventory\\") @requires(fields: \\"metadata { description }\\") | ||
id: ID! | ||
metadata: [UserMetadata] | ||
name: String | ||
numberOfReviews: Int! @resolve(graph: \\"reviews\\") | ||
reviews: [Review] @resolve(graph: \\"reviews\\") | ||
thing: Thing @resolve(graph: \\"product\\") | ||
username: String | ||
vehicle: Vehicle @resolve(graph: \\"product\\") | ||
} | ||
union AccountType = PasswordAccount | SMSAccount | ||
type PasswordAccount | ||
@owner(graph: \\"accounts\\") | ||
@key(fields: \\"email\\", graph: \\"accounts\\") | ||
{ | ||
email: String! | ||
} | ||
type SMSAccount | ||
@owner(graph: \\"accounts\\") | ||
@key(fields: \\"number\\", graph: \\"accounts\\") | ||
{ | ||
number: String | ||
} | ||
type UserMetadata { | ||
address: String | ||
description: String | ||
name: String | ||
} | ||
union Thing = Car | Ikea | ||
type Car implements Vehicle | ||
@owner(graph: \\"product\\") | ||
@key(fields: \\"id\\", graph: \\"product\\") | ||
@key(fields: \\"id\\", graph: \\"reviews\\") | ||
{ | ||
description: String | ||
id: String! | ||
price: String | ||
retailPrice: String @resolve(graph: \\"reviews\\") @requires(fields: \\"price\\") | ||
} | ||
interface Vehicle { | ||
description: String | ||
id: String! | ||
price: String | ||
retailPrice: String | ||
} | ||
type Ikea { | ||
asile: Int | ||
} | ||
union MetadataOrError = Error | KeyValue | ||
type Error { | ||
code: Int | ||
message: String | ||
} | ||
type KeyValue { | ||
key: String! | ||
value: String! | ||
} | ||
type ProductDetailsBook implements ProductDetails { | ||
country: String | ||
pages: Int | ||
} | ||
type Library | ||
@owner(graph: \\"books\\") | ||
@key(fields: \\"id\\", graph: \\"books\\") | ||
@key(fields: \\"id\\", graph: \\"accounts\\") | ||
{ | ||
id: ID! | ||
name: String | ||
userAccount(id: ID! = 1): User @resolve(graph: \\"accounts\\") @requires(fields: \\"name\\") | ||
} | ||
type Mutation { | ||
deleteReview(id: ID!): Boolean @resolve(graph: \\"reviews\\") | ||
login(password: String!, username: String!): User @resolve(graph: \\"accounts\\") | ||
reviewProduct(body: String!, upc: String!): Product @resolve(graph: \\"reviews\\") | ||
updateReview(review: UpdateReviewInput!): Review @resolve(graph: \\"reviews\\") | ||
} | ||
input UpdateReviewInput { | ||
body: String | ||
id: ID! | ||
} | ||
type Amazon { | ||
referrer: String | ||
} | ||
union Brand = Amazon | Ikea | ||
type Furniture implements Product | ||
@owner(graph: \\"product\\") | ||
@key(fields: \\"upc\\", graph: \\"product\\") | ||
@key(fields: \\"sku\\", graph: \\"product\\") | ||
@key(fields: \\"sku\\", graph: \\"inventory\\") | ||
@key(fields: \\"upc\\", graph: \\"reviews\\") | ||
{ | ||
brand: Brand | ||
details: ProductDetailsFurniture | ||
inStock: Boolean @resolve(graph: \\"inventory\\") | ||
isHeavy: Boolean @resolve(graph: \\"inventory\\") | ||
metadata: [MetadataOrError] | ||
name: String | ||
price: String | ||
reviews: [Review] @resolve(graph: \\"reviews\\") | ||
sku: String! | ||
upc: String! | ||
} | ||
type ProductDetailsFurniture implements ProductDetails { | ||
color: String | ||
country: String | ||
} | ||
type Van implements Vehicle | ||
@owner(graph: \\"product\\") | ||
@key(fields: \\"id\\", graph: \\"product\\") | ||
@key(fields: \\"id\\", graph: \\"reviews\\") | ||
{ | ||
description: String | ||
id: String! | ||
price: String | ||
retailPrice: String @resolve(graph: \\"reviews\\") @requires(fields: \\"price\\") | ||
} | ||
" | ||
`); | ||
}); | ||
}); |
Oops, something went wrong.