Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] graphql schema refactor #10995

Closed
wants to merge 124 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
0c0fb00
Schema refactor
stefanprobst Nov 12, 2018
e8034c2
Remove some comments
stefanprobst Nov 28, 2018
5755b7e
Add check
stefanprobst Nov 28, 2018
143a1ac
Document Date constructor weirdness
stefanprobst Nov 28, 2018
af784ed
Fix query benchmark
stefanprobst Nov 28, 2018
6dcc7da
Fix isDate
stefanprobst Nov 29, 2018
4d4ef26
Deep merge inferred fields
stefanprobst Nov 29, 2018
15ec84c
Ignore node interface fields in getExampleValue
stefanprobst Nov 29, 2018
13b2686
Don't do full query when linked by id
stefanprobst Nov 30, 2018
d6898ce
Export types from graphql-compose
stefanprobst Dec 5, 2018
b6f7298
Add tests for utils, snakecase sortkeys
stefanprobst Dec 7, 2018
c05fb76
Prefer float
stefanprobst Dec 9, 2018
c0b58fe
Add isDefined util
stefanprobst Dec 9, 2018
dbe8218
Add test for getExampleValue
stefanprobst Dec 9, 2018
a371f51
Add snapshot
stefanprobst Dec 9, 2018
97b7251
Handle type mismatches when merging fields
stefanprobst Dec 10, 2018
62297dd
Infer mix of dates and strings as strings
stefanprobst Dec 10, 2018
7151dc9
Remove unused file
stefanprobst Dec 10, 2018
6a644f6
Add comments
stefanprobst Dec 10, 2018
4ec77ea
Remove alternative quey engines
stefanprobst Dec 10, 2018
738e2fe
Allow adding custom resolve functions
stefanprobst Dec 11, 2018
26f4a2a
Handle String objects in IsObject
stefanprobst Dec 11, 2018
99101ce
Remove unneeded assignment
stefanprobst Dec 11, 2018
9da27c4
Add dummy tests
stefanprobst Dec 11, 2018
ec5ed4e
Add test for type-conflict-reporter
stefanprobst Dec 11, 2018
91ee40b
Fix Date handling
stefanprobst Dec 11, 2018
e777e43
Update snapshot
stefanprobst Dec 11, 2018
9a3197a
Add tests for type inference
stefanprobst Dec 11, 2018
c721dcf
Serialize String objects in snapshot
stefanprobst Dec 12, 2018
0374b1e
Handle enums in input filter
stefanprobst Dec 17, 2018
b343390
Fix sorting
stefanprobst Dec 18, 2018
77df044
Remove unused files
stefanprobst Dec 18, 2018
b7933b1
Support regex flags
stefanprobst Dec 18, 2018
a0c02a0
Handle array of arrays
stefanprobst Dec 21, 2018
ab9ba20
Small fixes
stefanprobst Dec 22, 2018
de307d6
Typo
stefanprobst Dec 23, 2018
0dd7788
Add tests
stefanprobst Dec 23, 2018
df8f46b
Fix custom resolvers (WIP)
stefanprobst Dec 24, 2018
9201989
Allow returning object literal
stefanprobst Dec 24, 2018
2e073f7
Fix test
stefanprobst Dec 25, 2018
97c7df7
Get component path from source
stefanprobst Dec 25, 2018
1bcf992
Adjust test
stefanprobst Dec 25, 2018
75f8a72
Update graphql-compose
stefanprobst Dec 25, 2018
928f7ea
Fix schema update for SitePage
stefanprobst Dec 25, 2018
f4455d7
Get nodes for query with link resolvers
stefanprobst Dec 25, 2018
e538530
Comments
stefanprobst Dec 26, 2018
7522949
Use executable schema
stefanprobst Dec 26, 2018
0fc3bf8
Fix schema stitching
stefanprobst Dec 28, 2018
823ea6c
Cache nodes during bootstrap
stefanprobst Dec 28, 2018
f0a9c09
Only cache in production
stefanprobst Dec 28, 2018
dd5c9f0
Fix import, add comments
stefanprobst Dec 28, 2018
1311ae5
Pass parentType to field resolver
stefanprobst Dec 28, 2018
9b4c380
Add test
stefanprobst Dec 28, 2018
a80357b
Update
stefanprobst Dec 28, 2018
f3dffb4
Cache getNodesByType during bootstrap
stefanprobst Dec 29, 2018
5d64201
Fix
stefanprobst Dec 29, 2018
66e2541
Add typeDefs for SitePage and SitePlugin
stefanprobst Dec 29, 2018
faecc61
Add benchmark
stefanprobst Dec 29, 2018
4d00324
Add benchmark
stefanprobst Dec 29, 2018
59dfd72
Fix
stefanprobst Dec 29, 2018
4f69e32
Disable mergeSchemas for now
stefanprobst Dec 30, 2018
5e76979
Add simple schema merging
stefanprobst Dec 31, 2018
7cdf052
Update snapshot
stefanprobst Dec 31, 2018
e9c8ec9
Remove comments
stefanprobst Dec 31, 2018
3c0cf97
Resolve with default values
stefanprobst Dec 31, 2018
effce54
Add invariant
stefanprobst Dec 31, 2018
5c76114
Simplify further
stefanprobst Jan 2, 2019
0a0e125
Add some more tests
stefanprobst Jan 3, 2019
87318f6
Expand Internal type
stefanprobst Jan 3, 2019
5aa8946
Add hasResolvers util
stefanprobst Jan 3, 2019
a1f8290
Add nodesByType redux namespace
stefanprobst Jan 3, 2019
157b4ca
Remove pluginOptions from type defs
stefanprobst Jan 3, 2019
f6af5d1
Internal type defs
stefanprobst Jan 3, 2019
39a738d
Add test
stefanprobst Jan 3, 2019
0f4beba
Add test
stefanprobst Jan 4, 2019
d5069d5
Add test
stefanprobst Jan 4, 2019
3e22aa2
Fix nodesByType namespace
stefanprobst Jan 4, 2019
fb99bbd
Update dateformat
stefanprobst Jan 4, 2019
b085de3
Add @dateformat test
stefanprobst Jan 5, 2019
4654884
Update Sift for correct Date comparisons
stefanprobst Jan 5, 2019
efa53a0
Don't convert Date to string
stefanprobst Jan 5, 2019
bf5ca6c
Sift update
stefanprobst Jan 5, 2019
2b3ba04
Add test
stefanprobst Jan 6, 2019
e12e5f4
Use date-fns v2
stefanprobst Jan 6, 2019
a3bb5e5
rename default args
stefanprobst Jan 7, 2019
40c3a8f
Fix children query
stefanprobst Jan 7, 2019
ef45772
Add test
stefanprobst Jan 7, 2019
cacddb8
Call resolver for not-yet-existing fields
stefanprobst Jan 7, 2019
f68616b
Add test
stefanprobst Jan 7, 2019
3038bfd
Pass resolvers with context
stefanprobst Jan 7, 2019
642d808
Hoist context
stefanprobst Jan 8, 2019
3ce4906
Remove unused file
stefanprobst Jan 8, 2019
3c8c63f
Fix 10557
stefanprobst Jan 8, 2019
6eea7cd
Add @dateformat to inferred Date fields
stefanprobst Jan 8, 2019
e75df79
Lint
stefanprobst Jan 8, 2019
fa8f7b5
Add difference option to @dateformat
stefanprobst Jan 8, 2019
f128fe6
Update snapshot
stefanprobst Jan 8, 2019
0197d0e
Mostly comments
stefanprobst Jan 9, 2019
b547bec
Update snapshot
stefanprobst Jan 9, 2019
093e996
[compatibility] Don't uppercase sort fields enum values
stefanprobst Jan 9, 2019
280da26
Don't create page dependencies in getNodesForQuery
stefanprobst Jan 9, 2019
82f90ac
Pin date-fns at alpha (needs rework to parseISO change)
stefanprobst Jan 9, 2019
651ea88
Fix
stefanprobst Jan 9, 2019
8e9488b
Expand test
stefanprobst Jan 9, 2019
4ced3fa
[compatibility] Don't put filter arg on filter field for findOne queries
stefanprobst Jan 9, 2019
55ec9b5
[compatibility] check mime-type and is-relative-url for File nodes
stefanprobst Jan 9, 2019
974cd10
Fix tests
stefanprobst Jan 9, 2019
d86629c
Use getTypes
stefanprobst Jan 9, 2019
986c5fb
Add test
stefanprobst Jan 10, 2019
8824f4c
Don't keep relativePath
stefanprobst Jan 10, 2019
2cb164a
Lint
stefanprobst Jan 10, 2019
3614b5e
Handle relativeDirectory
stefanprobst Jan 10, 2019
84e47ad
Refactor
stefanprobst Jan 10, 2019
3dcea52
Fix isFile for Windows
stefanprobst Jan 10, 2019
5087d5b
Update graphql-compose
stefanprobst Jan 10, 2019
f4ec061
[compatibility] Fix specialcasing relativePath
stefanprobst Jan 10, 2019
0027a75
Add typedefs for File
stefanprobst Jan 10, 2019
77ed78c
Only infer File when it is registered
stefanprobst Jan 10, 2019
211dcd7
Fix test
stefanprobst Jan 10, 2019
c9123ad
Add failing test
stefanprobst Jan 10, 2019
b0ac1e2
Fix some tests and dependencies (#1)
freiksenet Jan 10, 2019
ea3a27e
Fix test
stefanprobst Jan 10, 2019
1592f99
Fix test
stefanprobst Jan 11, 2019
af1c76e
Fix
stefanprobst Jan 11, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions benchmarks/query/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ exports.sourceNodes = ({ actions: { createNode } }) => {
id,
parent: null,
children: [],
custom: {
nestedId: id,
},
internal: {
type: typeName,
nestedId: id,
content: faker.lorem.word(),
contentDigest: step.toString(),
},
Expand Down Expand Up @@ -68,7 +70,7 @@ export default ({ data }) => {

export const query = graphql\`
query($id: String!) {
${lowerTypeName}(internal: { nestedId: { eq: $id } }) {
${lowerTypeName}(filter: { custom: { nestedId: { eq: $id } } }) {
id
}
}
Expand All @@ -79,12 +81,8 @@ export const query = graphql\`
function allTypeQuery(typeName) {
return `
{
all${typeName}(sort: { fields: [id] }) {
edges {
node {
id
}
}
all${typeName}(sort: { fields: [ID] }) {
id
}
}
`
Expand All @@ -97,8 +95,7 @@ async function createTypePages({ graphql, actions }, typeName) {
const templateFilename = `./.cache/${typeName}Template.js`
fs.writeFileSync(templateFilename, templateSrc)
let result = await graphql(allTypeQuery(typeName))
_.forEach(result.data[`all${typeName}`].edges, edge => {
const { node } = edge
_.forEach(result.data[`all${typeName}`], node => {
actions.createPage({
path: `/${typeName}/${node.id}/`,
component: require.resolve(templateFilename),
Expand Down
99 changes: 99 additions & 0 deletions benchmarks/schema/create-posts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/node
const fs = require(`fs-extra`)
const path = require(`path`)
const faker = require(`faker`)
const fetch = require(`node-fetch`)
const YAML = require(`yamljs`)

const BASEPATH = `./data`
fs.ensureDirSync(BASEPATH)
fs.emptyDirSync(BASEPATH)

const IMAGE_BASEPATH = `./static/images`
fs.ensureDirSync(IMAGE_BASEPATH)
fs.emptyDirSync(IMAGE_BASEPATH)

const NUM_AUTHORS = 1000
const NUM_TAGS = 100
const NUM_POSTS = 10000
const NUM_IMAGES = 2

const range = num => [...Array(num).keys()]
const pick = arr => arr[Math.floor(Math.random() * arr.length)]

const imageDigits = NUM_IMAGES.toString().length
const createImage = async num => {
const url = faker.image.avatar()
const response = await fetch(url)
const image = await response.buffer()
const filename = path.join(
IMAGE_BASEPATH,
num.toString().padStart(imageDigits, `0`) + `.jpg`
)
fs.writeFileSync(filename, image)
return `../` + filename
}

const createAuthor = images => {
return {
name: faker.name.lastName(),
firstname: faker.name.firstName(),
email: faker.internet.email(),
image: pick(images),
}
}

const createFrontmatter = (authors, tags) => {
return {
title: faker.lorem.sentence(),
date: faker.date.past().toJSON(),
published: pick([true, false]),
authors: range(2).map(() => pick(authors).email),
tags: range(3).map(() => pick(tags)),
}
}

const createMarkdown = async (authors, tags) => {
const frontmatter = await createFrontmatter(authors, tags)
const heading = faker.lorem.sentence()
const text = faker.lorem.paragraph()
return `---
title: ${frontmatter.title}
date: ${frontmatter.date}
published: ${frontmatter.published}
authors: [${frontmatter.authors.join(`, `)}]
tags: [${frontmatter.tags.join(`, `)}]
---

# ${heading}

${text}
`
}

const digits = NUM_POSTS.toString().length
const createFile = (content, num) =>
fs.writeFile(
path.join(BASEPATH, num.toString().padStart(digits, `0`) + `.md`),
content,
err => {
if (err) throw err
}
)

Promise.all(range(NUM_IMAGES).map(createImage))
.then(images =>
Promise.all(range(NUM_AUTHORS).map(() => createAuthor(images)))
)
.then(authors => {
fs.writeFileSync(
path.join(BASEPATH, `authors.yaml`),
YAML.stringify(authors)
)
const tags = range(NUM_TAGS).map(faker.lorem.word)
return Promise.all(
range(NUM_POSTS).map(() => createMarkdown(authors, tags))
)
})
.then(posts => Promise.all(posts.map(createFile)))
.then(() => console.log(`Done`))
166 changes: 166 additions & 0 deletions benchmarks/schema/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
const fs = require(`fs`)
const path = require(`path`)
const mime = require(`mime/lite`)
const YAML = require(`yamljs`)

const DATA_DIR = `./data`
const IMAGE_DIR = `./static/images`

const isObject = obj => obj && typeof obj === `object` && !Array.isArray(obj)

const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)

const addTypeDefs = ({ addTypeDefs }) => {
const typeDefs = `
type File implements Node {
name: String!
dir: String
absolutePath: String
}

type AuthorsYaml implements Node {
name: String
firstname: String
email: String
image: File @link(by: "relativePath")
}

type Frontmatter {
title: String
date: Date @dateformat(defaultFormat: "YYYY")
published: Boolean
authors: [AuthorsYaml] @link(by: "email")
}

type Markdown implements Node {
md: String
frontmatter: Frontmatter
}
`
addTypeDefs(typeDefs)
}

const sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
const { createNode } = actions
const dirs = [path.resolve(DATA_DIR), path.resolve(IMAGE_DIR)]
dirs.forEach(dir => {
const files = fs.readdirSync(dir, { withFileTypes: true })
files.forEach(file => {
if (!file.isFile()) return
const { name } = file
const absolutePath = path.join(dir, name)
const relativeDir = dir.startsWith(`static`)
? path.relative(__dirname, dir)
: path.relative(path.join(__dirname, `static`), dir)
const relativePath = path.join(relativeDir, name)
const mediaType = mime.getType(absolutePath)
const content = mediaType.startsWith(`text`)
? fs.readFileSync(absolutePath, `utf-8`)
: ``
createNode({
id: createNodeId(`File ${name}`),
parent: null,
children: [],
internal: {
type: `File`,
mediaType,
content,
contentDigest: createContentDigest(content),
},
name,
dir,
relativeDir,
absolutePath,
relativePath,
})
})
})
}

const onCreateNode = ({ actions, node, createNodeId, createContentDigest }) => {
const { createNode, createParentChildLink } = actions
const { id, name, internal } = node
const { content } = internal

switch (node.internal.mediaType) {
case `text/markdown`: {
const [frontmatter, md] = content.split(`---`).filter(Boolean)
const child = {
id: createNodeId(`Markdown ${id}`),
parent: id,
children: [],
internal: {
type: `Markdown`,
content,
contentDigest: createContentDigest(content),
},
frontmatter: YAML.parse(frontmatter),
md,
}
createNode(child)
createParentChildLink({ parent: node, child })
break
}

case `text/yaml`: {
const type = capitalize(name.slice(0, name.lastIndexOf(`.`))) + `Yaml`
const createYamlNode = (fields, i) => {
if (!isObject(fields)) return
const child = {
id: createNodeId(`${type} [${i}] ${id}`),
parent: id,
children: [],
internal: {
type,
content,
contentDigest: createContentDigest(content),
},
...fields,
}
createNode(child)
createParentChildLink({ parent: node, child })
}
const parsed = YAML.parse(content)
Array.isArray(parsed)
? parsed.forEach(createYamlNode)
: createYamlNode(parsed)
break
}

default:
}
}

const createPages = ({ actions, graphql }) => {
const { createPage } = actions
return graphql(`
query {
allMarkdown(
sort: { fields: [FRONTMATTER___DATE], order: DESC }
filter: { frontmatter: { title: { ne: null } } }
) {
id
}
}
`).then(({ errors, data }) => {
if (errors) throw errors
createPage({
path: `/`,
component: path.resolve(`./templates/index.js`),
})
data.allMarkdown.forEach(({ id }) => {
createPage({
path: id,
component: path.resolve(`./templates/template.js`),
context: { id },
})
})
})
}

module.exports = {
addTypeDefs,
createPages,
onCreateNode,
sourceNodes,
}
20 changes: 20 additions & 0 deletions benchmarks/schema/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "playground",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"date-fns": "^1.30.1",
"faker": "^4.1.0",
"gatsby": "^2.0.76",
"graphql-compose": "^5.4.0",
"mime": "^2.4.0",
"node-fetch": "^2.3.0",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"yamljs": "^0.3.0"
},
"browserslist": [
"chrome > 68"
]
}
25 changes: 25 additions & 0 deletions benchmarks/schema/templates/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react"
import { graphql } from "gatsby"

const IndexPage = ({ data }) => (
<>
<h1>Pages</h1>
<ul>
{data.allMarkdown.map(({ id }) => (
<li key={id}>
<a href={id}>Page {id}</a>
</li>
))}
</ul>
</>
)

export default IndexPage

export const query = graphql`
{
allMarkdown {
id
}
}
`
Loading