Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
next: result => {
count++;
if (count === 1) {
expect(result.data).toBeUndefined();
expect(result.loading).toBe(true);
}
if (count === 2) {
expect(result.loading).toBe(false);
expect(stripSymbols(result.data)).toEqual(initialData);
expect(stripSymbols(observable.getCurrentResult().data)).toEqual(
initialData,
);
// step 2, recycle it
observable.setOptions({
fetchPolicy: 'standby',
pollInterval: 0,
fetchResults: false,
});
observableQueries.push({
observableQuery: observable,
subscription: observable.subscribe({}),
});
public request(operation: Operation, forward?: NextLink): Observable {
const {query} = operation;
const isRtdbQuery = hasDirectives(['rtdbSub'], query);
if (!isRtdbQuery && forward) {
return forward(operation);
}
const queryWithTypename = addTypenameToDocument(query);
const mainDefinition = getMainDefinition(query);
const context: ResolverContext = {
database: this.database,
findType: fieldDirectives =>
(fieldDirectives.rtdbSub && fieldDirectives.rtdbSub.type) ||
(fieldDirectives.rtdbQuery && fieldDirectives.rtdbQuery.type),
exportVal: {}
};
// Subscription operations must have exactly one root field.
const onlyRootField: FieldNode = mainDefinition.selectionSet.selections[0] as FieldNode;
// get directives
const directives = getDirectiveInfoFromField(onlyRootField, operation.variables);
const rtdbDirectives: SubDirectiveArgs = directives.rtdbSub as any;
public request (operation: Operation, forward?: NextLink) {
const isRestQuery = hasDirectives(['rest'], operation.query)
if (!isRestQuery && forward) return forward(operation)
const nonRestQuery = removeRestDirective(operation.query)
const typeNamedQuery = addTypenameToDocument(operation.query)
const observable =
nonRestQuery && forward
? // tslint:disable-next-line:prefer-object-spread
forward(Object.assign(operation, { query: nonRestQuery }))
: Observable.of({ data: {} })
return observable.flatMap(
({ data, ...rest }) =>
new Observable(subscriber => {
graphql(
resolver,
typeNamedQuery,
data,
this.resolverMap,
operation.variables
)
.then(resolvedData => {
// early return if trying to read from cache during refetch
if (fetchPolicy === 'cache-only') {
return Promise.reject(new InvariantError(
'cache-only fetchPolicy option should not be used together with query refetch.',
));
}
// Unless the provided fetchPolicy always consults the network
// (no-cache, network-only, or cache-and-network), override it with
// network-only to force the refetch for this fetchQuery call.
if (fetchPolicy !== 'no-cache' &&
fetchPolicy !== 'cache-and-network') {
fetchPolicy = 'network-only';
}
if (!isEqual(this.variables, variables)) {
// update observable variables
this.variables = {
...this.variables,
...variables,
};
}
if (!isEqual(this.options.variables, this.variables)) {
// Update the existing options with new variables
this.options.variables = {
...this.options.variables,
...this.variables,
};
}
return this.queryManager.fetchQuery(
// Note that we're careful to fetch the value of our new container; not
// the outer container.
const previousFieldValue = deepGet(this._getNodeData(containerIdForField), fieldPath);
// For fields with sub selections, we walk into them; only leaf fields are
// directly written via _setValue. This allows us to perform minimal
// edits to the graph.
if (node.children) {
this._mergeSubgraph(referenceEdits, warnings, containerIdForField, fieldPrefixPath, fieldPath, node.children, fieldValue);
// We've hit a leaf field.
//
// Note that we must perform a _deep_ equality check here, to cover cases
// where a leaf value is a complex object.
} else if (!isEqual(fieldValue, previousFieldValue)) {
// We intentionally do not deep copy the nodeValue as Apollo will
// then perform Object.freeze anyway. So any change in the payload
// value afterward will be reflect in the graph as well.
//
// We use selection.name.value instead of payloadKey so that we
// always write to cache using real field name rather than alias
// name.
this._setValue(containerIdForField, fieldPath, fieldValue);
}
}
}
const { fetchPolicy } = this.options;
// early return if trying to read from cache during refetch
if (fetchPolicy === 'cache-only') {
return Promise.reject(
new Error(
'cache-only fetchPolicy option should not be used together with query refetch.',
),
);
}
if (!isEqual(this.variables, variables)) {
// update observable variables
this.variables = Object.assign({}, this.variables, variables);
}
if (!isEqual(this.options.variables, this.variables)) {
// Update the existing options with new variables
this.options.variables = Object.assign(
{},
this.options.variables,
this.variables,
);
}
// Override fetchPolicy for this call only
// only network-only and no-cache are safe to use
const isNetworkFetchPolicy =
fetchPolicy === 'network-only' || fetchPolicy === 'no-cache';
const combinedOptions: WatchQueryOptions = {
...this.options,
fetchPolicy: isNetworkFetchPolicy ? fetchPolicy : 'network-only',
refetch: variables => {
// If variables have not changed and not subscribed, skip refetch
if (!subscribed && isEqual(variables, observable_query.variables))
return observable_query.result();
return observable_query.refetch(variables);
},
result: () => observable_query.result(),
function addPreviousResultToIdValues(value: any, previousResult: any): any {
// If the value is an `IdValue`, add the previous result to it whether or not that
// `previousResult` is undefined.
//
// If the value is an array, recurse over each item trying to add the `previousResult` for that
// item.
if (isIdValue(value)) {
return {
...value,
previousResult,
};
} else if (Array.isArray(value)) {
const idToPreviousResult: { [id: string]: any } = {};
// If the previous result was an array, we want to build up our map of ids to previous results
// using the private `ID_KEY` property that is added in `resultMapper`.
if (Array.isArray(previousResult)) {
previousResult.forEach(item => {
// item can be null
if (item && item[ID_KEY]) {
idToPreviousResult[item[ID_KEY]] = item;
}
});
public startGraphQLSubscription(
options: SubscriptionOptions,
): Observable {
const { query } = options;
let transformedDoc = this.dataStore.getCache().transformDocument(query);
const variables = assign(
{},
getDefaultValues(getOperationDefinition(query)),
options.variables,
);
const request: Request = {
query: transformedDoc,
variables,
operationName: getOperationName(transformedDoc) || undefined,
};
let sub: Subscription;
let observers: Observer[] = [];
return new Observable(observer => {
observers.push(observer);
// If this is the first observer, actually initiate the network subscription
if (observers.length === 1) {
const handler = {
next: (result: FetchResult) => {
this.dataStore.markSubscriptionResult(
result,
transformedDoc,
variables,
queryId,
document,
options,
fetchMoreForQueryId,
}: {
requestId: number;
queryId: string;
document: DocumentNode;
options: WatchQueryOptions;
fetchMoreForQueryId?: string;
}): Promise {
const { variables, context, errorPolicy = 'none' } = options;
const request = {
query: document,
variables,
operationName: getOperationName(document) || undefined,
context: context || {},
};
request.context.forceFetch = !this.queryDeduplication;
// add the cache to the context to links can do things with it
request.context.cache = this.dataStore.getCache();
let resultFromStore: any;
let errorsFromStore: any;
const retPromise = new Promise>((resolve, reject) => {
this.addFetchQueryPromise(requestId, retPromise, resolve, reject);
const subscription = execute(this.deduplicator, request).subscribe({
next: (result: ExecutionResult) => {
// default the lastRequestId to 1
const { lastRequestId } = this.getQuery(queryId);