cs306-versus/versus-app

View on GitHub
app/src/main/java/com/github/versus/db/FsScheduleManager.java

Summary

Maintainability
A
3 hrs
Test Coverage
B
81%
package com.github.versus.db;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.versus.posts.Post;
import com.github.versus.posts.Timestamp;
import com.github.versus.schedule.Schedule;
import com.github.versus.user.User;
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 com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

public class FsScheduleManager implements ScheduleManager {
    private final FirebaseFirestore db;
    public static FsCollections SCHEDULECOLLECTION = FsCollections.SCHEDULES ;

    public FsScheduleManager(FirebaseFirestore db){
        this.db = db;
    }


    @Override
    public Future<Boolean> insert(Schedule data) {
        //inserting the schedule in the Schedule database
        DocumentReference docRef = db.collection(SCHEDULECOLLECTION.toString()).document();
        Task<Void> task = docRef.set(data.getAllAttributes());

        // Wrap the Task in a CompletableFuture that returns the status of the insertion
        CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();

        task.addOnSuccessListener(res -> {
            completableFuture.complete(true);
        }).addOnFailureListener(e -> {
            completableFuture.complete(false);
        });

        return completableFuture;
    }

    @Override
    public CompletableFuture<Schedule> fetch(String UID){

        //accessing the User Schedule collection
        CollectionReference postsRef = db.collection(SCHEDULECOLLECTION.toString());

        //finding the user with the right id
        Query query = postsRef.whereEqualTo("UID", UID);
        Task<QuerySnapshot> task = query.get();

        //Creating the CompletableFuture wrap that returns the schedule
        CompletableFuture<Schedule> future = new CompletableFuture<>();

        // Add a listener to the Task to handle the result
        task.addOnSuccessListener(res -> {
            //we get the query result
            List<DocumentSnapshot> docs = res.getDocuments();
            if(docs.isEmpty()){
                //in case the query result is empty complete the future with null
                future.complete(null);
            }else{
                //if the query is not empty we assume that the first document has the correct user
                DocumentSnapshot doc = docs.get(0);
                //converting the data we get into an actual post object

                Schedule schedule = (new ObjectMapper()).convertValue(doc.getData(), Schedule.class);
                future.complete(schedule);
            }
        }).addOnFailureListener(res ->{
            future.complete(null);
        });

        return future;
    }

    @Override
    public CompletableFuture<Schedule> getScheduleStartingFromDate(String UID, Timestamp startingDate) {
        return fetch(UID).thenApply(s -> s == null ? null :  s.startingFromDate(startingDate));
    }


    public CompletableFuture<Schedule> getScheduleOnDate(String UID, Timestamp startingDate) {
        return fetch(UID).thenApply(s -> s == null ? null :  s.onDate(startingDate));
    }

    @Override
    public Future<Boolean> delete(String id) {

        //accessing the collection
        CollectionReference postsRef = db.collection(SCHEDULECOLLECTION.toString());
        //finding the post with the right id
        Query query = postsRef.whereEqualTo("UID", id);
        Task<QuerySnapshot> task = query.get();

        // Wrap the Task in a CompletableFuture that returns status of deletion
        CompletableFuture<Boolean> future = new CompletableFuture<>();

        // Add a listener to the Task to handle the result
        task.addOnSuccessListener(res -> {
            //we get the query result
            List<DocumentSnapshot> docs = res.getDocuments();
            if(docs.isEmpty()){
                //in case the query result is empty complete the future with true
                //because there was nothing to delete
                future.complete(true);
            }else{
                //getting all the matching posts reference
                for (DocumentSnapshot doc: docs
                ) {
                    DocumentReference docRef = doc.getReference();
                    //deleting the document
                    docRef.delete().addOnFailureListener(av ->{
                        future.complete(false);
                    });
                }
                future.complete(true);
            }
        }).addOnFailureListener(res ->{
            future.complete(false);
        });

        return future;
    }

    @Override
    public Future<Boolean> addPostToSchedule(String UID, Post post) {
        //accessing the schedule collection
        CollectionReference scheduleRef = db.collection(SCHEDULECOLLECTION.toString());

        //finding the schedule with the right UID
        Query query = scheduleRef.whereEqualTo("UID", UID);
        Task<QuerySnapshot> task = query.get();

        // Wrap the Task in a CompletableFuture that returns the status of the schedule update
        CompletableFuture<Boolean> future = new CompletableFuture<>();

        //we complete the future with false if the query failed
        //otherwise we try to update the value of the scheduled posts field
        task.addOnSuccessListener(res -> {

            //getting the documents corresponding to the post
            List<DocumentSnapshot> docs = res.getDocuments();
            if(docs.isEmpty()){
                future.complete(false);
            }else{
                DocumentSnapshot doc = docs.get(0);
                List<Post> scheduledPosts = (List<Post>)doc.get("posts");

                //creating a new list corresponding to the old one + the new post
                List<Post> newScheduledPosts = new ArrayList<>(scheduledPosts);
                newScheduledPosts.add(post);

                //updating the field value
                //if the update task is a success we complete the future with true
                //otherwise we complete the future with false
                doc.getReference().update("posts", newScheduledPosts).addOnSuccessListener(aVoid ->{
                        future.complete(true);
                    }).addOnFailureListener(e ->{
                                future.complete(false);
                            }
                    );

            }
        }).addOnFailureListener(e -> {
            future.complete(false);
        });

        return future;
    }

}