/*
* 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 org.eigenbase.rel;
import java.util.*;
import org.eigenbase.sql.SqlExplainLevel;
import org.eigenbase.util.*;
import com.google.common.collect.ImmutableList;
/**
* Callback for a relational expression to dump itself as JSON.
*
* @see org.eigenbase.rel.RelJsonReader
*/
public class RelJsonWriter implements RelWriter {
//~ Instance fields ----------------------------------------------------------
private final JsonBuilder jsonBuilder;
private final RelJson relJson;
private final Map<RelNode, String> relIdMap =
new IdentityHashMap<RelNode, String>();
private final List<Object> relList;
private final List<Pair<String, Object>> values =
new ArrayList<Pair<String, Object>>();
private String previousId;
//~ Constructors -------------------------------------------------------------
public RelJsonWriter() {
jsonBuilder = new JsonBuilder();
relList = jsonBuilder.list();
relJson = new RelJson(jsonBuilder);
}
//~ Methods ------------------------------------------------------------------
protected void explain_(RelNode rel, List<Pair<String, Object>> values) {
final Map<String, Object> map = jsonBuilder.map();
map.put("id", null); // ensure that id is the first attribute
map.put("relOp", relJson.classToTypeName(rel.getClass()));
for (Pair<String, Object> value : values) {
if (value.right instanceof RelNode) {
continue;
}
put(map, value.left, value.right);
}
// omit 'inputs: ["3"]' if "3" is the preceding rel
final List<Object> list = explainInputs(rel.getInputs());
if (list.size() != 1 || !list.get(0).equals(previousId)) {
map.put("inputs", list);
}
final String id = Integer.toString(relIdMap.size());
relIdMap.put(rel, id);
map.put("id", id);
relList.add(map);
previousId = id;
}
private void put(Map<String, Object> map, String name, Object value) {
map.put(name, relJson.toJson(value));
}
private List<Object> explainInputs(List<RelNode> inputs) {
final List<Object> list = jsonBuilder.list();
for (RelNode input : inputs) {
String id = relIdMap.get(input);
if (id == null) {
input.explain(this);
id = previousId;
}
list.add(id);
}
return list;
}
public final void explain(RelNode rel, List<Pair<String, Object>> valueList) {
explain_(rel, valueList);
}
public SqlExplainLevel getDetailLevel() {
return SqlExplainLevel.ALL_ATTRIBUTES;
}
public RelWriter input(String term, RelNode input) {
return this;
}
public RelWriter item(String term, Object value) {
values.add(Pair.of(term, value));
return this;
}
private List<Object> getList(List<Pair<String, Object>> values, String tag) {
for (Pair<String, Object> value : values) {
if (value.left.equals(tag)) {
//noinspection unchecked
return (List<Object>) value.right;
}
}
final List<Object> list = new ArrayList<Object>();
values.add(Pair.of(tag, (Object) list));
return list;
}
public RelWriter itemIf(String term, Object value, boolean condition) {
if (condition) {
item(term, value);
}
return this;
}
public RelWriter done(RelNode node) {
final List<Pair<String, Object>> valuesCopy =
ImmutableList.copyOf(values);
values.clear();
explain_(node, valuesCopy);
return this;
}
public boolean nest() {
return true;
}
/**
* Returns a JSON string describing the relational expressions that were just
* explained.
*/
public String asString() {
final Map<String, Object> map = jsonBuilder.map();
map.put("rels", relList);
return jsonBuilder.toJsonString(map);
}
}
// End RelJsonWriter.java