/// <summary> /// Return a list of MoBackRow object from the relation JSON /// </summary> /// <returns>The back row from relation JSO.</returns> /// <param name="relationJSON">Relation JSO.</param> public static List <MoBackRow> MoBackRowFromRelationJSON(SimpleJSONNode relationJSON) { SimpleJSONArray nestedArray = relationJSON["value"] as SimpleJSONArray; List <MoBackRow> moBackRows = new List <MoBackRow>(); // If the nested json doesn't have an object type, just return null. // When AchieveRelation without ?include={ColumnName}, it will return a pointer type. for (int i = 0; i < nestedArray.Count; i++) { if (nestedArray[i]["__type"].Value != "object") { if (nestedArray[i]["__type"].Value == "Pointer") { Debug.LogWarning("The response JSON contains Pointer type, not Object type, can't parse this relationJson. Try MoBackRelation.RelationFromMoBackJSON() instead"); return(null); } else { Debug.LogError("Unknown type: " + nestedArray[i]["__type"].Value); return(null); } } SimpleJSONClass jsonObject = nestedArray[i] as SimpleJSONClass; // This will get the MoBackObject exlucde the 2 keys: "__type" and "className". moBackRows.Add(MoBackRow.FromJSON(jsonObject, nestedArray[i]["className"])); } return(moBackRows); }
/// <summary> /// Creates a MoBackRelation object from JSON returned from server. /// </summary> /// <returns>The relation.</returns> /// <param name="relationJSON">Relation in JSON form, from server.</param> public static MoBackRelation RelationFromMoBackJSON(SimpleJSONNode relationJSON) { MoBackRelation relation = new MoBackRelation(); SimpleJSONArray pointersJSON = relationJSON ["value"].AsArray; for (int i = 0; i < pointersJSON.Count; i++) { // If the nested json doesn't have a pointer type, just return null. // When AchieveRelation with ?include={ColumnName}, it will return an object type. if (pointersJSON[i]["__type"].Value != "Pointer") { if (pointersJSON[i]["__type"].Value == "object") { Debug.LogWarning("The response JSON contains Object type, not Pointer type, can't parse this relationJson. Try MoBackRelation.MoBackRowFromRelationJSON() instead"); return(null); } else { Debug.LogError("Unknown type: " + pointersJSON[i]["__type"].Value); return(null); } } relation._pointers.Add(MoBackPointer.PointerFromMoBackJSON(pointersJSON[i])); } return(relation); }
/// <summary> /// Converts MobackValueType objects into JSON objects. /// </summary> /// <returns> An simple JSON array of JSON objects. </returns> public SimpleJSONArray GetJSON() { SimpleJSONArray jsonArray = new SimpleJSONArray(); for (int i = 0; i < objects.Count; i++) { SimpleJSONNode node = MoBackUtils.MoBackTypedObjectToJSON(objects[i], objectTypes[i]); jsonArray.Add(node); } return(jsonArray); }
/// <summary> /// Initializes a new instance of the <see cref="MoBackInternal.CompoundQuery"/> class. /// </summary> /// <param name="compoundOperator"> A compound operator. </param> /// <param name="queriesToCompound"> An array of queries to compound. </param> public CompoundQuery(string compoundOperator, params Query[] queriesToCompound) { constraints = new SimpleJSONClass(); SimpleJSONArray constraintValues = new SimpleJSONArray(); foreach (Query query in queriesToCompound) { constraintValues.Add(query.constraints); } constraints.Add(compoundOperator, constraintValues); }
/// <summary> /// Gets the objects processor. /// </summary> /// <returns>A list of objects of the MoBackRow type converted from a JSON object.</returns> /// <param name="jsonObject">JSON object.</param> private List <MoBackRow> GetObjects_processor(SimpleJSONNode jsonObject) { List <MoBackRow> objects = new List <MoBackRow>(); // TODO: this doesn't work. Need to double check later. SimpleJSONArray results = jsonObject["results"].AsArray; for (int i = 0; i < results.Count; i++) { objects.Add(MoBackRow.FromJSON(results[i] as SimpleJSONClass, table.TableName)); } return(objects); }
/// <summary> /// Converts JSON objects into MoBackValueType objects. /// </summary> /// <returns> A MoBackArray containing converted JSON objects. </returns> /// <param name="jsonArray"> A simple JSON Array. </param> public static MoBackArray FromJSON(SimpleJSONArray jsonArray) { MoBackArray mArray = new MoBackArray(); foreach (SimpleJSONNode value in jsonArray) { MoBackValueType moBackType; object data = MoBackUtils.MoBackTypedObjectFromJSON(value, out moBackType); // This should always be equivalent to calling Add() with the appropriate type; if Add() functions are refactored then so too should this. mArray.objects.Add(data); mArray.objectTypes.Add(moBackType); } return(mArray); }
/// <summary> /// MoBack JSON from relation. Of dubious usefulness because uploading and updating relations directly is presently forbidden. /// </summary> /// <returns>The moback JSON representing the relation.</returns> /// <param name="relation">Relation.</param> public static SimpleJSONNode MoBackJSONFromRelation(MoBackRelation relation) { SimpleJSONClass relationJSON = new SimpleJSONClass(); relationJSON ["__type"] = "Pointer"; SimpleJSONArray pointersJSON = new SimpleJSONArray(); for (int i = 0; i < relation._pointers.Count; i++) { pointersJSON.Add(MoBackPointer.PointerToMoBackJSON(relation._pointers[i])); } relationJSON ["value"] = pointersJSON; return(relationJSON); }
/// <summary> /// Gets JSON the server expects for an remove relation operation, that removes the supplied list of pointers to some relation. /// </summary> /// <returns>The remove operation as mo back JSO.</returns> /// <param name="pointersToRemove">Pointers to add.</param> public static SimpleJSONClass RelationRemoveOpAsMoBackJSON(MoBackPointer[] pointersToRemove) { SimpleJSONClass relationOpJsonStructure = new SimpleJSONClass(); relationOpJsonStructure ["__op"] = "removeRelation"; SimpleJSONArray pointers = new SimpleJSONArray(); for (int i = 0; i < pointersToRemove.Length; i++) { pointers.Add(MoBackPointer.PointerToMoBackJSON(pointersToRemove[i])); } relationOpJsonStructure ["objects"] = pointers; return(relationOpJsonStructure); }
/// <summary> /// Initializes a new instance of the <see cref="MoBackInternal.ComparisonQuery"/> class. /// </summary> /// <param name="column"> A column.</param> /// <param name="values"> An array object values. </param> /// <param name="comparisonOperator"> A comparison operator as a string. </param> public ComparisonQuery(string column, object[] values, string comparisonOperator) { constraints = new SimpleJSONClass(); SimpleJSONClass constraint = new SimpleJSONClass(); SimpleJSONArray constraintValues = new SimpleJSONArray(); for (int i = 0; i < values.Length; i++) { object value = values[i]; MoBackValueType type = MoBackInternal.MoBackUtils.ExtractMobackType(ref value); constraintValues.Add(MoBackInternal.MoBackUtils.MoBackTypedObjectToJSON(value, type)); } constraint.Add(comparisonOperator, constraintValues); constraints.Add(column, constraint); }
/// <summary> /// Deletes the multiple ojbects. /// </summary> /// <returns>A MoBackRequest.</returns> /// <param name="objectsToDelete">Objects to delete.</param> public MoBackRequest DeleteMultipleOjbects(List <MoBackRow> objectsToDelete) { string uri = MoBackURLS.BatchDelete + table.TableName; SimpleJSONArray jsonArray = new SimpleJSONArray(); SimpleJSONClass jsonBody = new SimpleJSONClass(); foreach (MoBackRow item in objectsToDelete) { jsonArray.Add(MoBackUtils.MoBackTypedObjectToJSON(item.ObjectId, MoBackValueType.String)); } jsonBody.Add("objectIds", jsonArray); byte[] bytes = jsonBody.ToString().ToByteArray(); MoBackRequest.ResponseProcessor deleteCallBack = (SimpleJSONNode responseJson) => { SimpleJSONArray responseArray = responseJson["deletedObjectIds"].AsArray; Debug.Log(responseArray.ToString()); foreach (SimpleJSONNode item in responseArray) { MoBackRow deletedRow = objectsToDelete.Find(row => row.ObjectId == item.Value); if (deletedRow != null) { deletedRow.ResetMetaData(null); } else { Debug.Log("Can't find row"); } } }; /* * Sample uri: https://api.moback.com/objectmgr/api/collections/batch/delete/{tableName} * Sample Json Request Body: * { * "objectIds" : ["Vp6pfOSwp23tC3IN", "Vp6ZnOSwp23tC3Hv"] * } */ return(new MoBackRequest(deleteCallBack, uri, HTTPMethod.POST, null, bytes)); }
/// <summary> /// Merge queries, potentially recursively. /// </summary> /// <param name="first">First query. This also contains the merged result after the merge.</param> /// <param name="second">Second query.</param> private void MergeQueries(SimpleJSONClass first, SimpleJSONClass second) { // Needs to merge various things correctly. For a (non-encompassing) example of the problem, take: // {"playerName":"Sean Plott","cheatMode":{"thisIsanObject":true}} // {"playerName":{"$exists":true}} // {"cheatMode":{"note":"ThisIsPartOfAnObjectNotAConstraint", "cheat":"noSecretCows"}} // {"rank":{"$gte":1,"$lte":10}} // {"rank":{"$in":[2,3,6]}} // {"$and":[{"StudentName":”Mark Lee”},{"standard":4}]} // Should turn into: // {"playerName":"Sean Plott","cheatMode":{"note":"ThisIsPartOfAnObjectNotAConstraint", "cheat":"noSecretCows"}, "rank":{"$gte":1,"$lte":10,"$in":[2,3,6]}, // "$and":[{"StudentName":”Mark Lee”},{"standard":4}]} // Approach: // 0.When keywords don't conflict, just add both // 1.Two objects containing $keywords should be merged, following these rules recursively (relevantly, constants override constants, but arrays with $names are merged) // 2.Arrays with $names should be merged, by appending second array after first // 3.For two constant values (strings, ints, etc), in the case of a conflict the second value should override the first. // ^Objects not containing $keywords and arrays without $names should be treated as constants // 5.When a conflict is not otherwise covered by these rules, just use the second of the two values // 6.Consider implementing in the future: Between an object containing $keywords and a constant match being provied, pick the constant match // (because an exact match effectively supercedes all constraints (except maybe mutually conflicting constraints which should axiomatically return nothing... // but not sure how that should be dealt with anyway? life would be simpler if we had an $eq operator exposed) foreach (KeyValuePair <string, SimpleJSONNode> node in second.dict) { if (first.dict.ContainsKey(node.Key)) { SimpleJSONNode firstNode = first[node.Key]; SimpleJSONNode secondNode = node.Value; System.Type firstType = firstNode.valueType; System.Type secondType = secondNode.valueType; if (firstType == typeof(SimpleJSONClass) || secondType == typeof(SimpleJSONClass)) { bool firstIsClassContainingKeywords = firstType == typeof(SimpleJSONClass) && JsonClassContainsKeywords((SimpleJSONClass)firstNode); bool secondIsClassContainingKeywords = secondType == typeof(SimpleJSONClass) && JsonClassContainsKeywords((SimpleJSONClass)secondNode); if (firstIsClassContainingKeywords && secondIsClassContainingKeywords) { // Merge recursively SimpleJSONClass firstObject = (SimpleJSONClass)firstNode; SimpleJSONClass secondObject = (SimpleJSONClass)secondNode; MergeQueries(firstObject, secondObject); } else { // Newer value takes precedence first.Add(node.Key, node.Value); } } else if (firstType == typeof(SimpleJSONArray) && secondType == typeof(SimpleJSONArray) && NameIsKeyword(node.Key)) { // Merge arrays SimpleJSONArray firstArray = (SimpleJSONArray)firstNode; SimpleJSONArray secondArray = (SimpleJSONArray)secondNode; for (int i = 0; i < secondArray.Count; i++) { firstArray.Add(secondArray[i]); } } else { // Newer value takes precedence first.Add(node.Key, node.Value); } } else { // No conflict, just add first.Add(node.Key, node.Value); } } }
/// <summary> /// Saves multiple objects with one single call to server. /// </summary> /// <returns>The MobackRequest.</returns> /// <param name="rowsToSave">MoBack Rows need to save.</param> public MoBackRequest SaveMultipleObjects(List <MoBackRow> rowsToSave) { string uri = MoBackURLS.Batch + table.TableName; SimpleJSONArray jsonArray = new SimpleJSONArray(); SimpleJSONClass jsonStructure = new SimpleJSONClass(); for (int i = 0; i < rowsToSave.Count; i++) { SimpleJSONClass jsonToSave = rowsToSave[i].GetJSON(); if (rowsToSave[i].ObjectId != null) { jsonToSave.Add("objectId", rowsToSave[i].ObjectId); } jsonArray.Add(jsonToSave); } jsonStructure.Add("objects", jsonArray); Debug.Log(jsonStructure.ToString()); byte[] bytes = jsonStructure.ToString().ToByteArray(); // Construct a callback to update all rowsToSave. MoBackRequest.ResponseProcessor objUpdater = (SimpleJSONNode responseJson) => { SimpleJSONClass allObjectsInJsonFormat = responseJson["batchResponse"].AsObject; // The response should have the same amount as of the request body. if (allObjectsInJsonFormat.Count != rowsToSave.Count) { Debug.LogError(string.Format("Response objects count: {0}. Request objects count: {1}", allObjectsInJsonFormat.Count, rowsToSave.Count)); Debug.LogError("Response doesn't have the same object as Request Body. Something wrong!"); return; } for (int i = 0; i < rowsToSave.Count; i++) { SimpleJSONClass jsonAtCurrentIndex = allObjectsInJsonFormat[i] as SimpleJSONClass; if (!jsonAtCurrentIndex["success"].AsBool) { Debug.LogError("Unable to save: " + jsonAtCurrentIndex["objectId"]); continue; } if (!string.IsNullOrEmpty(jsonAtCurrentIndex["createdAt"].ToString())) { string objectId = jsonAtCurrentIndex["objectId"]; DateTime createdTime = MoBackDate.DateFromString(jsonAtCurrentIndex["createdAt"]); rowsToSave[i].UpdateAfterSave(objectId, createdTime, createdTime); } else if (!string.IsNullOrEmpty(jsonAtCurrentIndex["updatedAt"].ToString())) { string objectId = jsonAtCurrentIndex["objectId"]; DateTime updateTime = MoBackDate.DateFromString(jsonAtCurrentIndex["updatedAt"]); rowsToSave[i].UpdateAfterSave(objectId, null, updateTime); } } }; /* * Sample uri: https://api.moback.com/objectmgr/api/collections/batch/{tableName} * Sample Json Request Body: * { * "objects" : [{ "Name" : "Joe", "FavoriteFood" : ["pizza", "fried eggs", "ham sandwich"]}] * } */ return(new MoBackRequest(objUpdater, uri, HTTPMethod.POST, null, bytes)); }