2016-04-13 17 views
5

Lưu ý: Tôi đang sao chép câu hỏi này từ circe Gitter channel vì mục đích của hậu thế.Chuyển đổi JSON với trạng thái trong circe

Giả sử chúng ta muốn dịch tài liệu JSON này:

{ 
    "places": [{ 
    "id": "dadcc0d9-0615-4e46-9df4-2619f49930a0" 
    }, { 
    "id": "21d02f4b-7e88-47d7-bf2b-48e50761b6c3" 
    }], 
    "transitions": [{ 
    "id": "10a3aee5-541b-4d04-bb45-cb1dbbfe2128", 
    "startPlaceId": "dadcc0d9-0615-4e46-9df4-2619f49930a0", 
    "endPlaceId": "21d02f4b-7e88-47d7-bf2b-48e50761b6c3" 
    }], 
    "routes": [{ 
    "id": "6ded1763-86c0-44ce-b94b-f05934976a3b", 
    "transitionId": "10a3aee5-541b-4d04-bb45-cb1dbbfe2128" 
    }] 
} 

Into này:

{ 
    "places": [{ 
    "id": "1" 
    }, { 
    "id": "2" 
    }], 
    "transitions": [{ 
    "id": "3", 
    "startPlaceId": "ref:1", 
    "endPlaceId": "ref:2" 
    }], 
    "routes": [{ 
    "id": "4", 
    "transitionId": "ref:3" 
    }] 
} 

Ie, chúng tôi muốn thay thế các UUID trong mỗi id với một định danh số tăng lên đơn giản, và để thay thế tất cả các tham chiếu đến từng UUID bằng tham chiếu đến các số nhận dạng mới.

Làm cách nào chúng tôi có thể thực hiện việc này với circe?

Trả lời

8

Có thể thực hiện điều này khá thẳng thắn với biến đơn nguyên nhà nước từ Cats (một thư viện mà Circe phụ thuộc vào):

import cats.data.StateT 
import cats.std.option._ 
import cats.std.list._ 
import cats.syntax.traverse._ 
import io.circe.{ Json, JsonObject } 
import java.util.UUID 

def update(j: Json): StateT[Option, Map[UUID, Long], Json] = j.arrayOrObject(
    StateT.pure[Option, Map[UUID, Long], Json](j), 
    _.traverseU(update).map(Json.fromValues), 
    _.toList.traverseU { 
    case ("id", value) => StateT { (ids: Map[UUID, Long]) => 
     value.as[UUID].toOption.map { uuid => 
     val next = if (ids.isEmpty) 1L else ids.values.max + 1L 
     (ids.updated(uuid, next), "id" -> Json.fromString(s"$next")) 
     } 
    } 
    case (other, value) => value.as[UUID].toOption match { 
     case Some(uuid) => StateT { (ids: Map[UUID, Long]) => 
     ids.get(uuid).map(id => (ids, other -> Json.fromString(s"ref:$id"))) 
     } 
     case None => update(value).map(other -> _) 
    } 
    }.map(Json.fromFields) 
) 

Và sau đó:

import io.circe.literal._ 

val doc: Json = json""" 
{ 
    "places": [{ 
    "id": "dadcc0d9-0615-4e46-9df4-2619f49930a0" 
    }, { 
    "id": "21d02f4b-7e88-47d7-bf2b-48e50761b6c3" 
    }], 
    "transitions": [{ 
    "id": "10a3aee5-541b-4d04-bb45-cb1dbbfe2128", 
    "startPlaceId": "dadcc0d9-0615-4e46-9df4-2619f49930a0", 
    "endPlaceId": "21d02f4b-7e88-47d7-bf2b-48e50761b6c3" 
    }], 
    "routes": [{ 
    "id": "6ded1763-86c0-44ce-b94b-f05934976a3b", 
    "transitionId": "10a3aee5-541b-4d04-bb45-cb1dbbfe2128" 
    }] 
} 
""" 

Và cuối cùng:

scala> import cats.std.long._ 
import cats.std.long._ 

scala> import cats.std.map._ 
import cats.std.map._ 

scala> update(doc).runEmptyA 
res0: Option[io.circe.Json] = 
Some({ 
    "places" : [ 
    { 
     "id" : "1" 
    }, 
    { 
     "id" : "2" 
    } 
    ], 
    "transitions" : [ 
    { 
     "id" : "3", 
     "startPlaceId" : "ref:1", 
     "endPlaceId" : "ref:2" 
    } 
    ], 
    "routes" : [ 
    { 
     "id" : "4", 
     "transitionId" : "ref:3" 
    } 
    ] 
}) 

Nếu bất kỳ trường id nào không phải là UUID hợp pháp, hoặc nếu bất kỳ trường nào khác chứa tham chiếu đến UUID không xác định, việc tính toán sẽ không thành công với None. Hành vi này có thể được tinh chỉnh một chút nếu cần và nếu bạn muốn biết thêm thông tin cụ thể về nơi xảy ra lỗi, bạn có thể điều chỉnh việc triển khai để làm việc với con trỏ thay vì các giá trị JSON (nhưng điều này sẽ phức tạp hơn một chút).

+0

Có thể 'ids.updated (uuid, next)' được thay thế bằng 'ids + (uuid -> next)'? –

+1

@ Łukasz Có, nhưng tôi thấy 'cập nhật' rõ ràng hơn một chút, vì nó không yêu cầu tạo ra một bộ dữ liệu rõ ràng và vì sẽ luôn chỉ có một cặp khóa-giá trị mà chúng tôi đang thêm vào đó. –

+0

Được rồi, cảm ơn vì đã giải thích. Tôi thấy nó hơi khó hiểu vì điều này cũng sẽ cho phép thay thế giá trị hiện tại nhưng điều đó sẽ không bao giờ xảy ra và ý định của bạn là chèn một phần tử mới, nhưng bây giờ tôi cũng có thể thấy lợi thế của cách tiếp cận của bạn. –

Các vấn đề liên quan