8000 validation: AQL functions by ObiWahn · Pull Request #11327 · arangodb/arangodb · GitHub
[go: up one dir, main page]

Skip to content

validation: AQL functions #11327

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

Merged
merged 20 commits into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions arangod/Aql/AqlFunctionFeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ void AqlFunctionFeature::addMiscFunctions() {
add({"DECODE_REV", ".", flags, &Functions::DecodeRev});
add({"V8", ".", Function::makeFlags(FF::Deterministic, FF::Cacheable)}); // only function without a
// C++ implementation
//
auto validationFlags = Function::makeFlags(FF::None);
add({"GET_SCHEMA", ".", validationFlags, &Functions::GetSchema});
add({"SCHEMA_VALIDATE", ".,.", validationFlags, &Functions::SchemaValidate});

// special flags:
add({"VERSION", "", Function::makeFlags(FF::Deterministic), &Functions::Version}); // deterministic, not cacheable. only on
Expand Down
481 changes: 278 additions & 203 deletions arangod/Aql/Functions.cpp

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion arangod/Aql/Functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ struct Functions {
static AqlValue NgramSimilarity(ExpressionContext*, transaction::Methods*,
VPackFunctionParameters const&);
static AqlValue NgramPositionalSimilarity(ExpressionContext* ctx,
transaction::Methods*,
transaction::Methods*,
VPackFunctionParameters const&);
static AqlValue NgramMatch(ExpressionContext*, transaction::Methods*,
VPackFunctionParameters const&);
Expand Down Expand Up @@ -471,6 +471,11 @@ struct Functions {
static AqlValue CurrentUser(arangodb::aql::ExpressionContext*,
transaction::Methods*, VPackFunctionParameters const&);

static AqlValue GetSchema(arangodb::aql::ExpressionContext*,
transaction::Methods*, VPackFunctionParameters const&);
static AqlValue SchemaValidate(arangodb::aql::ExpressionContext*,
transaction::Methods*, VPackFunctionParameters const&);

/// @brief dummy function that will only throw an error when called
static AqlValue NotImplemented(arangodb::aql::ExpressionContext*,
transaction::Methods*, VPackFunctionParameters const&);
Expand Down
10 changes: 6 additions & 4 deletions arangod/VocBase/LogicalCollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1157,8 +1157,9 @@ Result LogicalCollection::validate(VPackSlice s, VPackOptions const* options) co
auto vals = std::atomic_load_explicit(&_validators, std::memory_order_relaxed);
if (vals == nullptr) { return {}; }
for(auto const& validator : *vals) {
if(!validator->validate(s, VPackSlice::noneSlice(), true, options)) {
return {TRI_ERROR_VALIDATION_FAILED, "validation failed: " + validator->message() };
auto rv = validator->validate(s, VPackSlice::noneSlice(), true, options);
if(rv.fail()) {
return rv;
}
}
return {};
Expand All @@ -1168,8 +1169,9 @@ Result LogicalCollection::validate(VPackSlice modifiedDoc, VPackSlice oldDoc, VP
auto vals = std::atomic_load_explicit(&_validators, std::memory_order_relaxed);
if (vals == nullptr) { return {}; }
for(auto const& validator : *vals) {
if(!validator->validate(modifiedDoc, oldDoc, false, options)) {
return {TRI_ERROR_VALIDATION_FAILED, "validation failed: " + validator->message() };
auto rv = validator->validate(modifiedDoc, oldDoc, false, options);
if(rv.fail()) {
return rv;
}
}
return {};
Expand Down
40 changes: 31 additions & 9 deletions arangod/VocBase/Validators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,34 +119,44 @@ ValidatorBase::ValidatorBase(VPackSlice params)
}
}

bool ValidatorBase::validate(VPackSlice newDoc, VPackSlice oldDoc, bool isInsert, VPackOptions const* options) const {
Result ValidatorBase::validate(VPackSlice newDoc, VPackSlice oldDoc, bool isInsert, VPackOptions const* options) const {
// This function performs the validation depending on operation (Insert /
// Update / Replace) and requested validation level (None / Insert / New /
// Strict / Moderate).

if (this->_level == ValidationLevel::None) {
return true;
return {};
}

if (isInsert) {
return this->validateDerived(newDoc, options);
return this->validateOne(newDoc, options);
}

/* update replace case */
if (this->_level == ValidationLevel::New) {
// Level NEW is for insert only.
return true;
return {};
}

if (this->_level == ValidationLevel::Strict) {
// Changed document must be good!
return validateDerived(newDoc, options);
return validateOne(newDoc, options);
}

TRI_ASSERT(this->_level == ValidationLevel::Moderate);
// Changed document must be good IIF the unmodified
// document passed validation.
return (this->validateDerived(newDoc, options) || !this->validateDerived(oldDoc, options));

auto resNew = this->validateOne(newDoc, options);
if(resNew.ok()){
return {};
}

if(this->validateOne(oldDoc, options).fail()){
return {};
}

return resNew;
}

void ValidatorBase::toVelocyPack(VPackBuilder& b) const {
Expand All @@ -163,10 +173,17 @@ void ValidatorBase::toVelocyPack(VPackBuilder& b) const {
ValidatorBool::ValidatorBool(VPackSlice params) : ValidatorBase(params) {
_result = params.get(StaticStrings::ValidatorParameterRule).getBool();
}
bool ValidatorBool::validateDerived(VPackSlice slice, VPackOptions const* options) const { return _result; }
Result ValidatorBool::validateOne(VPackSlice slice, VPackOptions const* options) const {
if (_result){
return {};
}
return {TRI_ERROR_VALIDATION_FAILED, _message};
}

void ValidatorBool::toVelocyPackDerived(VPackBuilder& b) const {
b.add(StaticStrings::ValidatorParameterRule, VPackValue(_result));
}

std::string const& ValidatorBool::type() const {
return StaticStrings::ValidatorTypeBool;
}
Expand All @@ -191,8 +208,13 @@ ValidatorJsonSchema::ValidatorJsonSchema(VPackSlice params) : ValidatorBase(para
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_VALIDATION_BAD_PARAMETER, msg);
}
}
bool ValidatorJsonSchema::validateDerived(VPackSlice slice, VPackOptions const* options) const {
return validation::validate(*_schema, _special, slice, options);

Result ValidatorJsonSchema::validateOne(VPackSlice slice, VPackOptions const* options) const {
auto res = validation::validate(*_schema, _special, slice, options);
if (res){
return {};
}
return {TRI_ERROR_VALIDATION_FAILED, _message};
}
void ValidatorJsonSchema::toVelocyPackDerived(VPackBuilder& b) const {
TRI_ASSERT(!_builder.slice().isNone());
Expand Down
13 changes: 9 additions & 4 deletions arangod/VocBase/Validators.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,19 @@ struct ValidatorBase {
explicit ValidatorBase(VPackSlice params);
virtual ~ValidatorBase() = default;

bool validate(VPackSlice new_, VPackSlice old_, bool isInsert, VPackOptions const*) const;
// Validation function as it should be used in the logical collection or storage engine.
Result validate(VPackSlice newDoc, VPackSlice oldDoc, bool isInsert, VPackOptions const*) const;

// Validate a single document in the specialized class ignoring the the level.
// This version is used in the implementations of AQL Functions.
virtual Result validateOne(VPackSlice slice, VPackOptions const*) const = 0;

void toVelocyPack(VPackBuilder&) const;
virtual std::string const& type() const = 0;
std::string const& message() const { return this->_message; }
std::string const& specialProperties() const;

protected:
virtual bool validateDerived(VPackSlice slice, VPackOptions const*) const = 0;
virtual void toVelocyPackDerived(VPackBuilder&) const = 0;

std::string _message;
Expand All @@ -70,7 +75,7 @@ struct ValidatorBase {

struct ValidatorJsonSchema : public ValidatorBase {
explicit ValidatorJsonSchema(VPackSlice params);
bool validateDerived(VPackSlice slice, VPackOptions const*) const override;
Result validateOne(VPackSlice slice, VPackOptions const*) const override;
void toVelocyPackDerived(VPackBuilder& b) const override;
std::string const& type() const override;
private:
Expand All @@ -80,7 +85,7 @@ struct ValidatorJsonSchema : public ValidatorBase {

struct ValidatorBool : public ValidatorBase {
explicit ValidatorBool(VPackSlice params);
bool validateDerived(VPackSlice slice, VPackOptions const*) const override;
Result validateOne(VPackSlice slice, VPackOptions const*) const override;
void toVelocyPackDerived(VPackBuilder& b) const override;
std::string const& type() const override;

Expand Down
22 changes: 22 additions & 0 deletions tests/js/common/shell/shell-validation-rocksdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,28 @@ function ValidationBasicsSuite () {
}

},
// AQL ////////////////////////////////////////////////////////////////////////////////////////////
testGET_SCHEMA: () => {
const v = validatorJson;
v.level = "strict";
testCollection.properties({"validation" : v });
sleepInCluster();

let res = db._query(`RETURN GET_SCHEMA("${testCollectionName}")`).toArray();
assertEqual(res[0], v.rule);
},

testSCHEMA_VALIDATE: () => {
const v = validatorJson;
testCollection.properties({"validation" : { rule:{} } });
sleepInCluster();

let res = db._query(`RETURN SCHEMA_VALIDATE({"foo" : 24}, { "properties" : { "foo" : { "type" : "string" } } } )`).toArray();
assertEqual(res[0].valid, false);

res = db._query(`RETURN SCHEMA_VALIDATE({"foo" : "bar"}, { "properties" : { "foo" : { "type" : "string" } } } )`).toArray();
assertEqual(res[0].valid, true);
},

////////////////////////////////////////////////////////////////////////////////
}; // return
Expand Down
0