Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

apollo-magic-refetch

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

apollo-magic-refetch - npm Package Compare versions

Comparing version 1.0.3 to 1.1.0

27

es/index.js

@@ -12,6 +12,20 @@

export default (async function refetch(client, typename, ids, idField = 'id') {
function every(array, predicate) {
for (let elem of array) {
if (!predicate(elem)) return false;
}
return true;
}
export default (async function refetch(client, typenameOrTerms, ids, idField) {
const types = await getSchemaTypes(client);
const finalIds = ids != null ? normalizeIds(ids) : null;
let terms;
if (typeof typenameOrTerms === 'string') {
terms = [[typenameOrTerms, ids, idField]];
} else if (Array.isArray(typenameOrTerms)) {
terms = typenameOrTerms;
} else {
throw new Error(`invalid typename or terms: ${typenameOrTerms}`);
}

@@ -24,7 +38,6 @@ const { queryManager: { queries } } = client;

let data;
if (finalIds) {
const currentResult = observableQuery.currentResult();
if (currentResult) data = currentResult.data;
}
if (doesQueryContain(document, types, typename, data, finalIds, idField)) {
const currentResult = observableQuery.currentResult();
if (currentResult) data = currentResult.data;
if (every(terms, ([typename, ids, idField]) => doesQueryContain(document, types, typename, data, ids != null ? normalizeIds(ids) : null, idField || 'id'))) {
promises.push(observableQuery.refetch());

@@ -31,0 +44,0 @@ }

@@ -11,5 +11,5 @@ 'use strict';

var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);

@@ -20,2 +20,6 @@ var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _set = require('babel-runtime/core-js/set');

@@ -41,8 +45,35 @@

function every(array, predicate) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator3.default)(array), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _elem = _step.value;
if (!predicate(_elem)) return false;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return true;
}
exports.default = function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(client, typename, ids) {
var idField = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'id';
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(client, typenameOrTerms, ids, idField) {
var types, terms, queries, promises, _loop, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, query, _ret;
var types, finalIds, queries, promises, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, query, document, observableQuery, data, currentResult;
return _regenerator2.default.wrap(function _callee$(_context) {

@@ -57,83 +88,117 @@ while (1) {

types = _context.sent;
finalIds = ids != null ? normalizeIds(ids) : null;
queries = client.queryManager.queries;
promises = [];
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
_context.prev = 9;
_iterator = (0, _getIterator3.default)(queries.values());
terms = void 0;
case 11:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
_context.next = 22;
if (!(typeof typenameOrTerms === 'string')) {
_context.next = 8;
break;
}
query = _step.value;
document = query.document, observableQuery = query.observableQuery;
terms = [[typenameOrTerms, ids, idField]];
_context.next = 13;
break;
if (observableQuery) {
_context.next = 16;
case 8:
if (!Array.isArray(typenameOrTerms)) {
_context.next = 12;
break;
}
return _context.abrupt('continue', 19);
terms = typenameOrTerms;
_context.next = 13;
break;
case 16:
data = void 0;
case 12:
throw new Error('invalid typename or terms: ' + typenameOrTerms);
if (finalIds) {
currentResult = observableQuery.currentResult();
case 13:
queries = client.queryManager.queries;
promises = [];
_loop = function _loop(query) {
var document = query.document,
observableQuery = query.observableQuery;
if (!observableQuery) return 'continue';
var data = void 0;
var currentResult = observableQuery.currentResult();
if (currentResult) data = currentResult.data;
if (every(terms, function (_ref2) {
var _ref3 = (0, _slicedToArray3.default)(_ref2, 3),
typename = _ref3[0],
ids = _ref3[1],
idField = _ref3[2];
return (0, _doesQueryContain2.default)(document, types, typename, data, ids != null ? normalizeIds(ids) : null, idField || 'id');
})) {
promises.push(observableQuery.refetch());
}
};
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
_context.prev = 19;
_iterator2 = (0, _getIterator3.default)(queries.values());
case 21:
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
_context.next = 29;
break;
}
if ((0, _doesQueryContain2.default)(document, types, typename, data, finalIds, idField)) {
promises.push(observableQuery.refetch());
query = _step2.value;
_ret = _loop(query);
if (!(_ret === 'continue')) {
_context.next = 26;
break;
}
case 19:
_iteratorNormalCompletion = true;
_context.next = 11;
return _context.abrupt('continue', 26);
case 26:
_iteratorNormalCompletion2 = true;
_context.next = 21;
break;
case 22:
_context.next = 28;
case 29:
_context.next = 35;
break;
case 24:
_context.prev = 24;
_context.t0 = _context['catch'](9);
_didIteratorError = true;
_iteratorError = _context.t0;
case 31:
_context.prev = 31;
_context.t0 = _context['catch'](19);
_didIteratorError2 = true;
_iteratorError2 = _context.t0;
case 28:
_context.prev = 28;
_context.prev = 29;
case 35:
_context.prev = 35;
_context.prev = 36;
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
case 31:
_context.prev = 31;
case 38:
_context.prev = 38;
if (!_didIteratorError) {
_context.next = 34;
if (!_didIteratorError2) {
_context.next = 41;
break;
}
throw _iteratorError;
throw _iteratorError2;
case 34:
return _context.finish(31);
case 41:
return _context.finish(38);
case 35:
return _context.finish(28);
case 42:
return _context.finish(35);
case 36:
_context.next = 38;
case 43:
_context.next = 45;
return promises;
case 38:
case 45:
case 'end':

@@ -143,6 +208,6 @@ return _context.stop();

}
}, _callee, this, [[9, 24, 28, 36], [29,, 31, 35]]);
}, _callee, this, [[19, 31, 35, 43], [36,, 38, 42]]);
}));
function refetch(_x, _x2, _x3) {
function refetch(_x, _x2, _x3, _x4) {
return _ref.apply(this, arguments);

@@ -149,0 +214,0 @@ }

{
"name": "apollo-magic-refetch",
"version": "1.0.3",
"version": "1.1.0",
"description": "magically refetches relevant queries after creates and deletes",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -8,3 +8,4 @@ # apollo-magic-refetch

Handling Apollo cache updates after creating and deleting objects remains a
Handling Apollo cache updates after creating and deleting objects, or
associating and dissociating objects, remains a
[poorly solved problem](https://github.com/apollographql/apollo-client/issues/899).

@@ -20,2 +21,15 @@ `update` and `refetchQueries` props on `Mutation`s couple different areas of

# Table of Contents
* [How it works](#how-it-works)
* [Current limitations](#current-limitations)
* [ES environment requirements](#es-environment-requirements)
* [Type metadata usage](#type-metadata-usage)
* [Handling Deletions](#handling-deletions)
* [Handling Creation](#handling-creation)
* [Handling associations being broken](#handling-associations-being-broken)
* [Handling associations being created](#handling-associations-being-created)
* [API](#api)
+ [`refetch(client, typenameOrTerms, [ids], [idField])`](#refetchclient-typenameorterms-ids-idfield)
## How it works

@@ -145,5 +159,153 @@

## Handling associations being broken
In this example, a view shows a list of `Organization`s, each containing a
sublist of `User`s. When one or more users is removed from an organization,
it makes the following call:
```js
refetch(client, [
['User', userIds],
['Organization', organizationId],
])
```
Passing an array to `refetch` means to only refetch queries containing all of
the conditions in the array. So the query below would be refetched, but a query
containing only `Organizations` or a query containing only `User`s would not.
```js
import * as React from 'react'
import gql from 'graphql-tag'
import refetch from 'apollo-magic-refetch'
import {Mutation, ApolloConsumer} from 'react-apollo'
import OrganizationView from './OrganizationView'
const query = gql`
query {
Organizations {
id
name
Users {
id
username
}
}
}
`
const mutation = gql`
mutation removeUsersFromOrganization($organizationId: Int!, $userIds: [Int!]!) {
result: removeUsersFromOrganization(organizationId: $organizationId, userIds: $userIds) {
organizationId
userIds
}
}
`
const OrganizationViewContainer = ({organization: {id, name, Users}}) => (
<ApolloConsumer>
{client => (
<Mutation
mutation={mutation}
update={(cache, {data: {result: {organizationId, userIds}}}) =>
refetch(client, [
['User', userIds],
['Organization', organizationId],
])
}
>
{removeUsersFromOrganization => (
<OrganizationView
organization={organization}
onRemoveUsers={userIds => removeUsersFromOrganization({
variables: {organizationId, userIds},
})}
/>
)}
</Mutation>
)}
</ApolloConsumer>
)
const OrganizationsViewContainer = () => (
<Query query={query}>
{({data}) => {
const {Organizations} = data || {}
if (!Organizations) return <div />
return (
<div>
<h1>Organizations</h1>
{Organizations.map((organization) => (
<OrganizationViewContainer
key={organization.id}
organization={organization}
/>
)}
</div>
)
}}
</Query>
)
```
## Handling associations being created
Assuming the same `Organization`s/`User`s schema as above, the example performs
the necessary refetches when a user is created and added to an organization:
```js
refetch(client, [
['User'],
['Organization', organizationId],
])
```
In this case no `ids` are given for `User`, so any query containing the an
`Organization` with the given `organizationId` in its results and selecting any
`User`s would be refetched. (This doesn't perfectly exclude cases that fetch
Users and Organizations separately, instead of one nested inside the other, but
it's better than nothing).
```js
import * as React from 'react'
import gql from 'graphql-tag'
import refetch from 'apollo-magic-refetch'
import {Mutation, ApolloConsumer} from 'react-apollo'
import CreateUserForm from './CreateUserForm'
const mutation = gql`
mutation createUser($organizationId: Int!, $values: CreateUser!) {
result: createUser(organizationId: $organizationId, values: $values) {
organizationId
id
username
}
}
`
const CreateUserFormContainer = ({organizationId}) => (
<ApolloConsumer>
{client => (
<Mutation
mutation={mutation}
update={() =>
refetch(client, [
['User'],
['Organization', organizationId],
])
}
>
{createUser => (
<CreateUserForm
onSubmit={values => createUser({
variables: {organizationId, values},
})}
/>
)}
</Mutation>
)}
</ApolloConsumer>
)
```
## API
### `refetch(client, typename, [ids], [idField])`
### `refetch(client, typenameOrTerms, [ids], [idField])`

@@ -156,7 +318,10 @@ #### Arguments

##### `typename: string`
##### `typenameOrTerms: string | Array<Term>`
The `__typename` of the GraphQL type that was created or deleted.
The `__typename` of the GraphQL type that was created or deleted, or an array of
`[typename, ids, idField]` tuples (`ids` and `idField` are optional). If an
array is given, a query must match all of the conditions in the array to be
refetched.
##### `ids: any (*optional*)`
##### `ids: any` (*optional*)

@@ -167,4 +332,4 @@ A single id, an array of ids, or a `Set` of ids that were deleted. If given,

##### `idField: string (*optional, default*: 'id')`
##### `idField: string` (*optional, default*: `'id'`)
The name of the id field in the type that was deleted.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc