コード例 #1
0
        /// <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);
        }
コード例 #2
0
        /// <summary>
        /// Converts latitude and longitude data from a JSON object to a double value type.
        /// </summary>
        /// <returns>The JSO.</returns>
        /// <param name="node">Node.</param>
        public static MoBackGeoPoint FromJSON(SimpleJSONNode node)
        {
            double lat = node["lat"].AsDouble;
            double lon = node["lon"].AsDouble;

            return(new MoBackGeoPoint(lat, lon));
        }
コード例 #3
0
        /// <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);
        }
コード例 #4
0
        /// <summary>
        /// Converts a JSON object to a MoBackPointer object.
        /// </summary>
        /// <returns> A MoBackPointer object. </returns>
        /// <param name="pointerJSON"> A JSON object. </param>
        public static MoBackPointer PointerFromMoBackJSON(SimpleJSONNode pointerJSON)
        {
            string objID = pointerJSON["objectId"];
            string table = pointerJSON["className"];

            return(new MoBackPointer(objID, table));
        }
コード例 #5
0
ファイル: MoBackFile.cs プロジェクト: SimonBellV/v0.93
        /// <summary>
        /// Converts MoBackObject data to a JSON object for storage.
        /// </summary>
        /// <returns>A JSON object.</returns>
        public override SimpleJSONClass GetJSON()
        {
            // Construct a child json object, which is the File type.
            SimpleJSONClass jsonForUploadFile = new SimpleJSONClass();

            jsonForUploadFile["__type"] = "File";
            jsonForUploadFile["name"]   = Name;
            jsonForUploadFile["url"]    = url;

            // Final json structure to send to server, to create a new row.
            SimpleJSONClass jsonStructure = new SimpleJSONClass();

            // Add the child json.
            jsonStructure.Add("FileURL", jsonForUploadFile);

            // Add other values if any.
            foreach (KeyValuePair <string, object> item in storeValues)
            {
                if (item.Key == "objectId" || item.Key == "createdAt" || item.Key == "updatedAt")
                {
                    continue; // No need to send auto-populated fields as part of JSON message
                }

                SimpleJSONNode node = MoBackUtils.MoBackTypedObjectToJSON(item.Value, columnTypeData[item.Key]);
                jsonStructure.Add(item.Key, node);
            }

            return(jsonStructure);
        }
コード例 #6
0
            /// <summary>
            /// Modifies the relation for a given row/column.
            /// </summary>
            /// <returns>The request object.</returns>
            /// <param name="tableName">Table name.</param>
            /// <param name="objectID">Row ID.</param>
            /// <param name="columnName">Column ID.</param>
            /// <param name="relationOp">JSON that signifies details of relation operation to MoBack servers.</param>
            public static MoBackRequest ModifyRelationForGivenRowColumn(string tableName, string objectID, string columnName, SimpleJSONNode relationOp)
            {
                SimpleJSONClass opOnColumn = new SimpleJSONClass();

                opOnColumn [columnName] = relationOp;

                /*
                 * Sample uri: https://api.moback.com/objectmgr/api/collections/{tableName}/{objectID}
                 * Sample Json Request Body:
                 * {
                 *  "Car": {
                 *      "objects": [
                 *      {
                 *          "__type": "Pointer",
                 *          "objectId": "VqFsguSwp23tC3gF",
                 *          "className": "Relations"
                 *          },{
                 *          "__type": "Pointer",
                 *          "objectId": "VqFsnuSwp23tC3gH",
                 *          "className": "Relations"
                 *          }
                 *      ],
                 *      "__op": "addRelation"
                 *  }
                 * }
                 */
                return(new MoBackRequest(MoBackURLS.TablesDefault + tableName + "/" + objectID, HTTPMethod.PUT, null, opOnColumn.ToString().ToByteArray()));
            }
コード例 #7
0
ファイル: MoBackFile.cs プロジェクト: SimonBellV/v0.93
        /// <summary>
        /// Froms the JSO.
        /// </summary>
        /// <returns>The JSO.</returns>
        /// <param name="jsonObject">Json object.</param>
        public static MoBackFile FromJSON(SimpleJSONNode jsonObject)
        {
            MoBackFile fileHolder = new MoBackFile();

            fileHolder.Name = jsonObject["name"];
            fileHolder.url  = jsonObject["url"];
            return(fileHolder);
        }
コード例 #8
0
ファイル: MoBackRow.cs プロジェクト: SimonBellV/v0.93
        public void ResetMetaData(SimpleJSONNode rawResponse)
        {
            Debug.Log("Reset meta data");

            // Reset default meta values.
            ObjectId    = null;
            CreatedDate = null;
            UpdatedDate = null;
        }
コード例 #9
0
ファイル: MoBackRequest.cs プロジェクト: SimonBellV/v0.93
        /// <summary>
        /// Requests the result callback.
        /// </summary>
        /// <param name="rawMessage"> The raw message. </param>
        /// <param name="jsonIfAny"> A JSON object, if any. </param>
        protected virtual void RequestResultCallback(string rawMessage, SimpleJSONNode jsonIfAny)
        {
            if (responseProcessor != null)
            {
                responseProcessor(jsonIfAny);
            }

            message    = rawMessage;
            currentRun = null;
            State      = RequestState.COMPLETED;
        }
コード例 #10
0
ファイル: MoBackArray.cs プロジェクト: SimonBellV/v0.93
        /// <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);
        }
コード例 #11
0
        /// <summary>
        /// Converts MoBackObject data to a JSON object for storage.
        /// </summary>
        /// <returns> A JSON object. </returns>
        public virtual SimpleJSONClass GetJSON()
        {
            SimpleJSONClass jsonStructure = new SimpleJSONClass();

            foreach (KeyValuePair <string, object> item in storeValues)
            {
                SimpleJSONNode node = MoBackUtils.MoBackTypedObjectToJSON(item.Value, columnTypeData[item.Key]);
                jsonStructure.Add(item.Key, node);
            }
            return(jsonStructure);
        }
コード例 #12
0
ファイル: MoBackFile.cs プロジェクト: SimonBellV/v0.93
        /// <summary>
        /// Deletes the file processor.
        /// </summary>
        /// <param name="responseJson">Response json.</param>
        private void DeleteFileProcessor(SimpleJSONNode responseJson)
        {
            string responseCode = responseJson["code"];

            if (responseCode == "1000")
            {
                Debug.Log("Reset MoBackFile object");
                // delete request success. Reset the local version of the MoBackFile.
                this.url  = null;
                this.Name = null;
                this.data = null;
            }
        }
コード例 #13
0
            /// <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);
            }
コード例 #14
0
            /// <summary>
            /// Gets all relation objects.
            /// </summary>
            /// <returns>The all relation objects.</returns>
            /// <param name="tableName">Table name.</param>
            /// <param name="objectID">Object I.</param>
            /// <param name="columnName">Column name.</param>
            public static MoBackRequest <List <MoBackRow> > GetAllRelationObjects(string tableName, string objectID, string columnName)
            {
                MoBackRequest <List <MoBackRow> > .ResponseProcessor getAllRelationObjectsProcessor = (SimpleJSONNode responseJson) =>
                {
                    SimpleJSONNode   relationJson  = responseJson[columnName];
                    List <MoBackRow> moBackObjects = MoBackRelation.MoBackRowFromRelationJSON(relationJson);
                    return(moBackObjects);
                };

                /*
                 * Sample uri: https://api.moback.com/objectmgr/api/collections/{tableName}/{objectID}?include={columnName}
                 */
                return(new MoBackRequest <List <MoBackRow> >(getAllRelationObjectsProcessor, MoBackURLS.TablesDefault + tableName + "/" + objectID + string.Format("?include={0}", columnName), HTTPMethod.GET));
            }
コード例 #15
0
ファイル: MoBackRow.cs プロジェクト: SimonBellV/v0.93
        /// <summary>
        /// Converts MoBackObject data to a JSON object for storage.
        /// </summary>
        /// <returns>A JSON object.</returns>
        public override SimpleJSONClass GetJSON()
        {
            SimpleJSONClass jsonStructure = new SimpleJSONClass();

            foreach (KeyValuePair <string, object> item in storeValues)
            {
                if (item.Key == "objectId" || item.Key == "createdAt" || item.Key == "updatedAt")
                {
                    continue; // No need to send auto-populated fields as part of JSON message
                }

                SimpleJSONNode node = MoBackUtils.MoBackTypedObjectToJSON(item.Value, columnTypeData[item.Key]);
                jsonStructure.Add(item.Key, node);
            }
            return(jsonStructure);
        }
コード例 #16
0
            /// <summary>
            /// Gets all relation pointers.
            /// </summary>
            /// <returns>The all relation pointers.</returns>
            /// <param name="tableName">Table name.</param>
            /// <param name="objectID">Object I.</param>
            /// <param name="columnName">Column name.</param>
            public static MoBackRequest <List <MoBackPointer> > GetAllRelationPointers(string tableName, string objectID, string columnName)
            {
                MoBackRequest <List <MoBackPointer> > .ResponseProcessor getAllRelationPointersProcessor = (SimpleJSONNode responseJson) =>
                {
                    SimpleJSONNode relationJson   = responseJson[columnName];
                    MoBackRelation moBackRelation = MoBackRelation.RelationFromMoBackJSON(relationJson);

                    if (moBackRelation != null)
                    {
                        return(moBackRelation.pointers.ToList());
                    }

                    return(null);
                };

                /*
                 * Sample uri: https://api.moback.com/objectmgr/api/collections/{tableName}/{objectID}
                 */
                return(new MoBackRequest <List <MoBackPointer> >(getAllRelationPointersProcessor, MoBackURLS.TablesDefault + tableName + "/" + objectID, HTTPMethod.GET));
            }
コード例 #17
0
        /// <summary>
        /// Runs the request.
        /// </summary>
        /// <param name="url"> The url to send a request to. </param>
        /// <param name="methodType"> A method type. </param>
        /// <param name="errorHandler"> A callback to handle errors. </param>
        /// <param name="callback"> A callback to handle a succesful request. Null by default. </param>
        /// <param name="query"> A set of query parameters. Null by default. </param>
        /// <param name="body"> A byte array. </param>
        /// <param name="contentType"> A content type of this request. If left the value null, the contentType will be "application/json". </param>
        public static void RunRequest(string url, HTTPMethod methodType, RequestErrorCallback errorHandler,
                                      RequestResultCallback callback = null, MoBackRequestParameters query = null,
                                      byte[] body = null, string contentType = null)
        {
            WebRequest request;

            if (query != null)
            {
                request = WebRequest.Create(url + query);
            }
            else
            {
                request = WebRequest.Create(url);
            }

            if (MoBack.MoBackAppSettings.loggingLevel >= MoBackAppSettings.LoggingLevel.VERBOSE)
            {
                Debug.Log(request.RequestUri.AbsoluteUri);
            }

            // Insert keys
            WebHeaderCollection collection = new WebHeaderCollection();

            collection.Add("X-Moback-Application-Key", MoBack.MoBackAppSettings.ApplicationID);
            collection.Add("X-Moback-Environment-Key", MoBack.MoBackAppSettings.EnvironmentKey);

            // Set session token if there is one.
            if (!string.IsNullOrEmpty(MoBack.MoBackAppSettings.SessionToken))
            {
                collection.Add("X-Moback-SessionToken-Key", MoBack.MoBackAppSettings.SessionToken);
            }

            request.Headers = collection;

            // Specify request as GET, POST, PUT, or DELETE
            request.Method = methodType.ToString();

            if (string.IsNullOrEmpty(contentType))
            {
                request.ContentType = "application/json";
            }
            else
            {
                request.ContentType = contentType;
            }
            // Specify request content length
            request.ContentLength = body == null ? 0 : body.Length;

            string responseFromServer = String.Empty;

            #if UNITY_ANDROID && !UNITY_EDITOR
            ServicePointManager.ServerCertificateValidationCallback = SSLValidator.Validator;
            #elif UNITY_EDITOR_WIN || (UNITY_STANDALONE_WIN && !UNITY_EDITOR_OSX)
            ServicePointManager.ServerCertificateValidationCallback = Validator;
            #endif

            try
            {
                // Open a stream and send the request to the remote server
                Stream dataStream = null;
                if (body != null)
                {
                    dataStream = request.GetRequestStream();
                    dataStream.Write(body, 0, body.Length);
                    dataStream.Close();
                }

                // Complete the request, wait for and accept any response
                WebResponse response = request.GetResponse();
                // Process response
                if (MoBackAppSettings.loggingLevel >= MoBackAppSettings.LoggingLevel.VERBOSE)
                {
                    Debug.Log(((HttpWebResponse)response).StatusDescription);
                }
                dataStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(dataStream);
                responseFromServer = reader.ReadToEnd();
                // Debug.Log("the json is "+responseFromServer.ToString());
                // Close all streams
                reader.Close();
                response.Close();
            }
            catch (WebException webException)
            {
                HttpWebResponse errorResponse = webException.Response as HttpWebResponse;
                if (errorResponse != null)
                {
                    if (MoBackAppSettings.loggingLevel >= MoBackAppSettings.LoggingLevel.WARNINGS)
                    {
                        Debug.LogWarning(string.Format("Network Request Error {0}: {1}.\nFull Exception: {2}", (int)errorResponse.StatusCode, errorResponse.StatusCode.ToString(), MoBackError.FormatException(webException)));
                    }
                    errorHandler(webException, webException.Status, errorResponse.StatusCode, webException.Message);
                }
                else
                {
                    if (MoBackAppSettings.loggingLevel >= MoBackAppSettings.LoggingLevel.WARNINGS)
                    {
                        Debug.LogWarning(string.Format("Network Request Failed with message {0}.\nFull exception: {1}", webException.Message, MoBackError.FormatException(webException)));
                    }
                    errorHandler(webException, webException.Status, null, webException.Message);
                }
                return;
            }

            if (MoBackAppSettings.loggingLevel >= MoBackAppSettings.LoggingLevel.VERBOSE)
            {
                Debug.Log(responseFromServer);
            }
            if (callback != null)
            {
                SimpleJSONNode responseAsJSON = SimpleJSONNode.Parse(responseFromServer);

                callback(responseFromServer, responseAsJSON);
            }
        }
コード例 #18
0
ファイル: MoBackFile.cs プロジェクト: SimonBellV/v0.93
 /// <summary>
 /// A callback when UploadFile request is completed.
 /// </summary>
 /// <param name="responseJson">Response json.</param>
 private void UploadFileProcessor(SimpleJSONNode responseJson)
 {
     this.Name = responseJson["name"];
     this.url  = responseJson["url"];
 }
コード例 #19
0
ファイル: MoBackDate.cs プロジェクト: SimonBellV/v0.93
 public static DateTime DateFromMoBackJSON(SimpleJSONNode dateWrapper)
 {
     return(DateFromString(dateWrapper["iso"]));
 }
コード例 #20
0
        public static object MoBackTypedObjectFromJSON(SimpleJSONNode node, out MoBackValueType dataType)
        {
            if (MoBackAppSettings.doublePrecisionFloatingPoint && node.valueType == typeof(double))
            {
                dataType = MoBackValueType.Number;
                return(new MoBackNumber(node.AsDouble));
            }
            else if (!MoBackAppSettings.doublePrecisionFloatingPoint && node.valueType == typeof(float))
            {
                dataType = MoBackValueType.Number;
                return(new MoBackNumber(node.AsFloat));
            }
            else if (node.valueType == typeof(int))
            {
                dataType = MoBackValueType.Number;
                return(new MoBackNumber(node.AsInt));
            }
            else if (node.valueType == typeof(bool))
            {
                dataType = MoBackValueType.Boolean;
                return(node.AsBool);
            }
            else if (node.valueType == typeof(string))
            {
                dataType = MoBackValueType.String;
                return(node.Value);
            }
            else if (node.valueType == typeof(SimpleJSONClass))
            {
                SimpleJSONClass nestedClass = (SimpleJSONClass)node;
                if (nestedClass.dict.ContainsKey("__type"))
                {
                    //is a special type, treat accordingly
                    switch (nestedClass["__type"].Value)
                    {
                    case "Date":
                        dataType = MoBackValueType.Date;
                        return(MoBackDate.DateFromMoBackJSON(node));

                    case "Pointer":
                        dataType = MoBackValueType.Pointer;
                        return(MoBackPointer.PointerFromMoBackJSON(node));

                    case "Relation":
                        dataType = MoBackValueType.Relation;
                        return(MoBackRelation.RelationFromMoBackJSON(node));

                    case "File":
                        dataType = MoBackValueType.File;
                        return(MoBackFile.FromJSON(node));

                    default:
                        //not familiar with this special type; fall back to parsing as regular object
                        if (MoBack.MoBackAppSettings.loggingLevel >= MoBack.MoBackAppSettings.LoggingLevel.WARNINGS)
                        {
                            Debug.LogWarning("Unrecognized MoBack reserved type '" + nestedClass["__type"] + "'.");
                        }
                        dataType = MoBackValueType.MoBackObject;
                        return(MoBackObject.FromJSON(nestedClass));
                    }
                }
                else
                {
                    dataType = MoBackValueType.MoBackObject;
                    return(MoBackObject.FromJSON(nestedClass));
                }
            }
            else if (node.valueType == typeof(SimpleJSONArray))
            {
                dataType = MoBackValueType.Array;
                return(MoBackArray.FromJSON((SimpleJSONArray)node));
            }

            throw new ArgumentException("JSON data type not supported in some manner.", "SimpleJsonNode node");
        }
コード例 #21
0
 // Basically the callbacks for processing results, with particular regards to the current table
 #region JSONResponseProcessors
 /// <summary>
 /// Fetch the column descriptions_processor.
 /// </summary>
 /// <param name="jsonObject">JSON object.</param>
 private void FetchColumnDescriptions_processor(SimpleJSONNode jsonObject)
 {
     // Stub
 }
コード例 #22
0
 /// <summary>
 /// Gets the object processor.
 /// </summary>
 /// <returns>The a MoBackRow converted from a JSON object.</returns>
 /// <param name="jsonObject">A JSON object.</param>
 private MoBackRow GetObject_processor(SimpleJSONNode jsonObject)
 {
     return(MoBackRow.FromJSON(jsonObject as SimpleJSONClass, table.TableName));
 }
コード例 #23
0
        /// <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);
                }
            }
        }