public static Object read(BsonReader reader) {
        return switch (reader.getCurrentBsonType()) {
            case DOUBLE -> reader.readDouble();
            case STRING -> reader.readString();
            case DOCUMENT -> {
                // We use LinkedHashMap because we don't know
                // if the user cares about the order or not,
                // so we always use LinkedHashMap to keep the order.
                Map<String, Object> map = new LinkedHashMap<>();
                reader.readStartDocument();
                while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    String key = reader.readName();
                    Object value = read(reader);
                    map.put(key, value);
                }
                reader.readEndDocument();
                yield map;
            }
            case ARRAY -> {
                // For our use cases, we just use small lists in most cases,
                // so 32 is a reasonable size.
                List<Object> list = new ArrayList<>(32);
                reader.readStartArray();
                while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    Object value = read(reader);
                    list.add(value);
                }
                reader.readEndArray();
                yield list;
            }
            case BINARY -> reader.readBinaryData()
                    .getData();
            case UNDEFINED -> {
                reader.readUndefined();
                yield null;
            }
            case OBJECT_ID -> reader.readObjectId();
            case BOOLEAN -> reader.readBoolean();
            case DATE_TIME -> new Date(reader.readDateTime());
            case NULL -> {
                reader.readNull();
                yield null;
            }
            case REGULAR_EXPRESSION -> Pattern.compile(reader.readRegularExpression()
                    .getPattern());
            case DB_POINTER ->
                throw new UnsupportedOperationException("DBPointer is not supported");
            case JAVASCRIPT -> reader.readJavaScript();
            case SYMBOL -> throw new UnsupportedOperationException("Symbol is not supported");
            case JAVASCRIPT_WITH_SCOPE ->
                throw new UnsupportedOperationException("JavaScriptWithScope is not supported");
            case INT32 -> reader.readInt32();
            case TIMESTAMP -> reader.readTimestamp();
            case INT64 -> reader.readInt64();
            case DECIMAL128 -> reader.readDecimal128();
            case MIN_KEY -> {
                reader.readMinKey();
                yield BsonPool.MIN_KEY;
            }
            case MAX_KEY -> {
                reader.readMaxKey();
                yield BsonPool.MAX_KEY;
            }
            case END_OF_DOCUMENT -> throw new UnsupportedOperationException(
                    "The caller must handle the end of a document");
        };
    }
TODO: unify the logic of {@link #encode} and {@link #write}
turms-server-common/src/main/java/im/turms/server/common/storage/mongo/codec/CodecUtil.java