ArangoDB-Community / pyArango

Python Driver for ArangoDB with built-in validation
https://pyarango.readthedocs.io/en/latest/
Apache License 2.0
238 stars 90 forks source link

Not able to add additional fields to document #196

Open declance opened 3 years ago

declance commented 3 years ago

I have a document definition similar to this one:

` class Humans(COL.Collection):

_properties = { "keyOptions" : { "allowUserKeys": False, "type": "autoincrement", "increment": 1, "offset": 0, } }

_validation = {
    'on_save': True,
    'on_set': True,
    'allow_foreign_fields': True  # allow fields that are not part of the schema
}

_fields = {
    'name': COL.Field(validators=[VAL.NotNull(), String_val()]),
    'anything': COL.Field(),
    'species': COL.Field(validators=[VAL.NotNull(), VAL.Length(5, 15), String_val()])
}

`

---> 'allow_foreign_fields': True is set to True

When I create a document and want to add a field (remember ---> 'allow_foreign_fields': True) it throws an exception

 66 
 67             if field in self.patchStore:

---> 68 return self.validators[field].validate(self.patchStore[field]) 69 else: 70 try:

KeyError: 'test'

I know, that it would change the schema... but I thought I have a validation part, that has to be there and an optional part... How can this be reached? Thanks for support!

Alexsaphir commented 3 years ago

First thing the string validator is not valid in python 3, I rewrited the String_val class to work :

class String_val(VAL.Validator):
    def validate(self, value):
        if not isinstance(value, str):
            raise ValidationError("Field value must be a string")
        return True

And you're right, there is an issue with the validation, the following definition for validateField, in the file document.py, fix this issue :

    def validateField(self, field):
        """Validatie a field"""
        if field not in self.validators:
            if not self.collection._validation['allow_foreign_fields']:
                raise SchemaViolation(self.collection.__class__, field)
            else:
                return True

        if field in self.store:
            if isinstance(self.store[field], DocumentStore):
                return self[field].validate()

            if field in self.patchStore:
                return self.validators[field].validate(self.patchStore[field])
            else:
                try:
                    return self.validators[field].validate(self.store[field])
                except ValidationError as e:
                    raise ValidationError( "'%s' -> %s" % ( field, str(e)) )
                except AttributeError:
                    if isinstance(self.validators[field], dict) and not isinstance(self.store[field], dict):
                        raise ValueError("Validator expected a sub document for field '%s', got '%s' instead" % (field, self.store[field]) )
                    else:
                        raise
        return True