Socket
Socket
Sign inDemoInstall

apollo-link-state

Package Overview
Dependencies
10
Maintainers
2
Versions
13
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.0 to 0.3.1

src/__tests__/__snapshots__/advanced.ts.snap

9

CHANGELOG.md
# Change log
### vNEXT
### 0.3.1
- Fix propogating errors thrown in resolvers [#148](https://github.com/apollographql/apollo-link-state/pull/148)
- Support aliases in @client queries [#150](https://github.com/apollographql/apollo-link-state/pull/150)
- Fix aliases for default resolvers for @client queries [#162](https://github.com/apollographql/apollo-link-state/pull/162)
- Exposed writeDefaults method on the state link for `client.onResetStore` [#164](https://github.com/apollographql/apollo-link-state/pull/164)
- Removed writeData monkey-patching [#164](https://github.com/apollographql/apollo-link-state/pull/164)
### 0.3.0
- BREAKING: Changed `withClientState` API to take a config object with `resolvers`, `defaults`, and `cache` properties: [#132](https://github.com/apollographql/apollo-link-state/pull/132)

@@ -5,0 +12,0 @@ - Fix overriding fragment parent's __typename: [#131](https://github.com/apollographql/apollo-link-state/pull/131)

251

lib/bundle.umd.js

@@ -7,10 +7,2 @@ (function (global, factory) {

var __assign = (undefined && undefined.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
var connectionRemoveConfig = {

@@ -30,131 +22,13 @@ test: function (directive) { return directive.name.value === 'client'; },

}
function queryFromPojo(obj) {
var op = {
kind: 'OperationDefinition',
operation: 'query',
name: {
kind: 'Name',
value: 'GeneratedClientQuery',
},
selectionSet: selectionSetFromObj(obj),
var __extends = (undefined && undefined.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var out = {
kind: 'Document',
definitions: [op],
};
return out;
}
function fragmentFromPojo(obj, typename) {
var frag = {
kind: 'FragmentDefinition',
typeCondition: {
kind: 'NamedType',
name: {
kind: 'Name',
value: typename || '__FakeType',
},
},
name: {
kind: 'Name',
value: 'GeneratedClientQuery',
},
selectionSet: selectionSetFromObj(obj),
};
var out = {
kind: 'Document',
definitions: [frag],
};
return out;
}
function selectionSetFromObj(obj) {
if (typeof obj === 'number' ||
typeof obj === 'boolean' ||
typeof obj === 'string' ||
typeof obj === 'undefined' ||
obj === null) {
return null;
}
if (Array.isArray(obj)) {
return selectionSetFromObj(obj[0]);
}
var selections = [];
Object.keys(obj).forEach(function (key) {
var field = {
kind: 'Field',
name: {
kind: 'Name',
value: key,
},
};
var nestedSelSet = selectionSetFromObj(obj[key]);
if (nestedSelSet) {
field.selectionSet = nestedSelSet;
}
selections.push(field);
});
var selectionSet = {
kind: 'SelectionSet',
selections: selections,
};
return selectionSet;
}
function addWriteDataToCache(cache) {
cache.writeData = function (_a) {
var id = _a.id, data = _a.data;
if (id) {
var typenameResult = null;
try {
typenameResult = cache.read({
rootId: id,
optimistic: false,
query: justTypenameQuery,
});
}
catch (e) {
}
var __typename = (typenameResult && typenameResult.__typename) || '__ClientData';
var dataToWrite = __assign({ __typename: __typename }, data);
cache.writeFragment({
id: id,
fragment: fragmentFromPojo(dataToWrite, __typename),
data: dataToWrite,
});
}
else {
cache.writeQuery({
query: queryFromPojo(data),
data: data,
});
}
};
}
var justTypenameQuery = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'query',
name: null,
variableDefinitions: null,
directives: [],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
alias: null,
name: {
kind: 'Name',
value: '__typename',
},
arguments: [],
directives: [],
selectionSet: null,
},
],
},
},
],
};
})();
var capitalizeFirstLetter = function (str) { return str.charAt(0).toUpperCase() + str.slice(1); };

@@ -164,55 +38,64 @@ var withClientState = function (_a) {

if (cache && defaults) {
if (!cache.writeData) {
addWriteDataToCache(cache);
}
cache.writeData({ data: defaults });
}
return new apolloLink.ApolloLink(function (operation, forward) {
var isClient = apolloUtilities.hasDirectives(['client'], operation.query);
if (!isClient)
return forward(operation);
var server = removeClientSetsFromDocument(operation.query);
var query = operation.query;
var type = capitalizeFirstLetter((apolloUtilities.getMainDefinition(query) || {}).operation) || 'Query';
var resolver = function (fieldName, rootValue, args, context, info) {
if (rootValue === void 0) { rootValue = {}; }
var fieldValue = rootValue[info.resultKey || fieldName];
if (fieldValue !== undefined)
return fieldValue;
var resolve = resolvers[rootValue.__typename || type][info.resultKey || fieldName];
if (resolve)
return resolve(rootValue, args, context, info);
return new (function (_super) {
__extends(StateLink, _super);
function StateLink() {
return _super !== null && _super.apply(this, arguments) || this;
}
StateLink.prototype.writeDefaults = function () {
if (cache && defaults) {
cache.writeData({ data: defaults });
}
};
return new apolloLink.Observable(function (observer) {
if (server)
operation.query = server;
var obs = server && forward
? forward(operation)
: apolloLink.Observable.of({
data: {},
StateLink.prototype.request = function (operation, forward) {
var isClient = apolloUtilities.hasDirectives(['client'], operation.query);
if (!isClient)
return forward(operation);
var server = removeClientSetsFromDocument(operation.query);
var query = operation.query;
var type = capitalizeFirstLetter((apolloUtilities.getMainDefinition(query) || {}).operation) || 'Query';
var resolver = function (fieldName, rootValue, args, context, info) {
if (rootValue === void 0) { rootValue = {}; }
var fieldValue = rootValue[fieldName];
if (fieldValue !== undefined)
return fieldValue;
var resolverMap = resolvers[rootValue.__typename || type];
var resolve = resolverMap[fieldName];
if (resolve)
return resolve(rootValue, args, context, info);
};
return new apolloLink.Observable(function (observer) {
if (server)
operation.query = server;
var obs = server && forward
? forward(operation)
: apolloLink.Observable.of({
data: {},
});
var observerErrorHandler = observer.error.bind(observer);
var sub = obs.subscribe({
next: function (_a) {
var data = _a.data, errors = _a.errors;
var context = operation.getContext();
graphqlAnywhere_lib_async.graphql(resolver, query, data, context, operation.variables)
.then(function (nextData) {
observer.next({
data: nextData,
errors: errors,
});
observer.complete();
})
.catch(observerErrorHandler);
},
error: observerErrorHandler,
});
var sub = obs.subscribe({
next: function (_a) {
var data = _a.data, errors = _a.errors;
var context = operation.getContext();
var contextCache = context.cache;
if (contextCache && !contextCache.writeData) {
addWriteDataToCache(contextCache);
}
graphqlAnywhere_lib_async.graphql(resolver, query, data, context, operation.variables).then(function (nextData) {
observer.next({
data: nextData,
errors: errors,
});
observer.complete();
});
},
error: observer.error.bind(observer),
return function () {
if (sub)
sub.unsubscribe();
};
});
return function () {
if (sub)
sub.unsubscribe();
};
});
});
};
return StateLink;
}(apolloLink.ApolloLink))();
};

@@ -219,0 +102,0 @@

@@ -1,16 +0,14 @@

import { ApolloLink } from 'apollo-link';
/// <reference types="zen-observable" />
import { ApolloLink, Observable, Operation, NextLink, FetchResult } from 'apollo-link';
import { ApolloCache } from 'apollo-cache';
export declare type ClientStateConfig = {
cache?: ApolloCacheClient;
cache?: ApolloCache<any>;
resolvers: any;
defaults?: any;
};
export declare type WriteDataArgs = {
id?: string;
data: any;
export declare const withClientState: ({resolvers, defaults, cache}?: ClientStateConfig) => {
writeDefaults(): void;
request(operation: Operation, forward: NextLink): Observable<FetchResult<Record<string, any>, Record<string, any>>>;
split(test: (op: Operation) => boolean, left: ApolloLink | ((operation: Operation, forward?: NextLink) => Observable<FetchResult<Record<string, any>, Record<string, any>>>), right?: ApolloLink | ((operation: Operation, forward?: NextLink) => Observable<FetchResult<Record<string, any>, Record<string, any>>>)): ApolloLink;
concat(next: ApolloLink | ((operation: Operation, forward?: NextLink) => Observable<FetchResult<Record<string, any>, Record<string, any>>>)): ApolloLink;
};
export declare type WriteData = {
writeData: ({id, data}: WriteDataArgs) => void;
};
export declare type ApolloCacheClient = ApolloCache<any> & WriteData;
export declare const withClientState: ({resolvers, defaults, cache}?: ClientStateConfig) => ApolloLink;

@@ -1,5 +0,15 @@

import { ApolloLink, Observable } from 'apollo-link';
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import { ApolloLink, Observable, } from 'apollo-link';
import { hasDirectives, getMainDefinition } from 'apollo-utilities';
import { graphql } from 'graphql-anywhere/lib/async';
import { removeClientSetsFromDocument, addWriteDataToCache } from './utils';
import { removeClientSetsFromDocument } from './utils';
var capitalizeFirstLetter = function (str) { return str.charAt(0).toUpperCase() + str.slice(1); };

@@ -9,56 +19,65 @@ export var withClientState = function (_a) {

if (cache && defaults) {
if (!cache.writeData) {
addWriteDataToCache(cache);
}
cache.writeData({ data: defaults });
}
return new ApolloLink(function (operation, forward) {
var isClient = hasDirectives(['client'], operation.query);
if (!isClient)
return forward(operation);
var server = removeClientSetsFromDocument(operation.query);
var query = operation.query;
var type = capitalizeFirstLetter((getMainDefinition(query) || {}).operation) || 'Query';
var resolver = function (fieldName, rootValue, args, context, info) {
if (rootValue === void 0) { rootValue = {}; }
var fieldValue = rootValue[info.resultKey || fieldName];
if (fieldValue !== undefined)
return fieldValue;
var resolve = resolvers[rootValue.__typename || type][info.resultKey || fieldName];
if (resolve)
return resolve(rootValue, args, context, info);
return new (function (_super) {
__extends(StateLink, _super);
function StateLink() {
return _super !== null && _super.apply(this, arguments) || this;
}
StateLink.prototype.writeDefaults = function () {
if (cache && defaults) {
cache.writeData({ data: defaults });
}
};
return new Observable(function (observer) {
if (server)
operation.query = server;
var obs = server && forward
? forward(operation)
: Observable.of({
data: {},
StateLink.prototype.request = function (operation, forward) {
var isClient = hasDirectives(['client'], operation.query);
if (!isClient)
return forward(operation);
var server = removeClientSetsFromDocument(operation.query);
var query = operation.query;
var type = capitalizeFirstLetter((getMainDefinition(query) || {}).operation) || 'Query';
var resolver = function (fieldName, rootValue, args, context, info) {
if (rootValue === void 0) { rootValue = {}; }
var fieldValue = rootValue[fieldName];
if (fieldValue !== undefined)
return fieldValue;
var resolverMap = resolvers[rootValue.__typename || type];
var resolve = resolverMap[fieldName];
if (resolve)
return resolve(rootValue, args, context, info);
};
return new Observable(function (observer) {
if (server)
operation.query = server;
var obs = server && forward
? forward(operation)
: Observable.of({
data: {},
});
var observerErrorHandler = observer.error.bind(observer);
var sub = obs.subscribe({
next: function (_a) {
var data = _a.data, errors = _a.errors;
var context = operation.getContext();
graphql(resolver, query, data, context, operation.variables)
.then(function (nextData) {
observer.next({
data: nextData,
errors: errors,
});
observer.complete();
})
.catch(observerErrorHandler);
},
error: observerErrorHandler,
});
var sub = obs.subscribe({
next: function (_a) {
var data = _a.data, errors = _a.errors;
var context = operation.getContext();
var contextCache = context.cache;
if (contextCache && !contextCache.writeData) {
addWriteDataToCache(contextCache);
}
graphql(resolver, query, data, context, operation.variables).then(function (nextData) {
observer.next({
data: nextData,
errors: errors,
});
observer.complete();
});
},
error: observer.error.bind(observer),
return function () {
if (sub)
sub.unsubscribe();
};
});
return function () {
if (sub)
sub.unsubscribe();
};
});
});
};
return StateLink;
}(ApolloLink))();
};
//# sourceMappingURL=index.js.map
import { DocumentNode } from 'graphql';
import { ApolloCacheClient } from './';
export declare function removeClientSetsFromDocument(query: DocumentNode): DocumentNode;
export declare function queryFromPojo(obj: any): DocumentNode;
export declare function fragmentFromPojo(obj: any, typename?: string): DocumentNode;
export declare function addWriteDataToCache(cache: ApolloCacheClient): void;

@@ -1,9 +0,1 @@

var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
import { checkDocument, removeDirectivesFromDocument, } from 'apollo-utilities';

@@ -24,130 +16,2 @@ var connectionRemoveConfig = {

}
export function queryFromPojo(obj) {
var op = {
kind: 'OperationDefinition',
operation: 'query',
name: {
kind: 'Name',
value: 'GeneratedClientQuery',
},
selectionSet: selectionSetFromObj(obj),
};
var out = {
kind: 'Document',
definitions: [op],
};
return out;
}
export function fragmentFromPojo(obj, typename) {
var frag = {
kind: 'FragmentDefinition',
typeCondition: {
kind: 'NamedType',
name: {
kind: 'Name',
value: typename || '__FakeType',
},
},
name: {
kind: 'Name',
value: 'GeneratedClientQuery',
},
selectionSet: selectionSetFromObj(obj),
};
var out = {
kind: 'Document',
definitions: [frag],
};
return out;
}
function selectionSetFromObj(obj) {
if (typeof obj === 'number' ||
typeof obj === 'boolean' ||
typeof obj === 'string' ||
typeof obj === 'undefined' ||
obj === null) {
return null;
}
if (Array.isArray(obj)) {
return selectionSetFromObj(obj[0]);
}
var selections = [];
Object.keys(obj).forEach(function (key) {
var field = {
kind: 'Field',
name: {
kind: 'Name',
value: key,
},
};
var nestedSelSet = selectionSetFromObj(obj[key]);
if (nestedSelSet) {
field.selectionSet = nestedSelSet;
}
selections.push(field);
});
var selectionSet = {
kind: 'SelectionSet',
selections: selections,
};
return selectionSet;
}
export function addWriteDataToCache(cache) {
cache.writeData = function (_a) {
var id = _a.id, data = _a.data;
if (id) {
var typenameResult = null;
try {
typenameResult = cache.read({
rootId: id,
optimistic: false,
query: justTypenameQuery,
});
}
catch (e) {
}
var __typename = (typenameResult && typenameResult.__typename) || '__ClientData';
var dataToWrite = __assign({ __typename: __typename }, data);
cache.writeFragment({
id: id,
fragment: fragmentFromPojo(dataToWrite, __typename),
data: dataToWrite,
});
}
else {
cache.writeQuery({
query: queryFromPojo(data),
data: data,
});
}
};
}
var justTypenameQuery = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'query',
name: null,
variableDefinitions: null,
directives: [],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
alias: null,
name: {
kind: 'Name',
value: '__typename',
},
arguments: [],
directives: [],
selectionSet: null,
},
],
},
},
],
};
//# sourceMappingURL=utils.js.map
{
"name": "apollo-link-state",
"version": "0.3.0",
"version": "0.3.1",
"description": "An easy way to manage local state with Apollo Link",

@@ -53,4 +53,4 @@ "author": "James Baxley <james@meteor.com>",

"@types/jest": "21.1.5",
"apollo-cache-inmemory": "^1.0.0",
"apollo-client": "^2.0.1",
"apollo-cache-inmemory": "^1.1.5",
"apollo-client": "^2.2.0",
"apollo-link": "^1.0.0",

@@ -57,0 +57,0 @@ "browserify": "14.5.0",

@@ -107,2 +107,71 @@ import gql from 'graphql-tag';

});
it('correctly propagates an error from a client-state resolver', async done => {
const data = {
list: {
__typename: 'List',
items: [
{ __typename: 'ListItem', id: 1, name: 'first', isDone: true },
{ __typename: 'ListItem', id: 2, name: 'second', isDone: false },
],
},
};
// mocked endpoint acting as server data
const http = new ApolloLink(() => Observable.of({ data }));
const local = withClientState({
resolvers: {
Query: {
hasBeenIllegallyTouched: (_, _v, _c) => {
throw new Error('Illegal Query Operation Occurred');
},
},
Mutation: {
touchIllegally: (_, _v, _c) => {
throw new Error('Illegal Mutation Operation Occurred');
},
},
},
});
const client = new ApolloClient({
link: local.concat(http),
cache: new InMemoryCache(),
});
const variables = { id: 1 };
const query = gql`
query hasBeenIllegallyTouched($id: Int!) {
hasBeenIllegallyTouched(id: $id) @client
}
`;
const mutation = gql`
mutation SelectItem($id: Int!) {
touchIllegally(id: $id) @client
}
`;
try {
await client.query({ query, variables });
done.fail('Should have thrown!');
} catch (e) {
// Test Passed!
expect(() => {
throw e;
}).toThrowErrorMatchingSnapshot();
}
try {
await client.mutate({ mutation, variables });
done.fail('Should have thrown!');
} catch (e) {
// Test Passed!
expect(() => {
throw e;
}).toThrowErrorMatchingSnapshot();
}
done();
});
});

@@ -283,2 +283,89 @@ import gql from 'graphql-tag';

});
it('runs default resolvers for aliased fields tagged with @client', () => {
const query = gql`
{
fie: foo @client {
bar
}
}
`;
const cache = new InMemoryCache();
const client = new ApolloClient({
cache,
link: withClientState({
cache,
resolvers: {},
defaults: {
foo: {
bar: 'yo',
__typename: 'Foo',
},
},
}),
});
return client.query({ query }).then(({ data }) => {
expect({ ...data }).toMatchObject({
fie: { bar: 'yo', __typename: 'Foo' },
});
});
});
it('writeDefaults lets you write defaults to the cache after the store is reset', async () => {
const mutation = gql`
mutation foo {
foo @client
}
`;
const query = gql`
{
foo @client
}
`;
const cache = new InMemoryCache();
const stateLink = withClientState({
defaults: {
foo: 'bar',
},
resolvers: {
Mutation: {
foo: (_, $, { cache }) => {
cache.writeData({ data: { foo: 'woo' } });
return null;
},
},
},
cache,
});
const client = new ApolloClient({
cache,
link: stateLink,
});
client.onResetStore(stateLink.writeDefaults);
client.query({ query }).then(({ data }) => {
expect({ ...data }).toEqual({ foo: 'bar' });
});
client
.mutate({ mutation })
.then(() => client.query({ query }))
.then(({ data }) => {
expect({ ...data }).toEqual({ foo: 'woo' });
});
await client.resetStore();
client.query({ query }).then(({ data }) => {
expect({ ...data }).toEqual({ foo: 'bar' });
});
});
});

@@ -285,0 +372,0 @@

@@ -18,2 +18,10 @@ import gql from 'graphql-tag';

const aliasedQuery = gql`
query Test {
fie: foo @client {
bar
}
}
`;
const doubleQuery = gql`

@@ -188,3 +196,3 @@ query Double {

const sample = new ApolloLink(() =>
Observable.of({ data: { baz: { foo: true } } }),
Observable.of({ data: { bar: { foo: true } } }),
);

@@ -200,2 +208,21 @@ const client = withClientState({

it('runs resolvers for client queries when aliases are in use on the @client-tagged node', done => {
const client = withClientState({
resolvers: {
Query: {
foo: () => ({ bar: true }),
fie: () => {
done.fail(
"Called the resolver using the alias' name, instead of the correct resolver name.",
);
},
},
},
});
execute(client, { query: aliasedQuery }).subscribe(({ data }) => {
expect(data).toEqual({ fie: { bar: true } });
done();
}, done.fail);
});
it('passes context to client resolvers', done => {

@@ -202,0 +229,0 @@ const query = gql`

@@ -11,11 +11,2 @@ import gql from 'graphql-tag';

it('attaches writeData to the cache if you pass in defaults', () => {
const cache = {
writeQuery: jest.fn(),
};
withClientState({ cache, resolvers, defaults });
expect('cache.writeData').toBeDefined();
});
it('writes defaults to the cache upon initialization', () => {

@@ -22,0 +13,0 @@ const cache = new InMemoryCache();

@@ -12,74 +12,2 @@ import gql from 'graphql-tag';

describe('writing data with no query', () => {
describe('converts a JavaScript object to a query correctly', () => {
it('basic', () => {
expect(
print(
queryFromPojo({
number: 5,
bool: true,
bool2: false,
undef: undefined,
nullField: null,
str: 'string',
}),
),
).toMatchSnapshot();
});
it('nested', () => {
expect(
print(
queryFromPojo({
number: 5,
bool: true,
nested: {
bool2: false,
undef: undefined,
nullField: null,
str: 'string',
},
}),
),
).toMatchSnapshot();
});
it('arrays', () => {
expect(
print(
queryFromPojo({
number: [5],
bool: [[true]],
nested: [
{
bool2: false,
undef: undefined,
nullField: null,
str: 'string',
},
],
}),
),
).toMatchSnapshot();
});
it('fragments', () => {
expect(
print(
fragmentFromPojo({
number: [5],
bool: [[true]],
nested: [
{
bool2: false,
undef: undefined,
nullField: null,
str: 'string',
},
],
}),
),
).toMatchSnapshot();
});
});
describe('writeData on cache', () => {

@@ -247,5 +175,24 @@ it('lets you write to the cache with a mutation', () => {

start: (_, $, { cache }: { cache: ApolloCacheClient }) => {
// This will cause a warning to be printed because we don't have
// This would cause a warning to be printed because we don't have
// __typename on the obj field. But that's intentional because
// that's exactly the situtation we're trying to test...
// that's exactly the situation we're trying to test...
// Let's swap out console.warn to suppress this one message
const suppressString = '__typename';
const originalWarn = console.warn;
console.warn = (...args: any[]) => {
if (
args.find(element => {
if (typeof element === 'string') {
return element.indexOf(suppressString) !== -1;
}
return false;
}) != null
) {
// Found a thing in the args we told it to exclude
return;
}
originalWarn.apply(console, args);
};
// Actually call the problematic query
cache.writeQuery({

@@ -260,2 +207,4 @@ query,

});
// Restore warning logger
console.warn = originalWarn;

@@ -262,0 +211,0 @@ cache.writeData({

@@ -1,2 +0,8 @@

import { ApolloLink, Observable, Operation, NextLink } from 'apollo-link';
import {
ApolloLink,
Observable,
Operation,
NextLink,
FetchResult,
} from 'apollo-link';
import { ApolloCache } from 'apollo-cache';

@@ -7,3 +13,3 @@

import { removeClientSetsFromDocument, addWriteDataToCache } from './utils';
import { removeClientSetsFromDocument } from './utils';

@@ -13,3 +19,3 @@ const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1);

export type ClientStateConfig = {
cache?: ApolloCacheClient;
cache?: ApolloCache<any>;
resolvers: any;

@@ -19,13 +25,2 @@ defaults?: any;

export type WriteDataArgs = {
id?: string;
data: any;
};
export type WriteData = {
writeData: ({ id, data }: WriteDataArgs) => void;
};
export type ApolloCacheClient = ApolloCache<any> & WriteData;
export const withClientState = (

@@ -35,71 +30,71 @@ { resolvers, defaults, cache }: ClientStateConfig = { resolvers: {} },

if (cache && defaults) {
if (!cache.writeData) {
addWriteDataToCache(cache);
}
cache.writeData({ data: defaults });
}
return new ApolloLink((operation: Operation, forward: NextLink) => {
const isClient = hasDirectives(['client'], operation.query);
return new class StateLink extends ApolloLink {
public writeDefaults() {
if (cache && defaults) {
cache.writeData({ data: defaults });
}
}
if (!isClient) return forward(operation);
public request(
operation: Operation,
forward: NextLink,
): Observable<FetchResult> {
const isClient = hasDirectives(['client'], operation.query);
const server = removeClientSetsFromDocument(operation.query);
const { query } = operation;
const type =
capitalizeFirstLetter(
(getMainDefinition(query) || ({} as any)).operation,
) || 'Query';
if (!isClient) return forward(operation);
const resolver = (fieldName, rootValue = {}, args, context, info) => {
const fieldValue = rootValue[info.resultKey || fieldName];
if (fieldValue !== undefined) return fieldValue;
const server = removeClientSetsFromDocument(operation.query);
const { query } = operation;
const type =
capitalizeFirstLetter(
(getMainDefinition(query) || ({} as any)).operation,
) || 'Query';
// Look for the field in the custom resolver map
const resolve =
resolvers[(rootValue as any).__typename || type][
info.resultKey || fieldName
];
if (resolve) return resolve(rootValue, args, context, info);
};
const resolver = (fieldName, rootValue = {}, args, context, info) => {
const fieldValue = rootValue[fieldName];
if (fieldValue !== undefined) return fieldValue;
return new Observable(observer => {
if (server) operation.query = server;
const obs =
server && forward
? forward(operation)
: Observable.of({
data: {},
});
// Look for the field in the custom resolver map
const resolverMap = resolvers[(rootValue as any).__typename || type];
const resolve = resolverMap[fieldName];
if (resolve) return resolve(rootValue, args, context, info);
};
const sub = obs.subscribe({
next: ({ data, errors }) => {
const context = operation.getContext();
return new Observable(observer => {
if (server) operation.query = server;
const obs =
server && forward
? forward(operation)
: Observable.of({
data: {},
});
// Add a writeData method to the cache
const contextCache: ApolloCacheClient = context.cache;
const observerErrorHandler = observer.error.bind(observer);
if (contextCache && !contextCache.writeData) {
addWriteDataToCache(contextCache);
}
const sub = obs.subscribe({
next: ({ data, errors }) => {
const context = operation.getContext();
graphql(resolver, query, data, context, operation.variables).then(
nextData => {
observer.next({
data: nextData,
errors,
});
observer.complete();
},
);
},
error: observer.error.bind(observer),
graphql(resolver, query, data, context, operation.variables)
.then(nextData => {
observer.next({
data: nextData,
errors,
});
observer.complete();
})
.catch(observerErrorHandler);
},
error: observerErrorHandler,
});
return () => {
if (sub) sub.unsubscribe();
};
});
return () => {
if (sub) sub.unsubscribe();
};
});
});
}
}();
};

@@ -1,9 +0,2 @@

import {
DocumentNode,
DirectiveNode,
OperationDefinitionNode,
SelectionSetNode,
FieldNode,
FragmentDefinitionNode,
} from 'graphql';
import { DocumentNode, DirectiveNode } from 'graphql';

@@ -16,4 +9,2 @@ import {

import { ApolloCacheClient, WriteDataArgs } from './';
const connectionRemoveConfig = {

@@ -43,160 +34,1 @@ test: (directive: DirectiveNode) => directive.name.value === 'client',

}
export function queryFromPojo(obj: any): DocumentNode {
const op: OperationDefinitionNode = {
kind: 'OperationDefinition',
operation: 'query',
name: {
kind: 'Name',
value: 'GeneratedClientQuery',
},
selectionSet: selectionSetFromObj(obj),
};
const out: DocumentNode = {
kind: 'Document',
definitions: [op],
};
return out;
}
export function fragmentFromPojo(obj: any, typename?: string): DocumentNode {
const frag: FragmentDefinitionNode = {
kind: 'FragmentDefinition',
typeCondition: {
kind: 'NamedType',
name: {
kind: 'Name',
value: typename || '__FakeType',
},
},
name: {
kind: 'Name',
value: 'GeneratedClientQuery',
},
selectionSet: selectionSetFromObj(obj),
};
const out: DocumentNode = {
kind: 'Document',
definitions: [frag],
};
return out;
}
function selectionSetFromObj(obj) {
if (
typeof obj === 'number' ||
typeof obj === 'boolean' ||
typeof obj === 'string' ||
typeof obj === 'undefined' ||
obj === null
) {
// No selection set here
return null;
}
if (Array.isArray(obj)) {
// GraphQL queries don't include arrays
return selectionSetFromObj(obj[0]);
}
// Now we know it's an object
const selections: FieldNode[] = [];
Object.keys(obj).forEach(key => {
const field: FieldNode = {
kind: 'Field',
name: {
kind: 'Name',
value: key,
},
};
// Recurse
const nestedSelSet: SelectionSetNode = selectionSetFromObj(obj[key]);
if (nestedSelSet) {
field.selectionSet = nestedSelSet;
}
selections.push(field);
});
const selectionSet: SelectionSetNode = {
kind: 'SelectionSet',
selections,
};
return selectionSet;
}
export function addWriteDataToCache(cache: ApolloCacheClient) {
cache.writeData = ({ id, data }: WriteDataArgs) => {
if (id) {
let typenameResult = null;
// Since we can't use fragments without having a typename in the store,
// we need to make sure we have one.
// To avoid overwriting an existing typename, we need to read it out first
// and generate a fake one if none exists.
try {
typenameResult = cache.read({
rootId: id,
optimistic: false,
query: justTypenameQuery,
});
} catch (e) {
// Do nothing, since an error just means no typename exists
}
// tslint:disable-next-line
const __typename =
(typenameResult && typenameResult.__typename) || '__ClientData';
// Add a type here to satisfy the inmemory cache
const dataToWrite = { __typename, ...data };
cache.writeFragment({
id,
fragment: fragmentFromPojo(dataToWrite, __typename),
data: dataToWrite,
});
} else {
cache.writeQuery({
query: queryFromPojo(data),
data,
});
}
};
}
const justTypenameQuery: DocumentNode = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'query',
name: null,
variableDefinitions: null,
directives: [],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
alias: null,
name: {
kind: 'Name',
value: '__typename',
},
arguments: [],
directives: [],
selectionSet: null,
},
],
},
},
],
};

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc