Skip to content

Commit

Permalink
feat(gatsby): Move connection out of sift (gatsbyjs#9508)
Browse files Browse the repository at this point in the history
**Builds on gatsbyjs#9416 . Merge that one before this**

In additional to performing the queries, `run-sift.js` also currently converts the results into connections (if connection query). But as part of gatsbyjs#9338, we will be using `loki` to perform queries too. So we would need to duplicate the connection logic in both query engines.

This PR pulls the connection logic out of run-sift and into `build-node-connections` which makes sense to me as the query engine doesn't need to know about connections. Only about whether it should return one result or many (thus the `firstOnly` flag).

Another benefit is that the query engine no longer needs to understand page dependencies.
  • Loading branch information
Moocar authored and jedrichards committed Nov 1, 2018
1 parent cda5682 commit 4731239
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Unfortunately, in practice, great performance is surprisingly hard to achieve --

Why is that? Increased site complexity often distributes bottlenecks across multiple code points and teams of stakeholders. While performance checklists exist, they’ve ballooned to 40+ items -- making them costly and time-consuming for teams to implement.

As Gatsby's co-founder Kyle Mathews likes to say (paraphrasing Tolstoy):
As Gatsby's co-founder Kyle Mathews likes to say (paraphrasing Tolstoy):

> "All fast websites are alike, but all slow websites are slow in different ways."
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/add-seo-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ const query = graphql`
}
}
}
`;
`
```

## Examples
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/visual-testing-with-storybook.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ title: Visual Testing with Storybook

Knowing your components look as intended in every permutation is not only a great way to test them visually, but also provides "living documentation" for them. This makes it easier for teams to:

1) know what components are available to them in a given project and
2) what props those components accept and what all of the states of that component are.
1. know what components are available to them in a given project and
2. what props those components accept and what all of the states of that component are.

As your project grows over time having this information available will be invaluable. This is the function of the Storybook library. Storybook is a UI development environment for your UI components. With it, you can visualize different states of your UI components and develop them interactively.

Expand Down
44 changes: 9 additions & 35 deletions packages/gatsby-plugin-sharp/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe(`gatsby-plugin-sharp`, () => {
const file = getFileObject(absolutePath)

// used to find all breakpoints in a srcSet string
const findAllBreakpoints = (srcSet) => {
const findAllBreakpoints = srcSet => {
// RegEx to find all occurrences of 'Xw', where 'X' can be any int
const regEx = /[0-9]+w/g
return srcSet.match(regEx)
Expand Down Expand Up @@ -129,12 +129,7 @@ describe(`gatsby-plugin-sharp`, () => {
})

it(`accepts srcSet breakpoints`, async () => {
const srcSetBreakpoints = [
50,
70,
150,
250,
]
const srcSetBreakpoints = [50, 70, 150, 250]
const args = { srcSetBreakpoints }
const result = await fluid({
file: getFileObject(path.join(__dirname, `images/144-density.png`)),
Expand All @@ -143,8 +138,7 @@ describe(`gatsby-plugin-sharp`, () => {

// width of the image tested
const originalWidth = 281
const expected = srcSetBreakpoints
.map((size) => `${size}w`)
const expected = srcSetBreakpoints.map(size => `${size}w`)
// add the original size of `144-density.png`
expected.push(`${originalWidth}w`)

Expand All @@ -154,10 +148,7 @@ describe(`gatsby-plugin-sharp`, () => {
})

it(`should throw on srcSet breakpoints less than 1`, async () => {
const srcSetBreakpoints = [
50,
0,
]
const srcSetBreakpoints = [50, 0]
const args = { srcSetBreakpoints }
const result = fluid({
file: getFileObject(path.join(__dirname, `images/144-density.png`)),
Expand All @@ -168,11 +159,7 @@ describe(`gatsby-plugin-sharp`, () => {
})

it(`ensure maxWidth is in srcSet breakpoints`, async () => {
const srcSetBreakpoints = [
50,
70,
150,
]
const srcSetBreakpoints = [50, 70, 150]
const maxWidth = 200
const args = {
maxWidth,
Expand Down Expand Up @@ -208,8 +195,8 @@ describe(`gatsby-plugin-sharp`, () => {
const originalWidth = 281
const expected = srcSetBreakpoints
// filter out the widths that are larger than the source image width
.filter((size) => size < originalWidth)
.map((size) => `${size}w`)
.filter(size => size < originalWidth)
.map(size => `${size}w`)
// add the original size of `144-density.png`
expected.push(`${originalWidth}w`)

Expand All @@ -221,15 +208,7 @@ describe(`gatsby-plugin-sharp`, () => {
})

it(`prevents duplicate breakpoints`, async () => {
const srcSetBreakpoints = [
50,
50,
100,
100,
100,
250,
250,
]
const srcSetBreakpoints = [50, 50, 100, 100, 100, 250, 250]
const maxWidth = 100
const args = {
maxWidth,
Expand All @@ -241,12 +220,7 @@ describe(`gatsby-plugin-sharp`, () => {
})

const originalWidth = 281
const expected = [
`50w`,
`100w`,
`250w`,
`${originalWidth}w`,
]
const expected = [`50w`, `100w`, `250w`, `${originalWidth}w`]

const actual = findAllBreakpoints(result.srcSet)
expect(actual).toEqual(expect.arrayContaining(expected))
Expand Down
4 changes: 3 additions & 1 deletion packages/gatsby/src/redux/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ const saveState = state => {
pickedState.components = mapToObject(pickedState.components)
pickedState.nodes = mapToObject(pickedState.nodes)

const writeStream = fs.createWriteStream(`${process.cwd()}/.cache/redux-state.json`)
const writeStream = fs.createWriteStream(
`${process.cwd()}/.cache/redux-state.json`
)

new stringify(pickedState, null, 2, true)
.pipe(writeStream)
Expand Down
197 changes: 197 additions & 0 deletions packages/gatsby/src/schema/__tests__/build-node-connections-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
const { graphql, GraphQLObjectType, GraphQLSchema } = require(`graphql`)
const _ = require(`lodash`)
const buildNodeTypes = require(`../build-node-types`)
const buildNodeConnections = require(`../build-node-connections`)

jest.mock(`../../redux/actions/add-page-dependency`, () => {
return {
createPageDependency: jest.fn(),
}
})

const {
createPageDependency,
} = require(`../../redux/actions/add-page-dependency`)

describe(`build-node-connections`, () => {
let schema, store, types, connections

async function runQuery(query) {
let context = { path: `foo` }
let { data, errors } = await graphql(schema, query, context, context)
expect(errors).not.toBeDefined()
return data
}

beforeEach(async () => {
;({ store } = require(`../../redux`))
store.dispatch({ type: `DELETE_CACHE` })
;[
{
id: `p1`,
internal: { type: `Parent` },
hair: `red`,
children: [`c1`, `c2`, `r1`],
},
{
id: `r1`,
internal: { type: `Relative` },
hair: `black`,
children: [],
parent: `p1`,
},
{
id: `c1`,
internal: { type: `Child` },
hair: `brown`,
children: [],
parent: `p1`,
},
{
id: `c2`,
internal: { type: `Child` },
hair: `blonde`,
children: [],
parent: `p1`,
},
].forEach(n => store.dispatch({ type: `CREATE_NODE`, payload: n }))

types = await buildNodeTypes({})
connections = await buildNodeConnections(_.values(types))

schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: `RootQueryType`,
fields: { ...connections, ..._.mapValues(types, `node`) },
}),
})
})

it(`should build connections`, () => {
expect(Object.keys(connections)).toHaveLength(3)
})

it(`should result in a valid queryable schema`, async () => {
let { allParent, allChild, allRelative } = await runQuery(
`
{
allParent(filter: { id: { eq: "p1" } }) {
edges {
node {
hair
}
}
}
allChild(filter: { id: { eq: "c1" } }) {
edges {
node {
hair
}
}
}
allRelative(filter: { id: { eq: "r1" } }) {
edges {
node {
hair
}
}
}
}
`
)
expect(allParent.edges[0].node.hair).toEqual(`red`)
expect(allChild.edges[0].node.hair).toEqual(`brown`)
expect(allRelative.edges[0].node.hair).toEqual(`black`)
})

it(`should link children automatically`, async () => {
let { allParent } = await runQuery(
`
{
allParent(filter: { id: { eq: "p1" } }) {
edges {
node {
children {
id
}
}
}
}
}
`
)
expect(allParent.edges[0].node.children).toBeDefined()
expect(allParent.edges[0].node.children.map(c => c.id)).toEqual([
`c1`,
`c2`,
`r1`,
])
})

it(`should create typed children fields`, async () => {
let { allParent } = await runQuery(
`
{
allParent(filter: { id: { eq: "p1" } }) {
edges {
node {
childrenChild { # lol
id
}
}
}
}
}
`
)
expect(allParent.edges[0].node.childrenChild).toBeDefined()
expect(allParent.edges[0].node.childrenChild.map(c => c.id)).toEqual([
`c1`,
`c2`,
])
})

it(`should create typed child field for singular children`, async () => {
let { allParent } = await runQuery(
`
{
allParent(filter: { id: { eq: "p1" } }) {
edges {
node {
childRelative { # lol
id
}
}
}
}
}
`
)

expect(allParent.edges[0].node.childRelative).toBeDefined()
expect(allParent.edges[0].node.childRelative.id).toEqual(`r1`)
})

it(`should create page dependency`, async () => {
await runQuery(
`
{
allParent(filter: { id: { eq: "p1" } }) {
edges {
node {
childRelative { # lol
id
}
}
}
}
}
`
)

expect(createPageDependency).toHaveBeenCalledWith({
path: `foo`,
connection: `Parent`,
})
})
})
29 changes: 29 additions & 0 deletions packages/gatsby/src/schema/__tests__/build-node-types-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ const { graphql, GraphQLObjectType, GraphQLSchema } = require(`graphql`)
const _ = require(`lodash`)
const buildNodeTypes = require(`../build-node-types`)

jest.mock(`../../redux/actions/add-page-dependency`, () => {
return {
createPageDependency: jest.fn(),
}
})

const {
createPageDependency,
} = require(`../../redux/actions/add-page-dependency`)

describe(`build-node-types`, () => {
let schema, store, types

Expand Down Expand Up @@ -127,4 +137,23 @@ describe(`build-node-types`, () => {
expect(parent.childRelative).toBeDefined()
expect(parent.childRelative.id).toEqual(`r1`)
})

it(`should create page dependency`, async () => {
await runQuery(
`
{
parent(id: { eq: "p1" }) {
childRelative { # lol
id
}
}
}
`
)

expect(createPageDependency).toHaveBeenCalledWith({
path: `foo`,
nodeId: `p1`,
})
})
})
Loading

0 comments on commit 4731239

Please sign in to comment.