All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.values.utils.PrettyPrinter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [https://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.values.utils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZonedDateTime;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import org.neo4j.values.AnyValueWriter;
import org.neo4j.values.storable.CoordinateReferenceSystem;
import org.neo4j.values.storable.TextArray;
import org.neo4j.values.storable.TextValue;
import org.neo4j.values.virtual.MapValue;
import org.neo4j.values.virtual.NodeValue;
import org.neo4j.values.virtual.RelationshipValue;
import org.neo4j.values.virtual.VirtualNodeValue;
import org.neo4j.values.virtual.VirtualRelationshipValue;

/**
 * Pretty printer for AnyValues.
 * 

* Used to format AnyValue as a json-like string, as following: *

    *
  • nodes: (id=42 :LABEL {prop1: ["a", 13]})
  • *
  • edges: -[id=42 :TYPE {prop1: ["a", 13]}]-
  • *
  • paths: (id=1 :L)-[id=42 :T {k: "v"}]->(id=2)-...
  • *
  • points are serialized to geojson
  • *
  • maps: {foo: 42, bar: "baz"}
  • *
  • lists and arrays: ["aa", "bb", "cc"]
  • *
  • Numbers: 2.7182818285
  • *
  • Strings: "this is a string"
  • *
*/ public class PrettyPrinter implements AnyValueWriter { private final Deque stack = new ArrayDeque<>(); private final String quoteMark; private final StringBuilder builder; private final EntityMode entityMode; private final Counter counter; private final int maxLength; public PrettyPrinter() { this(EntityMode.FULL); } public PrettyPrinter(EntityMode entityMode) { this("\"", entityMode, Integer.MAX_VALUE); } public PrettyPrinter(String quoteMark, EntityMode entityMode) { this(quoteMark, entityMode, Integer.MAX_VALUE); } public PrettyPrinter(String quoteMark, EntityMode entityMode, int maxLength) { this.quoteMark = quoteMark; this.entityMode = entityMode; this.maxLength = maxLength; this.counter = new Counter(maxLength); this.builder = new StringBuilder(64); this.stack.push(new ValueWriter(builder, quoteMark, counter)); } public void reset() { stack.clear(); stack.push(new ValueWriter(builder, quoteMark, counter)); builder.setLength(0); counter.setCount(maxLength); } @Override public EntityMode entityMode() { return entityMode; } @Override public void writeNodeReference(long nodeId) { append("(id="); append(String.valueOf(nodeId)); append(")"); } @Override public void writeNode(String elementId, long nodeId, TextArray labels, MapValue properties, boolean isDeleted) throws RuntimeException { append("(elementId="); append(elementId); String sep = " "; for (int i = 0; i < labels.intSize(); i++) { append(sep); append(":"); append(labels.stringValue(i)); sep = ""; } if (properties.size() > 0) { append(" "); properties.writeTo(this); } append(")"); } @Override public void writeRelationshipReference(long relId) { append("-[id="); append(String.valueOf(relId)); append("]-"); } @Override public void writeRelationship( String elementId, long relId, String startNodeElementId, long startNodeId, String endNodeElementId, long endNodeId, TextValue type, MapValue properties, boolean isDeleted) throws RuntimeException { append("-[elementId="); append(elementId); append(" :"); append(type.stringValue()); if (properties.size() > 0) { append(" "); properties.writeTo(this); } append("]-"); } @Override public void beginMap(int size) { assert !stack.isEmpty(); stack.peek().nest(); stack.push(new MapWriter(builder, quoteMark, counter)); } @Override public void endMap() { assert !stack.isEmpty(); stack.pop().done(); if (!stack.isEmpty()) { stack.peek().next(); } } @Override public void beginList(int size) { assert !stack.isEmpty(); stack.peek().nest(); stack.push(new ListWriter(builder, quoteMark, counter)); } @Override public void endList() { assert !stack.isEmpty(); stack.pop().done(); if (!stack.isEmpty()) { stack.peek().next(); } } @Override public void writePathReference(long[] nodes, long[] relationships) { if (nodes.length == 0) { return; } // Path guarantees that nodes.length = edges.length = 1 writeNodeReference(nodes[0]); for (int i = 0; i < relationships.length; i++) { writeRelationshipReference(relationships[i]); append(">"); writeNodeReference(nodes[i + 1]); } } @Override public void writePathReference(VirtualNodeValue[] nodes, VirtualRelationshipValue[] relationships) throws RuntimeException { if (nodes.length == 0) { return; } // Path guarantees that nodes.length = edges.length = 1 writeNodeReference(nodes[0].id()); for (int i = 0; i < relationships.length; i++) { writeRelationshipReference(relationships[i].id()); append(">"); writeNodeReference(nodes[i + 1].id()); } } @Override public void writePathReference(List nodes, List relationships) throws RuntimeException { if (nodes.size() == 0) { return; } // Path guarantees that nodes.length = edges.length = 1 writeNodeReference(nodes.get(0).id()); for (int i = 0; i < relationships.size(); i++) { writeRelationshipReference(relationships.size()); append(">"); writeNodeReference(nodes.get(i + 1).id()); } } @Override public void writePath(NodeValue[] nodes, RelationshipValue[] relationships) { if (nodes.length == 0) { return; } // Path guarantees that nodes.length = edges.length = 1 nodes[0].writeTo(this); for (int i = 0; i < relationships.length; i++) { relationships[i].writeTo(this); append(">"); nodes[i + 1].writeTo(this); } } @Override public void writePoint(CoordinateReferenceSystem crs, double[] coordinate) throws RuntimeException { append("{geometry: {type: \"Point\", coordinates: "); append(Arrays.toString(coordinate)); append(", crs: {type: link, properties: {href: \""); append(crs.getHref()); append("\", code: "); append(Integer.toString(crs.getCode())); append("}}}}"); } @Override public void writeDuration(long months, long days, long seconds, int nanos) throws RuntimeException { append("{duration: {months: "); append(Long.toString(months)); append(", days: "); append(Long.toString(days)); append(", seconds: "); append(Long.toString(seconds)); append(", nanos: "); append(Long.toString(nanos)); append("}}"); } @Override public void writeDate(LocalDate localDate) throws RuntimeException { append("{date: "); appendQuoted(localDate.toString()); append("}"); } @Override public void writeLocalTime(LocalTime localTime) throws RuntimeException { append("{localTime: "); appendQuoted(localTime.toString()); append("}"); } @Override public void writeTime(OffsetTime offsetTime) throws RuntimeException { append("{time: "); appendQuoted(offsetTime.toString()); append("}"); } @Override public void writeLocalDateTime(LocalDateTime localDateTime) throws RuntimeException { append("{localDateTime: "); appendQuoted(localDateTime.toString()); append("}"); } @Override public void writeDateTime(ZonedDateTime zonedDateTime) throws RuntimeException { append("{datetime: "); appendQuoted(zonedDateTime.toString()); append("}"); } @Override public void writeNull() { append(""); } @Override public void writeBoolean(boolean value) { append(Boolean.toString(value)); } @Override public void writeInteger(byte value) { append(Byte.toString(value)); } @Override public void writeInteger(short value) { append(Short.toString(value)); } @Override public void writeInteger(int value) { append(Integer.toString(value)); } @Override public void writeInteger(long value) { append(Long.toString(value)); } @Override public void writeFloatingPoint(float value) { append(Float.toString(value)); } @Override public void writeFloatingPoint(double value) { append(Double.toString(value)); } @Override public void writeString(String value) { appendQuoted(value); } @Override public void writeString(char value) { writeString(Character.toString(value)); } @Override public void beginArray(int size, ArrayType arrayType) { assert !stack.isEmpty(); stack.peek().nest(); stack.push(new ListWriter(builder, quoteMark, counter)); } @Override public void endArray() { assert !stack.isEmpty(); stack.pop().done(); if (!stack.isEmpty()) { stack.peek().next(); } } @Override public void writeByteArray(byte[] value) { String sep = ""; append("["); for (byte b : value) { append(sep); append(Byte.toString(b)); sep = ", "; } append("]"); } public String value() { assert stack.size() == 1; stack.getLast().done(); return builder.toString(); } public void valueInto(StringBuilder target) { assert stack.size() == 1; stack.getLast().done(); target.append(builder); } private void append(String value) { if (counter.isDone()) { return; } assert !stack.isEmpty(); stack.peek().append(value); } private void appendQuoted(String value) { if (counter.isDone()) { return; } assert !stack.isEmpty(); stack.peek().appendQuoted(value); } private interface Writer { void append(String value); void appendQuoted(String value); void next(); void done(); void nest(); } private abstract static class BaseWriter implements Writer { protected final StringBuilder builder; protected Counter counter; private final String quoteMark; protected BaseWriter(StringBuilder builder, String quoteMark, Counter counter) { this.builder = builder; this.quoteMark = quoteMark; this.counter = counter; } @Override public void appendQuoted(String value) { write(quoteMark); this.append(value); write(quoteMark); } @Override public void next() {} @Override public void done() {} @Override public void nest() {} protected void write(String value) { int remaining = counter.remaining(); if (remaining <= 0) { return; } if (remaining < value.length()) { builder.append(value, 0, remaining).append("..."); counter.decrement(remaining); } else { builder.append(value); counter.decrement(value.length()); } } } private static class ValueWriter extends BaseWriter { private ValueWriter(StringBuilder builder, String quoteMark, Counter counter) { super(builder, quoteMark, counter); } @Override public void append(String value) { write(value); } } private static class MapWriter extends BaseWriter { private boolean writeKey = true; private String sep = ""; MapWriter(StringBuilder builder, String quoteMark, Counter counter) { super(builder, quoteMark, counter); write("{"); } @Override public void append(String value) { if (writeKey) { write(sep); write(value); write(": "); } else { write(value); } writeKey = !writeKey; sep = ", "; } @Override public void appendQuoted(String value) { if (writeKey) { append(value); } else { super.appendQuoted(value); } } @Override public void next() { writeKey = true; } @Override public void done() { write("}"); } } private class ListWriter extends BaseWriter { private String sep = ""; ListWriter(StringBuilder builder, String quoteMark, Counter counter) { super(builder, quoteMark, counter); write("["); } @Override public void append(String value) { write(sep); write(value); sep = ", "; } @Override public void appendQuoted(String value) { write(sep); write(quoteMark); write(value); write(quoteMark); sep = ", "; } @Override public void done() { write("]"); } @Override public void nest() { write(sep); } } private static final class Counter { private int count; Counter(int count) { this.count = count; } void setCount(int n) { count = n; } void decrement(int n) { count -= n; } int remaining() { return count; } public boolean isDone() { return count <= 0; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy