moigagoo / norm

A Nim ORM for SQLite and Postgres
https://norm.nim.town
MIT License
381 stars 34 forks source link

[Feature Request] Enum Support #166

Closed aMOPel closed 1 year ago

aMOPel commented 2 years ago

You've already indirectly talked about enum support in https://github.com/moigagoo/norm/issues/34#issuecomment-544385989

Enums feel like a rather important thing in nim to me, so I think it would great to support it out of the box.

Since Postgres has an enumtype it should be kinda straight forward.

Regarding your question how to handle enums in sqlite: I have this in my project atm, which encodes enums as strings and parses them back using std/strutils.parseEnum

func dbType*(T: typedesc[enum]): string = "STRING"
func dbValue*(val: enum): DbValue = DbValue(kind: dvkString, s: $val)
func to*(dbVal: DbValue, T: typedesc[enum]): T = parseEnum[T](dbVal.s)

I imagine this could be rather costly for huge databases, so I don't know if it's a great solution. However the benefit is, that the meaning of the value is preserved in the database.

The alternative would be to encode the enum as ints, obviously. Probably that is the better default choice. The best way would be, to enable norm users to choose I guess.

Thanks for all the work put into norm. It's great!

PhilippMDoerner commented 2 years ago

This is not strictly helpful to you since you already stumbled upon how to add enum support, but for others:

There now is norm documentation that details how to add support for whatever data-type you have, including enums.

I'm conflicted on providing a default when this feels like a decision the user might want to specify themselves (not that my opinion matters, I merely wanted to voice it). If a default must be provided I'd vote for storing as int, with the user having to provide their own dbType/dbValue/to procs if they want something else.

Luckily, as you noted, adding default enum support isn't really difficult, literally just defining these 3 procs once for sqlite and once for postgres and then writing some test-cases for it (which should include a test-case where the default procs get overwritten by user-defined procs for a specific enum, just to make sure that works).

moigagoo commented 2 years ago

I agree with the previous comment.

Summary:

  1. Supporting arbitrary types is as easy as implementing three procs.
  2. Norm doesn't have to cover all types there are. Norm covers the obvious types (string is TEXT, int is INTEGER, etc.).
  3. I'm not against adding enum support to the core. PRs are welcome.
  4. If someone chooses to implement this, please store enum values as ints.
PhilippMDoerner commented 1 year ago

Was implemented in lowdb as part of https://github.com/PhilippMDoerner/lowdb/pull/8 , kudos to ire4ever for doing pretty much all of the work there. Did show me that I should be going over the test-suite there though.

So I just need to release a new lowdb version and norm needs to update its lowdb dependency and we have it here.