const raw = JSON.parse(await AsyncStorage.getItem("apollo-cache"));
cache.restore(reviveScalarsInCache(raw, { schema, typesMap }));
await persistCache({ cache, storage });
cache.restore(reviveScalarsInCache(cache.extract(), { schema, typesMap }));
Mutates extracted in place and returns the same reference. The
generic signature is there for type flow, not copy semantics. Pass
a fresh snapshot such as cache.extract() (already a clone of the
live cache) or a JSON.parse(...) result; don't pass a live
in-memory structure shared with the rest of the app.
Merges typesMap with the schema's own leaf types and honors
nullFunctions the same way withScalars does (see
src/lib/link.ts). A scalar defined programmatically via
new GraphQLScalarType({ parseValue }) is therefore applied on
rehydration even when the caller's typesMap omits it, and any
null-monad transform passed to withScalars can be repeated here
to keep both paths producing the same shape.
Requires __typename on embedded non-normalized objects, which is
Apollo's default behavior. A cache built with
new InMemoryCache({ addTypename: false }) stores embedded objects
without a __typename key, so reviveScalarsInCache cannot look
them up in the schema and will leave their scalars unparsed.
Top-level normalized entities still work because their cache key
(Foo:1) and their __typename field are written by Apollo
independent of the addTypename setting.
Interfaces, unions, and enum-scalar validation are out of scope in
this first pass. Scalar fields nested under an interface- or
union-typed field are not revived because the helper does not
resolve the runtime __typename on the value itself the way the
network parser does.
Idempotence is caller-contingent. reviveScalarsInCache calls
parseValue once per field per pass, so invoking it twice on the
same snapshot parses every scalar twice. Safe only when the
supplied parseValue is itself idempotent — e.g. a DateTime
parser that guards with typeof v === "string" before constructing
a Date will leave Date instances alone on the second pass. A
naive Money parser like (v) => Number(v) * 100 is NOT
idempotent: first pass turns "1.50" into 150, second pass turns
150 into 15000 — silent corruption. When in doubt, make
parseValue detect its own output and short-circuit.
Re-applies the custom scalar
parseValuefunctions to a cache snapshot that has been round-tripped through JSON (localStorage / AsyncStorage / any store that usesapollo3-cache-persistor equivalent).Fix for https://github.com/eturino/apollo-link-scalars/issues/760 — the scalar link only sees operations flowing through
ApolloLink, so values restored viacache.restore()come back as the JSON shape they had in storage (Date-> ISO string, customMoney-> the serialized form, etc.) and the consumer never gets the parsed types.Pure and schema-driven: no dependency on
ApolloCache. Call it on the payload beforecache.restore(...)or after you read it from the persisted store yourself.