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
564 stars 144 forks source link

OnConflict.Update ignores None/ValueNone values when using DatabaseProviderTypes.POSTGRESQL #814

Open mishun opened 5 months ago

mishun commented 5 months ago

Hi!

Describe the bug If I create following simple key-value pairs Postgresql database:

begin;

create table "Test" (
    "ID"    int4 generated by default as identity primary key,
    "Value" int4 null
);

insert into "Test" ("ID", "Value") values
    (0, 1),
    (1, 1);

commit;

and run following code:

module Main

open System.Threading.Tasks
open FSharp.Data.Sql
open FSharp.Data.Sql.Common

[<Literal>]
let private resolutionPath = __SOURCE_DIRECTORY__ + "/obj/db-libs/"

[<Literal>]
let private connectionString = "Host=localhost;Port=5433;Database=test;User ID=test;Password=test"

type postgres =
    SqlDataProvider<
        DatabaseVendor   = DatabaseProviderTypes.POSTGRESQL,
        ResolutionPath   = resolutionPath,
        ConnectionString = connectionString,
        UseOptionTypes   = NullableColumnType.OPTION
    >

let update (key : int) (value : int option) = task {
    let ctx = postgres.GetDataContext connectionString
    let row = ctx.Public.Test.Create()
    row.Id <- key
    row.Value <- value
    row.OnConflict <- OnConflict.Update
    do! ctx.SubmitUpdatesAsync()
}

[<EntryPoint>]
let main args =
    Task.WaitAll(task {
        try
            do! update 0 None
        with ex ->
            printfn "Exception: %A" ex
    })
    0

I'd expect Value in the first row to be changed to NULL, but in fact nothing happens. Same goes for NullableColumnType.VALUE_OPTION and ValueNone. Something like update 0 (Some 69) and update 2 None work as expected.

Tested with SQLProvider 1.3.23 from nuget package.

Additional context fsproj and docker-compose.yaml for reproduction:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Update="FSharp.Core" Version="7.0.400" />
    <PackageReference Include="Npgsql" Version="7.0.6" />
    <PackageReference Include="SQLProvider" Version="1.3.23" />
    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" GeneratePathProperty="true" />
  </ItemGroup>

  <Target Name="CopyDBLibs" BeforeTargets="BeforeBuild">
    <Copy SourceFiles="$(PkgMicrosoft_Extensions_Logging_Abstractions)/lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll"
          DestinationFolder="$(MSBuildThisFileDirectory)/obj/db-libs/"
          UseSymbolicLinksIfPossible="True" />
  </Target>
</Project>
version: "3.8"

services:
  geometra-db:
    image: postgres:14
    container_name: test-db
    restart: no
    ports:
      - 5433:5432
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/00-init.sql:ro
    environment:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test

Complete example can be found here.