From cddcc470fd4d387f20c603c1581ab34bca391631 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Fri, 5 Oct 2018 15:33:00 -0400 Subject: [PATCH] Avoid using prototype objects as keys in QueryKeyMaker Maps. Fixes https://github.com/apollographql/react-apollo/issues/2442. This temporarily mitigates the prototype chain bug that will be permanently fixed by this React Native PR that I submitted yesterday: https://github.com/facebook/react-native/pull/21492 I would like to find a way to bundle a different Map polyfill in React Native apps, without increasing bundle sizes for non-RN apps, but that has proven tricky so far. For future reference, this seems to be the way to do it (thanks to @peggyrayzis for the tip): https://facebook.github.io/react-native/docs/platform-specific-code#platform-specific-extensions Until a new version of React Native is released with these changes included, the simplest way to fix the problem is simply to avoid storing any prototype objects in a Map, so that's what I've done in this commit. We are already wrapping Object.freeze and friends in src/fixPolyfills.ts, which should make it possible to use frozen objects as Map keys (the other bug that I addressed in the React Native PR linked above). --- packages/apollo-cache-inmemory/src/queryKeyMaker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/apollo-cache-inmemory/src/queryKeyMaker.ts b/packages/apollo-cache-inmemory/src/queryKeyMaker.ts index 1325f975322..da1ee5ee451 100644 --- a/packages/apollo-cache-inmemory/src/queryKeyMaker.ts +++ b/packages/apollo-cache-inmemory/src/queryKeyMaker.ts @@ -3,6 +3,7 @@ import { DocumentNode, SelectionSetNode, FragmentSpreadNode, FragmentDefinitionN import { QueryDocumentKeys } from "graphql/language/visitor"; const CIRCULAR = Object.create(null); +const objToStr = Object.prototype.toString; export class QueryKeyMaker { private perQueryKeyMakers = new Map(); @@ -99,7 +100,7 @@ class PerQueryKeyMaker { private lookupArray(array: any[]): object { const elements = array.map(this.lookupAny, this); return this.cacheKeyRoot.lookup( - Array.prototype, + objToStr.call(array), this.cacheKeyRoot.lookupArray(elements), ); } @@ -108,7 +109,7 @@ class PerQueryKeyMaker { const keys = safeSortedKeys(object); const values = keys.map(key => this.lookupAny(object[key])); return this.cacheKeyRoot.lookup( - Object.getPrototypeOf(object), + objToStr.call(object), this.cacheKeyRoot.lookupArray(keys), this.cacheKeyRoot.lookupArray(values), );