Skip to content

Commit 270af67

Browse files
committed
Preserve GeoArrow CRS JSON formatting
1 parent 0230946 commit 270af67

1 file changed

Lines changed: 66 additions & 47 deletions

File tree

‎cpp/src/parquet/geospatial/util_json_internal.cc‎

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "parquet/geospatial/util_json_internal.h"
1919

20+
#include <simdjson/minify.h>
2021
#include <string>
2122

2223
#include "arrow/extension_type.h"
@@ -57,62 +58,80 @@ ::arrow::Result<std::string> GeospatialGeoArrowCrsToParquetCrs(
5758
// longitude/latitude in WGS84 according to the Parquet specification
5859
return "";
5960
}
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 "";
101108
}
102109
}
103110
}
104111
}
105112

106113
// If we could not detect a longitude/latitude CRS, just write the string to the
107114
// 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));
111131
}
112132

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;
116135
}
117136

118137
// Utility for ensuring that a Parquet CRS is valid JSON when written to

0 commit comments

Comments
 (0)