MasoniteFramework / orm

Masonite ORM is a beautiful Python ORM. It's also a nearly drop in replacement of the Orator ORM
https://orm.masoniteproject.com
MIT License
179 stars 49 forks source link

Question: how to implement multiple (possibly virtual) bool attributes for global scope manipulation #539

Closed circulon closed 2 years ago

circulon commented 2 years ago

Describe the feature as you'd like to see it So in many of my tables I currently have 2 (sometimes more) boolean flags that indicate a given rows state (eg "active", "verified")

I am currently implementing these as separate mixins with their own global scopes. The problem lies in combining these global scopes.
As the scopes have no knowledge of each other combining them for various AND, OR, NOT etc boolean logical operations.

Then I considered combining them all into a single mixin with a special __active_flags__ attribute that defined which columns are active on that model. The mixin contains logic for combining these flags in various ways and building the where, but its still seems overly complicated.

Then I thought hey lets use bit flags on a single column INT as this gives maximum flexibility and I can use bit AND, OR, NOT, XOR combinations in both python and the db engine.

Then I tried and failed to implement this (bit)flags scenario with the py-flags module. More specifically I could not work out how to make the virtual attributes contained inside the Flags Class be visible to the Model as callable attributes.

So my question is really how could I implement some kind of dynamic boolean flag implementation? Am I on the right track? or is there a different way I should be looking at this problem? This is not an uncommon scenario and offers a lot of flexibility around per row settings.

Feedback and discussion or ideas for implementation would be greatly appreciated

Marlysson commented 2 years ago

How are you currently implementing these scopes in separated logics?

josephmancuso commented 2 years ago

@circulon If I understand the issue correctly this this could only really be done using normal scopes:

class User(Model):

    def active(self, query):
        return query.where('active', 1)

    def verified(self, query):
        return query.where('verified', 1)

    def verified_active(self, query):
        return self.active().verified()

And then used like this:

user = User.active().get()
user = User.verified_active().get()
josephmancuso commented 2 years ago

For dynamic you could also put in a parameter into the scope:

class User(Model):

    def active(self, query, value):
        return query.where('active', value)

    def verified(self, query, value):
        return query.where('verified', value)

    def verified_active(self, query, active=1, verified=1):
        return self.active(active).verified(verified)
user = User.verified_active(1, 0).get()