|
17 | 17 |
|
18 | 18 | #include "parquet/geospatial/util_json_internal.h" |
19 | 19 |
|
| 20 | +#include <simdjson/minify.h> |
20 | 21 | #include <string> |
21 | 22 |
|
22 | 23 | #include "arrow/extension_type.h" |
@@ -57,62 +58,80 @@ ::arrow::Result<std::string> GeospatialGeoArrowCrsToParquetCrs( |
57 | 58 | // longitude/latitude in WGS84 according to the Parquet specification |
58 | 59 | return ""; |
59 | 60 | } |
60 | | - } else if (auto crs_object = |
61 | | - ::arrow::internal::GetJsonAs<simdjson::ondemand::object>(json_crs); |
62 | | - crs_object.ok()) { |
63 | | - // Attempt to detect common PROJJSON representations of longitude/latitude and return |
64 | | - // an empty crs to maximize compatibility with readers that do not implement CRS |
65 | | - // support. PROJJSON stores this in the "id" member like: |
66 | | - // {..., "id": {"authority": "...", "code": "..."}} |
67 | | - auto id_field = (*crs_object)["id"]; |
68 | | - |
69 | | - if (id_field.error() != simdjson::NO_SUCH_FIELD) { |
70 | | - ARROW_ASSIGN_OR_RAISE(auto identifier, ::arrow::internal::GetSimdjsonResult( |
71 | | - id_field, "Failed to get 'id' field: ")); |
72 | | - |
73 | | - auto authority_field = identifier["authority"]; |
74 | | - auto code_field = identifier["code"]; |
75 | | - |
76 | | - if (authority_field.error() != simdjson::NO_SUCH_FIELD && |
77 | | - code_field.error() != simdjson::NO_SUCH_FIELD) { |
78 | | - ARROW_ASSIGN_OR_RAISE(auto authority, |
79 | | - ::arrow::internal::GetSimdjsonResult( |
80 | | - authority_field, "Failed to get 'authority' field: ")); |
81 | | - |
82 | | - ARROW_ASSIGN_OR_RAISE(auto code, ::arrow::internal::GetSimdjsonResult( |
83 | | - code_field, "Failed to get 'code' field: ")); |
84 | | - |
85 | | - ARROW_ASSIGN_OR_RAISE(auto authority_string, |
86 | | - ::arrow::internal::GetJsonAs<std::string_view>(authority)); |
87 | | - |
88 | | - auto code_string = ::arrow::internal::GetJsonAs<std::string_view>(code); |
89 | | - |
90 | | - if (code_string.ok()) { |
91 | | - if ((authority_string == "OGC" && *code_string == "CRS84") || |
92 | | - (authority_string == "EPSG" && *code_string == "4326")) { |
93 | | - return ""; |
94 | | - } |
95 | | - } else if (authority_string == "EPSG") { |
96 | | - auto code_int = ::arrow::internal::GetJsonAs<int64_t>(code); |
97 | | - |
98 | | - if (code_int.ok() && *code_int == 4326) { |
99 | | - return ""; |
100 | | - } |
| 61 | + |
| 62 | + // If we could not detect a longitude/latitude CRS, just write the string to the |
| 63 | + // LogicalType crs (being sure to unescape a JSON string into a regular string) |
| 64 | + return std::string(*string); |
| 65 | + } |
| 66 | + |
| 67 | + ARROW_ASSIGN_OR_RAISE( |
| 68 | + auto crs_object, |
| 69 | + ::arrow::internal::GetJsonAs<simdjson::ondemand::object>(json_crs)); |
| 70 | + |
| 71 | + // Attempt to detect common PROJJSON representations of longitude/latitude and return |
| 72 | + // an empty crs to maximize compatibility with readers that do not implement CRS |
| 73 | + // support. PROJJSON stores this in the "id" member like: |
| 74 | + // {..., "id": {"authority": "...", "code": "..."}} |
| 75 | + auto id_field = crs_object["id"]; |
| 76 | + |
| 77 | + if (id_field.error() != simdjson::NO_SUCH_FIELD) { |
| 78 | + ARROW_ASSIGN_OR_RAISE(auto identifier, ::arrow::internal::GetSimdjsonResult( |
| 79 | + id_field, "Failed to get 'id' field: ")); |
| 80 | + |
| 81 | + auto authority_field = identifier["authority"]; |
| 82 | + auto code_field = identifier["code"]; |
| 83 | + |
| 84 | + if (authority_field.error() != simdjson::NO_SUCH_FIELD && |
| 85 | + code_field.error() != simdjson::NO_SUCH_FIELD) { |
| 86 | + ARROW_ASSIGN_OR_RAISE(auto authority, |
| 87 | + ::arrow::internal::GetSimdjsonResult( |
| 88 | + authority_field, "Failed to get 'authority' field: ")); |
| 89 | + |
| 90 | + ARROW_ASSIGN_OR_RAISE(auto code, ::arrow::internal::GetSimdjsonResult( |
| 91 | + code_field, "Failed to get 'code' field: ")); |
| 92 | + |
| 93 | + ARROW_ASSIGN_OR_RAISE(auto authority_string, |
| 94 | + ::arrow::internal::GetJsonAs<std::string_view>(authority)); |
| 95 | + |
| 96 | + auto code_string = ::arrow::internal::GetJsonAs<std::string_view>(code); |
| 97 | + |
| 98 | + if (code_string.ok()) { |
| 99 | + if ((authority_string == "OGC" && *code_string == "CRS84") || |
| 100 | + (authority_string == "EPSG" && *code_string == "4326")) { |
| 101 | + return ""; |
| 102 | + } |
| 103 | + } else if (authority_string == "EPSG") { |
| 104 | + auto code_int = ::arrow::internal::GetJsonAs<int64_t>(code); |
| 105 | + |
| 106 | + if (code_int.ok() && *code_int == 4326) { |
| 107 | + return ""; |
101 | 108 | } |
102 | 109 | } |
103 | 110 | } |
104 | 111 | } |
105 | 112 |
|
106 | 113 | // If we could not detect a longitude/latitude CRS, just write the string to the |
107 | 114 | // LogicalType crs (being sure to unescape a JSON string into a regular string) |
108 | | - auto string = ::arrow::internal::GetJsonAs<std::string_view>(json_crs); |
109 | | - if (string.ok()) { |
110 | | - return std::string(*string); |
| 115 | + RETURN_NOT_OK(::arrow::internal::GetSimdjsonResult(crs_object.reset(), |
| 116 | + "Failed to reset 'crs' object: ") |
| 117 | + .status()); |
| 118 | + |
| 119 | + ARROW_ASSIGN_OR_RAISE(auto raw_crs, |
| 120 | + ::arrow::internal::GetSimdjsonResult( |
| 121 | + crs_object.raw_json(), "Failed to get raw 'crs' JSON: ")); |
| 122 | + |
| 123 | + std::string minified(raw_crs.size(), '\0'); |
| 124 | + size_t minified_len = 0; |
| 125 | + |
| 126 | + if (auto error = |
| 127 | + simdjson::minify(raw_crs.data(), raw_crs.size(), minified.data(), minified_len); |
| 128 | + error != simdjson::SUCCESS) { |
| 129 | + return ::arrow::Status::Invalid("Failed to minify CRS JSON: ", |
| 130 | + simdjson::error_message(error)); |
111 | 131 | } |
112 | 132 |
|
113 | | - ::arrow::json::JsonWriter writer; |
114 | | - RETURN_NOT_OK(writer.WriteValue(json_crs)); |
115 | | - return std::string(writer.GetString().ValueUnsafe()); |
| 133 | + minified.resize(minified_len); |
| 134 | + return minified; |
116 | 135 | } |
117 | 136 |
|
118 | 137 | // Utility for ensuring that a Parquet CRS is valid JSON when written to |
|
0 commit comments