I am facing a difficulty to bind a conditional parameters to SQL query using Spring Data R2DBC DatabaseClient. Two parameters can be null. Since the DatabaseClient requires to specify explicitly that the parameter is null, I have tried the following syntax but the conditional parameters were not appended to existing ones:
public Mono<Void> createAddress(Address address) {
DatabaseClient.GenericExecuteSpec bindings = databaseClient.execute(addressesQueries.getProperty("addresses.insert"))
.bind("line1", address.getLine1())
.bind("zipCode", address.getZipCode())
.bind("city", address.getCity())
.bind("countryId", address.getCountry())
.bind("id", address.getId()); // UUID
if(address.getLine2() == null) {
bindings.bindNull("line2", String.class);
} else {
bindings.bind("line2", address.getLine2());
}
if(address.getState() == null) {
bindings.bindNull("state", String.class);
} else {
bindings.bind("state", address.getState());
}
return bindings.fetch().rowsUpdated().then();
}
SQL query:
INSERT INTO addresses(id,line1,line2,zip_code,city,state,country) VALUES(:id,:line1,:line2,:zipCode,:city,:state,:countryId)
I know that I can split the SQL query to handle cases with/without null parameters but it will be a little bit complicated if I have more that one conditional parameter.
Do you know a solution that can help me to keep one SQL query and handle conditional parameters in Java code?
As commented, the bindings object is not changing with conditionals since you call bind and bindNull methods without saving such changed states back to object. Therefore line2 and state parameters are never populated with values. To fix, consider re-assigning bindings to update the object before its return:
if(address.getLine2() == null) {
bindings = bindings.bindNull("line2", String.class);
} else {
bindings = bindings.bind("line2", address.getLine2());
}
if(address.getState() == null) {
bindings = bindings.bindNull("state", String.class);
} else {
bindings = bindings.bind("state", address.getState());
}
I'm running a query to fetch all objects that are contained in the objectStrings but not all objects returned in the query.
var queryRestaurants = PFQuery(className: "Restaurant")
queryRestaurants.whereKey("objectId", containedIn: objectStrings)
queryRestaurants.findObjectsInBackgroundWithBlock {
(objectsRestaurants: [AnyObject]?, error: NSError?) -> Void in
if objectsRestaurants!.isEmpty { //if objects != nil {
println("ERROR, NO RESULTS")
} else {
restaurantArray = objectsRestaurants!
println(objectsRestaurants)
}
I double checked my backend and the objectIds in objectStrings are valid.
Example of what objectStrings looks like:
var objectStrings = [7US4aCNtae, odRzaG2zPn, T3QPXn8fvi, B4UDIKfR2t, ScuShpQbj2]
Why is Parse not fetching every object with objectIds contained in objectStrings? Only some of them are returned.
Update:
After many tests, i found that if I remove B4UDIKfR2t, all the values can be found. Once I add it back, some objects are missing again. But there's nothing different about B4UDIKfR2t and it can be fetched on its own just fine.
I just tried fetching only B4UDIKfR2t and the value that is missing odRzaG2zPn. They both are fetched successfully when its just the two of them.
Any idea what the problem is here?
I am using json-schema validator for validating json data. if any error occur it will generate a report. But I want to show the error to the user the report is too big so I want to show only error messages.
This is my report
----------reports-------------
com.github.fge.jsonschema.report.ListProcessingReport: failure
--- BEGIN MESSAGES ---
error: instance failed to match at least one required schema among 4
level: "error"
schema: {"loadingURI":"#","pointer":"/properties/question-groups/items"}
instance: {"pointer":"/question-groups/0"}
domain: "validation"
keyword: "anyOf"
nrSchemas: 4
reports: {"/properties/question-groups/items/anyOf/0":[{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/multiple-choice/properties/evaluation-key/properties/options/items"},"instance":{"pointer":"/question-groups/0/evaluation-key/options/0"},"domain":"validation","keyword":"allOf","message":"instance failed to match all required schemas (matched only 0 out of 1)","matched":0,"nrSchemas":1,"reports":{"/definitions/multiple-choice/properties/evaluation-key/properties/options/items/allOf/0":[{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/multiple-choice/properties/evaluation-key/properties/options/items/allOf/0/properties/score"},"instance":{"pointer":"/question-groups/0/evaluation-key/options/0/score"},"domain":"validation","keyword":"type","message":"instance type (string) does not match any allowed primitive type (allowed: [\"integer\"])","found":"string","expected":["integer"]}]}}],"/properties/question-groups/items/anyOf/1":[{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/text/properties/evaluation-key"},"instance":{"pointer":"/question-groups/0/evaluation-key"},"domain":"validation","keyword":"additionalProperties","message":"object instance has properties which are not allowed by the schema: [\"options\"]","unwanted":["options"]},{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/text/properties/evaluation-key"},"instance":{"pointer":"/question-groups/0/evaluation-key"},"domain":"validation","keyword":"required","message":"object has missing required properties ([\"scorers\"])","required":["scorers"],"missing":["scorers"]},{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/text/properties/type"},"instance":{"pointer":"/question-groups/0/type"},"domain":"validation","keyword":"enum","message":"instance value (\"multiple-choice\") not found in enum (possible values: [\"text\"])","value":"multiple-choice","enum":["text"]}],"/properties/question-groups/items/anyOf/2":[{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/numeric/properties/evaluation-key"},"instance":{"pointer":"/question-groups/0/evaluation-key"},"domain":"validation","keyword":"additionalProperties","message":"object instance has properties which are not allowed by the schema: [\"options\"]","unwanted":["options"]},{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/numeric/properties/evaluation-key"},"instance":{"pointer":"/question-groups/0/evaluation-key"},"domain":"validation","keyword":"required","message":"object has missing required properties ([\"scorers\"])","required":["scorers"],"missing":["scorers"]},{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/numeric/properties/type"},"instance":{"pointer":"/question-groups/0/type"},"domain":"validation","keyword":"enum","message":"instance value (\"multiple-choice\") not found in enum (possible values: [\"numeric\"])","value":"multiple-choice","enum":["numeric"]}],"/properties/question-groups/items/anyOf/3":[{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/table"},"instance":{"pointer":"/question-groups/0"},"domain":"validation","keyword":"anyOf","message":"instance failed to match at least one required schema among 2","nrSchemas":2,"reports":{"/definitions/table/anyOf/0":[{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/table/anyOf/0"},"instance":{"pointer":"/question-groups/0"},"domain":"validation","keyword":"required","message":"object has missing required properties ([\"cells\"])","required":["cells","evaluation-key","group-id","question-text","type"],"missing":["cells"]}],"/definitions/table/anyOf/1":[{"level":"error","schema":{"loadingURI":"#","pointer":"/definitions/table/anyOf/1"},"instance":{"pointer":"/question-groups/0"},"domain":"validation","keyword":"required","message":"object has missing required properties ([\"cells\",\"matching-unit\"])","required":["cells","evaluation-key","group-id","matching-unit","question-text","type"],"missing":["cells","matching-unit"]}]}}]}
--- END MESSAGES ---
How can I get only error messages, any suggestions will be help full.
Thank you
somu
You can read the report as a JsonNode and get what ever parameter you need from that.
ProcessingReport report;
ProcessingMessage message;
report = schema.validate(jsonData);
Iterator itr = report.iterator();
while(itr.hasNext())
{
message = (ProcessingMessage) itr.next();
System.out.println("Message" + message.asJson().get("message").asText());
System.out.println("Reports" + message.asJson().get("reports").asText());
}
You should iterate over all messages and choose only errors comparing getLogLevel() with LogLevel.ERROR. That works for me
Iterator<ProcessingMessage> itr = report.iterator();
while(itr.hasNext())
{
ProcessingMessage message = (ProcessingMessage) itr.next();
if(message.getLogLevel().equals(LogLevel.ERROR)){
System.out.println(message.toString());
}
}
You can use the following method
String getErrorsList(ProcessingReport report, boolean onlyErrors) {
StringBuilder jsonValidationErrors = new StringBuilder();
for (ProcessingMessage processingMessage : report) {
if(onlyErrors && LogLevel.ERROR.equals(processingMessage.getLogLevel())) {
jsonValidationErrors.append(processingMessage.getMessage()).append("\n\r");
} else if(!onlyErrors) {
jsonValidationErrors.append(processingMessage.getMessage()).append("\n\r");
}
}
return jsonValidationErrors.toString();
}
What I have:
public function beforeValidate() {
$offender = Accounts::model()->find(array('select'=>'id','condition'=>'username=:username','params'=>array(':username'=>$this->offender)));
$informer = Accounts::model()->find(array('select'=>'id','condition'=>'username=:username','params'=>array(':username'=>$this->informer)));
$this->offender = $offender->id;
$this->informer = $informer->id;
return parent::beforeValidate();
}
What I get:
PHP Notice, that says, that i'm trying to get property "id" of non-object $offender and $informer.
But those are 100% objects:
var_dump($offender):
object(Accounts)[46]
var_dump($informer):
object(Accounts)[46]
And it actually sets the right id, but shows that notice anyway. What is wrong?
SOLVED
Can't post it as official answer for six more hours, so i just leave it here:
Actually, the problem was in double beforeValidate() call.
AbuseController.php:
if(isset($_POST['AbuseReport']))
{
$model->attributes=$_POST['AbuseReport'];
if($model->validate())
{
$model->save();
}
}
First time it validates on $model->validate(), and replaces $this->offender and $this->informer with correct ID's. Second time it validates on $model->save();, but model returns null this time, because $this->offender is already ID, but it expects username.
The whole solution to this is to disable second validation: $model->save(false);.
use isset or is_object
if(isset($offender->id) || is_object($offender->id)){
$this->offender = $offender->id;
$this->informer = $informer->id;
}
numberrange returns [String value]
: numberrangesub
{
String numberRange = ($numberrangesub.text);
String [] v = numberRange.split(",");
if ( Integer.parseInt(v[0].trim()) < Integer.parseInt(v[1].trim())) $value =numberRange;
else throw new RecognitionException();
}
;
Please observe the above ANTLR code. In this I want to throw a user friendly error message like "from value should be less than to value in BETWEEN clause".
I am expecting like this RecognitionException("from value should be less than to value in BETWEEN clause"); But antlr did not accept like as above.
In java class where I am calling the generated java class by Antlr. I am handling like as follows.
try
{
parser.numberRangeCheck();
}
catch (RecognitionException e)
{
throw createException("Invalid Business logic syntax at " + parser.getErrorHeader(e) + ", " + parser.getErrorMessage(e, null), Level.INFO, logger);
}
Any help will be appriciated.
Why not simply throw a RuntimeException with your custom error message?
// ...
else throw new RuntimeException("from value should be less than to value in BETWEEN clause");
// ...
As Terrance wrote in "The Definitive ANTLR Reference" error chapter excerpt:
To avoid forcing English-only error messages and to generally make
things as flexible as possible, the recognizer does not create exception
objects with string messages. Instead, it tracks the information necessary to generate an error.
So there is no error message supplied to RecognitionError's constructor. But you can define additional field of your recognizer to hold user-friendly error message shown on RecognitionError handling:
numberrange returns [String value]
: numberrangesub
{
String numberRange = ($numberrangesub.text);
String [] v = numberRange.split(",");
if ( Integer.parseInt(v[0].trim()) < Integer.parseInt(v[1].trim()))
$value = numberRange;
else {
this.errorMessage = "from value should be less than to value in BETWEEN clause";
throw new RecognitionException(this.input);
}
}
;
And then override the getErrorMessage method:
public String getErrorMessage(RecognitionException e, String[] tokenNames) {
String msg = this.errorMessage;
// ...
}
This works similar to paraphrase mechanism explained in the same excerpt.