diff --git a/.changeset/rare-ways-hunt.md b/.changeset/rare-ways-hunt.md new file mode 100644 index 000000000..cb7a5131b --- /dev/null +++ b/.changeset/rare-ways-hunt.md @@ -0,0 +1,5 @@ +--- +'apollo-angular': patch +--- + +`fetchMore` typing is duplicated from `@apollo/client` diff --git a/.changeset/thin-otters-move.md b/.changeset/thin-otters-move.md deleted file mode 100644 index ce0d34ee2..000000000 --- a/.changeset/thin-otters-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'apollo-angular': patch ---- - -Let types flow naturally from `ObservableQuery` diff --git a/packages/apollo-angular/src/query-ref.ts b/packages/apollo-angular/src/query-ref.ts index 5a1462499..4d4fb52b5 100644 --- a/packages/apollo-angular/src/query-ref.ts +++ b/packages/apollo-angular/src/query-ref.ts @@ -2,9 +2,13 @@ import { from, Observable } from 'rxjs'; import { NgZone } from '@angular/core'; import type { ApolloQueryResult, + FetchMoreQueryOptions, + MaybeMasked, ObservableQuery, OperationVariables, + SubscribeToMoreOptions, TypedDocumentNode, + Unmasked, } from '@apollo/client/core'; import { NetworkStatus } from '@apollo/client/core'; import { EmptyObject, WatchQueryOptions } from './types'; @@ -42,79 +46,107 @@ function useInitialLoading(obsQuery: Observable export type QueryRefFromDocument = T extends TypedDocumentNode ? QueryRef : never; -export class QueryRef - implements - Pick< - ObservableQuery, - | 'queryId' - | 'options' - | 'variables' - | 'result' - | 'getCurrentResult' - | 'getLastResult' - | 'getLastError' - | 'resetLastResults' - | 'refetch' - | 'fetchMore' - | 'subscribeToMore' - | 'updateQuery' - | 'stopPolling' - | 'startPolling' - | 'setOptions' - | 'setVariables' - > -{ +export class QueryRef { public readonly valueChanges: Observable>; - - // Types flow straight from ObservableQuery - public readonly queryId; - public readonly result; - public readonly getCurrentResult; - public readonly getLastResult; - public readonly getLastError; - public readonly resetLastResults; - public readonly refetch; - public readonly fetchMore; - public readonly subscribeToMore; - public readonly updateQuery; - public readonly stopPolling; - public readonly startPolling; - public readonly setOptions; - public readonly setVariables; + public readonly queryId: ObservableQuery['queryId']; constructor( - private readonly query: ObservableQuery, + private readonly obsQuery: ObservableQuery, ngZone: NgZone, options: WatchQueryOptions, ) { - const wrapped = wrapWithZone(from(fixObservable(this.query)), ngZone); + const wrapped = wrapWithZone(from(fixObservable(this.obsQuery)), ngZone); this.valueChanges = options.useInitialLoading - ? wrapped.pipe(useInitialLoading(this.query)) + ? wrapped.pipe(useInitialLoading(this.obsQuery)) : wrapped; - this.queryId = this.query.queryId; - - // ObservableQuery's methods - this.result = this.query.result.bind(this.query); - this.getCurrentResult = this.query.getCurrentResult.bind(this.query); - this.getLastResult = this.query.getLastResult.bind(this.query); - this.getLastError = this.query.getLastError.bind(this.query); - this.resetLastResults = this.query.resetLastResults.bind(this.query); - this.refetch = this.query.refetch.bind(this.query); - this.fetchMore = this.query.fetchMore.bind(this.query); - this.subscribeToMore = this.query.subscribeToMore.bind(this.query); - this.updateQuery = this.query.updateQuery.bind(this.query); - this.stopPolling = this.query.stopPolling.bind(this.query); - this.startPolling = this.query.startPolling.bind(this.query); - this.setOptions = this.query.setOptions.bind(this.query); - this.setVariables = this.query.setVariables.bind(this.query); - } - - public get options() { - return this.query.options; - } - - public get variables() { - return this.query.variables; + this.queryId = this.obsQuery.queryId; + } + + // ObservableQuery's methods + + public get options(): ObservableQuery['options'] { + return this.obsQuery.options; + } + + public get variables(): ObservableQuery['variables'] { + return this.obsQuery.variables; + } + + public result(): ReturnType['result']> { + return this.obsQuery.result(); + } + + public getCurrentResult(): ReturnType['getCurrentResult']> { + return this.obsQuery.getCurrentResult(); + } + + public getLastResult(): ReturnType['getLastResult']> { + return this.obsQuery.getLastResult(); + } + + public getLastError(): ReturnType['getLastError']> { + return this.obsQuery.getLastError(); + } + + public resetLastResults(): ReturnType['resetLastResults']> { + return this.obsQuery.resetLastResults(); + } + + public refetch( + variables?: Parameters['refetch']>[0], + ): ReturnType['refetch']> { + return this.obsQuery.refetch(variables); + } + + public fetchMore( + fetchMoreOptions: FetchMoreQueryOptions & { + updateQuery?: ( + previousQueryResult: Unmasked, + options: { + fetchMoreResult: Unmasked; + variables: TFetchVars; + }, + ) => Unmasked; + }, + ): Promise>> { + return this.obsQuery.fetchMore(fetchMoreOptions); + } + + public subscribeToMore< + TSubscriptionData = TData, + TSubscriptionVariables extends OperationVariables = TVariables, + >( + options: SubscribeToMoreOptions, + ): ReturnType['subscribeToMore']> { + return this.obsQuery.subscribeToMore(options); + } + + public updateQuery( + mapFn: Parameters['updateQuery']>[0], + ): ReturnType['updateQuery']> { + return this.obsQuery.updateQuery(mapFn); + } + + public stopPolling(): ReturnType['stopPolling']> { + return this.obsQuery.stopPolling(); + } + + public startPolling( + pollInterval: Parameters['startPolling']>[0], + ): ReturnType['startPolling']> { + return this.obsQuery.startPolling(pollInterval); + } + + public setOptions( + opts: Parameters['setOptions']>[0], + ): ReturnType['setOptions']> { + return this.obsQuery.setOptions(opts); + } + + public setVariables( + variables: Parameters['setVariables']>[0], + ): ReturnType['setVariables']> { + return this.obsQuery.setVariables(variables); } } diff --git a/packages/apollo-angular/tests/Apollo.spec.ts b/packages/apollo-angular/tests/Apollo.spec.ts index fb1789adf..a993d1a6b 100644 --- a/packages/apollo-angular/tests/Apollo.spec.ts +++ b/packages/apollo-angular/tests/Apollo.spec.ts @@ -83,10 +83,10 @@ describe('Apollo', () => { `, }; - const spy = jest.spyOn(client, 'watchQuery'); + client.watchQuery = jest.fn().mockReturnValue(new Observable()); apollo.watchQuery(options); - expect(spy).toBeCalledWith(options); + expect(client.watchQuery).toBeCalledWith(options); }); test('should be able to refetch', (done: jest.DoneCallback) => { diff --git a/packages/apollo-angular/tests/QueryRef.spec.ts b/packages/apollo-angular/tests/QueryRef.spec.ts index 1784df1b2..9fbff5755 100644 --- a/packages/apollo-angular/tests/QueryRef.spec.ts +++ b/packages/apollo-angular/tests/QueryRef.spec.ts @@ -12,16 +12,8 @@ const createClient = (link: ApolloLink) => cache: new InMemoryCache(), }); -type Result = { - heroes: { name: string }[]; -}; - -type Variables = { - foo?: number; -}; - const heroesOperation = { - query: gql` + query: gql` query allHeroes { heroes { name @@ -48,7 +40,8 @@ const Batman = { describe('QueryRef', () => { let ngZone: NgZone; let client: ApolloClient; - let obsQuery: ObservableQuery; + let obsQuery: ObservableQuery; + let queryRef: QueryRef; beforeEach(() => { ngZone = { run: jest.fn(cb => cb()) } as any; @@ -65,14 +58,10 @@ describe('QueryRef', () => { client = createClient(mockedLink); obsQuery = client.watchQuery(heroesOperation); + queryRef = new QueryRef(obsQuery, ngZone, {} as any); }); - function createQueryRef(obsQuery: ObservableQuery): QueryRef { - return new QueryRef(obsQuery, ngZone, { query: heroesOperation.query }); - } - test('should listen to changes', done => { - const queryRef = createQueryRef(obsQuery); queryRef.valueChanges.subscribe({ next: result => { expect(result.data).toBeDefined(); @@ -88,7 +77,6 @@ describe('QueryRef', () => { const mockCallback = jest.fn(); obsQuery.refetch = mockCallback; - const queryRef = createQueryRef(obsQuery); queryRef.refetch(); expect(mockCallback.mock.calls.length).toBe(1); @@ -97,7 +85,6 @@ describe('QueryRef', () => { test('should be able refetch and receive new results', done => { let calls = 0; - const queryRef = createQueryRef(obsQuery); queryRef.valueChanges.subscribe({ next: result => { calls++; @@ -123,7 +110,6 @@ describe('QueryRef', () => { test('should be able refetch and receive new results after using rxjs operator', done => { let calls = 0; - const queryRef = createQueryRef(obsQuery); const obs = queryRef.valueChanges; obs.pipe(map(result => result.data)).subscribe({ @@ -153,10 +139,9 @@ describe('QueryRef', () => { test('should be able to call updateQuery()', () => { const mockCallback = jest.fn(); - const mapFn = () => undefined; + const mapFn = () => ({}); obsQuery.updateQuery = mockCallback; - const queryRef = createQueryRef(obsQuery); queryRef.updateQuery(mapFn); expect(mockCallback.mock.calls.length).toBe(1); @@ -167,7 +152,6 @@ describe('QueryRef', () => { const mockCallback = jest.fn(); obsQuery.result = mockCallback.mockReturnValue('expected'); - const queryRef = createQueryRef(obsQuery); const result = queryRef.result(); expect(result).toBe('expected'); @@ -176,7 +160,6 @@ describe('QueryRef', () => { test('should be able to call getCurrentResult() and get updated results', done => { let calls = 0; - const queryRef = createQueryRef(obsQuery); const obs = queryRef.valueChanges; obs.pipe(map(result => result.data)).subscribe({ @@ -206,7 +189,6 @@ describe('QueryRef', () => { const mockCallback = jest.fn(); obsQuery.getLastResult = mockCallback.mockReturnValue('expected'); - const queryRef = createQueryRef(obsQuery); const result = queryRef.getLastResult(); expect(result).toBe('expected'); @@ -217,7 +199,6 @@ describe('QueryRef', () => { const mockCallback = jest.fn(); obsQuery.getLastError = mockCallback.mockReturnValue('expected'); - const queryRef = createQueryRef(obsQuery); const result = queryRef.getLastError(); expect(result).toBe('expected'); @@ -228,7 +209,6 @@ describe('QueryRef', () => { const mockCallback = jest.fn(); obsQuery.resetLastResults = mockCallback.mockReturnValue('expected'); - const queryRef = createQueryRef(obsQuery); const result = queryRef.resetLastResults(); expect(result).toBe('expected'); @@ -237,11 +217,10 @@ describe('QueryRef', () => { test('should be able to call fetchMore()', () => { const mockCallback = jest.fn(); - const opts = { variables: { foo: 1 } }; + const opts = { foo: 1 }; obsQuery.fetchMore = mockCallback.mockReturnValue('expected'); - const queryRef = createQueryRef(obsQuery); - const result = queryRef.fetchMore(opts); + const result = queryRef.fetchMore(opts as any); expect(result).toBe('expected'); expect(mockCallback.mock.calls.length).toBe(1); @@ -250,11 +229,10 @@ describe('QueryRef', () => { test('should be able to call subscribeToMore()', () => { const mockCallback = jest.fn(); - const opts = { document: heroesOperation.query }; + const opts = { foo: 1 }; obsQuery.subscribeToMore = mockCallback; - const queryRef = createQueryRef(obsQuery); - queryRef.subscribeToMore(opts); + queryRef.subscribeToMore(opts as any); expect(mockCallback.mock.calls.length).toBe(1); expect(mockCallback.mock.calls[0][0]).toBe(opts); @@ -264,7 +242,6 @@ describe('QueryRef', () => { const mockCallback = jest.fn(); obsQuery.stopPolling = mockCallback; - const queryRef = createQueryRef(obsQuery); queryRef.stopPolling(); expect(mockCallback.mock.calls.length).toBe(1); @@ -274,7 +251,6 @@ describe('QueryRef', () => { const mockCallback = jest.fn(); obsQuery.startPolling = mockCallback; - const queryRef = createQueryRef(obsQuery); queryRef.startPolling(3000); expect(mockCallback.mock.calls.length).toBe(1); @@ -286,7 +262,6 @@ describe('QueryRef', () => { const opts = {}; obsQuery.setOptions = mockCallback.mockReturnValue('expected'); - const queryRef = createQueryRef(obsQuery); const result = queryRef.setOptions(opts); expect(result).toBe('expected'); @@ -299,7 +274,6 @@ describe('QueryRef', () => { const variables = {}; obsQuery.setVariables = mockCallback.mockReturnValue('expected'); - const queryRef = createQueryRef(obsQuery); const result = queryRef.setVariables(variables); expect(result).toBe('expected'); @@ -308,7 +282,6 @@ describe('QueryRef', () => { }); test('should handle multiple subscribers', done => { - const queryRef = createQueryRef(obsQuery); const obsFirst = queryRef.valueChanges; const obsSecond = queryRef.valueChanges; @@ -365,7 +338,6 @@ describe('QueryRef', () => { }); test('should unsubscribe', done => { - const queryRef = createQueryRef(obsQuery); const obs = queryRef.valueChanges; const id = queryRef.queryId; @@ -384,7 +356,6 @@ describe('QueryRef', () => { test('should unsubscribe based on rxjs operators', done => { const gate = new Subject(); - const queryRef = createQueryRef(obsQuery); const obs = queryRef.valueChanges.pipe(takeUntil(gate)); const id = queryRef.queryId;