Jaymon / prom

A PostgreSQL or SQLite orm for Python
MIT License
22 stars 4 forks source link

Field and Orm assure methods #131

Open Jaymon opened 3 years ago

Jaymon commented 3 years ago

I commonly need to make sure the input is valid in relation to other fields, there are a couple places you can currently do this, using modify_fields or to_interface. Here are some ideas to make this more robust:

assure_fields

Here is an example of a modify_fields that sets values based on other values:

def modify_fields(self, fields):
    ret = {}

    foo = fields.pop("foo", None)
    bar = fields.pop("bar", None)

    if foo and bar:
        if not fields.get("foo_hash", None):
            fields["foo_hash"] = self.hash_value(String(foo), bar)

        if not fields.get("bar_hash", None):
            fields["bar_hash"] = self.hash_value(bar, String(foo))

    else:
        if foo and not fields.get("foo_hash", None):
            raise ValueError("You cannot set foo without bar")

        if bar and not fields.get("bar_hash", None):
            raise ValueError("You cannot set bar without foo")

    if fields.get("che", None):
        che = fields.pop("che")
        if che and not fields.get("che_hash", None):
            fields["che_hash"] = self.hash_che(che)

    # find all the passed in fields that should be in the misc dict
    misc_fields = fields.pop("misc", self.misc)

    for k in self.schema.fields.keys():
        if k in fields:
            ret[k] = fields.pop(k)

    misc_fields.update(fields)
    ret["misc"] = misc_fields
    return ret

As you can see, foo is dependent on bar, and things like that. It works to do it here but this is only ran when all fields are modified, so this wouldn't get run when something is set individually, something like this:

fb = FooBar()
fb.foo = "blah"

So I'm wondering if I can add an assure_fields method that would get called in to_interface and modify and would take a fields and allow you to normalize the fields and shift everything around, basically exactly what modify_fields is for but is ran more often to make sure the Orm instance is in the correct state.

Bad things is it would be run multiple times in a row if you did something like FooBar.create(**kwargs) because it would get run in modify and then ran again in to_interface but I don't know if that is awful for the assurance that it does give that the data is what is expected.

Individual Field methods

I could also add an assure method on the Field that would be called with a signature like this:

def assure(self, orm, fields)

and then it would return the correct value from the fields dict. You could even segment this more and have iassure() for going into the db and fassure for setting the field's value.