Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: gatsbyjs/gatsby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 680b526156b0b22b6a6cd229612359e59874a526
Choose a base ref
...
head repository: gatsbyjs/gatsby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f12c34cf83af26fe3c16d8ad995eeb552dc7ab0e
Choose a head ref
  • 2 commits
  • 18 files changed
  • 3 contributors

Commits on Jun 29, 2022

  1. fix(gatsby): fix potentially wrong query results when querying fields…

    … with custom resolvers (#35369) (#36003)
    
    Co-authored-by: Ward Peeters <ward@coding-tech.com>
    (cherry picked from commit 69824f6)
    
    Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
    gatsbybot and pieh authored Jun 29, 2022
    Copy the full SHA
    c5475b7 View commit details
  2. chore(release): Publish

     - gatsby@4.17.2
    tyhopp committed Jun 29, 2022
    Copy the full SHA
    f12c34c View commit details
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -550,6 +550,7 @@ jobs:
no_output_timeout: 15m
environment:
NODE_OPTIONS: --max-old-space-size=2048
GATSBY_EXPERIMENTAL_LMDB_STORE: 1
GENERATE_JEST_REPORT: "true"
JEST_JUNIT_OUTPUT_DIR: ./test-results/jest-node/
JEST_JUNIT_OUTPUT_NAME: results.xml
2 changes: 1 addition & 1 deletion packages/gatsby/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "gatsby",
"description": "Blazing fast modern site generator for React",
"version": "4.17.1",
"version": "4.17.2",
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"bin": {
"gatsby": "./cli.js"
95 changes: 28 additions & 67 deletions packages/gatsby/src/datastore/in-memory/indexing.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { store } from "../../redux"
import { IGatsbyNode } from "../../redux/types"
import {
IDbQueryElemMatch,
@@ -9,6 +8,7 @@ import {
import { getDataStore, getNode } from "../"
import _ from "lodash"
import { getValueAt } from "../../utils/get-value-at"
import { getResolvedFields } from "../../schema/utils"

// Only list supported ops here. "CacheableFilterOp"
// TODO: merge with DbComparator ?
@@ -29,6 +29,7 @@ type GatsbyNodeID = string
export interface IGatsbyNodePartial {
id: GatsbyNodeID
internal: {
type: string
counter: number
}
gatsbyNodePartialInternalData: {
@@ -88,30 +89,29 @@ export const getGatsbyNodePartial = (
)
let fullNodeObject: IGatsbyNode | undefined =
node.gatsbyNodePartialInternalData ? undefined : (node as IGatsbyNode)
let resolvedNodeFields

for (const dottedField of sortFieldIds) {
if (dottedField in node) {
dottedFields[dottedField] = node[dottedField]
} else {
// if we haven't gotten the full node object, fetch it once
if (!fullNodeObject) {
fullNodeObject = getNode(node.id)!
}
if (dottedField.startsWith(`__gatsby_resolved.`)) {
if (!resolvedNodeFields) {
resolvedNodeFields = getResolvedFields(node)
}

if (
dottedField.startsWith(`__gatsby_resolved.`) &&
!fullNodeObject.__gatsby_resolved
) {
const typeName = fullNodeObject.internal.type
const resolvedNodes = store.getState().resolvedNodesCache.get(typeName)
const resolved = resolvedNodes?.get(fullNodeObject.id)
if (resolved !== undefined) {
fullNodeObject.__gatsby_resolved = resolved
dottedFields[dottedField] = getValueAt(
resolvedNodeFields,
dottedField.slice(`__gatsby_resolved.`.length)
)
} else {
// if we haven't gotten the full node object, fetch it once
// use the full node object to fetch the value
if (!fullNodeObject) {
fullNodeObject = getNode(node.id)!
}
dottedFields[dottedField] = getValueAt(fullNodeObject, dottedField)
}

// use the full node object to fetch the value
dottedFields[dottedField] = getValueAt(fullNodeObject, dottedField)
}
}

@@ -120,6 +120,7 @@ export const getGatsbyNodePartial = (
id: node.id,
internal: {
counter: node.internal.counter,
type: node.internal.type,
},
gatsbyNodePartialInternalData: {
indexFields: fieldsToStore,
@@ -293,9 +294,6 @@ export const ensureIndexByQuery = (
indexFields: Array<string>,
resolvedFields: Record<string, any>
): void => {
const state = store.getState()
const resolvedNodesCache = state.resolvedNodesCache

const filterCache: IFilterCache = {
op,
byValue: new Map<FilterValueNullable, Array<IGatsbyNodePartial>>(),
@@ -315,7 +313,6 @@ export const ensureIndexByQuery = (
node,
chain: filterPath,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
})
@@ -334,7 +331,6 @@ export const ensureIndexByQuery = (
node,
chain: filterPath,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
})
@@ -355,8 +351,6 @@ export function ensureEmptyFilterCache(
// We want to cache the result since it's basically a list of nodes by type(s)
// There are sites that have multiple queries which are empty

const state = store.getState()
const resolvedNodesCache = state.resolvedNodesCache
const orderedByCounter: Array<IGatsbyNodePartial> = []

filtersCache.set(filterCacheKey, {
@@ -371,14 +365,6 @@ export function ensureEmptyFilterCache(
getDataStore()
.iterateNodesByType(nodeTypeNames[0])
.forEach(node => {
if (!node.__gatsby_resolved) {
const typeName = node.internal.type
const resolvedNodes = resolvedNodesCache.get(typeName)
const resolved = resolvedNodes?.get(node.id)
if (resolved !== undefined) {
node.__gatsby_resolved = resolved
}
}
orderedByCounter.push(
getGatsbyNodePartial(node, indexFields, resolvedFields)
)
@@ -390,14 +376,6 @@ export function ensureEmptyFilterCache(
.iterateNodes()
.forEach(node => {
if (nodeTypeNames.includes(node.internal.type)) {
if (!node.__gatsby_resolved) {
const typeName = node.internal.type
const resolvedNodes = resolvedNodesCache.get(typeName)
const resolved = resolvedNodes?.get(node.id)
if (resolved !== undefined) {
node.__gatsby_resolved = resolved
}
}
orderedByCounter.push(
getGatsbyNodePartial(node, indexFields, resolvedFields)
)
@@ -414,33 +392,28 @@ function addNodeToFilterCache({
node,
chain,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
valueOffset = node,
}: {
node: IGatsbyNode
chain: Array<string>
filterCache: IFilterCache
resolvedNodesCache: Map<string, any>
indexFields: Array<string>
resolvedFields: Record<string, any>
valueOffset?: any
}): void {
// There can be a filter that targets `__gatsby_resolved` so fix that first
if (!node.__gatsby_resolved) {
const typeName = node.internal.type
const resolvedNodes = resolvedNodesCache.get(typeName)
node.__gatsby_resolved = resolvedNodes?.get(node.id)
}

// - for plain query, valueOffset === node
// - for elemMatch, valueOffset is sub-tree of the node to continue matching
let v = valueOffset as any
let i = 0
while (i < chain.length && v) {
const nextProp = chain[i++]
v = v[nextProp]
if (i === 1 && nextProp === `__gatsby_resolved`) {
v = getResolvedFields(v)
} else {
v = v[nextProp]
}
}

if (
@@ -503,9 +476,6 @@ export const ensureIndexByElemMatch = (
// Given an elemMatch filter, generate the cache that contains all nodes that
// matches a given value for that sub-query

const state = store.getState()
const { resolvedNodesCache } = state

const filterCache: IFilterCache = {
op,
byValue: new Map<FilterValueNullable, Array<IGatsbyNodePartial>>(),
@@ -522,7 +492,6 @@ export const ensureIndexByElemMatch = (
valueAtCurrentStep: node,
filter,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
})
@@ -541,7 +510,6 @@ export const ensureIndexByElemMatch = (
valueAtCurrentStep: node,
filter,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
})
@@ -556,32 +524,27 @@ function addNodeToBucketWithElemMatch({
valueAtCurrentStep, // Arbitrary step on the path inside the node
filter,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
}: {
node: IGatsbyNode
valueAtCurrentStep: any // Arbitrary step on the path inside the node
filter: IDbQueryElemMatch
filterCache: IFilterCache
resolvedNodesCache
indexFields: Array<string>
resolvedFields: Record<string, any>
}): void {
// There can be a filter that targets `__gatsby_resolved` so fix that first
if (!node.__gatsby_resolved) {
const typeName = node.internal.type
const resolvedNodes = resolvedNodesCache.get(typeName)
node.__gatsby_resolved = resolvedNodes?.get(node.id)
}

const { path, nestedQuery } = filter

// Find the value to apply elemMatch to
let i = 0
while (i < path.length && valueAtCurrentStep) {
const nextProp = path[i++]
valueAtCurrentStep = valueAtCurrentStep[nextProp]
if (i === 1 && nextProp === `__gatsby_resolved`) {
valueAtCurrentStep = getResolvedFields(valueAtCurrentStep)
} else {
valueAtCurrentStep = valueAtCurrentStep[nextProp]
}
}

if (path.length !== i) {
@@ -606,7 +569,6 @@ function addNodeToBucketWithElemMatch({
valueAtCurrentStep: elem,
filter: nestedQuery,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
})
@@ -616,7 +578,6 @@ function addNodeToBucketWithElemMatch({
node,
chain: nestedQuery.path,
filterCache,
resolvedNodesCache,
indexFields,
resolvedFields,
valueOffset: elem,
1 change: 0 additions & 1 deletion packages/gatsby/src/redux/persist.ts
Original file line number Diff line number Diff line change
@@ -165,7 +165,6 @@ function prepareCacheFolder(
counter: 0,
owner: ``,
},
__gatsby_resolved: {},
fields: [],
}
nodesMap.set(dummyNode.id, dummyNode)
5 changes: 1 addition & 4 deletions packages/gatsby/src/redux/reducers/inference-metadata.ts
Original file line number Diff line number Diff line change
@@ -13,10 +13,7 @@ import { typesWithoutInference } from "../../schema/types/type-defs"

import { IGatsbyState, ActionsUnion } from "../types"

const ignoredFields: Set<string> = new Set([
...NodeInterfaceFields,
`__gatsby_resolved`,
])
const ignoredFields: Set<string> = new Set(NodeInterfaceFields)

const initialTypeMetadata = (): { ignoredFields: Set<string> } => {
return { ignoredFields }
24 changes: 23 additions & 1 deletion packages/gatsby/src/redux/reducers/resolved-nodes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import merge from "lodash/merge"
import { IGatsbyState, ActionsUnion } from "../types"

export const resolvedNodesCacheReducer = (
@@ -12,7 +13,28 @@ export const resolvedNodesCacheReducer = (

case `SET_RESOLVED_NODES`: {
const { key, nodes } = action.payload
state.set(key, nodes)
const existingResolvedNodes = state.get(key)
if (existingResolvedNodes) {
// merge new resolved fields for given type with previously existing ones
for (const [nodeId, resolvedFields] of nodes.entries()) {
const previouslyResolvedNodeFields = existingResolvedNodes.get(nodeId)
if (previouslyResolvedNodeFields) {
// merge new resolved fields for given node id with previously existing ones
existingResolvedNodes.set(
nodeId,
merge(previouslyResolvedNodeFields, resolvedFields)
)
} else {
// we didn't have any resolved fields for this node id, so we can just set new
// ones as-is
existingResolvedNodes.set(nodeId, resolvedFields)
}
}
} else {
// we didn't have resolved fields for this type yet, so
// we can just set it
state.set(key, nodes)
}
return state
}

1 change: 0 additions & 1 deletion packages/gatsby/src/redux/types.ts
Original file line number Diff line number Diff line change
@@ -121,7 +121,6 @@ export interface IGatsbyNode {
content?: string
description?: string
}
__gatsby_resolved: any // TODO
[key: string]: unknown
fields: Array<string>
}
Original file line number Diff line number Diff line change
@@ -155,6 +155,7 @@ async function queryResult(nodes, query) {
inferenceMetadata: store.getState().inferenceMetadata,
})
store.dispatch({ type: `SET_SCHEMA`, payload: schema })
store.dispatch({ type: `SET_SCHEMA_COMPOSER`, payload: schemaComposer })

const context = { path: `foo` }
return graphql(schema, query, undefined, {
4 changes: 2 additions & 2 deletions packages/gatsby/src/schema/__tests__/fixtures/queries.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ const path = require(`path`)

const dir = os.platform() === "win32" ? "C:/Users/test/site" : "/home/test/site"

const nodes = [
const getTestNodes = () => [
{
id: `file1`,
parent: null,
@@ -163,4 +163,4 @@ const nodes = [
},
]

module.exports = nodes
module.exports = getTestNodes
Loading