using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using zero.Core.Entities; using zero.Core.Extensions; using zero.Core.Utils; namespace zero.Core.Blueprints { /// /// /// public class Blueprint : Blueprint where T : ZeroEntity, new() { public List> UnlockedFields { get; private set; } = new(); protected static string[] DefaultFields { get; set; } = new[] { "name", "alias", "key", "sort", "isActive", "hash", "languageId", "createdById", "createdDate", "lastModifiedById", "lastModifiedDate", "blueprint" }; public Blueprint() : base(typeof(T)) { //Sync(x => x.Name); //Sync(x => x.Alias); //Sync(x => x.Sort); //Sync(x => x.IsActive); //Sync(x => x.LanguageId); //Sync(x => x.Key); } /// /// Merges blueprint data into a model based on the configuration /// public virtual T Apply(T blueprint, T model) { // reset blueprint options for model in case no blueprint was found if (blueprint == null || model.Blueprint == null) { model.Blueprint = null; return model; } // copy all properties which are synced from the blueprint to the model ApplyDefaults(blueprint, model); ObjectCloner.CopyProperties(blueprint, model, DefaultFields.Union(model.Blueprint.Desync).ToArray()); return model; } /// public override ZeroEntity Apply(ZeroEntity blueprint, ZeroEntity model) => Apply(blueprint as T, model as T); /// /// Update default entity data /// protected virtual void ApplyDefaults(T blueprint, T model) { if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.Name), StringComparer)) { model.Name = blueprint.Name; model.Alias = blueprint.Alias; } if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.Key), StringComparer)) { model.Key = blueprint.Key; } if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.Sort), StringComparer)) { model.Sort = blueprint.Sort; } if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.IsActive), StringComparer)) { model.IsActive = blueprint.IsActive; } // these values can't be overridden model.Hash = blueprint.Hash; model.LanguageId = blueprint.LanguageId; model.CreatedById = blueprint.CreatedById; model.CreatedDate = blueprint.CreatedDate; model.LastModifiedById = blueprint.LastModifiedById; model.LastModifiedDate = blueprint.LastModifiedDate; } /// /// Lock a field so it always get synchronized no and cannot be changed /// public void LockAll() { UnlockedFields = new(); } /// /// Lock a field so it always get synchronized no and cannot be changed /// public void Lock(Expression> selector) { RemoveField(selector); } public void Unlock(Expression> selector) { AddField(selector); } public void UnlockDefaults() { AddField(x => x.Name); AddField(x => x.Alias); AddField(x => x.Sort); AddField(x => x.Key); AddField(x => x.IsActive); } /// public override IEnumerable GetUnlockedFieldNames() { foreach (BlueprintField field in UnlockedFields) { yield return field.FieldName.ToCamelCaseId(); } } /// /// Get existing field or create a new one /// protected BlueprintField AddField(Expression> selector) { BlueprintField tempField = new(selector); BlueprintField storedField = UnlockedFields.FirstOrDefault(x => x.FieldName.Equals(tempField.FieldName, StringComparison.InvariantCultureIgnoreCase)); if (storedField != null) { return storedField; } UnlockedFields.Add(tempField); return tempField; } /// /// Removes a field /// protected void RemoveField(Expression> selector) { BlueprintField tempField = new(selector); if (tempField != null) { UnlockedFields.RemoveAll(x => x.FieldName.Equals(tempField.FieldName, StringComparison.InvariantCultureIgnoreCase)); } } } /// /// /// public abstract class Blueprint { /// /// Type of the associated entity /// public Type ContentType { get; private set; } public string Alias { get; private set; } /// /// String comparer for property name comparison /// protected readonly StringComparer StringComparer = StringComparer.InvariantCultureIgnoreCase; public Blueprint(Type type) { ContentType = type; Alias = type.Name.ToCamelCaseId(); } /// /// Merges blueprint data into a model based on the configuration /// public abstract ZeroEntity Apply(ZeroEntity blueprint, ZeroEntity model); /// /// Get all fields which have been unlocked /// public abstract IEnumerable GetUnlockedFieldNames(); } public class DefaultBlueprint : Blueprint where T : ZeroEntity, new() { public DefaultBlueprint(Action> expression = null) : base() { expression?.Invoke(this); } } }