fsprojects / SQLProvider

A general F# SQL database erasing type provider, supporting LINQ queries, schema exploration, individuals, CRUD operations and much more besides.
https://fsprojects.github.io/SQLProvider
Other
580 stars 146 forks source link

Discriminated Unions for Static Data #392

Open ghost opened 7 years ago

ghost commented 7 years ago

Another question, but are there any plans for allowing discriminated unions to be used as the type for foreign key IDs to static data? I know entity framework supports this with enums but it would be handy to be able to use discriminated unions for obvious reasons:

type ContentTypeId =
  | Book
  | Magazine
  | Newspaper

...

let printData item =
  match item.ContentTypeId with
  | Book -> printfn "Found a book with id: %d" item.Id
  | Magazine -> printfn "Found a magazine with id: %d" item.Id
  | Newspaper -> printfn "Found a newspaper with id: %d" item.Id

It's possible to do this now by mapping the ID when projecting results:

let getContentTypeId = function
  | 1 -> Book
  | 2 -> Magazine
  | 3 -> Newpaper

...

query {
  for item in ctx.Dbo.Media do
  select
    { contentTypeId = getContentTypeId item.contentTypeId;
    }
}

This can get tedious and is pretty brittle, and an auto-generated solution would be preferable if possible. The infrastructure for the Individuals feature would probably be reusable to accomplish this?

Thorium commented 7 years ago

I would also be happy us to have something like this or SqlEnumProvider (which works only for MSSQL) so that some string-column values would be handled as discriminated union entities. @pezipink even said once (after n drinks in a bar) that it would be easy to add.


Later we could create one more constructor parameter that if you want to convert some columns having the column-name with some extension like "Unit" to convert to unit-of-measures, like

Table1:

Sum SumUnit
10 GBP
12 EUR
7 GBP

...we could say that behind the scenes instead of current entity generated

type Table1Entity = {
      Sum : int
      SumUnit : string
}

this would actually create

[<Measure>] type GBP
[<Measure>] type EUR

type Table1Entity<[<Measure>] 'sum> = {
      Sum : int<'sum>
}
ghost commented 7 years ago

I hadn't considered the cases of string-columns with "in practice" enumerated values, but this would also be really handy! It could also be applied generally to columns of (almost) any type, GUIDs come to mind also.