From 32a42d60da0015809f3220cd3f11e7db0c5cb27e Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Thu, 16 May 2024 16:27:29 +0200 Subject: [PATCH 01/17] Refactor relational results for reuse with graphs --- .../jdbc/multimodel/GraphResult.java | 33 ++++++++++ .../polypheny/jdbc/multimodel/PolyRow.java | 34 +++++++---- .../jdbc/multimodel/PolyStatement.java | 3 + .../multimodel/RelationalColumnMetadata.java | 44 +++++++++++++ .../jdbc/multimodel/RelationalMetadata.java | 61 +++++++++++++++++++ .../jdbc/multimodel/RelationalResult.java | 6 +- .../org/polypheny/jdbc/multimodel/Result.java | 1 + .../java/org/polypheny/jdbc/QueryTest.java | 34 +++++++++-- 8 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java create mode 100644 src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java create mode 100644 src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java diff --git a/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java new file mode 100644 index 0000000..c864dcb --- /dev/null +++ b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc.multimodel; + +import org.polypheny.prism.Frame; + +public class GraphResult extends Result { // implements iterable over some graph representation + + private final PolyStatement polyStatement; + private boolean isFullyFetched; + + + public GraphResult( Frame frame, PolyStatement polyStatement ) { + super( ResultType.GRAPH ); + this.polyStatement= polyStatement; + this.isFullyFetched = frame.getIsLast(); + } + +} diff --git a/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java b/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java index 5fda1ed..1933062 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java @@ -16,30 +16,29 @@ package org.polypheny.jdbc.multimodel; +import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import org.polypheny.jdbc.PrismInterfaceErrors; +import org.polypheny.jdbc.PrismInterfaceServiceException; import org.polypheny.jdbc.types.TypedValue; import org.polypheny.prism.Row; public class PolyRow { - List values; + private List values; + private RelationalMetadata metadata; - public PolyRow( List value ) { + public PolyRow( List value, RelationalMetadata metadata ) { this.values = new ArrayList<>( value ); - } - - - public PolyRow( TypedValue... value ) { - this( Arrays.asList( value ) ); + this.metadata = metadata; } public int getColumnCount() { - return values.size(); + return metadata.getColumnCount(); } @@ -48,13 +47,22 @@ public TypedValue getValue( int columnIndex ) { } - public static PolyRow of( E... values ) { - return new PolyRow( values ); + public TypedValue getValue( String columnName ) throws PrismInterfaceServiceException { + try { + int index = metadata.getColumnIndexFromLabel( columnName ); + return values.get( index ); + } catch ( SQLException e ) { + throw new PrismInterfaceServiceException( + PrismInterfaceErrors.VALUE_ILLEGAL, + "Failed to retrieve column bsaed on the column name.", + e + ); + } } - public static PolyRow fromProto( Row protoRow ) { - return new PolyRow( protoRow.getValuesList().stream().map( TypedValue::new ).collect( Collectors.toList() ) ); + public static PolyRow fromProto( Row protoRow, RelationalMetadata metadata ) { + return new PolyRow( protoRow.getValuesList().stream().map( TypedValue::new ).collect( Collectors.toList() ), metadata ); } } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java index debf74a..ba1701d 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java @@ -23,6 +23,7 @@ import org.polypheny.jdbc.PrismInterfaceServiceException; import org.polypheny.jdbc.utils.CallbackQueue; import org.polypheny.prism.Frame; +import org.polypheny.prism.Frame.ResultCase; import org.polypheny.prism.Response; import org.polypheny.prism.StatementResponse; @@ -53,6 +54,8 @@ private Result getResultFromFrame( Frame frame ) throws PrismInterfaceServiceExc return new RelationalResult( frame, this ); case DOCUMENT_FRAME: return new DocumentResult( frame, this ); + case GRAPH_FRAME: + return new GraphResult(frame, this); } throw new PrismInterfaceServiceException( PrismInterfaceErrors.RESULT_TYPE_INVALID, "Statement produced unknown result type" ); } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java b/src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java new file mode 100644 index 0000000..fa92070 --- /dev/null +++ b/src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc.multimodel; + +import lombok.Getter; +import org.polypheny.prism.ColumnMeta; + +@Getter +public class RelationalColumnMetadata { + private final int columnIndex; + private final boolean isNullable; + private final int length; + private final String columnLabel; + private final String columnName; + private final int precision; + + private final String protocolTypeName; + private final int scale; + + public RelationalColumnMetadata( ColumnMeta columnMeta ) { + this.columnIndex = columnMeta.getColumnIndex(); + this.isNullable = columnMeta.getIsNullable(); + this.length = columnMeta.getLength(); + this.columnLabel = columnMeta.getColumnLabel(); + this.columnName = columnMeta.getColumnName(); + this.precision = columnMeta.getPrecision(); + this.protocolTypeName = columnMeta.getTypeMeta().getProtoValueType().name(); + this.scale = columnMeta.getScale(); + } +} diff --git a/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java b/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java new file mode 100644 index 0000000..f5107a4 --- /dev/null +++ b/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc.multimodel; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.polypheny.jdbc.PrismInterfaceErrors; +import org.polypheny.jdbc.PrismInterfaceServiceException; +import org.polypheny.prism.ColumnMeta; + +public class RelationalMetadata { + + private List columnMetas; + private Map columnIndexes; + + + public RelationalMetadata( List columnMetadata ) { + this.columnMetas = columnMetadata.stream().map( RelationalColumnMetadata::new ).collect( Collectors.toList() ); + this.columnIndexes = this.columnMetas.stream().collect( Collectors.toMap( RelationalColumnMetadata::getColumnLabel, RelationalColumnMetadata::getColumnIndex, ( m, n ) -> n ) ); + + } + + + private RelationalColumnMetadata getColumnMeta( int columnIndex ) throws PrismInterfaceServiceException { + try { + return columnMetas.get( columnIndex ); + } catch ( IndexOutOfBoundsException e ) { + throw new PrismInterfaceServiceException( PrismInterfaceErrors.VALUE_ILLEGAL, "Column index out of bounds", e ); + } + } + + + public int getColumnIndexFromLabel( String columnLabel ) throws PrismInterfaceServiceException { + Integer columnIndex = columnIndexes.get( columnLabel ); + if ( columnIndex == null ) { + throw new PrismInterfaceServiceException( PrismInterfaceErrors.COLUMN_NOT_EXISTS, "Invalid column label: " + columnLabel ); + } + return columnIndex; + } + + + public int getColumnCount() { + return columnMetas.size(); + } + +} diff --git a/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java b/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java index 4198591..01a1718 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java @@ -20,6 +20,7 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; +import lombok.Getter; import org.polypheny.jdbc.PolyConnection; import org.polypheny.jdbc.PrismInterfaceClient; import org.polypheny.jdbc.PrismInterfaceErrors; @@ -32,6 +33,8 @@ public class RelationalResult extends Result implements Iterable { private final PolyStatement polyStatement; + @Getter + private final RelationalMetadata metadata; private final List rows; private boolean isFullyFetched; @@ -41,12 +44,13 @@ public RelationalResult( Frame frame, PolyStatement polyStatement ) throws Prism this.polyStatement = polyStatement; this.isFullyFetched = frame.getIsLast(); this.rows = new ArrayList<>(); + this.metadata = new RelationalMetadata( frame.getRelationalFrame().getColumnMetaList() ); addRows( frame.getRelationalFrame() ); } private void addRows( RelationalFrame relationalFrame ) { - relationalFrame.getRowsList().forEach( d -> rows.add( PolyRow.fromProto( d ) ) ); + relationalFrame.getRowsList().forEach( d -> rows.add( PolyRow.fromProto( d, metadata ) ) ); } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/Result.java b/src/main/java/org/polypheny/jdbc/multimodel/Result.java index eb9db43..3c6bd8e 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/Result.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/Result.java @@ -42,6 +42,7 @@ public T unwrap( Class aClass ) throws PrismInterfaceServiceException { public enum ResultType { RELATIONAL, DOCUMENT, + GRAPH, SCALAR } diff --git a/src/test/java/org/polypheny/jdbc/QueryTest.java b/src/test/java/org/polypheny/jdbc/QueryTest.java index 0b74f49..3271bbe 100644 --- a/src/test/java/org/polypheny/jdbc/QueryTest.java +++ b/src/test/java/org/polypheny/jdbc/QueryTest.java @@ -27,15 +27,23 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.polypheny.jdbc.multimodel.DocumentResult; +import org.polypheny.jdbc.multimodel.GraphResult; import org.polypheny.jdbc.multimodel.PolyStatement; +import org.polypheny.jdbc.multimodel.RelationalResult; import org.polypheny.jdbc.multimodel.Result; import org.polypheny.jdbc.multimodel.Result.ResultType; import org.polypheny.jdbc.types.PolyDocument; public class QueryTest { + private static final String SQL_LANGUAGE_NAME = "sql"; + private static final String SQL_TEST_QUERY = "SELECT * FROM customers"; + private static final String MQL_LANGUAGE_NAME = "mongo"; - private static final String TEST_QUERY = "db.customers.find({});"; + private static final String MQL_TEST_QUERY = "db.customers.find({});"; + + private static final String CYPHER_LANGUAGE_NAME = "cypher"; + private static final String CYPHER_TEST_QUERY = "MATCH (c:customers)"; @BeforeAll @@ -49,7 +57,7 @@ public void thisOneWorks() throws SQLException { try ( Connection connection = TestHelper.getConnection(); Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery( "SELECT * FROM customers" ) + ResultSet resultSet = statement.executeQuery( SQL_TEST_QUERY ) ) { while ( resultSet.next() ) { // Process the result set... @@ -65,7 +73,7 @@ public void simpleRelationalTest() { fail( "Driver must support unwrapping to PolyphenyConnection" ); } PolyStatement polyStatement = connection.unwrap( PolyConnection.class ).createPolyStatement(); - Result result = polyStatement.execute( "public", "sql", "SELECT * FROM customers" ); + Result result = polyStatement.execute( "public", SQL_LANGUAGE_NAME, SQL_TEST_QUERY ); assertEquals( ResultType.RELATIONAL, result.getResultType() ); } catch ( SQLException e ) { throw new RuntimeException( e ); @@ -80,7 +88,7 @@ public void simpleMqlTest() { fail( "Driver must support unwrapping to PolyphenyConnection" ); } PolyStatement polyStatement = connection.unwrap( PolyConnection.class ).createPolyStatement(); - Result result = polyStatement.execute( "public", MQL_LANGUAGE_NAME, TEST_QUERY ); + Result result = polyStatement.execute( "public", MQL_LANGUAGE_NAME, MQL_TEST_QUERY ); assertEquals( ResultType.DOCUMENT, result.getResultType() ); } catch ( SQLException e ) { throw new RuntimeException( e ); @@ -95,9 +103,10 @@ public void mqlDataRetrievalTest() { fail( "Driver must support unwrapping to PolyphenyConnection" ); } PolyStatement polyStatement = connection.unwrap( PolyConnection.class ).createPolyStatement(); - Result result = polyStatement.execute( "public", MQL_LANGUAGE_NAME, TEST_QUERY ); + Result result = polyStatement.execute( "public", MQL_LANGUAGE_NAME, MQL_TEST_QUERY ); DocumentResult docs = result.unwrap( DocumentResult.class ); for ( PolyDocument doc : docs ) { + // Process the results... } assertEquals( ResultType.DOCUMENT, result.getResultType() ); } catch ( SQLException e ) { @@ -105,4 +114,19 @@ public void mqlDataRetrievalTest() { } } + @Test + public void simpleCypherTest() { + try ( Connection connection = TestHelper.getConnection() ) { + if ( !connection.isWrapperFor( PolyConnection.class ) ) { + fail( "Driver must support unwrapping to PolyphenyConnection" ); + } + PolyStatement polyStatement = connection.unwrap( PolyConnection.class ).createPolyStatement(); + Result result = polyStatement.execute( "gph", CYPHER_LANGUAGE_NAME, "MATCH (p:Person) RETURN p.age, p.name" ); + RelationalResult relRes = result.unwrap( RelationalResult.class ); + assertEquals( ResultType.RELATIONAL, result.getResultType() ); + } catch ( SQLException e ) { + throw new RuntimeException( e ); + } + } + } From 01efda1d546e2acce798ec4032d29629030fadde Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Thu, 16 May 2024 21:27:20 +0200 Subject: [PATCH 02/17] Add graph results --- build.gradle | 3 +- .../jdbc/multimodel/GraphResult.java | 91 ++++++++++++++++++- .../polypheny/jdbc/multimodel/PolyRow.java | 17 +--- .../polypheny/jdbc/types/PolyDocument.java | 5 - .../org/polypheny/jdbc/types/PolyEdge.java | 52 +++++++++++ .../jdbc/types/PolyGraphElement.java | 32 +++++++ .../org/polypheny/jdbc/types/PolyNode.java | 38 ++++++++ .../org/polypheny/jdbc/types/PolyPath.java | 27 ++++++ 8 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 src/main/java/org/polypheny/jdbc/types/PolyEdge.java create mode 100644 src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java create mode 100644 src/main/java/org/polypheny/jdbc/types/PolyNode.java create mode 100644 src/main/java/org/polypheny/jdbc/types/PolyPath.java diff --git a/build.gradle b/build.gradle index dda3804..880c149 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,7 @@ repositories { maven { url "https://plugins.gradle.org/m2/" } + mavenLocal() } compileJava.options.encoding = "UTF-8" @@ -55,7 +56,7 @@ def protobufVersion = "3.23.4" dependencies { // Prism API files (protobuf files), needs to be implementation due to the prism-api-version.properties - implementation group: 'org.polypheny', name: 'prism', version: '1.9' + implementation group: 'org.polypheny', name: 'prism', version: '5.1' //1.9 // Protobuf implementation group: 'com.google.protobuf', name: 'protobuf-java', version: protobufVersion diff --git a/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java index c864dcb..ce7398f 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java @@ -16,18 +16,107 @@ package org.polypheny.jdbc.multimodel; +import java.util.ArrayList; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import org.polypheny.jdbc.PolyConnection; +import org.polypheny.jdbc.PrismInterfaceClient; +import org.polypheny.jdbc.PrismInterfaceErrors; +import org.polypheny.jdbc.PrismInterfaceServiceException; +import org.polypheny.jdbc.properties.PropertyUtils; +import org.polypheny.jdbc.types.PolyEdge; +import org.polypheny.jdbc.types.PolyGraphElement; +import org.polypheny.jdbc.types.PolyNode; +import org.polypheny.jdbc.types.PolyPath; import org.polypheny.prism.Frame; +import org.polypheny.prism.Frame.ResultCase; +import org.polypheny.prism.GraphFrame; -public class GraphResult extends Result { // implements iterable over some graph representation +public class GraphResult extends Result implements Iterable { // implements iterable over some graph representation private final PolyStatement polyStatement; private boolean isFullyFetched; + private final List elements; + public GraphResult( Frame frame, PolyStatement polyStatement ) { super( ResultType.GRAPH ); this.polyStatement= polyStatement; this.isFullyFetched = frame.getIsLast(); + this.elements = new ArrayList<>(); + addGraphElements(frame.getGraphFrame()); + } + + private void addGraphElements( GraphFrame graphFrame ) { + if (graphFrame.getNodesCount() > 0) { + graphFrame.getNodesList().forEach( n -> elements.add( new PolyNode(n) ) ); + return; + } + if (graphFrame.getEdgesCount() > 0) { + graphFrame.getEdgesList().forEach( n -> elements.add( new PolyEdge(n) ) ); + return; + } + if (graphFrame.getPathsCount() > 0) { + graphFrame.getPathsList().forEach( n -> elements.add( new PolyPath(n) ) ); + } + } + + private void fetchMore() throws PrismInterfaceServiceException { + int id = polyStatement.getStatementId(); + int timeout = getPolyphenyConnection().getTimeout(); + Frame frame = getPrismInterfaceClient().fetchResult( id, timeout, PropertyUtils.getDEFAULT_FETCH_SIZE() ); + if ( frame.getResultCase() != ResultCase.GRAPH_FRAME ) { + throw new PrismInterfaceServiceException( + PrismInterfaceErrors.RESULT_TYPE_INVALID, + "Statement returned a result of illegal type " + frame.getResultCase() + ); + } + isFullyFetched = frame.getIsLast(); + addGraphElements( frame.getGraphFrame() ); + } + + private PolyConnection getPolyphenyConnection() { + return polyStatement.getConnection(); + } + + + private PrismInterfaceClient getPrismInterfaceClient() { + return getPolyphenyConnection().getPrismInterfaceClient(); } + @Override + public Iterator iterator() {return new GraphElementIterator();} + + class GraphElementIterator implements Iterator { + int index = -1; + + @Override + public boolean hasNext() { + if ( index + 1 >= elements.size() ) { + if ( isFullyFetched ) { + return false; + } + try { + fetchMore(); + } catch ( PrismInterfaceServiceException e ) { + throw new RuntimeException( e ); + } + } + return index + 1 < elements.size(); + } + + @Override + public PolyGraphElement next() { + if ( !hasNext() ) { + throw new NoSuchElementException( "There are no more graph elements" ); + } + return elements.get( ++index ); + } + } + + + } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java b/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java index 1933062..48ce9f1 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java @@ -25,32 +25,21 @@ import org.polypheny.jdbc.types.TypedValue; import org.polypheny.prism.Row; -public class PolyRow { +public class PolyRow extends ArrayList { - private List values; private RelationalMetadata metadata; public PolyRow( List value, RelationalMetadata metadata ) { - this.values = new ArrayList<>( value ); + super( value ); this.metadata = metadata; } - public int getColumnCount() { - return metadata.getColumnCount(); - } - - - public TypedValue getValue( int columnIndex ) { - return values.get( columnIndex ); - } - - public TypedValue getValue( String columnName ) throws PrismInterfaceServiceException { try { int index = metadata.getColumnIndexFromLabel( columnName ); - return values.get( index ); + return get( index ); } catch ( SQLException e ) { throw new PrismInterfaceServiceException( PrismInterfaceErrors.VALUE_ILLEGAL, diff --git a/src/main/java/org/polypheny/jdbc/types/PolyDocument.java b/src/main/java/org/polypheny/jdbc/types/PolyDocument.java index 7e1bfdd..0d899b8 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyDocument.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyDocument.java @@ -33,11 +33,6 @@ public PolyDocument() { } - public PolyDocument( HashMap entries ) { - super( entries ); - } - - public PolyDocument( ProtoDocument document ) { super(); document.getEntriesList().stream() diff --git a/src/main/java/org/polypheny/jdbc/types/PolyEdge.java b/src/main/java/org/polypheny/jdbc/types/PolyEdge.java new file mode 100644 index 0000000..66a1801 --- /dev/null +++ b/src/main/java/org/polypheny/jdbc/types/PolyEdge.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc.types; + +import lombok.Getter; +import org.polypheny.prism.ProtoEdge; +import org.polypheny.prism.ProtoValue.ValueCase; + +@Getter +public class PolyEdge extends PolyGraphElement { + + private final String source; + private final String target; + private final EdgeDirection direction; + + public PolyEdge( ProtoEdge protoEdge ) { + super(); + this.id = protoEdge.getId(); + this.name = protoEdge.getName(); + this.labels = protoEdge.getLabelsList(); + protoEdge.getPropertiesList().stream() + .filter( e -> e.getKey().getValueCase() == ValueCase.STRING ) + .forEach( p -> put( + p.getKey().getString().getString(), + new TypedValue( p.getValue() ) + ) ); + this.source = protoEdge.getSource(); + this.target = protoEdge.getTarget(); + this.direction = EdgeDirection.valueOf( protoEdge.getDirection().name() ); + } + + enum EdgeDirection { + LEFT_TO_RIGHT, + RIGHT_TO_LEFT, + NONE + } + +} diff --git a/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java new file mode 100644 index 0000000..baeaeb2 --- /dev/null +++ b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc.types; + + +import java.util.HashMap; +import java.util.List; +import lombok.Getter; + +@Getter +public class PolyGraphElement extends HashMap { + + protected String id; + protected String name; + protected List labels; + + +} diff --git a/src/main/java/org/polypheny/jdbc/types/PolyNode.java b/src/main/java/org/polypheny/jdbc/types/PolyNode.java new file mode 100644 index 0000000..7172cdc --- /dev/null +++ b/src/main/java/org/polypheny/jdbc/types/PolyNode.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc.types; + +import org.polypheny.prism.ProtoNode; +import org.polypheny.prism.ProtoValue.ValueCase; + +public class PolyNode extends PolyGraphElement { + + + public PolyNode( ProtoNode protoNode ) { + super(); + this.id = protoNode.getId(); + this.name = protoNode.getName(); + this.labels = protoNode.getLabelsList(); + protoNode.getPropertiesList().stream() + .filter( e -> e.getKey().getValueCase() == ValueCase.STRING ) + .forEach( p -> put( + p.getKey().getString().getString(), + new TypedValue( p.getValue() ) + ) ); + } + +} diff --git a/src/main/java/org/polypheny/jdbc/types/PolyPath.java b/src/main/java/org/polypheny/jdbc/types/PolyPath.java new file mode 100644 index 0000000..0c47854 --- /dev/null +++ b/src/main/java/org/polypheny/jdbc/types/PolyPath.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc.types; + +import org.polypheny.prism.ProtoPath; + +public class PolyPath extends PolyGraphElement { + + public PolyPath( ProtoPath protoPath ) { + + } + +} From 3c2ab9f26302f183edde5d19657bdfe773ccf2f2 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Fri, 17 May 2024 11:28:56 +0200 Subject: [PATCH 03/17] Add tests --- .../polypheny/jdbc/multimodel/PolyRow.java | 2 +- .../jdbc/types/PolyGraphElement.java | 9 +++++ .../java/org/polypheny/jdbc/QueryTest.java | 37 +++++++++++++++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java b/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java index 48ce9f1..9883550 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/PolyRow.java @@ -36,7 +36,7 @@ public PolyRow( List value, RelationalMetadata metadata ) { } - public TypedValue getValue( String columnName ) throws PrismInterfaceServiceException { + public TypedValue get( String columnName ) throws PrismInterfaceServiceException { try { int index = metadata.getColumnIndexFromLabel( columnName ); return get( index ); diff --git a/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java index baeaeb2..dced7e0 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java @@ -20,6 +20,8 @@ import java.util.HashMap; import java.util.List; import lombok.Getter; +import org.polypheny.jdbc.PrismInterfaceErrors; +import org.polypheny.jdbc.PrismInterfaceServiceException; @Getter public class PolyGraphElement extends HashMap { @@ -28,5 +30,12 @@ public class PolyGraphElement extends HashMap { protected String name; protected List labels; + public T unwrap( Class aClass ) throws PrismInterfaceServiceException { + if ( aClass.isInstance( this ) ) { + return aClass.cast( this ); + } + throw new PrismInterfaceServiceException( PrismInterfaceErrors.WRAPPER_INCORRECT_TYPE, "Not a wrapper for " + aClass ); + } + } diff --git a/src/test/java/org/polypheny/jdbc/QueryTest.java b/src/test/java/org/polypheny/jdbc/QueryTest.java index 3271bbe..1d334bd 100644 --- a/src/test/java/org/polypheny/jdbc/QueryTest.java +++ b/src/test/java/org/polypheny/jdbc/QueryTest.java @@ -28,11 +28,14 @@ import org.junit.jupiter.api.Test; import org.polypheny.jdbc.multimodel.DocumentResult; import org.polypheny.jdbc.multimodel.GraphResult; +import org.polypheny.jdbc.multimodel.PolyRow; import org.polypheny.jdbc.multimodel.PolyStatement; import org.polypheny.jdbc.multimodel.RelationalResult; import org.polypheny.jdbc.multimodel.Result; import org.polypheny.jdbc.multimodel.Result.ResultType; import org.polypheny.jdbc.types.PolyDocument; +import org.polypheny.jdbc.types.PolyGraphElement; +import org.polypheny.jdbc.types.PolyNode; public class QueryTest { @@ -115,18 +118,44 @@ public void mqlDataRetrievalTest() { } @Test - public void simpleCypherTest() { + public void simpleCypherNodesTest() { try ( Connection connection = TestHelper.getConnection() ) { if ( !connection.isWrapperFor( PolyConnection.class ) ) { fail( "Driver must support unwrapping to PolyphenyConnection" ); } PolyStatement polyStatement = connection.unwrap( PolyConnection.class ).createPolyStatement(); - Result result = polyStatement.execute( "gph", CYPHER_LANGUAGE_NAME, "MATCH (p:Person) RETURN p.age, p.name" ); - RelationalResult relRes = result.unwrap( RelationalResult.class ); - assertEquals( ResultType.RELATIONAL, result.getResultType() ); + Result result = polyStatement.execute( "public", CYPHER_LANGUAGE_NAME, "MATCH (c:customers) WHERE c.name = \"Maria\" OR c.name = \"Daniel\" RETURN c" ); + assertEquals( ResultType.GRAPH, result.getResultType() ); + GraphResult graphResult = result.unwrap( GraphResult.class ); + for ( PolyGraphElement element : graphResult ) { + element.get("name"); + element.get("year_joined"); + element.getLabels(); + element.getId(); + } } catch ( SQLException e ) { throw new RuntimeException( e ); } } + @Test + public void simpleCypherPropertyTest() { + try ( Connection connection = TestHelper.getConnection() ) { + if ( !connection.isWrapperFor( PolyConnection.class ) ) { + fail( "Driver must support unwrapping to PolyphenyConnection" ); + } + PolyStatement polyStatement = connection.unwrap( PolyConnection.class ).createPolyStatement(); + Result result = polyStatement.execute( "public", CYPHER_LANGUAGE_NAME, "MATCH (c:customers)\n" + + "WHERE c.name = \"Maria\" OR c.name = \"Daniel\"\n" + + "RETURN c.name, c.year_joined" ); + assertEquals( ResultType.RELATIONAL, result.getResultType() ); + RelationalResult relationalResult = result.unwrap( RelationalResult.class ); + for ( PolyRow row : relationalResult ) { + row.get(0); + row.get("c.name"); + } + } catch ( SQLException e ) { + throw new RuntimeException( e ); + } + } } From 30be8534b8e78781ddd287abafec163ed045e13f Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Fri, 17 May 2024 13:23:32 +0200 Subject: [PATCH 04/17] Fix multi-model statement closing bug --- .../java/org/polypheny/jdbc/multimodel/PolyStatement.java | 5 ++++- .../org/polypheny/jdbc/multimodel/RelationalMetadata.java | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java index ba1701d..5ffcbe9 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java @@ -38,7 +38,10 @@ public class PolyStatement { private int statementId; - private void resetStatement() { + private void resetStatement() throws PrismInterfaceServiceException { + if (statementId != -1) { + connection.getPrismInterfaceClient().closeStatement( statementId, connection.getTimeout() ); + } statementId = NO_STATEMENT_ID; } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java b/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java index f5107a4..f75e24e 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java @@ -19,12 +19,12 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import lombok.Getter; import org.polypheny.jdbc.PrismInterfaceErrors; import org.polypheny.jdbc.PrismInterfaceServiceException; import org.polypheny.prism.ColumnMeta; public class RelationalMetadata { - private List columnMetas; private Map columnIndexes; @@ -35,8 +35,7 @@ public RelationalMetadata( List columnMetadata ) { } - - private RelationalColumnMetadata getColumnMeta( int columnIndex ) throws PrismInterfaceServiceException { + public RelationalColumnMetadata getColumnMeta( int columnIndex ) throws PrismInterfaceServiceException { try { return columnMetas.get( columnIndex ); } catch ( IndexOutOfBoundsException e ) { From 4712d94f92b4e2b3a61f336c54d2590cf358e1ce Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Wed, 19 Jun 2024 13:18:30 +0200 Subject: [PATCH 05/17] Add parameterized and batched execution --- .../polypheny/jdbc/PrismInterfaceClient.java | 44 ++++++++- .../java/org/polypheny/jdbc/RpcService.java | 45 ++++++---- .../jdbc/multimodel/PolyStatement.java | 89 ++++++++++++++++++- .../org/polypheny/jdbc/utils/ProtoUtils.java | 16 ++++ 4 files changed, 172 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/polypheny/jdbc/PrismInterfaceClient.java b/src/main/java/org/polypheny/jdbc/PrismInterfaceClient.java index e075229..a46764b 100644 --- a/src/main/java/org/polypheny/jdbc/PrismInterfaceClient.java +++ b/src/main/java/org/polypheny/jdbc/PrismInterfaceClient.java @@ -47,6 +47,7 @@ import org.polypheny.prism.Entity; import org.polypheny.prism.ExecuteIndexedStatementBatchRequest; import org.polypheny.prism.ExecuteIndexedStatementRequest; +import org.polypheny.prism.ExecuteNamedStatementRequest; import org.polypheny.prism.ExecuteUnparameterizedStatementBatchRequest; import org.polypheny.prism.ExecuteUnparameterizedStatementRequest; import org.polypheny.prism.FetchRequest; @@ -54,6 +55,7 @@ import org.polypheny.prism.Function; import org.polypheny.prism.FunctionsRequest; import org.polypheny.prism.IndexedParameters; +import org.polypheny.prism.NamedParameters; import org.polypheny.prism.Namespace; import org.polypheny.prism.NamespacesRequest; import org.polypheny.prism.PrepareStatementRequest; @@ -145,15 +147,26 @@ public void unregister( int timeout ) throws PrismInterfaceServiceException { public void executeUnparameterizedStatement( String namespaceName, String languageName, String statement, CallbackQueue callback, int timeout ) throws PrismInterfaceServiceException { + ExecuteUnparameterizedStatementRequest request = buildExecuteUnparameterizedStatementRequest( statement, namespaceName, languageName ); + rpc.executeUnparameterizedStatement( request, callback ); // TODO timeout + } + + + public void executeUnparameterizedStatementBatch( List statements, String namespaceName, String languageName, CallbackQueue updateCallback, int timeout ) throws PrismInterfaceServiceException { + List requests = statements.stream().map( s -> buildExecuteUnparameterizedStatementRequest( s, namespaceName, languageName ) ).collect( Collectors.toList() ); + executeUnparameterizedStatementBatch( requests, updateCallback, timeout ); + } + + + public ExecuteUnparameterizedStatementRequest buildExecuteUnparameterizedStatementRequest( String statement, String namespaceName, String languageName ) { ExecuteUnparameterizedStatementRequest.Builder requestBuilder = ExecuteUnparameterizedStatementRequest.newBuilder(); if ( namespaceName != null ) { requestBuilder.setNamespaceName( namespaceName ); } - ExecuteUnparameterizedStatementRequest request = requestBuilder + return requestBuilder .setLanguageName( languageName ) .setStatement( statement ) .build(); - rpc.executeUnparameterizedStatement( request, callback ); // TODO timeout } @@ -179,6 +192,19 @@ public PreparedStatementSignature prepareIndexedStatement( String namespaceName, } + public PreparedStatementSignature prepareNamedStatement( String namespaceName, String languageName, String statement, int timeout ) throws PrismInterfaceServiceException { + PrepareStatementRequest.Builder requestBuilder = PrepareStatementRequest.newBuilder(); + if ( namespaceName != null ) { + requestBuilder.setNamespaceName( namespaceName ); + } + PrepareStatementRequest request = requestBuilder + .setStatement( statement ) + .setLanguageName( languageName ) + .build(); + return rpc.prepareNamedStatement( request, timeout ); + } + + public StatementResult executeIndexedStatement( int statementId, List values, int fetchSize, int timeout ) throws PrismInterfaceServiceException { IndexedParameters parameters = IndexedParameters.newBuilder() .addAllParameters( ProtoUtils.serializeParameterList( values ) ) @@ -193,6 +219,20 @@ public StatementResult executeIndexedStatement( int statementId, List values, int fetchSize, int timeout ) throws PrismInterfaceServiceException { + NamedParameters parameters = NamedParameters.newBuilder() + .putAllParameters( ProtoUtils.serializeParameterMap( values ) ) + .build(); + ExecuteNamedStatementRequest request = ExecuteNamedStatementRequest.newBuilder() + .setStatementId( statementId ) + .setParameters( parameters ) + .setFetchSize( fetchSize ) + .build(); + + return rpc.executeNamedStatement( request, timeout ); + } + + public StatementBatchResponse executeIndexedStatementBatch( int statementId, List> parameterBatch, int timeout ) throws PrismInterfaceServiceException { List parameters = parameterBatch.stream() .map( ProtoUtils::serializeParameterList ) diff --git a/src/main/java/org/polypheny/jdbc/RpcService.java b/src/main/java/org/polypheny/jdbc/RpcService.java index 17ed8d8..cbb948f 100644 --- a/src/main/java/org/polypheny/jdbc/RpcService.java +++ b/src/main/java/org/polypheny/jdbc/RpcService.java @@ -55,6 +55,7 @@ import org.polypheny.prism.EntitiesResponse; import org.polypheny.prism.ExecuteIndexedStatementBatchRequest; import org.polypheny.prism.ExecuteIndexedStatementRequest; +import org.polypheny.prism.ExecuteNamedStatementRequest; import org.polypheny.prism.ExecuteUnparameterizedStatementBatchRequest; import org.polypheny.prism.ExecuteUnparameterizedStatementRequest; import org.polypheny.prism.FetchRequest; @@ -90,25 +91,25 @@ public class RpcService { private final AtomicLong idCounter = new AtomicLong( 1 ); - private final Transport con; + private final Transport connection; private final Thread service; - private boolean closed = false; - private boolean disconnectSent = false; + private boolean isClosed = false; + private boolean hasSentDisconnect = false; private IOException error = null; private final Map> callbacks = new ConcurrentHashMap<>(); private final Map> callbackQueues = new ConcurrentHashMap<>(); - RpcService( Transport con ) { - this.con = con; + RpcService( Transport connection ) { + this.connection = connection; this.service = new Thread( this::readResponses, "PrismInterfaceResponseHandler" ); this.service.start(); } void close() { - closed = true; - con.close(); + isClosed = true; + connection.close(); try { service.join(); } catch ( InterruptedException e ) { @@ -131,15 +132,15 @@ private void sendMessage( Request req ) throws IOException { throw e; } } - if ( this.closed ) { + if ( this.isClosed ) { throw new IOException( "Connection is closed" ); } - con.sendMessage( req.toByteArray() ); + connection.sendMessage( req.toByteArray() ); } private Response receiveMessage() throws IOException { - return Response.parseFrom( con.receiveMessage() ); + return Response.parseFrom( connection.receiveMessage() ); } @@ -177,15 +178,15 @@ private void readResponses() { c.complete( resp ); } } catch ( EOFException | ClosedChannelException e ) { - this.closed = true; + this.isClosed = true; callbacks.forEach( ( id, c ) -> c.completeExceptionally( e ) ); callbackQueues.forEach( ( id, cq ) -> cq.onError( e ) ); } catch ( IOException e ) { // Communicate this to ProtoInterfaceClient - this.closed = true; + this.isClosed = true; callbacks.forEach( ( id, c ) -> c.completeExceptionally( e ) ); callbackQueues.forEach( ( id, cq ) -> cq.onError( e ) ); /* For Windows */ - if ( e.getMessage().contains( "An existing connection was forcibly closed by the remote host" ) && disconnectSent ) { + if ( e.getMessage().contains( "An existing connection was forcibly closed by the remote host" ) && hasSentDisconnect ) { return; } /* For Windows */ @@ -197,7 +198,7 @@ private void readResponses() { this.error = e; throw new RuntimeException( e ); } catch ( Throwable t ) { - this.closed = true; + this.isClosed = true; callbacks.forEach( ( id, c ) -> c.completeExceptionally( t ) ); callbackQueues.forEach( ( id, cq ) -> cq.onError( t ) ); log.error( "Unhandled exception", t ); @@ -224,7 +225,7 @@ private Response completeSynchronously( Request.Builder req, int timeout ) throw CompletableFuture f = new CompletableFuture<>(); callbacks.put( req.getId(), f ); if ( req.getTypeCase() == TypeCase.DISCONNECT_REQUEST ) { - disconnectSent = true; + hasSentDisconnect = true; } sendMessage( req.build() ); Response resp = waitForCompletion( f, timeout ); @@ -423,6 +424,13 @@ PreparedStatementSignature prepareIndexedStatement( PrepareStatementRequest msg, return completeSynchronously( req, timeout ).getPreparedStatementSignature(); } + public PreparedStatementSignature prepareNamedStatement( PrepareStatementRequest msg, int timeout ) throws PrismInterfaceServiceException { + Request.Builder req = newMessage(); + req.setPrepareIndexedStatementRequest( msg ); + return completeSynchronously( req, timeout ).getPreparedStatementSignature(); + } + + StatementResult executeIndexedStatement( ExecuteIndexedStatementRequest msg, int timeout ) throws PrismInterfaceServiceException { Request.Builder req = newMessage(); @@ -430,6 +438,12 @@ StatementResult executeIndexedStatement( ExecuteIndexedStatementRequest msg, int return completeSynchronously( req, timeout ).getStatementResult(); } + public StatementResult executeNamedStatement( ExecuteNamedStatementRequest msg, int timeout ) throws PrismInterfaceServiceException { + Request.Builder req = newMessage(); + req.setExecuteNamedStatementRequest( msg ); + return completeSynchronously( req, timeout ).getStatementResult(); + } + StatementBatchResponse executeIndexedStatementBatch( ExecuteIndexedStatementBatchRequest msg, int timeout ) throws PrismInterfaceServiceException { Request.Builder req = newMessage(); @@ -457,5 +471,4 @@ CloseResultResponse closeResult( CloseResultRequest msg, int timeout ) throws Pr req.setCloseResultRequest( msg ); return completeSynchronously( req, timeout ).getCloseResultResponse(); } - } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java index 5ffcbe9..e4566b9 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java @@ -16,33 +16,41 @@ package org.polypheny.jdbc.multimodel; +import java.util.HashMap; +import java.util.List; import lombok.Getter; import org.polypheny.jdbc.PolyConnection; import org.polypheny.jdbc.PrismInterfaceClient; import org.polypheny.jdbc.PrismInterfaceErrors; import org.polypheny.jdbc.PrismInterfaceServiceException; +import org.polypheny.jdbc.properties.PropertyUtils; +import org.polypheny.jdbc.types.TypedValue; import org.polypheny.jdbc.utils.CallbackQueue; import org.polypheny.prism.Frame; -import org.polypheny.prism.Frame.ResultCase; +import org.polypheny.prism.PreparedStatementSignature; import org.polypheny.prism.Response; +import org.polypheny.prism.StatementBatchResponse; import org.polypheny.prism.StatementResponse; +import org.polypheny.prism.StatementResult; public class PolyStatement { - private static final long SCALAR_NOT_SET = -1; private static final int NO_STATEMENT_ID = -1; @Getter private PolyConnection connection; @Getter private int statementId; + @Getter + private boolean isPrepared; private void resetStatement() throws PrismInterfaceServiceException { - if (statementId != -1) { + if ( statementId != -1 ) { connection.getPrismInterfaceClient().closeStatement( statementId, connection.getTimeout() ); } statementId = NO_STATEMENT_ID; + isPrepared = false; } @@ -58,7 +66,7 @@ private Result getResultFromFrame( Frame frame ) throws PrismInterfaceServiceExc case DOCUMENT_FRAME: return new DocumentResult( frame, this ); case GRAPH_FRAME: - return new GraphResult(frame, this); + return new GraphResult( frame, this ); } throw new PrismInterfaceServiceException( PrismInterfaceErrors.RESULT_TYPE_INVALID, "Statement produced unknown result type" ); } @@ -100,4 +108,77 @@ public Result execute( String namespaceName, String languageName, String stateme } } + + public List execute( String namespaceName, String languageName, List statements ) throws PrismInterfaceServiceException, InterruptedException { + resetStatement(); + CallbackQueue callback = new CallbackQueue<>( Response::getStatementBatchResponse ); + int timeout = connection.getTimeout(); + getPrismInterfaceClient().executeUnparameterizedStatementBatch( statements, namespaceName, languageName, callback, timeout ); + while ( true ) { + StatementBatchResponse response = callback.takeNext(); + if ( statementId == NO_STATEMENT_ID ) { + statementId = response.getBatchId(); + } + if ( response.getScalarsCount() == 0 ) { + continue; + } + callback.awaitCompletion(); + return response.getScalarsList(); + } + } + + + public void prepare( String namespaceName, String languageName, String statement ) throws PrismInterfaceServiceException { + int timeout = connection.getTimeout(); + if ( statement.contains( "?" ) ) { + PreparedStatementSignature signature = getPrismInterfaceClient().prepareIndexedStatement( namespaceName, languageName, statement, timeout ); + statementId = signature.getStatementId(); + isPrepared = true; + return; + } + if ( statement.contains( ":" ) ) { + org.polypheny.prism.PreparedStatementSignature signature = connection.getPrismInterfaceClient().prepareNamedStatement( namespaceName, languageName, statement, timeout ); + statementId = signature.getStatementId(); + isPrepared = true; + return; + } + throw new PrismInterfaceServiceException( PrismInterfaceErrors.VALUE_ILLEGAL, "Statement must be either of the indexed or named parameterized kind." ); + } + + + public Result executePrepared( List parameters ) throws PrismInterfaceServiceException { + if ( !isPrepared ) { + throw new PrismInterfaceServiceException( PrismInterfaceErrors.OPERATION_ILLEGAL, "This operation requires a statmement to be prepared first" ); + } + int timeout = connection.getTimeout(); + StatementResult result = getPrismInterfaceClient().executeIndexedStatement( statementId, parameters, PropertyUtils.getDEFAULT_FETCH_SIZE(), timeout ); + if ( !result.hasFrame() ) { + return new ScalarResult( result.getScalar() ); + } + return getResultFromFrame( result.getFrame() ); + } + + + public Result executePrepared( HashMap parameters ) throws PrismInterfaceServiceException { + if ( !isPrepared ) { + throw new PrismInterfaceServiceException( PrismInterfaceErrors.OPERATION_ILLEGAL, "This operation requires a statmement to be prepared first" ); + } + int timeout = connection.getTimeout(); + StatementResult result = getPrismInterfaceClient().executeNamedStatement( statementId, parameters, PropertyUtils.getDEFAULT_FETCH_SIZE(), timeout ); + if ( !result.hasFrame() ) { + return new ScalarResult( result.getScalar() ); + } + return getResultFromFrame( result.getFrame() ); + } + + + List executePreparedBatch( List> parameterBatch ) throws PrismInterfaceServiceException { + if ( !isPrepared ) { + throw new PrismInterfaceServiceException( PrismInterfaceErrors.OPERATION_ILLEGAL, "This operation requires a statmement to be prepared first" ); + } + int timeout = connection.getTimeout(); + StatementBatchResponse response = getPrismInterfaceClient().executeIndexedStatementBatch( statementId, parameterBatch, timeout ); + return response.getScalarsList(); + } + } diff --git a/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java b/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java index 7cfa640..5aeb9ed 100644 --- a/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java +++ b/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java @@ -18,6 +18,8 @@ import java.sql.SQLException; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.stream.Collectors; import org.polypheny.jdbc.types.TypedValue; import org.polypheny.prism.ProtoString; @@ -45,4 +47,18 @@ public static List serializeParameterList( List values ) } ).collect( Collectors.toList() ); } + + public static Map serializeParameterMap(Map values) { + return values.entrySet().stream().collect(Collectors.toMap( + Entry::getKey, + value -> { + try { + return value.getValue().serialize(); + } catch (Exception e) { + throw new RuntimeException("Serialization failed", e); + } + } + )); + } + } From ce8ed620a71692ce05b957fec1a1990190223714 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Fri, 5 Jul 2024 10:08:21 +0200 Subject: [PATCH 06/17] Add demo --- src/test/java/org/polypheny/jdbc/Demo.java | 204 +++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 src/test/java/org/polypheny/jdbc/Demo.java diff --git a/src/test/java/org/polypheny/jdbc/Demo.java b/src/test/java/org/polypheny/jdbc/Demo.java new file mode 100644 index 0000000..4dfd3be --- /dev/null +++ b/src/test/java/org/polypheny/jdbc/Demo.java @@ -0,0 +1,204 @@ +/* + * Copyright 2019-2024 The Polypheny Project + * + * Licensed 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.polypheny.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import org.polypheny.jdbc.multimodel.DocumentResult; +import org.polypheny.jdbc.multimodel.GraphResult; +import org.polypheny.jdbc.multimodel.PolyRow; +import org.polypheny.jdbc.multimodel.PolyStatement; +import org.polypheny.jdbc.multimodel.RelationalMetadata; +import org.polypheny.jdbc.multimodel.RelationalResult; +import org.polypheny.jdbc.multimodel.Result; +import org.polypheny.jdbc.multimodel.ScalarResult; +import org.polypheny.jdbc.types.PolyDocument; +import org.polypheny.jdbc.types.PolyGraphElement; +import org.polypheny.jdbc.types.TypedValue; + +public class Demo { + + private static String language = "sql"; + private static String namespace = "public"; + private static Connection con; + + public static void main(String[] args) { + try { + con = DriverManager.getConnection("jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", ""); + if (!con.isWrapperFor(PolyConnection.class)) { + System.out.println("Driver must support unwrapping to PolyConnection"); + return; + } + Scanner scanner = new Scanner(System.in); + + while (true) { + printPrompt(); + String input = scanner.nextLine(); + + if (input.startsWith("lng ")) { + language = input.substring(4).trim(); + System.out.println("Language set to " + language); + } else if (input.startsWith("ns ")) { + namespace = input.substring(3).trim(); + System.out.println("Namespace set to " + namespace); + } else if (input.equals("exit")) { + break; + } else { + if (language == null || namespace == null) { + System.out.println("Please set both language and namespace before executing a statement."); + continue; + } + String statement = input.trim(); + executeStatement(namespace, language, statement); + } + } + + scanner.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (con != null && !con.isClosed()) { + con.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + + private static void printPrompt() { + System.out.print( language + "@" + namespace + "> " ); + } + + + private static void executeStatement( String namespace, String language, String statement ) { + try ( Connection con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ) ) { + if ( !con.isWrapperFor( PolyConnection.class ) ) { + System.out.println( "Driver must support unwrapping to PolyConnection" ); + return; + } + PolyStatement polyStatement = con.unwrap( PolyConnection.class ).createPolyStatement(); + Result result = polyStatement.execute( namespace, language, statement ); + switch ( result.getResultType() ) { + case RELATIONAL: + RelationalResult relationalResult = result.unwrap( RelationalResult.class ); + printRelationalResult( relationalResult ); + break; + case DOCUMENT: + DocumentResult documentResult = result.unwrap( DocumentResult.class ); + printDocumentResult( documentResult ); + break; + case SCALAR: + ScalarResult scalarResult = result.unwrap( ScalarResult.class ); + System.out.println( "Update count: " + scalarResult.getScalar() + "." ); + break; + case GRAPH: + GraphResult graphResult = result.unwrap( GraphResult.class ); + printGraphResult( graphResult ); + break; + default: + System.out.println( "Unknown result type." ); + } + } catch ( Exception e ) { + e.printStackTrace(); + } + } + + + private static void printRelationalResult( RelationalResult relationalResult ) throws PrismInterfaceServiceException { + RelationalMetadata metadata = relationalResult.getMetadata(); + int columnsCount = metadata.getColumnCount(); + + List columnLabels = new ArrayList<>(); + List columnWidths = new ArrayList<>(); + for ( int i = 0; i < columnsCount; i++ ) { + String label = metadata.getColumnMeta( i ).getColumnLabel(); + columnLabels.add( label ); + columnWidths.add( label.length() ); + } + + List> rows = new ArrayList<>(); + for ( PolyRow row : relationalResult ) { + List formattedRow = new ArrayList<>(); + for ( int colIndex = 0; colIndex < columnsCount; colIndex++ ) { + String valueStr = row.get( colIndex ).toString(); + formattedRow.add( valueStr ); + columnWidths.set( colIndex, Math.max( columnWidths.get( colIndex ), valueStr.length() ) ); + } + rows.add( formattedRow ); + } + + printSeparator( columnWidths ); + printRow( columnLabels, columnWidths ); + printSeparator( columnWidths ); + for ( List row : rows ) { + printRow( row, columnWidths ); + } + printSeparator( columnWidths ); + } + + + private static void printDocumentResult( DocumentResult documentResult ) { + System.out.println( "DOC------------------------" ); + for ( PolyDocument document : documentResult ) { + System.out.println( document.toString() ); + System.out.println( "---------------------------" ); + } + } + + + private static void printGraphResult( GraphResult graphResult ) { + System.out.println( "GRAPH----------------------" ); + for ( PolyGraphElement graphElement : graphResult ) { + for ( Map.Entry property : graphElement.entrySet() ) { + System.out.println( property.getKey() + ": " + property.getValue() ); + } + System.out.println( "---------------------------" ); + } + } + + + private static void printSeparator( List columnWidths ) { + for ( int width : columnWidths ) { + System.out.print( "+" ); + for ( int i = 0; i < width + 2; i++ ) { + System.out.print( "-" ); + } + } + System.out.println( "+" ); + } + + + private static void printRow( List row, List columnWidths ) { + for ( int i = 0; i < row.size(); i++ ) { + System.out.print( "| " + padRight( row.get( i ), columnWidths.get( i ) ) + " " ); + } + System.out.println( "|" ); + } + + + private static String padRight( String s, int n ) { + return String.format( "%-" + n + "s", s ); + } + +} From d370c70813a1270a75c97c683d644a3b95fc9368 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Fri, 5 Jul 2024 10:08:34 +0200 Subject: [PATCH 07/17] Fix fetch type bug --- .../java/org/polypheny/jdbc/multimodel/RelationalResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java b/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java index 01a1718..e1590c8 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/RelationalResult.java @@ -58,7 +58,7 @@ private void fetchMore() throws PrismInterfaceServiceException { int id = polyStatement.getStatementId(); int timeout = getPolyphenyConnection().getTimeout(); Frame frame = getPrismInterfaceClient().fetchResult( id, timeout, PropertyUtils.getDEFAULT_FETCH_SIZE() ); - if ( frame.getResultCase() != ResultCase.DOCUMENT_FRAME ) { + if ( frame.getResultCase() != ResultCase.RELATIONAL_FRAME ) { throw new PrismInterfaceServiceException( PrismInterfaceErrors.RESULT_TYPE_INVALID, "Statement returned a result of illegal type " + frame.getResultCase() From 5cb91ffafb37d80ee0721d75a84a9b751bd35a1b Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Fri, 5 Jul 2024 10:08:53 +0200 Subject: [PATCH 08/17] Reformat --- .../org/polypheny/jdbc/types/TypedValue.java | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/polypheny/jdbc/types/TypedValue.java b/src/main/java/org/polypheny/jdbc/types/TypedValue.java index 550af23..c496b18 100644 --- a/src/main/java/org/polypheny/jdbc/types/TypedValue.java +++ b/src/main/java/org/polypheny/jdbc/types/TypedValue.java @@ -1277,7 +1277,6 @@ public ProtoValue serialize() throws SQLException { return serializeAsProtoFile(); case DOCUMENT: return serializeAsProtoDocument(); - } throw new PrismInterfaceServiceException( PrismInterfaceErrors.DATA_TYPE_MISMATCH, "Failed to serialize unknown type: " + valueCase.name() ); } @@ -1471,11 +1470,44 @@ private static PolyInterval getInterval( ProtoInterval interval ) { @Override public String toString() { - try { - return asString(); - } catch ( SQLException e ) { - throw new RuntimeException( e ); + if ( isSerialized ) { + deserialize(); + } + switch ( valueCase ) { + case BOOLEAN: + return "" + booleanValue; + case INTEGER: + return "" + integerValue; + case LONG: + return "" + bigintValue; + case BIG_DECIMAL: + return "" + bigDecimalValue; + case FLOAT: + return "" + floatValue; + case DOUBLE: + return "" + doubleValue; + case DATE: + return "" + dateValue; + case TIME: + return "" + timeValue; + case TIMESTAMP: + return "" + timestampValue; + case INTERVAL: + return "" + otherValue; + case STRING: + return varcharValue; + case BINARY: + return "BINARY"; + case NULL: + return "NULL"; + case LIST: + return "LIST"; + case FILE: + return "FILE"; + case DOCUMENT: + return "DOCUMENT"; } + return ""; } } From 228b9ad5b184c13d193cdc370b46875698646183 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Tue, 9 Jul 2024 11:33:01 +0200 Subject: [PATCH 09/17] Fix method access --- src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java index e4566b9..50021b9 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/PolyStatement.java @@ -172,7 +172,7 @@ public Result executePrepared( HashMap parameters ) throws P } - List executePreparedBatch( List> parameterBatch ) throws PrismInterfaceServiceException { + public List executePreparedBatch( List> parameterBatch ) throws PrismInterfaceServiceException { if ( !isPrepared ) { throw new PrismInterfaceServiceException( PrismInterfaceErrors.OPERATION_ILLEGAL, "This operation requires a statmement to be prepared first" ); } From a8d7f90c82229685f3abd5a399d6e562395d44c5 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Thu, 18 Jul 2024 10:11:48 +0200 Subject: [PATCH 10/17] Add not implemented exception for paths --- src/main/java/org/polypheny/jdbc/types/PolyPath.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/polypheny/jdbc/types/PolyPath.java b/src/main/java/org/polypheny/jdbc/types/PolyPath.java index 0c47854..2b1fb8c 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyPath.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyPath.java @@ -16,12 +16,14 @@ package org.polypheny.jdbc.types; +import org.apache.commons.lang3.NotImplementedException; import org.polypheny.prism.ProtoPath; public class PolyPath extends PolyGraphElement { public PolyPath( ProtoPath protoPath ) { - + // TODO: implementation + throw new NotImplementedException(); } } From bad82ff55ecd63e5f712dd25ce5dbd4f6d01da38 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Thu, 18 Jul 2024 10:14:04 +0200 Subject: [PATCH 11/17] Update api version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 880c149..3007471 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ def protobufVersion = "3.23.4" dependencies { // Prism API files (protobuf files), needs to be implementation due to the prism-api-version.properties - implementation group: 'org.polypheny', name: 'prism', version: '5.1' //1.9 + implementation group: 'org.polypheny', name: 'prism', version: '1.4' //1.3 // Protobuf implementation group: 'com.google.protobuf', name: 'protobuf-java', version: protobufVersion From 8915c8ca81ecda7828ad6cead427a261bf31c1a7 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Sun, 28 Jul 2024 08:21:13 +0200 Subject: [PATCH 12/17] Fix api version --- build.gradle | 5 +- .../org/polypheny/jdbc/ConnectionTest.java | 80 ++++++++++++++++++- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 3007471..dfb926a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ plugins { + id 'java' id 'java-library' id 'maven-publish' id 'signing' @@ -20,10 +21,10 @@ version = versionMajor + "." + versionMinor + (versionQualifier != '' ? "-" + ve repositories { mavenCentral() + mavenLocal() maven { url "https://plugins.gradle.org/m2/" } - mavenLocal() } compileJava.options.encoding = "UTF-8" @@ -56,7 +57,7 @@ def protobufVersion = "3.23.4" dependencies { // Prism API files (protobuf files), needs to be implementation due to the prism-api-version.properties - implementation group: 'org.polypheny', name: 'prism', version: '1.4' //1.3 + implementation group: 'org.polypheny', name: 'prism', version: '1.10' // Protobuf implementation group: 'com.google.protobuf', name: 'protobuf-java', version: protobufVersion diff --git a/src/test/java/org/polypheny/jdbc/ConnectionTest.java b/src/test/java/org/polypheny/jdbc/ConnectionTest.java index a36283e..23ee20a 100644 --- a/src/test/java/org/polypheny/jdbc/ConnectionTest.java +++ b/src/test/java/org/polypheny/jdbc/ConnectionTest.java @@ -106,28 +106,104 @@ void testClientProperties() throws SQLException { @Test - void testMetaData() throws SQLException { + void testMetaDataGetURL() throws SQLException { DatabaseMetaData meta = con.getMetaData(); meta.getURL(); + } + + + @Test + void testMetaDataGetDatabaseProductName() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getDatabaseProductName(); + } + + + @Test + void testMetaDataGetCatalogs() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getCatalogs(); + } + + + @Test + void testMetaDataGetTableTypes() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getTableTypes(); + } + + + @Test + void testMetaDataGetTypeInfo() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getTypeInfo(); + } + + + @Test + void testMetaDataGetColumns() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getColumns( "public", ".*", ".*", ".*" ); + } + + + @Test + void testMetaDataGetStringFunctions() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getStringFunctions(); + } + + + @Test + void testMetaDataGetSystemFunctions() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getSystemFunctions(); + } + + + @Test + void testMetaDataGetTimeDateFunctions() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getTimeDateFunctions(); + } + + + @Test + void testMetaDataGetNumericFunctions() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getNumericFunctions(); + } + + + @Test + void testMetaDataGetSQLKeywords() throws SQLException { + DatabaseMetaData meta = con.getMetaData(); meta.getSQLKeywords(); } @Test - void testMetaDataNotStrict() throws SQLException { + void testMetaDataGetProceduresNotStrict() throws SQLException { try ( Connection con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ) ) { DatabaseMetaData meta = con.getMetaData(); meta.getProcedures( "public", ".*", ".*" ); + } + } + + + @Test + void testMetaDataGetFunctionsNotStrict() throws SQLException { + try ( Connection con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ) ) { + DatabaseMetaData meta = con.getMetaData(); meta.getFunctions( "public", ".*", ".*" ); + } + } + + + @Test + void testMetaDataGetSchemasNotStrict() throws SQLException { + try ( Connection con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ) ) { + DatabaseMetaData meta = con.getMetaData(); meta.getSchemas( "public", ".*" ); } } From eaba6d16586f126adf665361945608ad497b1449 Mon Sep 17 00:00:00 2001 From: TobiasHafner Date: Wed, 31 Jul 2024 11:29:04 +0200 Subject: [PATCH 13/17] Ignore and mark broken test --- src/test/java/org/polypheny/jdbc/ConnectionTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/polypheny/jdbc/ConnectionTest.java b/src/test/java/org/polypheny/jdbc/ConnectionTest.java index 23ee20a..0354f82 100644 --- a/src/test/java/org/polypheny/jdbc/ConnectionTest.java +++ b/src/test/java/org/polypheny/jdbc/ConnectionTest.java @@ -29,6 +29,7 @@ import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; import java.util.Properties; +import jdk.nashorn.internal.ir.annotations.Ignore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -192,6 +193,8 @@ void testMetaDataGetProceduresNotStrict() throws SQLException { @Test + @Ignore + // This test fails due to syntax definitions missing for some of the functions on the server side (operator registry). void testMetaDataGetFunctionsNotStrict() throws SQLException { try ( Connection con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ) ) { DatabaseMetaData meta = con.getMetaData(); From b3d253d8a0edeb2ea781e48221b270b9add152ba Mon Sep 17 00:00:00 2001 From: Martin Vahlensieck Date: Wed, 31 Jul 2024 12:29:14 +0200 Subject: [PATCH 14/17] Use JUnit 5 annotation --- src/test/java/org/polypheny/jdbc/ConnectionTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/polypheny/jdbc/ConnectionTest.java b/src/test/java/org/polypheny/jdbc/ConnectionTest.java index 0354f82..4961c1a 100644 --- a/src/test/java/org/polypheny/jdbc/ConnectionTest.java +++ b/src/test/java/org/polypheny/jdbc/ConnectionTest.java @@ -29,9 +29,9 @@ import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; import java.util.Properties; -import jdk.nashorn.internal.ir.annotations.Ignore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class ConnectionTest { @@ -193,7 +193,7 @@ void testMetaDataGetProceduresNotStrict() throws SQLException { @Test - @Ignore + @Disabled // This test fails due to syntax definitions missing for some of the functions on the server side (operator registry). void testMetaDataGetFunctionsNotStrict() throws SQLException { try ( Connection con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ) ) { From b6fce281528d44c6c0b083358dd303565f88ac09 Mon Sep 17 00:00:00 2001 From: Martin Vahlensieck Date: Wed, 31 Jul 2024 12:30:49 +0200 Subject: [PATCH 15/17] Reformat code & optimize imports --- .../java/org/polypheny/jdbc/RpcService.java | 4 +- .../jdbc/multimodel/GraphResult.java | 32 ++++-- .../multimodel/RelationalColumnMetadata.java | 3 + .../jdbc/multimodel/RelationalMetadata.java | 3 +- .../org/polypheny/jdbc/types/PolyEdge.java | 2 + .../jdbc/types/PolyGraphElement.java | 1 + .../org/polypheny/jdbc/types/TypedValue.java | 43 ------- .../org/polypheny/jdbc/utils/ProtoUtils.java | 10 +- .../org/polypheny/jdbc/ConnectionTest.java | 2 +- src/test/java/org/polypheny/jdbc/Demo.java | 39 +++---- .../java/org/polypheny/jdbc/QueryTest.java | 12 +- .../polypheny/jdbc/types/TypedValueTest.java | 105 ++++++++++++++++++ 12 files changed, 169 insertions(+), 87 deletions(-) diff --git a/src/main/java/org/polypheny/jdbc/RpcService.java b/src/main/java/org/polypheny/jdbc/RpcService.java index cbb948f..d5c421a 100644 --- a/src/main/java/org/polypheny/jdbc/RpcService.java +++ b/src/main/java/org/polypheny/jdbc/RpcService.java @@ -424,6 +424,7 @@ PreparedStatementSignature prepareIndexedStatement( PrepareStatementRequest msg, return completeSynchronously( req, timeout ).getPreparedStatementSignature(); } + public PreparedStatementSignature prepareNamedStatement( PrepareStatementRequest msg, int timeout ) throws PrismInterfaceServiceException { Request.Builder req = newMessage(); req.setPrepareIndexedStatementRequest( msg ); @@ -431,13 +432,13 @@ public PreparedStatementSignature prepareNamedStatement( PrepareStatementRequest } - StatementResult executeIndexedStatement( ExecuteIndexedStatementRequest msg, int timeout ) throws PrismInterfaceServiceException { Request.Builder req = newMessage(); req.setExecuteIndexedStatementRequest( msg ); return completeSynchronously( req, timeout ).getStatementResult(); } + public StatementResult executeNamedStatement( ExecuteNamedStatementRequest msg, int timeout ) throws PrismInterfaceServiceException { Request.Builder req = newMessage(); req.setExecuteNamedStatementRequest( msg ); @@ -471,4 +472,5 @@ CloseResultResponse closeResult( CloseResultRequest msg, int timeout ) throws Pr req.setCloseResultRequest( msg ); return completeSynchronously( req, timeout ).getCloseResultResponse(); } + } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java index ce7398f..f9848d9 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java @@ -17,7 +17,6 @@ package org.polypheny.jdbc.multimodel; import java.util.ArrayList; - import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -41,29 +40,30 @@ public class GraphResult extends Result implements Iterable { private final List elements; - public GraphResult( Frame frame, PolyStatement polyStatement ) { super( ResultType.GRAPH ); - this.polyStatement= polyStatement; + this.polyStatement = polyStatement; this.isFullyFetched = frame.getIsLast(); this.elements = new ArrayList<>(); - addGraphElements(frame.getGraphFrame()); + addGraphElements( frame.getGraphFrame() ); } + private void addGraphElements( GraphFrame graphFrame ) { - if (graphFrame.getNodesCount() > 0) { - graphFrame.getNodesList().forEach( n -> elements.add( new PolyNode(n) ) ); + if ( graphFrame.getNodesCount() > 0 ) { + graphFrame.getNodesList().forEach( n -> elements.add( new PolyNode( n ) ) ); return; } - if (graphFrame.getEdgesCount() > 0) { - graphFrame.getEdgesList().forEach( n -> elements.add( new PolyEdge(n) ) ); + if ( graphFrame.getEdgesCount() > 0 ) { + graphFrame.getEdgesList().forEach( n -> elements.add( new PolyEdge( n ) ) ); return; } - if (graphFrame.getPathsCount() > 0) { - graphFrame.getPathsList().forEach( n -> elements.add( new PolyPath(n) ) ); + if ( graphFrame.getPathsCount() > 0 ) { + graphFrame.getPathsList().forEach( n -> elements.add( new PolyPath( n ) ) ); } } + private void fetchMore() throws PrismInterfaceServiceException { int id = polyStatement.getStatementId(); int timeout = getPolyphenyConnection().getTimeout(); @@ -78,6 +78,7 @@ private void fetchMore() throws PrismInterfaceServiceException { addGraphElements( frame.getGraphFrame() ); } + private PolyConnection getPolyphenyConnection() { return polyStatement.getConnection(); } @@ -87,12 +88,18 @@ private PrismInterfaceClient getPrismInterfaceClient() { return getPolyphenyConnection().getPrismInterfaceClient(); } + @Override - public Iterator iterator() {return new GraphElementIterator();} + public Iterator iterator() { + return new GraphElementIterator(); + } + class GraphElementIterator implements Iterator { + int index = -1; + @Override public boolean hasNext() { if ( index + 1 >= elements.size() ) { @@ -108,6 +115,7 @@ public boolean hasNext() { return index + 1 < elements.size(); } + @Override public PolyGraphElement next() { if ( !hasNext() ) { @@ -115,8 +123,8 @@ public PolyGraphElement next() { } return elements.get( ++index ); } - } + } } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java b/src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java index fa92070..f0004ef 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/RelationalColumnMetadata.java @@ -21,6 +21,7 @@ @Getter public class RelationalColumnMetadata { + private final int columnIndex; private final boolean isNullable; private final int length; @@ -31,6 +32,7 @@ public class RelationalColumnMetadata { private final String protocolTypeName; private final int scale; + public RelationalColumnMetadata( ColumnMeta columnMeta ) { this.columnIndex = columnMeta.getColumnIndex(); this.isNullable = columnMeta.getIsNullable(); @@ -41,4 +43,5 @@ public RelationalColumnMetadata( ColumnMeta columnMeta ) { this.protocolTypeName = columnMeta.getTypeMeta().getProtoValueType().name(); this.scale = columnMeta.getScale(); } + } diff --git a/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java b/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java index f75e24e..f4fea83 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/RelationalMetadata.java @@ -19,12 +19,12 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import lombok.Getter; import org.polypheny.jdbc.PrismInterfaceErrors; import org.polypheny.jdbc.PrismInterfaceServiceException; import org.polypheny.prism.ColumnMeta; public class RelationalMetadata { + private List columnMetas; private Map columnIndexes; @@ -35,6 +35,7 @@ public RelationalMetadata( List columnMetadata ) { } + public RelationalColumnMetadata getColumnMeta( int columnIndex ) throws PrismInterfaceServiceException { try { return columnMetas.get( columnIndex ); diff --git a/src/main/java/org/polypheny/jdbc/types/PolyEdge.java b/src/main/java/org/polypheny/jdbc/types/PolyEdge.java index 66a1801..92ac758 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyEdge.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyEdge.java @@ -27,6 +27,7 @@ public class PolyEdge extends PolyGraphElement { private final String target; private final EdgeDirection direction; + public PolyEdge( ProtoEdge protoEdge ) { super(); this.id = protoEdge.getId(); @@ -43,6 +44,7 @@ public PolyEdge( ProtoEdge protoEdge ) { this.direction = EdgeDirection.valueOf( protoEdge.getDirection().name() ); } + enum EdgeDirection { LEFT_TO_RIGHT, RIGHT_TO_LEFT, diff --git a/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java index dced7e0..1c9df69 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java @@ -30,6 +30,7 @@ public class PolyGraphElement extends HashMap { protected String name; protected List labels; + public T unwrap( Class aClass ) throws PrismInterfaceServiceException { if ( aClass.isInstance( this ) ) { return aClass.cast( this ); diff --git a/src/main/java/org/polypheny/jdbc/types/TypedValue.java b/src/main/java/org/polypheny/jdbc/types/TypedValue.java index c496b18..09451c1 100644 --- a/src/main/java/org/polypheny/jdbc/types/TypedValue.java +++ b/src/main/java/org/polypheny/jdbc/types/TypedValue.java @@ -1467,47 +1467,4 @@ private static PolyInterval getInterval( ProtoInterval interval ) { return new PolyInterval( interval.getMonths(), interval.getMilliseconds() ); } - - @Override - public String toString() { - if ( isSerialized ) { - deserialize(); - } - switch ( valueCase ) { - case BOOLEAN: - return "" + booleanValue; - case INTEGER: - return "" + integerValue; - case LONG: - return "" + bigintValue; - case BIG_DECIMAL: - return "" + bigDecimalValue; - case FLOAT: - return "" + floatValue; - case DOUBLE: - return "" + doubleValue; - case DATE: - return "" + dateValue; - case TIME: - return "" + timeValue; - case TIMESTAMP: - return "" + timestampValue; - case INTERVAL: - return "" + otherValue; - case STRING: - return varcharValue; - case BINARY: - return "BINARY"; - case NULL: - return "NULL"; - case LIST: - return "LIST"; - case FILE: - return "FILE"; - case DOCUMENT: - return "DOCUMENT"; - } - return ""; - } - } diff --git a/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java b/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java index 5aeb9ed..ef1b5a0 100644 --- a/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java +++ b/src/main/java/org/polypheny/jdbc/utils/ProtoUtils.java @@ -48,17 +48,17 @@ public static List serializeParameterList( List values ) } - public static Map serializeParameterMap(Map values) { - return values.entrySet().stream().collect(Collectors.toMap( + public static Map serializeParameterMap( Map values ) { + return values.entrySet().stream().collect( Collectors.toMap( Entry::getKey, value -> { try { return value.getValue().serialize(); - } catch (Exception e) { - throw new RuntimeException("Serialization failed", e); + } catch ( Exception e ) { + throw new RuntimeException( "Serialization failed", e ); } } - )); + ) ); } } diff --git a/src/test/java/org/polypheny/jdbc/ConnectionTest.java b/src/test/java/org/polypheny/jdbc/ConnectionTest.java index 4961c1a..2e9e74a 100644 --- a/src/test/java/org/polypheny/jdbc/ConnectionTest.java +++ b/src/test/java/org/polypheny/jdbc/ConnectionTest.java @@ -194,7 +194,7 @@ void testMetaDataGetProceduresNotStrict() throws SQLException { @Test @Disabled - // This test fails due to syntax definitions missing for some of the functions on the server side (operator registry). + // This test fails due to syntax definitions missing for some of the functions on the server side (operator registry). void testMetaDataGetFunctionsNotStrict() throws SQLException { try ( Connection con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ) ) { DatabaseMetaData meta = con.getMetaData(); diff --git a/src/test/java/org/polypheny/jdbc/Demo.java b/src/test/java/org/polypheny/jdbc/Demo.java index 4dfd3be..e796f68 100644 --- a/src/test/java/org/polypheny/jdbc/Demo.java +++ b/src/test/java/org/polypheny/jdbc/Demo.java @@ -40,46 +40,47 @@ public class Demo { private static String namespace = "public"; private static Connection con; - public static void main(String[] args) { + + public static void main( String[] args ) { try { - con = DriverManager.getConnection("jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", ""); - if (!con.isWrapperFor(PolyConnection.class)) { - System.out.println("Driver must support unwrapping to PolyConnection"); + con = DriverManager.getConnection( "jdbc:polypheny://127.0.0.1:20590?strict=false", "pa", "" ); + if ( !con.isWrapperFor( PolyConnection.class ) ) { + System.out.println( "Driver must support unwrapping to PolyConnection" ); return; } - Scanner scanner = new Scanner(System.in); + Scanner scanner = new Scanner( System.in ); - while (true) { + while ( true ) { printPrompt(); String input = scanner.nextLine(); - if (input.startsWith("lng ")) { - language = input.substring(4).trim(); - System.out.println("Language set to " + language); - } else if (input.startsWith("ns ")) { - namespace = input.substring(3).trim(); - System.out.println("Namespace set to " + namespace); - } else if (input.equals("exit")) { + if ( input.startsWith( "lng " ) ) { + language = input.substring( 4 ).trim(); + System.out.println( "Language set to " + language ); + } else if ( input.startsWith( "ns " ) ) { + namespace = input.substring( 3 ).trim(); + System.out.println( "Namespace set to " + namespace ); + } else if ( input.equals( "exit" ) ) { break; } else { - if (language == null || namespace == null) { - System.out.println("Please set both language and namespace before executing a statement."); + if ( language == null || namespace == null ) { + System.out.println( "Please set both language and namespace before executing a statement." ); continue; } String statement = input.trim(); - executeStatement(namespace, language, statement); + executeStatement( namespace, language, statement ); } } scanner.close(); - } catch (Exception e) { + } catch ( Exception e ) { e.printStackTrace(); } finally { try { - if (con != null && !con.isClosed()) { + if ( con != null && !con.isClosed() ) { con.close(); } - } catch (Exception e) { + } catch ( Exception e ) { e.printStackTrace(); } } diff --git a/src/test/java/org/polypheny/jdbc/QueryTest.java b/src/test/java/org/polypheny/jdbc/QueryTest.java index 1d334bd..09a6e00 100644 --- a/src/test/java/org/polypheny/jdbc/QueryTest.java +++ b/src/test/java/org/polypheny/jdbc/QueryTest.java @@ -35,7 +35,6 @@ import org.polypheny.jdbc.multimodel.Result.ResultType; import org.polypheny.jdbc.types.PolyDocument; import org.polypheny.jdbc.types.PolyGraphElement; -import org.polypheny.jdbc.types.PolyNode; public class QueryTest { @@ -117,6 +116,7 @@ public void mqlDataRetrievalTest() { } } + @Test public void simpleCypherNodesTest() { try ( Connection connection = TestHelper.getConnection() ) { @@ -128,8 +128,8 @@ public void simpleCypherNodesTest() { assertEquals( ResultType.GRAPH, result.getResultType() ); GraphResult graphResult = result.unwrap( GraphResult.class ); for ( PolyGraphElement element : graphResult ) { - element.get("name"); - element.get("year_joined"); + element.get( "name" ); + element.get( "year_joined" ); element.getLabels(); element.getId(); } @@ -138,6 +138,7 @@ public void simpleCypherNodesTest() { } } + @Test public void simpleCypherPropertyTest() { try ( Connection connection = TestHelper.getConnection() ) { @@ -151,11 +152,12 @@ public void simpleCypherPropertyTest() { assertEquals( ResultType.RELATIONAL, result.getResultType() ); RelationalResult relationalResult = result.unwrap( RelationalResult.class ); for ( PolyRow row : relationalResult ) { - row.get(0); - row.get("c.name"); + row.get( 0 ); + row.get( "c.name" ); } } catch ( SQLException e ) { throw new RuntimeException( e ); } } + } diff --git a/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java b/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java index e2dcbad..d192f36 100644 --- a/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java +++ b/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java @@ -942,7 +942,112 @@ void getLengthTest() throws SQLException { TypedValue typedValue2 = new TypedValue( protoValue ); assertEquals( value.length(), typedValue2.getLength() ); } + +<<<<<<< Conflict 1 of 1 ++++++++ Contents of side #1 + + @Test + void testFromBoolean() throws SQLException { + TypedValue value = TypedValue.fromBoolean( true ); + assertEquals( "1", value.asString() ); + } + + + @Test + void testFromByte() throws SQLException { + byte byteValue = 10; + TypedValue value = TypedValue.fromByte( byteValue ); + assertEquals( "10", value.asString() ); + } + + + @Test + void testFromShort() throws SQLException { + short shortValue = 20; + TypedValue value = TypedValue.fromShort( shortValue ); + assertEquals( "20", value.asString() ); + } + + + @Test + void testFromInteger() throws SQLException { + int intValue = 30; + TypedValue value = TypedValue.fromInteger( intValue ); + assertEquals( "30", value.asString() ); + } + + + @Test + void testFromLong() throws SQLException { + long longValue = 40L; + TypedValue value = TypedValue.fromLong( longValue ); + assertEquals( "40", value.asString() ); + } + + + @Test + void testFromFloat() throws SQLException { + float floatValue = 50.5f; + TypedValue value = TypedValue.fromFloat( floatValue ); + assertEquals( "50.5", value.asString() ); + } + + + @Test + void testFromDouble() throws SQLException { + double doubleValue = 60.6; + TypedValue value = TypedValue.fromDouble( doubleValue ); + assertEquals( "60.6", value.asString() ); + } + + + @Test + void testFromBigDecimal() throws SQLException { + BigDecimal bigDecimalValue = new BigDecimal( "70.7" ); + TypedValue value = TypedValue.fromBigDecimal( bigDecimalValue ); + assertEquals( "70.7", value.asString() ); + } + + + @Test + void testFromString() throws SQLException { + String stringValue = "test"; + TypedValue value = TypedValue.fromString( stringValue ); + assertEquals( "test", value.asString() ); + } + + + @Test + void testFromDate() throws SQLException { + Date dateValue = new Date( 2024, 7, 28 ); + TypedValue value = TypedValue.fromDate( dateValue ); + assertEquals( dateValue.toString(), value.asString() ); + } + + + @Test + void testFromTime() throws SQLException { + Time timeValue = new Time( System.currentTimeMillis() ); + TypedValue value = TypedValue.fromTime( timeValue ); + assertEquals( timeValue.toString(), value.asString() ); + } + + + @Test + void testFromTimestamp() throws SQLException { + Timestamp timestampValue = new Timestamp( System.currentTimeMillis() ); + TypedValue value = TypedValue.fromTimestamp( timestampValue ); + assertEquals( timestampValue.toString(), value.asString() ); + } + + + @Test + void testFromInterval() throws SQLException { + PolyInterval interval = new PolyInterval( 1, 0 ); + TypedValue value = TypedValue.fromInterval( interval ); + assertEquals( interval.toString(), value.asString() ); + } @Test void testFromBoolean() throws SQLException { From 3c0528c7dd5dc67acccf812ac4283f35b70366c7 Mon Sep 17 00:00:00 2001 From: Martin Vahlensieck Date: Fri, 4 Oct 2024 10:30:20 +0200 Subject: [PATCH 16/17] Fix fallout from rebase --- .../java/org/polypheny/jdbc/RpcService.java | 2 +- .../polypheny/jdbc/types/TypedValueTest.java | 104 ------------------ 2 files changed, 1 insertion(+), 105 deletions(-) diff --git a/src/main/java/org/polypheny/jdbc/RpcService.java b/src/main/java/org/polypheny/jdbc/RpcService.java index d5c421a..bdcec00 100644 --- a/src/main/java/org/polypheny/jdbc/RpcService.java +++ b/src/main/java/org/polypheny/jdbc/RpcService.java @@ -190,7 +190,7 @@ private void readResponses() { return; } /* For Windows */ - if ( e instanceof SocketException && e.getMessage().contains( "Connection reset" ) && disconnectSent ) { + if ( e instanceof SocketException && e.getMessage().contains( "Connection reset" ) && hasSentDisconnect ) { return; } // This will cause the exception to be thrown when the next call is made diff --git a/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java b/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java index d192f36..d090b63 100644 --- a/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java +++ b/src/test/java/org/polypheny/jdbc/types/TypedValueTest.java @@ -942,10 +942,7 @@ void getLengthTest() throws SQLException { TypedValue typedValue2 = new TypedValue( protoValue ); assertEquals( value.length(), typedValue2.getLength() ); } - -<<<<<<< Conflict 1 of 1 -+++++++ Contents of side #1 @Test void testFromBoolean() throws SQLException { @@ -1049,106 +1046,5 @@ void testFromInterval() throws SQLException { assertEquals( interval.toString(), value.asString() ); } - @Test - void testFromBoolean() throws SQLException { - TypedValue value = TypedValue.fromBoolean( true ); - assertEquals( "1", value.asString() ); - } - - - @Test - void testFromByte() throws SQLException { - byte byteValue = 10; - TypedValue value = TypedValue.fromByte( byteValue ); - assertEquals( "10", value.asString() ); - } - - - @Test - void testFromShort() throws SQLException { - short shortValue = 20; - TypedValue value = TypedValue.fromShort( shortValue ); - assertEquals( "20", value.asString() ); - } - - - @Test - void testFromInteger() throws SQLException { - int intValue = 30; - TypedValue value = TypedValue.fromInteger( intValue ); - assertEquals( "30", value.asString() ); - } - - - @Test - void testFromLong() throws SQLException { - long longValue = 40L; - TypedValue value = TypedValue.fromLong( longValue ); - assertEquals( "40", value.asString() ); - } - - - @Test - void testFromFloat() throws SQLException { - float floatValue = 50.5f; - TypedValue value = TypedValue.fromFloat( floatValue ); - assertEquals( "50.5", value.asString() ); - } - - - @Test - void testFromDouble() throws SQLException { - double doubleValue = 60.6; - TypedValue value = TypedValue.fromDouble( doubleValue ); - assertEquals( "60.6", value.asString() ); - } - - - @Test - void testFromBigDecimal() throws SQLException { - BigDecimal bigDecimalValue = new BigDecimal( "70.7" ); - TypedValue value = TypedValue.fromBigDecimal( bigDecimalValue ); - assertEquals( "70.7", value.asString() ); - } - - - @Test - void testFromString() throws SQLException { - String stringValue = "test"; - TypedValue value = TypedValue.fromString( stringValue ); - assertEquals( "test", value.asString() ); - } - - - @Test - void testFromDate() throws SQLException { - Date dateValue = new Date( 2024, 7, 28 ); - TypedValue value = TypedValue.fromDate( dateValue ); - assertEquals( dateValue.toString(), value.asString() ); - } - - - @Test - void testFromTime() throws SQLException { - Time timeValue = new Time( System.currentTimeMillis() ); - TypedValue value = TypedValue.fromTime( timeValue ); - assertEquals( timeValue.toString(), value.asString() ); - } - - - @Test - void testFromTimestamp() throws SQLException { - Timestamp timestampValue = new Timestamp( System.currentTimeMillis() ); - TypedValue value = TypedValue.fromTimestamp( timestampValue ); - assertEquals( timestampValue.toString(), value.asString() ); - } - - - @Test - void testFromInterval() throws SQLException { - PolyInterval interval = new PolyInterval( 1, 0 ); - TypedValue value = TypedValue.fromInterval( interval ); - assertEquals( interval.toString(), value.asString() ); - } } From 9b5af76bb5cd18e4256fe921121ab4f572a02d97 Mon Sep 17 00:00:00 2001 From: Martin Vahlensieck Date: Fri, 4 Oct 2024 10:30:20 +0200 Subject: [PATCH 17/17] Adapt to new API files --- .../jdbc/multimodel/GraphResult.java | 16 +--------- .../org/polypheny/jdbc/types/PolyEdge.java | 16 ++++------ .../jdbc/types/PolyGraphElement.java | 14 ++++++++- .../org/polypheny/jdbc/types/PolyNode.java | 7 +---- .../org/polypheny/jdbc/types/PolyPath.java | 29 ------------------- 5 files changed, 20 insertions(+), 62 deletions(-) delete mode 100644 src/main/java/org/polypheny/jdbc/types/PolyPath.java diff --git a/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java index f9848d9..1e20423 100644 --- a/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java +++ b/src/main/java/org/polypheny/jdbc/multimodel/GraphResult.java @@ -25,10 +25,7 @@ import org.polypheny.jdbc.PrismInterfaceErrors; import org.polypheny.jdbc.PrismInterfaceServiceException; import org.polypheny.jdbc.properties.PropertyUtils; -import org.polypheny.jdbc.types.PolyEdge; import org.polypheny.jdbc.types.PolyGraphElement; -import org.polypheny.jdbc.types.PolyNode; -import org.polypheny.jdbc.types.PolyPath; import org.polypheny.prism.Frame; import org.polypheny.prism.Frame.ResultCase; import org.polypheny.prism.GraphFrame; @@ -50,17 +47,7 @@ public GraphResult( Frame frame, PolyStatement polyStatement ) { private void addGraphElements( GraphFrame graphFrame ) { - if ( graphFrame.getNodesCount() > 0 ) { - graphFrame.getNodesList().forEach( n -> elements.add( new PolyNode( n ) ) ); - return; - } - if ( graphFrame.getEdgesCount() > 0 ) { - graphFrame.getEdgesList().forEach( n -> elements.add( new PolyEdge( n ) ) ); - return; - } - if ( graphFrame.getPathsCount() > 0 ) { - graphFrame.getPathsList().forEach( n -> elements.add( new PolyPath( n ) ) ); - } + graphFrame.getElementList().forEach( n -> elements.add( PolyGraphElement.of( n ) ) ); } @@ -126,5 +113,4 @@ public PolyGraphElement next() { } - } diff --git a/src/main/java/org/polypheny/jdbc/types/PolyEdge.java b/src/main/java/org/polypheny/jdbc/types/PolyEdge.java index 92ac758..5716e7e 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyEdge.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyEdge.java @@ -18,13 +18,12 @@ import lombok.Getter; import org.polypheny.prism.ProtoEdge; -import org.polypheny.prism.ProtoValue.ValueCase; @Getter public class PolyEdge extends PolyGraphElement { - private final String source; - private final String target; + private final String left; + private final String right; private final EdgeDirection direction; @@ -33,14 +32,9 @@ public PolyEdge( ProtoEdge protoEdge ) { this.id = protoEdge.getId(); this.name = protoEdge.getName(); this.labels = protoEdge.getLabelsList(); - protoEdge.getPropertiesList().stream() - .filter( e -> e.getKey().getValueCase() == ValueCase.STRING ) - .forEach( p -> put( - p.getKey().getString().getString(), - new TypedValue( p.getValue() ) - ) ); - this.source = protoEdge.getSource(); - this.target = protoEdge.getTarget(); + protoEdge.getPropertiesMap().forEach( ( k, v ) -> put( k, new TypedValue( v ) ) ); + this.left = protoEdge.getSource(); + this.right = protoEdge.getTarget(); this.direction = EdgeDirection.valueOf( protoEdge.getDirection().name() ); } diff --git a/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java index 1c9df69..2e1de89 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyGraphElement.java @@ -22,9 +22,10 @@ import lombok.Getter; import org.polypheny.jdbc.PrismInterfaceErrors; import org.polypheny.jdbc.PrismInterfaceServiceException; +import org.polypheny.prism.GraphElement; @Getter -public class PolyGraphElement extends HashMap { +public abstract class PolyGraphElement extends HashMap { protected String id; protected String name; @@ -39,4 +40,15 @@ public T unwrap( Class aClass ) throws PrismInterfaceServiceException { } + public static PolyGraphElement of( GraphElement element ) { + switch ( element.getElementCase() ) { + case NODE: + return new PolyNode( element.getNode() ); + case EDGE: + return new PolyEdge( element.getEdge() ); + default: + throw new RuntimeException( "Unknown graph element of type " + element.getElementCase() ); + } + } + } diff --git a/src/main/java/org/polypheny/jdbc/types/PolyNode.java b/src/main/java/org/polypheny/jdbc/types/PolyNode.java index 7172cdc..5fc9e9c 100644 --- a/src/main/java/org/polypheny/jdbc/types/PolyNode.java +++ b/src/main/java/org/polypheny/jdbc/types/PolyNode.java @@ -27,12 +27,7 @@ public PolyNode( ProtoNode protoNode ) { this.id = protoNode.getId(); this.name = protoNode.getName(); this.labels = protoNode.getLabelsList(); - protoNode.getPropertiesList().stream() - .filter( e -> e.getKey().getValueCase() == ValueCase.STRING ) - .forEach( p -> put( - p.getKey().getString().getString(), - new TypedValue( p.getValue() ) - ) ); + protoNode.getPropertiesMap().forEach( ( k, v ) -> put( k, new TypedValue( v ) ) ); } } diff --git a/src/main/java/org/polypheny/jdbc/types/PolyPath.java b/src/main/java/org/polypheny/jdbc/types/PolyPath.java deleted file mode 100644 index 2b1fb8c..0000000 --- a/src/main/java/org/polypheny/jdbc/types/PolyPath.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2019-2024 The Polypheny Project - * - * Licensed 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.polypheny.jdbc.types; - -import org.apache.commons.lang3.NotImplementedException; -import org.polypheny.prism.ProtoPath; - -public class PolyPath extends PolyGraphElement { - - public PolyPath( ProtoPath protoPath ) { - // TODO: implementation - throw new NotImplementedException(); - } - -}