|
41 | 41 | import java.util.Set; |
42 | 42 | import java.util.function.Supplier; |
43 | 43 | import org.apache.parquet.Preconditions; |
| 44 | +import org.apache.parquet.column.schema.EdgeInterpolationAlgorithm; |
44 | 45 |
|
45 | 46 | public abstract class LogicalTypeAnnotation { |
| 47 | + |
| 48 | + public static final String DEFAULT_CRS = "OGC:CRS84"; |
| 49 | + public static final EdgeInterpolationAlgorithm DEFAULT_ALGO = EdgeInterpolationAlgorithm.SPHERICAL; |
| 50 | + |
46 | 51 | enum LogicalTypeToken { |
47 | 52 | MAP { |
48 | 53 | @Override |
@@ -155,6 +160,31 @@ protected LogicalTypeAnnotation fromString(List<String> params) { |
155 | 160 | return float16Type(); |
156 | 161 | } |
157 | 162 | }, |
| 163 | + GEOMETRY { |
| 164 | + @Override |
| 165 | + protected LogicalTypeAnnotation fromString(List<String> params) { |
| 166 | + if (params.size() > 1) { |
| 167 | + throw new RuntimeException( |
| 168 | + "Expecting at most 1 parameter for geometry logical type, got " + params.size()); |
| 169 | + } |
| 170 | + String crs = params.isEmpty() ? null : params.get(0); |
| 171 | + return geometryType(crs); |
| 172 | + } |
| 173 | + }, |
| 174 | + GEOGRAPHY { |
| 175 | + @Override |
| 176 | + protected LogicalTypeAnnotation fromString(List<String> params) { |
| 177 | + if (params.size() > 2) { |
| 178 | + throw new RuntimeException( |
| 179 | + "Expecting at most 2 parameters for geography logical type (crs and edge algorithm), got " |
| 180 | + + params.size()); |
| 181 | + } |
| 182 | + String crs = !params.isEmpty() ? params.get(0) : null; |
| 183 | + EdgeInterpolationAlgorithm algo = |
| 184 | + params.size() > 1 ? EdgeInterpolationAlgorithm.valueOf(params.get(1)) : null; |
| 185 | + return geographyType(crs, algo); |
| 186 | + } |
| 187 | + }, |
158 | 188 | UNKNOWN { |
159 | 189 | @Override |
160 | 190 | protected LogicalTypeAnnotation fromString(List<String> params) { |
@@ -334,6 +364,18 @@ public static Float16LogicalTypeAnnotation float16Type() { |
334 | 364 | return Float16LogicalTypeAnnotation.INSTANCE; |
335 | 365 | } |
336 | 366 |
|
| 367 | + public static GeometryLogicalTypeAnnotation geometryType(String crs) { |
| 368 | + return new GeometryLogicalTypeAnnotation(crs); |
| 369 | + } |
| 370 | + |
| 371 | + public static GeographyLogicalTypeAnnotation geographyType(String crs, EdgeInterpolationAlgorithm edgeAlgorithm) { |
| 372 | + return new GeographyLogicalTypeAnnotation(crs, edgeAlgorithm); |
| 373 | + } |
| 374 | + |
| 375 | + public static GeographyLogicalTypeAnnotation geographyType() { |
| 376 | + return new GeographyLogicalTypeAnnotation(null, null); |
| 377 | + } |
| 378 | + |
337 | 379 | public static UnknownLogicalTypeAnnotation unknownType() { |
338 | 380 | return UnknownLogicalTypeAnnotation.INSTANCE; |
339 | 381 | } |
@@ -1183,6 +1225,124 @@ public boolean equals(Object obj) { |
1183 | 1225 | } |
1184 | 1226 | } |
1185 | 1227 |
|
| 1228 | + public static class GeometryLogicalTypeAnnotation extends LogicalTypeAnnotation { |
| 1229 | + private final String crs; |
| 1230 | + |
| 1231 | + private GeometryLogicalTypeAnnotation(String crs) { |
| 1232 | + this.crs = crs; |
| 1233 | + } |
| 1234 | + |
| 1235 | + @Override |
| 1236 | + @Deprecated |
| 1237 | + public OriginalType toOriginalType() { |
| 1238 | + return null; |
| 1239 | + } |
| 1240 | + |
| 1241 | + @Override |
| 1242 | + public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) { |
| 1243 | + return logicalTypeAnnotationVisitor.visit(this); |
| 1244 | + } |
| 1245 | + |
| 1246 | + @Override |
| 1247 | + LogicalTypeToken getType() { |
| 1248 | + return LogicalTypeToken.GEOMETRY; |
| 1249 | + } |
| 1250 | + |
| 1251 | + @Override |
| 1252 | + protected String typeParametersAsString() { |
| 1253 | + if (crs == null || crs.isEmpty()) { |
| 1254 | + return ""; |
| 1255 | + } |
| 1256 | + return String.format("(%s)", crs); |
| 1257 | + } |
| 1258 | + |
| 1259 | + public String getCrs() { |
| 1260 | + return crs; |
| 1261 | + } |
| 1262 | + |
| 1263 | + @Override |
| 1264 | + public boolean equals(Object obj) { |
| 1265 | + if (!(obj instanceof GeometryLogicalTypeAnnotation)) { |
| 1266 | + return false; |
| 1267 | + } |
| 1268 | + GeometryLogicalTypeAnnotation other = (GeometryLogicalTypeAnnotation) obj; |
| 1269 | + return Objects.equals(crs, other.crs); |
| 1270 | + } |
| 1271 | + |
| 1272 | + @Override |
| 1273 | + public int hashCode() { |
| 1274 | + return Objects.hash(crs); |
| 1275 | + } |
| 1276 | + |
| 1277 | + @Override |
| 1278 | + PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) { |
| 1279 | + return PrimitiveStringifier.WKB_STRINGIFIER; |
| 1280 | + } |
| 1281 | + } |
| 1282 | + |
| 1283 | + public static class GeographyLogicalTypeAnnotation extends LogicalTypeAnnotation { |
| 1284 | + private final String crs; |
| 1285 | + private final EdgeInterpolationAlgorithm algorithm; |
| 1286 | + |
| 1287 | + private GeographyLogicalTypeAnnotation(String crs, EdgeInterpolationAlgorithm algorithm) { |
| 1288 | + this.crs = crs; |
| 1289 | + this.algorithm = algorithm; |
| 1290 | + } |
| 1291 | + |
| 1292 | + @Override |
| 1293 | + @Deprecated |
| 1294 | + public OriginalType toOriginalType() { |
| 1295 | + return null; |
| 1296 | + } |
| 1297 | + |
| 1298 | + @Override |
| 1299 | + public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) { |
| 1300 | + return logicalTypeAnnotationVisitor.visit(this); |
| 1301 | + } |
| 1302 | + |
| 1303 | + @Override |
| 1304 | + LogicalTypeToken getType() { |
| 1305 | + return LogicalTypeToken.GEOGRAPHY; |
| 1306 | + } |
| 1307 | + |
| 1308 | + @Override |
| 1309 | + protected String typeParametersAsString() { |
| 1310 | + boolean hasCrs = crs != null && !crs.isEmpty(); |
| 1311 | + boolean hasAlgo = algorithm != null; |
| 1312 | + if (!hasCrs && !hasAlgo) { |
| 1313 | + return ""; |
| 1314 | + } |
| 1315 | + return String.format("(%s,%s)", hasCrs ? crs : DEFAULT_CRS, hasAlgo ? algorithm : DEFAULT_ALGO); |
| 1316 | + } |
| 1317 | + |
| 1318 | + public String getCrs() { |
| 1319 | + return crs; |
| 1320 | + } |
| 1321 | + |
| 1322 | + public EdgeInterpolationAlgorithm getAlgorithm() { |
| 1323 | + return algorithm; |
| 1324 | + } |
| 1325 | + |
| 1326 | + @Override |
| 1327 | + public boolean equals(Object obj) { |
| 1328 | + if (!(obj instanceof GeographyLogicalTypeAnnotation)) { |
| 1329 | + return false; |
| 1330 | + } |
| 1331 | + GeographyLogicalTypeAnnotation other = (GeographyLogicalTypeAnnotation) obj; |
| 1332 | + return Objects.equals(crs, other.crs) && Objects.equals(algorithm, other.algorithm); |
| 1333 | + } |
| 1334 | + |
| 1335 | + @Override |
| 1336 | + public int hashCode() { |
| 1337 | + return Objects.hash(crs, algorithm); |
| 1338 | + } |
| 1339 | + |
| 1340 | + @Override |
| 1341 | + PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) { |
| 1342 | + return PrimitiveStringifier.WKB_STRINGIFIER; |
| 1343 | + } |
| 1344 | + } |
| 1345 | + |
1186 | 1346 | /** |
1187 | 1347 | * Implement this interface to visit a logical type annotation in the schema. |
1188 | 1348 | * The default implementation for each logical type specific visitor method is empty. |
@@ -1259,6 +1419,14 @@ default Optional<T> visit(Float16LogicalTypeAnnotation float16LogicalType) { |
1259 | 1419 | return empty(); |
1260 | 1420 | } |
1261 | 1421 |
|
| 1422 | + default Optional<T> visit(GeometryLogicalTypeAnnotation geometryLogicalType) { |
| 1423 | + return empty(); |
| 1424 | + } |
| 1425 | + |
| 1426 | + default Optional<T> visit(GeographyLogicalTypeAnnotation geographyLogicalType) { |
| 1427 | + return empty(); |
| 1428 | + } |
| 1429 | + |
1262 | 1430 | default Optional<T> visit(UnknownLogicalTypeAnnotation unknownLogicalTypeAnnotation) { |
1263 | 1431 | return empty(); |
1264 | 1432 | } |
|
0 commit comments