diff --git a/sql/api/src/main/java/org/apache/spark/sql/types/Geography.java b/sql/api/src/main/java/org/apache/spark/sql/types/Geography.java new file mode 100644 index 000000000000..e99902336ffe --- /dev/null +++ b/sql/api/src/main/java/org/apache/spark/sql/types/Geography.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.spark.sql.types; + +import java.io.Serializable; +import java.util.Arrays; + +// This class represents the Geography data for clients. +public final class Geography implements Serializable { + // The GEOGRAPHY type is implemented as WKB bytes + SRID integer stored in class itself. + protected final byte[] value; + + protected final int srid; + + // We make the constructor private. We should use `fromWKB` to create new instances. + private Geography(byte[] value, int srid) { + this.value = value; + this.srid = srid; + } + + // We provide `getBytes` and `fromBytes` methods to access GEOGRAPHY data. + + public byte[] getBytes() { + return value; + } + + public int getSrid() { + return srid; + } + + // Default SRID value for the Geography client class. + public static final int DEFAULT_SRID = 4326; + + // Factory methods to create new Geography instances from WKB bytes and optional SRID. + + public static Geography fromWKB(byte[] bytes, int srid) { + return new Geography(bytes, srid); + } + + public static Geography fromWKB(byte[] bytes) { + return new Geography(bytes, DEFAULT_SRID); + } + + // Overrides for `equals` and `hashCode` methods. + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Geography other = (Geography) obj; + return srid == other.srid && java.util.Arrays.equals(value, other.value); + } + + @Override + public int hashCode() { + return 31 * Arrays.hashCode(value) + Integer.hashCode(srid); + } +} diff --git a/sql/api/src/main/java/org/apache/spark/sql/types/Geometry.java b/sql/api/src/main/java/org/apache/spark/sql/types/Geometry.java new file mode 100644 index 000000000000..3974aec131d0 --- /dev/null +++ b/sql/api/src/main/java/org/apache/spark/sql/types/Geometry.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.spark.sql.types; + +import java.io.Serializable; +import java.util.Arrays; + +// This class represents the Geometry data for clients. +public final class Geometry implements Serializable { + // The GEOMETRY type is implemented as WKB bytes + SRID integer stored in class itself. + protected final byte[] value; + + protected final int srid; + + // We make the constructor private. We should use `fromWKB` to create new instances. + private Geometry(byte[] value, int srid) { + this.value = value; + this.srid = srid; + } + + // We provide `getBytes` and `fromBytes` methods to access GEOMETRY data. + + public byte[] getBytes() { + return value; + } + + public int getSrid() { + return srid; + } + + // Default SRID value for the Geometry client class. + public static final int DEFAULT_SRID = 0; + + // Factory methods to create new Geometry instances from WKB bytes and optional SRID. + + public static Geometry fromWKB(byte[] bytes, int srid) { + return new Geometry(bytes, srid); + } + + public static Geometry fromWKB(byte[] bytes) { + return new Geometry(bytes, DEFAULT_SRID); + } + + // Overrides for `equals` and `hashCode` methods. + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Geometry other = (Geometry) obj; + return srid == other.srid && java.util.Arrays.equals(value, other.value); + } + + @Override + public int hashCode() { + return 31 * Arrays.hashCode(value) + Integer.hashCode(srid); + } +} diff --git a/sql/core/src/test/java/org/apache/spark/sql/types/GeographyClientSuite.java b/sql/core/src/test/java/org/apache/spark/sql/types/GeographyClientSuite.java new file mode 100644 index 000000000000..24fd246f56c6 --- /dev/null +++ b/sql/core/src/test/java/org/apache/spark/sql/types/GeographyClientSuite.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.spark.sql.types; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + + +/** + * Test suite for the Geography client-side class. + */ +class GeographyClientSuite { + + // A sample Geography WKB array for testing purposes, representing a POINT(1 2). + private final byte[] testGeographyWkb = new byte[] { 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, (byte)0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 }; + private final int testGeographySrid = 4326; + + /** Tests for Geography factory methods and getters. */ + + @Test + void testFromWkb() { + Geography geography = Geography.fromWKB(testGeographyWkb); + assertNotNull(geography); + assertArrayEquals(testGeographyWkb, geography.getBytes()); + assertEquals(Geography.DEFAULT_SRID, geography.getSrid()); + } + + @Test + void testFromWkbSrid() { + Geography geography = Geography.fromWKB(testGeographyWkb, testGeographySrid); + assertNotNull(geography); + assertArrayEquals(testGeographyWkb, geography.getBytes()); + assertEquals(testGeographySrid, geography.getSrid()); + } + + /** Tests for Geography constants. */ + + @Test + void testDefaultSrid() { + assertEquals(4326, Geography.DEFAULT_SRID); + } + + /** Tests for other Geography methods. */ + + @Test + void testEquals() { + Geography geography1 = Geography.fromWKB(testGeographyWkb); + Geography geography2 = Geography.fromWKB(testGeographyWkb); + Geography geography3 = Geography.fromWKB(testGeographyWkb, 1); + assertNotEquals(geography1, null); + assertNotEquals(geography2, null); + assertNotEquals(geography3, null); + assertEquals(geography1, geography2); + assertNotEquals(geography1, geography3); + assertNotEquals(geography2, geography3); + } + + @Test + void testHashCode() { + Geography geography1 = Geography.fromWKB(testGeographyWkb); + Geography geography2 = Geography.fromWKB(testGeographyWkb, testGeographySrid); + int wkbHash = Arrays.hashCode(testGeographyWkb); + assertEquals(31 * wkbHash + Integer.hashCode(Geography.DEFAULT_SRID), geography1.hashCode()); + assertEquals(31 * wkbHash + Integer.hashCode(testGeographySrid), geography2.hashCode()); + } + +} diff --git a/sql/core/src/test/java/org/apache/spark/sql/types/GeometryClientSuite.java b/sql/core/src/test/java/org/apache/spark/sql/types/GeometryClientSuite.java new file mode 100644 index 000000000000..5dd527b220b5 --- /dev/null +++ b/sql/core/src/test/java/org/apache/spark/sql/types/GeometryClientSuite.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.spark.sql.types; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + + +/** + * Test suite for the Geometry client-side class. + */ +class GeometryClientSuite { + + // A sample Geometry WKB array for testing purposes, representing a POINT(1 2). + private final byte[] testGeometryWkb = new byte[] { 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, (byte)0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 }; + private final int testGeometrySrid = 4326; + + /** Tests for Geometry factory methods and getters. */ + + @Test + void testFromWkb() { + Geometry geometry = Geometry.fromWKB(testGeometryWkb); + assertNotNull(geometry); + assertArrayEquals(testGeometryWkb, geometry.getBytes()); + assertEquals(Geometry.DEFAULT_SRID, geometry.getSrid()); + } + + @Test + void testFromWkbSrid() { + Geometry geometry = Geometry.fromWKB(testGeometryWkb, testGeometrySrid); + assertNotNull(geometry); + assertArrayEquals(testGeometryWkb, geometry.getBytes()); + assertEquals(testGeometrySrid, geometry.getSrid()); + } + + /** Tests for Geometry constants. */ + + @Test + void testDefaultSrid() { + assertEquals(0, Geometry.DEFAULT_SRID); + } + + /** Tests for other Geometry methods. */ + + @Test + void testEquals() { + Geometry geometry1 = Geometry.fromWKB(testGeometryWkb); + Geometry geometry2 = Geometry.fromWKB(testGeometryWkb); + Geometry geometry3 = Geometry.fromWKB(testGeometryWkb, 1); + assertNotEquals(geometry1, null); + assertNotEquals(geometry2, null); + assertNotEquals(geometry3, null); + assertEquals(geometry1, geometry2); + assertNotEquals(geometry1, geometry3); + assertNotEquals(geometry2, geometry3); + } + + @Test + void testHashCode() { + Geometry geometry1 = Geometry.fromWKB(testGeometryWkb); + Geometry geometry2 = Geometry.fromWKB(testGeometryWkb, testGeometrySrid); + int wkbHash = Arrays.hashCode(testGeometryWkb); + assertEquals(31 * wkbHash + Integer.hashCode(Geometry.DEFAULT_SRID), geometry1.hashCode()); + assertEquals(31 * wkbHash + Integer.hashCode(testGeometrySrid), geometry2.hashCode()); + } + +}