Example #1
0
        /// <summary>
        /// Apply the changes in this diff to the given target
        /// </summary>
        public ApplyAction ApplyTo(DatonDef datondef, Persiston target)
        {
            if (MainTable.Count == 0)
            {
                return(ApplyAction.NoChanges);
            }

            if (datondef.MultipleMainRows)
            {
                bool anyChanges = false;
                var  field      = target.GetType().GetField(datondef.MainTableDef.Name);
                var  targetList = Utils.CreateOrGetFieldValue <IList>(target, field);
                if (targetList == null)
                {
                    throw new Exception($"Row class {target.GetType().Name} must include field member {datondef.MainTableDef.Name}");
                }
                foreach (var source in MainTable)
                {
                    anyChanges |= ApplyDiffRowToList(datondef.MainTableDef, source, targetList);
                }
                return(anyChanges ? ApplyAction.Changes : ApplyAction.NoChanges);
            }
            else
            {
                //handle top level edge cases to ensure the key matches the new/modified/delete status of the top row
                if (MainTable.Count != 1)
                {
                    throw new Exception("For single-main-table persistons the diff may only include the single main row");
                }
                bool diffIsNewRow = MainTable[0].Kind == DiffKind.NewRow;
                if (diffIsNewRow != target.Key.IsNew)
                {
                    throw new Exception("The key specifies a new row but the diff does not indicate a new row; or the key specifies modified/delete but the diff indicates a new row");
                }
                var source = MainTable[0];
                if (source.Kind == DiffKind.DeletedRow)
                {
                    return(ApplyAction.PersistonDeleted);
                }

                //reached here, so its a plain update of the single row; primary key ignored
                bool anyChanges = false;
                foreach (string colName in source.Columns.Keys)
                {
                    anyChanges |= SetValue(datondef.MainTableDef, source, colName, target);
                }

                //child tables
                anyChanges |= ApplyChildTables(source, target, target.GetType());

                return(anyChanges ? ApplyAction.Changes : ApplyAction.NoChanges);
            }
        }
Example #2
0
        /// <summary>
        /// Validate the persiston and populate Errors in this instance with the problems found.
        /// </summary>
        public async Task ValidatePersiston(DatonDef datondef, Persiston daton)
        {
            Errors = new List <string>();

            //built-in validation
            var r = RecurPoint.FromDaton(datondef, daton);

            if (r is RowRecurPoint rr)
            {
                Validate(rr);
            }
            else if (r is TableRecurPoint rt)
            {
                Validate(rt);
            }

            //custom validation
            await daton.Validate(User, message => Errors.Add(message));
        }
Example #3
0
        /// <summary>
        /// Save persiston to database
        /// </summary>
        /// <param name="pristineDaton">null or the version before the diff was applied</param>
        /// <param name="modifiedDaton">the validated final version</param>
        /// <param name="diff">the difference between pristine and modified, which is what this method inspects to make the changes</param>
        public virtual async Task Save(IDbConnection db, IUser user, Persiston pristineDaton, Persiston modifiedDaton, PersistonDiff diff)
        {
            //called for each row in traversal; return true to recurse over children
            async Task <(object, bool)> rowCallback(RowChangingData cdata)
            {
                if (cdata.DiffRow.Kind == DiffKind.DeletedRow)
                {
                    await DeleteRowWithCascade(db, cdata.TableDef, cdata.PristineRow);

                    return(null, false);  //don't recur to children of deleted row
                }
                object newpk = await InsertUpdateRow(db, cdata);

                return(newpk, true);
            }

            var tdata = new TraversalData
            {
                ParentKey    = null,
                TableDef     = diff.DatonDef.MainTableDef,
                DiffRowList  = diff.MainTable,
                PristineList = null,
                ModifiedList = null,
                ProcessRowF  = rowCallback
            };

            if (diff.DatonDef.MultipleMainRows)
            {
                var mainListField = diff.DatonDef.Type.GetField(tdata.TableDef.Name);
                tdata.PristineList = mainListField.GetValue(pristineDaton) as IList;
                tdata.ModifiedList = mainListField.GetValue(modifiedDaton) as IList;
                await TraverseDiffList(tdata, null, null);
            }
            else
            {
                await TraverseDiffList(tdata, pristineDaton, modifiedDaton);
            }
        }