Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
public watchQuery(
options: WatchQueryOptions,
shouldSubscribe = true,
): ObservableQuery {
invariant(
options.fetchPolicy !== 'standby',
'client.watchQuery cannot be called with fetchPolicy set to "standby"',
);
// assign variable default values if supplied
options.variables = this.getVariables(options.query, options.variables);
if (typeof options.notifyOnNetworkStatusChange === 'undefined') {
options.notifyOnNetworkStatusChange = false;
}
let transformedOptions = { ...options } as WatchQueryOptions;
return new ObservableQuery({
queryManager: this,
options: transformedOptions,
invariant(
directiveArguments && directiveArguments.length === 1,
`Incorrect number of arguments for the @${directiveName} directive.`,
);
const ifArgument = directiveArguments[0];
invariant(
ifArgument.name && ifArgument.name.value === 'if',
`Invalid argument for the @${directiveName} directive.`,
);
const ifValue: ValueNode = ifArgument.value;
// means it has to be a variable value if this is a valid @skip or @include directive
invariant(
ifValue &&
(ifValue.kind === 'Variable' || ifValue.kind === 'BooleanValue'),
`Argument for the @${directiveName} directive must be a variable or a boolean value.`,
);
return { directive, ifArgument };
}) : [];
}
// data from that id with the data we're about to write in the store.
storeObject = store.get(dataId);
const escapedId =
storeObject && (storeObject[storeFieldName] as IdValue | undefined);
if (escapedId !== storeValue && isIdValue(escapedId)) {
const hadTypename = escapedId.typename !== undefined;
const hasTypename = typename !== undefined;
const typenameChanged =
hadTypename && hasTypename && escapedId.typename !== typename;
// If there is already a real id in the store and the current id we
// are dealing with is generated, we throw an error.
// One exception we allow is when the typename has changed, which occurs
// when schema defines a union, both with and without an ID in the same place.
// checks if we "lost" the read id
invariant(
!generated || escapedId.generated || typenameChanged,
`Store error: the application attempted to write an object with no provided id but the store already contains an id of ${
escapedId.id
} for this object. The selectionSet that was trying to be written is:\n${
JSON.stringify(field)
}`,
);
// checks if we "lost" the typename
invariant(
!hadTypename || hasTypename,
`Store error: the application attempted to write an object with no provided typename but the store already contains an object with typename of ${
escapedId.typename
} for the object of id ${escapedId.id}. The selectionSet that was trying to be written is:\n${
JSON.stringify(field)
}`,
let generated = true;
// We only prepend the '$' if the valueDataId isn't already a generated
// id.
if (!isGeneratedId(valueDataId)) {
valueDataId = '$' + valueDataId;
}
if (dataIdFromObject) {
const semanticId = dataIdFromObject(value);
// We throw an error if the first character of the id is '$. This is
// because we use that character to designate an Apollo-generated id
// and we use the distinction between user-desiginated and application-provided
// ids when managing overwrites.
invariant(
!semanticId || !isGeneratedId(semanticId),
'IDs returned by dataIdFromObject cannot begin with the "$" character.',
);
if (
semanticId ||
(typeof semanticId === 'number' && semanticId === 0)
) {
valueDataId = semanticId;
generated = false;
}
}
if (!isDataProcessed(valueDataId, field, context.processedData)) {
this.writeSelectionSetToStore({
dataId: valueDataId,
: onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) =>
// tslint:disable-next-line
invariant.warn(
`[GraphQL error]: Message: ${message}, Location: ` +
`${locations}, Path: ${path}`,
),
);
}
if (networkError) {
// tslint:disable-next-line
invariant.warn(`[Network error]: ${networkError}`);
}
});
constructor(config: InMemoryCacheConfig = {}) {
super();
this.config = { ...defaultConfig, ...config };
// backwards compat
if ((this.config as any).customResolvers) {
invariant.warn(
'customResolvers have been renamed to cacheRedirects. Please update your config as we will be deprecating customResolvers in the next major version.',
);
this.config.cacheRedirects = (this.config as any).customResolvers;
}
if ((this.config as any).cacheResolvers) {
invariant.warn(
'cacheResolvers have been renamed to cacheRedirects. Please update your config as we will be deprecating cacheResolvers in the next major version.',
);
this.config.cacheRedirects = (this.config as any).cacheResolvers;
}
this.addTypename = !!this.config.addTypename;
// Passing { resultCaching: false } in the InMemoryCache constructor options
// will completely disable dependency tracking, which will improve memory
// without having all of the selection set values available.
// This is because the @client field values might have already
// been written to the cache separately (e.g. via Apollo
// Cache's `writeData` capabilities). Because of this, we'll
// skip the missing field warning for fields with @client
// directives.
isClient = selection.directives.some(
directive => directive.name && directive.name.value === 'client',
);
}
if (!isDefered && !isClient && context.fragmentMatcherFunction) {
// XXX We'd like to throw an error, but for backwards compatibility's sake
// we just print a warning for the time being.
//throw new WriteError(`Missing field ${resultFieldKey} in ${JSON.stringify(result, null, 2).substring(0, 100)}`);
invariant.warn(
`Missing field ${resultFieldKey} in ${JSON.stringify(
result,
null,
2,
).substring(0, 100)}`,
);
}
}
} else {
// This is not a field, so it must be a fragment, either inline or named
let fragment: InlineFragmentNode | FragmentDefinitionNode;
if (isInlineFragment(selection)) {
fragment = selection;
} else {
// Named fragment
}
const { __typename = isRootQuery && 'Query' } = obj;
if (!__typename) {
if (shouldWarn()) {
invariant.warn(`You're using fragments in your queries, but either don't have the addTypename:
true option set in Apollo Client, or you are trying to write a fragment to the store without the __typename.
Please turn on the addTypename option and include __typename when writing fragments so that Apollo Client
can accurately match fragments.`);
invariant.warn(
'Could not find __typename on Fragment ',
typeCondition,
obj,
);
invariant.warn(
`DEPRECATION WARNING: using fragments without __typename is unsupported behavior ` +
`and will be removed in future versions of Apollo client. You should fix this and set addTypename to true now.`,
);
}
return 'heuristic';
}
if (__typename === typeCondition) {
return true;
}
// At this point we don't know if this fragment should match or not. It's
// either:
//
// 1. (GOOD) A fragment on a matching interface or union.
graphQLErrors.map(({ message, locations, path }) =>
// tslint:disable-next-line
invariant.warn(
`[GraphQL error]: Message: ${message}, Location: ` +
`${locations}, Path: ${path}`,
),
);
// At this point we don't know if this fragment should match or not. It's
// either:
//
// 1. (GOOD) A fragment on a matching interface or union.
// 2. (BAD) A fragment on a non-matching concrete type or interface or union.
//
// If it's 2, we don't want it to match. If it's 1, we want it to match. We
// can't tell the difference, so we warn the user, but still try to match
// it (for backwards compatibility reasons). This unfortunately means that
// using the `HeuristicFragmentMatcher` with unions and interfaces is
// very unreliable. This will be addressed in a future major version of
// Apollo Client, but for now the recommendation is to use the
// `IntrospectionFragmentMatcher` when working with unions/interfaces.
if (shouldWarn()) {
invariant.error(
'You are using the simple (heuristic) fragment matcher, but your ' +
'queries contain union or interface types. Apollo Client will not be ' +
'able to accurately map fragments. To make this error go away, use ' +
'the `IntrospectionFragmentMatcher` as described in the docs: ' +
'https://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher',
);
}
return 'heuristic';
}
}