All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.parse.ParseRelationOperation Maven / Gradle / Ivy

Go to download

A library that gives you access to the powerful Parse cloud platform from your Android app.

There is a newer version: 1.17.3
Show newest version
/*
 * Copyright (c) 2015-present, Parse, LLC.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
package com.parse;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * An operation where a ParseRelation's value is modified.
 */
/** package */ class ParseRelationOperation implements ParseFieldOperation {
  // The className of the target objects.
  private final String targetClass;

  // A set of objects to add to this relation.
  private final Set relationsToAdd;
  // A set of objects to remove from this relation.
  private final Set relationsToRemove;
  
  ParseRelationOperation(Set newRelationsToAdd, Set newRelationsToRemove) {
    String targetClass = null;
    relationsToAdd = new HashSet<>();
    relationsToRemove = new HashSet<>();

    if (newRelationsToAdd != null) {
      for (T object : newRelationsToAdd) {
        addParseObjectToSet(object, relationsToAdd);

        if (targetClass == null) {
          targetClass = object.getClassName();
        } else {
          if (!targetClass.equals(object.getClassName())) {
            throw new IllegalArgumentException(
                "All objects in a relation must be of the same class.");
          }
        }
      }
    }

    if (newRelationsToRemove != null) {
      for (T object : newRelationsToRemove) {
        addParseObjectToSet(object, relationsToRemove);

        if (targetClass == null) {
          targetClass = object.getClassName();
        } else {
          if (!targetClass.equals(object.getClassName())) {
            throw new IllegalArgumentException(
                "All objects in a relation must be of the same class.");
          }
        }
      }
    }

    if (targetClass == null) {
      throw new IllegalArgumentException("Cannot create a ParseRelationOperation with no objects.");
    }
    this.targetClass = targetClass;
  }

  private ParseRelationOperation(String newTargetClass, Set newRelationsToAdd,
      Set newRelationsToRemove) {
    targetClass = newTargetClass;
    relationsToAdd = new HashSet<>(newRelationsToAdd);
    relationsToRemove = new HashSet<>(newRelationsToRemove);
  }

  /*
   * Adds a ParseObject to a set, replacing any existing instance of the same object.
   */
  private void addParseObjectToSet(ParseObject obj, Set set) {
    if (Parse.getLocalDatastore() != null || obj.getObjectId() == null) {
      // There's no way there could be duplicate instances.
      set.add(obj);
      return;
    }
    
    // We have to do this the hard way.
    for (ParseObject existingObject : set) {
      if (obj.getObjectId().equals(existingObject.getObjectId())) {
        set.remove(existingObject);
      }
    }
    set.add(obj);
  }

  /*
   * Adds a list of ParseObject to a set, replacing any existing instance of the same object.
   */
  private void addAllParseObjectsToSet(Collection list, Set set) {
    for (ParseObject obj : list) {
      addParseObjectToSet(obj, set);
    }
  }
  
  /*
   * Removes an object (and any duplicate instances of that object) from the set.
   */
  private void removeParseObjectFromSet(ParseObject obj, Set set) {
    if (Parse.getLocalDatastore() != null || obj.getObjectId() == null) {
      // There's no way there could be duplicate instances.
      set.remove(obj);
      return;
    }
    
    // We have to do this the hard way.
    for (ParseObject existingObject : set) {
      if (obj.getObjectId().equals(existingObject.getObjectId())) {
        set.remove(existingObject);
      }
    }
  }

  /*
   * Removes all objects (and any duplicate instances of those objects) from the set.
   */
  private void removeAllParseObjectsFromSet(Collection list, Set set) {
    for (ParseObject obj : list) {
      removeParseObjectFromSet(obj, set);
    }
  }

  String getTargetClass() {
    return targetClass;
  }

  /*
   * Converts a set of objects into a JSONArray of Parse pointers.
   */
  JSONArray convertSetToArray(Set set, ParseEncoder objectEncoder)
      throws JSONException {
    JSONArray array = new JSONArray();
    for (ParseObject obj : set) {
      array.put(objectEncoder.encode(obj));
    }
    return array;
  }

  // Encodes any add/removes ops to JSON to send to the server.
  @Override
  public JSONObject encode(ParseEncoder objectEncoder) throws JSONException {
    JSONObject adds = null;
    JSONObject removes = null;

    if (relationsToAdd.size() > 0) {
      adds = new JSONObject();
      adds.put("__op", "AddRelation");
      adds.put("objects", convertSetToArray(relationsToAdd, objectEncoder));
    }

    if (relationsToRemove.size() > 0) {
      removes = new JSONObject();
      removes.put("__op", "RemoveRelation");
      removes.put("objects", convertSetToArray(relationsToRemove, objectEncoder));
    }

    if (adds != null && removes != null) {
      JSONObject result = new JSONObject();
      result.put("__op", "Batch");
      JSONArray ops = new JSONArray();
      ops.put(adds);
      ops.put(removes);
      result.put("ops", ops);
      return result;
    }

    if (adds != null) {
      return adds;
    }

    if (removes != null) {
      return removes;
    }

    throw new IllegalArgumentException("A ParseRelationOperation was created without any data.");
  }

  @Override
  public ParseFieldOperation mergeWithPrevious(ParseFieldOperation previous) {
    if (previous == null) {
      return this;

    } else if (previous instanceof ParseDeleteOperation) {
      throw new IllegalArgumentException("You can't modify a relation after deleting it.");

    } else if (previous instanceof ParseRelationOperation) {
      @SuppressWarnings("unchecked")
      ParseRelationOperation previousOperation = (ParseRelationOperation) previous;

      if (previousOperation.targetClass != null
          && !previousOperation.targetClass.equals(targetClass)) {
        throw new IllegalArgumentException("Related object object must be of class "
            + previousOperation.targetClass + ", but " + targetClass + " was passed in.");
      }

      Set newRelationsToAdd = new HashSet<>(previousOperation.relationsToAdd);
      Set newRelationsToRemove = new HashSet<>(previousOperation.relationsToRemove);
      if (relationsToAdd != null) {
        addAllParseObjectsToSet(relationsToAdd, newRelationsToAdd);
        removeAllParseObjectsFromSet(relationsToAdd, newRelationsToRemove);
      }
      if (relationsToRemove != null) {
        removeAllParseObjectsFromSet(relationsToRemove, newRelationsToAdd);
        addAllParseObjectsToSet(relationsToRemove, newRelationsToRemove);
      }
      return new ParseRelationOperation(targetClass, newRelationsToAdd, newRelationsToRemove);

    } else {
      throw new IllegalArgumentException("Operation is invalid after previous operation.");
    }
  }

  @Override
  @SuppressWarnings("unchecked")
  public Object apply(Object oldValue, String key) {
    ParseRelation relation;

    if (oldValue == null) {
      relation = new ParseRelation<>(targetClass);

    } else if (oldValue instanceof ParseRelation) {
      relation = (ParseRelation) oldValue;
      if (targetClass != null && !targetClass.equals(relation.getTargetClass())) {
        throw new IllegalArgumentException("Related object object must be of class "
            + relation.getTargetClass() + ", but " + targetClass + " was passed in.");
      }
    } else {
      throw new IllegalArgumentException("Operation is invalid after previous operation.");
    }
    
    for (ParseObject relationToAdd : relationsToAdd) {
      relation.addKnownObject(relationToAdd);
    }
    for (ParseObject relationToRemove : relationsToRemove) {
      relation.removeKnownObject(relationToRemove);
    }
    return relation;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy