Exemple #1
0
        /// <summary>
        /// Apply the merge as a full collection replacement; there is <b>no</b> way to detect changes or perform partial property update.
        /// </summary>
        private static JsonEntityMergeResult MergeApplyComplexItems(JsonEntityMergeArgs args, IPropertyReflector pr, JProperty jp, object entity)
        {
            var hasError = false;
            var lo       = new List <object>();
            var ier      = pr.GetItemEntityReflector();

            foreach (var ji in jp.Values())
            {
                if (ji.Type == JTokenType.Null)
                {
                    lo.Add(null);
                    continue;
                }

                var ival = pr.ComplexTypeReflector.CreateItemValue();
                if (MergeApply(args, ier, ji, ival) == JsonEntityMergeResult.Error)
                {
                    hasError = true;
                }
                else
                {
                    lo.Add(ival);
                }
            }

            if (hasError)
            {
                return(JsonEntityMergeResult.Error);
            }

            pr.ComplexTypeReflector.SetValue(entity, lo);
            return(JsonEntityMergeResult.SuccessWithChanges);
        }
Exemple #2
0
        /// <summary>
        /// Apply the merge from the json to the entity value as a more complex type.
        /// </summary>
        private static JsonEntityMergeResult MergeApplyComplex(JsonEntityMergeArgs args, IPropertyReflector pr, JProperty jp, object entity)
        {
            if (jp.Value.Type == JTokenType.Null)
            {
                return(pr.SetValue(entity, null) ? JsonEntityMergeResult.SuccessWithChanges : JsonEntityMergeResult.SuccessNoChanges);
            }

            // Update the sub-entity.
            if (pr.ComplexTypeReflector !.ComplexTypeCode == ComplexTypeCode.Object)
            {
                if (jp.Value.Type != JTokenType.Object)
                {
                    return(args.Log(MessageItem.CreateMessage(jp.Path, MessageType.Error, $"The JSON token is malformed and could not be parsed.")));
                }

                var hasChanged = true;
                var current    = pr.PropertyExpression.GetValue(entity);
                if (current == null)
                {
                    current = pr.NewValue(entity).value;
                }
                else
                {
                    hasChanged = false;
                }

                var mr = MergeApply(args, pr.GetEntityReflector() !, jp.Value, current !);
                return(mr == JsonEntityMergeResult.SuccessNoChanges ? (hasChanged ? JsonEntityMergeResult.SuccessWithChanges : JsonEntityMergeResult.SuccessNoChanges) : mr);
            }
Exemple #3
0
        /// <summary>
        /// Apply the merge from the json to the entity value as a more complex type.
        /// </summary>
        private static JsonEntityMergeResult MergeApplyComplex(JsonEntityMergeArgs args, IPropertyReflector pr, JProperty jp, object entity)
        {
            if (jp.Value.Type == JTokenType.Null)
            {
                return(pr.SetValue(entity, null) ? JsonEntityMergeResult.SuccessWithChanges : JsonEntityMergeResult.SuccessNoChanges);
            }

            // Update the sub-entity.
            if (pr.ComplexTypeReflector.ComplexTypeCode == ComplexTypeCode.Object)
            {
                if (jp.Value.Type != JTokenType.Object)
                {
                    return(args.Log(MessageItem.CreateMessage(jp.Path, MessageType.Error, $"The JSON token is malformed and could not be parsed.")));
                }

                var hasChanged = true;
                var current    = pr.PropertyExpression.GetValue(entity);
                if (current == null)
                {
                    current = pr.NewValue(entity).value;
                }
                else
                {
                    hasChanged = false;
                }

                var mr = MergeApply(args, pr.GetEntityReflector(), jp.Value, current);
                return(mr == JsonEntityMergeResult.SuccessNoChanges ? (hasChanged ? JsonEntityMergeResult.SuccessWithChanges : JsonEntityMergeResult.SuccessNoChanges) : mr);
            }
            else
            {
                // Ensure we are dealing with an array.
                if (jp.Value.Type != JTokenType.Array)
                {
                    return(args.Log(MessageItem.CreateMessage(jp.Path, MessageType.Error, $"The JSON token is malformed and could not be parsed.")));
                }

                // Where empty array then update as such.
                if (!jp.Value.HasValues)
                {
                    return(UpdateArrayValue(args, pr, entity, (IEnumerable)pr.PropertyExpression.GetValue(entity), (IEnumerable)pr.ComplexTypeReflector.CreateValue()));
                }

                // Handle array with primitive types.
                if (!pr.ComplexTypeReflector.IsItemComplexType)
                {
                    var lo = new List <object>();
                    foreach (var iv in jp.Value.Values())
                    {
                        lo.Add(iv.ToObject(pr.ComplexTypeReflector.ItemType));
                    }

                    return(UpdateArrayValue(args, pr, entity, (IEnumerable)pr.PropertyExpression.GetValue(entity), (IEnumerable)pr.ComplexTypeReflector.CreateValue(lo)));
                }

                // Finally, handle array with complex entity items.
                return((pr.Tag == null) ? MergeApplyComplexItems(args, pr, jp, entity) : MergeApplyUniqueKeyItems(args, pr, jp, entity));
            }
        }
Exemple #4
0
        /// <summary>
        /// Updates the array value.
        /// </summary>
        private static JsonEntityMergeResult UpdateArrayValue(JsonEntityMergeArgs args, IPropertyReflector pr, object entity, IEnumerable curVal, IEnumerable newVal)
        {
            if (pr.ComplexTypeReflector.CompareSequence(newVal, curVal))
            {
                return(JsonEntityMergeResult.SuccessNoChanges);
            }

            pr.ComplexTypeReflector.SetValue(entity, newVal);
            return(JsonEntityMergeResult.SuccessWithChanges);
        }
Exemple #5
0
        /// <summary>
        /// Apply the merge from the json to the entity value.
        /// </summary>
        private static JsonEntityMergeResult MergeApply(JsonEntityMergeArgs args, IEntityReflector er, JToken json, object entity)
        {
            if (!json.HasValues)
            {
                return(JsonEntityMergeResult.SuccessNoChanges);
            }

            bool hasError   = false;
            bool hasChanged = false;

            foreach (var jp in json.Children <JProperty>())
            {
                // Get the corresponding property from the entity.
                var pr = er.GetJsonProperty(jp.Name);
                if (pr == null)
                {
                    if (args.Log(MessageItem.CreateMessage(jp.Path, MessageType.Warning, $"The JSON path is not valid for the entity.")) == JsonEntityMergeResult.Error)
                    {
                        hasError = true;
                    }

                    continue;
                }

                // Handle the intrinsic types.
                if (!pr.IsComplexType)
                {
                    if (jp.Value.Type == JTokenType.Array || jp.Value.Type == JTokenType.Object)
                    {
                        return(args.Log(MessageItem.CreateMessage(jp.Path, MessageType.Error, $"The JSON token is malformed and could not be parsed.")));
                    }

                    try
                    {
                        if (pr.SetValueFromJToken(entity, jp.Value))
                        {
                            hasChanged = true;
                        }
                    }
                    catch (FormatException fex)
                    {
                        return(args.Log(MessageItem.CreateMessage(jp.Path, MessageType.Error, $"The JSON token is malformed: {fex.Message}")));
                    }
                    catch (Exception)
                    {
                        throw;
                    }

                    continue;
                }

                // Handle complex types (objects, arrays, collections, etc).
                switch (MergeApplyComplex(args, pr, jp, entity))
                {
                case JsonEntityMergeResult.SuccessWithChanges:
                    hasChanged = true;
                    break;

                case JsonEntityMergeResult.Error:
                    hasError = true;
                    break;
                }
            }

            return(hasError ? JsonEntityMergeResult.Error : hasChanged?JsonEntityMergeResult.SuccessWithChanges : JsonEntityMergeResult.SuccessNoChanges);
        }
Exemple #6
0
        /// <summary>
        /// Apply the merge using the UniqueKey to match items between JSON and entity.
        /// </summary>
        private static JsonEntityMergeResult MergeApplyUniqueKeyItems(JsonEntityMergeArgs args, IPropertyReflector pr, JProperty jp, object entity)
        {
            var hasError   = false;
            var hasChanges = false;
            var count      = 0;
            var ukc        = (UniqueKeyConfig)pr.Tag;
            var lo         = new List <object>();
            var ier        = pr.GetItemEntityReflector();

            // Determine the unique key for a comparison.
            var ukpr = ukc.GetPropertyReflectors(ier);

            // Get the current value to update.
            var current = (IEnumerable)pr.PropertyExpression.GetValue(entity);

            if (current == null)
            {
                hasChanges = true;
            }

            // Merge each item into the new collection.
            foreach (var ji in jp.Values())
            {
                // Check not null.
                if (ji.Type != JTokenType.Object)
                {
                    hasError = true;
                    args.Log(MessageItem.CreateErrorMessage(ji.Path, "The JSON token must be an object where Unique Key value(s) are required."));
                    continue;
                }

                // Generate the unique key from the json properties.
                bool skip = false;
                var  uk   = new object[ukpr.Length];
                for (int i = 0; i < ukc.Properties.Length; i++)
                {
                    var jk = ji[ukpr[i].JsonName];
                    if (jk == null)
                    {
                        hasError = skip = true;
                        args.Log(MessageItem.CreateErrorMessage(ji.Path, $"The JSON object must specify the '{ukpr[i].JsonName}' token as required for the unique key."));
                        break;
                    }

                    try
                    {
                        uk[i] = ukpr[i].GetJtokenValue(jk);
                    }
                    catch (FormatException fex)
                    {
                        hasError = skip = true;
                        args.Log(MessageItem.CreateMessage(jk.Path, MessageType.Error, $"The JSON token is malformed: {fex.Message}"));
                        break;
                    }
                    catch (Exception)
                    {
                        throw;
                    }
                }

                if (skip)
                {
                    continue;
                }

                // Get existing by unique key.
                var uniqueKey = new UniqueKey(uk);
                var item      = current == null ? null : ukc.IsEntityBaseCollection
                    ? ((IEntityBaseCollection)current).GetByUniqueKey(uniqueKey)
                    : current.OfType <EntityBase>().FirstOrDefault(x => uniqueKey.Equals(x.UniqueKey));

                // Create new if not found.
                if (item == null)
                {
                    hasChanges = true;
                    item       = pr.ComplexTypeReflector.CreateItemValue();
                }

                // Update.
                count++;
                var mr = MergeApply(args, ier, ji, item);
                if (mr == JsonEntityMergeResult.Error)
                {
                    hasError = true;
                }
                else
                {
                    if (mr == JsonEntityMergeResult.SuccessWithChanges)
                    {
                        hasChanges = true;
                    }

                    lo.Add(item);
                }
            }

            if (hasError)
            {
                return(JsonEntityMergeResult.Error);
            }

            // Confirm nothing was deleted (only needed where nothing changed so far).
            if (!hasChanges && count == (ukc.IsEntityBaseCollection ? ((IEntityBaseCollection)current).Count : current.OfType <EntityBase>().Count()))
            {
                return(JsonEntityMergeResult.SuccessNoChanges);
            }

            pr.ComplexTypeReflector.SetValue(entity, lo);
            return(JsonEntityMergeResult.SuccessWithChanges);
        }
Exemple #7
0
        /// <summary>
        /// Merges the JSON content into the <paramref name="value"/>.
        /// </summary>
        /// <typeparam name="TEntity">The entity <see cref="Type"/>.</typeparam>
        /// <param name="json">The <see cref="JToken"/> to merge.</param>
        /// <param name="value">The value to merge into.</param>
        /// <param name="args">The <see cref="JsonEntityMergeArgs"/>.</param>
        /// <returns><c>true</c> indicates that a least one change was made to the value; otherwise, <c>false</c>.</returns>
        public static JsonEntityMergeResult Merge <TEntity>(JToken json, TEntity value, JsonEntityMergeArgs args = null)
        {
            Check.NotNull(json, nameof(json));
            Check.NotNull(value, nameof(value));
            args = args ?? new JsonEntityMergeArgs();

            if (json.Type != JTokenType.Object)
            {
                return(args.Log(MessageItem.CreateMessage(json.Path, MessageType.Error, $"The JSON document is malformed and could not be parsed.")));
            }

            return(MergeApply(args, _erArgs.GetReflector(typeof(TEntity)), json, value));
        }