fishy commented on code in PR #2469:
URL: https://github.com/apache/thrift/pull/2469#discussion_r939540233
##########
lib/go/thrift/application_exception.go:
##########
@@ -49,6 +50,7 @@ var defaultApplicationExceptionMessage = map[int32]string{
INVALID_TRANSFORM: "Invalid transform",
INVALID_PROTOCOL: "Invalid protocol",
UNSUPPORTED_CLIENT_TYPE: "Unsupported client type",
+ VALIDATOR_CHECK_FAILED: "Validator check failed",
Review Comment:
"validator check failed" sounds weird to me, maybe it should be "validator
failed" or "validation failed"?
##########
lib/go/test/tests/validate_test.go:
##########
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package tests
+
+import (
+ "testing"
+
+ "github.com/apache/thrift/lib/go/test/gopath/src/validatetest"
+)
+
+func TestValidator(t *testing.T) {
+ bt := validatetest.NewBasicTest()
+ if err := bt.Validate(); err != nil {
+ t.Fatal(err)
Review Comment:
1. this should be `t.Error` not `t.Fatal`
2. what this tests is that all zero/default values of the thrift struct
passes the validation, which both requires the validation definition written in
the thrift file to allow all zero/default values, and also is not very useful.
we need to actually fill some data that would fail the validator and test that
`Validate` does indeed return an error, and also valid data passes them.
##########
compiler/cpp/src/thrift/generate/t_go_generator.h:
##########
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_GO_GENERATOR_H
+#define T_GO_GENERATOR_H
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "thrift/generate/t_generator.h"
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include <algorithm>
+#include <clocale>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift";
+static std::string package_flag;
+
+/**
+ * Go code generator.
+ */
+class t_go_generator : public t_generator {
+public:
+ t_go_generator(t_program* program,
+ const std::map<std::string, std::string>& parsed_options,
+ const std::string& option_string)
+ : t_generator(program) {
+ (void)option_string;
+ std::map<std::string, std::string>::const_iterator iter;
+
+ gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
+ gen_package_prefix_ = "";
+ package_flag = "";
+ read_write_private_ = false;
+ ignore_initialisms_ = false;
+ skip_remote_ = false;
+ generate_validator = false;
+ for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+ if (iter->first.compare("package_prefix") == 0) {
+ gen_package_prefix_ = (iter->second);
+ } else if (iter->first.compare("thrift_import") == 0) {
+ gen_thrift_import_ = (iter->second);
+ } else if (iter->first.compare("package") == 0) {
+ package_flag = (iter->second);
+ } else if (iter->first.compare("read_write_private") == 0) {
+ read_write_private_ = true;
+ } else if (iter->first.compare("ignore_initialisms") == 0) {
+ ignore_initialisms_ = true;
+ } else if( iter->first.compare("skip_remote") == 0) {
+ skip_remote_ = true;
+ } else if (iter->first.compare("generate_validator") == 0) {
+ generate_validator = true;
Review Comment:
so this is actually opt-in, e.g. users need to add `generate_validator` to
the thrift compiler command line to enable this feature, right? I don't see
this documented anywhere (my impression from the proposal is that this would be
opt-out instead)
also if we have this as a command line arg then I'm not sure why would we
add it as an option to CMake, on CMake level it should always be enabled or
disabled together with the go compiler itself?
##########
compiler/cpp/src/thrift/generate/go_validator_generator.cc:
##########
@@ -0,0 +1,692 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U go_validator_generator.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "thrift/generate/go_validator_generator.h"
+#include "thrift/generate/validator_parser.h"
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include <algorithm>
+#include <clocale>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+std::string go_validator_generator::get_field_reference_name(t_field* field) {
+ t_type* type(field->get_type());
+ std::string tgt;
+ t_const_value* def_value;
+ go_generator->get_publicized_name_and_def_value(field, &tgt, &def_value);
+ tgt = "p." + tgt;
+ if (go_generator->is_pointer_field(field)
+ && (type->is_base_type() || type->is_enum() || type->is_container())) {
+ tgt = "*" + tgt;
+ }
+ return tgt;
+}
+
+void go_validator_generator::generate_struct_validator(std::ostream& out,
t_struct* tstruct) {
+ std::vector<t_field*> members = tstruct->get_members();
+ validation_parser parser(tstruct);
+ for (auto it = members.begin(); it != members.end(); it++) {
+ t_field* field(*it);
+ const std::vector<validation_rule*>& rules
+ = parser.parse_field(field->get_type(), field->annotations_);
+ if (rules.size() == 0) {
+ continue;
+ }
+ bool opt = field->get_req() == t_field::T_OPTIONAL;
+ t_type* type = field->get_type();
+ std::string tgt = get_field_reference_name(field);
+ std::string field_symbol = tstruct->get_name() + "." + field->get_name();
+ generate_field_validator(out, generator_context{field_symbol, "", tgt,
opt, type, rules});
+ }
+}
+
+void go_validator_generator::generate_field_validator(std::ostream& out,
+ const generator_context&
context) {
+ t_type* type = context.type;
+ if (type->is_typedef()) {
+ type = type->get_true_type();
+ }
+ if (type->is_enum()) {
+ if (context.tgt[0] == '*') {
+ out << "if " << context.tgt.substr(1) << " != nil {" << endl;
Review Comment:
please call `indent_up();` after `{` and `indent_down();` before `}`.
##########
compiler/cpp/src/thrift/generate/t_json_generator.cc:
##########
@@ -268,7 +268,9 @@ void t_json_generator::write_type_spec(t_type* ttype) {
write_key_and("annotations");
start_object();
for (auto & annotation : ttype->annotations_) {
- write_key_and_string(annotation.first, annotation.second);
+ for (auto& annotation_value : annotation.second) {
+ write_key_and_string(annotation.first, annotation_value);
+ }
Review Comment:
we should also add a test to make sure that the validator annotations can
co-exist with other annotations.
##########
compiler/cpp/CMakeLists.txt:
##########
@@ -71,35 +73,50 @@ macro(THRIFT_ADD_COMPILER name description initial)
endif()
endmacro()
+# This macro adds an option THRIFT_VALIDATOR_COMPILER_${NAME}
+# that allows enabling or disabling certain languages
Review Comment:
```suggestion
# that allows enabling or disabling certain languages' validator
```
##########
compiler/cpp/CMakeLists.txt:
##########
@@ -71,35 +73,50 @@ macro(THRIFT_ADD_COMPILER name description initial)
endif()
endmacro()
+# This macro adds an option THRIFT_VALIDATOR_COMPILER_${NAME}
+# that allows enabling or disabling certain languages
+macro(THRIFT_ADD_VALIDATOR_COMPILER name description initial)
+ string(TOUPPER "THRIFT_VALIDATOR_COMPILER_${name}" enabler)
+ set(src "src/thrift/generate/${name}_validator_generator.cc")
+ list(APPEND "src/thrift/generate/${name}_validator_generator.h")
+ option(${enabler} ${description} ${initial})
+ if(${enabler})
+ list(APPEND thrift-compiler_SOURCES ${src})
Review Comment:
I'm not very familiar with CMake but looking at this and line 71, it seems
to me that if someone tries to disable `THRIFT_VALIDATOR_COMPILER_go` it will
also disable `THRIFT_COMPILER_go`? or maybe this will add duplicated items to
the list?
##########
compiler/cpp/src/thrift/generate/go_validator_generator.cc:
##########
@@ -0,0 +1,692 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U go_validator_generator.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "thrift/generate/go_validator_generator.h"
+#include "thrift/generate/validator_parser.h"
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include <algorithm>
+#include <clocale>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+std::string go_validator_generator::get_field_reference_name(t_field* field) {
+ t_type* type(field->get_type());
+ std::string tgt;
+ t_const_value* def_value;
+ go_generator->get_publicized_name_and_def_value(field, &tgt, &def_value);
+ tgt = "p." + tgt;
+ if (go_generator->is_pointer_field(field)
+ && (type->is_base_type() || type->is_enum() || type->is_container())) {
+ tgt = "*" + tgt;
+ }
+ return tgt;
+}
+
+void go_validator_generator::generate_struct_validator(std::ostream& out,
t_struct* tstruct) {
+ std::vector<t_field*> members = tstruct->get_members();
+ validation_parser parser(tstruct);
+ for (auto it = members.begin(); it != members.end(); it++) {
+ t_field* field(*it);
+ const std::vector<validation_rule*>& rules
+ = parser.parse_field(field->get_type(), field->annotations_);
+ if (rules.size() == 0) {
+ continue;
+ }
+ bool opt = field->get_req() == t_field::T_OPTIONAL;
+ t_type* type = field->get_type();
+ std::string tgt = get_field_reference_name(field);
+ std::string field_symbol = tstruct->get_name() + "." + field->get_name();
+ generate_field_validator(out, generator_context{field_symbol, "", tgt,
opt, type, rules});
+ }
+}
+
+void go_validator_generator::generate_field_validator(std::ostream& out,
+ const generator_context&
context) {
+ t_type* type = context.type;
+ if (type->is_typedef()) {
+ type = type->get_true_type();
+ }
+ if (type->is_enum()) {
+ if (context.tgt[0] == '*') {
+ out << "if " << context.tgt.substr(1) << " != nil {" << endl;
+ }
+ generate_enum_field_validator(out, context);
+ if (context.tgt[0] == '*') {
+ out << "}" << endl;
+ }
+ return;
+ } else if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ if (context.tgt[0] == '*') {
+ out << "if " << context.tgt.substr(1) << " != nil {" << endl;
+ }
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ break;
+ case t_base_type::TYPE_I8:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ case t_base_type::TYPE_I64:
+ generate_integer_field_validator(out, context);
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ generate_double_field_validator(out, context);
+ break;
+ case t_base_type::TYPE_STRING:
+ generate_string_field_validator(out, context);
+ break;
+ case t_base_type::TYPE_BOOL:
+ generate_bool_field_validator(out, context);
+ break;
+ }
+ if (context.tgt[0] == '*') {
+ out << "}" << endl;
+ }
+ return;
+ } else if (type->is_list()) {
+ return generate_list_field_validator(out, context);
+ } else if (type->is_set()) {
+ return generate_set_field_validator(out, context);
+ } else if (type->is_map()) {
+ return generate_map_field_validator(out, context);
+ } else if (type->is_struct() || type->is_xception()) {
+ return generate_struct_field_validator(out, context);
+ }
+ throw "validator error: unsupported type: " + type->get_name();
+}
+
+void go_validator_generator::generate_enum_field_validator(std::ostream& out,
+ const
generator_context& context) {
+ for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+ const std::vector<validation_value*>& values = (*it)->get_values();
+ if (values.size() == 0) {
+ continue;
+ }
+ std::string key = (*it)->get_name();
+
+ if (key == "vt.in") {
+ std::string exist = GenID("_exist");
+ out << "var " << exist << " bool" << endl;
+
+ std::string src = GenID("_src");
+ out << src << " := []string{";
+ for (auto it = values.begin(); it != values.end(); it++) {
+ if (it != values.begin()) {
+ out << ", ";
+ }
+ if ((*it)->is_field_reference()) {
+ out << get_field_reference_name((*it)->get_field_reference());
+ } else {
+ out << "\"" << (*it)->get_string() << "\"";
+ }
+ }
+ out << "}" << endl;
+
+ out << "for _, src := range " << src << " {" << endl;
+ out << "if (" << context.tgt << ").String() == src {" << endl;
+ out << exist << " = true" << endl;
+ out << "break" << endl;
+ out << "}" << endl;
+ out << "}" << endl;
+ out << "if " << exist << " == false {" << endl;
+ out << "return
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule vt.in check failed\")"
+ << endl;
+ out << "}" << endl;
+ } else if (key == "vt.not_in") {
+ std::string src = GenID("_src");
+ out << src << " := []string{";
+ for (auto it = values.begin(); it != values.end(); it++) {
+ if (it != values.begin()) {
+ out << ", ";
+ }
+ if ((*it)->is_field_reference()) {
+ out << get_field_reference_name((*it)->get_field_reference());
+ } else {
+ out << "\"" << (*it)->get_string() << "\"";
+ }
+ }
+ out << "}" << endl;
+
+ out << "for _, src := range " << src << " {" << endl;
+ out << "if (" << context.tgt << ").String() == src {";
+ out << " return
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule vt.not_in check failed\")"
+ << endl;
+ out << "}" << endl;
+ out << "}" << endl;
+ } else if (key == "vt.defined_only") {
+ if (values[0]->get_bool()) {
+ out << "if (" << context.tgt << ").String() == \"<UNSET>\" " << endl;
+ } else {
+ continue;
+ }
+ }
+ out << "{\nreturn
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule " << key
+ << " check failed\")\n}" << endl;
+ }
+}
+
+void go_validator_generator::generate_bool_field_validator(std::ostream& out,
+ const
generator_context& context) {
+ for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+ const std::vector<validation_value*>& values = (*it)->get_values();
+ if (values.size() == 0) {
+ continue;
+ }
+ std::string key = (*it)->get_name();
+
+ if (key == "vt.const") {
+ out << "if " << context.tgt << " != ";
+ if (values[0]->is_field_reference()) {
+ out << get_field_reference_name(values[0]->get_field_reference());
+ } else {
+ if (values[0]->get_bool()) {
+ out << "true";
+ } else {
+ out << "false";
+ }
+ }
+ }
+ out << "{\nreturn
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule " << key
+ << " check failed\")\n}" << endl;
+ }
+}
+
+void go_validator_generator::generate_double_field_validator(std::ostream& out,
+ const
generator_context& context) {
+ for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+ const std::vector<validation_value*>& values = (*it)->get_values();
+ if (values.size() == 0) {
+ continue;
+ }
+
+ std::map<std::string, std::string> signs{{"vt.lt", ">="},
+ {"vt.le", ">"},
+ {"vt.gt", "<="},
+ {"vt.ge", "<"}};
+ std::string key = (*it)->get_name();
+ auto key_it = signs.find(key);
+ if (key_it != signs.end()) {
+ out << "if " << context.tgt << " " << key_it->second << " ";
+ if (values[0]->is_field_reference()) {
+ out << get_field_reference_name(values[0]->get_field_reference());
+ } else {
+ out << values[0]->get_double();
+ }
+ out << " {\nreturn
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol
+ << " not valid, rule vt.const check failed\")\n}" << endl;
+ continue;
+ } else if (key == "vt.in") {
+ std::string exist = GenID("_exist");
+ out << "var " << exist << " bool" << endl;
+
+ std::string src = GenID("_src");
+ out << src << " := []float64{";
+ for (auto it = values.begin(); it != values.end(); it++) {
+ if (it != values.begin()) {
+ out << ", ";
+ }
+ if ((*it)->is_field_reference()) {
+ out << get_field_reference_name((*it)->get_field_reference());
+ } else {
+ out << (*it)->get_double();
+ }
+ }
+ out << "}" << endl;
+
+ out << "for _, src := range " << src << " {" << endl;
+ out << "if " << context.tgt << " == src {" << endl;
+ out << exist << " = true" << endl;
+ out << "break" << endl;
+ out << "}" << endl;
+ out << "}" << endl;
+ out << "if " << exist << " == false {" << endl;
+ out << "return
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule vt.in check failed\")"
+ << endl;
+ out << "}" << endl;
+ } else if (key == "vt.not_in") {
+ std::string src = GenID("_src");
+ out << src << " := []float64{";
+ for (auto it = values.begin(); it != values.end(); it++) {
+ if (it != values.begin()) {
+ out << ", ";
+ }
+ if ((*it)->is_field_reference()) {
+ out << get_field_reference_name((*it)->get_field_reference());
+ } else {
+ out << (*it)->get_double();
+ }
+ }
+ out << "}" << endl;
+
+ out << "for _, src := range " << src << " {" << endl;
+ out << "if " << context.tgt << " == src {";
+ out << " return
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule vt.not_in check failed\")"
+ << endl;
+ out << "}" << endl;
+ out << "}" << endl;
+ }
+ }
+}
+
+void go_validator_generator::generate_integer_field_validator(std::ostream&
out,
+ const
generator_context& context) {
+ auto generate_current_type = [](std::ostream& out, t_type* type) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_I8:
+ out << "int8";
+ break;
+ case t_base_type::TYPE_I16:
+ out << "int16";
+ break;
+ case t_base_type::TYPE_I32:
+ out << "int32";
+ break;
+ case t_base_type::TYPE_I64:
+ out << "int64";
+ break;
+ default:
+ throw "validator error: unsupported integer type: " + type->get_name();
+ }
+ };
+
+ for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+ const std::vector<validation_value*>& values = (*it)->get_values();
+ if (values.size() == 0) {
+ continue;
+ }
+
+ std::map<std::string, std::string> signs{{"vt.lt", ">="},
+ {"vt.le", ">"},
+ {"vt.gt", "<="},
+ {"vt.ge", "<"}};
+ std::string key = (*it)->get_name();
+ auto key_it = signs.find(key);
+ if (key_it != signs.end()) {
+ out << "if " << context.tgt << " " << key_it->second << " ";
+ if (values[0]->is_field_reference()) {
+ out << get_field_reference_name(values[0]->get_field_reference());
+ } else if (values[0]->is_validation_function()) {
+ generate_current_type(out, context.type);
+ out << "(";
+ validation_value::validation_function* func =
values[0]->get_function();
+ if (func->name == "len") {
+ out << "len(";
+ if (func->arguments[0]->is_field_reference()) {
+ out <<
get_field_reference_name(func->arguments[0]->get_field_reference());
+ }
+ out << ")";
+ }
+ out << ")";
+ } else {
+ out << values[0]->get_int();
+ }
+ out << "{\nreturn
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule " << key_it->first
+ << " check failed\")\n}" << endl;
+ } else if (key == "vt.in") {
+ std::string exist = GenID("_exist");
+ out << "var " << exist << " bool" << endl;
+
+ std::string src = GenID("_src");
+ out << src << " := []";
+ generate_current_type(out, context.type);
+ out << "{";
+ for (auto it = values.begin(); it != values.end(); it++) {
+ if (it != values.begin()) {
+ out << ", ";
+ }
+ if ((*it)->is_field_reference()) {
+ out << get_field_reference_name((*it)->get_field_reference());
+ } else if ((*it)->is_validation_function()) {
+ generate_current_type(out, context.type);
+ out << "(";
+ validation_value::validation_function* func = (*it)->get_function();
+ if (func->name == "len") {
+ out << "len(";
+ if (func->arguments[0]->is_field_reference()) {
+ out <<
get_field_reference_name(func->arguments[0]->get_field_reference());
+ }
+ out << ")";
+ }
+ out << ")";
+ } else {
+ out << (*it)->get_int();
+ }
+ }
+ out << "}" << endl;
+
+ out << "for _, src := range " << src << " {" << endl;
+ out << "if " << context.tgt << " == src {" << endl;
+ out << exist << " = true" << endl;
+ out << "break" << endl;
+ out << "}" << endl;
+ out << "}" << endl;
+ out << "if " << exist << " == false {" << endl;
+ out << "return
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule vt.in check failed\")"
+ << endl;
+ out << "}" << endl;
+ } else if (key == "vt.not_in") {
+ std::string src = GenID("_src");
+ out << src << " := []";
+ t_base_type::t_base tbase = ((t_base_type*)context.type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_I8:
+ out << "int8";
+ break;
+ case t_base_type::TYPE_I16:
+ out << "int16";
+ break;
+ case t_base_type::TYPE_I32:
+ out << "int32";
+ break;
+ case t_base_type::TYPE_I64:
+ out << "int64";
+ break;
+ default:
+ throw "validator error: unsupported integer type: " +
context.type->get_name();
+ }
+ out << "{";
+ for (auto it = values.begin(); it != values.end(); it++) {
+ if (it != values.begin()) {
+ out << ", ";
+ }
+ if ((*it)->is_field_reference()) {
+ out << get_field_reference_name((*it)->get_field_reference());
+ } else if ((*it)->is_validation_function()) {
+ generate_current_type(out, context.type);
+ out << "(";
+ validation_value::validation_function* func = (*it)->get_function();
+ if (func->name == "len") {
+ out << "len(";
+ if (func->arguments[0]->is_field_reference()) {
+ out <<
get_field_reference_name(func->arguments[0]->get_field_reference());
+ }
+ out << ")";
+ }
+ out << ")";
+ } else {
+ out << (*it)->get_int();
+ }
+ }
+ out << "}" << endl;
+
+ out << "for _, src := range " << src << " {" << endl;
+ out << "if " << context.tgt << " == src {";
+ out << " {\nreturn
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol
+ << " not valid, rule vt.not_in check failed\")\n}" << endl;
+ out << "}" << endl;
+ out << "}" << endl;
+ }
+ }
+}
+
+void go_validator_generator::generate_string_field_validator(std::ostream& out,
+ const
generator_context& context) {
+ std::string target = context.tgt;
+ t_type* type = context.type;
+ if (type->is_typedef()) {
+ type = type->get_true_type();
+ }
+ if (type->is_binary()) {
+ target = GenID("_tgt");
+ out << target << " := "
+ << "string(" << context.tgt << ")" << endl;
+ }
+ for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+ const std::vector<validation_value*>& values = (*it)->get_values();
+ if (values.size() == 0) {
+ continue;
+ }
+ std::string key = (*it)->get_name();
+
+ if (key == "vt.const") {
+ out << "if " << target << " != ";
+ if (values[0]->is_field_reference()) {
+ out << "string(";
+ out << get_field_reference_name(values[0]->get_field_reference());
+ out << ")";
+ } else {
+ out << "\"" << values[0]->get_string() << "\"";
+ }
+ } else if (key == "vt.min_size" || key == "vt.max_size") {
+ out << "if len(" << target << ") ";
+ if (key == "vt.min_size") {
+ out << "<";
+ } else {
+ out << ">";
+ }
+ out << "int(";
+ if (values[0]->is_field_reference()) {
+ out << get_field_reference_name(values[0]->get_field_reference());
+ } else if (values[0]->is_validation_function()) {
+ validation_value::validation_function* func =
values[0]->get_function();
+ if (func->name == "len") {
+ out << "len(";
+ if (func->arguments[0]->is_field_reference()) {
+ out << "string(";
+ out << get_field_reference_name(values[0]->get_field_reference());
+ out << ")";
+ }
+ out << ")";
+ }
+ } else {
+ out << values[0]->get_int();
+ }
+ out << ")";
+ } else if (key == "vt.pattern") {
+ out << "if ok, _ := regexp.MatchString(" << target << ",";
+ if (values[0]->is_field_reference()) {
+ out << "string(";
+ out << get_field_reference_name(values[0]->get_field_reference());
+ out << ")";
+ } else {
+ out << "\"" << values[0]->get_string() << "\"";
+ }
+ out << "); ok ";
+ } else if (key == "vt.prefix") {
+ out << "if !strings.HasPrefix(" << target << ",";
+ if (values[0]->is_field_reference()) {
+ out << "string(";
+ out << get_field_reference_name(values[0]->get_field_reference());
+ out << ")";
+ } else {
+ out << "\"" << values[0]->get_string() << "\"";
+ }
+ out << ")";
+ } else if (key == "vt.suffix") {
+ out << "if !strings.HasSuffix(" << target << ",";
+ if (values[0]->is_field_reference()) {
+ out << "string(";
+ out << get_field_reference_name(values[0]->get_field_reference());
+ out << ")";
+ } else {
+ out << "\"" << values[0]->get_string() << "\"";
+ }
+ out << ")";
+ } else if (key == "vt.contains") {
+ out << "if !strings.Contains(" << target << ",";
+ if (values[0]->is_field_reference()) {
+ out << "string(";
+ out << get_field_reference_name(values[0]->get_field_reference());
+ out << ")";
+ } else {
+ out << "\"" << values[0]->get_string() << "\"";
+ }
+ out << ")";
+ } else if (key == "vt.not_contains") {
+ out << "if strings.Contains(" << target << ",";
+ if (values[0]->is_field_reference()) {
+ out << "string(";
+ out << get_field_reference_name(values[0]->get_field_reference());
+ out << ")";
+ } else {
+ out << "\"" << values[0]->get_string() << "\"";
+ }
+ out << ")";
+ }
+ out << "{\nreturn
thrift.NewTApplicationException(thrift.VALIDATOR_CHECK_FAILED, \"" <<
context.field_symbol << " not valid, rule " << key
Review Comment:
output code line by line, don't use `\n`s as the indentation is certainly
wrong with those.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]