Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
Merge pull request #364 from aerogear/expose-getUpdateFunction
Browse files Browse the repository at this point in the history
fix: expose update function
  • Loading branch information
StephenCoady authored May 24, 2019
2 parents c585554 + 892eb2b commit f690888
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 10 deletions.
3 changes: 2 additions & 1 deletion packages/sync/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"graphql-tag": "2.10.1",
"graphql-tools": "4.0.4",
"idb-localstorage": "0.2.0",
"subscriptions-transport-ws": "0.9.16"
"subscriptions-transport-ws": "0.9.16",
"util": "^0.12.0"
}
}
30 changes: 24 additions & 6 deletions packages/sync/src/cache/createMutationOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { CacheOperation } from "./CacheOperation";
import { createOptimisticResponse } from "./createOptimisticResponse";
import { Query } from "./CacheUpdates";
import { getOperationFieldName, deconstructQuery } from "../utils/helpers";
import { isArray } from "util";

export interface MutationHelperOptions {
mutation: DocumentNode;
variables: OperationVariables;
updateQuery: Query;
updateQuery: Query | Query[];
typeName: string;
operationType?: CacheOperation;
idField?: string;
Expand All @@ -33,14 +34,31 @@ export const createMutationOptions = (options: MutationHelperOptions): MutationO
typeName
});

const update = getUpdateFunction(operationName, idField, updateQuery, operationType);
const update: MutationUpdaterFn = (cache, { data }) => {
if (isArray(updateQuery)) {
for (const query of updateQuery) {
const updateFunction = getUpdateFunction(operationName, idField, query, operationType);
updateFunction(cache, { data });
}
} else {
const updateFunction = getUpdateFunction(operationName, idField, updateQuery, operationType);
updateFunction(cache, { data });
}
};

return { mutation, variables, optimisticResponse, update };
};

// returns the update function used to update the cache by the client
// ignores the scenario where the cache operation is an update as this is handled automatically
// from Apollo client 2.5 onwards.
const getUpdateFunction = (
/**
* Generate the update function to update the cache for a given operation and query.
* Ignores the scenario where the cache operation is an update as this is handled automatically
* from Apollo Client 2.5 onwards.
* @param operation The title of the operation being performed
* @param idField The id field the item keys off
* @param updateQuery The Query to update in the cache
* @param opType The type of operation being performed
*/
export const getUpdateFunction = (
operation: string,
idField: string,
updateQuery: Query,
Expand Down
15 changes: 15 additions & 0 deletions packages/sync/src/cache/createSubscriptionOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@ export interface SubscriptionHelperOptions {
idField?: string;
}

/**
* Helper function which can be used to call subscribeToMore for multiple SubscriptionHelperOptions
* @param observableQuery the query which you would like to call subscribeToMore on.
* @param arrayOfHelperOptions the array of `SubscriptionHelperOptions`
*/
export const subscribeToMoreHelper = (observableQuery: ObservableQuery,
arrayOfHelperOptions: SubscriptionHelperOptions[]) => {
for (const option of arrayOfHelperOptions) {
observableQuery.subscribeToMore(createSubscriptionOptions(option));
}
};

/**
* Creates a SubscribeToMoreOptions object which can be used with Apollo Client's subscribeToMore function
* on an observable query.
* @param options see `SubscriptionHelperOptions`
*/
export const createSubscriptionOptions = (options: SubscriptionHelperOptions): SubscribeToMoreOptions => {
const {
subscriptionQuery,
Expand Down Expand Up @@ -53,6 +63,11 @@ export const createSubscriptionOptions = (options: SubscriptionHelperOptions): S
};
};

/**
* Generate the standard update function to update the cache for a given operation type and query.
* @param opType The type of operation being performed
* @param idField The id field the item keys off
*/
export const getUpdateQueryFunction = (opType: CacheOperation, idField = "id"): UpdateFunction => {
let updateFunction: UpdateFunction;

Expand Down
71 changes: 68 additions & 3 deletions packages/sync/test/CacheHelpersTest.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { expect, should } from "chai";
import { MutationHelperOptions, CacheOperation, createMutationOptions, createSubscriptionOptions } from "../src/cache";
import { CacheOperation, createMutationOptions, createSubscriptionOptions } from "../src/cache";
import {
CREATE_ITEM,
GET_ITEMS,
GET_LISTS,
DELETE_ITEM,
ITEM_CREATED_SUB,
ITEM_DELETED_SUB,
ITEM_UPDATED_SUB
ITEM_UPDATED_SUB,
CREATE_LIST,
DOESNT_EXIST,
GET_NON_EXISTENT
} from "./mock/mutations";
import { NormalizedCacheObject } from "apollo-cache-inmemory";
import { OfflineClient } from "../src";
Expand Down Expand Up @@ -39,6 +43,26 @@ describe("CacheHelpers", () => {
operationType: CacheOperation.DELETE,
idField: "id"
});
const builtOptionsWithArray = createMutationOptions({
mutation: CREATE_LIST,
variables: {
"title": "new list"
},
updateQuery: [{ query: GET_ITEMS, variables: {} }, { query: GET_LISTS, variables: {} }],
typeName: "List",
operationType: CacheOperation.ADD,
idField: "id"
});
const builtNonExistent = createMutationOptions({
mutation: DOESNT_EXIST,
variables: {
"title": "new list"
},
updateQuery: { query: GET_NON_EXISTENT, variables: {} },
typeName: "Something",
operationType: CacheOperation.ADD,
idField: "id"
});
const builtSubCreateOptions = createSubscriptionOptions({
subscriptionQuery: ITEM_CREATED_SUB,
cacheUpdateQuery: GET_ITEMS,
Expand Down Expand Up @@ -70,6 +94,34 @@ describe("CacheHelpers", () => {
}
};

const createList = (id: string) => {
if (builtOptionsWithArray && builtOptionsWithArray.update) {
builtOptionsWithArray.update(client.cache, {
data: {
"createList": {
"id": id,
"title": "new list" + id,
"__typename": "Item"
}
}
});
}
};

const createNonExistent = (id: string) => {
if (builtNonExistent && builtNonExistent.update) {
builtNonExistent.update(client.cache, {
data: {
"somethingFake": {
"id": id,
"title": "new list" + id,
"__typename": "Item"
}
}
});
}
};

const remove = (id: string) => {
if (builtDeleteOptions && builtDeleteOptions.update) {
builtDeleteOptions.update(client.cache, {
Expand All @@ -96,6 +148,12 @@ describe("CacheHelpers", () => {
"allItems": []
}
});
client.writeQuery({
query: GET_LISTS,
data: {
"allLists": []
}
});
});

it("ensures built mutation options include a function", () => {
Expand All @@ -109,6 +167,13 @@ describe("CacheHelpers", () => {
expect(client.readQuery({ query: GET_ITEMS }).allItems).to.have.length(1);
});

it("add item to cache with multiple", () => {
expect(client.readQuery({ query: GET_LISTS }).allLists).to.have.length(0);
createList("1");
expect(client.readQuery({ query: GET_LISTS }).allLists).to.have.length(1);
expect(client.readQuery({ query: GET_ITEMS }).allItems).to.have.length(1);
});

it("delete item from cache", async () => {
expect(client.readQuery({ query: GET_ITEMS }).allItems).to.have.length(0);
create("1");
Expand Down Expand Up @@ -232,7 +297,7 @@ describe("CacheHelpers", () => {
{
subscriptionData: {
data: {
itemUpdated: { }
itemUpdated: {}
}
}
});
Expand Down
34 changes: 34 additions & 0 deletions packages/sync/test/mock/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ mutation createItem($title: String!){
}
`;

export const CREATE_LIST = gql`
mutation createList($title: String!){
createList(title: $title){
title
}
}
`;

export const DELETE_ITEM = gql`
mutation deleteItem($id: ID!){
deleteItem(id: $id){
Expand All @@ -16,6 +24,14 @@ mutation deleteItem($id: ID!){
}
`;

export const DOESNT_EXIST = gql`
mutation somethingFake($id: ID!){
somethingFake(id: $id){
title
}
}
`;

export const GET_ITEMS = gql`
query allItems($first: Int) {
allItems(first: $first) {
Expand All @@ -25,6 +41,24 @@ export const GET_ITEMS = gql`
}
`;

export const GET_LISTS = gql`
query allLists($first: Int) {
allLists(first: $first) {
id
title
}
}
`;

export const GET_NON_EXISTENT = gql`
query somethingFake($first: Int) {
somethingFake(first: $first) {
id
title
}
}
`;

export const ITEM_CREATED_SUB = gql`
subscription itemCreated {
itemCreated {
Expand Down

0 comments on commit f690888

Please sign in to comment.