/* * Licensed to Crate under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. Crate 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. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial * agreement. */ package io.crate.rest.action; import io.crate.analyze.symbol.Field; import io.crate.data.Row; import io.crate.types.CollectionType; import io.crate.types.DataType; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.rest.RestChannel; import java.io.IOException; import java.util.List; class ResultToXContentBuilder { static final class FIELDS { static final String RESULTS = "results"; static final String COLS = "cols"; static final String COLUMN_TYPES = "col_types"; static final String ROWS = "rows"; static final String ROW_COUNT = "rowcount"; static final String DURATION = "duration"; static final String ERROR_MESSAGE = "error_message"; } private final XContentBuilder builder; private ResultToXContentBuilder(RestChannel channel) throws IOException { builder = channel.newBuilder(); builder.startObject(); } static ResultToXContentBuilder builder(RestChannel channel) throws IOException { return new ResultToXContentBuilder(channel); } ResultToXContentBuilder cols(List<Field> fields) throws IOException { builder.startArray(FIELDS.COLS); for (Field field : fields) { builder.value(field.path().outputName()); } builder.endArray(); return this; } ResultToXContentBuilder colTypes(List<Field> fields) throws IOException { builder.startArray(FIELDS.COLUMN_TYPES); for (Field field : fields) { toXContentNestedDataType(builder, field.valueType()); } builder.endArray(); return this; } private void toXContentNestedDataType(XContentBuilder builder, DataType dataType) throws IOException { if (dataType instanceof CollectionType) { builder.startArray(); builder.value(dataType.id()); toXContentNestedDataType(builder, ((CollectionType) dataType).innerType()); builder.endArray(); } else { builder.value(dataType.id()); } } ResultToXContentBuilder duration(long startTime) throws IOException { builder.field(FIELDS.DURATION, (float) ((System.nanoTime() - startTime) / 1_000_000.0)); return this; } /** * startRows() must be called before first setNextRow() */ ResultToXContentBuilder startRows() throws IOException { builder.startArray(FIELDS.ROWS); return this; } /** * finishRows() must be called after last setNextRow() */ ResultToXContentBuilder finishRows() throws IOException { builder.endArray(); return this; } /** * addRow() should be called from setNextRow() * make sure startRows() is called before and finishRows() is called thereafter * @param row * @param numCols */ ResultToXContentBuilder addRow(Row row, int numCols) throws IOException { builder.startArray(); for (int j = 0; j < numCols; j++) { builder.value(row.get(j)); } builder.endArray(); return this; } /** * rowCount() can override the internal row counter that is increased upon every addRow() call * @param rowCount */ ResultToXContentBuilder rowCount(long rowCount) throws IOException { builder.field(FIELDS.ROW_COUNT, rowCount); return this; } ResultToXContentBuilder bulkRows(RestBulkRowCountReceiver.Result[] results) throws IOException { builder.startArray(FIELDS.RESULTS); for (RestBulkRowCountReceiver.Result result : results) { builder.startObject(); builder.field(FIELDS.ROW_COUNT, result.rowCount()); if (result.errorMessage() != null) { builder.field(FIELDS.ERROR_MESSAGE, result.errorMessage()); } builder.endObject(); } builder.endArray(); return this; } XContentBuilder build() throws IOException { builder.endObject(); return builder; } }