Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

[PPL] Add simple json formatter #476

Merged
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import com.amazon.opendistroforelasticsearch.sql.elasticsearch.security.SecurityAccess;
import com.amazon.opendistroforelasticsearch.sql.plugin.request.PPLQueryRequestFactory;
import com.amazon.opendistroforelasticsearch.sql.ppl.PPLService;
import com.amazon.opendistroforelasticsearch.sql.ppl.ResponseListener;
import com.amazon.opendistroforelasticsearch.sql.protocol.response.ResponseListener;
import com.amazon.opendistroforelasticsearch.sql.ppl.config.PPLServiceConfig;
import com.amazon.opendistroforelasticsearch.sql.ppl.domain.PPLQueryResponse;
import org.elasticsearch.client.node.NodeClient;
Expand Down
1 change: 1 addition & 0 deletions ppl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
compile group: 'org.springframework', name: 'spring-beans', version: '5.2.5.RELEASE'
compile project(':common')
compile project(':core')
compile project(':protocol')

testCompile group: 'junit', name: 'junit', version: '4.12'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

package com.amazon.opendistroforelasticsearch.sql.ppl;

import com.amazon.opendistroforelasticsearch.sql.protocol.response.ResponseListener;
import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.PPLSyntaxParser;
import com.amazon.opendistroforelasticsearch.sql.ppl.domain.PPLQueryRequest;
import com.amazon.opendistroforelasticsearch.sql.ppl.domain.PPLQueryResponse;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

package com.amazon.opendistroforelasticsearch.sql.ppl;

import com.amazon.opendistroforelasticsearch.sql.protocol.response.ResponseListener;
import com.amazon.opendistroforelasticsearch.sql.ppl.config.PPLServiceConfig;
import com.amazon.opendistroforelasticsearch.sql.ppl.domain.PPLQueryRequest;
import com.amazon.opendistroforelasticsearch.sql.ppl.domain.PPLQueryResponse;
Expand Down
60 changes: 60 additions & 0 deletions protocol/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
plugins {
id 'java'
id "io.freefair.lombok"
id 'jacoco'
}

repositories {
mavenCentral()
}

dependencies {
compile group: 'com.google.guava', name: 'guava', version:'23.0'
compile group: 'org.json', name: 'json', version:'20180813' //TODO: change to other JSON lib?
compile project(':core')

testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '2.1'
testCompile group: 'org.mockito', name: 'mockito-core', version: '3.3.3'
testCompile group: 'org.mockito', name: 'mockito-junit-jupiter', version: '3.3.3'
}

test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}

jacoco {
toolVersion = "0.8.3"
}
jacocoTestReport {
reports {
html.enabled true
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it)
}))
}
}
test.finalizedBy(project.tasks.jacocoTestReport)

jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 1.0
}

}
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it)
}))
}
}
check.dependsOn jacocoTestCoverageVerification
jacocoTestCoverageVerification.dependsOn jacocoTestReport
3 changes: 3 additions & 0 deletions protocol/lombok.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This file is generated by the 'io.freefair.lombok' Gradle plugin
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.sql.protocol.response;

import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue;
import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils;
import lombok.RequiredArgsConstructor;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* Query response that encapsulates query results and isolate {@link ExprValue} related from formatter implementation.
*/
@RequiredArgsConstructor
public class QueryResponse implements Iterable<Object[]> {

/**
* Results which are collection of expression
*/
private final Collection<ExprValue> exprValues;


/**
* @return size of results
*/
public int size() {
return exprValues.size();
}

/**
* Parse column name from results
* @return mapping from column names to its expression type
*/
public Map<String, String> columnNameTypes() {
if (exprValues.isEmpty()) {
return Collections.emptyMap();
}

Map<String, ExprValue> tupleValue = getFirstTupleValue();
dai-chen marked this conversation as resolved.
Show resolved Hide resolved
return populateColumnNameAndTypes(tupleValue);
}

@Override
public Iterator<Object[]> iterator() {
// Any chance to avoid copy for json response generation?
return exprValues.stream().
map(ExprValueUtils::getTupleValue).
map(Map::values).
map(this::convertExprValuesToValues).
iterator();
}

private Map<String, ExprValue> getFirstTupleValue() {
// Assume expression is always tuple on first level
// and columns (keys) of all tuple values are exactly same
ExprValue firstValue = exprValues.iterator().next();
return ExprValueUtils.getTupleValue(firstValue);
}

private Map<String, String> populateColumnNameAndTypes(Map<String, ExprValue> tupleValue) {
// Use linked hashmap to maintain original order in tuple expression
Map<String, String> colNameTypes = new LinkedHashMap<>();
tupleValue.forEach((name, expr) -> colNameTypes.put(name, getTypeString(expr)));
return colNameTypes;
}

private Object[] convertExprValuesToValues(Collection<ExprValue> exprValues) {
return exprValues.stream().
map(ExprValue::value).
toArray(Object[]::new);
}

private String getTypeString(ExprValue exprValue) {
return exprValue.type().name().toLowerCase();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.sql.protocol.response;

/**
* Response listener for response post-processing callback.
* This is necessary because execution engine may schedule and execute in different thread.
*
* @param <Response> response class
*/
public interface ResponseListener<Response> {

/**
* Handle successful response.
* @param response successful response
*/
void onResponse(Response response);

/**
* Handle failed response.
* @param e exception captured
*/
void onFailure(Exception e);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.sql.protocol.response.format;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.json.JSONObject;

import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY;

/**
* Abstract class for all JSON formatter.
* @param <Response> response generic type which could be DQL or DML response
*/
@RequiredArgsConstructor
public abstract class JsonResponseFormatter<Response> implements ResponseFormatter<Response> {

/**
* JSON format styles: pretty format or compact format without indent and space
*/
public enum Style {
PRETTY, COMPACT
}

/**
* JSON format style
*/
private final Style style;


@Override
public String format(Response response) {
return jsonify(buildJsonObject(response));
}

@Override
public String format(Throwable t) {
JsonError error = new JsonError(t.getClass().getSimpleName(),
t.getMessage());
return jsonify(error);
}

/**
* Build JSON object to generate response json string.
* @param response response
* @return json object for response
*/
protected abstract Object buildJsonObject(Response response);


private String jsonify(Object jsonObject) {
JSONObject json = new JSONObject(jsonObject);
return (style == PRETTY) ? json.toString(2) : json.toString();
}

@RequiredArgsConstructor
@Getter
public static class JsonError {
private final String type;
private final String reason;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.sql.protocol.response.format;

/**
* Response formatter to format response to different formats.
*/
public interface ResponseFormatter<Response> {

/**
* Format response into string in expected format.
* @param response response
* @return string with response content formatted
*/
String format(Response response);

/**
* Format an exception into string.
* @param t exception occurred
* @return string with exception content formatted
*/
String format(Throwable t);

}
Loading