Skip to content

Commit

Permalink
Added support for lists
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed Jul 12, 2016
1 parent df1d9aa commit 6bbc6ca
Show file tree
Hide file tree
Showing 8 changed files with 708 additions and 193 deletions.
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.proc;

import java.lang.reflect.Type;
import java.util.function.Function;

import org.neo4j.kernel.api.proc.Neo4jTypes;

import static org.neo4j.kernel.impl.proc.Neo4jValue.ntList;
import static org.neo4j.kernel.impl.proc.ParseUtil.parseList;


public class ListConverter implements Function<String,Neo4jValue>
{
private final Type type;
private final Neo4jTypes.AnyType neoType;

public ListConverter( Type type, Neo4jTypes.AnyType neoType )
{
this.type = type;
this.neoType = neoType;
}

@Override
public Neo4jValue apply( String s )
{
String value = s.trim();
if ( value.equalsIgnoreCase( "null" ) )
{
return ntList( null, neoType );
}
else
{
return ntList( parseList( value, type ), neoType );
}
}
}
Expand Up @@ -19,11 +19,10 @@
*/ */
package org.neo4j.kernel.impl.proc; package org.neo4j.kernel.impl.proc;


import java.util.HashMap;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;


import static org.neo4j.kernel.impl.proc.Neo4jValue.ntMap; import static org.neo4j.kernel.impl.proc.Neo4jValue.ntMap;
import static org.neo4j.kernel.impl.proc.ParseUtil.parseMap;


/** /**
* A naive implementation of a Cypher-map/json parser. If you find yourself using this * A naive implementation of a Cypher-map/json parser. If you find yourself using this
Expand All @@ -45,186 +44,4 @@ public Neo4jValue apply( String s )
return ntMap( parseMap( value ) ); return ntMap( parseMap( value ) );
} }
} }

Map<String,Object> parseMap( String s )
{
int pos = 0;
int braceCounter = 0;
Map<String,Object> map = new HashMap<>();
StringBuilder builder = new StringBuilder();
while ( pos < s.length() )
{

char character = s.charAt( pos );
switch ( character )
{
case ' ':
++pos;
break;
case '{':
if ( braceCounter++ > 0 )
{
builder.append( s.charAt( pos ) );
}
++pos;
break;
case ',':
if ( braceCounter == 1 )
{
addKeyValue( map, builder.toString().trim() );
builder = new StringBuilder();
}
else
{
builder.append( s.charAt( pos ) );
}
++pos;
break;
case '}':
if ( --braceCounter == 0 )
{
addKeyValue( map, builder.toString().trim() );
}
else
{
builder.append( s.charAt( pos ) );
}
++pos;
break;
default:
builder.append( s.charAt( pos++ ) );
break;
}
}
if ( braceCounter != 0 )
{
throw new IllegalArgumentException( String.format( "%s contains unbalanced '{', '}'.", s ) );
}

return map;
}

private void addKeyValue( Map<String,Object> map, String keyValue )
{
if ( keyValue.isEmpty() )
{
return;
}
int split = keyValue.indexOf( ":" );
if ( split < 0 )
{
throw new IllegalArgumentException( "Keys and values must be separated with ':'" );
}
String key = parseKey( keyValue.substring( 0, split ).trim() );
Object value = parseValue( keyValue.substring( split + 1 ).trim() );

if ( map.containsKey( key ) )
{
throw new IllegalArgumentException(
String.format( "Multiple occurrences of key '%s'", key ) );
}
map.put( key, value );
}

private String parseKey( String s )
{
int pos = 0;
while ( pos < s.length() )
{
char c = s.charAt( pos );
switch ( c )
{
case '\'':
case '\"':
++pos;
break;
default:
return s.substring( pos, s.length() - pos );
}
}

throw new IllegalArgumentException( "" );
}

private Object parseValue( String s )
{
int pos = 0;
while ( pos < s.length() )
{
char c = s.charAt( pos );
int closing;
switch ( c )
{
case ' ':
++pos;
break;
case '\'':
closing = s.indexOf( '\'', pos + 1 );
if ( closing < 0 )
{
throw new IllegalArgumentException( "Did not find a matching end quote, '" );
}
return s.substring( pos + 1, closing );
case '\"':
closing = s.indexOf( '\"', pos + 1 );
if ( closing < 0 )
{
throw new IllegalArgumentException( "Did not find a matching end quote, \"" );
}
return s.substring( pos + 1, closing );
case '{':
return parseMap( s.substring( pos ) );
case '[':
return parseList( s.substring( pos ) );

case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
String number = s.substring( pos );
try
{
return Long.parseLong( number );
}
catch ( NumberFormatException e )
{
return Double.parseDouble( number );
}

//deliberate fallthrough
case 'n':
if ( s.charAt( pos + 1 ) == 'u' && s.charAt( pos + 2 ) == 'l' && s.charAt( pos + 3 ) == 'l' )
{
return null;
}

case 't':
if ( s.charAt( pos + 1 ) == 'r' && s.charAt( pos + 2 ) == 'u' && s.charAt( pos + 3 ) == 'e' )
{
return true;
}
case 'f':
if ( s.charAt( pos + 1 ) == 'a' && s.charAt( pos + 2 ) == 'l' && s.charAt( pos + 3 ) == 's' && s.charAt( pos + 4 ) == 'e' )
{
return false;
}

default:
throw new IllegalArgumentException( String.format( "%s is not a valid value", s ) );
}
}

throw new IllegalArgumentException( String.format( "%s is not a valid value", s ) );
}

Object parseList( String s )
{
throw new UnsupportedOperationException();
}
} }
Expand Up @@ -19,6 +19,7 @@
*/ */
package org.neo4j.kernel.impl.proc; package org.neo4j.kernel.impl.proc;


import java.util.List;
import java.util.Map; import java.util.Map;


import org.neo4j.kernel.api.proc.Neo4jTypes; import org.neo4j.kernel.api.proc.Neo4jTypes;
Expand Down Expand Up @@ -69,6 +70,11 @@ public static Neo4jValue ntMap(Map<String, Object> value)
return new Neo4jValue( value, Neo4jTypes.NTMap ); return new Neo4jValue( value, Neo4jTypes.NTMap );
} }


public static Neo4jValue ntList(List<?> value, Neo4jTypes.AnyType inner)
{
return new Neo4jValue( value, Neo4jTypes.NTList( inner ) );
}

@Override @Override
public String toString() public String toString()
{ {
Expand Down

0 comments on commit 6bbc6ca

Please sign in to comment.