apollo-link-dedup
Advanced tools
Comparing version 0.0.0 to 0.1.0
{ | ||
"name": "apollo-link-dedup", | ||
"version": "0.0.0", | ||
"version": "0.1.0", | ||
"description": "Deduplicates queries that are currently on the wire", | ||
@@ -5,0 +5,0 @@ "author": "Evans Hauser <evanshauser@gmail.com>", |
@@ -12,10 +12,12 @@ import { | ||
/* | ||
* Expects context to contain the deduplicate field | ||
* Expects context to contain the forceFetch field if no dedup | ||
*/ | ||
export class DedupLink extends ApolloLink { | ||
private inFlightRequestPromises: { [key: string]: Observable<FetchResult> }; | ||
export default class DedupLink extends ApolloLink { | ||
private inFlightRequestObservables: { | ||
[key: string]: Observable<FetchResult>; | ||
}; | ||
constructor() { | ||
super(); | ||
this.inFlightRequestPromises = {}; | ||
this.inFlightRequestObservables = {}; | ||
} | ||
@@ -28,3 +30,3 @@ | ||
// sometimes we might not want to deduplicate a request, for example when we want to force fetch it. | ||
if (!operation.context.deduplicate) { | ||
if (operation.context.forceFetch) { | ||
return forward(operation); | ||
@@ -34,15 +36,15 @@ } | ||
const key = this.getKey(operation); | ||
if (!this.inFlightRequestPromises[key]) { | ||
this.inFlightRequestPromises[key] = forward(operation); | ||
if (!this.inFlightRequestObservables[key]) { | ||
this.inFlightRequestObservables[key] = forward(operation); | ||
} | ||
return new Observable<FetchResult>(observer => { | ||
this.inFlightRequestPromises[key].subscribe({ | ||
this.inFlightRequestObservables[key].subscribe({ | ||
next: observer.next.bind(observer), | ||
error: error => { | ||
delete this.inFlightRequestObservables[key]; | ||
observer.error(error); | ||
delete this.inFlightRequestPromises[key]; | ||
}, | ||
complete: () => { | ||
delete this.inFlightRequestObservables[key]; | ||
observer.complete(); | ||
delete this.inFlightRequestPromises[key]; | ||
}, | ||
@@ -49,0 +51,0 @@ }); |
@@ -1,14 +0,189 @@ | ||
import { assert, expect } from 'chai'; | ||
import * as sinon from 'sinon'; | ||
import { assert } from 'chai'; | ||
import DedupLink from '../src/dedupLink'; | ||
import * as Links from 'apollo-link-core'; | ||
import { ApolloLink, execute } from 'apollo-link-core'; | ||
import { ApolloLink, execute, Operation, Observable } from 'apollo-link-core'; | ||
import { createApolloFetch } from 'apollo-fetch'; | ||
import { print } from 'graphql'; | ||
import gql from 'graphql-tag'; | ||
import * as fetchMock from 'fetch-mock'; | ||
describe('DedupLink', () => {}); | ||
import { DocumentNode } from 'graphql'; | ||
function getOperationName(doc: DocumentNode): string | null { | ||
let res: string | null = null; | ||
doc.definitions.forEach(definition => { | ||
if (definition.kind === 'OperationDefinition' && definition.name) { | ||
res = definition.name.value; | ||
} | ||
}); | ||
return res; | ||
} | ||
describe('DedupLink', () => { | ||
it(`does not affect different queries`, () => { | ||
const document: DocumentNode = gql` | ||
query test1($x: String) { | ||
test(x: $x) | ||
} | ||
`; | ||
const variables1 = { x: 'Hello World' }; | ||
const variables2 = { x: 'Goodbye World' }; | ||
const request1: Operation = { | ||
query: document, | ||
variables: variables1, | ||
operationName: getOperationName(document), | ||
}; | ||
const request2: Operation = { | ||
query: document, | ||
variables: variables2, | ||
operationName: getOperationName(document), | ||
}; | ||
let called = 0; | ||
const deduper = ApolloLink.from([ | ||
new DedupLink(), | ||
() => { | ||
called += 1; | ||
return null; | ||
}, | ||
]); | ||
execute(deduper, request1); | ||
execute(deduper, request2); | ||
assert.equal(called, 2); | ||
}); | ||
it(`will not deduplicate requests following an errored query`, done => { | ||
const document: DocumentNode = gql` | ||
query test1($x: String) { | ||
test(x: $x) | ||
} | ||
`; | ||
const variables = { x: 'Hello World' }; | ||
let error; | ||
const data = { data: { data: 'some data' } }; | ||
const request: Operation = { | ||
query: document, | ||
variables: variables, | ||
operationName: getOperationName(document), | ||
}; | ||
let called = 0; | ||
const deduper = ApolloLink.from([ | ||
new DedupLink(), | ||
() => { | ||
called += 1; | ||
switch (called) { | ||
case 1: | ||
return new Observable(observer => { | ||
error = new Error('some error'); | ||
observer.error(error); | ||
}); | ||
case 2: | ||
return new Observable(observer => { | ||
observer.next(data); | ||
observer.complete(); | ||
}); | ||
default: | ||
assert(false, 'Should not have been called more than twice'); | ||
return null; | ||
} | ||
}, | ||
]); | ||
execute(deduper, request).subscribe({ | ||
error: actualError => { | ||
assert.equal(actualError, error); | ||
//second query | ||
execute(deduper, request).subscribe({ | ||
next: result => { | ||
assert.equal(result, data); | ||
assert.equal(called, 2); | ||
done(); | ||
}, | ||
}); | ||
}, | ||
}); | ||
}); | ||
it(`deduplicates identical queries`, () => { | ||
const document: DocumentNode = gql` | ||
query test1($x: String) { | ||
test(x: $x) | ||
} | ||
`; | ||
const variables1 = { x: 'Hello World' }; | ||
const variables2 = { x: 'Hello World' }; | ||
const request1: Operation = { | ||
query: document, | ||
variables: variables1, | ||
operationName: getOperationName(document), | ||
}; | ||
const request2: Operation = { | ||
query: document, | ||
variables: variables2, | ||
operationName: getOperationName(document), | ||
}; | ||
let called = 0; | ||
const deduper = ApolloLink.from([ | ||
new DedupLink(), | ||
() => { | ||
called += 1; | ||
return new Observable(observer => { | ||
setTimeout(observer.complete.bind(observer)); | ||
}); | ||
}, | ||
]); | ||
execute(deduper, request1).subscribe({}); | ||
execute(deduper, request2).subscribe({}); | ||
assert.equal(called, 1); | ||
}); | ||
it(`can bypass deduplication if desired`, () => { | ||
const document: DocumentNode = gql` | ||
query test1($x: String) { | ||
test(x: $x) | ||
} | ||
`; | ||
const variables1 = { x: 'Hello World' }; | ||
const variables2 = { x: 'Hello World' }; | ||
const request1: Operation = { | ||
query: document, | ||
variables: variables1, | ||
operationName: getOperationName(document), | ||
context: { | ||
forceFetch: true, | ||
}, | ||
}; | ||
const request2: Operation = { | ||
query: document, | ||
variables: variables2, | ||
operationName: getOperationName(document), | ||
context: { | ||
forceFetch: true, | ||
}, | ||
}; | ||
let called = 0; | ||
const deduper = ApolloLink.from([ | ||
new DedupLink(), | ||
() => { | ||
called += 1; | ||
return null; | ||
}, | ||
]); | ||
execute(deduper, request1).subscribe({}); | ||
execute(deduper, request2).subscribe({}); | ||
assert.equal(called, 2); | ||
}); | ||
}); |
@@ -1,1 +0,1 @@ | ||
import './*'; | ||
import './dedupLink'; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29848
18
613
1