Skip to content

Commit 58fced7

Browse files
authored
feat(firestore): Add Firestore
1 parent 4761ba1 commit 58fced7

File tree

12 files changed

+96
-83
lines changed

12 files changed

+96
-83
lines changed

src/firestore/collection-group/collection-group.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { BehaviorSubject } from 'rxjs';
44
import { skip, switchMap, take } from 'rxjs/operators';
55
import { TestBed } from '@angular/core/testing';
66
import { COMMON_CONFIG } from '../../test-config';
7-
import 'firebase/firestore';
87

98
import {
109
createRandomStocks,

src/firestore/collection-group/collection-group.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { from, Observable } from 'rxjs';
22
import { fromCollectionRef } from '../observable/fromRef';
33
import { filter, map, observeOn, scan } from 'rxjs/operators';
4-
import firebase from 'firebase/app';
54

65
import { DocumentChangeAction, DocumentChangeType, DocumentData, Query } from '../interfaces';
76
import { validateEventsArray } from '../collection/collection';
87
import { docChanges, sortedChanges } from '../collection/changes';
98
import { AngularFirestore } from '../firestore';
9+
import { getDocs } from 'firebase/firestore';
1010

1111
/**
1212
* AngularFirestoreCollectionGroup service
@@ -19,7 +19,7 @@ import { AngularFirestore } from '../firestore';
1919
*
2020
* Example:
2121
*
22-
* const collectionGroup = firebase.firestore.collectionGroup('stocks');
22+
* const collectionGroup = collectionGroup('stocks');
2323
* const query = collectionRef.where('price', '>', '0.01');
2424
* const fakeStock = new AngularFirestoreCollectionGroup<Stock>(query, afs);
2525
*
@@ -105,8 +105,10 @@ export class AngularFirestoreCollectionGroup<T = DocumentData> {
105105
/**
106106
* Retrieve the results of the query once.
107107
*/
108-
get(options?: firebase.firestore.GetOptions) {
109-
return from(this.query.get(options)).pipe(
108+
// MARK: Breaking change
109+
// previous: get(options?: firebase.firestore.GetOptions)
110+
get() {
111+
return from(getDocs(this.query)).pipe(
110112
observeOn(this.afs.schedulers.insideAngular)
111113
);
112114
}

src/firestore/collection/changes.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { fromCollectionRef } from '../observable/fromRef';
22
import { Observable, SchedulerLike } from 'rxjs';
33
import { distinctUntilChanged, map, pairwise, scan, startWith } from 'rxjs/operators';
44
import { DocumentChange, DocumentChangeAction, DocumentChangeType, Query } from '../interfaces';
5+
import { refEqual } from 'firebase/firestore';
56

67
/**
78
* Return a stream of document changes on a query. These results are not in sort order but in
@@ -19,8 +20,8 @@ export function docChanges<T>(query: Query, scheduler?: SchedulerLike): Observab
1920
if (priorAction && JSON.stringify(priorAction.payload.metadata) !== JSON.stringify(action.payload.metadata)) {
2021
// go through all the docs in payload and figure out which ones changed
2122
action.payload.docs.forEach((currentDoc, currentIndex) => {
22-
const docChange = docChanges.find(d => d.doc.ref.isEqual(currentDoc.ref));
23-
const priorDoc = priorAction?.payload.docs.find(d => d.ref.isEqual(currentDoc.ref));
23+
const docChange = docChanges.find(d => refEqual(d.doc.ref, currentDoc.ref));
24+
const priorDoc = priorAction?.payload.docs.find(d => refEqual(d.ref, currentDoc.ref));
2425
if (docChange && JSON.stringify(docChange.doc.metadata) === JSON.stringify(currentDoc.metadata) ||
2526
!docChange && priorDoc && JSON.stringify(priorDoc.metadata) === JSON.stringify(currentDoc.metadata)) {
2627
// document doesn't appear to have changed, don't log another action
@@ -94,14 +95,14 @@ function sliceAndSplice<T>(
9495
export function combineChange<T>(combined: DocumentChange<T>[], change: DocumentChange<T>): DocumentChange<T>[] {
9596
switch (change.type) {
9697
case 'added':
97-
if (combined[change.newIndex] && combined[change.newIndex].doc.ref.isEqual(change.doc.ref)) {
98+
if (combined[change.newIndex] && refEqual(combined[change.newIndex].doc.ref, change.doc.ref)) {
9899
// Not sure why the duplicates are getting fired
99100
} else {
100101
return sliceAndSplice(combined, change.newIndex, 0, change);
101102
}
102103
break;
103104
case 'modified':
104-
if (combined[change.oldIndex] == null || combined[change.oldIndex].doc.ref.isEqual(change.doc.ref)) {
105+
if (combined[change.oldIndex] == null || refEqual(combined[change.oldIndex].doc.ref, change.doc.ref)) {
105106
// When an item changes position we first remove it
106107
// and then add it's new position
107108
if (change.oldIndex !== change.newIndex) {
@@ -115,7 +116,7 @@ export function combineChange<T>(combined: DocumentChange<T>[], change: Document
115116
}
116117
break;
117118
case 'removed':
118-
if (combined[change.oldIndex] && combined[change.oldIndex].doc.ref.isEqual(change.doc.ref)) {
119+
if (combined[change.oldIndex] && refEqual(combined[change.oldIndex].doc.ref, change.doc.ref)) {
119120
return sliceAndSplice(combined, change.oldIndex, 1);
120121
}
121122
break;

src/firestore/collection/collection.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { AngularFireModule, FirebaseApp } from '@angular/fire';
22
import { AngularFirestore, SETTINGS, AngularFirestoreModule, AngularFirestoreCollection, QueryFn, CollectionReference } from '@angular/fire/firestore';
33
import { BehaviorSubject } from 'rxjs';
44
import { skip, switchMap, take } from 'rxjs/operators';
5-
import 'firebase/firestore';
65

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

src/firestore/collection/collection.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { from, Observable } from 'rxjs';
22
import { fromCollectionRef } from '../observable/fromRef';
33
import { filter, map, observeOn, pairwise, scan, startWith } from 'rxjs/operators';
4-
import firebase from 'firebase/app';
4+
import { addDoc, doc, getDocs } from 'firebase/firestore';
55

66
import { CollectionReference, DocumentChangeAction, DocumentChangeType, DocumentData, DocumentReference, Query } from '../interfaces';
77
import { docChanges, sortedChanges } from './changes';
@@ -126,8 +126,10 @@ export class AngularFirestoreCollection<T = DocumentData> {
126126
/**
127127
* Retrieve the results of the query once.
128128
*/
129-
get(options?: firebase.firestore.GetOptions) {
130-
return from(this.query.get(options)).pipe(
129+
// MARK: Breaking change
130+
// previous: get(options?: firebase.firestore.GetOptions)
131+
get() {
132+
return from(getDocs(this.query)).pipe(
131133
observeOn(this.afs.schedulers.insideAngular),
132134
);
133135
}
@@ -140,14 +142,14 @@ export class AngularFirestoreCollection<T = DocumentData> {
140142
* the data fits the criteria of the query.
141143
*/
142144
add(data: T): Promise<DocumentReference<T>> {
143-
return this.ref.add(data);
145+
return addDoc(this.ref, data);
144146
}
145147

146148
/**
147149
* Create a reference to a single document in a collection.
148150
*/
149151
doc<T2 = T>(path?: string): AngularFirestoreDocument<T2> {
150152
// TODO is there a better way to solve this type issue
151-
return new AngularFirestoreDocument(this.ref.doc(path) as any, this.afs);
153+
return new AngularFirestoreDocument(doc(this.ref, path) as any, this.afs);
152154
}
153155
}

src/firestore/document/document.spec.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import { TestBed } from '@angular/core/testing';
66
import { COMMON_CONFIG } from '../../test-config';
77

88
import { FAKE_STOCK_DATA, rando, randomName, Stock } from '../utils.spec';
9-
import firebase from 'firebase/app';
10-
import 'firebase/firestore';
119

1210
describe('AngularFirestoreDocument', () => {
1311
let app: FirebaseApp;
@@ -36,7 +34,7 @@ describe('AngularFirestoreDocument', () => {
3634

3735
it('should get unwrapped snapshot', async (done: any) => {
3836
const randomCollectionName = afs.firestore.collection('a').doc().id;
39-
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as firebase.firestore.DocumentReference<Stock>;
37+
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as DocumentReference<Stock>;
4038
const stock = new AngularFirestoreDocument(ref, afs);
4139
await stock.set(FAKE_STOCK_DATA);
4240
const obs$ = stock.valueChanges();

src/firestore/document/document.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { from, Observable } from 'rxjs';
2-
import { Action, DocumentData, DocumentReference, DocumentSnapshot, QueryFn, SetOptions } from '../interfaces';
2+
import { Action, DocumentData, DocumentReference, DocumentSnapshot, QueryFn, SetOptions, CollectionReference } from '../interfaces';
33
import { fromDocRef } from '../observable/fromRef';
44
import { map, observeOn } from 'rxjs/operators';
55
import { AngularFirestore, associateQuery } from '../firestore';
66
import { AngularFirestoreCollection } from '../collection/collection';
7-
import firebase from 'firebase/app';
7+
import { setDoc, updateDoc, deleteDoc, getDoc, collection } from 'firebase/firestore';
88

99
/**
1010
* AngularFirestoreDocument service
@@ -40,29 +40,29 @@ export class AngularFirestoreDocument<T = DocumentData> {
4040
* Create or overwrite a single document.
4141
*/
4242
set(data: T, options?: SetOptions): Promise<void> {
43-
return this.ref.set(data, options);
43+
return setDoc(this.ref, data, options);
4444
}
4545

4646
/**
4747
* Update some fields of a document without overwriting the entire document.
4848
*/
4949
update(data: Partial<T>): Promise<void> {
50-
return this.ref.update(data);
50+
return updateDoc(this.ref, data);
5151
}
5252

5353
/**
5454
* Delete a document.
5555
*/
5656
delete(): Promise<void> {
57-
return this.ref.delete();
57+
return deleteDoc(this.ref);
5858
}
5959

6060
/**
6161
* Create a reference to a sub-collection given a path and an optional query
6262
* function.
6363
*/
6464
collection<R = DocumentData>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<R> {
65-
const collectionRef = this.ref.collection(path) as firebase.firestore.CollectionReference<R>;
65+
const collectionRef = collection(this.ref, path) as CollectionReference<R>;
6666
const { ref, query } = associateQuery(collectionRef, queryFn);
6767
return new AngularFirestoreCollection(ref, query, this.afs);
6868
}
@@ -99,8 +99,10 @@ export class AngularFirestoreDocument<T = DocumentData> {
9999
/**
100100
* Retrieve the document once.
101101
*/
102-
get(options?: firebase.firestore.GetOptions) {
103-
return from(this.ref.get(options)).pipe(
102+
// MARK: Breaking change
103+
// previous: get(options?: firebase.firestore.GetOptions)
104+
get() {
105+
return from(getDoc(this.ref)).pipe(
104106
observeOn(this.afs.schedulers.insideAngular),
105107
);
106108
}

src/firestore/firestore.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { AngularFirestore, SETTINGS, AngularFirestoreModule, AngularFirestoreDoc
33

44
import { TestBed } from '@angular/core/testing';
55
import { COMMON_CONFIG } from '../test-config';
6-
import 'firebase/firestore';
76
import { rando } from './utils.spec';
87

98
describe('AngularFirestore', () => {

src/firestore/firestore.ts

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ import {
2424
FirebaseApp
2525
} from '@angular/fire';
2626
import { isPlatformServer } from '@angular/common';
27-
import firebase from 'firebase/app';
28-
import 'firebase/firestore';
27+
import { FirebaseFirestore, useFirestoreEmulator, enableIndexedDbPersistence, collection, collectionGroup, doc } from 'firebase/firestore';
2928
import { USE_EMULATOR as USE_AUTH_EMULATOR } from '@angular/fire/auth';
3029
import { ɵfetchInstance, ɵlogAuthEmulatorError } from '@angular/fire';
3130

@@ -36,8 +35,8 @@ export const ENABLE_PERSISTENCE = new InjectionToken<boolean>('angularfire2.enab
3635
export const PERSISTENCE_SETTINGS = new InjectionToken<PersistenceSettings | undefined>('angularfire2.firestore.persistenceSettings');
3736
export const SETTINGS = new InjectionToken<Settings>('angularfire2.firestore.settings');
3837

39-
// SEMVER(7): use Parameters to detirmine the useEmulator arguments
40-
// type UseEmulatorArguments = Parameters<typeof firebase.firestore.Firestore.prototype.useEmulator>;
38+
// SEMVER(7): use Parameters to determine the useEmulator arguments
39+
// type UseEmulatorArguments = Parameters<typeof Firestore.prototype.useEmulator>;
4140
type UseEmulatorArguments = [string, number];
4241
export const USE_EMULATOR = new InjectionToken<UseEmulatorArguments>('angularfire2.firestore.use-emulator');
4342

@@ -60,8 +59,8 @@ export function associateQuery<T>(collectionRef: CollectionReference<T>, queryFn
6059
}
6160

6261
type InstanceCache = Map<FirebaseApp, [
63-
firebase.firestore.Firestore,
64-
firebase.firestore.Settings | null,
62+
FirebaseFirestore,
63+
Settings | null,
6564
UseEmulatorArguments | null,
6665
boolean | null]
6766
>;
@@ -125,7 +124,7 @@ type InstanceCache = Map<FirebaseApp, [
125124
providedIn: 'any'
126125
})
127126
export class AngularFirestore {
128-
public readonly firestore: firebase.firestore.Firestore;
127+
public readonly firestore: FirebaseFirestore;
129128
public readonly persistenceEnabled$: Observable<boolean>;
130129
public readonly schedulers: ɵAngularFireSchedulers;
131130
public readonly keepUnstableUntilFirst: <T>(obs: Observable<T>) => Observable<T>;
@@ -151,26 +150,30 @@ export class AngularFirestore {
151150
this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers);
152151

153152
const app = ɵfirebaseAppFactory(options, zone, nameOrConfig);
154-
if (!firebase.auth && useAuthEmulator) {
155-
ɵlogAuthEmulatorError();
156-
}
153+
// if (!firebase.auth && useAuthEmulator) {
154+
// ɵlogAuthEmulatorError();
155+
// }
157156
const useEmulator: UseEmulatorArguments | null = _useEmulator;
158157

159158
[this.firestore, this.persistenceEnabled$] = ɵfetchInstance(`${app.name}.firestore`, 'AngularFirestore', app, () => {
160159
const firestore = zone.runOutsideAngular(() => app.firestore());
161-
if (settings) {
162-
firestore.settings(settings);
163-
}
160+
161+
// TODO(team): Initialize settings in NgModule for initializeFirestore()
162+
// if (settings) {
163+
// firestore.settings(settings);
164+
// }
165+
164166
if (useEmulator) {
165-
firestore.useEmulator(...useEmulator);
167+
const [host, port] = useEmulator;
168+
useFirestoreEmulator(firestore, host, port);
166169
}
167170

168171
if (shouldEnablePersistence && !isPlatformServer(platformId)) {
169172
// We need to try/catch here because not all enablePersistence() failures are caught
170173
// https://github.com/firebase/firebase-js-sdk/issues/608
171174
const enablePersistence = () => {
172175
try {
173-
return from(firestore.enablePersistence(persistenceSettings || undefined).then(() => true, () => false));
176+
return from(enableIndexedDbPersistence(firestore, persistenceSettings || undefined).then(() => true, () => false));
174177
} catch (e) {
175178
if (typeof console !== 'undefined') { console.warn(e); }
176179
return of(false);
@@ -195,7 +198,7 @@ export class AngularFirestore {
195198
collection<T>(pathOrRef: string | CollectionReference<T>, queryFn?: QueryFn): AngularFirestoreCollection<T> {
196199
let collectionRef: CollectionReference<T>;
197200
if (typeof pathOrRef === 'string') {
198-
collectionRef = this.firestore.collection(pathOrRef) as firebase.firestore.CollectionReference<T>;
201+
collectionRef = collection(this.firestore, pathOrRef) as CollectionReference<T>;
199202
} else {
200203
collectionRef = pathOrRef;
201204
}
@@ -211,8 +214,8 @@ export class AngularFirestore {
211214
*/
212215
collectionGroup<T>(collectionId: string, queryGroupFn?: QueryGroupFn<T>): AngularFirestoreCollectionGroup<T> {
213216
const queryFn = queryGroupFn || (ref => ref);
214-
const collectionGroup: Query<T> = this.firestore.collectionGroup(collectionId) as firebase.firestore.Query<T>;
215-
return new AngularFirestoreCollectionGroup<T>(queryFn(collectionGroup), this);
217+
const colGroup: Query<T> = collectionGroup(this.firestore, collectionId) as Query<T>;
218+
return new AngularFirestoreCollectionGroup<T>(queryFn(colGroup), this);
216219
}
217220

218221
/**
@@ -227,7 +230,7 @@ export class AngularFirestore {
227230
doc<T>(pathOrRef: string | DocumentReference<T>): AngularFirestoreDocument<T> {
228231
let ref: DocumentReference<T>;
229232
if (typeof pathOrRef === 'string') {
230-
ref = this.firestore.doc(pathOrRef) as firebase.firestore.DocumentReference<T>;
233+
ref = doc(this.firestore, pathOrRef) as DocumentReference<T>;
231234
} else {
232235
ref = pathOrRef;
233236
}
@@ -239,6 +242,7 @@ export class AngularFirestore {
239242
* Returns a generated Firestore Document Id.
240243
*/
241244
createId() {
242-
return this.firestore.collection('_').doc().id;
245+
const col = collection(this.firestore, '_');
246+
return doc(col).id;
243247
}
244248
}

0 commit comments

Comments
 (0)