@@ -21,6 +21,8 @@ namespace arrow::json {
2121
2222namespace sj = simdjson::ondemand;
2323
24+ JsonWriter::JsonWriter () = default ;
25+
2426void JsonWriter::StartObject () {
2527 MaybeComma ();
2628 builder_.start_object ();
@@ -218,3 +220,207 @@ void JsonWriter::BoolField(std::string_view key, bool value) {
218220}
219221
220222} // namespace arrow::json
223+
224+ namespace arrow ::internal {
225+
226+ const char * JsonTypeName (simdjson::dom::element_type type) {
227+ switch (type) {
228+ case simdjson::dom::element_type::ARRAY :
229+ return " array" ;
230+ case simdjson::dom::element_type::OBJECT :
231+ return " object" ;
232+ case simdjson::dom::element_type::INT64 :
233+ case simdjson::dom::element_type::UINT64 :
234+ case simdjson::dom::element_type::DOUBLE :
235+ return " number" ;
236+ case simdjson::dom::element_type::STRING :
237+ return " string" ;
238+ case simdjson::dom::element_type::BOOL :
239+ return " boolean" ;
240+ case simdjson::dom::element_type::NULL_VALUE :
241+ return " null" ;
242+ default :
243+ return " unknown" ;
244+ }
245+ }
246+
247+ Result<simdjson::dom::array> GetJsonArray (simdjson::dom::element value,
248+ std::string_view name) {
249+ if (!value.is_array ()) {
250+ return Status::Invalid (name, " must be an array, got " , JsonTypeName (value.type ()));
251+ }
252+ return ResolveSimdjsonResult (value.get_array (), " Failed to get JSON array" );
253+ }
254+
255+ Result<int64_t > GetJsonInt (simdjson::dom::element value, std::string_view name,
256+ std::string_view expected) {
257+ if (!value.is_int64 ()) {
258+ return Status::Invalid (name, " must contain " , expected, " , got " ,
259+ JsonTypeName (value.type ()));
260+ }
261+ return ResolveSimdjsonResult (value.get_int64 (), " Failed to get JSON integer" );
262+ }
263+
264+ Result<simdjson::dom::object> ParseJsonObject (simdjson::dom::parser& parser,
265+ const std::string& json) {
266+ return ResolveSimdjsonResult (parser.parse (json).get_object (),
267+ " Invalid serialized JSON data" );
268+ }
269+
270+ Result<std::optional<simdjson::dom::element>> GetOptionalJsonField (
271+ const simdjson::dom::object& object, std::string_view key) {
272+ auto field = object.at_key (key);
273+ if (field.error () == simdjson::NO_SUCH_FIELD ) {
274+ return std::nullopt ;
275+ }
276+
277+ ARROW_ASSIGN_OR_RAISE (
278+ auto value,
279+ ResolveSimdjsonResult (std::move (field), " Failed to get JSON object field" ));
280+
281+ return std::optional<simdjson::dom::element>(std::move (value));
282+ }
283+
284+ Result<std::vector<int64_t >> GetJsonIntArray (simdjson::dom::element value,
285+ std::string_view name) {
286+ ARROW_ASSIGN_OR_RAISE (auto array, GetJsonArray (value, name));
287+
288+ std::vector<int64_t > result;
289+ result.reserve (array.size ());
290+
291+ for (auto element : array) {
292+ ARROW_ASSIGN_OR_RAISE (auto number, GetJsonInt (element, name, " integers" ));
293+ result.push_back (number);
294+ }
295+
296+ return result;
297+ }
298+
299+ Result<std::vector<std::optional<int64_t >>> GetJsonNullableIntArray (
300+ simdjson::dom::element value, std::string_view name) {
301+ ARROW_ASSIGN_OR_RAISE (auto array, GetJsonArray (value, name));
302+
303+ std::vector<std::optional<int64_t >> result;
304+ result.reserve (array.size ());
305+
306+ for (auto element : array) {
307+ if (element.is_null ()) {
308+ result.emplace_back (std::nullopt );
309+ } else {
310+ ARROW_ASSIGN_OR_RAISE (auto number, GetJsonInt (element, name, " integers or nulls" ));
311+ result.emplace_back (number);
312+ }
313+ }
314+
315+ return result;
316+ }
317+
318+ Result<std::vector<std::string>> GetJsonStringArray (simdjson::dom::element value,
319+ std::string_view name) {
320+ ARROW_ASSIGN_OR_RAISE (auto array, GetJsonArray (value, name));
321+
322+ std::vector<std::string> result;
323+ result.reserve (array.size ());
324+
325+ for (auto element : array) {
326+ if (!element.is_string ()) {
327+ return Status::Invalid (name, " must contain strings, got " ,
328+ JsonTypeName (element.type ()));
329+ }
330+
331+ ARROW_ASSIGN_OR_RAISE (
332+ auto string,
333+ ResolveSimdjsonResult (element.get_string (), " Failed to get JSON string" ));
334+ result.emplace_back (string);
335+ }
336+
337+ return result;
338+ }
339+
340+ const char * JsonTypeName (simdjson::ondemand::json_type type) {
341+ switch (type) {
342+ case simdjson::ondemand::json_type::array:
343+ return " array" ;
344+ case simdjson::ondemand::json_type::object:
345+ return " object" ;
346+ case simdjson::ondemand::json_type::number:
347+ return " number" ;
348+ case simdjson::ondemand::json_type::string:
349+ return " string" ;
350+ case simdjson::ondemand::json_type::boolean:
351+ return " boolean" ;
352+ case simdjson::ondemand::json_type::null:
353+ return " null" ;
354+ default :
355+ return " unknown" ;
356+ }
357+ }
358+
359+ Result<bool > IsJsonNull (simdjson::ondemand::value& value) {
360+ bool is_null;
361+ auto error_code = value.is_null ().get (is_null);
362+ if (error_code != simdjson::SUCCESS ) {
363+ return Status::Invalid (" Error checking for JSON null: " ,
364+ simdjson::error_message (error_code));
365+ }
366+ return is_null;
367+ }
368+
369+ Result<std::string> MinifyJson (std::string_view json) {
370+ std::string minified (json.size (), ' \0 ' );
371+ size_t minified_len = 0 ;
372+
373+ if (auto error =
374+ simdjson::minify (json.data (), json.size (), minified.data (), minified_len);
375+ error != simdjson::SUCCESS ) {
376+ return Status::Invalid (" Failed to minify JSON: " , simdjson::error_message (error));
377+ }
378+
379+ minified.resize (minified_len);
380+ return minified;
381+ }
382+
383+ Status ConsumeJsonValue (simdjson::ondemand::value value) {
384+ return VisitJsonValue (
385+ value, ValidateJsonObject, ValidateJsonArray,
386+ [](std::string_view) { return Status::OK (); }, [](bool ) { return Status::OK (); },
387+ []() { return Status::OK (); }, [](int64_t ) { return Status::OK (); },
388+ [](uint64_t ) { return Status::OK (); }, [](double ) { return Status::OK (); },
389+ [](simdjson::ondemand::value) { return Status::OK (); });
390+ }
391+
392+ Status ValidateJsonObject (simdjson::ondemand::object object) {
393+ for (auto field_result : object) {
394+ ARROW_ASSIGN_OR_RAISE (
395+ auto field, ResolveSimdjsonResult (field_result, " Failed to iterate JSON object" ));
396+
397+ RETURN_NOT_OK (ConsumeJsonValue (field.value ()));
398+ }
399+
400+ return Status::OK ();
401+ }
402+
403+ Status ValidateJsonArray (simdjson::ondemand::array array) {
404+ for (auto element_result : array) {
405+ ARROW_ASSIGN_OR_RAISE (
406+ auto value,
407+ ResolveSimdjsonResult (element_result, " Failed to iterate JSON array" ));
408+
409+ RETURN_NOT_OK (ConsumeJsonValue (value));
410+ }
411+
412+ return Status::OK ();
413+ }
414+
415+ Status ValidateJsonDocument (simdjson::ondemand::parser& parser,
416+ simdjson::padded_string& json) {
417+ ARROW_ASSIGN_OR_RAISE (
418+ auto document, ResolveSimdjsonResult (parser.iterate(json), " Failed to parse JSON" ));
419+
420+ ARROW_ASSIGN_OR_RAISE (auto value, ResolveSimdjsonResult (document.get_value (),
421+ " Failed to get JSON value" ));
422+
423+ return ConsumeJsonValue (value);
424+ }
425+
426+ } // namespace arrow::internal
0 commit comments