modules/backend/Write-DomainLayer.ps1
|
param( [string]$ProjectName, [string]$OrmMode, [string]$OutputPath, [string[]]$Entities ) . (Join-Path (Split-Path $MyInvocation.MyCommand.Path) "..\core\Utils.ps1") $base = Join-Path $OutputPath "src\$ProjectName.Domain" function Write-File($rel, $con) { Write-CoreFile (Join-Path $base $rel) $con } function T($template, $e = "") { $res = $template.Replace("{P}", $ProjectName) if ($e) { $res = $res.Replace("{E}", $e) } return $res } # ---- IAggregateRoot ---- Write-File "Common\IAggregateRoot.cs" (T @' namespace {P}.Domain.Common; public interface IAggregateRoot { } '@) # ---- ValueObject ---- Write-File "Common\ValueObject.cs" (T @' using System.Reflection; namespace {P}.Domain.Common; public abstract class ValueObject { protected abstract IEnumerable<object> GetEqualityComponents(); public override bool Equals(object? obj) { if (obj == null || obj.GetType() != GetType()) return false; var other = (ValueObject)obj; return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents()); } public override int GetHashCode() { return GetEqualityComponents() .Select(x => x != null ? x.GetHashCode() : 0) .Aggregate((x, y) => x ^ y); } public static bool operator ==(ValueObject? left, ValueObject? right) { if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null)) return false; return ReferenceEquals(left, null) || left.Equals(right); } public static bool operator !=(ValueObject? left, ValueObject? right) { return !(left == right); } } '@) # ---- BaseEntity ---- Write-File "Common\BaseEntity.cs" (T @' namespace {P}.Domain.Common; public abstract class BaseEntity { public int Id { get; protected set; } public DateTime CreatedAt { get; protected set; } = DateTime.UtcNow; public DateTime UpdatedAt { get; protected set; } = DateTime.UtcNow; public bool IsDeleted { get; protected set; } = false; public DateTime? DeletedAt { get; protected set; } public virtual void Delete() { if (!IsDeleted) { IsDeleted = true; DeletedAt = DateTime.UtcNow; UpdatedAt = DateTime.UtcNow; } } } '@) # ---- PagedQuery ---- Write-File "Common\PagedQuery.cs" (T @' namespace {P}.Domain.Common; public class PagedQuery { public int Page { get; set; } = 1; public int Size { get; set; } = 20; public int Skip => (Page - 1) * Size; } '@) # ---- PagedResult<T> ---- Write-File "Common\PagedResult.cs" (T @' namespace {P}.Domain.Common; public class PagedResult<T> { public IEnumerable<T> Items { get; set; } = Enumerable.Empty<T>(); public int TotalCount { get; set; } public int Page { get; set; } public int Size { get; set; } public int TotalPages => (int)Math.Ceiling((double)TotalCount / Size); public bool HasNextPage => Page < TotalPages; public bool HasPreviousPage => Page > 1; } '@) # ---- Email Value Object ---- Write-File "ValueObjects\Email.cs" (T @' using System.Text.RegularExpressions; using {P}.Domain.Common; namespace {P}.Domain.ValueObjects; public class Email : ValueObject { private static readonly Regex EmailRegex = new( @"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); public string Value { get; } protected Email() { Value = string.Empty; } public Email(string value) { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Email address cannot be empty.", nameof(value)); if (!EmailRegex.IsMatch(value)) throw new ArgumentException("Invalid email format.", nameof(value)); Value = value.Trim(); } protected override IEnumerable<object> GetEqualityComponents() { yield return Value.ToLowerInvariant(); } public override string ToString() => Value; } '@) # ---- IRepository<T> ---- Write-File "Interfaces\IRepository.cs" (T @' using {P}.Domain.Common; namespace {P}.Domain.Interfaces; public interface IRepository<T> where T : class { Task<T?> GetByIdAsync(int id); Task<IEnumerable<T>> GetAllAsync(); Task<PagedResult<T>> GetPagedAsync(PagedQuery query); Task<int> AddAsync(T entity); Task UpdateAsync(T entity); Task DeleteAsync(int id); } '@) # ---- IUnitOfWork ---- Write-File "Interfaces\IUnitOfWork.cs" (T @' namespace {P}.Domain.Interfaces; public interface IUnitOfWork : IDisposable { Task<int> SaveChangesAsync(CancellationToken cancellationToken = default); Task BeginTransactionAsync(); Task CommitTransactionAsync(); Task RollbackTransactionAsync(); } '@) # ---- Dinamik Entity ve Repository Üretimi ---- foreach ($e in $Entities) { if ($e -eq "User") { Write-File "Entities\User.cs" (T @' using {P}.Domain.Common; using {P}.Domain.ValueObjects; namespace {P}.Domain.Entities; public class User : BaseEntity, IAggregateRoot { public string Username { get; private set; } = string.Empty; public string PasswordHash { get; private set; } = string.Empty; public Email Email { get; private set; } = null!; public bool IsActive { get; private set; } = true; public string Role { get; private set; } = "User"; protected User() { } public User(string username, string passwordHash, Email email, string role = "User") { if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Username cannot be empty.", nameof(username)); if (string.IsNullOrWhiteSpace(passwordHash)) throw new ArgumentException("Password hash cannot be empty.", nameof(passwordHash)); Username = username.Trim(); PasswordHash = passwordHash; Email = email ?? throw new ArgumentNullException(nameof(email)); Role = string.IsNullOrWhiteSpace(role) ? "User" : role; IsActive = true; CreatedAt = DateTime.UtcNow; UpdatedAt = DateTime.UtcNow; } public void UpdateRole(string role) { if (string.IsNullOrWhiteSpace(role)) throw new ArgumentException("Role cannot be empty.", nameof(role)); Role = role; UpdatedAt = DateTime.UtcNow; } public void ChangeEmail(Email email) { Email = email ?? throw new ArgumentNullException(nameof(email)); UpdatedAt = DateTime.UtcNow; } public void Activate() { IsActive = true; UpdatedAt = DateTime.UtcNow; } public void Deactivate() { IsActive = false; UpdatedAt = DateTime.UtcNow; } } '@) Write-File "Interfaces\IUserRepository.cs" (T @' using {P}.Domain.Entities; namespace {P}.Domain.Interfaces; public interface IUserRepository { Task<User?> GetByUsernameAsync(string username); Task<int> AddAsync(User user); } '@) } else { # Jenerik Entity (Rich Domain Model) $extraFields = "" $extraCtorParams = "" $ctorAssignments = "" if ($e -eq "Product") { $extraFields = "`n public decimal Price { get; private set; }" $extraCtorParams = ", decimal price" $ctorAssignments = "`n if (price < 0) throw new ArgumentException(`"Price cannot be negative.`", nameof(price));`n Price = price;" } $entityTemplate = @" using {P}.Domain.Common; namespace {P}.Domain.Entities; public class {E} : BaseEntity { public string Name { get; private set; } = string.Empty;$extraFields protected {E}() { } public {E}(string name$extraCtorParams) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Name cannot be empty.", nameof(name)); Name = name.Trim();$ctorAssignments CreatedAt = DateTime.UtcNow; UpdatedAt = DateTime.UtcNow; } public void UpdateDetails(string name$extraCtorParams) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Name cannot be empty.", nameof(name)); Name = name.Trim();$ctorAssignments UpdatedAt = DateTime.UtcNow; } } "@ Write-File "Entities\$e.cs" (T $entityTemplate $e) # Jenerik Repository Arayüzü Write-File "Interfaces\I$e`Repository.cs" (T @' using {P}.Domain.Entities; namespace {P}.Domain.Interfaces; public interface I{E}Repository : IRepository<{E}> { } '@ $e) } } |