Skip to content

Support for joins #276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 87 commits into from
Nov 1, 2016
Merged

Support for joins #276

merged 87 commits into from
Nov 1, 2016

Conversation

SUPERCILEX
Copy link
Collaborator

@SUPERCILEX SUPERCILEX commented Sep 1, 2016

TODO:

  • tests

@giautm
Copy link

giautm commented Sep 4, 2016

I'm waiting for this deloy. 👍

@SUPERCILEX SUPERCILEX mentioned this pull request Sep 6, 2016
@puf
Copy link
Contributor

puf commented Sep 7, 2016

Hey Alex. Thanks for the PR. Looks great, definitely a very clean implementation of attaching and detaching the listeners. I also like that it uses the data model from the Firebase documentation as its basis.

I don't think we should add this code to the basic FirebaseXxxAdapters though. Scanning your code structure I see many if (condition) oldBehavior() else newBehavior(), which would be cleaner to catch in a subclass. That would also keep the current classes as simple as we intentionally kept them and allows us to later add support for other join structures without breaking backwards compatibility of the basic adapters.

Can you see if you can isolate the behavior in separate sub-adapters?

public DataSnapshot getItem(int index) {
return mSnapshots.get(index);
}

protected DataSnapshot internalGetItem(int index) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is completely gross IMO, but I don't know how to get rid of it. Any feedback is welcome!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I'll brood on a better way to do this.

Copy link

@giautm giautm Sep 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a bug here. When you remove the last element of the list, remove trigger events before and list have no element. So it would make an exception:

    java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
    at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
    at java.util.ArrayList.get(ArrayList.java:308)
    at com.firebase.ui.database.FirebaseArray.internalGetItem(FirebaseArray.java:61)
    at com.firebase.ui.database.FirebaseIndexArray.notifyChangedListeners(FirebaseIndexArray.java:119)
    at com.firebase.ui.database.FirebaseArray.notifyChangedListeners(FirebaseArray.java:119)
    at com.firebase.ui.database.FirebaseArray.onChildRemoved(FirebaseArray.java:100)
    at com.firebase.ui.database.FirebaseIndexArray.onChildRemoved(FirebaseIndexArray.java:29)
    at com.google.android.gms.internal.zzahe.zza(Unknown Source)
    at com.google.android.gms.internal.zzaje.zzcta(Unknown Source)
    at com.google.android.gms.internal.zzajh$1.run(Unknown Source)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:155)
    at android.app.ActivityThread.main(ActivityThread.java:5727)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)

because mSnapshots.remove(index) was call before notifyChangedListeners

    @Override
    public void onChildRemoved(DataSnapshot snapshot) {
        int index = getIndexForKey(snapshot.getKey());
        mSnapshots.remove(index);
        notifyChangedListeners(OnChangedListener.EventType.Removed, index);
    }

More seriously, your code is removed mistakenly listener. :(

Copy link
Collaborator Author

@SUPERCILEX SUPERCILEX Sep 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that!!! I completely messed up removing an item: mSnapshots.remove(index) wasn't even getting called! Check it out now: https://github.com/firebase/FirebaseUI-Android/pull/276/files#diff-c7d9ac7c32439f20359555e3db253268R119

@SUPERCILEX
Copy link
Collaborator Author

Thanks a ton for the feedback!!! I'm new to the object oriented thing and to programming in general so this was a huge help (and a bit of a struggle). I just figured how to use interfaces to get rid of instanceof two weeks ago, pretty sad. :)

Anyway, thanks again. I think I have a nice implementation now. Also, I left a question/comment if you have any thoughts about it.

@SUPERCILEX
Copy link
Collaborator Author

Should I update the app example to index the data? I don't think it's necessary, but it would put people on the right track for scalability.

}
index++;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this change please.

public void onCancelled(DatabaseError error) {
Log.e(TAG, "A fatal error occur retrieving the necessary keys to poplulate your adapter");
super.onCancelled(error);
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

I should add that invalidating the whole object feels kind of gross, since the dev who encounters this error basically has the options of giving up or creating another indexed array and hoping that one doesn't error. It's like a failable initializer, but in this case the failure is asynchronous and therefore extremely nasty.

If you have ideas for better handling this error, please do share them!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devs can override this method in which they could reinitialize their adapter with a new ref or replace their view with an "Oops, an unexpected error occurred." message. I think this gives devs nice options. What do you think of having a separate error method to override for the key failure vs the ref failure?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think we've done what we can to avoid badness here. How you handle other errors I'll leave to you since I don't know the platform specifics well, but imo they should be passed up to the API consumer with enough info for them to make a good decision.

@SUPERCILEX
Copy link
Collaborator Author

@morganchen12 @samtstern
While working on tests, I discovered that you cannot change the priority of the dataRefs (well you can, but it won't do anything). Should I add in the documentation that the order of the list items is determined by the order they are received in from the keyRef? If you think about it, that's kinda obvious because you're going to have all the other entries in dataRef and having a bunch of haphazard priorities in dataRef would be weird... should I add it anyway?

@SUPERCILEX
Copy link
Collaborator Author

We've got a problem. The database tests aren't running at all and haven't ever been. Is this on purpose?

@puf
Copy link
Contributor

puf commented Oct 21, 2016

I've run the database test locally, manually when we just started the project. They've never been run automatically afaik.

@SUPERCILEX
Copy link
Collaborator Author

@puf So as long as the tests ran fine for me, we're good?

I got all greens so unless you guys have a few final comments, this PR is good to merge!

@puf
Copy link
Contributor

puf commented Oct 25, 2016

I wouldn't mind them running in CI. We just never had CI when we started.

On Thu, Oct 20, 2016 at 5:51 PM Alex Saveau [email protected]
wrote:

@puf https://github.com/puf So as long as the tests ran fine for me,
we're good?

I got all greens so unless you guys have a few final comments, this PR is
good to merge!


You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
#276 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA3w33poOIuq3GezTTYXkRHQ-T5iTxQ6ks5q2AyXgaJpZM4JyPx9
.

@SUPERCILEX
Copy link
Collaborator Author

I'm pretty sure we'd need an emulator with the current state of the tests which would significantly slow Travis down.

public void onChildMoved(DataSnapshot snapshot, String previousChildKey) {
int oldIndex = getIndexForKey(snapshot.getKey());
mSnapshots.remove(oldIndex);
int newIndex = previousChildKey == null ? 0 : (getIndexForKey(previousChildKey) + 1);
int newIndex = previousChildKey == null ? 0 : getIndexForKey(previousChildKey) + 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put back the parentheses around (getIndexForKey(previousChildKey) + 1). The behavior is the same, but it makes the intent more explicit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

mListener = listener;
}

private class DataRefSnapshot implements ValueEventListener {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should name this class to indicate that it's a listener.

Copy link
Collaborator Author

@SUPERCILEX SUPERCILEX Oct 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed it DataRefListener, what do you think?

@puf
Copy link
Contributor

puf commented Oct 31, 2016

I had a few nits, aside from that this looks good to me. Thanks for all the hard work on this!

@SUPERCILEX
Copy link
Collaborator Author

SUPERCILEX commented Nov 1, 2016

@puf @samtstern firebase/FirebaseUI-iOS#164 was just merged, any idea when this PR will be merged?

@morganchen12
Copy link

@SUPERCILEX can you edit this PR to target the 1.0 branch? Once that's done and tests pass/conflicts are resolved I'll merge

@SUPERCILEX SUPERCILEX changed the base branch from master to version-1.0.0-dev November 1, 2016 23:39
@SUPERCILEX
Copy link
Collaborator Author

No conflicts!!! @morganchen12 This is awesome!!! I finally get to delete my tmpfirebasedatabase package!

@morganchen12 morganchen12 merged commit 5a4b661 into firebase:version-1.0.0-dev Nov 1, 2016
@samtstern
Copy link
Contributor

@SUPERCILEX two months later it's in! Thank you for your patience and all the other contributions you made while this one was pending. Version 1.0.0 is getting very close, excited to see this live.

@SUPERCILEX
Copy link
Collaborator Author

@puf @samstern thank you guys for your patience guiding me towards writing better code. I really appreciate it! I've learned a ton working on FirebaseUI and I hope to keep it up. Thanks!

I'm pretty excited for 1.0 too–there are so many new features!

@samtstern samtstern mentioned this pull request Nov 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants