Donald icon indicating copy to clipboard operation
Donald copied to clipboard

How to deal with DB enums in Donald?

Open Darkle opened this issue 2 years ago • 1 comments

Hi, I am using Donald with Postgres, where I have a Logs table with one of the columns being a postgres enum. I'm not too sure how to read this properly with Donald.

Here is the sql:

CREATE TYPE "LogLevel" AS ENUM ('Trace', 'Debug', 'Information', 'Warning', 'Error', 'Critical');

CREATE TABLE "Logs" (
    "uniqueId" UUID NOT NULL DEFAULT gen_random_uuid(),
    "createdAt" DOUBLE PRECISION NOT NULL,
    "level" "LogLevel" NOT NULL,
    "message" TEXT,
    "service" TEXT,
    "error" TEXT,
    "other" TEXT,

    CONSTRAINT "Logs_pkey" PRIMARY KEY ("uniqueId")
);

Here is my F# type for a Log:

module RidoModels

type LogLevel =
  | Trace = 1
  | Debug = 2
  | Information = 3
  | Warning = 4
  | Error = 5
  | Critical = 6

[<CLIMutable>]
type Log =
  { uniqueId: string
    createdAt: double
    level: LogLevel
    message: Option<string>
    service: Option<string>
    error: Option<string>
    other: Option<string> }

Here is my F# DB code:

module DB.DB

open System.Data
open Donald
open Npgsql
open System

let conn =
  new NpgsqlConnection(Environment.GetEnvironmentVariable("DOTNET_DB_CONNECTION_STRING"))
  :> IDbConnection

module Log =
  let ofDataReader (rd: IDataReader) : RidoModels.Log =
    { uniqueId = rd.ReadString "uniqueId"
      createdAt = rd.ReadDouble "createdAt"
      level = rd.ReadString "level"
      message = rd.ReadStringOption "message"
      service = rd.ReadStringOption "service"
      error = rd.ReadStringOption "error"
      other = rd.ReadStringOption "other" }

The compiler complains about a type mismach for the level = rd.ReadString "level" line:

Type constraint mismatch. The type 
    'string'    
is not compatible with type
    'RidoModels.LogLevel' 

So how would I go about dealing with an DB enum in Donald?

Darkle avatar Jun 25 '23 02:06 Darkle

Apologies, doing the best I can to manage my OSS as the business in my life goes up.

This is a good question. I don't use postgres, so my ability to test is limited. BUT! I would solve this by reading the value in raw as an obj and parse it. Something like:

module LogLevel = 
    let parse (level : obj) = 
        // ...

// meanwhile in your `Log` module...
level = rd.GetOrdinal("level") |> rd.GetValue |> LogLevel.parse 

pimbrouwers avatar Jan 28 '24 01:01 pimbrouwers