public static async Task <Customer> CreateCustomer(IClient client, IDraft <Customer> buildDraft)
        {
            var signInResult = (CustomerSignInResult)await client
                               .ExecuteAsync(new SignUpCustomerCommand(buildDraft));

            return(signInResult.Customer);
        }
Beispiel #2
0
        /// <summary>
        /// Checks the arguments of the generator.
        /// </summary>
        /// <param name="draft">The draft.</param>
        /// <param name="basePath">The base path.</param>
        /// <param name="patches">The patches collection to add to.</param>
        /// <param name="inversePatches">The inverse patches to add to.</param>
        /// <returns>The adjusted base path.</returns>
        protected static string CheckArgumentsAndNormalizePath(IDraft draft, string?basePath, JsonPatchDocument patches, JsonPatchDocument inversePatches)
        {
            if (draft is null)
            {
                throw new ArgumentNullException(nameof(draft));
            }

            basePath = $"/{(basePath ?? string.Empty).Trim('/')}";

            if (patches is null)
            {
                throw new ArgumentNullException(nameof(patches));
            }

            if (inversePatches is null)
            {
                throw new ArgumentNullException(nameof(inversePatches));
            }

            if (draft.DraftState == null)
            {
                throw new PatchGenerationException(draft, "The draft has no draft state.");
            }

            return(basePath);
        }
        /// <summary>
        /// Generates JSON Patches for a draft for changes and inverse changes and
        /// adds them to the specified JsonPatchDocuments.
        /// </summary>
        /// <param name="draft">The draft to process.</param>
        /// <param name="basePath">The base path for the patches.</param>
        /// <param name="patches">The patches.</param>
        /// <param name="inversePatches">The inverse patches.</param>
        public void Generate(IDraft draft, string?basePath, JsonPatchDocument patches, JsonPatchDocument inversePatches)
        {
            basePath = CheckArgumentsAndNormalizePath(draft, basePath, patches, inversePatches);

            // nothing to do.
            if (!draft.DraftState !.Changed)
            {
                return;
            }

            object source = draft.DraftState.GetOriginal <object>();

            if (source is null)
            {
                throw new PatchGenerationException(draft, "The draft has no original state.");
            }

            IDictionary draftDictionary  = (IDictionary)draft;
            IDictionary sourceDictionary = draft.DraftState.GetOriginal <IDictionary>();

            if (sourceDictionary is null)
            {
                throw new PatchGenerationException(draft, "The draft has no original dictionary state.");
            }

            // Equals function that compares both values, but also checks whether the newValue might be just a
            // draft of the old value.
            bool DraftOrOriginalEquals(object oldValue, object newValue) =>
            Equals(oldValue, newValue) || draft.DraftState.Scope.HasPatches.Contains(newValue) ||
            (newValue is IDraft newDraft && newDraft.DraftState != null && Equals(oldValue, newDraft.DraftState !.GetOriginal <object>()));

            foreach (DictionaryEntry entry in sourceDictionary)
            {
                string key = entry.Key.ToString();

                if (!draftDictionary.Contains(key))
                {
                    patches.Remove(basePath.PathJoin(key));
                    inversePatches.Add(basePath.PathJoin(key), sourceDictionary[entry.Key]);
                }
                else if (!DraftOrOriginalEquals(sourceDictionary[entry.Key], draftDictionary[entry.Key]))
                {
                    patches.Replace(basePath.PathJoin(key), entry.Value);
                    inversePatches.Replace(basePath.PathJoin(key), sourceDictionary[entry.Key]);
                }
            }

            foreach (DictionaryEntry entry in draftDictionary)
            {
                string key = entry.Key.ToString();

                if (!sourceDictionary.Contains(entry.Key))
                {
                    patches.Add(basePath.PathJoin(key), entry.Value);
                    inversePatches.Remove(basePath.PathJoin(key));
                }
            }
        }
Beispiel #4
0
 public static void Check(IDraft draft)
 {
     foreach (PropertyInfo prop in draft.GetType().GetProperties())
     {
         if (prop.GetValue(draft) == null)
         {
             throw new PropertyNotFilledException(string.Format(propertyNotFilled, prop.Name), prop.Name);
         }
     }
 }
        /// <summary>
        /// Generates JSON Patches for a draft for changes and inverse changes and
        /// adds them to the specified JsonPatchDocuments.
        /// </summary>
        /// <param name="draft">The draft to process.</param>
        /// <param name="basePath">The base path for the patches.</param>
        /// <param name="patches">The patches.</param>
        /// <param name="inversePatches">The inverse patches.</param>
        public void Generate(IDraft draft, string?basePath, JsonPatchDocument patches, JsonPatchDocument inversePatches)
        {
            basePath = CheckArgumentsAndNormalizePath(draft, basePath, patches, inversePatches);

            // nothing to do.
            if (!draft.DraftState !.Changed)
            {
                return;
            }

            object source = draft.DraftState.GetOriginal <object>();

            if (source is null)
            {
                throw new PatchGenerationException(draft, "The draft has no original state.");
            }

            if (!(draft is IPropertyAccessors draftProperties))
            {
                throw new PatchGenerationException(draft, "The draft has no property accessors.");
            }

            if (!(source is IPropertyAccessors sourceProperties))
            {
                throw new PatchGenerationException(draft, "The source has no property accessors.");
            }

            foreach (string propertyName in draftProperties.PublicPropertyGetters.Keys)
            {
                object?oldValue = sourceProperties.PublicPropertyGetters[propertyName]();
                object?newValue = draftProperties.PublicPropertyGetters[propertyName]();

                // if the newValue is a draft and points to the same original, it's actually the same object in
                // a mutable sense and the patches will reflect that. Otherwise we would end up with very large patches
                // of the entire tree.
                if (Equals(oldValue, newValue) || draft.DraftState.Scope.HasPatches.Contains(newValue) ||
                    (newValue is IDraft newDraft && newDraft.DraftState != null && Equals(oldValue, newDraft.DraftState !.GetOriginal <object>())))
                {
                    continue;
                }
 public static async Task <T> CreateResource <T>(IClient client, IDraft <T> buildDraft) where T : Resource <T>
 {
     return(await client
            .ExecuteAsync(new CreateCommand <T>(buildDraft)));
 }
 public SignUpCustomerCommand(IDraft <Customer> entity)
     : base(entity)
 {
 }
 public UpsertCommand(IDraft <T> entity)
 {
     this.Entity = entity;
 }
 public UpsertCommand(IDraft <T> entity, IAdditionalParameters <T> additionalParameters)
 {
     this.Entity = entity;
     this.AdditionalParameters = additionalParameters;
 }
Beispiel #10
0
        /// <summary>
        /// Generates JSON Patches for a draft for changes and inverse changes and
        /// adds them to the specified JsonPatchDocuments.
        /// </summary>
        /// <param name="draft">The draft to process.</param>
        /// <param name="basePath">The base path for the patches.</param>
        /// <param name="patches">The patches.</param>
        /// <param name="inversePatches">The inverse patches.</param>
        public void Generate(IDraft draft, string?basePath, JsonPatchDocument patches, JsonPatchDocument inversePatches)
        {
            basePath = CheckArgumentsAndNormalizePath(draft, basePath, patches, inversePatches);

            // nothing to do.
            if (!draft.DraftState !.Changed)
            {
                return;
            }

            IList draftList  = (IList)draft;
            IList sourceList = draft.DraftState.GetOriginal <IList>();

            if (sourceList is null)
            {
                throw new PatchGenerationException(draft, "The draft has no original list state.");
            }

            int commonHead = 0;
            int commonTail = 0;

            // Equals function that compares both values, but also checks whether the newValue might be just a
            // draft of the old value.
            bool DraftOrOriginalEquals(object oldValue, object newValue) =>
            Equals(oldValue, newValue) || draft.DraftState.Scope.HasPatches.Contains(newValue) ||
            (newValue is IDraft newDraft && newDraft.DraftState != null && Equals(oldValue, newDraft.DraftState.GetOriginal <object>()));

            // Find common head
            while (commonHead < sourceList.Count &&
                   commonHead < draftList.Count &&
                   DraftOrOriginalEquals(sourceList[commonHead], draftList[commonHead]))
            {
                commonHead++;
            }

            // Find common tail
            while (commonTail + commonHead < sourceList.Count &&
                   commonTail + commonHead < draftList.Count &&
                   DraftOrOriginalEquals(sourceList[sourceList.Count - 1 - commonTail], draftList[draftList.Count - 1 - commonTail]))
            {
                commonTail++;
            }

            if (commonHead + commonTail == draftList.Count)
            {
                // Trivial case, a block (one or more consecutive items) was removed
                // reverse the order so that there is never a problem with different implementations
                // (patch atomicity v.s. operation atomicity).
                for (int index = sourceList.Count - commonTail - 1; index >= commonHead; --index)
                {
                    patches.Remove(basePath.PathJoin($"{index}"));
                    inversePatches.Add(basePath.PathJoin($"{(index < draftList.Count ? index.ToString() : "-")}"), sourceList[index]);
                }

                return;
            }

            if (commonHead + commonTail == sourceList.Count)
            {
                // Trivial case, a block (one or more consecutive items) was added
                for (int index = commonHead; index < draftList.Count - commonTail; ++index)
                {
                    patches.Add(basePath.PathJoin($"{(index < sourceList.Count ? index.ToString() : "-")}"), draftList[index]);
                    inversePatches.Remove(basePath.PathJoin($"{index}"));
                }

                return;
            }

            // complex case, use lcs to determine list operations.
            var lcs = this.longestCommonSubsequence.Get(
                sourceList,
                draftList,
                commonHead,
                sourceList.Count - commonTail - commonHead,
                commonHead,
                draftList.Count - commonTail - commonHead,
                DraftOrOriginalEquals);

            int lcsIndex = lcs.Length - 1;

            // reverse the order so that there is never a problem with different implementations
            // (patch atomicity v.s. operation atomicity).
            for (int index = sourceList.Count - commonTail - 1; index >= commonHead; --index)
            {
                if (lcsIndex < 0 || !Equals(sourceList[index], lcs[lcsIndex]))
                {
                    patches.Remove(basePath.PathJoin($"{index}"));
                    inversePatches.Add(basePath.PathJoin($"{(index < draftList.Count ? index.ToString() : "-")}"), sourceList[index]);
                }
                else
                {
                    --lcsIndex;
                }
            }

            lcsIndex = 0;

            for (int index = commonHead; index < draftList.Count - commonTail; ++index)
            {
                if (lcsIndex >= lcs.Length || !DraftOrOriginalEquals(lcs[lcsIndex], draftList[index]))
                {
                    patches.Add(basePath.PathJoin($"{(index < lcs.Length ? index.ToString() : "-")}"), draftList[index]);
                    inversePatches.Remove(basePath.PathJoin($"{index}"));
                }
                else
                {
                    ++lcsIndex;
                }
            }
        }
Beispiel #11
0
 public CustomObjectUpsertCommand(IDraft <CustomObject <T> > entity)
     : base(entity)
 {
 }
Beispiel #12
0
 public SignUpCommand(IDraft <T> entity)
 {
     this.Entity = entity;
 }
Beispiel #13
0
 public DraftController(IDraft draft)
 {
     _draft = draft;
 }
 public static async Task <CustomObject <T> > CreateCustomObject <T>(IClient client,
                                                                     IDraft <CustomObject <T> > buildDraft)
 {
     return(await client
            .ExecuteAsync(new CustomObjectUpsertCommand <T>(buildDraft)));
 }
 public CreateCommand(IDraft <T> entity)
 {
     this.Entity = entity;
 }