private CProtoRpc BuildRpcFromStoredProc(CProtoFile protoFile, CProtoService protoService, CMethod method,
                                                 CStoredProcedure storedProcedure)
        {
            var rpc = new CProtoRpc(protoService)
            {
                RpcName        = storedProcedure.StoredProcedureName,
                RpcDescription = storedProcedure.StoredProcedureDescription,
                //DomainModelName = storedProcedure.ResultSetName,
                DerivedFrom = storedProcedure
            };

            rpc.Request = new CProtoMessage(rpc)
            {
                IsRequest   = true,
                MessageName = $"{storedProcedure.StoredProcedureName}Request"
            };
            rpc.Response = new CProtoMessage(rpc)
            {
                IsResponse  = true,
                MessageName = $"{storedProcedure.StoredProcedureName}Response"
            };

            var requestMessage = rpc.Request;

            if (!string.IsNullOrEmpty(storedProcedure.ParameterSetName))
            {
                rpc.Request.ProtoField.Add(new CProtoMessageField(storedProcedure)
                {
                    IsScalar    = false,
                    MessageType = storedProcedure.ParameterSetName,
                    FieldName   = storedProcedure.ParameterSetName
                });

                requestMessage = new CProtoMessage(rpc)
                {
                    IsRequest   = true,
                    MessageName = storedProcedure.ParameterSetName
                };
                if (!protoFile.ProtoMessage.Exists(pm => pm.MessageName == requestMessage.MessageName))
                {
                    protoFile.ProtoMessage.Add(requestMessage);
                }
            }
            foreach (var parameter in storedProcedure.Parameter)
            {
                var field = new CProtoMessageField(parameter)
                {
                    FieldName = parameter.ParameterName //.SourceColumn.ColumnName,
                };

                if (!parameter.ParameterTypeIsUserDefined)
                {
                    var sqlType = SqlMapper.ParseValueAsSqlDbType(parameter.ParameterTypeRaw);
                    field.FieldType = SqlMapper.SqlDbTypeToGrpcType(sqlType);
                }
                else
                {
                    //todo: property handle user defined sql types (tables)
                    //lookup table type
                    //for now, use the data type of the first column, assumes single column table
                    var tableType = FindTableType(parameter.ParameterTypeRaw);
                    var converter = new CTableTypeToCClassConverter();
                    var @class    = converter.Convert(tableType.GeneratedTableType);
                    field.FieldType   = GrpcType.__string;
                    field.IsScalar    = false;
                    field.Repeated    = true;
                    field.MessageType = $@"{@class.ClassName}";

                    if (!protoFile.ProtoMessage.Exists(pm => pm.MessageName == field.MessageType))
                    {
                        //create a message
                        var tableTypeDerivedMessage = new CProtoMessage(rpc)
                        {
                            MessageName = field.MessageType
                        };
                        foreach (var property in @class.Property)
                        {
                            var field2 = new CProtoMessageField(property)
                            {
                                FieldName = property.PropertyName,
                                FieldType = SqlMapper.ClrTypeToGrpcType(SqlMapper.ClrTypeAliasToClrType(property.Type))
                            };

                            tableTypeDerivedMessage.ProtoField.Add(field2);
                        }
                        protoFile.ProtoMessage.Add(tableTypeDerivedMessage);
                    }
                }

                requestMessage.ProtoField.Add(field);
            }

            var responseMessage = rpc.Response;

            if (!string.IsNullOrEmpty(storedProcedure.ResultSetName))
            {
                rpc.Response.ProtoField.Add(new CProtoMessageField(null)
                {
                    IsScalar    = false,
                    Repeated    = true,
                    MessageType = storedProcedure.ResultSetName,
                    FieldName   = storedProcedure.ResultSetName
                });

                responseMessage = new CProtoMessage(rpc)
                {
                    IsResponse  = true,
                    MessageName = storedProcedure.ResultSetName
                };
                if (!protoFile.ProtoMessage.Exists(pm => pm.MessageName == responseMessage.MessageName))
                {
                    protoFile.ProtoMessage.Add(responseMessage);
                }
            }
            foreach (var resultColumn in storedProcedure.ResultSet)
            {
                var field = new CProtoMessageField(resultColumn)
                {
                    FieldName = resultColumn.ColumnName,
                    FieldType = SqlMapper.SqlDbTypeToGrpcType(resultColumn.ColumnSqlDbType)
                };

                responseMessage.ProtoField.Add(field);
            }
            return(rpc);
        }