Closed amrfarid140 closed 4 years ago
Looping in @ditman @hterkelsen who have been working on similar functionality in https://github.com/FirebaseExtended/flutterfire/pull/1633
Wow, thanks for doing this! I'm taking a look!
No probs @ditman 👍 . It might fail builds on CI as packages such as cloud_firestore_web
& cloud_firestore_platform_interface
are not published yet. If we change it to relative paths instead of versions then it works. I am using this fork on my personal app at the moment.
The only thing that I am not unsure about is Transaction
delegation work. As mentioned in the PR details, I am still in the process of adding tests for the new functionality.
Let me know if you have anything.
It might fail builds on CI as packages such as cloud_firestore_web & cloud_firestore_platform_interface are not published yet.
@amrfarid140 Yes, there's also some failures on analyze
and format
that need to be fixed in the PR, those are related with the coding style (but for example, dartfmt
is an automated fix).
The toughest part to fix analyze
is going to be (probably) adding documentation to every public member.
The only thing that I am not unsure about is Transaction delegation work. As mentioned in the PR details, I am still in the process of adding tests for the new functionality.
What I did in PR was to leave the tests in the core package of the plugin, slightly modified to run with the new interface and make sure everything works (similar to the changes you have done when you moved the tests from the core to the platform_interface package.
(I wasn't close to working in the Web plugin, so I didn't have a good story to test the web version!)
(BTW, feel free to email me directly: dit at google if you need anything from me, I have time to help you with this).
@amrfarid140 I cloned your fork, and modified it a little bit to run the example of the cloud_firestore
package and it loaded! However when clicking on the + icon I got an exception.
The error comes from the jsify util in package:firebase
.
It seems that the web types (maybe: 'DocumentReference', 'FieldValue', 'Blob', 'GeoPoint') need to extend the Firestore package types as well, look at _jsify
implementations here.
Uncaught (in promise) Error: Invalid argument (dartObject): Could not convert: Instance of 'FieldValue'
at Object.throw_ [as throw] (errors.dart:196)
at Object.jsify (utils.dart:120)
at utils.dart:94
at IdentityMap.from.forEach (linked_hash_map.dart:23)
at Object.jsify (utils.dart:93)
at firestore.DocumentReference._fromJsObject.set (firestore.dart:348)
at firestore_web.DocumentReferenceWeb.new.setData (document_reference_web.dart:11)
at cloud_firestore.DocumentReference.__.setData (document_reference.dart:47)
at cloud_firestore.CollectionReference.__.add (collection_reference.dart:50)
at add.next (<anonymous>)
at runBody (async_patch.dart:86)
at Object._async [as async] (async_patch.dart:125)
at cloud_firestore.CollectionReference.__.add (collection_reference.dart:48)
at main.MyHomePage.new._addMessage (main.dart:65)
at _addMessage.next (<anonymous>)
at runBody (async_patch.dart:86)
at Object._async [as async] (async_patch.dart:125)
at main.MyHomePage.new.[_addMessage] (main.dart:64)
at _InkResponseState.new.[_handleTap] (ink_well.dart:705)
So close!
Thanks for all feedback @ditman .. it's really helpful. I am happy to keep working at this PR to get it merged. I will start by looking into the issue with jsify
then address your comments before finally adding tests to all the new items and fixing the analyze
& format
issues.
The FieldValue issue should be resolved now. Moving into other parts of the feedback.
Hey @amrfarid140, some extra stuff regarding testing!
I have played a little bit with transactions, following the Firebase for Flutter codelab.
Here's the finished app that you should be able to clone and flutter run -d chrome
; if all goes according to plan, when you try to vote on a baby name, it'll throw some errors/assertions:
Type '_Future<dynamic>' should be '_Future<Map<String, dynamic>>' to implement expected type 'Future<Map<String, dynamic>>'.
...
========================================
Uncaught (in promise) Error: Assertion failed: org-dartlang-app:///packages/cloud_firestore_web/transaction_web.dart:19:12
documentReference is DocumentReferenceWeb
is not true
at Object.throw_ [as throw] (errors.dart:196)
at Object.assertFailed (errors.dart:26)
at firestore_web.TransactionWeb.__.get (transaction_web.dart:19)
at get.next (<anonymous>)
at runBody (async_patch.dart:86)
at Object._async [as async] (async_patch.dart:125)
at firestore_web.TransactionWeb.__.get (transaction_web.dart:18)
at cloud_firestore.Transaction.__.get (transaction.dart:19)
...
========================================
Uncaught (in promise) Error: TypeError: Cannot read property 'then' of undefined
...
(I'm sure they're all related to the DocumentReferenceWeb assertion, which ties in with the jsify discussion above)
The other bit of news, after discussing with @collinjackson about testing, is that there's a bunch of integration tests inside the cloud_firebase
example app, here.
I've managed to run them in the web by copying the contents of test_driver/cloud_firestore.dart into lib/main.dart, and then running flutter run -d chrome
in the example app; here's the current output, and an excerpt:
FirebaseError: [code=invalid-argument]: Function settings() requires its host option to be of type non-empty string, but it was:
null
https://www.gstatic.com/firebasejs/7.5.0/firebase-firestore.js 1:47893 new Gr
https://www.gstatic.com/firebasejs/7.5.0/firebase-firestore.js 1:50392 ci
https://www.gstatic.com/firebasejs/7.5.0/firebase-firestore.js 1:49519 oi
https://www.gstatic.com/firebasejs/7.5.0/firebase-firestore.js 1:332640 new Wp
https://www.gstatic.com/firebasejs/7.5.0/firebase-firestore.js 1:334921 settings
package:firebase/src/firestore.dart 119:16 settings
package:cloud_firestore_web/firestore_web.dart 65:20 <fn>
package:dart-sdk/lib/async/future.dart 224:31 sync
(Looks like an initialization issue is masking the real execution of the tests. (I'll tinker with this some more and add another dump of the output to this issue if I get the tests to run past that settings explosion).
Collin also mentioned that If you add tests there, they'll also help the mobile implementation of the plugin.
Again, thanks for all the work you're doing here!
@ditman I have sorted out transactions for both Web and Mobile. It should be working now. I've also added a button test them on the example app. Unit tests for it is still pending though.
Added WriteBatch
support and included examples in example
app. Runs on Web and Mobile. However, it always fails if we do the following
// get a document reference `docRef`
batch.update(docRef, {some_data})
batch.delete(docRef)
await batch.commit()
...
Basically if we update something then delete it (which maybe be pointless).. Firebase throws an internal error on all platforms
INTERNAL ASSERTION FAILED: Transform results missing for TransformMutation
@ditman Is that intended behaviour ?
On another news .. format and analyze now are passing 🎆
@amrfarid140 I'm looking at the documentation of batched writes here, and it seems they do update and delete on different document refs... I'll try to dig deeper in the flutterfire discord and get back to you (lmk if you want to join, I can send you an invite there).
Regarding the lack of permissions in tests, let me try and run them and see what's up with that; it might be an authentication issue (or lack of it thereof). I'll try to get that fixed/explained so they don't block you.
I'll take a look at the latest code changes!
Thanks @ditman that it would great if we can get to bottom if the WriteBatch issue. Also, yeah an invite to flutterfire discord would be helpful 😄 .
@amrfarid140 at this point I feel like I'm nitpicking rather than adding anything smart to the discussion, other than the initialization problem, I think this is looking great and almost ready to go! What do you think Amr?
Also, Discord link in this doc, ping me in there!
I am fairly happy with how it looks. I've kept testing different use cases with the example and satisfied that all is 💯 . Next steps would be address those latest comments then adding unit tests all over.
Not sure how can pass the publishable test though @ditman . Packages rely on paths right now for everything to work which ultimately is not what we want. We also, at this point, can't rely on specific versions since cloud_firestore_web
& cloud_firestore_platfrom_interface
are not published yet. What do you think is the best approach for this?
We also, at this point, can't rely on specific versions since
cloud_firestore_web
&cloud_firestore_platfrom_interface
are not published yet. What do you think is the best approach for this?
@amrfarid140 you found The Big Chore of this type of migrations which is that we need to split this one in 3 separate PRs to merge (and publish to pub.dev) the packages in the right order:
Our tooling is not smart enough to publish multiple packages at the same time :/
No problem. Let's get those new packages documented and unit tested then I will close this PR and open 3 PRs sequentially (1. Platform interface, 2. Web, 3. Firestore Core) to get it all published. Thanks so much @ditman for the feedback.
No problem. Let's get those new packages documented and unit tested then I will close this PR and open 3 PRs sequentially (1. Platform interface, 2. Web, 3. Firestore Core) to get it all published. Thanks so much @ditman for the feedback.
Sounds good, I'm currently trying to:
I've also closed most of the conversations above that were already addressed. I don't think there's too many open (other than the ensureInitialized thing which I'd be happy with a bug + comment stating why that line is needed and TODO: remove once bug ID is closed?)
master
and web.(Maybe it's an issue with "where" clauses?)
I had to do 2 small changes to the latest code that we've reviewed (but I can't send PRs to your fork :/)... These are needed so the example tests in web come back to only the 2 ones that were failing because of permission denied:
.setPersistenceEnabled()
I recently got permission to access the firebase backend that is used by the tests, where I'll try to review what's up with these two tests, but permissions seem to not have taken effect yet. I'll check again tomorrow in my AM.
Again, thank you very much for all of your work!
@ditman managed to run tests on mobile with this output.. most of them pass except some items where it needs indices defined or permissions.
I've also added your changes to it and resolved remaining outstanding comments
@ditman managed to run tests on mobile with this output.. most of them pass except some items where it needs indices defined or permissions.
@amrfarid140 I ran the tests in the origin/master branch, and only the 2 tests that fail in web fail there. This 3 tests were broken (somehow) by this PR:
I've been reading a little bit, and stumbled upon this StackOverflow answer... I don't see anything that changed that might affect that, other than how the query may be composed? Are we adding "where" clauses multiple times? I think those 3 tests are pointing to a bug (or at least a change in behavior that might affect other users of the plugin).
Are we adding "where" clauses multiple times? I think those 3 tests are pointing to a bug (or at least a change in behavior that might affect other users of the plugin).
I actually think we might be doing that. We are always resetting the Query on Web. We most probably need to that on mobile as well.
We are always resetting the Query on Web. We most probably need to that on mobile as well.
That can explain why the tests pass on web Just Fine ™, but not on the MethodChannel implementation.
(Currently looking at what's the difference between our getDocumentsFromCollectionGroup
and the one in master, I'm setting up Android Studio to debug what flows through the method channel)
I've debugged the getDocumentsFromCollectionGroup
(by placing a breakpoint in the invokeMapMethod
implementation of the platform_channel, didn't get one to work in the Java side).
It seems we're passing the wrong "app" name to firestore. Here's the good and bad messages that are being sent through the MethodChannel:
Everything else seems all right!
I'm going to do the same with the other 2 failing tests, to see if there's any clear difference like the one above.
Yeah.. I have just been reworking things in cloud_firestore
& cloud_firestore_platform_interface
to fix this and a same issue with runTransaction
test.
Yeah.. I have just been reworking things in
cloud_firestore
&cloud_firestore_platform_interface
to fix this and a same issue withrunTransaction
test.
@amrfarid140 do you want me to debug the other two tests, or are you on top of them?
@ditman do you mean those two whereArrayContainsAny
& whereIn
? .. if they are, then nope I am not on them.
The only other one failing now is runTransaction
, which I am currently investigating. I will tidy up and make a commit for the latest changes.
@ditman do you mean those two
whereArrayContainsAny
&whereIn
? .. if they are, then nope I am not on them.The only other one failing now is
runTransaction
. I will tidy up and make a commit for the latest changes.
@amrfarid140 I meant:
For whereArrayContainsAny
& whereIn
, I need access to the firestore project (which I haven't gotten yet, grrr), but those seem to fail on all platforms, so I'm a little bit less concerned about them 😛
@ditman Ah, those two are fixed now .. updates pushed if you want to have a look.
All driver tests pass now @ditman on mobile and web
All driver tests pass now @ditman on mobile and web
@amrfarid140 you're a beast! I'll take a final look and then we'll go on with the 3 PRs to merge this in order. Again, thanks for the contribution, and the patience!
:applause.gif:
Thanks for backporting the fixes from the platform_interface PR to this one, and the web unit tests. Looking great!
I faced an issue with Timestamp
being defined in both packages cloud_firestore
and cloud_firestore_platform_interface
. I resolved it by commenting out part 'src/timestamp.dart'
in cloud_firestore.dart
and adding Timestamp
to the export line.
Not sure if that's the best fix but you should test for Timestamp
type.
@ialhashim Are you depending on both cloud_firestore
& cloud_firestore_platform_interface
?
The only one you need is cloud_firestore
which exposes a Timestamp
class that's compatible with Firebase
type that you are going to use.
@amrfarid140 this is the error I am getting
Exception has occurred.
_TypeError (type 'Timestamp' is not a subtype of type 'Timestamp' where
Timestamp is from package:cloud_firestore_platform_interface/cloud_firestore_platform_interface.dart
Timestamp is from package:cloud_firestore/cloud_firestore.dart
)
It happens for a Timestamp
property being assigned from a returned document to a custom class I made. I am only including cloud_firestore
but cloud_firestore
includes cloud_firestore_platform_interface
.
Also, digging into it I know see that the same field from cloud store comes back as DateTime
on the web and Timestamp
on mobile.
Also, digging into it I know see that the same field from cloud store comes back as DateTime on the web and Timestamp on mobile.
@ialhashim @amrfarid140 I've seen the same, is it a problem of this change, or the underlying library?
In the mean time I had to write a runtimeType
check and do a conversion which is a bit ugly.
(Found the issue/PR where Timestamp support is being added to firebase-dart: https://github.com/FirebaseExtended/firebase-dart/pull/208)
@ditman @ialhashim This might be caused by cloud_firestore_platform_interface/firestore_message_code.dart
building cloud_firestore_platform_interface/timestamp.dart
when readValueOfType()
is executed.
We can fix that by using the same delegation method , similar to what we do for DocumentReference
, in cloud_firestore/timestamp.dart
and add some logic in cloud_firestore/codec_utility.dart
to make sure that we are passing the correct type for reads and writes.
I also think that the issue on firebase-dart
is something else. It might not have a direct impact but it will produce inconsistency when devs are expecting Timestamp
but instead get a DateTime
when running on Web.
Actually we can also do as @ialhashim mentioned. Delete cloud_firestore/timestamp.dart
and export cloud_firestore_platform_interface/timestamp.dart
.. we do that for GeoPoint and it works well. What do you think @ditman ?
@amrfarid140 I think the problem happens when we're assigning from the document snapshot to user's data structures (like here).
In web you get a DateTime
object, but in Android you get a Timestamp
, so you probably need some logic there to assign (similar to the .toDouble()
on ints!).
Right now, by the time we get the data from the firestore-dart package, it's already converted to DateTime on web, right?
(Also, wasn't Timestamp already in the platform_interface
package?)
(Just checked the Firebase Supported Data Types and there's no distinction between DateTime or Timestamp, so maybe the codec_utility
solution is enough, just return a Timestamp when we see a DateTime coming from the data?)
@amrfarid140 what do you think is the best solution? I don't have any specific preference here :)
@ditman agreed. This DateTime
is a problem but I think it's different from what @ialhashim is describing. We currently have two Timestamp
definitions, one in base and one in platform interface, and that might be the issue he is mentioning.
The DateTime
problem need some other piece of work, not sure what yet 😅 , since firestore_message_codec already makes a distinction between them.
@amrfarid140 Ah, I know why we're making the distinction; it's probably to preserve the types of the data that the user is encoding (imagine that you're storing a big map
where you're storing DateTime
or Timestamp
objects, that information needs to be preserved when reading back from the DB).
However in firestore itself, when you define your collection, you cannot create anything other than a Timestamp (I just checked). And for this one, I think we can't let firestore-dart do the conversion automatically (because then we lose information provided by the user?)
So I guess you're right, there's 2 problems here :)
It looks like firebase-dart
converts Timestamp
to DateTime
when reading from document, see here.
And it also converts from DateTime
to Timestamp
when writing to document, see here.
So I think it might make sense if we catch any DateTime
in cloud_firestore_web/utils/codec_utility.dart when reading from document and convert to Timestamp
. That way we can maintain the same return value across mobile and web.
Error occurs when creating as WriteBatch using Firestore.instance.batch();
Error: Expected a value of type 'WriteBatch', but got one of type 'WriteBatchWeb'
@KabirKwatra The issue should be fixed now. Give it another go and let me know if you get anymore issues. Thanks !
@KabirKwatra The issue should be fixed now. Give it another go and let me know if you get anymore issues. Thanks !
Write Batches are working for me now (both in web and mobile)
Thank you so much for this PR! Really looking forward to this 😎
Description
cloud_firestore_platform_interface
to host A common platform interface for the cloud_firestore plugin.cloud_firestore_web
to host the web implementation for Firestorecloud_firestore
implementation to delegate tomethod_channel_xyz
incloud_firestore_platform_interface
when necessarycloud_firestore
tocloud_firestore_platform_interface
This PR is created for gathering feedback on the approach and check mergeability.
Todo items This PR is created for gathering feedback on the approach. The remaining steps are
cloud_firestore_platform_interface
cloud_firestore_web
cloud_firestore
to use published version ofcloud_firestore_web
&cloud_firestore_platform_interface
cloud_firestore_web
cloud_firestore
delegates method calls to delegatecloud_firestore_platform_interface
FirebasePlatform._instance
initialisation until it's called for the first time (lazy init)DocumentReference
Transaction
WriteBatch
Related Issues
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.///
).flutter analyze
) does not report any problems on my PR.Breaking Change
Does your PR require plugin users to manually update their apps to accommodate your change?