diff --git a/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs b/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs index 6794fff..7a5c07d 100644 --- a/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs +++ b/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs @@ -904,9 +904,14 @@ namespace Svrnty.CQRS.Grpc.Generators } // Default: direct assignment (strings, ints, bools, etc.) - if (prop.IsNullable && prop.Type.Contains("string")) + if (prop.IsNullable) { - return $"{indent}{prop.Name} = {source} ?? string.Empty,"; + if (prop.Type.Contains("string")) + { + return $"{indent}{prop.Name} = {source} ?? string.Empty,"; + } + // Handle nullable primitives (long?, int?, etc.) - use default value + return $"{indent}{prop.Name} = {source} ?? default,"; } return $"{indent}{prop.Name} = {source},"; } @@ -1921,14 +1926,38 @@ namespace Svrnty.CQRS.Grpc.Generators if (command.HasResult) { sb.AppendLine(" var result = await handler.HandleAsync(command, context.CancellationToken);"); - // Handle Guid result conversion - if (command.ResultFullyQualifiedName?.Contains("System.Guid") == true) + + // Generate response with mapping if complex type + if (command.IsResultPrimitiveType) { - sb.AppendLine($" return new {responseType} {{ Result = result.ToString() }};"); + // Handle primitive type result conversion (e.g., Guid.ToString()) + if (command.ResultFullyQualifiedName?.Contains("System.Guid") == true) + { + sb.AppendLine($" return new {responseType} {{ Result = result.ToString() }};"); + } + else + { + sb.AppendLine($" return new {responseType} {{ Result = result }};"); + } } else { - sb.AppendLine($" return new {responseType} {{ Result = result }};"); + // Complex type - need to map from C# type to proto type + sb.AppendLine($" if (result == null)"); + sb.AppendLine($" {{"); + sb.AppendLine($" return new {responseType}();"); + sb.AppendLine($" }}"); + sb.AppendLine($" return new {responseType}"); + sb.AppendLine(" {"); + sb.AppendLine($" Result = new {command.ResultType}"); + sb.AppendLine(" {"); + foreach (var prop in command.ResultProperties) + { + var assignment = GenerateResultPropertyMapping(prop, "result", " "); + sb.AppendLine(assignment); + } + sb.AppendLine(" }"); + sb.AppendLine(" };"); } } else diff --git a/Svrnty.CQRS.Grpc.Generators/ProtoTypeMapper.cs b/Svrnty.CQRS.Grpc.Generators/ProtoTypeMapper.cs index 9d01d16..3e8ab62 100644 --- a/Svrnty.CQRS.Grpc.Generators/ProtoTypeMapper.cs +++ b/Svrnty.CQRS.Grpc.Generators/ProtoTypeMapper.cs @@ -108,6 +108,12 @@ internal static class ProtoFileTypeMapper needsImport = true; importPath = "google/protobuf/timestamp.proto"; return "google.protobuf.Timestamp"; + case "DateOnly": + // DateOnly serialized as string (YYYY-MM-DD format) + return "string"; + case "TimeOnly": + // TimeOnly serialized as string (HH:mm:ss format) + return "string"; case "TimeSpan": needsImport = true; importPath = "google/protobuf/duration.proto";