'How to convert a Google Repeated Field to a standard F# list or array (FSharp.GrpcCodeGenerator)?

I've been experimenting with the NuGet package FSharp.GrpcCodeGenerator in converting my proto files to F# types.

On my client side (in F#), I have:

namespace StargateIX.Network

open System
open Grpc.Core
open Protocol.ProtoBuf
open Grpc.Net.Client

module ClientNetwork =

    let channel = GrpcChannel.ForAddress("https://localhost:5001/")
    let client = PatientService.PatientServiceClient(channel)
    let req =  GetAllPatientsRequest.empty()  
    let resp = client.GetAllPatients(req).Patients
     ?????????????
    printfn "%s" resp.Message

Where GetAllPatientsRequest is an empty message, i.e.

message GetAllPatientsRequest {}

and the reponse to GetAllPatients is

message PatientListResponse {
    repeated Patient Patients = 1;
}

How do I convert the PatientListResponse with its repeated field to a standard F# Array or list such that I can print it?

(Also, all this should be done asynchronously).

message Patient {
    int32 PatientId =1;
    google.protobuf.Timestamp BirthDate = 2;
    string FirstName =3;
    string LastName=4;
    google.protobuf.StringValue Mi=5;  
    int32 ChartNumber=6;
}

TIA



Solution 1:[1]

This works -- or at least it compiles. I don't really like it since the fields for lastname, firstname, and birthdate will NEVER be null. So this seems unnecessarily complicated.

type Patient = 
  {
    PatientId : int option
    BirthDate : DateTime
    FirstName : string
    LastName : string
    Mi       : string
    ChartNumber : int
  }

module ClientNetwork =

    let patientToDomain  (x:Protocol.ProtoBuf.Patient) : Patient =  {PatientId = match x.PatientId with
                                                                                            | ValueNone  ->  None
                                                                                            | ValueSome d -> Some d;
                                                                     BirthDate = match x.BirthDate with
                                                                                            | ValueNone ->  DateTime(01,01,01)
                                                                                            | ValueSome d -> d.ToDateTime().Value ;
                                                                     FirstName = match x.FirstName with  
                                                                                            | ValueNone -> ""
                                                                                            | ValueSome s -> s;
                                                                     LastName = match x.LastName with
                                                                                            | ValueNone -> ""
                                                                                            | ValueSome s -> s;
                                                                     Mi =  match x.Mi with
                                                                                            | ValueNone -> ""
                                                                                            | ValueSome s -> s.ToString();
                                                                     ChartNumber = match x.ChartNumber with
                                                                                            | ValueNone -> 0
                                                                                            | ValueSome i -> i} 

    let channel = GrpcChannel.ForAddress("https://localhost:5001/")
    let client = PatientService.PatientServiceClient(channel)
    let req =  GetAllPatientsRequest.empty()  
    let resp = client.GetAllPatients(req).Patients |> Seq.map patientToDomain
    resp |> printfn "%A" 

This seems a little bit better but drops the error checks.

let patientToDomain  (x:Protocol.ProtoBuf.Patient) : Patient = 
        {   PatientId = match x.PatientId with
                        | ValueNone  ->  None
                        | ValueSome d -> Some d;
            BirthDate = x.BirthDate.Value.ToDateTime().Value; 
            FirstName = x.FirstName.Value;                                                                   
            LastName =  x.LastName.Value; 
            Mi =  match x.Mi with
                    | ValueNone -> ""
                    | ValueSome s -> s.ToString();
            ChartNumber = x.ChartNumber.Value } 

Now adding the async part gives:

module ClientNetwork =

    let channel = GrpcChannel.ForAddress("https://localhost:5001/")
    let client = PatientService.PatientServiceClient(channel)

    let patientToDomain  (x:Protocol.ProtoBuf.Patient) : Patient = 
        {   PatientId = match x.PatientId with
                        | ValueNone  ->  None
                        | ValueSome d -> Some d;
            BirthDate = x.BirthDate.Value.ToDateTime().Value; 
            FirstName = x.FirstName.Value;                                                                   
            LastName =  x.LastName.Value; 
            Mi =  match x.Mi with
                    | ValueNone -> ""
                    | ValueSome s -> s.ToString();
            ChartNumber = x.ChartNumber.Value } 
 
    let req =  GetAllPatientsRequest.empty()  

    let GetAllPatientsAsync req =
        async {
                let! resp = client.GetAllPatientsAsync(req).ResponseAsync |> Async.AwaitTask 
                return resp.Patients |> Seq.map patientToDomain
         }

This compiles correctly so I will go with it. Better answers are more then welcome!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1