Help with Nullable Foreign Reference in Beam

When you create a beam table it looks like this. From the documentation you do something that they call the ‘Identity Trick’ to get a constructor for the primary key:

data RelayT f = Relay {
        _rid :: C f Int64
      , _uri :: C f Text
      } deriving (Generic, Beamable)
type Relay = RelayT
type RelayId = PrimaryKey RelayT Identity 
instance Table RelayT where 
      data PrimaryKey RelayT f = RelayId (C f Int64) deriving (Generic, Beamable)
      primaryKey = RelayId . _rid

Then you are able to create related tables like this:

data EvT f = Ev {
        _eid :: C f Text 
      , _source :: PrimaryKey RelayT f
      } deriving (Generic, Beamable)
type Ev = EvT 
type EvId = PrimaryKey EvT Identity 
instance Table EvT where 
      data PrimaryKey EvT f = EvId (C f Text) deriving (Generic, Beamable)
      primaryKey = EvId . _eid

Then you are able to construct a value to insert into the database:

e :: EvT Identity
e = Ev "example" (RelayId 1) 

From the docs (and the types work) it is possible to create a nullable foreign reference in your table:

 , _source :: PrimaryKey RelayT (Nullable f) 

But I can’t figure out how to construct that value. Non foreign key nullables work quite simply with maybe but these permutation don’t work here.

  • Just (RelayId 2)
  • RelayId (Just 3)

Anyone know how to construct a nullable foreign reference in beam?

pushed a branch with the holes

I feel like it’s something I don’t understand about what this Identity Trick is actually doing so perhaps just trying to explain that to me will induce a lightbulb.

The “identity trick” is how higher-kinded types like C f Int where f :: * -> * simplify to the underlying type (Int)

TBH beam type sigs give me a headache but I have two concerns:

  1. is it a good idea to have a nullable foreign key?
  2. it seems you can only have nullable references if your Table type satisfies the SqlJustable constraint : Database.Beam.Schema.Tables

I was curious, so I looked into the beam-core library and the tests.

If you glance here - https://github.com/haskell-beam/beam/blob/master/beam-core/test/Database/Beam/Test/Schema.hs#L124 - you can see that the Department type is a nullable foreign key; and you can see where they use it here - https://github.com/haskell-beam/beam/blob/master/beam-core/test/Database/Beam/Test/SQL.hs#L840 - notably, the Just floats into the values of the foreign-key; so it seems to me it should just be RelayId (Just 3) as you suggested above.

Are you sure that doesn’t work?

1 Like

Oops, indeed it does

1 Like