public static void AuditAutoCrudMetadataFilter(AutoCrudMetadata meta) { foreach (var applyAttr in meta.AutoApplyAttrs) { switch (applyAttr.Name) { case Behavior.AuditQuery: meta.Add(new AutoFilterAttribute( QueryTerm.Ensure, nameof(AuditBase.DeletedDate), SqlTemplate.IsNull)); break; case Behavior.AuditCreate: case Behavior.AuditModify: if (applyAttr.Name == Behavior.AuditCreate) { meta.Add(new AutoPopulateAttribute(nameof(AuditBase.CreatedDate)) { Eval = "utcNow" }); meta.Add(new AutoPopulateAttribute(nameof(AuditBase.CreatedBy)) { Eval = "userAuthName" }); } meta.Add(new AutoPopulateAttribute(nameof(AuditBase.ModifiedDate)) { Eval = "utcNow" }); meta.Add(new AutoPopulateAttribute(nameof(AuditBase.ModifiedBy)) { Eval = "userAuthName" }); break; case Behavior.AuditDelete: case Behavior.AuditSoftDelete: if (applyAttr.Name == Behavior.AuditSoftDelete) { meta.SoftDelete = true; } meta.Add(new AutoPopulateAttribute(nameof(AuditBase.DeletedDate)) { Eval = "utcNow" }); meta.Add(new AutoPopulateAttribute(nameof(AuditBase.DeletedBy)) { Eval = "userAuthName" }); break; } } }
/// <summary> /// Deletes entry into Table /// </summary> public virtual async Task <object> Delete <Table>(IDeleteDb <Table> dto) { using var db = AutoQuery.GetDb <Table>(Request); using (Profiler.Current.Step("AutoQuery.Delete")) { var response = await ExecAndReturnResponseAsync <Table>(dto, db, async ctx => { var dtoValues = ResolveDtoValues(dto, skipDefaults: true); //Should have at least 1 non-default filter if (dtoValues.Count == 0) { throw new NotSupportedException($"'{dto.GetType().Name}' did not contain any filters"); } var meta = AutoCrudMetadata.Create(dto.GetType()); var pkFieldDef = meta.ModelDef.PrimaryKey; var idValue = pkFieldDef != null && dtoValues.TryGetValue(pkFieldDef.Name, out var oId) ? oId : null; // Should only update a Single Row if (GetAutoFilterExpressions(db, dto, dtoValues, Request, out var expr, out var exprParams)) { //If there were Auto Filters, construct filter expression manually by adding any remaining DTO values foreach (var entry in dtoValues) { var fieldDef = meta.ModelDef.GetFieldDefinition(entry.Key); if (fieldDef == null) { throw new NotSupportedException($"Unknown '{entry.Key}' Field in '{dto.GetType().Name}' IDeleteDb<{typeof(Table).Name}> Request"); } if (expr.Length > 0) { expr += " AND "; } var quotedColumn = db.GetDialectProvider().GetQuotedColumnName(meta.ModelDef, fieldDef); expr += quotedColumn + " = {" + exprParams.Count + "}"; exprParams.Add(entry.Value); } var q = db.From <Table>(); q.Where(expr, exprParams.ToArray()); return(new ExecValue(idValue, await db.DeleteAsync(q))); }
public static void AuditAutoCrudMetadataFilter(AutoCrudMetadata meta) { var applyAttrs = meta.AutoApplyAttrs; if (applyAttrs.IsEmpty()) { return; } var hasAuditQuery = applyAttrs.Any(x => x.Name == Behavior.AuditQuery); var hasAuditCreate = applyAttrs.Any(x => x.Name == Behavior.AuditCreate); var hasAuditModify = applyAttrs.Any(x => x.Name == Behavior.AuditModify); var hasAuditSoftDelete = applyAttrs.Any(x => x.Name == Behavior.AuditSoftDelete); if (hasAuditQuery) { meta.AddFilterAttribute(new AutoFilterAttribute( QueryTerm.Ensure, nameof(AuditBase.DeletedDate), SqlTemplate.IsNull)); } if (!hasAuditCreate && !hasAuditModify && !hasAuditSoftDelete) { return; } meta.PopulateAttrs ??= new List <AutoPopulateAttribute>(); if (hasAuditCreate) { meta.PopulateAttrs.Add(new AutoPopulateAttribute(nameof(AuditBase.CreatedDate)) { Eval = "utcNow" }); meta.PopulateAttrs.Add(new AutoPopulateAttribute(nameof(AuditBase.CreatedBy)) { Eval = "userAuthName" }); } if (hasAuditCreate || hasAuditModify) { meta.PopulateAttrs.Add(new AutoPopulateAttribute(nameof(AuditBase.ModifiedDate)) { Eval = "utcNow" }); meta.PopulateAttrs.Add(new AutoPopulateAttribute(nameof(AuditBase.ModifiedBy)) { Eval = "userAuthName" }); } if (hasAuditSoftDelete) { meta.PopulateAttrs.Add(new AutoPopulateAttribute(nameof(AuditBase.DeletedDate)) { Eval = "utcNow" }); meta.PopulateAttrs.Add(new AutoPopulateAttribute(nameof(AuditBase.DeletedBy)) { Eval = "userAuthName" }); meta.SoftDelete = true; } }
private Dictionary <string, object> ResolveDtoValues(object dto, bool skipDefaults = false) { var dtoValues = dto.ToObjectDictionary(); var meta = AutoCrudMetadata.Create(dto.GetType()); if (meta.MapAttrs != null) { foreach (var entry in meta.MapAttrs) { if (dtoValues.TryRemove(entry.Key, out var value)) { dtoValues[entry.Value.To] = value; } } } var appHost = HostContext.AppHost; if (skipDefaults || meta.UpdateAttrs != null || meta.DefaultAttrs != null) { List <string> removeKeys = null; Dictionary <string, object> replaceValues = null; foreach (var entry in dtoValues) { var isNullable = meta.NullableProps?.Contains(entry.Key) == true; var isDefaultValue = entry.Value == null || (!isNullable && AutoMappingUtils.IsDefaultValue(entry.Value)); if (isDefaultValue) { var handled = false; if (meta.DefaultAttrs != null && meta.DefaultAttrs.TryGetValue(entry.Key, out var defaultAttr)) { handled = true; replaceValues ??= new Dictionary <string, object>(); replaceValues[entry.Key] = appHost.EvalScriptValue(defaultAttr, Request); } if (!handled) { if (skipDefaults || (meta.UpdateAttrs != null && meta.UpdateAttrs.TryGetValue(entry.Key, out var attr) && attr.Style == AutoUpdateStyle.NonDefaults)) { removeKeys ??= new List <string>(); removeKeys.Add(entry.Key); } } } } if (removeKeys != null) { foreach (var key in removeKeys) { dtoValues.RemoveKey(key); } } if (replaceValues != null) { foreach (var entry in replaceValues) { dtoValues[entry.Key] = entry.Value; } } } if (meta.PopulateAttrs != null) { foreach (var populateAttr in meta.PopulateAttrs) { dtoValues[populateAttr.Field] = appHost.EvalScriptValue(populateAttr, Request); } } var populatorFn = AutoMappingUtils.GetPopulator( typeof(Dictionary <string, object>), meta.DtoType); populatorFn?.Invoke(dtoValues, dto); // Ensure RowVersion is always populated if defined on Request DTO if (meta.RowVersionGetter != null && !dtoValues.ContainsKey(Keywords.RowVersion)) { dtoValues[Keywords.RowVersion] = default(uint); } return(dtoValues); }
internal static AutoCrudMetadata Create(Type dtoType) { if (cache.TryGetValue(dtoType, out var to)) { return(to); } to = new AutoCrudMetadata { DtoType = dtoType, ModelType = GetModelType(dtoType), DtoProps = TypeProperties.Get(dtoType), }; if (to.ModelType != null) { to.ModelDef = to.ModelType.GetModelMetadata(); } to.RowVersionGetter = to.DtoProps.GetPublicGetter(Keywords.RowVersion); var dtoAttrs = dtoType.AllAttributes(); foreach (var dtoAttr in dtoAttrs) { if (dtoAttr is AutoPopulateAttribute populateAttr) { to.PopulateAttrs ??= new List <AutoPopulateAttribute>(); to.PopulateAttrs.Add(populateAttr); } else if (dtoAttr is AutoFilterAttribute filterAttr) { to.AutoFilters ??= new List <AutoFilterAttribute>(); to.AutoFiltersDbFields ??= new List <QueryDbFieldAttribute>(); to.AutoFilters.Add(filterAttr); to.AutoFiltersDbFields.Add(ExprResult.ToDbFieldAttribute(filterAttr)); } } foreach (var pi in to.DtoProps.PublicPropertyInfos) { var allAttrs = pi.AllAttributes(); var propName = pi.Name; if (allAttrs.FirstOrDefault(x => x is AutoMapAttribute) is AutoMapAttribute mapAttr) { to.MapAttrs ??= new Dictionary <string, AutoMapAttribute>(); to.MapAttrs[propName] = mapAttr; propName = mapAttr.To; } if (allAttrs.FirstOrDefault(x => x is AutoUpdateAttribute) is AutoUpdateAttribute updateAttr) { to.UpdateAttrs ??= new Dictionary <string, AutoUpdateAttribute>(); to.UpdateAttrs[propName] = updateAttr; } if (allAttrs.FirstOrDefault(x => x is AutoDefaultAttribute) is AutoDefaultAttribute defaultAttr) { to.DefaultAttrs ??= new Dictionary <string, AutoDefaultAttribute>(); to.DefaultAttrs[propName] = defaultAttr; } if (pi.PropertyType.IsNullableType()) { to.NullableProps ??= new HashSet <string>(); to.NullableProps.Add(propName); } } return(cache[dtoType] = to); }
internal bool GetAutoFilterExpressions(IDbConnection db, object dto, Dictionary <string, object> dtoValues, IRequest req, out string expr, out List <object> exprParams) { var meta = AutoCrudMetadata.Create(dto.GetType()); if (meta.AutoFilters != null) { var dialectProvider = db.GetDialectProvider(); var sb = StringBuilderCache.Allocate(); var exprParamsList = new List <object>(); //Update's require PK's, Delete's don't need to if (dtoValues.TryRemove(meta.ModelDef.PrimaryKey.Name, out var idValue)) { var idColumn = dialectProvider.GetQuotedColumnName(meta.ModelDef, meta.ModelDef.PrimaryKey); sb.Append(idColumn + " = {0}"); exprParamsList.Add(idValue); } var appHost = HostContext.AppHost; for (var i = 0; i < meta.AutoFilters.Count; i++) { var filter = meta.AutoFilters[i]; var dbAttr = meta.AutoFiltersDbFields[i]; var fieldDef = meta.ModelDef.GetFieldDefinition(filter.Field); if (fieldDef == null) { throw new NotSupportedException($"{dto.GetType().Name} '{filter.Field}' AutoFilter was not found on '{meta.ModelType.Name}'"); } var quotedColumn = dialectProvider.GetQuotedColumnName(meta.ModelDef, fieldDef); var value = appHost.EvalScriptValue(filter, req); var ret = ExprResult.CreateExpression("AND", quotedColumn, value, dbAttr); if (ret != null) { if (sb.Length > 0) { sb.Append(" AND "); } var exprResult = ret.Value; if (exprResult.Format.IndexOf("{1}", StringComparison.Ordinal) >= 0) { throw new NotSupportedException($"SQL Template '{exprResult.Format}' with multiple arguments is not supported"); } if (exprResult.Values != null) { for (var index = 0; index < exprResult.Values.Length; index++) { sb.Append(exprResult.Format.Replace("{" + index + "}", "{" + exprParamsList.Count + "}")); exprParamsList.Add(exprResult.Values[index]); } } } expr = StringBuilderCache.ReturnAndFree(sb); exprParams = exprParamsList; return(true); } } expr = null; exprParams = null; return(false); }