Skip to content

Commit

Permalink
fix(firestore): doc and collection methods generic (#2649)
Browse files Browse the repository at this point in the history
Co-authored-by: KingDarBoja <stevenbojato04@gmail.com>
  • Loading branch information
jamesdaniels and KingDarBoja authored Nov 12, 2020
1 parent 6934310 commit 796b7c1
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 47 deletions.
8 changes: 4 additions & 4 deletions src/firestore/collection-group/collection-group.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AngularFireModule, FirebaseApp } from '@angular/fire';
import { AngularFirestore, AngularFirestoreCollectionGroup, AngularFirestoreModule, SETTINGS } from '../public_api';
import { Query, QueryGroupFn } from '../interfaces';
import { QueryGroupFn, Query } from '../interfaces';
import { BehaviorSubject } from 'rxjs';
import { skip, switchMap, take } from 'rxjs/operators';
import { TestBed } from '@angular/core/testing';
Expand All @@ -19,11 +19,11 @@ import {
Stock
} from '../utils.spec';

async function collectionHarness(afs: AngularFirestore, items: number, queryGroupFn?: QueryGroupFn) {
async function collectionHarness(afs: AngularFirestore, items: number, queryGroupFn?: QueryGroupFn<Stock>) {
const randomCollectionName = randomName(afs.firestore);
const ref = afs.firestore.collection(`${randomCollectionName}`);
const firestore: any = afs.firestore;
const collectionGroup: Query = firestore.collectionGroup(randomCollectionName);
const firestore = afs.firestore;
const collectionGroup = firestore.collectionGroup(randomCollectionName) as Query<Stock>;
const queryFn = queryGroupFn || (ref => ref);
const stocks = new AngularFirestoreCollectionGroup<Stock>(queryFn(collectionGroup), afs);
const names = await createRandomStocks(afs.firestore, ref, items);
Expand Down
4 changes: 2 additions & 2 deletions src/firestore/collection-group/collection-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ import { AngularFirestore } from '../firestore';
* // Subscribe to changes as snapshots. This provides you data updates as well as delta updates.
* fakeStock.valueChanges().subscribe(value => console.log(value));
*/
export class AngularFirestoreCollectionGroup<T= DocumentData> {
export class AngularFirestoreCollectionGroup<T = DocumentData> {
/**
* The constructor takes in a CollectionGroupQuery to provide wrapper methods
* for data operations and data streaming.
*/
constructor(
private readonly query: Query,
private readonly query: Query<T>,
private readonly afs: AngularFirestore) { }

/**
Expand Down
6 changes: 3 additions & 3 deletions src/firestore/collection/collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AngularFireModule, FirebaseApp } from '@angular/fire';
import { AngularFirestore, SETTINGS } from '../firestore';
import { AngularFirestoreModule } from '../firestore.module';
import { AngularFirestoreCollection } from './collection';
import { QueryFn } from '../interfaces';
import { QueryFn, CollectionReference } from '../interfaces';
import { BehaviorSubject } from 'rxjs';
import { skip, switchMap, take } from 'rxjs/operators';
import 'firebase/firestore';
Expand All @@ -22,9 +22,9 @@ import {
Stock
} from '../utils.spec';

async function collectionHarness(afs: AngularFirestore, items: number, queryFn?: QueryFn) {
async function collectionHarness(afs: AngularFirestore, items: number, queryFn?: QueryFn<Stock>) {
const randomCollectionName = randomName(afs.firestore);
const ref = afs.firestore.collection(`${randomCollectionName}`);
const ref = afs.firestore.collection(`${randomCollectionName}`) as CollectionReference<Stock>;
if (!queryFn) {
queryFn = (ref) => ref;
}
Expand Down
12 changes: 6 additions & 6 deletions src/firestore/collection/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function validateEventsArray(events?: DocumentChangeType[]) {
* // Subscribe to changes as snapshots. This provides you data updates as well as delta updates.
* fakeStock.valueChanges().subscribe(value => console.log(value));
*/
export class AngularFirestoreCollection<T= DocumentData> {
export class AngularFirestoreCollection<T = DocumentData> {
/**
* The constructor takes in a CollectionReference and Query to provide wrapper methods
* for data operations and data streaming.
Expand All @@ -49,8 +49,8 @@ export class AngularFirestoreCollection<T= DocumentData> {
* on this implication.
*/
constructor(
public readonly ref: CollectionReference,
private readonly query: Query,
public readonly ref: CollectionReference<T>,
private readonly query: Query<T>,
private readonly afs: AngularFirestore) { }

/**
Expand Down Expand Up @@ -134,14 +134,14 @@ export class AngularFirestoreCollection<T= DocumentData> {
* when you update data it is not updating data to the window of your query unless
* the data fits the criteria of the query.
*/
add(data: T): Promise<DocumentReference> {
add(data: T): Promise<DocumentReference<T>> {
return this.ref.add(data);
}

/**
* Create a reference to a single document in a collection.
*/
doc<T2 = T>(path?: string): AngularFirestoreDocument<T2> {
return new AngularFirestoreDocument<T2>(this.ref.doc(path), this.afs);
doc(path?: string): AngularFirestoreDocument<T> {
return new AngularFirestoreDocument<T>(this.ref.doc(path), this.afs);
}
}
10 changes: 6 additions & 4 deletions src/firestore/document/document.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { AngularFirestore, SETTINGS } from '../firestore';
import { AngularFirestoreModule } from '../firestore.module';
import { Subscription } from 'rxjs';
import { AngularFirestoreDocument } from './document';
import { DocumentReference } from '../interfaces';
import { take } from 'rxjs/operators';

import { TestBed } from '@angular/core/testing';
import { COMMON_CONFIG } from '../../test-config';

import { FAKE_STOCK_DATA, rando, randomName, Stock } from '../utils.spec';
import firebase from 'firebase/app';
import 'firebase/firestore';

describe('AngularFirestoreDocument', () => {
Expand Down Expand Up @@ -38,8 +40,8 @@ describe('AngularFirestoreDocument', () => {

it('should get unwrapped snapshot', async (done: any) => {
const randomCollectionName = afs.firestore.collection('a').doc().id;
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
const stock = new AngularFirestoreDocument<Stock>(ref, afs);
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as firebase.firestore.DocumentReference<Stock>;
const stock = new AngularFirestoreDocument(ref, afs);
await stock.set(FAKE_STOCK_DATA);
const obs$ = stock.valueChanges();
obs$.pipe(take(1)).subscribe(async data => {
Expand Down Expand Up @@ -69,7 +71,7 @@ describe('AngularFirestoreDocument', () => {

it('should get action updates', async (done: any) => {
const randomCollectionName = randomName(afs.firestore);
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as DocumentReference<Stock>;
const stock = new AngularFirestoreDocument<Stock>(ref, afs);
await stock.set(FAKE_STOCK_DATA);
const sub = stock
Expand All @@ -85,7 +87,7 @@ describe('AngularFirestoreDocument', () => {

it('should get unwrapped snapshot', async (done: any) => {
const randomCollectionName = afs.firestore.collection('a').doc().id;
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as DocumentReference<Stock>;
const stock = new AngularFirestoreDocument<Stock>(ref, afs);
await stock.set(FAKE_STOCK_DATA);
const obs$ = stock.valueChanges();
Expand Down
8 changes: 4 additions & 4 deletions src/firestore/document/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ import firebase from 'firebase/app';
export class AngularFirestoreDocument<T = DocumentData> {

/**
* The contstuctor takes in a DocumentReference to provide wrapper methods
* The constructor takes in a DocumentReference to provide wrapper methods
* for data operations, data streaming, and Symbol.observable.
*/
constructor(public ref: DocumentReference, private afs: AngularFirestore) { }
constructor(public ref: DocumentReference<T>, private afs: AngularFirestore) { }

/**
* Create or overwrite a single document.
Expand Down Expand Up @@ -62,9 +62,9 @@ export class AngularFirestoreDocument<T = DocumentData> {
* function.
*/
collection<R = DocumentData>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<R> {
const collectionRef = this.ref.collection(path);
const collectionRef = this.ref.collection(path) as firebase.firestore.CollectionReference<R>;
const { ref, query } = associateQuery(collectionRef, queryFn);
return new AngularFirestoreCollection<R>(ref, query, this.afs);
return new AngularFirestoreCollection(ref, query, this.afs);
}

/**
Expand Down
20 changes: 10 additions & 10 deletions src/firestore/firestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const SETTINGS = new InjectionToken<Settings>('angularfire2.firestore.set
* return ref.where('age', '<', 200);
* });
*/
export function associateQuery(collectionRef: CollectionReference, queryFn = ref => ref): AssociatedReference {
export function associateQuery<T>(collectionRef: CollectionReference<T>, queryFn = ref => ref): AssociatedReference<T> {
const query = queryFn(collectionRef);
const ref = collectionRef;
return { query, ref };
Expand Down Expand Up @@ -173,14 +173,14 @@ export class AngularFirestore {
collection<T>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<T>;
// tslint:disable-next-line:unified-signatures
collection<T>(ref: CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection<T>;
collection<T>(pathOrRef: string | CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection<T> {
let collectionRef: CollectionReference;
collection<T>(pathOrRef: string | CollectionReference<T>, queryFn?: QueryFn): AngularFirestoreCollection<T> {
let collectionRef: CollectionReference<T>;
if (typeof pathOrRef === 'string') {
collectionRef = this.firestore.collection(pathOrRef);
collectionRef = this.firestore.collection(pathOrRef) as firebase.firestore.CollectionReference<T>;
} else {
collectionRef = pathOrRef;
}
const { ref, query } = associateQuery(collectionRef, queryFn);
const { ref, query } = associateQuery<T>(collectionRef, queryFn);
const refInZone = this.schedulers.ngZone.run(() => ref);
return new AngularFirestoreCollection<T>(refInZone, query, this);
}
Expand All @@ -190,9 +190,9 @@ export class AngularFirestore {
* and an optional query function to narrow the result
* set.
*/
collectionGroup<T>(collectionId: string, queryGroupFn?: QueryGroupFn): AngularFirestoreCollectionGroup<T> {
collectionGroup<T>(collectionId: string, queryGroupFn?: QueryGroupFn<T>): AngularFirestoreCollectionGroup<T> {
const queryFn = queryGroupFn || (ref => ref);
const collectionGroup: Query = this.firestore.collectionGroup(collectionId);
const collectionGroup: Query<T> = this.firestore.collectionGroup(collectionId) as firebase.firestore.Query<T>;
return new AngularFirestoreCollectionGroup<T>(queryFn(collectionGroup), this);
}

Expand All @@ -205,10 +205,10 @@ export class AngularFirestore {
doc<T>(path: string): AngularFirestoreDocument<T>;
// tslint:disable-next-line:unified-signatures
doc<T>(ref: DocumentReference): AngularFirestoreDocument<T>;
doc<T>(pathOrRef: string | DocumentReference): AngularFirestoreDocument<T> {
let ref: DocumentReference;
doc<T>(pathOrRef: string | DocumentReference<T>): AngularFirestoreDocument<T> {
let ref: DocumentReference<T>;
if (typeof pathOrRef === 'string') {
ref = this.firestore.doc(pathOrRef);
ref = this.firestore.doc(pathOrRef) as firebase.firestore.DocumentReference<T>;
} else {
ref = pathOrRef;
}
Expand Down
16 changes: 8 additions & 8 deletions src/firestore/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { Subscriber } from 'rxjs';
import firebase from 'firebase/app';

export type Settings = firebase.firestore.Settings;
export type CollectionReference = firebase.firestore.CollectionReference;
export type DocumentReference = firebase.firestore.DocumentReference;
export type CollectionReference<T = DocumentData> = firebase.firestore.CollectionReference<T>;
export type DocumentReference<T = DocumentData> = firebase.firestore.DocumentReference<T>;
export type PersistenceSettings = firebase.firestore.PersistenceSettings;
export type DocumentChangeType = firebase.firestore.DocumentChangeType;
export type SnapshotOptions = firebase.firestore.SnapshotOptions;
export type FieldPath = firebase.firestore.FieldPath;
export type Query = firebase.firestore.Query;
export type Query<T = DocumentData> = firebase.firestore.Query<T>;

export type SetOptions = firebase.firestore.SetOptions;
export type DocumentData = firebase.firestore.DocumentData;
Expand Down Expand Up @@ -54,9 +54,9 @@ export interface Reference<T> {

// A convience type for making a query.
// Example: const query = (ref) => ref.where('name', == 'david');
export type QueryFn = (ref: CollectionReference) => Query;
export type QueryFn<T = DocumentData> = (ref: CollectionReference<T>) => Query<T>;

export type QueryGroupFn = (query: Query) => Query;
export type QueryGroupFn<T = DocumentData> = (query: Query<T>) => Query<T>;

/**
* A structure that provides an association between a reference
Expand All @@ -80,7 +80,7 @@ export type QueryGroupFn = (query: Query) => Query;
* publisher: 'SportsPublisher'
* });
*/
export interface AssociatedReference {
ref: CollectionReference;
query: Query;
export interface AssociatedReference<T = DocumentData> {
ref: CollectionReference<T>;
query: Query<T>;
}
12 changes: 6 additions & 6 deletions src/firestore/observable/fromRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { map } from 'rxjs/operators';

function _fromRef<T, R>(ref: Reference<T>, scheduler: SchedulerLike = asyncScheduler): Observable<R> {
return new Observable(subscriber => {
let unsubscribe;
let unsubscribe: () => void;
if (scheduler != null) {
scheduler.schedule(() => {
unsubscribe = ref.onSnapshot(subscriber);
Expand All @@ -21,17 +21,17 @@ function _fromRef<T, R>(ref: Reference<T>, scheduler: SchedulerLike = asyncSched
});
}

export function fromRef<R>(ref: DocumentReference | Query, scheduler?: SchedulerLike) {
export function fromRef<R, T>(ref: DocumentReference<T> | Query<T>, scheduler?: SchedulerLike) {
return _fromRef<typeof ref, R>(ref, scheduler);
}

export function fromDocRef<T>(ref: DocumentReference, scheduler?: SchedulerLike): Observable<Action<DocumentSnapshot<T>>> {
return fromRef<DocumentSnapshot<T>>(ref, scheduler)
export function fromDocRef<T>(ref: DocumentReference<T>, scheduler?: SchedulerLike): Observable<Action<DocumentSnapshot<T>>> {
return fromRef<DocumentSnapshot<T>, T>(ref, scheduler)
.pipe(
map(payload => ({ payload, type: 'value' }))
);
}

export function fromCollectionRef<T>(ref: Query, scheduler?: SchedulerLike): Observable<Action<QuerySnapshot<T>>> {
return fromRef<QuerySnapshot<T>>(ref, scheduler).pipe(map(payload => ({ payload, type: 'query' })));
export function fromCollectionRef<T>(ref: Query<T>, scheduler?: SchedulerLike): Observable<Action<QuerySnapshot<T>>> {
return fromRef<QuerySnapshot<T>, T>(ref, scheduler).pipe(map(payload => ({ payload, type: 'query' })));
}

0 comments on commit 796b7c1

Please sign in to comment.