@@ -20,6 +20,7 @@ const initialState = (): IGatsbyState["queries"] => {
2020 return {
2121 byNode : new Map < NodeId , Set < QueryId > > ( ) ,
2222 byConnection : new Map < ConnectionName , Set < QueryId > > ( ) ,
23+ queryNodes : new Map < QueryId , Set < NodeId > > ( ) ,
2324 trackedQueries : new Map < QueryId , IQueryState > ( ) ,
2425 trackedComponents : new Map < ComponentPath , IComponentState > ( ) ,
2526 deletedQueries : new Set < QueryId > ( ) ,
@@ -88,12 +89,8 @@ export function queriesReducer(
8889 for ( const component of state . trackedComponents . values ( ) ) {
8990 component . pages . delete ( queryId )
9091 }
91- for ( const nodeQueries of state . byNode . values ( ) ) {
92- nodeQueries . delete ( queryId )
93- }
94- for ( const connectionQueries of state . byConnection . values ( ) ) {
95- connectionQueries . delete ( queryId )
96- }
92+ state = clearNodeDependencies ( state , queryId )
93+ state = clearConnectionDependencies ( state , queryId )
9794 state . trackedQueries . delete ( queryId )
9895 }
9996 state . deletedQueries . clear ( )
@@ -110,12 +107,12 @@ export function queriesReducer(
110107 }
111108 if ( component . query !== query ) {
112109 // Invalidate all pages associated with a component when query text changes
113- component . pages . forEach ( queryId => {
110+ for ( const queryId of component . pages ) {
114111 const query = state . trackedQueries . get ( queryId )
115112 if ( query ) {
116113 query . dirty = setFlag ( query . dirty , FLAG_DIRTY_TEXT )
117114 }
118- } )
115+ }
119116 component . query = query
120117 }
121118 return state
@@ -144,27 +141,18 @@ export function queriesReducer(
144141 case `CREATE_COMPONENT_DEPENDENCY` : {
145142 const { path : queryId , nodeId, connection } = action . payload
146143 if ( nodeId ) {
147- const queryIds = state . byNode . get ( nodeId ) ?? new Set < QueryId > ( )
148- queryIds . add ( queryId )
149- state . byNode . set ( nodeId , queryIds )
144+ state = addNodeDependency ( state , queryId , nodeId )
150145 }
151146 if ( connection ) {
152- const queryIds =
153- state . byConnection . get ( connection ) ?? new Set < QueryId > ( )
154- queryIds . add ( queryId )
155- state . byConnection . set ( connection , queryIds )
147+ state = addConnectionDependency ( state , queryId , connection )
156148 }
157149 return state
158150 }
159151 case `QUERY_START` : {
160152 // Reset data dependencies as they will be updated when running the query
161153 const { path } = action . payload
162- state . byNode . forEach ( queryIds => {
163- queryIds . delete ( path )
164- } )
165- state . byConnection . forEach ( queryIds => {
166- queryIds . delete ( path )
167- } )
154+ state = clearNodeDependencies ( state , path )
155+ state = clearConnectionDependencies ( state , path )
168156 return state
169157 }
170158 case `CREATE_NODE` :
@@ -177,18 +165,18 @@ export function queriesReducer(
177165 const queriesByConnection =
178166 state . byConnection . get ( node . internal . type ) ?? [ ]
179167
180- queriesByNode . forEach ( queryId => {
168+ for ( const queryId of queriesByNode ) {
181169 const query = state . trackedQueries . get ( queryId )
182170 if ( query ) {
183171 query . dirty = setFlag ( query . dirty , FLAG_DIRTY_DATA )
184172 }
185- } )
186- queriesByConnection . forEach ( queryId => {
173+ }
174+ for ( const queryId of queriesByConnection ) {
187175 const query = state . trackedQueries . get ( queryId )
188176 if ( query ) {
189177 query . dirty = setFlag ( query . dirty , FLAG_DIRTY_DATA )
190178 }
191- } )
179+ }
192180 return state
193181 }
194182 case `PAGE_QUERY_RUN` : {
@@ -213,6 +201,69 @@ export function hasFlag(allFlags: number, flag: number): boolean {
213201 return allFlags >= 0 && ( allFlags & flag ) > 0
214202}
215203
204+ function addNodeDependency (
205+ state : IGatsbyState [ "queries" ] ,
206+ queryId : QueryId ,
207+ nodeId : NodeId
208+ ) : IGatsbyState [ "queries" ] {
209+ // Perf: using two-side maps.
210+ // Without additional `queryNodes` map we would have to loop through
211+ // all existing nodes in `clearNodeDependencies` to delete node <-> query dependency
212+ let nodeQueries = state . byNode . get ( nodeId )
213+ if ( ! nodeQueries ) {
214+ nodeQueries = new Set < QueryId > ( )
215+ state . byNode . set ( nodeId , nodeQueries )
216+ }
217+ let queryNodes = state . queryNodes . get ( queryId )
218+ if ( ! queryNodes ) {
219+ queryNodes = new Set < NodeId > ( )
220+ state . queryNodes . set ( queryId , queryNodes )
221+ }
222+ nodeQueries . add ( queryId )
223+ queryNodes . add ( nodeId )
224+ return state
225+ }
226+
227+ function addConnectionDependency (
228+ state : IGatsbyState [ "queries" ] ,
229+ queryId : QueryId ,
230+ connection : ConnectionName
231+ ) : IGatsbyState [ "queries" ] {
232+ // Note: not using two-side maps for connections as associated overhead
233+ // for small number of elements is greater then benefits, so no perf. gains
234+ let queryIds = state . byConnection . get ( connection )
235+ if ( ! queryIds ) {
236+ queryIds = new Set ( )
237+ state . byConnection . set ( connection , queryIds )
238+ }
239+ queryIds . add ( queryId )
240+ return state
241+ }
242+
243+ function clearNodeDependencies (
244+ state : IGatsbyState [ "queries" ] ,
245+ queryId : QueryId
246+ ) : IGatsbyState [ "queries" ] {
247+ const queryNodeIds = state . queryNodes . get ( queryId ) ?? new Set ( )
248+ for ( const nodeId of queryNodeIds ) {
249+ const nodeQueries = state . byNode . get ( nodeId )
250+ if ( nodeQueries ) {
251+ nodeQueries . delete ( queryId )
252+ }
253+ }
254+ return state
255+ }
256+
257+ function clearConnectionDependencies (
258+ state : IGatsbyState [ "queries" ] ,
259+ queryId : QueryId
260+ ) : IGatsbyState [ "queries" ] {
261+ for ( const [ , queryIds ] of state . byConnection ) {
262+ queryIds . delete ( queryId )
263+ }
264+ return state
265+ }
266+
216267function registerQuery (
217268 state : IGatsbyState [ "queries" ] ,
218269 queryId : QueryId
0 commit comments