tomjaguarpaw / haskell-opaleye

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nullable vs MaybeFields

stevemao opened this issue · comments

It is recommended to use MaybeFields instead of NULL. But FieldNullable is using NULL so converting between the two isn't avoidable which is quite annoying to the users. Is there a plan to make FieldNullable to use MaybeFields internally?

Could you give an example of what's annoying?

My understanding is when selecting a nullable field, I get Select FieldNullable a, then I'll need to convert it to Select MaybeFields a to be able to work with things like optionalRestrict. What's the point of having two different types representing the same thing?

I see. It sounds like you are talking about fields that come from base tables, that you define with table. Is that right? If so then how about a way of defining table fields that doesn't mention NULLABLE fields in the first place, for example requiredTableMaybeField, as defined below? Does that solve the problem? If not could you say a little more about the problem?

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

import Opaleye
import Data.Profunctor.Product.TH
import Data.Profunctor

requiredTableMaybeField ::
  String ->
  TableFields (MaybeFields (Field a)) (MaybeFields (Field a))
requiredTableMaybeField name =
  dimap (\mf -> matchMaybe mf $ \case
            Nothing -> Opaleye.null
            Just x -> toNullable x)
        nullableToMaybeFields
        (requiredTableField name)

-- Example of using it

data Widget a b c = Widget { wid      :: a
                           , color    :: b
                           , location :: c
                           }

$(makeAdaptorAndInstance "pWidget" ''Widget)

widgetTableNullable ::
  Table (Widget (Maybe (Field SqlInt4)) (Field SqlText) (FieldNullable SqlText))
        (Widget (Field SqlInt4) (Field SqlText) (FieldNullable SqlText))
widgetTableNullable =
  table "widgetTable"
  (pWidget Widget { wid      = optionalTableField "id"
                  , color    = requiredTableField "color"
                  , location = requiredTableField "location"
                  })

widgetTableMaybe ::
  Table (Widget (Maybe (Field SqlInt4)) (Field SqlText) (MaybeFields (Field SqlText)))
        (Widget (Field SqlInt4) (Field SqlText) (MaybeFields (Field SqlText)))
widgetTableMaybe =
  table "widgetTable"
  (pWidget Widget { wid      = optionalTableField "id"
                  , color    = requiredTableField "color"
                  , location = requiredTableMaybeField "location"
                  })

Yes, this solves the problem! (though I haven't tried the code)

MaybeFields (Field SqlText) instead of FieldNullable SqlText seems much better. Do you think this should be the preferred way of defining nullable fields, and perhaps deprecate the other? If not, is there anything FieldNullable can do but MaybeFields can't?

Yes, this solves the problem! (though I haven't tried the code)

Cool! Please let me know your experience when you've tried it.

Some users may well want to handle nullability directly, but using MaybeFields by default seems like a reasonable idea. I'll add requiredTableMaybeField to the library at some point and suggest it in favour of nullable fields.

Cool! Please let me know your experience when you've tried it.

will do. We won't change it immediately as it's not a small codebase now...

Some users may well want to handle nullability directly

It seems that all functions working with nullable have an equivalent with MaybeFields. Having 2 equivalent Maybe types seems unnecessary. I'd only keep one in my codebase but I'll have to see how well it works.

Thanks again!

It seems that all functions working with nullable have an equivalent with MaybeFields. Having 2 equivalent Maybe types seems unnecessary. I'd only keep one in my codebase but I'll have to see how well it works.

Yes, I could replace all the nullable functionality with MaybeFields functionality. That would be much nicer from an API point of view. But it's possible that there will be a small performance impact to using MaybeFields.

Thanks again!

Happy to help! Please ask again any time.

Closing as inactive, but feel free to reopen if necessary.