You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
openSystemopenNpgsqlopenNpgsql.LoggingopenNpgsqlTypestypeDbPeriodStatus=|[<PgName("active")>] Active =0|[<PgName("deleted")>] Deleted =1letreadFirstStatus(connection:NpgsqlConnection)=use command = connection.CreateCommand()
command.CommandText <-"SELECT * FROM sch_accounting.accounting_periods;"use reader = command.ExecuteReader()
reader.Read()|> ignore
letstatus= reader.GetFieldValue<DbPeriodStatus>(3)
printfn "%A" status
letaddParameter((name:string),(maybeDbType:NpgsqlDbType option),(value:obj))(command:NpgsqlCommand)=letparameter= command.CreateParameter()
parameter.SourceColumn <- name
match maybeDbType with| Some dbType -> parameter.NpgsqlDbType <- dbType
| None ->()
parameter.Value <- value
command.Parameters.Add(parameter)|> ignore
letwriteStuff(connection:NpgsqlConnection)=use command = connection.CreateCommand()
command.CommandText <-"INSERT INTO sch_accounting.accounting_periods (id, start_date, end_date, status, created_by, created_on, updated_by, updated_on) VALUES (@id, @startDate, @endDate, @status, @createdBy, @createdOn, @updatedBy, @updatedOn)"[("id", Some NpgsqlDbType.Uuid, Guid.NewGuid():> obj)("start_date", Some NpgsqlDbType.TimestampTz, DateTimeOffset.UtcNow :> obj )("end_date", Some NpgsqlDbType.TimestampTz, DateTimeOffset.UtcNow :> obj )("status", None, DbPeriodStatus.Active :> obj )("created_by", Some NpgsqlDbType.Text,"Meow":> obj )("created_on", Some NpgsqlDbType.TimestampTz, DateTimeOffset.UtcNow :> obj )("updated_by", Some NpgsqlDbType.Text,"Meow":> obj )("updated_on", Some NpgsqlDbType.TimestampTz, DateTimeOffset.UtcNow :> obj )]|> List.iter(fun stuff -> addParameter stuff command)
command.ExecuteNonQuery()|> ignore
[<EntryPoint>]letmain _ =
NpgsqlLogManager.Provider <- ConsoleLoggingProvider(NpgsqlLogLevel.Trace,true,true)letconnectionString="Host=localhost;Port=5432;Database=read_model;User ID=postgres;Password=postgres"use connection =new NpgsqlConnection(connectionString)
connection.Open()
readFirstStatus connection
readFirstStatus connection
writeStuff connection
0
For unmapped enums:
Reading stuff works
Writing stuff fails
The issue
Atm, the attribute to decorate our enums only supports the value:
typeDbPeriodStatus=|[<PgName("active")>] Active =0|[<PgName("deleted")>] Deleted =1
It would be nice to instead of having to rely systematically on the mapper: NpgsqlConnection.GlobalTypeMapper.MapEnum("sch_accounting.accounting_period_status")
We could just put either:
[<PgName("sch_accounting.accounting_period_status")>]typeDbPeriodStatus=|[<PgName("active")>] Active =0|[<PgName("deleted")>] Deleted =1
or
typeDbPeriodStatus=|[<PgName("sch_accounting.accounting_period_status","active")>] Active =0|[<PgName("sch_accounting.accounting_period_status","deleted")>] Deleted =1
or maybe to make the read and write works with:
typeDbPeriodStatus=|[<PgName("sch_accounting.accounting_period_status.active")>] Active =0|[<PgName("sch_accounting.accounting_period_status.deleted")>] Deleted =1
There is already a few existing issues opened about unmapped and related stuff
So I know that my take on unmapped enums might be considered as controversial by some others.
The exception we're getting atm:
System.NotSupportedException: The CLR enum type DbPeriodStatus must be registered with Npgsql before usage, please refer to the documentation.
at Npgsql.TypeMapping.ConnectorTypeMapper.GetByClrType(Type type)
at Npgsql.NpgsqlParameter.ResolveHandler(ConnectorTypeMapper typeMapper)
at Npgsql.NpgsqlParameter.Bind(ConnectorTypeMapper typeMapper)
at Npgsql.NpgsqlCommand.ValidateParameters(ConnectorTypeMapper typeMapper)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteNonQuery(Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteNonQuery()
at Program.writeStuff(NpgsqlConnection connection) in C:\Users\Michelle\Desktop\Personal\Repos\fsharp-playground\FSharp.Playground\FSharp.Playground\Program.fs:line 102
at Program.main(String[] _arg1) in C:\Users\Michelle\Desktop\Personal\Repos\fsharp-playground\FSharp.Playground\FSharp.Playground\Program.fs:line 113
Further technical details
Npgsql version: 5.0.0
PostgreSQL version: PostgreSQL 12.4 on x86_64-pc-linux-musl, compiled by gcc (Alpine 9.3.0) 9.3.0, 64-bit
Operating system: Windows 10 Professional + Docker
I think this could be done even in a patch version, would be really useful for users. Thanks for reporting!
@YohDeadfall
I thought about adding the support in our F# library, but I think it would be a nice addition to npgsql itself, but yea a patch could just do as well.
Any pointers about existing patches / addons that can hint me in the right direction?
Otherwise, specify the type name instead of NpgsqlDbType. Or use discriminating unions to pass the exact name just for enums.
Already checked, this is what we did our with F# lib at work
By the way, you can avoid specifying the type in case when it can be determined by the driver from the CLR type. See our documnetation for details.
Also what we did that with our F# lib at work:
/// PostgreSQL unmapped through the npgsql mappertypeUnmappedEnum=/// As a .NET Enum marked with the PgName attribute, only works when reading data| AsEnum ofEnum/// As a string| AsString ofstring// https://www.npgsql.org/doc/types/basic.html// https://stackoverflow.com/a/845472/4636721typePostgreSqlDbValue=| Null
| Bit ofbool| Boolean ofbool| SmallInt ofint16| Integer ofint32| Oid ofuint32| Xid ofuint32| Cid ofuint32| BigInt ofint64| Real ofsingle| Double ofdouble| Money ofdecimal| Numeric ofdecimal| ByteA ofuint8array| OidVector ofuint32array| Uuid ofGuid| INet ofIPAddress| MacAddr ofPhysicalAddress| TsQuery ofNpgsqlTsQuery| TsVector ofNpgsqlTsVector| Point ofNpgsqlPoint| LSeg ofNpgsqlLSeg| Path ofNpgsqlPath| Polygon ofNpgsqlPolygon| Line ofNpgsqlLine| Circle ofNpgsqlCircle| Box ofNpgsqlBox| HStore ofDictionary<string,string>| Date ofDateTime| Interval ofTimeSpan| Time ofDateTime| TimeTz ofDateTime| Timestamp ofDateTime| TimestampTz ofDateTimeOffset| InternalChar ofuint8| Char ofstring| VarChar ofstring| Name ofstring| CiText ofstring| Text ofstring| Xml ofstring| Json ofstring| Jsonb ofstring/// Only if the relevant Npgsql mapping for the Enum has been set up beforehand./// See: https://www.npgsql.org/doc/types/enums_and_composites.html| MappedEnum ofEnum/// Only if there is no relevant Npgsql mapping that has been set up beforehand.| UnmappedEnum ofvalue:UnmappedEnum*typeName:string
@roji, the next PR with tests I told you about is for that issue, and I think it's a good non-breaking improvement for 5.0.1 which gave me some thoughts on mappings for future changes.
I know we merged #3391 for 5.0.1 even though it could be considered a feature, though it also seems to have been an omission (i.e. almost a bug). This case (writing unmapped enums) is less clear.
changed the title [-]Add another field (optional) in PgNameAttribute to support specific enum type for both reading and writing with unmapped enums.[/-][+]Allow unmapped enums to be written[/+]on Dec 11, 2020
I know we merged #3391 for 5.0.1 even though it could be considered a feature, though it also seems to have been an omission (i.e. almost a bug). This case (writing unmapped enums) is less clear.
I guess I'm fine with it, it's very low-risk.
Based on my understanding, this should work fine starting with version 5.0.1?
Activity
YohDeadfall commentedon Dec 4, 2020
I think this could be done even in a patch version, would be really useful for users. Thanks for reporting!
natalie-o-perret commentedon Dec 4, 2020
@YohDeadfall
I thought about adding the support in our F# library, but I think it would be a nice addition to npgsql itself, but yea a patch could just do as well.
Any pointers about existing patches / addons that can hint me in the right direction?
YohDeadfall commentedon Dec 4, 2020
For now you should map the enum since for mapped it's supported already:
npgsql/src/Npgsql/TypeMapping/TypeMapperBase.cs
Lines 53 to 54 in 4aad4c0
npgsql/src/Npgsql/TypeMapping/TypeMapperBase.cs
Lines 127 to 129 in 4aad4c0
Otherwise, specify the type name instead of
NpgsqlDbType. Or use discriminating unions to pass the exact name just for enums.By the way, you can avoid specifying the type in case when it can be determined by the driver from the CLR type. See our documnetation for details.
natalie-o-perret commentedon Dec 4, 2020
Already checked, this is what we did our with F# lib at work
Also what we did that with our F# lib at work:
YohDeadfall commentedon Dec 8, 2020
@roji, the next PR with tests I told you about is for that issue, and I think it's a good non-breaking improvement for 5.0.1 which gave me some thoughts on mappings for future changes.
roji commentedon Dec 10, 2020
@YohDeadfall approved this, thanks! I'm not quite sure it's a good fit for 5.0.1 though, as this is really a new feature.
roji commentedon Dec 10, 2020
I know we merged #3391 for 5.0.1 even though it could be considered a feature, though it also seems to have been an omission (i.e. almost a bug). This case (writing unmapped enums) is less clear.
I guess I'm fine with it, it's very low-risk.
Supported unmapped enum writing (#3398)
Supported unmapped enum writing (#3398)
[-]Add another field (optional) in PgNameAttribute to support specific enum type for both reading and writing with unmapped enums.[/-][+]Allow unmapped enums to be written[/+]natalie-o-perret commentedon Dec 18, 2020
@roji @YohDeadfall
Based on my understanding, this should work fine starting with version 5.0.1?
YohDeadfall commentedon Dec 18, 2020
Yes, it's published already.
natalie-o-perret commentedon Dec 18, 2020
@YohDeadfall cool, that's pretty awesome!
(Need to adjust our lib then)