From 01dad4f26388baa8caae2a0b9c9b0bbac17b104c Mon Sep 17 00:00:00 2001 From: Alexandre Roux Date: Mon, 21 Aug 2023 19:41:36 +0200 Subject: [PATCH] feat: rest support for list collections --- .../lib/src/document_reference_rest.dart | 5 ++ .../lib/src/firestore_rest_impl.dart | 71 +++++++++++++++++++ firestore_test/lib/list_collections_test.dart | 13 +++- firestore_test/lib/utils_collection_test.dart | 1 - 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/firestore_rest/lib/src/document_reference_rest.dart b/firestore_rest/lib/src/document_reference_rest.dart index 755384d..81992a8 100644 --- a/firestore_rest/lib/src/document_reference_rest.dart +++ b/firestore_rest/lib/src/document_reference_rest.dart @@ -35,6 +35,11 @@ class DocumentReferenceRestImpl @override Future update(Map data) => firestoreRestImpl.updateDocument(path, data); + + @override + Future> listCollections() async { + return firestoreRestImpl.listDocumentCollections(path); + } } class DocumentSnapshotRestImpl diff --git a/firestore_rest/lib/src/firestore_rest_impl.dart b/firestore_rest/lib/src/firestore_rest_impl.dart index 78d0b92..e916876 100644 --- a/firestore_rest/lib/src/firestore_rest_impl.dart +++ b/firestore_rest/lib/src/firestore_rest_impl.dart @@ -721,6 +721,74 @@ class FirestoreRestImpl rethrow; } } + + @override + Future> listCollections() async { + var request = api.ListCollectionIdsRequest(); + var parent = getDocumentRootName(); + var collections = []; + try { + while (true) { + // Debug + if (debugRest) { + print('listCollections: ${jsonPretty(request.toJson())}'); + } + // devPrint('commitRequest: ${jsonPretty(request.toJson())}'); + + // ignore: unused_local_variable + var response = await firestoreApi.projects.databases.documents + .listCollectionIds(request, parent); + print('response: ${jsonPretty(response.toJson())}'); + var stepCollections = (response.collectionIds ?? []) + .map((e) => collection(e)) + .toList(); + if (stepCollections.isEmpty) { + break; + } + collections.addAll(stepCollections); + if (response.nextPageToken == null) { + break; + } + request.pageToken = response.nextPageToken; + } + } catch (e) { + if (e is api.DetailedApiRequestError) { + // devPrint(e.status); + if (e.status == httpStatusCodeNotFound) { + // return DocumentSnapshotRestImpl(this, null); + } + } + rethrow; + } + return collections; + } + + Future> listDocumentCollections(String path) async { + var request = api.ListCollectionIdsRequest(); + var parent = getDocumentName(path); + try { + // Debug + if (debugRest) { + print('listCollections: ${jsonPretty(request.toJson())}'); + } + // devPrint('commitRequest: ${jsonPretty(request.toJson())}'); + + // ignore: unused_local_variable + var response = await firestoreApi.projects.databases.documents + .listCollectionIds(request, parent); + return (response.collectionIds ?? []) + .map((e) => collection(e)) + .toList(); + } catch (e) { + if (e is api.DetailedApiRequestError) { + // devPrint(e.status); + if (e.status == httpStatusCodeNotFound) { + // return DocumentSnapshotRestImpl(this, null); + } + } + rethrow; + } + } } class FirestoreServiceRestImpl @@ -752,6 +820,9 @@ class FirestoreServiceRestImpl @override bool get supportsTrackChanges => false; + + @override + bool get supportsListCollections => true; } /// Join ignoring null but not both! diff --git a/firestore_test/lib/list_collections_test.dart b/firestore_test/lib/list_collections_test.dart index 521970c..e051bdb 100644 --- a/firestore_test/lib/list_collections_test.dart +++ b/firestore_test/lib/list_collections_test.dart @@ -9,23 +9,30 @@ import 'package:test/test.dart'; void runListCollectionsTest({ required Firestore firestore, }) { + // firestore = firestore.debugQuickLoggerWrapper(); test('list root collections', () async { var collectionId = 'tekartik_test_root_collection'; var doc = firestore.doc('$collectionId/doc'); - await doc.set({}); var collections = await firestore.listCollections(); + print('Existing root collections: $collections'); + await doc.set({}); + collections = await firestore.listCollections(); + print('New root collections: $collections'); var collection = collections.firstWhere((element) => element.id == collectionId); expect(collection.path, collectionId); await doc.delete(); - }, solo: true, skip: !firestore.service.supportsListCollections); + }, skip: !firestore.service.supportsListCollections); test('list doc collections', () async { var parent = url.join(testsRefPath, 'tekartik_test_collection'); var collectionId = 'sub'; var doc = firestore.doc('$parent/$collectionId/doc'); - await doc.set({}); var collections = await firestore.doc(parent).listCollections(); + print('Existing collections: $collections'); + await doc.set({}); + collections = await firestore.doc(parent).listCollections(); + print('New collections: $collections'); expect(collections.map((e) => e.id), contains(collectionId)); await doc.delete(); }, skip: !firestore.service.supportsListCollections); diff --git a/firestore_test/lib/utils_collection_test.dart b/firestore_test/lib/utils_collection_test.dart index b915dec..68368e6 100644 --- a/firestore_test/lib/utils_collection_test.dart +++ b/firestore_test/lib/utils_collection_test.dart @@ -21,7 +21,6 @@ void runUtilsCollectionTests( Future findInCollection() async { var querySnapshot = await ref.get(); for (var doc in querySnapshot.docs) { - devPrint('doc ${doc.ref.path}'); if (doc.ref.path == itemDoc.path) { return true; }