This repository has been archived by the owner on Jul 6, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* (chore) - document idea's * (docs) - further document thought process * (chore) - document implementation details * (chore) - remove schemaFetching * (docs) - add wall of text about offline and partials * (feat) - find the rootFields in the schema or use sensible defaults * (chore) - start adding a test and define schema in our iterator * (feat) - see if a field is nullable * (feat) - add first implementation to exchange.ts * (refactor) - move to separate schemaPredicate class * (refactor) - add second argument to our query and write methods * (feat) - trigger heuristic matching when we are handling the no schema case * (feat) - implement heuristic/schema fragment matching and nullability. This also includes some readability improvements to the schemaPredicates class and uses the store.schemaPredicates instead of an additional pass * (tests) - add tests for our new SchemaPredicates class * (chore) - update paths for new schema * (chore) - update simpleSchema to include a union (this also updates snapshots for this case) * (tests) - test reexecution of operation on partial queryResult * (chore) - resolve typing issue and convert some Query ref to the rootKey from schemaPredicates * (refactor) - move rootKey logic to store * (refactor) - use graphql-js internals * (chore) - remove comment blocks * (refactor) - cleanup some unreachable code paths * (chore) - remove redundant comments * Add improved warning and invariant to SchemaPredicates.isFieldNullable * Add improved invariant to SchemaPredicates.isInterfaceOfType * Fix case for null type condition * Fix some types in schemaPredicates * Add warning on heuristic fragment matching * Add new partial handling to exchange * Fix partial query behaviour - When Query has no fields then return null and deem it incomplete (EMPTY) - When partial fields are found they still need to be set to null * Fix exchange outcome marking and tests * Add missing hasFields setter for invalid entities * Add limit for partial Query result to partial results * (tests) - update assertions of query.test.ts
- Loading branch information
1 parent
646b319
commit fce8b0e
Showing
14 changed files
with
1,848 additions
and
86 deletions.
There are no files selected for viewing
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
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,32 @@ | ||
import { SchemaPredicates } from './schemaPredicates'; | ||
|
||
describe('SchemaPredicates', () => { | ||
let schemaPredicates; | ||
|
||
beforeAll(() => { | ||
// eslint-disable-next-line | ||
const schema = require('../test-utils/simple_schema.json'); | ||
schemaPredicates = new SchemaPredicates(schema); | ||
}); | ||
|
||
it('should match fragments by interface/union', () => { | ||
expect(schemaPredicates.isInterfaceOfType('ITodo', 'BigTodo')).toBeTruthy(); | ||
expect( | ||
schemaPredicates.isInterfaceOfType('ITodo', 'SmallTodo') | ||
).toBeTruthy(); | ||
expect( | ||
schemaPredicates.isInterfaceOfType('Search', 'BigTodo') | ||
).toBeTruthy(); | ||
expect( | ||
schemaPredicates.isInterfaceOfType('Search', 'SmallTodo') | ||
).toBeTruthy(); | ||
expect(schemaPredicates.isInterfaceOfType('ITodo', 'Todo')).toBeFalsy(); | ||
expect(schemaPredicates.isInterfaceOfType('Search', 'Todo')).toBeFalsy(); | ||
}); | ||
|
||
it('should indicate nullability', () => { | ||
expect(schemaPredicates.isFieldNullable('Todo', 'text')).toBeFalsy(); | ||
expect(schemaPredicates.isFieldNullable('Todo', 'complete')).toBeTruthy(); | ||
expect(schemaPredicates.isFieldNullable('Todo', 'author')).toBeTruthy(); | ||
}); | ||
}); |
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,89 @@ | ||
import invariant from 'invariant'; | ||
import warning from 'warning'; | ||
|
||
import { | ||
buildClientSchema, | ||
isNullableType, | ||
GraphQLSchema, | ||
GraphQLAbstractType, | ||
GraphQLObjectType, | ||
GraphQLInterfaceType, | ||
GraphQLUnionType, | ||
} from 'graphql'; | ||
|
||
export class SchemaPredicates { | ||
schema: GraphQLSchema; | ||
|
||
constructor(schema) { | ||
this.schema = buildClientSchema(schema); | ||
} | ||
|
||
isFieldNullable(typename: string, fieldName: string): boolean { | ||
const type = this.schema.getType(typename); | ||
expectObjectType(type, typename); | ||
|
||
const object = type as GraphQLObjectType; | ||
if (object === undefined) { | ||
warning( | ||
false, | ||
'Invalid type: The type `%s` is not a type in the defined schema, ' + | ||
'but the GraphQL document expects it to exist.\n' + | ||
'Traversal will continue, however this may lead to undefined behavior!', | ||
typename | ||
); | ||
|
||
return false; | ||
} | ||
|
||
const field = object.getFields()[fieldName]; | ||
if (field === undefined) { | ||
warning( | ||
false, | ||
'Invalid field: The field `%s` does not exist on `%s`, ' + | ||
'but the GraphQL document expects it to exist.\n' + | ||
'Traversal will continue, however this may lead to undefined behavior!', | ||
fieldName, | ||
typename | ||
); | ||
|
||
return false; | ||
} | ||
|
||
return isNullableType(field.type); | ||
} | ||
|
||
isInterfaceOfType( | ||
typeCondition: null | string, | ||
typename: string | void | ||
): boolean { | ||
if (!typename || !typeCondition) return false; | ||
if (typename === typeCondition) return true; | ||
|
||
const abstractType = this.schema.getType(typeCondition); | ||
expectAbstractType(abstractType, typeCondition); | ||
const objectType = this.schema.getType(typename); | ||
expectObjectType(objectType, typename); | ||
|
||
const abstractNode = abstractType as GraphQLAbstractType; | ||
const concreteNode = objectType as GraphQLObjectType; | ||
return this.schema.isPossibleType(abstractNode, concreteNode); | ||
} | ||
} | ||
|
||
const expectObjectType = (type: any, typename: string) => { | ||
invariant( | ||
type instanceof GraphQLObjectType, | ||
'Invalid type: The type `%s` is not an object in the defined schema, ' + | ||
'but the GraphQL document is traversing it.', | ||
typename | ||
); | ||
}; | ||
|
||
const expectAbstractType = (type: any, typename: string) => { | ||
invariant( | ||
type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType, | ||
'Invalid type: The type `%s` is not an Interface or Union type in the defined schema, ' + | ||
'but a fragment in the GraphQL document is using it as a type condition.', | ||
typename | ||
); | ||
}; |
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
Oops, something went wrong.