@apollo/client/core#makeReference TypeScript Examples
The following examples show how to use
@apollo/client/core#makeReference.
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: utils.ts From apollo-cache-policies with Apache License 2.0 | 7 votes |
// Returns a query that can be used to watch a normalized cache entity by converting the fragment to a query
// and dynamically adding a type policy that returns the entity.
export function buildWatchFragmentQuery(
options: WatchFragmentOptions & {
fieldName: string;
policies: Policies,
}
): DocumentNode {
const { fragment, id, policies, fieldName } = options;
const fragmentDefinition = fragment.definitions[0] as FragmentDefinitionNode;
const query = _generateQueryFromFragment({
fragmentDefinition: fragmentDefinition,
fieldName,
});
// @ts-ignore The getFieldPolicy is private but we need it here to determine
// if the dynamic type policy we generate for the corresponding fragment has
// already been added
if (!policies.getFieldPolicy('Query', fieldName)) {
policies.addTypePolicies({
Query: {
fields: {
[fieldName]: {
read(_existing) {
return makeReference(id);
}
}
}
}
});
}
return query;
}
Example #2
Source File: CacheResultProcessor.ts From apollo-cache-policies with Apache License 2.0 | 6 votes |
private processWriteSubResult(result: any) {
const { cache, invalidationPolicyManager, entityTypeMap } = this.config;
if (isPlainObject(result)) {
const { __typename } = result;
Object.keys(result).forEach((resultField) =>
this.processWriteSubResult(result[resultField])
);
if (__typename) {
const id = cache.identify(result);
if (id) {
const renewalPolicy = invalidationPolicyManager.getRenewalPolicyForType(
__typename
);
if (
renewalPolicy === RenewalPolicy.WriteOnly ||
renewalPolicy === RenewalPolicy.AccessAndWrite
) {
entityTypeMap.renewEntity(id);
}
invalidationPolicyManager.runWritePolicy(__typename, {
parent: {
id,
ref: makeReference(id),
},
});
}
}
} else if (isArray(result)) {
result.forEach((resultListItem) =>
this.processWriteSubResult(resultListItem)
);
}
}
Example #3
Source File: InvalidationPolicyCache.ts From apollo-cache-policies with Apache License 2.0 | 6 votes |
// Supports reading a collection of references by type from the cache and filtering them by the given fields. Returns a
// list of the matching references.
readReferenceWhere<T>(options: {
__typename: string,
filter?: FragmentWhereFilter<T>;
}) {
const { __typename, filter } = options;
const collectionEntityName = collectionEntityIdForType(__typename);
const entityReferences = this.readField<Reference[]>('data', makeReference(collectionEntityName));
if (!entityReferences) {
return [];
}
if (!filter) {
return entityReferences;
}
return entityReferences.filter(ref => {
if (isFunction(filter)) {
return filter(ref, this.readField.bind(this));
}
const entityFilterResults = Object.keys(filter).map(filterField => {
// @ts-ignore
const filterValue = filter[filterField];
const entityValueForFilter = this.readField(filterField, ref);
return filterValue === entityValueForFilter;
});
return every(entityFilterResults, Boolean);
});
}
Example #4
Source File: InvalidationPolicyCache.ts From apollo-cache-policies with Apache License 2.0 | 5 votes |
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 #5
Source File: InvalidationPolicyCache.ts From apollo-cache-policies with Apache License 2.0 | 5 votes |
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 #6
Source File: InvalidationPolicyCache.ts From apollo-cache-policies with Apache License 2.0 | 5 votes |
protected updateCollectionField(typename: string, dataId: string) {
// Since colletion support is still experimental, only record entities in collections if enabled
if (!this.enableCollections) {
return;
}
const collectionEntityId = collectionEntityIdForType(typename);
const collectionFieldExists = !!this.readField<Record<string, any[]>>('id', makeReference(collectionEntityId));
// If the collection field for the type does not exist in the cache, then initialize it as
// an empty array.
if (!collectionFieldExists) {
this.writeFragment({
id: collectionEntityId,
fragment: gql`
fragment InitializeCollectionEntity on CacheExtensionsCollectionEntity {
data
id
}
`,
data: {
__typename: cacheExtensionsCollectionTypename,
id: typename,
data: [],
},
});
}
// If the entity does not already exist in the cache, add it to the collection field policy for its type
if (!this.entityTypeMap.readEntityById(dataId)) {
this.modify({
broadcast: false,
id: collectionEntityId,
fields: {
data: (existing, { canRead }) => {
return [
...existing.filter((ref: Reference) => canRead(ref)),
makeReference(dataId),
];
}
}
});
}
}
Example #7
Source File: InvalidationPolicyManager.ts From apollo-cache-policies with Apache License 2.0 | 5 votes |
private runPolicyEvent(
typeName: string,
policyEvent: InvalidationPolicyEvent.Evict | InvalidationPolicyEvent.Write,
policyMeta: PolicyActionMeta
) {
const { entityTypeMap } = this.config;
const { mutedCacheOperations } = this;
const typePolicyForEvent = this.getTypePolicyForEvent(
typeName,
policyEvent
);
if (!typePolicyForEvent) {
return;
}
let defaultPolicyAction: DefaultPolicyAction | undefined;
let restTypePolicyTypeNames: Record<string, PolicyAction> = {} as Record<string, PolicyAction>;
if (typeof typePolicyForEvent === 'object') {
let { __default: _defaultPolicyAction, ..._restTypePolicyTypeNames } = typePolicyForEvent;
defaultPolicyAction = _defaultPolicyAction;
restTypePolicyTypeNames = _restTypePolicyTypeNames;
} else {
defaultPolicyAction = typePolicyForEvent;
}
if (defaultPolicyAction) {
defaultPolicyAction(mutedCacheOperations, {
storage: this.getPolicyActionStorage(`${typeName}__default`),
...policyMeta,
});
}
Object.keys(restTypePolicyTypeNames).forEach((typePolicyTypeName: string) => {
const typeMapEntities = entityTypeMap.readEntitiesByType(typePolicyTypeName) ?? {};
const policyAction = (typePolicyForEvent as Record<string, PolicyAction>)[typePolicyTypeName];
Object.values(typeMapEntities).forEach((typeMapEntity) => {
const { dataId, fieldName, storeFieldNames } = typeMapEntity;
if (storeFieldNames) {
Object.keys(storeFieldNames.entries).forEach((storeFieldName) => {
policyAction(mutedCacheOperations, {
id: dataId,
fieldName,
storeFieldName,
variables: storeFieldNames.entries[storeFieldName].variables,
args: storeFieldNames.entries[storeFieldName].args,
ref: makeReference(dataId),
storage: this.getPolicyActionStorage(storeFieldName),
...policyMeta,
});
});
} else {
policyAction(mutedCacheOperations, {
id: dataId,
storage: this.getPolicyActionStorage(dataId),
ref: makeReference(dataId),
...policyMeta,
});
}
});
});
}
Example #8
Source File: CacheResultProcessor.ts From apollo-cache-policies with Apache License 2.0 | 4 votes |
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,
},
});
}
}
}
Example #9
Source File: InvalidationPolicyManager.test.ts From apollo-cache-policies with Apache License 2.0 | 4 votes |
describe("InvalidationPolicyManager", () => {
let invalidationPolicyManager: InvalidationPolicyManager;
let cacheOperations: PolicyActionCacheOperations;
let entityTypeMap: EntityTypeMap;
let policies: InvalidationPolicies;
beforeEach(() => {
policies = {};
entityTypeMap = new EntityTypeMap();
cacheOperations = {
evict: jest.fn((..._args: any[]): any => { }),
modify: jest.fn((..._args: any[]): any => { }),
readField: jest.fn((..._args: any[]): any => { }),
};
invalidationPolicyManager = new InvalidationPolicyManager({
entityTypeMap,
policies,
cacheOperations,
});
});
describe("#runPolicyEvent", () => {
let employeePolicyActionSpy: any;
let employeesResponsePolicyActionSpy: any;
let actionMeta: PolicyActionMeta;
let mutedCacheOperations: PolicyActionCacheOperations;
beforeEach(() => {
actionMeta = {
parent: {
id: "ROOT_QUERY",
fieldName: "createEmployee",
storeFieldName: "createEmployees({new: true})",
ref: makeReference("ROOT_QUERY"),
variables: { new: true },
},
};
employeePolicyActionSpy = jest.fn();
employeesResponsePolicyActionSpy = jest.fn();
policies = {
types: {
CreateEmployeeResponse: {
onEvict: {
Employee: (...args) => employeePolicyActionSpy(...args),
EmployeesResponse: (...args) => employeesResponsePolicyActionSpy(...args),
},
},
},
};
invalidationPolicyManager = new InvalidationPolicyManager({
entityTypeMap,
policies,
cacheOperations,
});
mutedCacheOperations =
// @ts-ignore
invalidationPolicyManager.mutedCacheOperations;
entityTypeMap.write("Employee", "Employee:1");
entityTypeMap.write("Employee", "Employee:2");
entityTypeMap.write(
"EmployeesResponse",
"ROOT_QUERY",
"employees({country: 'US'})",
{ country: "US" }
);
entityTypeMap.write(
"EmployeesResponse",
"ROOT_QUERY",
"employees({country: 'CAN'})",
{ country: "CAN" }
);
});
test("should call the policy action handlers with the correct arguments", () => {
invalidationPolicyManager.runEvictPolicy(
"CreateEmployeeResponse",
actionMeta
);
expect(employeePolicyActionSpy).toHaveBeenCalledTimes(2);
expect(employeesResponsePolicyActionSpy).toHaveBeenCalledTimes(2);
expect(employeePolicyActionSpy.mock.calls[0][0]).toEqual(
// @ts-ignore
invalidationPolicyManager.mutedCacheOperations
);
expect(employeePolicyActionSpy.mock.calls[0][1]).toEqual({
id: "Employee:1",
ref: makeReference("Employee:1"),
storage: {},
parent: actionMeta.parent,
});
expect(employeePolicyActionSpy.mock.calls[1][0]).toEqual(
mutedCacheOperations
);
expect(employeePolicyActionSpy.mock.calls[1][1]).toEqual({
id: "Employee:2",
ref: makeReference("Employee:2"),
storage: {},
parent: actionMeta.parent,
});
expect(employeesResponsePolicyActionSpy.mock.calls[0][0]).toEqual(
mutedCacheOperations
);
expect(employeesResponsePolicyActionSpy.mock.calls[0][1]).toEqual({
id: "ROOT_QUERY",
fieldName: "employees",
storeFieldName: "employees({country: 'US'})",
ref: makeReference("ROOT_QUERY"),
variables: { country: "US" },
storage: {},
parent: actionMeta.parent,
});
expect(employeesResponsePolicyActionSpy.mock.calls[1][0]).toEqual(
mutedCacheOperations
);
expect(employeesResponsePolicyActionSpy.mock.calls[1][1]).toEqual({
id: "ROOT_QUERY",
fieldName: "employees",
ref: makeReference("ROOT_QUERY"),
storeFieldName: "employees({country: 'CAN'})",
variables: { country: "CAN" },
storage: {},
parent: actionMeta.parent,
});
});
test('should persist storage per identifier across multiple policy events', () => {
employeePolicyActionSpy = jest.fn((_cacheOperations, policyAction) => {
policyAction.storage.count = (policyAction.storage?.count ?? 0) + 1;
});
invalidationPolicyManager.runEvictPolicy(
"CreateEmployeeResponse",
actionMeta
);
expect(employeePolicyActionSpy.mock.calls[0][1]).toEqual(
{
id: "Employee:1",
ref: makeReference("Employee:1"),
storage: { count: 1 },
parent: actionMeta.parent,
}
);
expect(employeePolicyActionSpy.mock.calls[1][1]).toEqual(
{
id: "Employee:2",
ref: makeReference("Employee:2"),
storage: { count: 1 },
parent: actionMeta.parent,
}
);
invalidationPolicyManager.runEvictPolicy(
"CreateEmployeeResponse",
actionMeta
);
expect(employeePolicyActionSpy.mock.calls[2][1]).toEqual(
{
id: "Employee:1",
ref: makeReference("Employee:1"),
storage: { count: 2 },
parent: actionMeta.parent,
}
);
expect(employeePolicyActionSpy.mock.calls[3][1]).toEqual(
{
id: "Employee:2",
ref: makeReference("Employee:2"),
storage: { count: 2 },
parent: actionMeta.parent,
}
);
});
});
describe("#activatePolicies", () => {
test("should activate all policies with config options", () => {
policies = {
types: {
Employee: {
timeToLive: 5,
},
EmployeeResponse: {
onWrite: {
Employee: () => { },
},
onEvict: {
Employee: () => { },
},
},
},
};
invalidationPolicyManager = new InvalidationPolicyManager({
entityTypeMap,
policies,
cacheOperations,
});
expect(
invalidationPolicyManager.isPolicyEventActive(InvalidationPolicyEvent.Read)
).toEqual(true);
expect(
invalidationPolicyManager.isPolicyEventActive(InvalidationPolicyEvent.Write)
).toEqual(true);
expect(
invalidationPolicyManager.isPolicyEventActive(InvalidationPolicyEvent.Evict)
).toEqual(true);
});
test("should not activate policies without config options", () => {
policies = {
types: {
Employee: {},
EmployeeResponse: {},
},
};
invalidationPolicyManager = new InvalidationPolicyManager({
entityTypeMap,
policies,
cacheOperations,
});
expect(
invalidationPolicyManager.isPolicyEventActive(InvalidationPolicyEvent.Read)
).toEqual(false);
expect(
invalidationPolicyManager.isPolicyEventActive(InvalidationPolicyEvent.Write)
).toEqual(false);
expect(
invalidationPolicyManager.isPolicyEventActive(InvalidationPolicyEvent.Evict)
).toEqual(false);
});
});
describe('#runReadPolicy', () => {
test('should not evaluate a read policy for normalized entities that are not in the cache', () => {
const employee = Employee();
expect(invalidationPolicyManager.runReadPolicy({
typename: employee.__typename,
dataId: employee.id
})).toEqual(false);
});
test('should not evaluate a read policy for non-normalized entities that are not in the cache', () => {
entityTypeMap.write('EmployeesResponse', 'ROOT_QUERY', 'employees({"name":"Tester1"})');
expect(invalidationPolicyManager.runReadPolicy({
typename: 'EmployeesResponse',
dataId: 'ROOT_QUERY',
fieldName: 'employees',
storeFieldName: 'employees({"name":"Tester2"})',
})).toEqual(false);
});
})
});