@@ -27,8 +27,8 @@ type Value = string | number | boolean | null | undefined | object | Value[];
2727 */
2828export interface QueryResultData {
2929 [ key : string ] : Value ;
30- __typename : string ;
31- __id : string ;
30+ __typename ? : string ;
31+ __id ? : string ;
3232}
3333
3434/**
@@ -169,46 +169,55 @@ export class Cache {
169169 queryResult . ref . name ,
170170 queryResult . ref . variables
171171 ) ;
172- const stubResultTree : StubResultTree = { } ;
173-
174- // eslint-disable-next-line guard-for-in
175- for ( const key in queryResult . data ) {
176- const entityOrEntityList = ( queryResult . data as Record < string , unknown > ) [
177- key
178- ] ;
179- if ( Array . isArray ( entityOrEntityList ) ) {
180- const sdoList : StubDataObjectList = [ ] ;
181- entityOrEntityList . forEach ( entity => {
182- if ( isCacheableQueryResultData ( entity ) ) {
183- const stubDataObject = this . cacheData ( entity ) ;
184- sdoList . push ( stubDataObject ) ;
185- }
186- } ) ;
187- stubResultTree [ key ] = sdoList ;
188- } else if ( isCacheableQueryResultData ( entityOrEntityList ) ) {
189- const stubDataObject = this . cacheData ( entityOrEntityList ) ;
190- stubResultTree [ key ] = stubDataObject ;
191- }
192- }
172+ const stubResultTree = this . normalize ( queryResult . data ) as StubResultTree ;
193173 this . resultTreeCache . set ( resultTreeCacheKey , stubResultTree ) ;
194174 }
195175
196176 /**
197- * Caches a single entity: gets or creates its BDO and returns a linked stub.
198- * @param data A single entity object from the query result.
199- * @returns A StubDataObject linked to the entity's BackingDataObject.
177+ * Recursively traverses a data object, normalizing cacheable entities into BDOs
178+ * and replacing them with stubs.
179+ * @param data The data to normalize (can be an object, array, or primitive).
180+ * @returns The normalized data with stubs.
200181 */
201- private cacheData ( data : QueryResultData ) : StubDataObject {
202- const stubDataaObject : StubDataObject = { ...data } ;
203- const bdoCacheKey = Cache . makeBdoCacheKey ( data . __typename , data . __id ) ;
204- const existingBdo = this . bdoCache . get ( bdoCacheKey ) ;
205-
206- if ( existingBdo ) {
207- this . updateBdo ( existingBdo , data , stubDataaObject ) ;
208- } else {
209- this . createBdo ( bdoCacheKey , data , stubDataaObject ) ;
182+ private normalize ( data : QueryResultData | Value ) : Value | StubDataObject {
183+ if ( Array . isArray ( data ) ) {
184+ return data . map ( item => this . normalize ( item ) ) ;
185+ }
186+
187+ if ( isCacheableQueryResultData ( data ) ) {
188+ const stub : StubDataObject = { } ;
189+ const bdoCacheKey = Cache . makeBdoCacheKey ( data . __typename , data . __id ) ;
190+ const existingBdo = this . bdoCache . get ( bdoCacheKey ) ;
191+
192+ // data is a single "movie" or "actor"
193+ // key is a field of the returned data
194+ for ( const key in data ) {
195+ // eslint-disable-next-line no-prototype-builtins
196+ if ( data . hasOwnProperty ( key ) ) {
197+ stub [ key ] = this . normalize ( data [ key ] ) ;
198+ }
199+ }
200+
201+ if ( existingBdo ) {
202+ this . updateBdo ( existingBdo , stub , stub ) ;
203+ } else {
204+ this . createBdo ( bdoCacheKey , stub , stub ) ;
205+ }
206+ return stub ;
207+ }
208+
209+ if ( typeof data === 'object' && data !== null ) {
210+ const newObj : { [ key : string ] : Value } = { } ;
211+ for ( const key in data ) {
212+ // eslint-disable-next-line no-prototype-builtins
213+ if ( data . hasOwnProperty ( key ) ) {
214+ newObj [ key ] = this . normalize ( data [ key ] ) ;
215+ }
216+ }
217+ return newObj ;
210218 }
211- return stubDataaObject ;
219+
220+ return data ;
212221 }
213222
214223 /**
0 commit comments