Skip to content

Commit 967f3f3

Browse files
committed
feat: firestore
1 parent 598edc8 commit 967f3f3

14 files changed

+762
-3
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,8 @@ build/
1010
# Directory created by dartdoc
1111
doc/api/
1212

13-
*.iml
13+
# IntelliJ related
14+
*.iml
15+
*.ipr
16+
*.iws
17+
.idea/

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Currently, only supports admin methods for the following firebase services:
55

66
* authentication
77
* realtime database
8+
* cloud firestore
89

910
## Example using service account
1011

lib/firebase_admin.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,10 @@ library firebase_admin;
33
export 'src/admin.dart';
44
export 'src/app.dart' hide AppInternalsExtension;
55
export 'src/auth.dart';
6-
export 'src/utils/error.dart';
76
export 'src/credential.dart' hide setApplicationDefaultCredential;
7+
export 'src/firestore/collection.dart';
8+
export 'src/firestore/document.dart';
9+
export 'src/firestore/firestore.dart';
10+
export 'src/firestore/query.dart';
11+
export 'src/firestore/transaction.dart';
12+
export 'src/utils/error.dart';

lib/src/app.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ class App {
5050
/// Gets [Storage] service for this application.
5151
Storage storage() => _getService(() => Storage(this));
5252

53+
/// Gets [Firestore] service for this application.
54+
Firestore firestore() => _getService(() => Firestore(this));
55+
5356
/// Renders this app unusable and frees the resources of all associated
5457
/// services.
5558
Future<void> delete() async {

lib/src/firestore/collection.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'package:firebase_admin/src/firestore/document.dart';
2+
import 'package:firebase_admin/src/firestore/firestore.dart';
3+
import 'package:firebase_admin/src/firestore/query.dart';
4+
import 'package:firebase_admin/src/firestore/utils/auto_id_generator.dart';
5+
import 'package:firebase_admin/src/firestore/utils/pointer.dart';
6+
7+
class CollectionReference<T> extends Query<T> {
8+
final Pointer _pointer;
9+
10+
CollectionReference({
11+
required super.firestore,
12+
required super.toFirestore,
13+
required super.fromFirestore,
14+
required super.path,
15+
}) : _pointer = Pointer(path),
16+
super(query: null) {
17+
assert(_pointer.isCollection());
18+
}
19+
20+
DocumentReference<T> doc([String? id]) {
21+
return DocumentReference(
22+
firestore: firestore,
23+
toFirestore: toFirestore,
24+
fromFirestore: fromFirestore,
25+
path: _pointer.documentPath(id ?? AutoIdGenerator.autoId()),
26+
);
27+
}
28+
29+
Future<DocumentSnapshot<T>> add(T data) async {
30+
final document = doc();
31+
return await document.set(data);
32+
}
33+
34+
CollectionReference<R> withConverter<R>({
35+
required FromFirestore<R> fromFirestore,
36+
required ToFirestore<R> toFirestore,
37+
}) {
38+
return CollectionReference<R>(
39+
firestore: firestore,
40+
path: path,
41+
fromFirestore: fromFirestore,
42+
toFirestore: toFirestore,
43+
);
44+
}
45+
}

lib/src/firestore/document.dart

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import 'package:firebase_admin/src/firestore/firestore.dart';
2+
import 'package:firebase_admin/src/firestore/utils/document_snapshot.dart';
3+
import 'package:firebase_admin/src/firestore/utils/pointer.dart';
4+
import 'package:firebase_admin/src/firestore/utils/serialization.dart';
5+
import 'package:googleapis/firestore/v1.dart';
6+
7+
class DocumentReference<T> {
8+
final Firestore firestore;
9+
final ToFirestore<T> toFirestore;
10+
final FromFirestore<T> fromFirestore;
11+
final Pointer _pointer;
12+
String get path => _pointer.path;
13+
String get id => _pointer.id;
14+
15+
DocumentReference({
16+
required this.firestore,
17+
required this.toFirestore,
18+
required this.fromFirestore,
19+
required String path,
20+
}) : _pointer = Pointer(path) {
21+
assert(_pointer.isDocument());
22+
}
23+
24+
Future<DocumentSnapshot<T>> set(T data) async {
25+
final result = await firestore.docsApi.createDocument(
26+
Document(fields: serializeData(toFirestore(data))),
27+
firestore.databasePath,
28+
_pointer.parentPath()!,
29+
documentId: _pointer.id,
30+
);
31+
32+
return SerializableDocumentSnapshot(
33+
firestore: firestore,
34+
toFirestore: toFirestore,
35+
fromFirestore: fromFirestore,
36+
document: result,
37+
);
38+
}
39+
40+
Future<DocumentSnapshot<T>> get() async {
41+
final result = await firestore.docsApi.get('${firestore.databasePath}/$path');
42+
43+
return SerializableDocumentSnapshot(
44+
firestore: firestore,
45+
toFirestore: toFirestore,
46+
fromFirestore: fromFirestore,
47+
document: result,
48+
);
49+
}
50+
51+
Future<DocumentSnapshot<T>> update(Map<String, dynamic> data) async {
52+
final result = await firestore.docsApi.patch(
53+
Document(fields: serializeData(data)),
54+
'${firestore.databasePath}/${_pointer.path}',
55+
);
56+
57+
return SerializableDocumentSnapshot(
58+
firestore: firestore,
59+
toFirestore: toFirestore,
60+
fromFirestore: fromFirestore,
61+
document: result,
62+
);
63+
}
64+
65+
Future<void> delete() async {
66+
await firestore.docsApi.delete('${firestore.databasePath}/$path');
67+
}
68+
69+
DocumentReference<R> withConverter<R>({
70+
required FromFirestore<R> fromFirestore,
71+
required ToFirestore<R> toFirestore,
72+
}) {
73+
return DocumentReference<R>(
74+
firestore: firestore,
75+
path: path,
76+
fromFirestore: fromFirestore,
77+
toFirestore: toFirestore,
78+
);
79+
}
80+
}
81+
82+
abstract class DocumentSnapshot<T> {
83+
final Firestore firestore;
84+
85+
const DocumentSnapshot({
86+
required this.firestore,
87+
});
88+
89+
DocumentReference<T> get reference;
90+
91+
T data();
92+
}

lib/src/firestore/firestore.dart

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import 'package:firebase_admin/src/app.dart';
2+
import 'package:firebase_admin/src/app/app_extension.dart';
3+
import 'package:firebase_admin/src/firestore/collection.dart';
4+
import 'package:firebase_admin/src/firestore/document.dart';
5+
import 'package:firebase_admin/src/firestore/transaction.dart';
6+
import 'package:firebase_admin/src/firestore/utils/serialization.dart';
7+
import 'package:firebase_admin/src/service.dart';
8+
import 'package:firebase_admin/src/utils/api_request.dart';
9+
import 'package:googleapis/firestore/v1.dart';
10+
import 'package:meta/meta.dart';
11+
12+
typedef ToFirestore<T> = Map<String, dynamic> Function(T value);
13+
typedef FromFirestore<T> = T Function(DocumentSnapshot<Map<String, dynamic>> snapshot);
14+
15+
class Firestore implements FirebaseService {
16+
@override
17+
final App app;
18+
19+
final FirestoreApi _api;
20+
21+
@internal
22+
ProjectsDatabasesDocumentsResource get docsApi => _api.projects.databases.documents;
23+
24+
@internal
25+
String get databasePath => 'projects/${app.projectId}/databases/(default)/documents';
26+
27+
Firestore(this.app) : _api = FirestoreApi(AuthorizedHttpClient(app));
28+
29+
@override
30+
Future<void> delete() async {}
31+
32+
CollectionReference<Map<String, dynamic>> collection(String id) {
33+
return CollectionReference(
34+
firestore: this,
35+
fromFirestore: fromFirestore,
36+
toFirestore: toFirestore,
37+
path: id,
38+
);
39+
}
40+
41+
DocumentReference<Map<String, dynamic>> doc(String id) {
42+
return DocumentReference(
43+
firestore: this,
44+
fromFirestore: fromFirestore,
45+
toFirestore: toFirestore,
46+
path: id,
47+
);
48+
}
49+
50+
Future<T> runTransaction<T>(
51+
Future<T> Function(Transaction transaction) handler, {
52+
Duration timeout = const Duration(seconds: 30),
53+
}) {
54+
return Transaction.run(
55+
firestore: this,
56+
timeout: timeout,
57+
handler: handler,
58+
);
59+
}
60+
}

0 commit comments

Comments
 (0)