Skip to content

Commit

Permalink
[1.0] WIP GraphQL connection operator name tweaks fixes #1174 (#1177)
Browse files Browse the repository at this point in the history
* Move connections to first as more often that's what you want

* Change 'sortBy' graphql connection operator to 'sort'

* Fix some colors on gatsbyjs.org

* Change 'groupBy' graphql connection field to 'group'

* Move all connection filter input arguments under a top-level field 'filter'

This both makes it easier to navigate the connection arguments as well
as protects against name collisions as if someone had a filter named
skip, limit, or sort (the other top-level input fields) then there'd be
a mysterious error.

* Update tests

* fix test

* Make node graphql type filtering work again
  • Loading branch information
KyleAMathews authored Jun 15, 2017
1 parent 7c30ffe commit 54cbbee
Show file tree
Hide file tree
Showing 20 changed files with 91 additions and 59 deletions.
2 changes: 1 addition & 1 deletion examples/hn/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default Index

export const pageQuery = graphql`
query PageQuery {
allHnStory(sortBy: {fields: [order]}) {
allHnStory(sort: {fields: [order]}) {
edges {
node {
...Story_item
Expand Down
2 changes: 1 addition & 1 deletion examples/using-drupal/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default IndexPage

export const pageQuery = graphql`
query PageQuery {
allDrupalNodeArticle(sortBy: { fields: [created], order: DESC }) {
allDrupalNodeArticle(sort: { fields: [created], order: DESC }) {
edges {
node {
title
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-plugin-feed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ plugins: [
{
allMarkdownRemark(
limit: 1000,
sortBy: { order: DESC, fields: [frontmatter___date] },
sort: { order: DESC, fields: [frontmatter___date] },
frontmatter: { draft: { ne: true } }
) {
edges {
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-plugin-feed/src/internals.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const defaultOptions = {
{
allMarkdownRemark(
limit: 1000,
sortBy: {
sort: {
order: DESC,
fields: [frontmatter___date]
},
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-source-hacker-news/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ You can query nodes created from Hacker News like the following:

```graphql
query StoriesQuery {
allHnStory(sortBy: {fields: [order]}) {
allHnStory(sort: {fields: [order]}) {
edges {
node {
id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default Dev404Page

export const pageQuery = graphql`
query Dev404Page {
allSitePage(path: { ne: "/dev-404-page/"}) {
allSitePage(filter: { path: { ne: "/dev-404-page/"}}) {
totalCount
edges {
node {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const _ = require(`lodash`)
const {
graphql,
GraphQLString,
GraphQLObjectType,
GraphQLSchema,
GraphQLInputObjectType,
} = require(`graphql`)
const { connectionArgs, connectionDefinitions } = require(`graphql-skip-limit`)

Expand Down Expand Up @@ -32,6 +34,10 @@ function queryResult(nodes, query, { types = [] } = {}) {
}),
})

const { sort, inferredFields } = inferInputObjectStructureFromNodes({
nodes,
typeName: `test`,
})
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: `RootQueryType`,
Expand All @@ -42,10 +48,14 @@ function queryResult(nodes, query, { types = [] } = {}) {
type: nodeConnection,
args: {
...connectionArgs,
...inferInputObjectStructureFromNodes({
nodes,
typeName: `test`,
}),
sort,
filter: {
type: new GraphQLInputObjectType({
name: _.camelCase(`filter test`),
description: `Filter connection on its fields`,
fields: () => inferredFields,
}),
},
},
resolve(nvi, args) {
return runSift({
Expand Down Expand Up @@ -212,7 +222,7 @@ describe(`GraphQL Input args`, () => {
},
},
],
})
}).inferredFields

expect(Object.keys(fields.foo.type.getFields())[2]).toEqual(`foo_moo`)
})
Expand All @@ -228,7 +238,7 @@ describe(`GraphQL Input args`, () => {
},
},
],
})
}).inferredFields

expect(Object.keys(fields)).toHaveLength(1)
expect(Object.keys(fields.foo.type.getFields())).toHaveLength(2)
Expand All @@ -239,7 +249,7 @@ describe(`GraphQL Input args`, () => {
nodes,
`
{
allNode(hair: { eq: 2 }) {
allNode(filter: {hair: { eq: 2 }}) {
edges { node { hair }}
}
}
Expand All @@ -256,7 +266,7 @@ describe(`GraphQL Input args`, () => {
nodes,
`
{
allNode(hair: { ne: 2 }) {
allNode(filter: {hair: { ne: 2 }}) {
edges { node { hair }}
}
}
Expand All @@ -273,7 +283,7 @@ describe(`GraphQL Input args`, () => {
nodes,
`
{
allNode(name: { regex: "/^the.*wax/i/" }) {
allNode(filter: {name: { regex: "/^the.*wax/i/" }}) {
edges { node { name }}
}
}
Expand All @@ -289,7 +299,7 @@ describe(`GraphQL Input args`, () => {
nodes,
`
{
allNode(anArray: { in: [5] }) {
allNode(filter: {anArray: { in: [5] }}) {
edges { node { name }}
}
}
Expand All @@ -305,7 +315,7 @@ describe(`GraphQL Input args`, () => {
nodes,
`
{
allNode(limit: 10, name: { glob: "*Wax" }) {
allNode(limit: 10, filter: {name: { glob: "*Wax" }}) {
edges { node { name }}
}
}
Expand All @@ -323,7 +333,7 @@ describe(`GraphQL Input args`, () => {
{
allNode(
limit: 10,
sortBy: {
sort: {
fields: [frontmatter___blue],
order: DESC
}
Expand Down Expand Up @@ -369,17 +379,17 @@ describe(`GraphQL Input args`, () => {
expect(result.data.allNode.circle[0]).toEqual(`happy`)
})

it(`handles the groupBy connection field`, async () => {
it(`handles the group connection field`, async () => {
let result = await queryResult(
nodes,
` {
allNode {
blue: groupBy(field: frontmatter___blue) {
blue: group(field: frontmatter___blue) {
field
fieldValue
totalCount
}
anArray: groupBy(field: anArray) {
anArray: group(field: anArray) {
field
fieldValue
totalCount
Expand Down
6 changes: 3 additions & 3 deletions packages/gatsby/src/schema/build-connection-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ module.exports = type => {
return _.sortBy(_.filter(_.uniq(_.flatten(fields)), _.identity))
},
},
groupBy: {
group: {
type: new GraphQLList(groupConnection),
args: {
...connectionArgs,
field: {
type: new GraphQLEnumType({
name: _.camelCase(`${type.name} groupBy enum`),
name: _.camelCase(`${type.name} group enum`),
values: enumValues,
}),
},
Expand All @@ -67,7 +67,7 @@ module.exports = type => {
const connectionNodes = connection.edges.map(edge => edge.node)

let groups = {}
// Do a custom groupBy for arrays (w/ a group per array value)
// Do a custom grouping for arrays (w/ a group per array value)
// Find the first node with this field and check if it's an array.
if (_.isArray(_.get(_.find(connectionNodes, fieldName), fieldName))) {
const values = _.uniq(
Expand Down
12 changes: 10 additions & 2 deletions packages/gatsby/src/schema/build-node-connections.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
const _ = require(`lodash`)
const { connectionArgs, connectionDefinitions } = require(`graphql-skip-limit`)
const { GraphQLInputObjectType } = require(`graphql`)
const {
inferInputObjectStructureFromNodes,
} = require(`./infer-graphql-input-fields`)
Expand All @@ -17,7 +18,7 @@ module.exports = (types: any) => {
connectionFields: () => buildConnectionFields(type),
})

const inferredInputFields = inferInputObjectStructureFromNodes({
const { sort, inferredFields } = inferInputObjectStructureFromNodes({
nodes,
typeName: `${type.name}Connection`,
})
Expand All @@ -27,7 +28,14 @@ module.exports = (types: any) => {
description: `Connection to all ${type.name} nodes`,
args: {
...connectionArgs,
...inferredInputFields,
sort,
filter: {
type: new GraphQLInputObjectType({
name: _.camelCase(`filter ${type.name}`),
description: `Filter connection on its fields`,
fields: () => inferredFields,
}),
},
},
resolve(object, resolveArgs, b, { rootValue }) {
let path
Expand Down
15 changes: 10 additions & 5 deletions packages/gatsby/src/schema/build-node-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,30 @@ module.exports = async () => {
isTypeOf: value => value.internal.type === typeName,
})

const inferedInputFields = inferInputObjectStructureFromNodes({
nodes,
typeName,
})

const proccesedType: ProcessedNodeType = {
...intermediateType,
fieldsFromPlugins: mergedFieldsFromPlugins,
nodeObjectType: gqlType,
node: {
name: typeName,
type: gqlType,
args: inferInputObjectStructureFromNodes({
nodes,
typeName,
}),
args: inferedInputFields.inferredFields,
resolve(a, args, context) {
const runSift = require(`./run-sift`)
const latestNodes = _.filter(
getNodes(),
n => n.internal.type === typeName
)
if (!_.isObject(args)) {
args = {}
}
return runSift({
args,
args: { filter: { ...args } },
nodes: latestNodes,
path: context.path,
})
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby/src/schema/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module.exports = async () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: `RootQueryType`,
fields: { ...nodes, ...connections },
fields: { ...connections, ...nodes },
}),
})

Expand Down
11 changes: 6 additions & 5 deletions packages/gatsby/src/schema/infer-graphql-input-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ function inferGraphQLInputFields({
nodes,
prefix,
exampleValue: value,
}),
}).inferredFields,
}),
}
}
Expand Down Expand Up @@ -210,6 +210,7 @@ export function inferInputObjectStructureFromNodes({
})

// Add sorting (but only to the top level).
let sort
if (typeName) {
const enumValues = buildFieldEnumValues(nodes)

Expand All @@ -218,12 +219,12 @@ export function inferInputObjectStructureFromNodes({
values: enumValues,
})

inferredFields.sortBy = {
sort = {
type: new GraphQLInputObjectType({
name: _.camelCase(`${typeName} sortBy`),
name: _.camelCase(`${typeName} sort`),
fields: {
fields: {
name: _.camelCase(`${typeName} sortByFields`),
name: _.camelCase(`${typeName} sortFields`),
type: new GraphQLNonNull(new GraphQLList(SortByType)),
},
order: {
Expand All @@ -242,5 +243,5 @@ export function inferInputObjectStructureFromNodes({
}
}

return inferredFields
return { inferredFields, sort }
}
18 changes: 10 additions & 8 deletions packages/gatsby/src/schema/run-sift.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,26 @@ module.exports = ({ args, nodes, connection = false, path = `` }) => {
}

const siftArgs = []
_.each(clonedArgs, (v, k) => {
// Ignore connection and sorting args
if (_.includes([`skip`, `limit`, `sortBy`], k)) return
if (clonedArgs.filter) {
_.each(clonedArgs.filter, (v, k) => {
// Ignore connection and sorting args
if (_.includes([`skip`, `limit`, `sort`], k)) return

siftArgs.push(siftifyArgs({ [k]: v }))
})
siftArgs.push(siftifyArgs({ [k]: v }))
})
}

let result = _.isEmpty(siftArgs) ? nodes : sift({ $and: siftArgs }, nodes)

if (!result || !result.length) return

// Sort results.
if (clonedArgs.sortBy) {
const convertedFields = clonedArgs.sortBy.fields.map(field =>
if (clonedArgs.sort) {
const convertedFields = clonedArgs.sort.fields.map(field =>
field.replace(/___/g, `.`)
)

result = _.orderBy(result, convertedFields, clonedArgs.sortBy.order)
result = _.orderBy(result, convertedFields, clonedArgs.sort.order)
}

if (connection) {
Expand Down
5 changes: 3 additions & 2 deletions www/src/pages/404.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from "react"
import Container from "../components/container"

const IndexRoute = React.createClass({
render() {
return (
<div>
<Container>
<h1>Page not found</h1>
</div>
</Container>
)
},
})
Expand Down
Loading

0 comments on commit 54cbbee

Please sign in to comment.