Merge remote-tracking branch 'origin/master'
# Conflicts: # tests/ios/Podfile.lock
This commit is contained in:
commit
868075d479
|
@ -36,3 +36,6 @@
|
||||||
|
|
||||||
<!--- (e.g. database, auth, messaging, analytics etc - or N/A if not applicable) --->
|
<!--- (e.g. database, auth, messaging, analytics etc - or N/A if not applicable) --->
|
||||||
6. Firebase Module:
|
6. Firebase Module:
|
||||||
|
|
||||||
|
<!-- Love react-native-firebase? Please consider supporting our collective:
|
||||||
|
👉 https://opencollective.com/react-native-firebase/donate -->
|
|
@ -0,0 +1,67 @@
|
||||||
|
# Contribute
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
First, thank you for considering contributing to react-native-firebase! It's people like you that make the open source community such a great community! 😊
|
||||||
|
|
||||||
|
We welcome any type of contribution, not only code. You can help with
|
||||||
|
- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
|
||||||
|
- **Marketing**: writing blog posts, howto's, printing stickers, ...
|
||||||
|
- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
|
||||||
|
- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
|
||||||
|
- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-firebase).
|
||||||
|
|
||||||
|
## Your First Contribution
|
||||||
|
|
||||||
|
Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
|
||||||
|
|
||||||
|
## Submitting code
|
||||||
|
|
||||||
|
Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
|
||||||
|
|
||||||
|
## Code review process
|
||||||
|
|
||||||
|
The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
|
||||||
|
It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
|
||||||
|
|
||||||
|
## Financial contributions
|
||||||
|
|
||||||
|
We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-firebase).
|
||||||
|
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!).
|
||||||
|
You can also reach us at oss@invertase.io
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Thank you to all the people who have already contributed to react-native-firebase!
|
||||||
|
<a href="graphs/contributors"><img src="https://opencollective.com/react-native-firebase/contributors.svg?width=890" /></a>
|
||||||
|
|
||||||
|
|
||||||
|
### Backers
|
||||||
|
|
||||||
|
Thank you to all our backers! [[Become a backer](https://opencollective.com/react-native-firebase#backer)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/react-native-firebase#backers" target="_blank"><img src="https://opencollective.com/react-native-firebase/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
|
||||||
|
### Sponsors
|
||||||
|
|
||||||
|
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/react-native-firebase#sponsor))
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/0/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/0/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/1/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/2/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/3/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/4/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/5/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/6/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/7/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/8/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/9/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/9/avatar.svg"></a>
|
||||||
|
|
||||||
|
<!-- This `CONTRIBUTING.md` is based on @nayafia's template https://github.com/nayafia/contributing-template -->
|
83
README.md
83
README.md
|
@ -1,8 +1,7 @@
|
||||||
# React Native Firebase<a href="https://rnfirebase.io"><img align="left" src="http://i.imgur.com/01XQL0x.png"></a>
|
# React Native Firebase<a href="https://rnfirebase.io"><img align="left" src="http://i.imgur.com/01XQL0x.png"></a>
|
||||||
|
|
||||||
[![npm version](https://img.shields.io/npm/v/react-native-firebase.svg?style=flat-square)](https://www.npmjs.com/package/react-native-firebase)
|
[![Backers on Open Collective](https://opencollective.com/react-native-firebase/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/react-native-firebase/sponsors/badge.svg)](#sponsors) [![npm version](https://img.shields.io/npm/v/react-native-firebase.svg?style=flat-square)](https://www.npmjs.com/package/react-native-firebase)
|
||||||
[![NPM downloads](https://img.shields.io/npm/dm/react-native-firebase.svg?style=flat-square)](https://www.npmjs.com/package/react-native-firebase)
|
[![NPM downloads](https://img.shields.io/npm/dm/react-native-firebase.svg?style=flat-square)](https://www.npmjs.com/package/react-native-firebase)
|
||||||
[![Package Quality](http://npm.packagequality.com/shield/react-native-firebase.svg?style=flat-square)](http://packagequality.com/#?package=react-native-firebase)
|
|
||||||
[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square)](https://discord.gg/t6bdqMs)
|
[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square)](https://discord.gg/t6bdqMs)
|
||||||
[![Donate](https://img.shields.io/badge/Donate-Patreon-green.svg?style=flat-square)](https://www.patreon.com/invertase)
|
[![Donate](https://img.shields.io/badge/Donate-Patreon-green.svg?style=flat-square)](https://www.patreon.com/invertase)
|
||||||
[![Twitter Follow](https://img.shields.io/twitter/follow/rnfirebase.svg?style=social&label=Follow)](https://twitter.com/rnfirebase)
|
[![Twitter Follow](https://img.shields.io/twitter/follow/rnfirebase.svg?style=social&label=Follow)](https://twitter.com/rnfirebase)
|
||||||
|
@ -53,40 +52,70 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
|
||||||
|
|
||||||
> '**?**' indicates partial support
|
> '**?**' indicates partial support
|
||||||
|
|
||||||
| Firebase Features | v1.x.x | v2.x.x | v3.x.x | Web SDK |
|
| Firebase Features | v1.x.x | v2.x.x | v3.x.x | v3.1.x | Web SDK |
|
||||||
| ---------------------- | :---: | :---: | :---: | :---: |
|
| ---------------------- | :---: | :---: | :---: | :---: | :---: |
|
||||||
| **AdMob** | ❌ | ✅ | ✅ | ❌ |
|
| **AdMob** | ❌ | ✅ | ✅ | ✅ | ❌ |
|
||||||
| **Analytics** | ✅ | ✅ | ✅ | ❌ |
|
| **Analytics** | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||||
| **App Indexing** | ❌ | ❌ | ❌ | ❌ |
|
| **App Indexing** | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| **Authentication** | ✅ | ✅ | ✅ | ✅ |
|
| **Authentication** | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| _-- Phone Auth_ | ❌ | ❌ | ✅ | ❌ |
|
| _-- Phone Auth_ | ❌ | ❌ | ✅ | ✅ | ❌ |
|
||||||
| **Core** | ❌ |**?**| ✅ | ✅ |
|
| **Core** | ❌ |**?**| ✅ | ✅ | ✅ |
|
||||||
| _-- Multiple Apps_ | ❌ | ❌ | ✅ | ✅ |
|
| _-- Multiple Apps_ | ❌ | ❌ | ✅ | ✅ | ✅ |
|
||||||
| **Cloud Firestore** | ❌ | ❌ | ✅ | ❌ |
|
| **Cloud Firestore** | ❌ | ❌ | ✅ | ✅ | ❌ |
|
||||||
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ |**?**|
|
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ | ✅ |**?**|
|
||||||
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
|
| **Crash Reporting** | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||||
| **Dynamic Links** | ❌ | ❌ | ❌ | ❌ |
|
| **Dynamic Links** | ❌ | ❌ | ❌ | ✅ | ❌ |
|
||||||
| **Invites** | ❌ | ❌ | ❌ | ❌ |
|
| **Invites** | ❌ | ❌ | ❌ |**?**| ❌ |
|
||||||
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ |
|
| **Performance Monitoring** | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||||
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ |
|
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| _-- Offline Persistence_ | ✅ | ✅ | ✅ |**?**|
|
| _-- Offline Persistence_ | ✅ | ✅ | ✅ | ✅ |**?**|
|
||||||
| _-- Transactions_ | ✅ | ✅ | ✅ | ✅ |
|
| _-- Transactions_ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| **Remote Config** | ✅ | ✅ | ✅ | ❌ |
|
| **Remote Config** | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||||
| **Storage** | ✅ | ✅ | ✅ |**?**|
|
| **Storage** | ✅ | ✅ | ✅ | ✅ |**?**|
|
||||||
|
|
||||||
---
|
---
|
||||||
### Supported versions - React Native / Firebase
|
### Supported versions - React Native / Firebase
|
||||||
|
|
||||||
> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
|
> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
|
||||||
|
|
||||||
| | 1.X.X | 2.0.X | 2.1.X / 2.2.X | 3.0.X |
|
| | 1.X.X | 2.0.X | 2.1.X / 2.2.X | 3.0.X | 3.1.X |
|
||||||
|------------------------|-------------|-------------|-----------------|----------|
|
|------------------------|-------------|-------------|-----------------|----------|----------|
|
||||||
| React Native | 0.36 - 0.39 | 0.40 - 0.46 | 0.47 + | 0.48 + |
|
| React Native | 0.36 - 0.39 | 0.40 - 0.46 | 0.47 + | 0.48 + | 0.48 + |
|
||||||
| Firebase Android SDK | 10.2.0 + | 11.0.0 + | 11.0.0 + | 11.4.2 + |
|
| Firebase Android SDK | 10.2.0 + | 11.0.0 + | 11.0.0 + | 11.4.2 + | 11.4.2 + |
|
||||||
| Firebase iOS SDK | 3.15.0 + | 4.0.0 + | 4.0.0 + | 4.3.0 + |
|
| Firebase iOS SDK | 3.15.0 + | 4.0.0 + | 4.0.0 + | 4.3.0 + | 4.5.0 + |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
This project exists thanks to all the people who contribute. [[Contribute]](CONTRIBUTING.md).
|
||||||
|
<a href="graphs/contributors"><img src="https://opencollective.com/react-native-firebase/contributors.svg?width=890" /></a>
|
||||||
|
|
||||||
|
|
||||||
|
## Backers
|
||||||
|
|
||||||
|
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/react-native-firebase#backer)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/react-native-firebase#backers" target="_blank"><img src="https://opencollective.com/react-native-firebase/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
|
||||||
|
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/react-native-firebase#sponsor)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/0/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/0/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/1/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/2/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/3/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/4/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/5/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/6/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/7/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/8/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/react-native-firebase/sponsor/9/website" target="_blank"><img src="https://opencollective.com/react-native-firebase/sponsor/9/avatar.svg"></a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
||||||
- See [LICENSE](/LICENSE)
|
- See [LICENSE](/LICENSE)
|
||||||
|
|
|
@ -33,6 +33,7 @@ import com.google.firebase.auth.ActionCodeResult;
|
||||||
import com.google.firebase.auth.AuthCredential;
|
import com.google.firebase.auth.AuthCredential;
|
||||||
import com.google.firebase.auth.AuthResult;
|
import com.google.firebase.auth.AuthResult;
|
||||||
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
|
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
|
||||||
|
import com.google.firebase.auth.FirebaseAuthProvider;
|
||||||
import com.google.firebase.auth.GithubAuthProvider;
|
import com.google.firebase.auth.GithubAuthProvider;
|
||||||
import com.google.firebase.auth.PhoneAuthCredential;
|
import com.google.firebase.auth.PhoneAuthCredential;
|
||||||
import com.google.firebase.auth.PhoneAuthProvider;
|
import com.google.firebase.auth.PhoneAuthProvider;
|
||||||
|
@ -54,6 +55,7 @@ import io.invertase.firebase.Utils;
|
||||||
class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||||
private static final String TAG = "RNFirebaseAuth";
|
private static final String TAG = "RNFirebaseAuth";
|
||||||
private String mVerificationId;
|
private String mVerificationId;
|
||||||
|
private PhoneAuthCredential mCredential;
|
||||||
private ReactContext mReactContext;
|
private ReactContext mReactContext;
|
||||||
private HashMap<String, FirebaseAuth.AuthStateListener> mAuthListeners = new HashMap<>();
|
private HashMap<String, FirebaseAuth.AuthStateListener> mAuthListeners = new HashMap<>();
|
||||||
private HashMap<String, FirebaseAuth.IdTokenListener> mIdTokenListeners = new HashMap<>();
|
private HashMap<String, FirebaseAuth.IdTokenListener> mIdTokenListeners = new HashMap<>();
|
||||||
|
@ -738,10 +740,16 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||||
|
|
||||||
Log.d(TAG, "verifyPhoneNumber:" + phoneNumber);
|
Log.d(TAG, "verifyPhoneNumber:" + phoneNumber);
|
||||||
|
|
||||||
|
// Reset the credential
|
||||||
|
mCredential = null;
|
||||||
|
|
||||||
PhoneAuthProvider.OnVerificationStateChangedCallbacks callbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
|
PhoneAuthProvider.OnVerificationStateChangedCallbacks callbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVerificationCompleted(final PhoneAuthCredential phoneAuthCredential) {
|
public void onVerificationCompleted(final PhoneAuthCredential phoneAuthCredential) {
|
||||||
|
// Cache the credential to protect against null verificationId
|
||||||
|
mCredential = phoneAuthCredential;
|
||||||
|
|
||||||
Log.d(TAG, "verifyPhoneNumber:verification:onVerificationCompleted");
|
Log.d(TAG, "verifyPhoneNumber:verification:onVerificationCompleted");
|
||||||
WritableMap state = Arguments.createMap();
|
WritableMap state = Arguments.createMap();
|
||||||
|
|
||||||
|
@ -1068,6 +1076,15 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||||
case "github.com":
|
case "github.com":
|
||||||
return GithubAuthProvider.getCredential(authToken);
|
return GithubAuthProvider.getCredential(authToken);
|
||||||
case "phone":
|
case "phone":
|
||||||
|
// If the phone number is auto-verified quickly, then the verificationId can be null
|
||||||
|
// We cached the credential as part of the verifyPhoneNumber request to be re-used here
|
||||||
|
// if possible
|
||||||
|
if (authToken == null && mCredential != null) {
|
||||||
|
PhoneAuthCredential credential = mCredential;
|
||||||
|
// Reset the cached credential
|
||||||
|
mCredential = null;
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
return PhoneAuthProvider.getCredential(authToken, authSecret);
|
return PhoneAuthProvider.getCredential(authToken, authSecret);
|
||||||
case "password":
|
case "password":
|
||||||
return EmailAuthProvider.getCredential(authToken, authSecret);
|
return EmailAuthProvider.getCredential(authToken, authSecret);
|
||||||
|
@ -1282,12 +1299,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||||
* @param providerData List<UserInfo> user.getProviderData()
|
* @param providerData List<UserInfo> user.getProviderData()
|
||||||
* @return WritableArray array
|
* @return WritableArray array
|
||||||
*/
|
*/
|
||||||
private WritableArray convertProviderData(List<? extends UserInfo> providerData) {
|
private WritableArray convertProviderData(List<? extends UserInfo> providerData, FirebaseUser user) {
|
||||||
WritableArray output = Arguments.createArray();
|
WritableArray output = Arguments.createArray();
|
||||||
for (UserInfo userInfo : providerData) {
|
for (UserInfo userInfo : providerData) {
|
||||||
// remove 'firebase' provider data - android fb sdk
|
// remove 'firebase' provider data - android fb sdk
|
||||||
// should not be returning this as the ios/web ones don't
|
// should not be returning this as the ios/web ones don't
|
||||||
if (!userInfo.getProviderId().equals("firebase")) {
|
if (!FirebaseAuthProvider.PROVIDER_ID.equals(userInfo.getProviderId())) {
|
||||||
WritableMap userInfoMap = Arguments.createMap();
|
WritableMap userInfoMap = Arguments.createMap();
|
||||||
userInfoMap.putString("providerId", userInfo.getProviderId());
|
userInfoMap.putString("providerId", userInfo.getProviderId());
|
||||||
userInfoMap.putString("uid", userInfo.getUid());
|
userInfoMap.putString("uid", userInfo.getUid());
|
||||||
|
@ -1295,20 +1312,34 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||||
|
|
||||||
final Uri photoUrl = userInfo.getPhotoUrl();
|
final Uri photoUrl = userInfo.getPhotoUrl();
|
||||||
|
|
||||||
if (photoUrl != null) {
|
if (photoUrl != null && !"".equals(photoUrl)) {
|
||||||
userInfoMap.putString("photoURL", photoUrl.toString());
|
userInfoMap.putString("photoURL", photoUrl.toString());
|
||||||
} else {
|
} else {
|
||||||
userInfoMap.putNull("photoURL");
|
userInfoMap.putNull("photoURL");
|
||||||
}
|
}
|
||||||
|
|
||||||
final String phoneNumber = userInfo.getPhoneNumber();
|
final String phoneNumber = userInfo.getPhoneNumber();
|
||||||
if (phoneNumber != null) {
|
// The Android SDK is missing the phone number property for the phone provider when the
|
||||||
|
// user first signs up using their phone number. Use the phone number from the user
|
||||||
|
// object instead
|
||||||
|
if (PhoneAuthProvider.PROVIDER_ID.equals(userInfo.getProviderId())
|
||||||
|
&& (userInfo.getPhoneNumber() == null || "".equals(userInfo.getPhoneNumber()))) {
|
||||||
|
userInfoMap.putString("phoneNumber", user.getPhoneNumber());
|
||||||
|
} else if (phoneNumber != null && !"".equals(phoneNumber)) {
|
||||||
userInfoMap.putString("phoneNumber", phoneNumber);
|
userInfoMap.putString("phoneNumber", phoneNumber);
|
||||||
} else {
|
} else {
|
||||||
userInfoMap.putNull("phoneNumber");
|
userInfoMap.putNull("phoneNumber");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Android SDK is missing the email property for the email provider, so we use UID instead
|
||||||
|
if (EmailAuthProvider.PROVIDER_ID.equals(userInfo.getProviderId())
|
||||||
|
&& (userInfo.getEmail() == null || "".equals(userInfo.getEmail()))) {
|
||||||
|
userInfoMap.putString("email", userInfo.getUid());
|
||||||
|
} else if (userInfo.getEmail() != null && !"".equals(userInfo.getEmail())) {
|
||||||
userInfoMap.putString("email", userInfo.getEmail());
|
userInfoMap.putString("email", userInfo.getEmail());
|
||||||
|
} else {
|
||||||
|
userInfoMap.putNull("email");
|
||||||
|
}
|
||||||
|
|
||||||
output.pushMap(userInfoMap);
|
output.pushMap(userInfoMap);
|
||||||
}
|
}
|
||||||
|
@ -1339,31 +1370,31 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||||
userMap.putBoolean("emailVerified", verified);
|
userMap.putBoolean("emailVerified", verified);
|
||||||
userMap.putBoolean("isAnonymous", user.isAnonymous());
|
userMap.putBoolean("isAnonymous", user.isAnonymous());
|
||||||
|
|
||||||
if (email != null) {
|
if (email != null && !"".equals(email)) {
|
||||||
userMap.putString("email", email);
|
userMap.putString("email", email);
|
||||||
} else {
|
} else {
|
||||||
userMap.putNull("email");
|
userMap.putNull("email");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null && !"".equals(name)) {
|
||||||
userMap.putString("displayName", name);
|
userMap.putString("displayName", name);
|
||||||
} else {
|
} else {
|
||||||
userMap.putNull("displayName");
|
userMap.putNull("displayName");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (photoUrl != null) {
|
if (photoUrl != null && !"".equals(photoUrl)) {
|
||||||
userMap.putString("photoURL", photoUrl.toString());
|
userMap.putString("photoURL", photoUrl.toString());
|
||||||
} else {
|
} else {
|
||||||
userMap.putNull("photoURL");
|
userMap.putNull("photoURL");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phoneNumber != null) {
|
if (phoneNumber != null && !"".equals(phoneNumber)) {
|
||||||
userMap.putString("phoneNumber", phoneNumber);
|
userMap.putString("phoneNumber", phoneNumber);
|
||||||
} else {
|
} else {
|
||||||
userMap.putNull("phoneNumber");
|
userMap.putNull("phoneNumber");
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap.putArray("providerData", convertProviderData(user.getProviderData()));
|
userMap.putArray("providerData", convertProviderData(user.getProviderData(), user));
|
||||||
|
|
||||||
return userMap;
|
return userMap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,7 +399,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||||
*/
|
*/
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void on(String appName, ReadableMap props) {
|
public void on(String appName, ReadableMap props) {
|
||||||
getInternalReferenceForApp(appName, props)
|
getCachedInternalReferenceForApp(appName, props)
|
||||||
.on(
|
.on(
|
||||||
props.getString("eventType"),
|
props.getString("eventType"),
|
||||||
props.getMap("registration")
|
props.getMap("registration")
|
||||||
|
@ -481,10 +481,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private RNFirebaseDatabaseReference getInternalReferenceForApp(String appName, String key, String path, ReadableArray modifiers) {
|
private RNFirebaseDatabaseReference getInternalReferenceForApp(String appName, String key, String path, ReadableArray modifiers) {
|
||||||
RNFirebaseDatabaseReference existingRef = references.get(key);
|
return new RNFirebaseDatabaseReference(
|
||||||
|
|
||||||
if (existingRef == null) {
|
|
||||||
existingRef = new RNFirebaseDatabaseReference(
|
|
||||||
getReactApplicationContext(),
|
getReactApplicationContext(),
|
||||||
appName,
|
appName,
|
||||||
key,
|
key,
|
||||||
|
@ -493,9 +490,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return existingRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
*
|
*
|
||||||
|
@ -503,7 +497,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||||
* @param props
|
* @param props
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private RNFirebaseDatabaseReference getInternalReferenceForApp(String appName, ReadableMap props) {
|
private RNFirebaseDatabaseReference getCachedInternalReferenceForApp(String appName, ReadableMap props) {
|
||||||
String key = props.getString("key");
|
String key = props.getString("key");
|
||||||
String path = props.getString("path");
|
String path = props.getString("path");
|
||||||
ReadableArray modifiers = props.getArray("modifiers");
|
ReadableArray modifiers = props.getArray("modifiers");
|
||||||
|
@ -511,14 +505,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||||
RNFirebaseDatabaseReference existingRef = references.get(key);
|
RNFirebaseDatabaseReference existingRef = references.get(key);
|
||||||
|
|
||||||
if (existingRef == null) {
|
if (existingRef == null) {
|
||||||
existingRef = new RNFirebaseDatabaseReference(
|
existingRef = getInternalReferenceForApp(appName, key, path, modifiers);
|
||||||
getReactApplicationContext(),
|
|
||||||
appName,
|
|
||||||
key,
|
|
||||||
path,
|
|
||||||
modifiers
|
|
||||||
);
|
|
||||||
|
|
||||||
references.put(key, existingRef);
|
references.put(key, existingRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,6 @@ import io.invertase.firebase.Utils;
|
||||||
|
|
||||||
public class FirestoreSerialize {
|
public class FirestoreSerialize {
|
||||||
private static final String TAG = "FirestoreSerialize";
|
private static final String TAG = "FirestoreSerialize";
|
||||||
private static final DateFormat READ_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
|
||||||
private static final DateFormat WRITE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
|
||||||
private static final String KEY_CHANGES = "changes";
|
private static final String KEY_CHANGES = "changes";
|
||||||
private static final String KEY_DATA = "data";
|
private static final String KEY_DATA = "data";
|
||||||
private static final String KEY_DOC_CHANGE_DOCUMENT = "document";
|
private static final String KEY_DOC_CHANGE_DOCUMENT = "document";
|
||||||
|
@ -43,12 +41,6 @@ public class FirestoreSerialize {
|
||||||
private static final String KEY_METADATA = "metadata";
|
private static final String KEY_METADATA = "metadata";
|
||||||
private static final String KEY_PATH = "path";
|
private static final String KEY_PATH = "path";
|
||||||
|
|
||||||
static {
|
|
||||||
// Javascript Date.toISOString is always formatted to UTC
|
|
||||||
// We set the read TimeZone to UTC to account for this
|
|
||||||
READ_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a DocumentSnapshot instance into a React Native WritableMap
|
* Convert a DocumentSnapshot instance into a React Native WritableMap
|
||||||
*
|
*
|
||||||
|
@ -220,7 +212,7 @@ public class FirestoreSerialize {
|
||||||
typeMap.putMap("value", geoPoint);
|
typeMap.putMap("value", geoPoint);
|
||||||
} else if (value instanceof Date) {
|
} else if (value instanceof Date) {
|
||||||
typeMap.putString("type", "date");
|
typeMap.putString("type", "date");
|
||||||
typeMap.putString("value", WRITE_DATE_FORMAT.format((Date) value));
|
typeMap.putDouble("value", ((Date) value).getTime());
|
||||||
} else {
|
} else {
|
||||||
// TODO: Changed to log an error rather than crash - is this correct?
|
// TODO: Changed to log an error rather than crash - is this correct?
|
||||||
Log.e(TAG, "buildTypeMap: Cannot convert object of type " + value.getClass());
|
Log.e(TAG, "buildTypeMap: Cannot convert object of type " + value.getClass());
|
||||||
|
@ -244,7 +236,7 @@ public class FirestoreSerialize {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Object> parseReadableArray(FirebaseFirestore firestore, ReadableArray readableArray) {
|
static List<Object> parseReadableArray(FirebaseFirestore firestore, ReadableArray readableArray) {
|
||||||
List<Object> list = new ArrayList<>();
|
List<Object> list = new ArrayList<>();
|
||||||
if (readableArray != null) {
|
if (readableArray != null) {
|
||||||
for (int i = 0; i < readableArray.size(); i++) {
|
for (int i = 0; i < readableArray.size(); i++) {
|
||||||
|
@ -254,7 +246,7 @@ public class FirestoreSerialize {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object parseTypeMap(FirebaseFirestore firestore, ReadableMap typeMap) {
|
static Object parseTypeMap(FirebaseFirestore firestore, ReadableMap typeMap) {
|
||||||
String type = typeMap.getString("type");
|
String type = typeMap.getString("type");
|
||||||
if ("boolean".equals(type)) {
|
if ("boolean".equals(type)) {
|
||||||
return typeMap.getBoolean("value");
|
return typeMap.getBoolean("value");
|
||||||
|
@ -275,13 +267,8 @@ public class FirestoreSerialize {
|
||||||
ReadableMap geoPoint = typeMap.getMap("value");
|
ReadableMap geoPoint = typeMap.getMap("value");
|
||||||
return new GeoPoint(geoPoint.getDouble("latitude"), geoPoint.getDouble("longitude"));
|
return new GeoPoint(geoPoint.getDouble("latitude"), geoPoint.getDouble("longitude"));
|
||||||
} else if ("date".equals(type)) {
|
} else if ("date".equals(type)) {
|
||||||
try {
|
Double time = typeMap.getDouble("value");
|
||||||
String date = typeMap.getString("value");
|
return new Date(time.longValue());
|
||||||
return READ_DATE_FORMAT.parse(date);
|
|
||||||
} catch (ParseException exception) {
|
|
||||||
Log.e(TAG, "parseTypeMap", exception);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else if ("fieldvalue".equals(type)) {
|
} else if ("fieldvalue".equals(type)) {
|
||||||
String value = typeMap.getString("value");
|
String value = typeMap.getString("value");
|
||||||
if ("delete".equals(value)) {
|
if ("delete".equals(value)) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import com.google.android.gms.tasks.OnCompleteListener;
|
||||||
import com.google.android.gms.tasks.Task;
|
import com.google.android.gms.tasks.Task;
|
||||||
import com.google.firebase.firestore.DocumentListenOptions;
|
import com.google.firebase.firestore.DocumentListenOptions;
|
||||||
import com.google.firebase.firestore.EventListener;
|
import com.google.firebase.firestore.EventListener;
|
||||||
|
import com.google.firebase.firestore.FirebaseFirestore;
|
||||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||||
import com.google.firebase.firestore.ListenerRegistration;
|
import com.google.firebase.firestore.ListenerRegistration;
|
||||||
import com.google.firebase.firestore.Query;
|
import com.google.firebase.firestore.Query;
|
||||||
|
@ -115,22 +116,22 @@ public class RNFirebaseFirestoreCollectionReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Query buildQuery() {
|
private Query buildQuery() {
|
||||||
Query query = RNFirebaseFirestore.getFirestoreForApp(appName).collection(path);
|
FirebaseFirestore firestore = RNFirebaseFirestore.getFirestoreForApp(appName);
|
||||||
query = applyFilters(query);
|
Query query = firestore.collection(path);
|
||||||
|
query = applyFilters(firestore, query);
|
||||||
query = applyOrders(query);
|
query = applyOrders(query);
|
||||||
query = applyOptions(query);
|
query = applyOptions(firestore, query);
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Query applyFilters(Query query) {
|
private Query applyFilters(FirebaseFirestore firestore, Query query) {
|
||||||
List<Object> filtersList = Utils.recursivelyDeconstructReadableArray(filters);
|
for (int i = 0; i < filters.size(); i++) {
|
||||||
|
ReadableMap filter = filters.getMap(i);
|
||||||
for (Object f : filtersList) {
|
String fieldPath = filter.getString("fieldPath");
|
||||||
Map<String, Object> filter = (Map) f;
|
String operator = filter.getString("operator");
|
||||||
String fieldPath = (String) filter.get("fieldPath");
|
ReadableMap jsValue = filter.getMap("value");
|
||||||
String operator = (String) filter.get("operator");
|
Object value = FirestoreSerialize.parseTypeMap(firestore, jsValue);
|
||||||
Object value = filter.get("value");
|
|
||||||
|
|
||||||
switch (operator) {
|
switch (operator) {
|
||||||
case "EQUAL":
|
case "EQUAL":
|
||||||
|
@ -165,14 +166,14 @@ public class RNFirebaseFirestoreCollectionReference {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Query applyOptions(Query query) {
|
private Query applyOptions(FirebaseFirestore firestore, Query query) {
|
||||||
if (options.hasKey("endAt")) {
|
if (options.hasKey("endAt")) {
|
||||||
ReadableArray endAtArray = options.getArray("endAt");
|
List<Object> endAtList = FirestoreSerialize.parseReadableArray(firestore, options.getArray("endAt"));
|
||||||
query = query.endAt(Utils.recursivelyDeconstructReadableArray(endAtArray));
|
query = query.endAt(endAtList.toArray());
|
||||||
}
|
}
|
||||||
if (options.hasKey("endBefore")) {
|
if (options.hasKey("endBefore")) {
|
||||||
ReadableArray endBeforeArray = options.getArray("endBefore");
|
List<Object> endBeforeList = FirestoreSerialize.parseReadableArray(firestore, options.getArray("endBefore"));
|
||||||
query = query.endBefore(Utils.recursivelyDeconstructReadableArray(endBeforeArray));
|
query = query.endBefore(endBeforeList.toArray());
|
||||||
}
|
}
|
||||||
if (options.hasKey("limit")) {
|
if (options.hasKey("limit")) {
|
||||||
int limit = options.getInt("limit");
|
int limit = options.getInt("limit");
|
||||||
|
@ -185,12 +186,12 @@ public class RNFirebaseFirestoreCollectionReference {
|
||||||
// Android doesn't support selectFields
|
// Android doesn't support selectFields
|
||||||
}
|
}
|
||||||
if (options.hasKey("startAfter")) {
|
if (options.hasKey("startAfter")) {
|
||||||
ReadableArray startAfterArray = options.getArray("startAfter");
|
List<Object> startAfterList= FirestoreSerialize.parseReadableArray(firestore, options.getArray("startAfter"));
|
||||||
query = query.startAfter(Utils.recursivelyDeconstructReadableArray(startAfterArray));
|
query = query.startAfter(startAfterList.toArray());
|
||||||
}
|
}
|
||||||
if (options.hasKey("startAt")) {
|
if (options.hasKey("startAt")) {
|
||||||
ReadableArray startAtArray = options.getArray("startAt");
|
List<Object> startAtList= FirestoreSerialize.parseReadableArray(firestore, options.getArray("startAt"));
|
||||||
query = query.startAt(Utils.recursivelyDeconstructReadableArray(startAtArray));
|
query = query.startAt(startAtList.toArray());
|
||||||
}
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@ import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
|
@ -339,14 +337,7 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
|
||||||
Log.i(TAG, "putFile: " + localPath + " to " + path);
|
Log.i(TAG, "putFile: " + localPath + " to " + path);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Uri file;
|
Uri file = getURI(localPath);
|
||||||
if (localPath.startsWith("content://")) {
|
|
||||||
String realPath = getRealPathFromURI(localPath);
|
|
||||||
file = Uri.fromFile(new File(realPath));
|
|
||||||
} else {
|
|
||||||
file = Uri.fromFile(new File(localPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
StorageMetadata md = buildMetadataFromMap(metadata);
|
StorageMetadata md = buildMetadataFromMap(metadata);
|
||||||
UploadTask uploadTask = reference.putFile(file, md);
|
UploadTask uploadTask = reference.putFile(file, md);
|
||||||
|
|
||||||
|
@ -415,24 +406,18 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal helper to convert content:// uri's to a real path
|
* Create a Uri from the path, defaulting to file when there is no supplied scheme
|
||||||
*
|
*
|
||||||
* @param uri
|
* @param uri
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private String getRealPathFromURI(final String uri) {
|
private Uri getURI(final String uri) {
|
||||||
Cursor cursor = null;
|
Uri parsed = Uri.parse(uri);
|
||||||
try {
|
|
||||||
String[] proj = {MediaStore.Images.Media.DATA};
|
if (parsed.getScheme() == null || parsed.getScheme().isEmpty()) {
|
||||||
cursor = getReactApplicationContext().getContentResolver().query(Uri.parse(uri), proj, null, null, null);
|
return Uri.fromFile(new File(uri));
|
||||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
|
||||||
cursor.moveToFirst();
|
|
||||||
return cursor.getString(column_index);
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
839D91731EF3E20B0077C7C8 /* RNFirebaseDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91621EF3E20A0077C7C8 /* RNFirebaseDatabase.m */; };
|
839D91731EF3E20B0077C7C8 /* RNFirebaseDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91621EF3E20A0077C7C8 /* RNFirebaseDatabase.m */; };
|
||||||
839D91741EF3E20B0077C7C8 /* RNFirebaseMessaging.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91651EF3E20A0077C7C8 /* RNFirebaseMessaging.m */; };
|
839D91741EF3E20B0077C7C8 /* RNFirebaseMessaging.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91651EF3E20A0077C7C8 /* RNFirebaseMessaging.m */; };
|
||||||
839D91751EF3E20B0077C7C8 /* RNFirebasePerformance.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91681EF3E20A0077C7C8 /* RNFirebasePerformance.m */; };
|
839D91751EF3E20B0077C7C8 /* RNFirebasePerformance.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91681EF3E20A0077C7C8 /* RNFirebasePerformance.m */; };
|
||||||
839D91761EF3E20B0077C7C8 /* RNFirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D916B1EF3E20A0077C7C8 /* RNFirebaseStorage.m */; };
|
83C3EEEE1FA1EACC00B64D3C /* RNFirebaseUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 83C3EEEC1FA1EACC00B64D3C /* RNFirebaseUtil.m */; };
|
||||||
|
BA84AE571FA9E59800E79390 /* RNFirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = BA84AE561FA9E59800E79390 /* RNFirebaseStorage.m */; };
|
||||||
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */ = {isa = PBXBuildFile; fileRef = D950369D1D19C77400F7094D /* RNFirebase.m */; };
|
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */ = {isa = PBXBuildFile; fileRef = D950369D1D19C77400F7094D /* RNFirebase.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
@ -82,9 +83,11 @@
|
||||||
839D91651EF3E20A0077C7C8 /* RNFirebaseMessaging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseMessaging.m; sourceTree = "<group>"; };
|
839D91651EF3E20A0077C7C8 /* RNFirebaseMessaging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseMessaging.m; sourceTree = "<group>"; };
|
||||||
839D91671EF3E20A0077C7C8 /* RNFirebasePerformance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebasePerformance.h; sourceTree = "<group>"; };
|
839D91671EF3E20A0077C7C8 /* RNFirebasePerformance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebasePerformance.h; sourceTree = "<group>"; };
|
||||||
839D91681EF3E20A0077C7C8 /* RNFirebasePerformance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebasePerformance.m; sourceTree = "<group>"; };
|
839D91681EF3E20A0077C7C8 /* RNFirebasePerformance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebasePerformance.m; sourceTree = "<group>"; };
|
||||||
839D916A1EF3E20A0077C7C8 /* RNFirebaseStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseStorage.h; sourceTree = "<group>"; };
|
|
||||||
839D916B1EF3E20A0077C7C8 /* RNFirebaseStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseStorage.m; sourceTree = "<group>"; };
|
|
||||||
839D91771EF3E22F0077C7C8 /* RNFirebaseEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseEvents.h; path = RNFirebase/RNFirebaseEvents.h; sourceTree = "<group>"; };
|
839D91771EF3E22F0077C7C8 /* RNFirebaseEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseEvents.h; path = RNFirebase/RNFirebaseEvents.h; sourceTree = "<group>"; };
|
||||||
|
83C3EEEC1FA1EACC00B64D3C /* RNFirebaseUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseUtil.m; path = RNFirebase/RNFirebaseUtil.m; sourceTree = "<group>"; };
|
||||||
|
83C3EEED1FA1EACC00B64D3C /* RNFirebaseUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseUtil.h; path = RNFirebase/RNFirebaseUtil.h; sourceTree = "<group>"; };
|
||||||
|
BA84AE551FA9E59800E79390 /* RNFirebaseStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseStorage.h; sourceTree = "<group>"; };
|
||||||
|
BA84AE561FA9E59800E79390 /* RNFirebaseStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseStorage.m; sourceTree = "<group>"; };
|
||||||
D950369C1D19C77400F7094D /* RNFirebase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebase.h; path = RNFirebase/RNFirebase.h; sourceTree = "<group>"; };
|
D950369C1D19C77400F7094D /* RNFirebase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebase.h; path = RNFirebase/RNFirebase.h; sourceTree = "<group>"; };
|
||||||
D950369D1D19C77400F7094D /* RNFirebase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebase.m; path = RNFirebase/RNFirebase.m; sourceTree = "<group>"; };
|
D950369D1D19C77400F7094D /* RNFirebase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebase.m; path = RNFirebase/RNFirebase.m; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
@ -121,6 +124,7 @@
|
||||||
58B511D21A9E6C8500147676 = {
|
58B511D21A9E6C8500147676 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
BA84AE541FA9E59800E79390 /* storage */,
|
||||||
17AF4F681F59CDBF00C02336 /* links */,
|
17AF4F681F59CDBF00C02336 /* links */,
|
||||||
839D914D1EF3E20A0077C7C8 /* admob */,
|
839D914D1EF3E20A0077C7C8 /* admob */,
|
||||||
839D91541EF3E20A0077C7C8 /* analytics */,
|
839D91541EF3E20A0077C7C8 /* analytics */,
|
||||||
|
@ -131,11 +135,12 @@
|
||||||
8376F70D1F7C141500D45A85 /* firestore */,
|
8376F70D1F7C141500D45A85 /* firestore */,
|
||||||
839D91631EF3E20A0077C7C8 /* messaging */,
|
839D91631EF3E20A0077C7C8 /* messaging */,
|
||||||
839D91661EF3E20A0077C7C8 /* perf */,
|
839D91661EF3E20A0077C7C8 /* perf */,
|
||||||
134814211AA4EA7D00B7C361 /* Products */,
|
|
||||||
D950369C1D19C77400F7094D /* RNFirebase.h */,
|
D950369C1D19C77400F7094D /* RNFirebase.h */,
|
||||||
D950369D1D19C77400F7094D /* RNFirebase.m */,
|
D950369D1D19C77400F7094D /* RNFirebase.m */,
|
||||||
839D91771EF3E22F0077C7C8 /* RNFirebaseEvents.h */,
|
839D91771EF3E22F0077C7C8 /* RNFirebaseEvents.h */,
|
||||||
839D91691EF3E20A0077C7C8 /* storage */,
|
83C3EEED1FA1EACC00B64D3C /* RNFirebaseUtil.h */,
|
||||||
|
83C3EEEC1FA1EACC00B64D3C /* RNFirebaseUtil.m */,
|
||||||
|
134814211AA4EA7D00B7C361 /* Products */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
@ -247,11 +252,11 @@
|
||||||
path = RNFirebase/perf;
|
path = RNFirebase/perf;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
839D91691EF3E20A0077C7C8 /* storage */ = {
|
BA84AE541FA9E59800E79390 /* storage */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
839D916A1EF3E20A0077C7C8 /* RNFirebaseStorage.h */,
|
BA84AE551FA9E59800E79390 /* RNFirebaseStorage.h */,
|
||||||
839D916B1EF3E20A0077C7C8 /* RNFirebaseStorage.m */,
|
BA84AE561FA9E59800E79390 /* RNFirebaseStorage.m */,
|
||||||
);
|
);
|
||||||
name = storage;
|
name = storage;
|
||||||
path = RNFirebase/storage;
|
path = RNFirebase/storage;
|
||||||
|
@ -317,7 +322,6 @@
|
||||||
839D916C1EF3E20B0077C7C8 /* RNFirebaseAdMob.m in Sources */,
|
839D916C1EF3E20B0077C7C8 /* RNFirebaseAdMob.m in Sources */,
|
||||||
17AF4F6B1F59CDBF00C02336 /* RNFirebaseLinks.m in Sources */,
|
17AF4F6B1F59CDBF00C02336 /* RNFirebaseLinks.m in Sources */,
|
||||||
8376F7161F7C149100D45A85 /* RNFirebaseFirestoreCollectionReference.m in Sources */,
|
8376F7161F7C149100D45A85 /* RNFirebaseFirestoreCollectionReference.m in Sources */,
|
||||||
839D91761EF3E20B0077C7C8 /* RNFirebaseStorage.m in Sources */,
|
|
||||||
8376F7151F7C149100D45A85 /* RNFirebaseFirestore.m in Sources */,
|
8376F7151F7C149100D45A85 /* RNFirebaseFirestore.m in Sources */,
|
||||||
839D91701EF3E20B0077C7C8 /* RNFirebaseAuth.m in Sources */,
|
839D91701EF3E20B0077C7C8 /* RNFirebaseAuth.m in Sources */,
|
||||||
8323CF091F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m in Sources */,
|
8323CF091F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m in Sources */,
|
||||||
|
@ -326,7 +330,9 @@
|
||||||
839D91711EF3E20B0077C7C8 /* RNFirebaseRemoteConfig.m in Sources */,
|
839D91711EF3E20B0077C7C8 /* RNFirebaseRemoteConfig.m in Sources */,
|
||||||
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */,
|
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */,
|
||||||
839D91731EF3E20B0077C7C8 /* RNFirebaseDatabase.m in Sources */,
|
839D91731EF3E20B0077C7C8 /* RNFirebaseDatabase.m in Sources */,
|
||||||
|
BA84AE571FA9E59800E79390 /* RNFirebaseStorage.m in Sources */,
|
||||||
8323CF071F6FBD870071420B /* NativeExpressComponent.m in Sources */,
|
8323CF071F6FBD870071420B /* NativeExpressComponent.m in Sources */,
|
||||||
|
83C3EEEE1FA1EACC00B64D3C /* RNFirebaseUtil.m in Sources */,
|
||||||
839D91721EF3E20B0077C7C8 /* RNFirebaseCrash.m in Sources */,
|
839D91721EF3E20B0077C7C8 /* RNFirebaseCrash.m in Sources */,
|
||||||
839D91741EF3E20B0077C7C8 /* RNFirebaseMessaging.m in Sources */,
|
839D91741EF3E20B0077C7C8 /* RNFirebaseMessaging.m in Sources */,
|
||||||
839D91751EF3E20B0077C7C8 /* RNFirebasePerformance.m in Sources */,
|
839D91751EF3E20B0077C7C8 /* RNFirebasePerformance.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef RNFirebaseUtil_h
|
||||||
|
#define RNFirebaseUtil_h
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <React/RCTEventEmitter.h>
|
||||||
|
|
||||||
|
@interface RNFirebaseUtil : NSObject
|
||||||
|
|
||||||
|
+ (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(NSDictionary *)body;
|
||||||
|
+ (void)sendJSEventWithAppName:(RCTEventEmitter *)emitter appName:(NSString *)appName name:(NSString *)name body:(NSDictionary *)body;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,25 @@
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
|
|
||||||
|
@implementation RNFirebaseUtil
|
||||||
|
|
||||||
|
+ (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(NSDictionary *)body {
|
||||||
|
@try {
|
||||||
|
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
||||||
|
// until a better solution comes around
|
||||||
|
if (emitter.bridge) {
|
||||||
|
[emitter sendEventWithName:name body:body];
|
||||||
|
}
|
||||||
|
} @catch (NSException *error) {
|
||||||
|
NSLog(@"An error occurred in sendJSEvent: %@", [error debugDescription]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)sendJSEventWithAppName:(RCTEventEmitter *)emitter appName:(NSString *)appName name:(NSString *)name body:(NSDictionary *)body {
|
||||||
|
// Add the appName to the body
|
||||||
|
NSMutableDictionary *newBody = [body mutableCopy];
|
||||||
|
newBody[@"appName"] = appName;
|
||||||
|
|
||||||
|
[RNFirebaseUtil sendJSEvent:emitter name:name body:newBody];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -1,4 +1,5 @@
|
||||||
#import "RNFirebaseAdMobInterstitial.h"
|
#import "RNFirebaseAdMobInterstitial.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
|
|
||||||
@implementation RNFirebaseAdMobInterstitial
|
@implementation RNFirebaseAdMobInterstitial
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendJSEvent:(NSString *)type payload:(NSDictionary *)payload {
|
- (void)sendJSEvent:(NSString *)type payload:(NSDictionary *)payload {
|
||||||
[_delegate sendEventWithName:ADMOB_INTERSTITIAL_EVENT body:@{
|
[RNFirebaseUtil sendJSEvent:self.delegate name:ADMOB_INTERSTITIAL_EVENT body:@{
|
||||||
@"type": type,
|
@"type": type,
|
||||||
@"adUnit": _adUnitID,
|
@"adUnit": _adUnitID,
|
||||||
@"payload": payload
|
@"payload": payload
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#import "RNFirebaseAdMobRewardedVideo.h"
|
#import "RNFirebaseAdMobRewardedVideo.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
|
|
||||||
@implementation RNFirebaseAdMobRewardedVideo
|
@implementation RNFirebaseAdMobRewardedVideo
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendJSEvent:(NSString *)type payload:(NSDictionary *)payload {
|
- (void)sendJSEvent:(NSString *)type payload:(NSDictionary *)payload {
|
||||||
[_delegate sendEventWithName:ADMOB_REWARDED_VIDEO_EVENT body:@{
|
[RNFirebaseUtil sendJSEvent:self.delegate name:ADMOB_REWARDED_VIDEO_EVENT body:@{
|
||||||
@"type": type,
|
@"type": type,
|
||||||
@"adUnit": _adUnitID,
|
@"adUnit": _adUnitID,
|
||||||
@"payload": payload
|
@"payload": payload
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#import "RNFirebaseAuth.h"
|
#import "RNFirebaseAuth.h"
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
#import "RCTDefines.h"
|
#import "RCTDefines.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,9 +29,9 @@ RCT_EXPORT_METHOD(addAuthStateListener:
|
||||||
FIRApp *firApp = [FIRApp appNamed:appName];
|
FIRApp *firApp = [FIRApp appNamed:appName];
|
||||||
FIRAuthStateDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
|
FIRAuthStateDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
|
||||||
if (user != nil) {
|
if (user != nil) {
|
||||||
[self sendJSEventWithAppName:appName title:AUTH_CHANGED_EVENT props:[@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]} mutableCopy]];
|
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}];
|
||||||
} else {
|
} else {
|
||||||
[self sendJSEventWithAppName:appName title:AUTH_CHANGED_EVENT props:[@{@"authenticated": @(false)} mutableCopy]];
|
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(false)}];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
@ -63,9 +64,9 @@ RCT_EXPORT_METHOD(addIdTokenListener:
|
||||||
FIRApp *firApp = [FIRApp appNamed:appName];
|
FIRApp *firApp = [FIRApp appNamed:appName];
|
||||||
FIRIDTokenDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addIDTokenDidChangeListener:^(FIRAuth * _Nonnull auth, FIRUser * _Nullable user) {
|
FIRIDTokenDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addIDTokenDidChangeListener:^(FIRAuth * _Nonnull auth, FIRUser * _Nullable user) {
|
||||||
if (user != nil) {
|
if (user != nil) {
|
||||||
[self sendJSEventWithAppName:appName title:AUTH_ID_TOKEN_CHANGED_EVENT props:[@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]} mutableCopy]];
|
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}];
|
||||||
} else {
|
} else {
|
||||||
[self sendJSEventWithAppName:appName title:AUTH_ID_TOKEN_CHANGED_EVENT props:[@{@"authenticated": @(false)} mutableCopy]];
|
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(false)}];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
@ -248,14 +249,7 @@ RCT_EXPORT_METHOD(reload:
|
||||||
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
|
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
[user reloadWithCompletion:^(NSError *_Nullable error) {
|
[self reloadAndReturnUser:user resolver:resolve rejecter: reject];
|
||||||
if (error) {
|
|
||||||
[self promiseRejectAuthException:reject error:error];
|
|
||||||
} else {
|
|
||||||
FIRUser *userAfterReload = [FIRAuth authWithApp:firApp].currentUser;
|
|
||||||
[self promiseWithUser:resolve rejecter:reject user:userAfterReload];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
} else {
|
} else {
|
||||||
[self promiseNoUser:resolve rejecter:reject isError:YES];
|
[self promiseNoUser:resolve rejecter:reject isError:YES];
|
||||||
}
|
}
|
||||||
|
@ -315,8 +309,7 @@ RCT_EXPORT_METHOD(updateEmail:
|
||||||
if (error) {
|
if (error) {
|
||||||
[self promiseRejectAuthException:reject error:error];
|
[self promiseRejectAuthException:reject error:error];
|
||||||
} else {
|
} else {
|
||||||
FIRUser *userAfterUpdate = [FIRAuth authWithApp:firApp].currentUser;
|
[self reloadAndReturnUser:user resolver:resolve rejecter: reject];
|
||||||
[self promiseWithUser:resolve rejecter:reject user:userAfterUpdate];
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
|
@ -399,8 +392,7 @@ RCT_EXPORT_METHOD(updateProfile:
|
||||||
if (error) {
|
if (error) {
|
||||||
[self promiseRejectAuthException:reject error:error];
|
[self promiseRejectAuthException:reject error:error];
|
||||||
} else {
|
} else {
|
||||||
FIRUser *userAfterUpdate = [FIRAuth authWithApp:firApp].currentUser;
|
[self reloadAndReturnUser:user resolver:resolve rejecter: reject];
|
||||||
[self promiseWithUser:resolve rejecter:reject user:userAfterUpdate];
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
|
@ -686,21 +678,21 @@ RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString *) appName
|
||||||
[[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
|
[[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
NSDictionary * jsError = [self getJSError:(error)];
|
NSDictionary * jsError = [self getJSError:(error)];
|
||||||
NSMutableDictionary * props = [@{
|
NSDictionary *body = @{
|
||||||
@"type": @"onVerificationFailed",
|
@"type": @"onVerificationFailed",
|
||||||
@"requestKey":requestKey,
|
@"requestKey":requestKey,
|
||||||
@"state": @{@"error": jsError},
|
@"state": @{@"error": jsError},
|
||||||
} mutableCopy];
|
};
|
||||||
[self sendJSEventWithAppName:appName title:PHONE_AUTH_STATE_CHANGED_EVENT props: props];
|
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:PHONE_AUTH_STATE_CHANGED_EVENT body:body];
|
||||||
} else {
|
} else {
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
[defaults setObject:verificationID forKey:@"authVerificationID"];
|
[defaults setObject:verificationID forKey:@"authVerificationID"];
|
||||||
NSMutableDictionary * props = [@{
|
NSDictionary *body = @{
|
||||||
@"type": @"onCodeSent",
|
@"type": @"onCodeSent",
|
||||||
@"requestKey":requestKey,
|
@"requestKey":requestKey,
|
||||||
@"state": @{@"verificationId": verificationID},
|
@"state": @{@"verificationId": verificationID},
|
||||||
} mutableCopy];
|
};
|
||||||
[self sendJSEventWithAppName:appName title:PHONE_AUTH_STATE_CHANGED_EVENT props: props];
|
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:PHONE_AUTH_STATE_CHANGED_EVENT body:body];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
@ -794,15 +786,7 @@ RCT_EXPORT_METHOD(unlink:
|
||||||
if (error) {
|
if (error) {
|
||||||
[self promiseRejectAuthException:reject error:error];
|
[self promiseRejectAuthException:reject error:error];
|
||||||
} else {
|
} else {
|
||||||
// This is here to protect against bugs in the iOS SDK which don't
|
[self reloadAndReturnUser:user resolver:resolve rejecter: reject];
|
||||||
// correctly refresh the user object when unlinking certain accounts
|
|
||||||
[user reloadWithCompletion:^(NSError * _Nullable error) {
|
|
||||||
if (error) {
|
|
||||||
[self promiseRejectAuthException:reject error:error];
|
|
||||||
} else {
|
|
||||||
[self promiseWithUser:resolve rejecter:reject user:user];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
|
@ -916,6 +900,19 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||||
return credential;
|
return credential;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is here to protect against bugs in the iOS SDK which don't
|
||||||
|
// correctly refresh the user object when performing certain operations
|
||||||
|
- (void)reloadAndReturnUser:(FIRUser *)user
|
||||||
|
resolver:(RCTPromiseResolveBlock)resolve
|
||||||
|
rejecter:(RCTPromiseRejectBlock)reject {
|
||||||
|
[user reloadWithCompletion:^(NSError * _Nullable error) {
|
||||||
|
if (error) {
|
||||||
|
[self promiseRejectAuthException:reject error:error];
|
||||||
|
} else {
|
||||||
|
[self promiseWithUser:resolve rejecter:reject user:user];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Resolve or reject a promise based on isError value
|
Resolve or reject a promise based on isError value
|
||||||
|
@ -1087,31 +1084,6 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
wrapper for sendEventWithName for auth events
|
|
||||||
|
|
||||||
@param title sendEventWithName
|
|
||||||
@param props <#props description#>
|
|
||||||
*/
|
|
||||||
- (void)sendJSEvent:(NSString *)title props:(NSDictionary *)props {
|
|
||||||
@try {
|
|
||||||
[self sendEventWithName:title body:props];
|
|
||||||
} @catch (NSException *error) {
|
|
||||||
NSLog(@"An error occurred in sendJSEvent: %@", [error debugDescription]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)sendJSEventWithAppName:(NSString *)appName title:(NSString *)title props:(NSMutableDictionary *)props {
|
|
||||||
props[@"appName"] = appName;
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[self sendEventWithName:title body:props];
|
|
||||||
} @catch (NSException *error) {
|
|
||||||
NSLog(@"An error occurred in sendJSEvent: %@", [error debugDescription]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Converts an array of FIRUserInfo instances into the correct format to match the web sdk
|
Converts an array of FIRUserInfo instances into the correct format to match the web sdk
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#import <Firebase.h>
|
#import <Firebase.h>
|
||||||
#import "RNFirebaseDatabaseReference.h"
|
#import "RNFirebaseDatabaseReference.h"
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
|
|
||||||
@implementation RNFirebaseDatabase
|
@implementation RNFirebaseDatabase
|
||||||
RCT_EXPORT_MODULE();
|
RCT_EXPORT_MODULE();
|
||||||
|
@ -39,7 +40,7 @@ RCT_EXPORT_METHOD(keepSynced:(NSString *) appName
|
||||||
path:(NSString *) path
|
path:(NSString *) path
|
||||||
modifiers:(NSArray *) modifiers
|
modifiers:(NSArray *) modifiers
|
||||||
state:(BOOL) state) {
|
state:(BOOL) state) {
|
||||||
FIRDatabaseQuery *query = [self getInternalReferenceForApp:appName key:key path:path modifiers:modifiers keep:false].query;
|
FIRDatabaseQuery *query = [self getInternalReferenceForApp:appName key:key path:path modifiers:modifiers].query;
|
||||||
[query keepSynced:state];
|
[query keepSynced:state];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +88,7 @@ RCT_EXPORT_METHOD(transactionStart:(NSString *) appName
|
||||||
dispatch_barrier_async(_transactionQueue, ^{
|
dispatch_barrier_async(_transactionQueue, ^{
|
||||||
[_transactions setValue:transactionState forKey:transactionId];
|
[_transactions setValue:transactionState forKey:transactionId];
|
||||||
NSDictionary *updateMap = [self createTransactionUpdateMap:appName transactionId:transactionId updatesData:currentData];
|
NSDictionary *updateMap = [self createTransactionUpdateMap:appName transactionId:transactionId updatesData:currentData];
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:updateMap];
|
||||||
// until a better solution comes around
|
|
||||||
if (self.bridge) {
|
|
||||||
[self sendEventWithName:DATABASE_TRANSACTION_EVENT body:updateMap];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// wait for the js event handler to call tryCommitTransaction
|
// wait for the js event handler to call tryCommitTransaction
|
||||||
|
@ -118,11 +115,7 @@ RCT_EXPORT_METHOD(transactionStart:(NSString *) appName
|
||||||
andCompletionBlock:
|
andCompletionBlock:
|
||||||
^(NSError *_Nullable databaseError, BOOL committed, FIRDataSnapshot *_Nullable snapshot) {
|
^(NSError *_Nullable databaseError, BOOL committed, FIRDataSnapshot *_Nullable snapshot) {
|
||||||
NSDictionary *resultMap = [self createTransactionResultMap:appName transactionId:transactionId error:databaseError committed:committed snapshot:snapshot];
|
NSDictionary *resultMap = [self createTransactionResultMap:appName transactionId:transactionId error:databaseError committed:committed snapshot:snapshot];
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:resultMap];
|
||||||
// until a better solution comes around
|
|
||||||
if (self.bridge) {
|
|
||||||
[self sendEventWithName:DATABASE_TRANSACTION_EVENT body:resultMap];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
withLocalEvents:
|
withLocalEvents:
|
||||||
applyLocally];
|
applyLocally];
|
||||||
|
@ -233,13 +226,13 @@ RCT_EXPORT_METHOD(once:(NSString *) appName
|
||||||
eventName:(NSString *) eventName
|
eventName:(NSString *) eventName
|
||||||
resolver:(RCTPromiseResolveBlock) resolve
|
resolver:(RCTPromiseResolveBlock) resolve
|
||||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||||
RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appName key:key path:path modifiers:modifiers keep:false];
|
RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appName key:key path:path modifiers:modifiers];
|
||||||
[ref once:eventName resolver:resolve rejecter:reject];
|
[ref once:eventName resolver:resolve rejecter:reject];
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(on:(NSString *) appName
|
RCT_EXPORT_METHOD(on:(NSString *) appName
|
||||||
props:(NSDictionary *) props) {
|
props:(NSDictionary *) props) {
|
||||||
RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appName key:props[@"key"] path:props[@"path"] modifiers:props[@"modifiers"] keep:false];
|
RNFirebaseDatabaseReference *ref = [self getCachedInternalReferenceForApp:appName props:props];
|
||||||
[ref on:props[@"eventType"] registration:props[@"registration"]];
|
[ref on:props[@"eventType"] registration:props[@"registration"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,16 +271,21 @@ RCT_EXPORT_METHOD(off:(NSString *) key
|
||||||
return [[RNFirebaseDatabase getDatabaseForApp:appName] referenceWithPath:path];
|
return [[RNFirebaseDatabase getDatabaseForApp:appName] referenceWithPath:path];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNFirebaseDatabaseReference *)getInternalReferenceForApp:(NSString *)appName key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers keep:(BOOL)keep {
|
- (RNFirebaseDatabaseReference *)getInternalReferenceForApp:(NSString *)appName key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers {
|
||||||
|
return [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self app:appName key:key refPath:path modifiers:modifiers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (RNFirebaseDatabaseReference *)getCachedInternalReferenceForApp:(NSString *)appName props:(NSDictionary *)props {
|
||||||
|
NSString *key = props[@"key"];
|
||||||
|
NSString *path = props[@"path"];
|
||||||
|
NSDictionary *modifiers = props[@"modifiers"];
|
||||||
|
|
||||||
RNFirebaseDatabaseReference *ref = _dbReferences[key];
|
RNFirebaseDatabaseReference *ref = _dbReferences[key];
|
||||||
|
|
||||||
if (ref == nil) {
|
if (ref == nil) {
|
||||||
ref = [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self app:appName key:key refPath:path modifiers:modifiers];
|
ref = [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self app:appName key:key refPath:path modifiers:modifiers];
|
||||||
|
|
||||||
if (keep) {
|
|
||||||
_dbReferences[key] = ref;
|
_dbReferences[key] = ref;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#import <FirebaseDatabase/FIRDatabase.h>
|
#import <FirebaseDatabase/FIRDatabase.h>
|
||||||
#import "RNFirebaseDatabase.h"
|
#import "RNFirebaseDatabase.h"
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
#import <React/RCTEventEmitter.h>
|
#import <React/RCTEventEmitter.h>
|
||||||
|
|
||||||
@interface RNFirebaseDatabaseReference : NSObject
|
@interface RNFirebaseDatabaseReference : NSObject
|
||||||
|
|
|
@ -71,11 +71,7 @@
|
||||||
[event setValue:eventType forKey:@"eventType"];
|
[event setValue:eventType forKey:@"eventType"];
|
||||||
[event setValue:registration forKey:@"registration"];
|
[event setValue:registration forKey:@"registration"];
|
||||||
|
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self.emitter name:DATABASE_SYNC_EVENT body:event];
|
||||||
// until a better solution comes around
|
|
||||||
if (_emitter.bridge) {
|
|
||||||
[_emitter sendEventWithName:DATABASE_SYNC_EVENT body:event];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleDatabaseError:(NSDictionary *) registration
|
- (void)handleDatabaseError:(NSDictionary *) registration
|
||||||
|
@ -85,11 +81,7 @@
|
||||||
[event setValue:[RNFirebaseDatabase getJSError:error] forKey:@"error"];
|
[event setValue:[RNFirebaseDatabase getJSError:error] forKey:@"error"];
|
||||||
[event setValue:registration forKey:@"registration"];
|
[event setValue:registration forKey:@"registration"];
|
||||||
|
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self.emitter name:DATABASE_SYNC_EVENT body:event];
|
||||||
// until a better solution comes around
|
|
||||||
if (_emitter) {
|
|
||||||
[_emitter sendEventWithName:DATABASE_SYNC_EVENT body:event];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDictionary *)snapshotToDictionary:(FIRDataSnapshot *) dataSnapshot
|
+ (NSDictionary *)snapshotToDictionary:(FIRDataSnapshot *) dataSnapshot
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
#import "RNFirebaseFirestore.h"
|
#import "RNFirebaseFirestore.h"
|
||||||
#import "RNFirebaseFirestoreDocumentReference.h"
|
#import "RNFirebaseFirestoreDocumentReference.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
|
|
||||||
@interface RNFirebaseFirestoreCollectionReference : NSObject
|
@interface RNFirebaseFirestoreCollectionReference : NSObject
|
||||||
@property RCTEventEmitter *emitter;
|
@property RCTEventEmitter *emitter;
|
||||||
|
|
|
@ -81,20 +81,22 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FIRQuery *)buildQuery {
|
- (FIRQuery *)buildQuery {
|
||||||
FIRQuery *query = (FIRQuery*)[[RNFirebaseFirestore getFirestoreForApp:_app] collectionWithPath:_path];
|
FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:_app];
|
||||||
query = [self applyFilters:query];
|
FIRQuery *query = (FIRQuery*)[firestore collectionWithPath:_path];
|
||||||
|
query = [self applyFilters:firestore query:query];
|
||||||
query = [self applyOrders:query];
|
query = [self applyOrders:query];
|
||||||
query = [self applyOptions:query];
|
query = [self applyOptions:firestore query:query];
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FIRQuery *)applyFilters:(FIRQuery *) query {
|
- (FIRQuery *)applyFilters:(FIRFirestore *) firestore
|
||||||
|
query:(FIRQuery *) query {
|
||||||
for (NSDictionary *filter in _filters) {
|
for (NSDictionary *filter in _filters) {
|
||||||
NSString *fieldPath = filter[@"fieldPath"];
|
NSString *fieldPath = filter[@"fieldPath"];
|
||||||
NSString *operator = filter[@"operator"];
|
NSString *operator = filter[@"operator"];
|
||||||
// TODO: Validate this works
|
NSDictionary *jsValue = filter[@"value"];
|
||||||
id value = filter[@"value"];
|
id value = [RNFirebaseFirestoreDocumentReference parseJSTypeMap:firestore jsTypeMap:jsValue];
|
||||||
|
|
||||||
if ([operator isEqualToString:@"EQUAL"]) {
|
if ([operator isEqualToString:@"EQUAL"]) {
|
||||||
query = [query queryWhereField:fieldPath isEqualTo:value];
|
query = [query queryWhereField:fieldPath isEqualTo:value];
|
||||||
|
@ -121,12 +123,16 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FIRQuery *)applyOptions:(FIRQuery *) query {
|
- (FIRQuery *)applyOptions:(FIRFirestore *) firestore
|
||||||
|
query:(FIRQuery *) query {
|
||||||
if (_options[@"endAt"]) {
|
if (_options[@"endAt"]) {
|
||||||
query = [query queryEndingAtValues:_options[@"endAt"]];
|
query = [query queryEndingAtValues:[RNFirebaseFirestoreDocumentReference parseJSArray:firestore jsArray:_options[@"endAt"]]];
|
||||||
}
|
}
|
||||||
if (_options[@"endBefore"]) {
|
if (_options[@"endBefore"]) {
|
||||||
query = [query queryEndingBeforeValues:_options[@"endBefore"]];
|
query = [query queryEndingBeforeValues:[RNFirebaseFirestoreDocumentReference parseJSArray:firestore jsArray:_options[@"endBefore"]]];
|
||||||
|
}
|
||||||
|
if (_options[@"limit"]) {
|
||||||
|
query = [query queryLimitedTo:[_options[@"limit"] intValue]];
|
||||||
}
|
}
|
||||||
if (_options[@"offset"]) {
|
if (_options[@"offset"]) {
|
||||||
// iOS doesn't support offset
|
// iOS doesn't support offset
|
||||||
|
@ -135,10 +141,10 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
||||||
// iOS doesn't support selectFields
|
// iOS doesn't support selectFields
|
||||||
}
|
}
|
||||||
if (_options[@"startAfter"]) {
|
if (_options[@"startAfter"]) {
|
||||||
query = [query queryStartingAfterValues:_options[@"startAfter"]];
|
query = [query queryStartingAfterValues:[RNFirebaseFirestoreDocumentReference parseJSArray:firestore jsArray:_options[@"startAfter"]]];
|
||||||
}
|
}
|
||||||
if (_options[@"startAt"]) {
|
if (_options[@"startAt"]) {
|
||||||
query = [query queryStartingAtValues:_options[@"startAt"]];
|
query = [query queryStartingAtValues:[RNFirebaseFirestoreDocumentReference parseJSArray:firestore jsArray:_options[@"startAt"]]];
|
||||||
}
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
@ -151,11 +157,7 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
||||||
[event setValue:listenerId forKey:@"listenerId"];
|
[event setValue:listenerId forKey:@"listenerId"];
|
||||||
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
|
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
|
||||||
|
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self.emitter name:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
|
||||||
// until a better solution comes around
|
|
||||||
if (_emitter.bridge) {
|
|
||||||
[_emitter sendEventWithName:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleQuerySnapshotEvent:(NSString *)listenerId
|
- (void)handleQuerySnapshotEvent:(NSString *)listenerId
|
||||||
|
@ -166,11 +168,7 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
||||||
[event setValue:listenerId forKey:@"listenerId"];
|
[event setValue:listenerId forKey:@"listenerId"];
|
||||||
[event setValue:[RNFirebaseFirestoreCollectionReference snapshotToDictionary:querySnapshot] forKey:@"querySnapshot"];
|
[event setValue:[RNFirebaseFirestoreCollectionReference snapshotToDictionary:querySnapshot] forKey:@"querySnapshot"];
|
||||||
|
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self.emitter name:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
|
||||||
// until a better solution comes around
|
|
||||||
if (_emitter.bridge) {
|
|
||||||
[_emitter sendEventWithName:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot {
|
+ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#import <React/RCTEventEmitter.h>
|
#import <React/RCTEventEmitter.h>
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
#import "RNFirebaseFirestore.h"
|
#import "RNFirebaseFirestore.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
|
|
||||||
@interface RNFirebaseFirestoreDocumentReference : NSObject
|
@interface RNFirebaseFirestoreDocumentReference : NSObject
|
||||||
@property RCTEventEmitter *emitter;
|
@property RCTEventEmitter *emitter;
|
||||||
|
@ -25,7 +26,10 @@
|
||||||
- (void)update:(NSDictionary *)data resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
- (void)update:(NSDictionary *)data resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||||
- (BOOL)hasListeners;
|
- (BOOL)hasListeners;
|
||||||
+ (NSDictionary *)snapshotToDictionary:(FIRDocumentSnapshot *)documentSnapshot;
|
+ (NSDictionary *)snapshotToDictionary:(FIRDocumentSnapshot *)documentSnapshot;
|
||||||
+(NSDictionary *)parseJSMap:(FIRFirestore *) firestore jsMap:(NSDictionary *) jsMap;
|
+ (NSDictionary *)parseJSMap:(FIRFirestore *) firestore jsMap:(NSDictionary *) jsMap;
|
||||||
|
+ (NSArray *)parseJSArray:(FIRFirestore *) firestore jsArray:(NSArray *) jsArray;
|
||||||
|
+ (id)parseJSTypeMap:(FIRFirestore *) firestore jsTypeMap:(NSDictionary *) jsTypeMap;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -136,11 +136,7 @@ static NSMutableDictionary *_listeners;
|
||||||
[event setValue:listenerId forKey:@"listenerId"];
|
[event setValue:listenerId forKey:@"listenerId"];
|
||||||
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
|
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
|
||||||
|
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self.emitter name:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
|
||||||
// until a better solution comes around
|
|
||||||
if (_emitter.bridge) {
|
|
||||||
[_emitter sendEventWithName:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleDocumentSnapshotEvent:(NSString *)listenerId
|
- (void)handleDocumentSnapshotEvent:(NSString *)listenerId
|
||||||
|
@ -151,11 +147,7 @@ static NSMutableDictionary *_listeners;
|
||||||
[event setValue:listenerId forKey:@"listenerId"];
|
[event setValue:listenerId forKey:@"listenerId"];
|
||||||
[event setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentSnapshot] forKey:@"documentSnapshot"];
|
[event setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentSnapshot] forKey:@"documentSnapshot"];
|
||||||
|
|
||||||
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
|
[RNFirebaseUtil sendJSEvent:self.emitter name:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
|
||||||
// until a better solution comes around
|
|
||||||
if (_emitter.bridge) {
|
|
||||||
[_emitter sendEventWithName:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,9 +197,9 @@ static NSMutableDictionary *_listeners;
|
||||||
typeMap[@"value"] = geopoint;
|
typeMap[@"value"] = geopoint;
|
||||||
} else if ([value isKindOfClass:[NSDate class]]) {
|
} else if ([value isKindOfClass:[NSDate class]]) {
|
||||||
typeMap[@"type"] = @"date";
|
typeMap[@"type"] = @"date";
|
||||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
// NOTE: The round() is important as iOS ends up giving .999 otherwise,
|
||||||
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
// and loses a millisecond when going between native and JS
|
||||||
typeMap[@"value"] = [dateFormatter stringFromDate:(NSDate *)value];
|
typeMap[@"value"] = @(round([(NSDate *)value timeIntervalSince1970] * 1000.0));
|
||||||
} else if ([value isKindOfClass:[NSNumber class]]) {
|
} else if ([value isKindOfClass:[NSNumber class]]) {
|
||||||
NSNumber *number = (NSNumber *)value;
|
NSNumber *number = (NSNumber *)value;
|
||||||
if (number == (void*)kCFBooleanFalse || number == (void*)kCFBooleanTrue) {
|
if (number == (void*)kCFBooleanFalse || number == (void*)kCFBooleanTrue) {
|
||||||
|
@ -262,9 +254,7 @@ static NSMutableDictionary *_listeners;
|
||||||
NSNumber *longitude = geopoint[@"longitude"];
|
NSNumber *longitude = geopoint[@"longitude"];
|
||||||
return [[FIRGeoPoint alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]];
|
return [[FIRGeoPoint alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]];
|
||||||
} else if ([type isEqualToString:@"date"]) {
|
} else if ([type isEqualToString:@"date"]) {
|
||||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
return [NSDate dateWithTimeIntervalSince1970:([(NSNumber *)value doubleValue] / 1000.0)];
|
||||||
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
|
||||||
return [dateFormatter dateFromString:value];
|
|
||||||
} else if ([type isEqualToString:@"fieldvalue"]) {
|
} else if ([type isEqualToString:@"fieldvalue"]) {
|
||||||
NSString *string = (NSString*)value;
|
NSString *string = (NSString*)value;
|
||||||
if ([string isEqualToString:@"delete"]) {
|
if ([string isEqualToString:@"delete"]) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
@import UserNotifications;
|
@import UserNotifications;
|
||||||
#if __has_include(<FirebaseMessaging/FirebaseMessaging.h>)
|
#if __has_include(<FirebaseMessaging/FirebaseMessaging.h>)
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
#import <FirebaseMessaging/FirebaseMessaging.h>
|
#import <FirebaseMessaging/FirebaseMessaging.h>
|
||||||
#import <FirebaseInstanceID/FIRInstanceID.h>
|
#import <FirebaseInstanceID/FIRInstanceID.h>
|
||||||
|
|
||||||
|
@ -217,7 +218,7 @@ RCT_EXPORT_MODULE()
|
||||||
data[@"_completionHandlerId"] = completionHandlerId;
|
data[@"_completionHandlerId"] = completionHandlerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self sendEventWithName:MESSAGING_NOTIFICATION_RECEIVED body:data];
|
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_NOTIFICATION_RECEIVED body:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,13 +235,13 @@ RCT_EXPORT_MODULE()
|
||||||
// ** Start FIRMessagingDelegate methods **
|
// ** Start FIRMessagingDelegate methods **
|
||||||
// Handle data messages in the background
|
// Handle data messages in the background
|
||||||
- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
|
- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
|
||||||
[self sendEventWithName:MESSAGING_NOTIFICATION_RECEIVED body:[remoteMessage appData]];
|
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_NOTIFICATION_RECEIVED body:[remoteMessage appData]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for token refreshes
|
// Listen for token refreshes
|
||||||
- (void)messaging:(nonnull FIRMessaging *)messaging didRefreshRegistrationToken:(nonnull NSString *)fcmToken {
|
- (void)messaging:(nonnull FIRMessaging *)messaging didRefreshRegistrationToken:(nonnull NSString *)fcmToken {
|
||||||
NSLog(@"FCM registration token: %@", fcmToken);
|
NSLog(@"FCM registration token: %@", fcmToken);
|
||||||
[self sendEventWithName:MESSAGING_TOKEN_REFRESHED body:fcmToken];
|
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_TOKEN_REFRESHED body:fcmToken];
|
||||||
}
|
}
|
||||||
// ** End FIRMessagingDelegate methods **
|
// ** End FIRMessagingDelegate methods **
|
||||||
|
|
||||||
|
@ -297,7 +298,9 @@ RCT_EXPORT_METHOD(requestPermissions:(RCTPromiseResolveBlock)resolve rejecter:(R
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[RCTSharedApplication() registerForRemoteNotifications];
|
[RCTSharedApplication() registerForRemoteNotifications];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(subscribeToTopic: (NSString*) topic) {
|
RCT_EXPORT_METHOD(subscribeToTopic: (NSString*) topic) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#if __has_include(<FirebaseStorage/FIRStorage.h>)
|
#if __has_include(<FirebaseStorage/FIRStorage.h>)
|
||||||
|
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
|
#import "RNFirebaseUtil.h"
|
||||||
#import <MobileCoreServices/MobileCoreServices.h>
|
#import <MobileCoreServices/MobileCoreServices.h>
|
||||||
#import <Photos/Photos.h>
|
#import <Photos/Photos.h>
|
||||||
#import <Firebase.h>
|
#import <Firebase.h>
|
||||||
|
@ -392,12 +393,7 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendJSEvent:(NSString *)appName type:(NSString *)type path:(NSString *)path title:(NSString *)title props:(NSDictionary *)props {
|
- (void)sendJSEvent:(NSString *)appName type:(NSString *)type path:(NSString *)path title:(NSString *)title props:(NSDictionary *)props {
|
||||||
@try {
|
[RNFirebaseUtil sendJSEvent:self name:type body:@{@"eventName": title, @"appName": appName, @"path": path, @"body": props}];
|
||||||
[self sendEventWithName:type body:@{@"eventName": title, @"appName": appName, @"path": path, @"body": props}];
|
|
||||||
} @catch (NSException *err) {
|
|
||||||
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
|
|
||||||
NSLog(@"Tried to send: %@ with %@", title, props);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -141,18 +141,14 @@ export default class PhoneAuthListener {
|
||||||
_removeAllListeners() {
|
_removeAllListeners() {
|
||||||
setTimeout(() => { // move to next event loop - not sure if needed
|
setTimeout(() => { // move to next event loop - not sure if needed
|
||||||
// internal listeners
|
// internal listeners
|
||||||
const events = Object.values(this._internalEvents);
|
Object.values(this._internalEvents).forEach((event) => {
|
||||||
|
this._auth.removeAllListeners(event);
|
||||||
for (let i = 0, len = events.length; i < len; i++) {
|
});
|
||||||
this._auth.removeAllListeners(events[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// user observer listeners
|
// user observer listeners
|
||||||
const publicEvents = Object.values(this._publicEvents);
|
Object.values(this._publicEvents).forEach((publicEvent) => {
|
||||||
|
this._auth.removeAllListeners(publicEvent);
|
||||||
for (let i = 0, len = events.length; i < len; i++) {
|
});
|
||||||
this._auth.removeAllListeners(publicEvents[i]);
|
|
||||||
}
|
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,33 +22,31 @@ export default class Auth extends ModuleBase {
|
||||||
_native: Object;
|
_native: Object;
|
||||||
_getAppEventName: Function;
|
_getAppEventName: Function;
|
||||||
_authResult: AuthResultType | null;
|
_authResult: AuthResultType | null;
|
||||||
authenticated: boolean;
|
|
||||||
|
|
||||||
constructor(firebaseApp: Object, options: Object = {}) {
|
constructor(firebaseApp: Object, options: Object = {}) {
|
||||||
super(firebaseApp, options, true);
|
super(firebaseApp, options, true);
|
||||||
this._user = null;
|
this._user = null;
|
||||||
this._authResult = null;
|
this._authResult = null;
|
||||||
this.authenticated = false;
|
|
||||||
|
|
||||||
this.addListener(
|
this.addListener(
|
||||||
// sub to internal native event - this fans out to
|
// sub to internal native event - this fans out to
|
||||||
// public event name: onAuthStateChanged
|
// public event name: onAuthStateChanged
|
||||||
this._getAppEventName('auth_state_changed'),
|
this._getAppEventName('auth_state_changed'),
|
||||||
this._onAuthStateChanged.bind(this),
|
this._onInternalAuthStateChanged.bind(this),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.addListener(
|
this.addListener(
|
||||||
// sub to internal native event - this fans out to
|
// sub to internal native event - this fans out to
|
||||||
// public events based on event.type
|
// public events based on event.type
|
||||||
this._getAppEventName('phone_auth_state_changed'),
|
this._getAppEventName('phone_auth_state_changed'),
|
||||||
this._onPhoneAuthStateChanged.bind(this),
|
this._onInternalPhoneAuthStateChanged.bind(this),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.addListener(
|
this.addListener(
|
||||||
// sub to internal native event - this fans out to
|
// sub to internal native event - this fans out to
|
||||||
// public event name: onIdTokenChanged
|
// public event name: onIdTokenChanged
|
||||||
this._getAppEventName('auth_id_token_changed'),
|
this._getAppEventName('auth_id_token_changed'),
|
||||||
this._onIdTokenChanged.bind(this),
|
this._onInternalIdTokenChanged.bind(this),
|
||||||
);
|
);
|
||||||
|
|
||||||
this._native.addAuthStateListener();
|
this._native.addAuthStateListener();
|
||||||
|
@ -60,34 +58,25 @@ export default class Auth extends ModuleBase {
|
||||||
* @param event
|
* @param event
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onPhoneAuthStateChanged(event: Object) {
|
_onInternalPhoneAuthStateChanged(event: Object) {
|
||||||
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
|
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
|
||||||
this.emit(eventKey, event.state);
|
this.emit(eventKey, event.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
_setAuthState(auth: AuthResultType) {
|
||||||
* Internal auth changed listener
|
|
||||||
* @param auth
|
|
||||||
* @param emit
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_onAuthStateChanged(auth: AuthResultType, emit: boolean = true) {
|
|
||||||
this._authResult = auth;
|
this._authResult = auth;
|
||||||
this.authenticated = auth ? auth.authenticated || false : false;
|
this._user = auth && auth.user ? new User(this, auth.user) : null;
|
||||||
if (auth && auth.user && !this._user) this._user = new User(this, auth);
|
this.emit(this._getAppEventName('onUserChanged'), this._user);
|
||||||
else if ((!auth || !auth.user) && this._user) this._user = null;
|
|
||||||
else if (this._user) this._user._updateValues(auth);
|
|
||||||
if (emit) this.emit(this._getAppEventName('onAuthStateChanged'), this._user);
|
|
||||||
return auth ? this._user : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove auth change listener
|
* Internal auth changed listener
|
||||||
* @param listener
|
* @param auth
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_offAuthStateChanged(listener: Function) {
|
_onInternalAuthStateChanged(auth: AuthResultType) {
|
||||||
this.log.info('Removing onAuthStateChanged listener');
|
this._setAuthState(auth);
|
||||||
this.removeListener(this._getAppEventName('onAuthStateChanged'), listener);
|
this.emit(this._getAppEventName('onAuthStateChanged'), this._user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,23 +85,9 @@ export default class Auth extends ModuleBase {
|
||||||
* @param emit
|
* @param emit
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onIdTokenChanged(auth: AuthResultType, emit: boolean = true) {
|
_onInternalIdTokenChanged(auth: AuthResultType) {
|
||||||
this._authResult = auth;
|
this._setAuthState(auth);
|
||||||
this.authenticated = auth ? auth.authenticated || false : false;
|
this.emit(this._getAppEventName('onIdTokenChanged'), this._user);
|
||||||
if (auth && auth.user && !this._user) this._user = new User(this, auth);
|
|
||||||
else if ((!auth || !auth.user) && this._user) this._user = null;
|
|
||||||
else if (this._user) this._user._updateValues(auth);
|
|
||||||
if (emit) this.emit(this._getAppEventName('onIdTokenChanged'), this._user);
|
|
||||||
return auth ? this._user : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove id token change listener
|
|
||||||
* @param listener
|
|
||||||
*/
|
|
||||||
_offIdTokenChanged(listener: Function) {
|
|
||||||
this.log.info('Removing onIdTokenChanged listener');
|
|
||||||
this.removeListener(this._getAppEventName('onIdTokenChanged'), listener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,10 +99,10 @@ export default class Auth extends ModuleBase {
|
||||||
*/
|
*/
|
||||||
_interceptUserValue(promise) {
|
_interceptUserValue(promise) {
|
||||||
return promise.then((result) => {
|
return promise.then((result) => {
|
||||||
if (!result) return this._onAuthStateChanged(null, false);
|
if (!result) this._setAuthState(null);
|
||||||
if (result.user) return this._onAuthStateChanged(result, false);
|
else if (result.user) this._setAuthState(result);
|
||||||
if (result.uid) return this._onAuthStateChanged({ authenticated: true, user: result }, false);
|
else if (result.uid) this._setAuthState({ authenticated: true, user: result });
|
||||||
return result;
|
return this._user;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +121,15 @@ export default class Auth extends ModuleBase {
|
||||||
return this._offAuthStateChanged.bind(this, listener);
|
return this._offAuthStateChanged.bind(this, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove auth change listener
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
_offAuthStateChanged(listener: Function) {
|
||||||
|
this.log.info('Removing onAuthStateChanged listener');
|
||||||
|
this.removeListener(this._getAppEventName('onAuthStateChanged'), listener);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for id token changes.
|
* Listen for id token changes.
|
||||||
* @param listener
|
* @param listener
|
||||||
|
@ -157,6 +141,35 @@ export default class Auth extends ModuleBase {
|
||||||
return this._offIdTokenChanged.bind(this, listener);
|
return this._offIdTokenChanged.bind(this, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove id token change listener
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
_offIdTokenChanged(listener: Function) {
|
||||||
|
this.log.info('Removing onIdTokenChanged listener');
|
||||||
|
this.removeListener(this._getAppEventName('onIdTokenChanged'), listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for user changes.
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
onUserChanged(listener: Function) {
|
||||||
|
this.log.info('Creating onUserChanged listener');
|
||||||
|
this.on(this._getAppEventName('onUserChanged'), listener);
|
||||||
|
if (this._authResult) listener(this._user || null);
|
||||||
|
return this._offUserChanged.bind(this, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove user change listener
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
_offUserChanged(listener: Function) {
|
||||||
|
this.log.info('Removing onUserChanged listener');
|
||||||
|
this.removeListener(this._getAppEventName('onUserChanged'), listener);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign the current user out
|
* Sign the current user out
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
|
|
|
@ -7,32 +7,17 @@ export default class User {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param authClass Instance of Authentication class
|
* @param authClass Instance of Authentication class
|
||||||
* @param authObj authentication result object from native
|
* @param user user result object from native
|
||||||
*/
|
*/
|
||||||
constructor(authClass, authObj) {
|
constructor(authClass, userObj) {
|
||||||
this._auth = authClass;
|
this._auth = authClass;
|
||||||
this._user = null;
|
this._user = userObj;
|
||||||
this._updateValues(authObj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNALS
|
* INTERNALS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param authObj
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_updateValues(authObj) {
|
|
||||||
this._authObj = authObj;
|
|
||||||
if (authObj.user) {
|
|
||||||
this._user = authObj.user;
|
|
||||||
} else {
|
|
||||||
this._user = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a user property or null if does not exist
|
* Returns a user property or null if does not exist
|
||||||
* @param prop
|
* @param prop
|
||||||
|
@ -40,7 +25,6 @@ export default class User {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_valueOrNull(prop) {
|
_valueOrNull(prop) {
|
||||||
if (!this._user) return null;
|
|
||||||
if (!Object.hasOwnProperty.call(this._user, prop)) return null;
|
if (!Object.hasOwnProperty.call(this._user, prop)) return null;
|
||||||
return this._user[prop];
|
return this._user[prop];
|
||||||
}
|
}
|
||||||
|
@ -52,7 +36,6 @@ export default class User {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_valueOrFalse(prop) {
|
_valueOrFalse(prop) {
|
||||||
if (!this._user) return false;
|
|
||||||
if (!Object.hasOwnProperty.call(this._user, prop)) return false;
|
if (!Object.hasOwnProperty.call(this._user, prop)) return false;
|
||||||
return this._user[prop];
|
return this._user[prop];
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ export default class Query {
|
||||||
*/
|
*/
|
||||||
orderBy(name: string, key?: string) {
|
orderBy(name: string, key?: string) {
|
||||||
this.modifiers.push({
|
this.modifiers.push({
|
||||||
|
id: `orderBy-${name}:${key}`,
|
||||||
type: 'orderBy',
|
type: 'orderBy',
|
||||||
name,
|
name,
|
||||||
key,
|
key,
|
||||||
|
@ -42,6 +43,7 @@ export default class Query {
|
||||||
*/
|
*/
|
||||||
limit(name: string, limit: number) {
|
limit(name: string, limit: number) {
|
||||||
this.modifiers.push({
|
this.modifiers.push({
|
||||||
|
id: `limit-${name}:${limit}`,
|
||||||
type: 'limit',
|
type: 'limit',
|
||||||
name,
|
name,
|
||||||
limit,
|
limit,
|
||||||
|
@ -59,6 +61,7 @@ export default class Query {
|
||||||
*/
|
*/
|
||||||
filter(name: string, value: any, key?: string) {
|
filter(name: string, value: any, key?: string) {
|
||||||
this.modifiers.push({
|
this.modifiers.push({
|
||||||
|
id: `filter-${name}:${objectToUniqueId(value)}:${key}`,
|
||||||
type: 'filter',
|
type: 'filter',
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
|
@ -82,14 +85,21 @@ export default class Query {
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
queryIdentifier() {
|
queryIdentifier() {
|
||||||
// convert query modifiers array into an object for generating a unique key
|
// sort modifiers to enforce ordering
|
||||||
const object = {};
|
const sortedModifiers = this.getModifiers().sort((a, b) => {
|
||||||
|
if (a.id < b.id) return -1;
|
||||||
|
if (a.id > b.id) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
for (let i = 0, len = this.modifiers.length; i < len; i++) {
|
// Convert modifiers to unique key
|
||||||
const { name, type, value } = this.modifiers[i];
|
let key = '{';
|
||||||
object[`${type}-${name}`] = value;
|
for (let i = 0; i < sortedModifiers.length; i++) {
|
||||||
|
if (i !== 0) key += ',';
|
||||||
|
key += sortedModifiers[i].id;
|
||||||
}
|
}
|
||||||
|
key += '}';
|
||||||
|
|
||||||
return objectToUniqueId(object);
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -736,14 +736,15 @@ export default class Reference extends ReferenceBase {
|
||||||
// remove the callback.
|
// remove the callback.
|
||||||
// Remove only a single registration
|
// Remove only a single registration
|
||||||
if (eventType && originalCallback) {
|
if (eventType && originalCallback) {
|
||||||
const registrations = this._syncTree.getRegistrationsByPathEvent(this.path, eventType);
|
const registration = this._syncTree.getOneByPathEventListener(this.path, eventType, originalCallback);
|
||||||
|
if (!registration) return [];
|
||||||
|
|
||||||
// remove the paired cancellation registration if any exist
|
// remove the paired cancellation registration if any exist
|
||||||
this._syncTree.removeListenersForRegistrations([`${registrations[0]}$cancelled`]);
|
this._syncTree.removeListenersForRegistrations([`${registration}$cancelled`]);
|
||||||
|
|
||||||
// remove only the first registration to match firebase web sdk
|
// remove only the first registration to match firebase web sdk
|
||||||
// call multiple times to remove multiple registrations
|
// call multiple times to remove multiple registrations
|
||||||
return this._syncTree.removeListenerRegistrations(originalCallback, [registrations[0]]);
|
return this._syncTree.removeListenerRegistrations(originalCallback, [registration]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Firebase Docs:
|
// Firebase Docs:
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
/**
|
/**
|
||||||
* @flow
|
* @flow
|
||||||
* Database representation wrapper
|
* Database Transaction representation wrapper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let transactionId = 0;
|
let transactionId = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Database
|
* @class TransactionHandler
|
||||||
*/
|
*/
|
||||||
export default class TransactionHandler {
|
export default class TransactionHandler {
|
||||||
constructor(database: Object) {
|
constructor(database: Object) {
|
||||||
|
|
|
@ -83,10 +83,6 @@ export default class CollectionReference {
|
||||||
return this._query.orderBy(fieldPath, directionStr);
|
return this._query.orderBy(fieldPath, directionStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
select(varArgs: string[]): Query {
|
|
||||||
return this._query.select(varArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
startAfter(fieldValues: any): Query {
|
startAfter(fieldValues: any): Query {
|
||||||
return this._query.startAfter(fieldValues);
|
return this._query.startAfter(fieldValues);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import DocumentSnapshot from './DocumentSnapshot';
|
import DocumentSnapshot from './DocumentSnapshot';
|
||||||
import Path from './Path';
|
import Path from './Path';
|
||||||
import QuerySnapshot from './QuerySnapshot';
|
import QuerySnapshot from './QuerySnapshot';
|
||||||
|
import { buildNativeArray, buildTypeMap } from './utils/serialize';
|
||||||
import { firestoreAutoId, isFunction, isObject } from '../../utils';
|
import { firestoreAutoId, isFunction, isObject } from '../../utils';
|
||||||
|
|
||||||
const DIRECTIONS = {
|
const DIRECTIONS = {
|
||||||
|
@ -77,24 +78,20 @@ export default class Query {
|
||||||
return this._firestore;
|
return this._firestore;
|
||||||
}
|
}
|
||||||
|
|
||||||
endAt(fieldValues: any): Query {
|
endAt(...snapshotOrVarArgs: any): Query {
|
||||||
fieldValues = [].slice.call(arguments);
|
|
||||||
// TODO: Validation
|
|
||||||
const options = {
|
const options = {
|
||||||
...this._queryOptions,
|
...this._queryOptions,
|
||||||
endAt: fieldValues,
|
endAt: this._buildOrderByOption(snapshotOrVarArgs),
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||||
this._fieldOrders, options);
|
this._fieldOrders, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
endBefore(fieldValues: any): Query {
|
endBefore(...snapshotOrVarArgs: any): Query {
|
||||||
fieldValues = [].slice.call(arguments);
|
|
||||||
// TODO: Validation
|
|
||||||
const options = {
|
const options = {
|
||||||
...this._queryOptions,
|
...this._queryOptions,
|
||||||
endBefore: fieldValues,
|
endBefore: this._buildOrderByOption(snapshotOrVarArgs),
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||||
|
@ -233,24 +230,20 @@ export default class Query {
|
||||||
combinedOrders, this._queryOptions);
|
combinedOrders, this._queryOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
startAfter(fieldValues: any): Query {
|
startAfter(...snapshotOrVarArgs: any): Query {
|
||||||
fieldValues = [].slice.call(arguments);
|
|
||||||
// TODO: Validation
|
|
||||||
const options = {
|
const options = {
|
||||||
...this._queryOptions,
|
...this._queryOptions,
|
||||||
startAfter: fieldValues,
|
startAfter: this._buildOrderByOption(snapshotOrVarArgs),
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||||
this._fieldOrders, options);
|
this._fieldOrders, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
startAt(fieldValues: any): Query {
|
startAt(...snapshotOrVarArgs: any): Query {
|
||||||
fieldValues = [].slice.call(arguments);
|
|
||||||
// TODO: Validation
|
|
||||||
const options = {
|
const options = {
|
||||||
...this._queryOptions,
|
...this._queryOptions,
|
||||||
startAt: fieldValues,
|
startAt: this._buildOrderByOption(snapshotOrVarArgs),
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||||
|
@ -261,10 +254,11 @@ export default class Query {
|
||||||
// TODO: Validation
|
// TODO: Validation
|
||||||
// validate.isFieldPath('fieldPath', fieldPath);
|
// validate.isFieldPath('fieldPath', fieldPath);
|
||||||
// validate.isFieldFilter('fieldFilter', opStr, value);
|
// validate.isFieldFilter('fieldFilter', opStr, value);
|
||||||
|
const nativeValue = buildTypeMap(value);
|
||||||
const newFilter = {
|
const newFilter = {
|
||||||
fieldPath,
|
fieldPath,
|
||||||
operator: OPERATORS[opStr],
|
operator: OPERATORS[opStr],
|
||||||
value,
|
value: nativeValue,
|
||||||
};
|
};
|
||||||
const combinedFilters = this._fieldFilters.concat(newFilter);
|
const combinedFilters = this._fieldFilters.concat(newFilter);
|
||||||
return new Query(this.firestore, this._referencePath, combinedFilters,
|
return new Query(this.firestore, this._referencePath, combinedFilters,
|
||||||
|
@ -275,6 +269,23 @@ export default class Query {
|
||||||
* INTERNALS
|
* INTERNALS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
_buildOrderByOption(snapshotOrVarArgs: any[]) {
|
||||||
|
// TODO: Validation
|
||||||
|
let values;
|
||||||
|
if (snapshotOrVarArgs.length === 1 && snapshotOrVarArgs[0] instanceof DocumentSnapshot) {
|
||||||
|
const docSnapshot = snapshotOrVarArgs[0];
|
||||||
|
values = [];
|
||||||
|
for (let i = 0; i < this._fieldOrders.length; i++) {
|
||||||
|
const fieldOrder = this._fieldOrders[i];
|
||||||
|
values.push(docSnapshot.get(fieldOrder.fieldPath));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
values = snapshotOrVarArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildNativeArray(values);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove query snapshot listener
|
* Remove query snapshot listener
|
||||||
* @param listener
|
* @param listener
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const buildNativeMap = (data: Object): Object => {
|
||||||
return nativeData;
|
return nativeData;
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildNativeArray = (array: Object[]): any[] => {
|
export const buildNativeArray = (array: Object[]): any[] => {
|
||||||
const nativeArray = [];
|
const nativeArray = [];
|
||||||
if (array) {
|
if (array) {
|
||||||
array.forEach((value) => {
|
array.forEach((value) => {
|
||||||
|
@ -37,7 +37,7 @@ const buildNativeArray = (array: Object[]): any[] => {
|
||||||
return nativeArray;
|
return nativeArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildTypeMap = (value: any): any => {
|
export const buildTypeMap = (value: any): any => {
|
||||||
const typeMap = {};
|
const typeMap = {};
|
||||||
const type = typeOf(value);
|
const type = typeOf(value);
|
||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
|
@ -67,7 +67,7 @@ const buildTypeMap = (value: any): any => {
|
||||||
};
|
};
|
||||||
} else if (value instanceof Date) {
|
} else if (value instanceof Date) {
|
||||||
typeMap.type = 'date';
|
typeMap.type = 'date';
|
||||||
typeMap.value = value.toISOString();
|
typeMap.value = value.getTime();
|
||||||
} else {
|
} else {
|
||||||
typeMap.type = 'object';
|
typeMap.type = 'object';
|
||||||
typeMap.value = buildNativeMap(value);
|
typeMap.value = buildNativeMap(value);
|
||||||
|
|
|
@ -11,6 +11,7 @@ type Registration = {
|
||||||
once?: Boolean,
|
once?: Boolean,
|
||||||
appName: String,
|
appName: String,
|
||||||
eventType: String,
|
eventType: String,
|
||||||
|
listener: Function,
|
||||||
eventRegistrationKey: String,
|
eventRegistrationKey: String,
|
||||||
ref: DatabaseReference,
|
ref: DatabaseReference,
|
||||||
}
|
}
|
||||||
|
@ -197,6 +198,28 @@ export default class SyncTree {
|
||||||
return Object.keys(this._tree[path][eventType]);
|
return Object.keys(this._tree[path][eventType]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a single registration key for the specified path, eventType, and listener
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @param eventType
|
||||||
|
* @param listener
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
getOneByPathEventListener(path: string, eventType: string, listener: Function): Array {
|
||||||
|
if (!this._tree[path]) return [];
|
||||||
|
if (!this._tree[path][eventType]) return [];
|
||||||
|
|
||||||
|
const registrationsForPathEvent = Object.entries(this._tree[path][eventType]);
|
||||||
|
|
||||||
|
for (let i = 0; i < registrationsForPathEvent.length; i++) {
|
||||||
|
const registration = registrationsForPathEvent[i];
|
||||||
|
if (registration[1] === listener) return registration[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new listener.
|
* Register a new listener.
|
||||||
|
@ -211,8 +234,8 @@ export default class SyncTree {
|
||||||
if (!this._tree[path]) this._tree[path] = {};
|
if (!this._tree[path]) this._tree[path] = {};
|
||||||
if (!this._tree[path][eventType]) this._tree[path][eventType] = {};
|
if (!this._tree[path][eventType]) this._tree[path][eventType] = {};
|
||||||
|
|
||||||
this._tree[path][eventType][eventRegistrationKey] = 0;
|
this._tree[path][eventType][eventRegistrationKey] = listener;
|
||||||
this._reverseLookup[eventRegistrationKey] = Object.assign({}, parameters);
|
this._reverseLookup[eventRegistrationKey] = Object.assign({ listener }, parameters);
|
||||||
|
|
||||||
if (once) {
|
if (once) {
|
||||||
INTERNALS.SharedEventEmitter.once(
|
INTERNALS.SharedEventEmitter.once(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "react-native-firebase",
|
"name": "react-native-firebase",
|
||||||
"version": "3.0.4",
|
"version": "3.0.6",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
"tests-npm-install": "cd tests && npm install",
|
"tests-npm-install": "cd tests && npm install",
|
||||||
"tests-pod-install": "cd tests && npm run ios:pod:install",
|
"tests-pod-install": "cd tests && npm run ios:pod:install",
|
||||||
"tests-watch-start": "npm run test-cli watch init start",
|
"tests-watch-start": "npm run test-cli watch init start",
|
||||||
"tests-watch-stop": "npm run test-cli watch stop"
|
"tests-watch-stop": "npm run test-cli watch stop",
|
||||||
|
"postinstall": "opencollective postinstall"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -88,6 +89,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bows": "^1.6.0",
|
"bows": "^1.6.0",
|
||||||
|
"opencollective": "^1.0.3",
|
||||||
"prop-types": "^15.6.0"
|
"prop-types": "^15.6.0"
|
||||||
},
|
},
|
||||||
"rnpm": {
|
"rnpm": {
|
||||||
|
@ -99,5 +101,10 @@
|
||||||
"commands": {
|
"commands": {
|
||||||
"postlink": "node node_modules/react-native-firebase/scripts/rnpm-postlink"
|
"postlink": "node node_modules/react-native-firebase/scripts/rnpm-postlink"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"collective": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/react-native-firebase",
|
||||||
|
"logo": "https://opencollective.com/opencollective/logo.txt"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -150,7 +150,7 @@ PODS:
|
||||||
- React/Core
|
- React/Core
|
||||||
- React/fishhook
|
- React/fishhook
|
||||||
- React/RCTBlob
|
- React/RCTBlob
|
||||||
- RNFirebase (3.1.0-alpha.1):
|
- RNFirebase (3.0.5):
|
||||||
- React
|
- React
|
||||||
- yoga (0.49.1.React)
|
- yoga (0.49.1.React)
|
||||||
|
|
||||||
|
@ -176,11 +176,11 @@ DEPENDENCIES:
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
React:
|
React:
|
||||||
:path: ../node_modules/react-native
|
:path: "../node_modules/react-native"
|
||||||
RNFirebase:
|
RNFirebase:
|
||||||
:path: ./../../
|
:path: "./../../"
|
||||||
yoga:
|
yoga:
|
||||||
:path: ../node_modules/react-native/ReactCommon/yoga
|
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
BoringSSL: 19083b821ef3ae0f758fae15482e183003b1e265
|
BoringSSL: 19083b821ef3ae0f758fae15482e183003b1e265
|
||||||
|
@ -199,7 +199,7 @@ SPEC CHECKSUMS:
|
||||||
FirebaseStorage: 0cca42d9b889a0227c3a50121f45a4469fc9eb27
|
FirebaseStorage: 0cca42d9b889a0227c3a50121f45a4469fc9eb27
|
||||||
Google-Mobile-Ads-SDK: ed8004a7265b424568dc84f3d2bbe3ea3fff958f
|
Google-Mobile-Ads-SDK: ed8004a7265b424568dc84f3d2bbe3ea3fff958f
|
||||||
GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0
|
GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0
|
||||||
gRPC: 07788969b862af21491908f82b83d17ac08c94cd
|
gRPC: '07788969b862af21491908f82b83d17ac08c94cd'
|
||||||
gRPC-Core: f707ade59c559fe718e27713189607d03b15f571
|
gRPC-Core: f707ade59c559fe718e27713189607d03b15f571
|
||||||
gRPC-ProtoRPC: de7505e493a9d1b6b96c8ea8f976c73100fdf53f
|
gRPC-ProtoRPC: de7505e493a9d1b6b96c8ea8f976c73100fdf53f
|
||||||
gRPC-RxLibrary: 17b9699beb0a838b95b57832244f9ead18e66777
|
gRPC-RxLibrary: 17b9699beb0a838b95b57832244f9ead18e66777
|
||||||
|
@ -208,9 +208,9 @@ SPEC CHECKSUMS:
|
||||||
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
|
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
|
||||||
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
|
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
|
||||||
React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee
|
React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee
|
||||||
RNFirebase: 0467ca8122b9257acd7f1bb6de1670d9fd51cede
|
RNFirebase: 7c86b4efd2860700048d927f34db237fbce1d5fc
|
||||||
yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a
|
yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a
|
||||||
|
|
||||||
PODFILE CHECKSUM: b5674be55653f5dda937c8b794d0479900643d45
|
PODFILE CHECKSUM: b5674be55653f5dda937c8b794d0479900643d45
|
||||||
|
|
||||||
COCOAPODS: 1.3.1
|
COCOAPODS: 1.2.1
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { View, SectionList, Text, Button } from 'react-native';
|
|
||||||
|
|
||||||
export default class HomeScreen extends Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
bgColor: '#cb2600',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
clickMe = () => {
|
|
||||||
if (this.state.bgColor === '#a8139f') {
|
|
||||||
this.setState({ bgColor: '#cb2600' });
|
|
||||||
} else {
|
|
||||||
this.setState({ bgColor: '#a8139f' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<View style={{ backgroundColor: this.state.bgColor }}>
|
|
||||||
<Text style={{ color: '#fff' }}>Hello</Text>
|
|
||||||
<Text style={{ color: '#22ff31' }}>World</Text>
|
|
||||||
<Button title="Change to pink" onPress={this.clickMe} />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sampleData = {
|
|
||||||
somePostId1: {
|
|
||||||
title: 'today now',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
startOfDay: 1502838000,
|
|
||||||
},
|
|
||||||
|
|
||||||
somePostId3: {
|
|
||||||
title: 'today but older',
|
|
||||||
timestamp: Date.now() - 10000000,
|
|
||||||
startOfDay: 1502838000,
|
|
||||||
},
|
|
||||||
|
|
||||||
somePostId4: {
|
|
||||||
title: 'today but even older',
|
|
||||||
timestamp: Date.now() - 60000000,
|
|
||||||
startOfDay: 1502838000,
|
|
||||||
},
|
|
||||||
|
|
||||||
somePostId2: {
|
|
||||||
title: 'hello yesterday',
|
|
||||||
timestamp: Date.now() - 82000000, // minus 23 hours - just to make it yesterday ;p
|
|
||||||
startOfDay: 1502751600, // yesterday ;p
|
|
||||||
},
|
|
||||||
|
|
||||||
somePostId5: {
|
|
||||||
title: 'hello yesterday but older',
|
|
||||||
timestamp: Date.now() - 82800000, // minus 23 hours - just to make it yesterday ;p
|
|
||||||
startOfDay: 1502751600, // yesterday ;p
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// export default class PostsScreen extends Component {
|
|
||||||
// constructor(props) {
|
|
||||||
// super(props);
|
|
||||||
// this.ref = null;
|
|
||||||
// this.state = {
|
|
||||||
// postSections: [],
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// componentDidMount() {
|
|
||||||
// // this.ref = firebase.database().ref('posts');
|
|
||||||
// // this.ref.on('value', this._onPostsUpdate);
|
|
||||||
// // just fake it to test
|
|
||||||
// this._onPostsUpdate({
|
|
||||||
// val() {
|
|
||||||
// return sampleData;
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// componentWillUnmount() {
|
|
||||||
// // always unsubscribe from realtime events when component unmounts
|
|
||||||
// // if (this.ref) {
|
|
||||||
// // this.ref.off('value', this._onPostsUpdate);
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// _onPostsUpdate(snapshot) {
|
|
||||||
// const value = snapshot.val() || {};
|
|
||||||
// const keys = Object.keys(value);
|
|
||||||
// const sections = {};
|
|
||||||
//
|
|
||||||
// // we'll group them now by date
|
|
||||||
// for (let i = 0, len = keys.length; i < len; i++) {
|
|
||||||
// const key = keys[i];
|
|
||||||
// const post = value[key];
|
|
||||||
//
|
|
||||||
// // assuming post will have a 'timestamp' field and a `startOfDay` field
|
|
||||||
// // start of day can be calculated as above `startOfToday`
|
|
||||||
//
|
|
||||||
// if (!sections[post.startOfDay]) {
|
|
||||||
// sections[post.startOfDay] = {
|
|
||||||
// title: 'Header - I will leave this up to you', // todo today/yesterday/3 days ago etc
|
|
||||||
// // will use this later to sort the sections so today is on top
|
|
||||||
// key: post.startOfDay,
|
|
||||||
// data: [],
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// const data = Object.assign({ key }, post);
|
|
||||||
// // add a post to a specific section date
|
|
||||||
// // we'll push/unshift depending on the date, so they' appear in order
|
|
||||||
// if (!sections[post.startOfDay].data.length) {
|
|
||||||
// // array is empty so nothing to compare sort, just push it
|
|
||||||
// sections[post.startOfDay].data.push(data);
|
|
||||||
// } else {
|
|
||||||
// const previousTimestamp = sections[post.startOfDay].data[sections[post.startOfDay].data.length - 1].timestamp;
|
|
||||||
// if (previousTimestamp < data.timestamp) sections[post.startOfDay].data.unshift(data);
|
|
||||||
// else sections[post.startOfDay].data.push(data);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// this.setState({
|
|
||||||
// postSections: Object.values(sections).sort((a, b) => a.key > b.key).reverse(),
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// _renderSectionItem = ({ item }) => {
|
|
||||||
// // todo your custom section item component
|
|
||||||
// // return (
|
|
||||||
// // <EventCell
|
|
||||||
// // userName={item.userName}
|
|
||||||
// // postTitle={item.postTitle}
|
|
||||||
// // />
|
|
||||||
// // );
|
|
||||||
//
|
|
||||||
// return <Text>{`${item.title} - ${item.timestamp}`}</Text>;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// _renderSectionHeader = ({ section }) => {
|
|
||||||
// // todo your custom section header
|
|
||||||
// return (
|
|
||||||
// <Text style={{ backgroundColor: '#000', color: '#fff' }}>{section.title}</Text>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// render() {
|
|
||||||
// return (
|
|
||||||
// <SectionList
|
|
||||||
// sections={this.state.postSections}
|
|
||||||
// renderItem={this._renderSectionItem}
|
|
||||||
// renderSectionHeader={this._renderSectionHeader}
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -1,4 +1,6 @@
|
||||||
import should from 'should';
|
import should from 'should';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import 'should-sinon';
|
||||||
import DatabaseContents from '../../support/DatabaseContents';
|
import DatabaseContents from '../../support/DatabaseContents';
|
||||||
|
|
||||||
function issueTests({ describe, it, context, firebase }) {
|
function issueTests({ describe, it, context, firebase }) {
|
||||||
|
@ -81,6 +83,212 @@ function issueTests({ describe, it, context, firebase }) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('issue_489', () => {
|
||||||
|
context('long numbers should', () => {
|
||||||
|
it('return as longs', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const long1Ref = firebase.native.database().ref('tests/issues/489/long1');
|
||||||
|
const long2Ref = firebase.native.database().ref('tests/issues/489/long2');
|
||||||
|
const long2 = 1234567890123456;
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
let snapshot = await long1Ref.once('value');
|
||||||
|
snapshot.val().should.eql(DatabaseContents.ISSUES[489].long1);
|
||||||
|
|
||||||
|
|
||||||
|
await long2Ref.set(long2);
|
||||||
|
snapshot = await long2Ref.once('value');
|
||||||
|
snapshot.val().should.eql(long2);
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('issue_521', () => {
|
||||||
|
context('orderByChild (numerical field) and limitToLast', () => {
|
||||||
|
it('once() returns correct results', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/issues/521');
|
||||||
|
// Test
|
||||||
|
|
||||||
|
return ref
|
||||||
|
.orderByChild('number')
|
||||||
|
.limitToLast(1)
|
||||||
|
.once('value')
|
||||||
|
.then((snapshot) => {
|
||||||
|
const val = snapshot.val();
|
||||||
|
// Assertion
|
||||||
|
val.key3.should.eql(DatabaseContents.ISSUES[521].key3);
|
||||||
|
should.equal(Object.keys(val).length, 1);
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('on() returns correct initial results', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/issues/521').orderByChild('number').limitToLast(2);
|
||||||
|
const callback = sinon.spy();
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
ref.on('value', (snapshot) => {
|
||||||
|
callback(snapshot.val());
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
callback.should.be.calledWith({
|
||||||
|
key2: DatabaseContents.ISSUES[521].key2,
|
||||||
|
key3: DatabaseContents.ISSUES[521].key3,
|
||||||
|
});
|
||||||
|
callback.should.be.calledOnce();
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('on() returns correct subsequent results', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/issues/521').orderByChild('number').limitToLast(2);
|
||||||
|
const callback = sinon.spy();
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
ref.on('value', (snapshot) => {
|
||||||
|
callback(snapshot.val());
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
callback.should.be.calledWith({
|
||||||
|
key2: DatabaseContents.ISSUES[521].key2,
|
||||||
|
key3: DatabaseContents.ISSUES[521].key3,
|
||||||
|
});
|
||||||
|
callback.should.be.calledOnce();
|
||||||
|
|
||||||
|
const newDataValue = {
|
||||||
|
name: 'Item 4',
|
||||||
|
number: 4,
|
||||||
|
string: 'item4',
|
||||||
|
};
|
||||||
|
const newRef = firebase.native.database().ref('tests/issues/521/key4');
|
||||||
|
await newRef.set(newDataValue);
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => resolve(), 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assertions
|
||||||
|
|
||||||
|
callback.should.be.calledWith({
|
||||||
|
key3: DatabaseContents.ISSUES[521].key3,
|
||||||
|
key4: newDataValue,
|
||||||
|
});
|
||||||
|
callback.should.be.calledTwice();
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('orderByChild (string field) and limitToLast', () => {
|
||||||
|
it('once() returns correct results', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/issues/521');
|
||||||
|
// Test
|
||||||
|
|
||||||
|
return ref
|
||||||
|
.orderByChild('string')
|
||||||
|
.limitToLast(1)
|
||||||
|
.once('value')
|
||||||
|
.then((snapshot) => {
|
||||||
|
const val = snapshot.val();
|
||||||
|
// Assertion
|
||||||
|
val.key3.should.eql(DatabaseContents.ISSUES[521].key3);
|
||||||
|
should.equal(Object.keys(val).length, 1);
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('on() returns correct initial results', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/issues/521').orderByChild('string').limitToLast(2);
|
||||||
|
const callback = sinon.spy();
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
ref.on('value', (snapshot) => {
|
||||||
|
callback(snapshot.val());
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
callback.should.be.calledWith({
|
||||||
|
key2: DatabaseContents.ISSUES[521].key2,
|
||||||
|
key3: DatabaseContents.ISSUES[521].key3,
|
||||||
|
});
|
||||||
|
callback.should.be.calledOnce();
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('on() returns correct subsequent results', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/issues/521').orderByChild('string').limitToLast(2);
|
||||||
|
const callback = sinon.spy();
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
ref.on('value', (snapshot) => {
|
||||||
|
callback(snapshot.val());
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
callback.should.be.calledWith({
|
||||||
|
key2: DatabaseContents.ISSUES[521].key2,
|
||||||
|
key3: DatabaseContents.ISSUES[521].key3,
|
||||||
|
});
|
||||||
|
callback.should.be.calledOnce();
|
||||||
|
|
||||||
|
const newDataValue = {
|
||||||
|
name: 'Item 4',
|
||||||
|
number: 4,
|
||||||
|
string: 'item4',
|
||||||
|
};
|
||||||
|
const newRef = firebase.native.database().ref('tests/issues/521/key4');
|
||||||
|
await newRef.set(newDataValue);
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => resolve(), 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assertions
|
||||||
|
|
||||||
|
callback.should.be.calledWith({
|
||||||
|
key3: DatabaseContents.ISSUES[521].key3,
|
||||||
|
key4: newDataValue,
|
||||||
|
});
|
||||||
|
callback.should.be.calledTwice();
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default issueTests;
|
export default issueTests;
|
||||||
|
|
|
@ -297,6 +297,167 @@ function offTests({ describe, it, xcontext, context, firebase }) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
context('when 2 different child_added callbacks on the same path', () => {
|
||||||
|
context('that has been added and removed in the same order', () => {
|
||||||
|
it('must be completely removed', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const spyA = sinon.spy();
|
||||||
|
let callbackA;
|
||||||
|
|
||||||
|
const spyB = sinon.spy();
|
||||||
|
let callbackB;
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/types/array');
|
||||||
|
const arrayLength = DatabaseContents.DEFAULT.array.length;
|
||||||
|
// Attach callbackA
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
callbackA = () => {
|
||||||
|
spyA();
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
ref.on('child_added', callbackA);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach callbackB
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
callbackB = () => {
|
||||||
|
spyB();
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
ref.on('child_added', callbackB);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a delay to ensure that the .on() has had time to be registered
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 15);
|
||||||
|
});
|
||||||
|
|
||||||
|
spyA.should.have.callCount(arrayLength);
|
||||||
|
spyB.should.have.callCount(arrayLength);
|
||||||
|
|
||||||
|
// Undo the first callback
|
||||||
|
const resp = await ref.off('child_added', callbackA);
|
||||||
|
should(resp, undefined);
|
||||||
|
|
||||||
|
// Trigger the event the callback is listening to
|
||||||
|
await ref.push(DatabaseContents.DEFAULT.number);
|
||||||
|
|
||||||
|
// Add a delay to ensure that the .set() has had time to be registered
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 15);
|
||||||
|
});
|
||||||
|
|
||||||
|
// CallbackA should have been called zero more times its attachment
|
||||||
|
// has been removed, and callBackB only one more time becuase it's still attached
|
||||||
|
spyA.should.have.callCount(arrayLength);
|
||||||
|
spyB.should.have.callCount(arrayLength + 1);
|
||||||
|
|
||||||
|
// Undo the second attachment
|
||||||
|
const resp2 = await ref.off('child_added', callbackB);
|
||||||
|
should(resp2, undefined);
|
||||||
|
|
||||||
|
// Trigger the event the callback is listening to
|
||||||
|
await ref.push(DatabaseContents.DEFAULT.number);
|
||||||
|
|
||||||
|
// Add a delay to ensure that the .set() has had time to be registered
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 15);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Both Callbacks should not have been called any more times
|
||||||
|
spyA.should.have.callCount(arrayLength);
|
||||||
|
spyB.should.have.callCount(arrayLength + 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ******This test is failed*******
|
||||||
|
context('that has been added and removed in reverse order', () => {
|
||||||
|
it('must be completely removed', async () => {
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
const spyA = sinon.spy();
|
||||||
|
let callbackA;
|
||||||
|
|
||||||
|
const spyB = sinon.spy();
|
||||||
|
let callbackB;
|
||||||
|
|
||||||
|
const ref = firebase.native.database().ref('tests/types/array');
|
||||||
|
const arrayLength = DatabaseContents.DEFAULT.array.length;
|
||||||
|
// Attach callbackA
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
callbackA = () => {
|
||||||
|
spyA();
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
ref.on('child_added', callbackA);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach callbackB
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
callbackB = () => {
|
||||||
|
spyB();
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
ref.on('child_added', callbackB);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a delay to ensure that the .on() has had time to be registered
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 15);
|
||||||
|
});
|
||||||
|
|
||||||
|
spyA.should.have.callCount(arrayLength);
|
||||||
|
spyB.should.have.callCount(arrayLength);
|
||||||
|
|
||||||
|
// Undo the second callback
|
||||||
|
const resp = await ref.off('child_added', callbackB);
|
||||||
|
should(resp, undefined);
|
||||||
|
|
||||||
|
// Trigger the event the callback is listening to
|
||||||
|
await ref.push(DatabaseContents.DEFAULT.number);
|
||||||
|
|
||||||
|
// Add a delay to ensure that the .set() has had time to be registered
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 15);
|
||||||
|
});
|
||||||
|
|
||||||
|
// CallbackB should have been called zero more times its attachment
|
||||||
|
// has been removed, and callBackA only one more time becuase it's still attached
|
||||||
|
spyA.should.have.callCount(arrayLength + 1);
|
||||||
|
spyB.should.have.callCount(arrayLength);
|
||||||
|
|
||||||
|
// Undo the second attachment
|
||||||
|
const resp2 = await ref.off('child_added', callbackA);
|
||||||
|
should(resp2, undefined);
|
||||||
|
|
||||||
|
// Trigger the event the callback is listening to
|
||||||
|
await ref.push(DatabaseContents.DEFAULT.number);
|
||||||
|
|
||||||
|
// Add a delay to ensure that the .set() has had time to be registered
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 15);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Both Callbacks should not have been called any more times
|
||||||
|
spyA.should.have.callCount(arrayLength + 1);
|
||||||
|
spyB.should.have.callCount(arrayLength);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
xcontext('when a context', () => {
|
xcontext('when a context', () => {
|
||||||
/**
|
/**
|
||||||
* @todo Add tests for when a context is passed. Not sure what the intended
|
* @todo Add tests for when a context is passed. Not sure what the intended
|
||||||
|
|
|
@ -2,9 +2,9 @@ import sinon from 'sinon';
|
||||||
import 'should-sinon';
|
import 'should-sinon';
|
||||||
import should from 'should';
|
import should from 'should';
|
||||||
|
|
||||||
import { COL_1 } from './index';
|
import { COL_1, cleanCollection } from './index';
|
||||||
|
|
||||||
function collectionReferenceTests({ describe, it, context, firebase }) {
|
function collectionReferenceTests({ describe, it, context, firebase, before, after }) {
|
||||||
describe('CollectionReference', () => {
|
describe('CollectionReference', () => {
|
||||||
context('class', () => {
|
context('class', () => {
|
||||||
it('should return instance methods', () => {
|
it('should return instance methods', () => {
|
||||||
|
@ -445,6 +445,26 @@ function collectionReferenceTests({ describe, it, context, firebase }) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('correctly handles == date values', () => {
|
||||||
|
return firebase.native.firestore()
|
||||||
|
.collection('collection-tests')
|
||||||
|
.where('timestamp', '==', COL_1.timestamp)
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly handles == geopoint values', () => {
|
||||||
|
return firebase.native.firestore()
|
||||||
|
.collection('collection-tests')
|
||||||
|
.where('geopoint', '==', COL_1.geopoint)
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('correctly handles >= number values', () => {
|
it('correctly handles >= number values', () => {
|
||||||
return firebase.native.firestore()
|
return firebase.native.firestore()
|
||||||
.collection('collection-tests')
|
.collection('collection-tests')
|
||||||
|
@ -458,6 +478,16 @@ function collectionReferenceTests({ describe, it, context, firebase }) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('correctly handles >= geopoint values', () => {
|
||||||
|
return firebase.native.firestore()
|
||||||
|
.collection('collection-tests')
|
||||||
|
.where('geopoint', '>=', new firebase.native.firestore.GeoPoint(-1, -1))
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('correctly handles <= float values', () => {
|
it('correctly handles <= float values', () => {
|
||||||
return firebase.native.firestore()
|
return firebase.native.firestore()
|
||||||
.collection('collection-tests')
|
.collection('collection-tests')
|
||||||
|
@ -470,6 +500,246 @@ function collectionReferenceTests({ describe, it, context, firebase }) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('correctly handles limit', async () => {
|
||||||
|
const collectionTests = firebase.native.firestore().collection('collection-tests2');
|
||||||
|
await Promise.all([
|
||||||
|
collectionTests.doc('col1').set(COL_1),
|
||||||
|
collectionTests.doc('col2').set({ ...COL_1, daz: 234 }),
|
||||||
|
collectionTests.doc('col3').set({ ...COL_1, daz: 234 }),
|
||||||
|
collectionTests.doc('col4').set({ ...COL_1, daz: 234 }),
|
||||||
|
collectionTests.doc('col5').set({ ...COL_1, daz: 234 }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return collectionTests.limit(3)
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
return cleanCollection(collectionTests);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('cursors', () => {
|
||||||
|
let collectionTests;
|
||||||
|
before(async () => {
|
||||||
|
collectionTests = firebase.native.firestore().collection('collection-tests2');
|
||||||
|
await Promise.all([
|
||||||
|
collectionTests.doc('col1').set({ ...COL_1, foo: 'bar0' }),
|
||||||
|
collectionTests.doc('col2').set({ ...COL_1, foo: 'bar1', daz: 234, timestamp: new Date(2017, 2, 11, 10, 0, 0) }),
|
||||||
|
collectionTests.doc('col3').set({ ...COL_1, foo: 'bar2', daz: 345, timestamp: new Date(2017, 2, 12, 10, 0, 0) }),
|
||||||
|
collectionTests.doc('col4').set({ ...COL_1, foo: 'bar3', daz: 456, timestamp: new Date(2017, 2, 13, 10, 0, 0) }),
|
||||||
|
collectionTests.doc('col5').set({ ...COL_1, foo: 'bar4', daz: 567, timestamp: new Date(2017, 2, 14, 10, 0, 0) }),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
context('endAt', () => {
|
||||||
|
it('handles dates', () => {
|
||||||
|
return collectionTests.orderBy('timestamp').endAt(new Date(2017, 2, 12, 10, 0, 0))
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234, 345],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles numbers', () => {
|
||||||
|
return collectionTests.orderBy('daz').endAt(345)
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234, 345],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles strings', () => {
|
||||||
|
return collectionTests.orderBy('foo').endAt('bar2')
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234, 345],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles snapshots', async () => {
|
||||||
|
const collectionSnapshot = await collectionTests.orderBy('foo').get();
|
||||||
|
return collectionTests.orderBy('foo').endAt(collectionSnapshot.docs[2])
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234, 345],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('endBefore', () => {
|
||||||
|
it('handles dates', () => {
|
||||||
|
return collectionTests.orderBy('timestamp').endBefore(new Date(2017, 2, 12, 10, 0, 0))
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles numbers', () => {
|
||||||
|
return collectionTests.orderBy('daz').endBefore(345)
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles strings', () => {
|
||||||
|
return collectionTests.orderBy('foo').endBefore('bar2')
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles snapshots', async () => {
|
||||||
|
const collectionSnapshot = await collectionTests.orderBy('foo').get();
|
||||||
|
return collectionTests.orderBy('foo').endBefore(collectionSnapshot.docs[2])
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[123, 234],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('startAt', () => {
|
||||||
|
it('handles dates', () => {
|
||||||
|
return collectionTests.orderBy('timestamp').startAt(new Date(2017, 2, 12, 10, 0, 0))
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[345, 456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles numbers', () => {
|
||||||
|
return collectionTests.orderBy('daz').startAt(345)
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[345, 456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles strings', () => {
|
||||||
|
return collectionTests.orderBy('foo').startAt('bar2')
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[345, 456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles snapshots', async () => {
|
||||||
|
const collectionSnapshot = await collectionTests.orderBy('foo').get();
|
||||||
|
return collectionTests.orderBy('foo').startAt(collectionSnapshot.docs[2])
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 3);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[345, 456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('startAfter', () => {
|
||||||
|
it('handles dates', () => {
|
||||||
|
return collectionTests.orderBy('timestamp').startAfter(new Date(2017, 2, 12, 10, 0, 0))
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles numbers', () => {
|
||||||
|
return collectionTests.orderBy('daz').startAfter(345)
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles strings', () => {
|
||||||
|
return collectionTests.orderBy('foo').startAfter('bar2')
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles snapshot', async () => {
|
||||||
|
const collectionSnapshot = await collectionTests.orderBy('foo').get();
|
||||||
|
return collectionTests.orderBy('foo').startAfter(collectionSnapshot.docs[2])
|
||||||
|
.get()
|
||||||
|
.then((querySnapshot) => {
|
||||||
|
should.equal(querySnapshot.size, 2);
|
||||||
|
should.deepEqual(
|
||||||
|
querySnapshot.docs.map(doc => doc.data().daz),
|
||||||
|
[456, 567],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
return cleanCollection(collectionTests);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,6 +435,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
||||||
const doc = await docRef.get();
|
const doc = await docRef.get();
|
||||||
doc.data().field.should.be.instanceof(Date);
|
doc.data().field.should.be.instanceof(Date);
|
||||||
should.equal(doc.data().field.toISOString(), date.toISOString());
|
should.equal(doc.data().field.toISOString(), date.toISOString());
|
||||||
|
should.equal(doc.data().field.getTime(), date.getTime());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,9 @@ export const COL_1 = {
|
||||||
daz: 123,
|
daz: 123,
|
||||||
foo: 'bar',
|
foo: 'bar',
|
||||||
gaz: 12.1234567,
|
gaz: 12.1234567,
|
||||||
|
geopoint: new firebase.native.firestore.GeoPoint(0, 0),
|
||||||
naz: null,
|
naz: null,
|
||||||
|
timestamp: new Date(2017, 2, 10, 10, 0, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DOC_1 = { name: 'doc1' };
|
export const DOC_1 = { name: 'doc1' };
|
||||||
|
@ -65,7 +67,7 @@ suite.addTests(firestoreTestSuite);
|
||||||
export default suite;
|
export default suite;
|
||||||
|
|
||||||
/* HELPER FUNCTIONS */
|
/* HELPER FUNCTIONS */
|
||||||
async function cleanCollection(collection) {
|
export async function cleanCollection(collection) {
|
||||||
const collectionTestsDocs = await collection.get();
|
const collectionTestsDocs = await collection.get();
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
collectionTestsDocs.forEach(doc => tasks.push(doc.ref.delete()));
|
collectionTestsDocs.forEach(doc => tasks.push(doc.ref.delete()));
|
||||||
|
|
|
@ -91,5 +91,28 @@ export default {
|
||||||
uid: 'aNYxLexOb2WsXGOPiEAu47q5bxH3',
|
uid: 'aNYxLexOb2WsXGOPiEAu47q5bxH3',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
489: {
|
||||||
|
long1: 1508777379000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://github.com/invertase/react-native-firebase/issues/521
|
||||||
|
521: {
|
||||||
|
key1: {
|
||||||
|
name: 'Item 1',
|
||||||
|
number: 1,
|
||||||
|
string: 'item1',
|
||||||
|
},
|
||||||
|
key3: {
|
||||||
|
name: 'Item 3',
|
||||||
|
number: 3,
|
||||||
|
string: 'item3',
|
||||||
|
},
|
||||||
|
key2: {
|
||||||
|
name: 'Item 2',
|
||||||
|
number: 2,
|
||||||
|
string: 'item2',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue