Skip to content

Commit

Permalink
Upgrade to Apollo v3
Browse files Browse the repository at this point in the history
No breaking changes
  • Loading branch information
AntonyThorpe committed Feb 3, 2021
1 parent 573a7ca commit 3e149c1
Show file tree
Hide file tree
Showing 13 changed files with 20,290 additions and 17,642 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules
*.sublime*
.DS_Store
11 changes: 5 additions & 6 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ A knockoutjs extension to connect to a GraphQL endpoint through an ApolloClient
* Utilises the structure and loading features of [ko.plus](http://stevegreatrex.github.io/ko.plus/) for queries and mutations

## How it works
Attaches additional methods to Observables/Observable Arrays via a [Custom Function](http://knockoutjs.com/documentation/fn.html). This library is strongly influenced by [Vue-Apollo](https://github.com/Akryum/vue-apollo).
Attaches additional methods to Observables/Observable Arrays via a [Custom Function](http://knockoutjs.com/documentation/fn.html). This library is strongly influenced by [Vue-Apollo v1](https://github.com/Akryum/vue-apollo).

## Requirements
* [Apollo Client & Apollo Link](https://github.com/apollographql/apollo-client)
* [Apollo Client](https://github.com/apollographql/apollo-client)
* [GraphQL Tag](https://github.com/apollographql/graphql-tag)
* [Knockout](http://knockoutjs.com)
* [ko.plus](http://stevegreatrex.github.io/ko.plus/)
Expand All @@ -22,9 +22,9 @@ Attaches additional methods to Observables/Observable Arrays via a [Custom Funct
To run a demo in localhost open a terminal and:
* `git clone https://github.com/AntonyThorpe/knockout-apollo.git`.
* And `cd knockout-apollo` and type `npm install`.
* Then `npm run tests` (we use Meteor Tests as a server for the demo)
* To update demo.js with any of your changes open a new terminal and `npm run watch`.
* Once Meteor is up and running open a third terminal, cd to the project root and `npm run demo` to open in Chrome.
* Then `npm run test` (we use Meteor Tests as a server for the demo)
* To update any of the demo files open a new terminal and `npm run watch` to save changes to `dist/demo.js`.
* Once Meteor is up and running open a third terminal, cd to the project root and `npm run demo` to open in Firefox.

## Tests
In the terminal cd to the `tests` folder and `meteor test --driver-package=practicalmeteor:mocha --port 3002`. Or, from project root, `npm run tests`.
Expand All @@ -48,4 +48,3 @@ None sorry.
* [The Anatomy of a GraphQL Query](https://dev-blog.apollodata.com/the-anatomy-of-a-graphql-query-6dffa9e9e747) - Apollo Blog by Sashko Stubailo. The code follows these definitions.
* [Apollo-Vue](https://github.com/Akryum/vue-apollo) - contains good non-React examples
* [Meteor-Ticker](https://github.com/quintstoffers/meteornl-ticker) - Apollo+Meteor app showcasing GraphQL subscriptions in its simplest form
* [How to get Apollo 2.0 working with GraphQL + subscriptions](https://medium.com/@michaelcbrook/how-to-get-apollo-2-0-working-with-graphql-subscriptions-321388be030c)
3 changes: 3 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog of Knockout Apollo

#### 0.5.0
* Upgraded to Apollo v3 (no breaking changes)
* Enabled accessible methods for the Apollo Client of watchQuery, subscribe, readQuery, readFragment, writeQuery, writeFragment, resetStore, onResetStore, clearStore, onClearStore, stop and reFetchObservableQueries
#### 0.4.1
* Upgraded Browsersync to lastest version to correct dependency vulnerability
#### 0.4.0
Expand Down
108 changes: 51 additions & 57 deletions demo/src/viewModel.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,20 @@
/**
* viewModel
* @link https://www.apollographql.com/docs/react/advanced/subscriptions.html#subscriptions-client
* @type function
* @link https://www.apollographql.com/docs/react/migrating/apollo-client-3-migration/#using-apollo-client-without-react
*/
import { ApolloClient } from 'apollo-client';
import { split } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { getMainDefinition } from 'apollo-utilities';
import gql from 'graphql-tag';

// Establish a GraphQL connection
const link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
new WebSocketLink({
uri: 'ws://localhost:4000/graphql',
options: {
reconnect: true
}
}),
new HttpLink(
{ uri: 'http://localhost:4000/graphql' }
)
);

const cache = new InMemoryCache({
dataIdFromObject: object => object._id
import { ApolloClient, InMemoryCache, gql } from '@apollo/client/core';
import { WebSocketLink } from "@apollo/client/link/ws";
import { SubscriptionClient } from "subscriptions-transport-ws";

// Establish a GraphQL connection using websockets
// @link
const client = new SubscriptionClient('ws://localhost:4000/graphql', {
reconnect: true
});
const link = new WebSocketLink(client);

const cache = new InMemoryCache();

const apolloClient = new ApolloClient({
link,
Expand Down Expand Up @@ -87,12 +70,12 @@ function TodoViewModel() {
var self = this;
var data;

// First example - update server based upon multiple changes
self.todoList = ko.observableArray().crud({
constructor: TodoList,
uniqueIdentifier: "_id"
}).launchApollo(apolloClient);
self.todoList.messages = ko.observableArray();

self.todoList.apollo(
{
query: getTodoListQuery
Expand Down Expand Up @@ -197,7 +180,7 @@ function TodoViewModel() {
};

self.cancel = function() {
// return model to cache version
// return model to prior version
self.todoList.cancelEdit();
self.todoList.beforeEdit(null);
};
Expand All @@ -207,7 +190,7 @@ function TodoViewModel() {
self.todoList.selectItem(item);
};

// Second example
// Second example - subscribe to changes in the ViewModel and update the server for each change
self.todoList2 = ko.observableArray().crud({
constructor: TodoList,
uniqueIdentifier: "_id"
Expand Down Expand Up @@ -291,13 +274,14 @@ function TodoViewModel() {
constructor: TodoList,
uniqueIdentifier: "_id"
}).liftOffSubscription(apolloClient);

self.todoList3.messages = ko.observableArray();
self.todoList3.startGraphqlSubscription(
{
query: graphqlDocumentTodoList,
},
{
next: function(data) {
self.todoList3.messages.push(ko.toJSON(data));
switch (data.data.todoList.status) {
case "added":
self.todoList3.insert(data.data.todoList.value);
Expand Down Expand Up @@ -325,7 +309,6 @@ function TodoViewModel() {
constructor: TodoList,
uniqueIdentifier: "_id"
}).launchApollo(apolloClient);

self.todoList4.messages = ko.observableArray();
self.todoList4.loading = true;

Expand Down Expand Up @@ -357,28 +340,36 @@ function TodoViewModel() {
};
},
update: function(cache, {data: {createTodo}}) {
// Read the data from our cache for this query.
// Read the data from our cache for this query
const data = cache.readQuery({ query: getTodoListQuery });

if (createTodo._id < 0) {
// Optimistic data goes into cache
data.todoList.push(createTodo.todoList);
// Optimistic data goes into the cache
let newDataOptimistic = {
...data,
todoList: [...data.todoList, createTodo.todoList]
};
// Write the Optimistic data back to the cache
cache.writeQuery({ query: getTodoListQuery, newDataOptimistic });
} else {
// _id returned from server so push again
data.todoList.push(
{
_id: createTodo._id,
task: item.task.peek(),
completed: item.completed.peek(),
__typename: createTodo.__typename
}
);

let newData = {
...data,
todoList: [
...data.todoList,
{
_id: createTodo._id,
task: item.task.peek(),
completed: item.completed.peek(),
__typename: createTodo.__typename
}
]
};

// Write our data back to the cache
cache.writeQuery({ query: getTodoListQuery, newData });
item._id(createTodo._id); // update _id in knockout
}

// Write our data back to the cache.
cache.writeQuery({ query: getTodoListQuery, data });
}
// close optimistic update
},
Expand Down Expand Up @@ -416,19 +407,24 @@ function TodoViewModel() {
};
},
update: function(cache, {data: {removeTodo}}) {
// Read the data from our cache for this query.
// Read the data from our cache for this query
const data = cache.readQuery({ query: getTodoListQuery });

// remove from store
let newData = {
...data,
todoList: [...data.todoList]
}; // clone

// remove from newData
ko.utils.arrayRemoveItem(
data.todoList,
ko.utils.arrayFirst(data.todoList, function(obj){
newData.todoList,
ko.utils.arrayFirst(newData.todoList, function(obj){
return obj._id === removeTodo._id;
})
);

// Write our data back to the cache.
cache.writeQuery({ query: getTodoListQuery, data });
// Write our data back to the cache
cache.writeQuery({ query: getTodoListQuery, newData });
}
// close optimistic update
},
Expand Down Expand Up @@ -506,8 +502,6 @@ function TodoViewModel() {
};




// Vanilla subscription
/* apolloClient.subscribe({
query: graphqlDocumentTodoList
Expand Down

0 comments on commit 3e149c1

Please sign in to comment.