Skip to content

Commit

Permalink
CypherFunctions.point() replaced map argument with 10 arguments for a…
Browse files Browse the repository at this point in the history
…ll possible values

ugly, but I can't get the map type to work
  • Loading branch information
murermader committed Oct 20, 2024
1 parent 6b5db16 commit fa36416
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 30 deletions.
70 changes: 56 additions & 14 deletions core/src/main/java/org/polypheny/db/functions/CypherFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.apache.calcite.linq4j.Enumerable;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.function.Deterministic;
import org.apache.commons.lang3.NotImplementedException;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
Expand Down Expand Up @@ -434,6 +433,43 @@ public static PolyBoolean like( PolyValue b0, PolyValue b1 ) {
}


/**
* 5 possible argument names with values:
* - 3 coordinates
* - 2 options
*/
@SuppressWarnings("unused")
public static PolyGeometry point(
PolyValue argName1,
PolyValue argValue1,
PolyValue argName2,
PolyValue argValue2,
PolyValue argName3,
PolyValue argValue3,
PolyValue argName4,
PolyValue argValue4,
PolyValue argName5,
PolyValue argValue5 ) {
Map<PolyValue, PolyValue> map = new HashMap<>();
if ( argName1 != null && argValue1 != null ) {
map.put( argName1, argValue1 );
}
if ( argName2 != null && argValue2 != null ) {
map.put( argName2, argValue2 );
}
if ( argName3 != null && argValue3 != null ) {
map.put( argName3, argValue3 );
}
if ( argName4 != null && argValue4 != null ) {
map.put( argName4, argValue4 );
}
if ( argName5 != null && argValue5 != null ) {
map.put( argName5, argValue5 );
}
return point( PolyMap.of( map ) );
}

@SuppressWarnings("unused")
public static PolyGeometry point( PolyValue map ) {
if ( !map.isMap() ) {
throw new GenericRuntimeException( "point() expects a map." );
Expand All @@ -458,47 +494,46 @@ public static PolyGeometry point( PolyValue map ) {
Coordinate coordinate = new Coordinate();

if ( polyMap.containsKey( x ) && polyMap.containsKey( y ) ) {
if(polyMap.get( x ).isNull()){
if ( polyMap.get( x ).isNull() ) {
return null;
}
coordinate.setX( convertPolyValueToDouble( polyMap.get( x ) ) );
if(polyMap.get( y ).isNull()){
if ( polyMap.get( y ).isNull() ) {
return null;
}
coordinate.setY( convertPolyValueToDouble( polyMap.get( y ) ) );
if ( polyMap.containsKey( z ) ) {
if(polyMap.get( z ).isNull()){
if ( polyMap.get( z ).isNull() ) {
return null;
}
coordinate.setZ( convertPolyValueToDouble( polyMap.get( z ) ) );
}

if (polyMap.containsKey( srid )){
SRID = switch (polyMap.get(srid).asInteger().intValue()){
if ( polyMap.containsKey( srid ) ) {
SRID = switch ( polyMap.get( srid ).asInteger().intValue() ) {
case WGS_84 -> WGS_84;
case WGS_84_3D -> WGS_84_3D;
default -> 0;
};
}
else if (polyMap.containsKey( crs )){
SRID = switch (polyMap.get(crs).asString().value){
} else if ( polyMap.containsKey( crs ) ) {
SRID = switch ( polyMap.get( crs ).asString().value ) {
case "WGS-84-2D" -> WGS_84;
case "WGS-84-3D" -> WGS_84_3D;
default -> 0;
};
}

} else if ( polyMap.containsKey( longitude ) && polyMap.containsKey( latitude ) ) {
if(polyMap.get( longitude ).isNull()){
if ( polyMap.get( longitude ).isNull() ) {
return null;
}
coordinate.setX( convertPolyValueToDouble( polyMap.get( longitude ) ) );
if(polyMap.get( latitude ).isNull()){
if ( polyMap.get( latitude ).isNull() ) {
return null;
}
coordinate.setY( convertPolyValueToDouble( polyMap.get( latitude ) ) );
if ( polyMap.containsKey( height ) ) {
if(polyMap.get( height ).isNull()){
if ( polyMap.get( height ).isNull() ) {
return null;
}
coordinate.setZ( convertPolyValueToDouble( polyMap.get( height ) ) );
Expand All @@ -511,7 +546,8 @@ else if (polyMap.containsKey( crs )){
return PolyGeometry.of( geometryFactory.createPoint( coordinate ) );
}

public static PolyDouble distance(PolyValue p1, PolyValue p2) {
@SuppressWarnings("unused")
public static PolyDouble distance( PolyValue p1, PolyValue p2 ) {
PolyGeometry g1 = p1.asGeometry();
PolyGeometry g2 = p2.asGeometry();

Expand All @@ -522,14 +558,20 @@ public static PolyDouble distance(PolyValue p1, PolyValue p2) {
}
}

public static PolyBoolean withinBBox(PolyValue point, PolyValue bbox) {
@SuppressWarnings("unused")
public static PolyBoolean withinBBox( PolyValue point, PolyValue bbox ) {
PolyGeometry g = point.asGeometry();
PolyGeometry gBBox = bbox.asGeometry();
return new PolyBoolean( g.within( gBBox ) );
}


private static double convertPolyValueToDouble( PolyValue value ) {
// This should be sufficient, as all numerical values from Cypher are stored as BigDecimal.
if (value.isString()){
return Double.parseDouble( value.toString() );
}

assert value.isBigDecimal() : "Extend method to handle other numerical data types.";
return Objects.requireNonNull( value.asBigDecimal().getValue() ).doubleValue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ public enum BuiltInMethod {
CYPHER_SET_LABELS( CypherFunctions.class, "setLabels", GraphPropertyHolder.class, List.class, PolyBoolean.class ),
CYPHER_REMOVE_LABELS( CypherFunctions.class, "removeLabels", GraphPropertyHolder.class, List.class ),
CYPHER_REMOVE_PROPERTY( CypherFunctions.class, "removeProperty", GraphPropertyHolder.class, String.class ),
CYPHER_POINT( CypherFunctions.class, "point", PolyValue.class ),
CYPHER_POINT( CypherFunctions.class, "point", PolyValue.class, PolyValue.class, PolyValue.class, PolyValue.class, PolyValue.class, PolyValue.class, PolyValue.class, PolyValue.class, PolyValue.class, PolyValue.class ),
CYPHER_DISTANCE( CypherFunctions.class, "distance", PolyValue.class, PolyValue.class ),
CYPHER_WITHIN_BBOX( CypherFunctions.class, "withinBBox", PolyValue.class, PolyValue.class ),
TO_NODE( CypherFunctions.class, "toNode", Enumerable.class ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import lombok.Getter;
import org.apache.commons.lang3.NotImplementedException;
import org.polypheny.db.algebra.operators.OperatorName;
import org.polypheny.db.algebra.type.AlgDataType;
import org.polypheny.db.cypher.cypher2alg.CypherToAlgConverter.CypherContext;
import org.polypheny.db.cypher.cypher2alg.CypherToAlgConverter.RexType;
import org.polypheny.db.cypher.expression.CypherAggregate;
Expand All @@ -33,10 +34,12 @@
import org.polypheny.db.languages.ParserPos;
import org.polypheny.db.languages.QueryLanguage;
import org.polypheny.db.rex.RexCall;
import org.polypheny.db.rex.RexNameRef;
import org.polypheny.db.rex.RexNode;
import org.polypheny.db.type.PolyType;
import org.polypheny.db.type.entity.PolyString;
import org.polypheny.db.util.Pair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -83,29 +86,29 @@ public Pair<PolyString, RexNode> getRex( CypherContext context, RexType type ) {

switch ( func.getOperatorName() ) {
case CYPHER_POINT: {
// VERY UGLY, but it works for now. This could be improved by using the function MAP_OF_ENTRIES,
// but I am not sure how to call it.
CypherLiteral mapExpression = (CypherLiteral) func.getArguments().get( 0 );
// RexBuilder cannot handle CypherLiteral values, so we have to extract the values first.
Map<String, Object> map = new HashMap<>();
List<RexNode> arguments = new ArrayList<>();
mapExpression.getMapValue().forEach( ( key, value ) -> {
if ( value instanceof CypherLiteral ) {
map.put( key, ((CypherLiteral) value).getValue() );
}
if (value instanceof CypherProperty ){
throw new NotImplementedException( "TODO" );
}
Pair<PolyString, RexNode> pair = value.getRex( context, RexType.PROJECT );
arguments.add( context.rexBuilder.makeLiteral( key ) );
arguments.add( pair.right );
} );
RexNode node = context.rexBuilder.makeLiteral(
map,
context.typeFactory.createMapType(
context.typeFactory.createPolyType( PolyType.VARCHAR ),
context.typeFactory.createPolyType( PolyType.ANY ) ),
true );
// Fill with NULL to make sure we have the correct amount of arguments.
// 3 coordinates + 3 names + srid + crs = up to 8 possible
while (arguments.size() < 10){
arguments.add( context.rexBuilder.makeNullLiteral( context.typeFactory.createUnknownType() ) );
}
return Pair.of( PolyString.of( name ), new RexCall(
context.geometryType,
OperatorRegistry.get( QueryLanguage.from( "cypher" ), OperatorName.CYPHER_POINT ),
List.of( node ) ) );
arguments ) );

}
case DISTANCE: {


throw new NotImplementedException( "TODO" );
}
default:
Expand Down

0 comments on commit fa36416

Please sign in to comment.