Variant Converter::ConvertFieldValueToVariant()

in blogs/sept-2021/converter.cc [237:340]


Variant Converter::ConvertFieldValueToVariant(const FieldValue& from) const {
  switch (from.type()) {
      // Primitives -- one-to-one mapping.

    case FieldValue::Type::kNull:
      return Variant::Null();
    case FieldValue::Type::kBoolean:
      return Variant(from.boolean_value());
    case FieldValue::Type::kInteger:
      return Variant(from.integer_value());
    case FieldValue::Type::kDouble:
      return Variant(from.double_value());

      // `FieldValue` always owns the underlying string or blob, so the safest
      // approach is to copy the value to a `Variant` that will assume
      // ownership.

    case FieldValue::Type::kString:
      return Variant(from.string_value());
    case FieldValue::Type::kBlob:
      return Variant::FromMutableBlob(from.blob_value(), from.blob_size());

      // Containers are converted recursively.

    case FieldValue::Type::kArray:
      return ConvertArray(from.array_value());
    case FieldValue::Type::kMap:
      return ConvertMap(from.map_value());

      // Firestore-specific structs are encoded as maps with a boolean field
      // "special" set to true and a string field "type" indicating the original
      // type.

    case FieldValue::Type::kTimestamp: {
      Timestamp ts = from.timestamp_value();
      MapFieldValue as_map = {
          {"special", FieldValue::Boolean(true)},
          {"type", FieldValue::String("timestamp")},
          {"seconds", FieldValue::Integer(ts.seconds())},
          {"nanoseconds", FieldValue::Integer(ts.nanoseconds())}};
      return ConvertRegularMap(as_map);
      // Note: if using the resulting `Variant` with RTDB, you might want to
      // convert timestamps to the number of milliseconds since Unix epoch:
      // Timestamp ts = from.timestamp_value();
      // int64_t millis = ts.seconds() * 1000 + ts.nanoseconds() / (1000*1000);
      // return Variant(millis);
    }

    case FieldValue::Type::kGeoPoint: {
      GeoPoint gp = from.geo_point_value();
      MapFieldValue as_map = {
          {"special", FieldValue::Boolean(true)},
          {"type", FieldValue::String("geo_point")},
          {"latitude", FieldValue::Double(gp.latitude())},
          {"longitude", FieldValue::Double(gp.longitude())}};
      return ConvertRegularMap(as_map);
    }

    case FieldValue::Type::kReference: {
      DocumentReference ref = from.reference_value();
      std::string path = ref.path();
      MapFieldValue as_map = {
          {"special", FieldValue::Boolean(true)},
          {"type", FieldValue::String("document_reference")},
          {"document_path", FieldValue::String(path)}};
      return ConvertRegularMap(as_map);
    }

      // Firestore-specific sentinel values can also be encoded as maps.

    case FieldValue::Type::kDelete: {
      // Note: if using the resulting `Variant` with RTDB, you might want to
      // convert a `delete` sentinel to null:
      // return Variant::Null();
      MapFieldValue as_map = {{"special", FieldValue::Boolean(true)},
                              {"type", FieldValue::String("delete")}};
      return ConvertRegularMap(as_map);
    }

    case FieldValue::Type::kServerTimestamp: {
      MapFieldValue as_map = {{"special", FieldValue::Boolean(true)},
                              {"type", FieldValue::String("server_timestamp")}};
      // Note: if using the resulting `Variant` with RTDB, you might want to
      // convert the server timestamp to the representation used by RTDB:
      // MapFieldValue as_map = {{".sv", FieldValue::String("timestamp")}};
      return ConvertRegularMap(as_map);
    }

      // Several Firestore sentinel values cannot be converted losslessly
      // (because they don't allow accessing the underlying value(s)). In this
      // example, we will simply assert that these values should never be given
      // to the converter.
    case FieldValue::Type::kArrayUnion:
    case FieldValue::Type::kArrayRemove:
    case FieldValue::Type::kIncrementInteger:
    case FieldValue::Type::kIncrementDouble:
      assert(false && "Unsupported FieldValue type");
      std::terminate();

    default:
      assert(false && "Unknown FieldValue type");
      std::terminate();
  }
}