std::string variant::toJson()

in velox/type/Variant.cpp [184:303]


std::string variant::toJson() const {
  // todo(youknowjack): consistent story around std::stringifying, converting,
  // and other basic operations. Stringification logic should not be specific
  // to variants; it should be consistent for all map representations

  if (isNull()) {
    return "null";
  }

  switch (kind_) {
    case TypeKind::MAP: {
      auto& map = value<TypeKind::MAP>();
      std::string b{};
      b += "[";
      bool first = true;
      for (auto& pair : map) {
        if (!first) {
          b += ",";
        }
        b += "{\"key\":";
        b += pair.first.toJson();
        b += ",\"value\":";
        b += pair.second.toJson();
        b += "}";
        first = false;
      }
      b += "]";
      return b;
    }
    case TypeKind::ROW: {
      auto& row = value<TypeKind::ROW>();
      std::string b{};
      b += "[";
      bool first = true;
      for (auto& v : row) {
        if (!first) {
          b += ",";
        }
        b += v.toJson();
        first = false;
      }
      b += "]";
      return b;
    }
    case TypeKind::ARRAY: {
      auto& array = value<TypeKind::ARRAY>();
      std::string b{};
      b += "[";
      bool first = true;
      for (auto& v : array) {
        if (!first) {
          b += ",";
        }
        b += v.toJson();
        first = false;
      }
      b += "]";
      return b;
    }
    case TypeKind::VARBINARY: {
      auto& str = value<TypeKind::VARBINARY>();
      auto encoded = encoding::Base64::encode(str);
      return '"' + encoded + '"';
    }
    case TypeKind::VARCHAR: {
      auto& str = value<TypeKind::VARCHAR>();
      std::string target;
      folly::json::escapeString(str, target, getOpts());
      return target;
    }
    case TypeKind::TINYINT:
    case TypeKind::SMALLINT:
    case TypeKind::INTEGER:
    case TypeKind::BIGINT:
    case TypeKind::BOOLEAN: {
      auto converted = VariantConverter::convert<TypeKind::VARCHAR>(*this);
      if (converted.isNull()) {
        return "null";
      } else {
        return converted.value<TypeKind::VARCHAR>();
      }
    }
    case TypeKind::REAL: {
      auto val = value<TypeKind::REAL>();
      if (std::isnormal(val)) {
        return folly::to<std::string>(val);
      } else {
        return '"' + folly::to<std::string>(val) + '"';
      }
    }
    case TypeKind::DOUBLE: {
      auto val = value<TypeKind::DOUBLE>();
      if (std::isnormal(val)) {
        return folly::to<std::string>(val);
      } else {
        return '"' + folly::to<std::string>(val) + '"';
      }
    }
    case TypeKind::TIMESTAMP: {
      auto& timestamp = value<TypeKind::TIMESTAMP>();
      return '"' + timestamp.toString() + '"';
    }
    case TypeKind::DATE: {
      auto& date = value<TypeKind::DATE>();
      return '"' + date.toString() + '"';
    }
    case TypeKind::OPAQUE: {
      // Return expression that we can't parse back - we use toJson for
      // debugging only. Variant::serialize should actually serialize the data.
      return "\"Opaque<" + value<TypeKind::OPAQUE>().type->toString() + ">\"";
    }
    case TypeKind::FUNCTION:
    case TypeKind::UNKNOWN:
    case TypeKind::INVALID:
      VELOX_NYI();
  }

  VELOX_UNSUPPORTED(
      "Unsupported: given type {} is not json-ready", mapTypeKindToName(kind_));
}