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

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

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://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 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;

/**
 * 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; 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.counter = new Counter( maxLength ); builder = new StringBuilder( 64 ); stack.push( new ValueWriter( builder, quoteMark, counter ) ); } @Override public EntityMode entityMode() { return entityMode; } @Override public void writeNodeReference( long nodeId ) { append( "(id=" ); append( String.valueOf( nodeId ) ); append( ")" ); } @Override public void writeNode( long nodeId, TextArray labels, MapValue properties, boolean ignored ) { append( "(id=" ); append( String.valueOf( nodeId ) ); String sep = " "; for ( int i = 0; i < labels.length(); 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( long relId, long startNodeId, long endNodeId, TextValue type, MapValue properties, boolean ignored ) { append( "-[id=" ); append( String.valueOf( relId ) ); 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 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 decrement( int n ) { count -= n; } int remaining() { return count; } public boolean isDone() { return count <= 0; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy