-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simple Enum Support #502
Comments
Sample Text |
Any plans to release this soon? Also, I doesn't look like it supports Enums in |
@matee911 You mean currently, or one of the planned approaches (A or B)? |
I'd now change the def _get_real_converter(self, py_type):
"""
Gets a converter for the underlying type.
:return: Type[Converter]
"""
for t, converter_cls in self.provider.converter_classes:
if issubclass(t, EnumConverter):
# skip our own type, otherwise this could get ugly
continue
# end if
if issubclass(py_type, t):
return converter_cls
# end if
# end for
throw(TypeError, 'No database converter found for enum base type %s' % py_type)
# end def (no longer a That should allow to use all the types the database/pony supports. |
I'll mirror the discussion we have in telegram here. |
Alexander Kozlovsky, 31. Jan 2021:
[Numbers added to easier reference them.] |
Thanks for taking your time for looking into this. I'll respond to your paragraphs below, counting them from the top, starting at 1. 1) I think the fact that this is no database side enum but actually just the values in the database is a fact which just has to be documented clearly, really. 2) Thanks! I think that will really be helpful for working with enum values. 3+4) Okey, I'll check py2 that in detail. 5) 6+1) I still think that doesn't really matter for this approach too much. If database enums are added later it could be done in a transparent and forward compatible way. Either opt-in or opt-out. I am thinking Required(SomeEnum, database=True) or something similar (don't pin me on that variable name). In fact, from reading up on enum types in postgres, I think it is compatible as long as you manually run a The only thing this is missing is the automised approach, but for that we should probably do migrations first, and thus I would want to keep those topics separated. [typos fixed] |
Additionally I want to add, there was asked about a key based version of this, so an int enum would still store a string like |
luckydonald, 10. February 2021: 3+4) I had a bit of thought about py2 compatibility. I mean I if there's no Enums in py2 one can simply use normal numbers instead. We don't need to support something which doesn't exist on py2. 5) Regarding 6) Regarding database enums, |
|
5.) Sure, will use that. |
@luckydonald I'm trying to use your fork. Works very nice with a sqlite-DB 👍 . With a mysql-DB I'm getting this exception: is there a reason it shouldn't work against mysql? The traceback doesn't look useful to me, but I can share it of course if you think it is useful |
@arian-f I would also especially be interested in the parts of the Pony model which breaks it, so basically a minimal code example making it go boom:boom: would be great!
Or considering how long it's been ago, anything you can remember about it 😅 |
Nice Idea @luckydonald, |
Hi all. Is there any movement on this? I was bitten by this yesterday and it took me a while to figure out what was going on. For anyone else who Googles their way to this page, my workaround was to use raw = [
'x.some_col=="{}"'.format(MyEnum.some_attr.value),
'x.some_other_col=="{}"'.format(MyEnum.some_other_attr.value),
]
res = orm.select(
x for x in MyDbEntity if orm.raw_sql(
" and ".join(raw)
)
) |
@tweigel-dev In fact has a PR ready (#585), and I did test it a bit as well. See the unit tests there. @austinjp not that I'm aware of, that PR is waiting for review. Actually it would need a merge with the new changes, but hopefully that should still work. |
Seems that no enum support are merged. Should this be merged? Enum support is important. |
Abstract
This proposes support for normal type enums to be supported.
There would be no special tables added to model those inside the database.
They would be implemented only on a pure python level.
The database would simply store the value of those.
Previous implementation attempt, e.g. #346 and #392, needed to change the type of the field to store the names string, thus introducing an overhead and possible headaches like max length of a
VARCHAR(x)
and such.Storing the underlaying values, e.g.
int
of anIntEnum
allows it to use the same code used forint
, as well as all related settings when defining them in models.Introduction
In python Enums can have a native type associated with them.
The popular
IntEnum
(from enum import IntEnum
) is defined as the following:which would be typically be used as:
The
Enum
class now automatically makes all the attributes the same type as the Enum class.So here that's
int
andEnum
Now, because
FoobarEnum
(and soFoobarEnum.MANGO
,FoobarEnum.BANANA
, etc.) are already validint
types:Those can already be used when writing to the database.
Having pony model
you can easily set that with the enum:
The problem here is they won't be converted back to that enum class:
Proposal
The proposal is to store the underlying enum values, as those are basically already implemented, and all the corner cases in queries and such should be ironed out.
So only the retrieval must have an additional step of loading the value in the right Enum type.
This is as easy as
FoobarEnum(4458)
:Implementation Approaches
Both share that the upgrade would be strait forward replacing a type with any fitting class being subclass of that original type (here:
int
) and implementingenum.Enum
. An example would beenum.IntEnum
:This can be monkey patched for testing purposes, like the following (click to expand)
Both work for enums with native types and the additional types supported by pony.
So
class IntEnum(int, Enum)
,class StrEnum(str, Enum)
,class BoolEnum(bool, Enum)
.Even more unusual enum types like
class DateEnum(datetime.datetime, Enum)
, etc. would work.Implementation Approach A
Possibly
self._get_real_converter(self.py_type)
can be replaced by simply usingself.provider.get_converter_by_py_type(self.py_type)
.It is just added above as an extra function to illustrate the working of it better.
Needed changes:
converter_classes
need to includeEnumConverter
as well.EnumConverter
class would always be chosen before any class implementing the underlying enum type, likeint
.pony.orm.dbproviders
).Example for
pony.orm.dbproviders.mysql
:converter_classes = [ + (Enum, dbapiprovider.EnumConverter), (NoneType, dbapiprovider.NoneConverter), (bool, dbapiprovider.BoolConverter), (basestring, MySQLStrConverter), (int_types, dbapiprovider.IntConverter), (float, MySQLRealConverter), … ]
Implementation Approach B
Here the existing
Converter
s would be modified to support enums.In their
dbval2val
they would be modified to include the following code before returning the value:Implementation Decision
Probably A is the cleaner approach as that requires less places to modify (or forget to do so), and also works with all database-native types as well as future types as well.
Limitations
The special meaning a enum has, that is both having a name and making sure those values are whitelisted will not be reflected inside the database, it would only be enforced by the python side.
Only enums combining native types (or other types already supported by pony) can be used, as the value is stored, not the keys.
This means no enums combining multiple types.
The following would be impossible:
The text was updated successfully, but these errors were encountered: