Created
April 18, 2018 07:36
-
-
Save NiPfi/f00dc0f8178ef907202ed1046ced2746 to your computer and use it in GitHub Desktop.
Basic implementation of a repository pattern for Firebase Firestore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ch.jojoni.jamplan.model.repository; | |
import android.support.annotation.NonNull; | |
import android.util.Log; | |
import com.google.android.gms.tasks.Continuation; | |
import com.google.android.gms.tasks.OnFailureListener; | |
import com.google.android.gms.tasks.Task; | |
import com.google.firebase.firestore.CollectionReference; | |
import com.google.firebase.firestore.DocumentReference; | |
import com.google.firebase.firestore.DocumentSnapshot; | |
import com.google.firebase.firestore.FirebaseFirestore; | |
import ch.jojoni.jamplan.model.Identifiable; | |
/** | |
* Manages data access for Firebase | |
*/ | |
public class FirestoreRepository<TEntity extends Identifiable<String>> implements Repository<TEntity, String> { | |
private static final String TAG = "FirestoreRepository"; | |
private final Class<TEntity> entityClass; | |
private final CollectionReference collectionReference; | |
private final String collectionName; | |
/** | |
* Initializes the repository storing the data in the given collection. Should be from {@link FirestoreCollections}. | |
*/ | |
public FirestoreRepository(Class<TEntity> entityClass, String collectionName) { | |
this.collectionName = collectionName; | |
this.entityClass = entityClass; | |
FirebaseFirestore db = FirebaseFirestore.getInstance(); | |
this.collectionReference = db.collection(this.collectionName); | |
} | |
@Override | |
public Task<Boolean> exists(final String documentName) { | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Checking existence of '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.get().continueWith(new Continuation<DocumentSnapshot, Boolean>() { | |
@Override | |
public Boolean then(@NonNull Task<DocumentSnapshot> task) { | |
Log.d(TAG,"Checking if '" + documentName + "' exists in '" + collectionName +"'."); | |
return task.getResult().exists(); | |
} | |
}); | |
} | |
@Override | |
public Task<TEntity> get(String id) { | |
final String documentName = id; | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Getting '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.get().continueWith(new Continuation<DocumentSnapshot, TEntity>() { | |
@Override | |
public TEntity then(@NonNull Task<DocumentSnapshot> task) throws Exception { | |
DocumentSnapshot documentSnapshot = task.getResult(); | |
if (documentSnapshot.exists()) { | |
return documentSnapshot.toObject(entityClass); | |
} else { | |
Log.d(TAG, "Document '" + documentName + "' does not exist in '" + collectionName + "'."); | |
return entityClass.newInstance(); | |
} | |
} | |
}); | |
} | |
@Override | |
public Task<Void> create(TEntity entity) { | |
final String documentName = entity.getEntityKey(); | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Creating '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.set(entity).addOnFailureListener(new OnFailureListener() { | |
@Override | |
public void onFailure(@NonNull Exception e) { | |
Log.d(TAG, "There was an error creating '" + documentName + "' in '" + collectionName + "'!", e); | |
} | |
}); | |
} | |
@Override | |
public Task<Void> update(TEntity entity) { | |
final String documentName = entity.getEntityKey(); | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Updating '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.set(entity).addOnFailureListener(new OnFailureListener() { | |
@Override | |
public void onFailure(@NonNull Exception e) { | |
Log.d(TAG, "There was an error updating '" + documentName + "' in '" + collectionName + "'.", e); | |
} | |
}); | |
} | |
@Override | |
public Task<Void> delete(final String documentName) { | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Deleting '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.delete().addOnFailureListener(new OnFailureListener() { | |
@Override | |
public void onFailure(@NonNull Exception e) { | |
Log.d(TAG, "There was an error deleting '" + documentName + "' in '" + collectionName + "'.", e); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ch.jojoni.jamplan.model; | |
import com.google.firebase.firestore.Exclude; | |
/** | |
* Represents an object that can be uniquely identified among other objects of the same type | |
* by using an UID. | |
* | |
* @param <TKey> type of the unique key (UID) this object is uniquely identified by. The type needs | |
* a correct implementation of its equals() method or the behaviour of code using this | |
* interface will be undefined. | |
*/ | |
public interface Identifiable<TKey> { | |
@Exclude | |
TKey getEntityKey(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ch.jojoni.jamplan.model.repository; | |
import com.google.android.gms.tasks.Task; | |
import ch.jojoni.jamplan.model.Identifiable; | |
/** | |
* Manages data access for POJOs that are uniquely identifiable by a key, such as POJOs implementing {@link Identifiable}. | |
*/ | |
public interface Repository<TEntity extends Identifiable<TKey>, TKey> { | |
/** | |
* Checks the repository for a given id and returns a boolean representing its existence. | |
* @param id the unique id of an entity. | |
* @return A {@link Task} for a boolean which is 'true' if the entity for the given id exists, 'false' otherwise. | |
*/ | |
Task<Boolean> exists(TKey id); | |
/** | |
* Queries the repository for an uniquely identified entity and returns it. If the entity does | |
* not exist in the repository, a new instance is returned. | |
* @param id the unique id of an entity. | |
* @return A {@link Task} for an entity implementing {@link Identifiable}. | |
*/ | |
Task<TEntity> get(TKey id); | |
/** | |
* Stores an entity in the repository so it is accessible via its unique id. | |
* @param entity the entity implementing {@link Identifiable} to be stored. | |
* @return An {@link Task} to be notified of failures. | |
*/ | |
Task<Void> create(TEntity entity); | |
/** | |
* Updates an entity in the repository | |
* @param entity the new entity to be stored. | |
* @return A {@link Task} to be notified of failures. | |
*/ | |
Task<Void> update(TEntity entity); | |
/** | |
* Deletes an entity from the repository. | |
* @param id uniquely identifying the entity. | |
* @return A {@link Task} to be notified of failures. | |
*/ | |
Task<Void> delete(TKey id); | |
} |
@NiPfi This is great!! One question though, how can I query by adding whereEqualTo and orderBy on get method?
Is there a reason these codes are written in Java instead of Kotlin?
@wonsuc There's a few but it basically boils down to this code being created for a school project during one semester and the school primarily teaching programming using Java. Also, when I wrote this code 2 years ago, Google was still in the process of making Kotlin the primary language for Android and since I don't program for Android professionally now, it didn't make sense to learn Kotlin for the purpose of a single semester.
@NiPfi Thanks for the answer, I just wondered if I can't use Repository
pattern with Kotlin for Firestore.
@wonsuc Maybe you can code it in Kotlin by taking inspiration from this
code here. If you do so, it would be great if you create a Gist too so it
can be linked to from here.
…On Wed, 1 Jul 2020 at 07:31, Jason Yoo (Wonsuc Yoo) < ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
@NiPfi <https://github.com/NiPfi> Thanks for the answer, I just wondered
if I can't use Repository pattern with Kotlin for Firestore.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<https://gist.github.com/f00dc0f8178ef907202ed1046ced2746#gistcomment-3360262>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAICRYXPM4XS4YU2QRDU563RZLCZNANCNFSM4JYPLBGA>
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is excellent !! Thanks :)