@apollo/client/core#Cache TypeScript Examples

The following examples show how to use @apollo/client/core#Cache. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CacheResultProcessor.ts    From apollo-cache-policies with Apache License 2.0 6 votes vote down vote up
private getFieldsForQuery(
    options: Cache.ReadOptions<any> | Cache.WriteOptions<any, any>
  ) {
    const operationDefinition = getOperationDefinition(options.query);
    const fragmentMap = createFragmentMap(
      getFragmentDefinitions(options.query)
    );

    return operationDefinition!.selectionSet.selections.reduce<SelectionNode[]>(
      (acc, selection) => {
        if (isField(selection)) {
          acc.push(selection);
          return acc;
        }

        const selections = getFragmentFromSelection(selection, fragmentMap)
          ?.selectionSet?.selections;

        if (selections) {
          acc.push(...selections);
        }

        return acc;
      },
      []
    ) as FieldNode[];
  }
Example #2
Source File: InvalidationPolicyCache.ts    From apollo-cache-policies with Apache License 2.0 6 votes vote down vote up
write(options: Cache.WriteOptions<any, any>) {
    const writeResult = super.write(options);

    // Do not trigger a write policy if the current write is being applied to an optimistic data layer since
    // the policy will later be applied when the server data response is received.
    if (
      (!this.invalidationPolicyManager.isPolicyEventActive(
        InvalidationPolicyEvent.Write
      ) &&
        !this.invalidationPolicyManager.isPolicyEventActive(
          InvalidationPolicyEvent.Read
        )) ||
      !this.isOperatingOnRootData()
    ) {
      return writeResult;
    }

    this.cacheResultProcessor.processWriteResult(options);

    if (options.broadcast) {
      this.broadcastWatches();
    }

    return writeResult;
  }
Example #3
Source File: InvalidationPolicyCache.ts    From apollo-cache-policies with Apache License 2.0 6 votes vote down vote up
read<T>(options: Cache.ReadOptions<any>): T | null {
    const result = super.read<T>(options);

    if (
      !this.invalidationPolicyManager.isPolicyEventActive(
        InvalidationPolicyEvent.Read
      )
    ) {
      return result;
    }

    const processedResult = maybeDeepClone(result);
    const processedResultStatus = this.cacheResultProcessor.processReadResult(
      processedResult,
      options
    );

    if (processedResultStatus === ReadResultStatus.Complete) {
      return result;
    }

    this.broadcastWatches();

    return processedResultStatus === ReadResultStatus.Evicted
      ? null
      : processedResult;
  }
Example #4
Source File: InvalidationPolicyCache.ts    From apollo-cache-policies with Apache License 2.0 6 votes vote down vote up
diff<T>(options: Cache.DiffOptions): Cache.DiffResult<T> {
    const cacheDiff = super.diff<T>(options);

    // Diff calls made by `broadcastWatches` should not trigger the read policy
    // as these are internal reads not reflective of client action and can lead to recursive recomputation of cached data which is an error.
    // Instead, diffs will trigger the read policies for client-based reads like `readCache` invocations from watched queries outside
    // the scope of broadcasts.
    if (
      !this.invalidationPolicyManager.isPolicyEventActive(
        InvalidationPolicyEvent.Read
      ) ||
      this.isBroadcasting
    ) {
      return cacheDiff;
    }

    const { result } = cacheDiff;

    const processedResult = maybeDeepClone(result);
    const processedResultStatus = this.cacheResultProcessor.processReadResult(
      processedResult,
      options
    );

    if (processedResultStatus === ReadResultStatus.Complete) {
      return cacheDiff;
    }

    this.broadcastWatches();

    cacheDiff.complete = false;
    cacheDiff.result =
      processedResultStatus === ReadResultStatus.Evicted
        ? undefined
        : processedResult;

    return cacheDiff;
  }
Example #5
Source File: InvalidationPolicyCache.ts    From apollo-cache-policies with Apache License 2.0 6 votes vote down vote up
// Supports reading a collection of entities by type from the cache and filtering them by the given fields. Returns
  // a list of the dereferenced matching entities from the cache based on the given fragment.
  readFragmentWhere<FragmentType, TVariables = any>(options: Cache.ReadFragmentOptions<FragmentType, TVariables> & {
    filter?: FragmentWhereFilter<FragmentType>;
  }): FragmentType[] {
    const { fragment, filter, ...restOptions } = options;
    const fragmentDefinition = fragment.definitions[0] as FragmentDefinitionNode;
    const __typename = fragmentDefinition.typeCondition.name.value;

    const matchingRefs = this.readReferenceWhere(
      {
        __typename,
        filter
      }
    );

    const matchingFragments = matchingRefs.map(ref => this.readFragment({
      ...restOptions,
      fragment,
      id: ref.__ref,
    }));

    return compact(matchingFragments);
  }
Example #6
Source File: InvalidationPolicyCache.ts    From apollo-cache-policies with Apache License 2.0 5 votes vote down vote up
modify(options: Cache.ModifyOptions) {
    const modifyResult = super.modify(options);

    if (
      !this.invalidationPolicyManager.isPolicyEventActive(
        InvalidationPolicyEvent.Write
      ) ||
      !modifyResult
    ) {
      return modifyResult;
    }

    const { id = "ROOT_QUERY", fields } = options;

    if (isQuery(id)) {
      Object.keys(fields).forEach((storeFieldName) => {
        const fieldName = fieldNameFromStoreName(storeFieldName);

        const typename = this.entityTypeMap.readEntityById(
          makeEntityId(id, fieldName)
        )?.typename;

        if (!typename) {
          return;
        }

        this.invalidationPolicyManager.runWritePolicy(typename, {
          parent: {
            id,
            fieldName,
            storeFieldName,
            ref: makeReference(id),
          },
        });
      });
    } else {
      const typename = this.entityTypeMap.readEntityById(id)?.typename;

      if (!typename) {
        return modifyResult;
      }

      this.invalidationPolicyManager.runWritePolicy(typename, {
        parent: {
          id,
          ref: makeReference(id),
        },
      });
    }

    if (options.broadcast) {
      this.broadcastWatches();
    }

    return modifyResult;
  }
Example #7
Source File: InvalidationPolicyCache.ts    From apollo-cache-policies with Apache License 2.0 5 votes vote down vote up
evict(options: Cache.EvictOptions): boolean {
    const { fieldName, args } = options;
    let { id } = options;
    if (!id) {
      if (Object.prototype.hasOwnProperty.call(options, "id")) {
        return false;
      }
      id = "ROOT_QUERY";
    }

    if (
      this.invalidationPolicyManager.isPolicyEventActive(
        InvalidationPolicyEvent.Evict
      )
    ) {
      const { typename } =
        this.entityTypeMap.readEntityById(makeEntityId(id, fieldName)) ?? {};

      if (typename) {
        const storeFieldName =
          isQuery(id) && fieldName
            ? this.policies.getStoreFieldName({
              typename,
              fieldName,
              args,
            })
            : undefined;

        this.invalidationPolicyManager.runEvictPolicy(typename, {
          parent: {
            id,
            fieldName,
            storeFieldName,
            variables: args,
            ref: makeReference(id),
          },
        });
      }
    }

    return super.evict(options);
  }
Example #8
Source File: CacheResultProcessor.ts    From apollo-cache-policies with Apache License 2.0 4 votes vote down vote up
processReadResult<T>(
    result: T,
    options: Cache.ReadOptions<any>
  ): ReadResultStatus {
    const { cache, entityTypeMap, invalidationPolicyManager } = this.config;
    const { rootId: dataId = "ROOT_QUERY" } = options;

    if (isPlainObject(result)) {
      if (isQuery(dataId)) {
        const { variables } = options;

        const aggregateResultComplete = this.getFieldsForQuery(options).reduce<
          boolean
        >((acc, field) => {
          const fieldName = field.name.value;
          // While the field name is used as the key in the cache, the result object
          // will have it keyed by an alias name if provided so we keep track of the 
          // result key name in case it needs to be removed from the response due to an evicted TTL
          const resultKeyName = resultKeyNameFromField(field);
          const subResultStatus = this.processReadSubResult(result, fieldName);

          const typename = entityTypeMap.readEntityById(
            makeEntityId(dataId, fieldName)
          )?.typename;

          if (typename) {
            const storeFieldNameForEntity = cache.policies.getStoreFieldName({
              typename,
              fieldName,
              field,
              variables,
            });
            const queryTypename = cache.policies.rootTypenamesById[dataId];
            const storeFieldNameForQuery = cache.policies.getStoreFieldName({
              typename: queryTypename,
              fieldName,
              field,
              variables,
            });

            const renewalPolicy = invalidationPolicyManager.getRenewalPolicyForType(
              typename
            );
            if (
              renewalPolicy === RenewalPolicy.AccessAndWrite ||
              renewalPolicy === RenewalPolicy.AccessOnly
            ) {
              entityTypeMap.renewEntity(dataId, storeFieldNameForEntity);
              entityTypeMap.renewEntity(dataId, storeFieldNameForQuery);
            }

            const evictedByStoreFieldNameForEntity = invalidationPolicyManager.runReadPolicy({
              typename,
              dataId,
              fieldName,
              storeFieldName: storeFieldNameForEntity,
            });
            const evictedByStoreFieldNameForQuery = invalidationPolicyManager.runReadPolicy({
              typename,
              dataId,
              fieldName,
              storeFieldName: storeFieldNameForQuery,
            });

            if (evictedByStoreFieldNameForEntity || evictedByStoreFieldNameForQuery) {
              delete (result as Record<string, any>)[resultKeyName];
              return false;
            }
          }

          return acc && subResultStatus === ReadResultStatus.Complete;
        }, true);

        maybeDeepFreeze(result);

        return aggregateResultComplete
          ? ReadResultStatus.Complete
          : ReadResultStatus.Incomplete;
      }

      maybeDeepFreeze(result);
      return this.processReadSubResult(result);
    }

    return ReadResultStatus.Complete;
  }
Example #9
Source File: CacheResultProcessor.ts    From apollo-cache-policies with Apache License 2.0 4 votes vote down vote up
processWriteResult(options: Cache.WriteOptions<any, any>) {
    const { dataId, variables, result } = options;
    const { entityTypeMap, cache, invalidationPolicyManager } = this.config;

    if (isPlainObject(result)) {
      this.processWriteSubResult(result);
    }

    if (dataId && isQuery(dataId) && isPlainObject(result)) {
      this.getFieldsForQuery(options).forEach((field) => {
        const fieldName = field.name.value;
        const typename = entityTypeMap.readEntityById(
          makeEntityId(dataId, fieldName)
        )?.typename;

        if (typename) {
          const storeFieldName = cache.policies.getStoreFieldName({
            typename,
            field,
            fieldName,
            variables,
          });

          const fieldArgs = argumentsObjectFromField(field, variables);
          const fieldVariables = variables ?? (fieldArgs !== null ? {} : undefined);

          const queryTypename = cache.policies.rootTypenamesById[dataId];
          const storeFieldNameForQuery = cache.policies.getStoreFieldName({
            typename: queryTypename,
            fieldName,
            field,
            variables,
          });

          // Write a query to the entity type map at `write` in addition to `merge` time so that we can keep track of its variables.
          entityTypeMap.write(typename, dataId, storeFieldName, fieldVariables, fieldArgs);
          entityTypeMap.write(typename, dataId, storeFieldNameForQuery, fieldVariables, fieldArgs);

          const renewalPolicy = invalidationPolicyManager.getRenewalPolicyForType(
            typename
          );
          if (
            renewalPolicy === RenewalPolicy.WriteOnly ||
            renewalPolicy === RenewalPolicy.AccessAndWrite
          ) {
            entityTypeMap.renewEntity(dataId, storeFieldName);
            entityTypeMap.renewEntity(dataId, storeFieldNameForQuery);
          }

          invalidationPolicyManager.runWritePolicy(typename, {
            parent: {
              id: dataId,
              fieldName,
              storeFieldName,
              ref: makeReference(dataId),
              variables: fieldVariables,
              args: fieldArgs,
            },
          });
        }
      });
    } else if (dataId) {
      const typename = entityTypeMap.readEntityById(makeEntityId(dataId))
        ?.typename;

      if (typename) {
        const renewalPolicy = invalidationPolicyManager.getRenewalPolicyForType(
          typename
        );
        if (
          renewalPolicy === RenewalPolicy.WriteOnly ||
          renewalPolicy === RenewalPolicy.AccessAndWrite
        ) {
          entityTypeMap.renewEntity(dataId);
        }

        invalidationPolicyManager.runWritePolicy(typename, {
          parent: {
            id: dataId,
            ref: makeReference(dataId),
            variables,
          },
        });
      }
    }
  }