All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lson.core_2.11.0.9.71.source-code.Json.scala Maven / Gradle / Ivy

The newest version!
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//:
//:   Licensed under the Apache License, Version 2.0 (the "License");
//:   you may not use this file except in compliance with the License.
//:   You may obtain a copy of the License at
//:
//:       http://www.apache.org/licenses/LICENSE-2.0
//:
//:   Unless required by applicable law or agreed to in writing, software
//:   distributed under the License is distributed on an "AS IS" BASIS,
//:   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//:   See the License for the specific language governing permissions and
//:   limitations under the License.
//:
//: ----------------------------------------------------------------------------
package nelson

import java.net.URI

import nelson.scheduler._

object Json {
  import argonaut._, Argonaut._
  import Datacenter._
  import concurrent.duration._
  import health.HealthStatus
  import scalaz._, Scalaz._

  implicit lazy val UriToJson: EncodeJson[URI] =
    implicitly[EncodeJson[String]].contramap(_.toString)

  implicit lazy val JsonToUri: DecodeJson[URI] =
    implicitly[DecodeJson[String]].map(new URI(_))

  implicit lazy val DurationEncoder: EncodeJson[Duration] =
    implicitly[EncodeJson[Long]].contramap(_.toMillis)

  implicit lazy val AccessTokenCodec: CodecJson[AccessToken] =
    casecodec1(AccessToken.apply, AccessToken.unapply)("access_token")

  implicit lazy val UserCodec: CodecJson[User] =
    casecodec5(User.apply, User.unapply)("login", "avatar_url", "name", "email", "organizations")

  implicit lazy val OrganizationCodec: CodecJson[Organization] =
    casecodec4(Organization.apply, Organization.unapply)("id", "name", "login", "avatar_url")

  implicit lazy val StackNameEncoder: EncodeJson[StackName] =
    implicitly[EncodeJson[String]].contramap(_.toString)

  implicit lazy val DeploymentEncoder: EncodeJson[Deployment] =
    EncodeJson { (d: Deployment) =>
      ("stack_name"  := d.stackName) ->:
      ("deployed_at" := d.deployTime) ->:
      ("workflow"    := d.workflow) ->:
      ("guid"        := d.guid) ->:
      ("unit"        := d.unit.name) ->:
      ("plan"        := d.plan) ->:
      ("resources"   := d.unit.resources) ->:
      jEmptyObject
    }

  implicit def tagEncoder[A, T](implicit ea: EncodeJson[A]): EncodeJson[A @@ T] = EncodeJson { a => Tag.unwrap[A, T](a).asJson }

  implicit val runningUnitEncoder: EncodeJson[RunningUnit] =
    EncodeJson((u: RunningUnit) =>
      ("name" := u.name) ->:
      ("status" := u.status) ->:
      jEmptyObject
    )

  implicit val taskStatusEncoder: EncodeJson[TaskStatus] = EncodeJson((s: TaskStatus) => s.toString.asJson )

  implicit val taskEventEncoder: EncodeJson[TaskEvent] =
    EncodeJson((e: TaskEvent) =>
      ("message" := e.message) ->:
      ("driver_message" := e.driverMessage) ->:
      jEmptyObject
    )

  implicit val taskStatusAndTaskEventsEncoder: EncodeJson[(TaskStatus, List[TaskEvent])] = EncodeJson((t: (TaskStatus, List[TaskEvent])) =>
    ("task_events" := t._2) ->:
    ("task_status" := t._1) ->:
    jEmptyObject
  )

  implicit val taskGroupAllocationTasksEncoder: EncodeJson[Map[String @@ TaskName, (TaskStatus, List[TaskEvent])]] =
    encodeTransposeMap[String @@ TaskName, (TaskStatus, List[TaskEvent])]('task_name, 'task_contents)

  implicit val taskGroupAllocationEncoder: EncodeJson[TaskGroupAllocation] =
    EncodeJson((a: TaskGroupAllocation) =>
      ("job_id" := a.jobId) ->:
      ("task_group" := a.taskGroup) ->:
      ("tasks" := a.tasks) ->:
      ("name" := a.name) ->:
      ("id" := a.id) ->:
      jEmptyObject
    )

  implicit lazy val RoutingNodeEncoder: EncodeJson[routing.RoutingNode] =
    EncodeJson((rn: routing.RoutingNode) =>
      rn.node.fold(
        lb =>
          ("guid" := lb.guid) ->:
          ("stack_name" := lb.stackName.toString) ->:
          ("type" := "loadbalancer") ->:
          ("deployed_at" := lb.deployTime) ->:
          jEmptyObject,
        de =>
          ("guid" := de.guid) ->:
          ("stack_name" := de.stackName.toString) ->:
          ("type" := "unit") ->:
          ("deployed_at" := de.deployTime) ->:
          jEmptyObject
      )
    )

  implicit lazy val RoutePathRoutingNodeEncoder: EncodeJson[(routing.RoutePath, routing.RoutingNode)] =
    EncodeJson {
      case (rp: routing.RoutePath, rn: routing.RoutingNode) =>
        (("weight" := rp.weight) ->:
         ("port_name" := rp.portName) ->:
         jEmptyObject
        ).deepmerge(rn.asJson)
    }

  implicit lazy val DeploymentDeploymentEncoder: EncodeJson[DependencyEdge] =
    EncodeJson((de: DependencyEdge) =>
      ("from" := de._1) ->:
      ("to" := de._2) ->:
      jEmptyObject
    )

  // Used for auditing purposes
  implicit lazy val ThrowableEncoder: EncodeJson[Throwable] =
    EncodeJson((t: Throwable) =>
      ("msg" := t.getMessage) ->:
      jEmptyObject
    )

  implicit def NelsonErrorEncoder[A <: NelsonError]: EncodeJson[A] =
    EncodeJson((error: A) =>
      ("msg" := error.getMessage) ->:
      jEmptyObject
    )

  implicit lazy val OrganizationEncoder: EncodeJson[Organization] =
    EncodeJson((o: Organization) =>
      ("id" := o.id) ->:
      ("name" := o.name) ->:
      ("slug" := o.slug) ->:
      ("avatar" := o.avatar) ->:
      jEmptyObject
    )

  implicit lazy val OrganizationDecoder: DecodeJson[Organization] =
    DecodeJson(c =>
      ((c --\ "id").as[Long] |@|
        (c --\ "name").as[Option[String]] |@|
        (c --\ "login").as[String] |@|
        (c --\ "avatar_url").as[URI]
      )(Organization.apply)
    )

  implicit lazy val HookEncoder: EncodeJson[Hook] =
    EncodeJson((h: Hook) =>
      ("id" := h.id) ->:
      ("is_active" := h.isActive) ->:
      jEmptyObject)

  implicit lazy val RepoAccessDecoder: DecodeJson[RepoAccess] =
    DecodeJson(c =>
      ((c --\ "push").as[Boolean] |@|
        (c --\ "pull").as[Boolean] |@|
        (c --\ "admin").as[Boolean]
      )(RepoAccess.fromBools)
    )

  implicit lazy val RepoDecoder: DecodeJson[Repo] =
    DecodeJson(c => for {
      z <- (c --\ "id").as[Long]
      y <- (c --\ "full_name").as[String]
      x <- Slug.fromString(y).map(DecodeResult.ok
            ).valueOr(e => DecodeResult.fail(e.getMessage,c.history))
      w <- (c --\ "permissions").as[RepoAccess]
    } yield Repo(z,x,w))

  implicit lazy val RepoEncoder: EncodeJson[Repo] =
    EncodeJson((r: Repo) =>
      ("id"         := r.id) ->:
      ("slug"       := r.slug.toString) ->:
      ("owner"      := r.slug.owner) ->:
      ("repository" := r.slug.repository) ->:
      ("access"     := r.access.toString) ->:
      ("hook"       := r.hook) ->:
      jEmptyObject)

  // never encode the whole session - only a non-private subset
  implicit lazy val SessionEncoder: EncodeJson[Session] =
    EncodeJson((s: Session) =>
      ("user" :=
        ("name" := s.user.name) ->:
        ("login" := s.user.login) ->:
        ("avatar" := s.user.avatar.toString) ->:
        ("organizations" := (s.user.toOrganization +: s.user.orgs)) ->:
        jEmptyObject
      ) ->:
      jEmptyObject
    )

  /**
   *{
   *  "id": 1,
   *  "url": "https://api.github.com/repos/octocat/Hello-World/hooks/1",
   *  "test_url": "https://api.github.com/repos/octocat/Hello-World/hooks/1/test",
   *  "ping_url": "https://api.github.com/repos/octocat/Hello-World/hooks/1/pings",
   *  "name": "web",
   *  "events": [
   *    "push",
   *    "pull_request"
   *  ],
   *  "active": true,
   *  "config": {
   *    "url": "http://example.com/webhook",
   *    "content_type": "json"
   *  },
   *  "updated_at": "2011-09-06T20:39:23Z",
   *  "created_at": "2011-09-06T17:26:27Z"
   *}
   */
  implicit lazy val GithubWebHookDecoder: DecodeJson[Github.WebHook] =
    DecodeJson(c =>
      ((c --\ "id").as[Long] |@|
        (c --\ "name").as[String] |@|
        (c --\ "events").as[List[String]] |@|
        (c --\ "active").as[Boolean] |@|
        (c --\ "config").as[Map[String,String]]
      )(Github.WebHook.apply)
    )

  /**
   *
   */
  implicit lazy val GithubPingEventDecoder: DecodeJson[Github.PingEvent] =
    DecodeJson(c => for {
      z <- (c --\ "zen").as[String]
    } yield Github.PingEvent(z))

  /**
   * a simple aggregate decoder that allows us to refer to all events
   * as a single inbound type; bit hacky but we're bridging the typed
   * and un-typed worlds here... *sigh*.
   *
   * TIM: this seems really hacky.
   */
  implicit lazy val GithubEventDecoder: DecodeJson[Github.Event] =
    GithubReleaseEventDecoder.asInstanceOf[DecodeJson[Github.ReleaseEvent]] |||
    GithubPingEventDecoder.asInstanceOf[DecodeJson[Github.Event]]

  /**
   * {
   *   "name": "web",
   *   "active": true,
   *   "events": [
   *     "push",
   *     "pull_request"
   *   ],
   *   "config": {
   *     "url": "http://example.com/webhook",
   *     "content_type": "json"
   *   }
   * }
   */
  implicit lazy val GithubWebHookEncoder: EncodeJson[Github.WebHook] =
    EncodeJson((w: Github.WebHook) =>
      ("name"   := w.name) ->:
      ("events" := w.events) ->:
      ("active" := w.active) ->:
      ("config" := w.config) ->:
      jEmptyObject
    )

  /**
   * {
   *   "content": "...",
   *   "name": ".travis.yml",
   *   "size": 633
   * }
   */
  implicit val GithubContentsDecoder: DecodeJson[Github.Contents] =
    DecodeJson(c =>
      ((c --\ "content").as[String] |@|
        (c --\ "name").as[String] |@|
        (c --\ "size").as[Long]
      )(Github.Contents.apply)
    )

  /**
   * {
   *   "assets": [
   *     {
   *       "browser_download_url": "https://github.example.com/tim/howdy/releases/download/0.13.17/example-howdy.deployable.yml",
   *       "content_type": "application/yaml; charset=UTF-8",
   *       "created_at": "2016-02-11T21:31:47Z",
   *       "download_count": 1,
   *       "id": 119,
   *       "label": "",
   *       "name": "example-howdy.deployable.yml",
   *       "size": 206,
   *       "state": "uploaded",
   *       "updated_at": "2016-02-11T21:31:48Z",
   *       "uploader": {
   *         "avatar_url": "https://github.example.com/avatars/u/703?",
   *         "events_url": "https://github.example.com/api/v3/users/travis/events{/privacy}",
   *         "followers_url": "https://github.example.com/api/v3/users/travis/followers",
   *         "following_url": "https://github.example.com/api/v3/users/travis/following{/other_user}",
   *         "gists_url": "https://github.example.com/api/v3/users/travis/gists{/gist_id}",
   *         "gravatar_id": "",
   *         "html_url": "https://github.example.com/travis",
   *         "id": 703,
   *         "login": "travis",
   *         "organizations_url": "https://github.example.com/api/v3/users/travis/orgs",
   *         "received_events_url": "https://github.example.com/api/v3/users/travis/received_events",
   *         "repos_url": "https://github.example.com/api/v3/users/travis/repos",
   *         "site_admin": false,
   *         "starred_url": "https://github.example.com/api/v3/users/travis/starred{/owner}{/repo}",
   *         "subscriptions_url": "https://github.example.com/api/v3/users/travis/subscriptions",
   *         "type": "User",
   *         "url": "https://github.example.com/api/v3/users/travis"
   *       },
   *       "url": "https://github.example.com/api/v3/repos/tim/howdy/releases/assets/119"
   *     }
   *   ],
   *   "assets_url": "https://github.example.com/api/v3/repos/tim/howdy/releases/250/assets",
   *   "author": {
   *     "avatar_url": "https://github.example.com/avatars/u/703?",
   *     "events_url": "https://github.example.com/api/v3/users/travis/events{/privacy}",
   *     "followers_url": "https://github.example.com/api/v3/users/travis/followers",
   *     "following_url": "https://github.example.com/api/v3/users/travis/following{/other_user}",
   *     "gists_url": "https://github.example.com/api/v3/users/travis/gists{/gist_id}",
   *     "gravatar_id": "",
   *     "html_url": "https://github.example.com/travis",
   *     "id": 703,
   *     "login": "travis",
   *     "organizations_url": "https://github.example.com/api/v3/users/travis/orgs",
   *     "received_events_url": "https://github.example.com/api/v3/users/travis/received_events",
   *     "repos_url": "https://github.example.com/api/v3/users/travis/repos",
   *     "site_admin": false,
   *     "starred_url": "https://github.example.com/api/v3/users/travis/starred{/owner}{/repo}",
   *     "subscriptions_url": "https://github.example.com/api/v3/users/travis/subscriptions",
   *     "type": "User",
   *     "url": "https://github.example.com/api/v3/users/travis"
   *   },
   *   "body": "",
   *   "created_at": "2016-02-11T21:30:05Z",
   *   "draft": false,
   *   "html_url": "https://github.example.com/tim/howdy/releases/tag/0.13.17",
   *   "id": 250,
   *   "name": "Inner Elemental",
   *   "prerelease": false,
   *   "published_at": "2016-02-11T21:31:47Z",
   *   "tag_name": "0.13.17",
   *   "tarball_url": "https://github.example.com/api/v3/repos/tim/howdy/tarball/0.13.17",
   *   "target_commitish": "master",
   *   "upload_url": "https://github.example.com/api/uploads/repos/tim/howdy/releases/250/assets{?name,label}",
   *   "url": "https://github.example.com/api/v3/repos/tim/howdy/releases/250",
   *   "zipball_url": "https://github.example.com/api/v3/repos/tim/howdy/zipball/0.13.17"
   * }
   */
  implicit val GithubReleaseDecoder: DecodeJson[Github.Release] =
    DecodeJson(z =>
      ((z --\ "id").as[Long] |@|
        (z --\ "url").as[String] |@|
        (z --\ "html_url").as[String] |@|
        (z --\ "assets").as[List[Github.Asset]] |@|
        (z --\ "tag_name").as[String]
        ) ((a, b, c, d, e) =>
        Github.Release(
          id = a,
          url = b,
          htmlUrl = c,
          assets = d,
          tagName = e
        )
      )
    )

  implicit val GithubAssetsEncoder: EncodeJson[Github.Asset] =
    EncodeJson((asset: Github.Asset) =>
      ("id" := asset.id) ->:
      ("name" := asset.name) ->:
      ("state" := asset.state) ->:
      ("url" := asset.url) ->:
      ("content" := asset.content) ->:
      jEmptyObject
    )

  implicit val GithubReleaseEncoder: EncodeJson[Github.Release] =
    EncodeJson((release: Github.Release) =>
      ("id" := release.id) ->:
      ("url" := release.url) ->:
      ("html_url" := release.htmlUrl) ->:
      ("assets" := release.assets) ->:
      ("tag_name" := release.tagName) ->:
      jEmptyObject
    )

  /**
   *{
   *  "action": "published",
   *  "release": {
   *    "url": "https://api.github.com/repos/baxterthehacker/public-repo/releases/1261438",
   *    "assets_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases/1261438/assets",
   *    "upload_url": "https://uploads.github.com/repos/baxterthehacker/public-repo/releases/1261438/assets{?name}",
   *    "html_url": "https://github.com/baxterthehacker/public-repo/releases/tag/0.0.1",
   *    "id": 1261438,
   *    "tag_name": "0.0.1",
   *    "target_commitish": "master",
   *    "name": null,
   *    "draft": false,
   *    "author": {
   *      "login": "baxterthehacker",
   *      "id": 6752317,
   *      "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
   *      "gravatar_id": "",
   *      "url": "https://api.github.com/users/baxterthehacker",
   *      "html_url": "https://github.com/baxterthehacker",
   *      ...
   *      "type": "User",
   *      "site_admin": false
   *    },
   *    "prerelease": false,
   *    "created_at": "2015-05-05T23:40:12Z",
   *    "published_at": "2015-05-05T23:40:38Z",
   *    "assets": [
   *
   *    ],
   *    "tarball_url": "https://api.github.com/repos/baxterthehacker/public-repo/tarball/0.0.1",
   *    "zipball_url": "https://api.github.com/repos/baxterthehacker/public-repo/zipball/0.0.1",
   *    "body": null
   *  },
   *  "repository": {
   *    "id": 35129377,
   *    "name": "public-repo",
   *    "full_name": "baxterthehacker/public-repo",
   *    "owner": {
   *      "login": "baxterthehacker",
   *      "id": 6752317,
   *      "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
   *      "gravatar_id": "",
   *      "url": "https://api.github.com/users/baxterthehacker",
   *      "html_url": "https://github.com/baxterthehacker",
   *      ...
   *      "type": "User",
   *      "site_admin": false
   *    },
   *    "private": false,
   *    "html_url": "https://github.com/baxterthehacker/public-repo",
   *    "description": "",
   *    "fork": false,
   *    ...
   *    "created_at": "2015-05-05T23:40:12Z",
   *    "updated_at": "2015-05-05T23:40:30Z",
   *    "pushed_at": "2015-05-05T23:40:38Z",
   *    "git_url": "git://github.com/baxterthehacker/public-repo.git",
   *    "ssh_url": "[email protected]:baxterthehacker/public-repo.git",
   *    "clone_url": "https://github.com/baxterthehacker/public-repo.git",
   *    "svn_url": "https://github.com/baxterthehacker/public-repo",
   *    "homepage": null,
   *    "size": 0,
   *    "stargazers_count": 0,
   *    "watchers_count": 0,
   *    "language": null,
   *    "has_issues": true,
   *    "has_downloads": true,
   *    "has_wiki": true,
   *    "has_pages": true,
   *    "forks_count": 0,
   *    "mirror_url": null,
   *    "open_issues_count": 2,
   *    "forks": 0,
   *    "open_issues": 2,
   *    "watchers": 0,
   *    "default_branch": "master"
   *  },
   *  "sender": {
   *    "login": "baxterthehacker",
   *    "id": 6752317,
   *    "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
   *    "gravatar_id": "",
   *    "url": "https://api.github.com/users/baxterthehacker",
   *    "html_url": "https://github.com/baxterthehacker",
   *    ...
   *    "type": "User",
   *    "site_admin": false
   *  }
   *}
   */
  implicit val GithubReleaseEventDecoder: DecodeJson[Github.ReleaseEvent] =
    DecodeJson(z => for {
      a <- (z --\ "release" --\ "id").as[Long]
      d <- (z --\ "repository" --\ "full_name").as[String]
      x <- Slug.fromString(d).map(DecodeResult.ok
           ).valueOr(e => DecodeResult.fail(e.getMessage,z.history))
      e <- (z --\ "repository" --\ "id").as[Long]
    } yield {
      Github.ReleaseEvent(
        id = a,
        slug = x,
        repositoryId = e
      )
    })

  /**
   * {
   *   "url": "https://github.example.com/api/v3/repos/example/howdy/releases/assets/1",
   *   "id": 1,
   *   "name": "example.yml",
   *   "label": "",
   *   "uploader": {
   *     ...
   *   },
   *   "content_type": "application/yaml",
   *   "state": "uploaded",
   *   "size": 36,
   *   "download_count": 0,
   *   "created_at": "2015-12-18T00:27:46Z",
   *   "updated_at": "2015-12-18T00:27:46Z",
   *   "browser_download_url": "https://github.example.com/example/howdy/releases/download/3.0.0/example.yml"
   * }
   */
  implicit lazy val AssetDecoder: DecodeJson[Github.Asset] =
    DecodeJson(c =>
      ((c --\ "id").as[Long] |@|
        (c --\ "name").as[String] |@|
        (c --\ "state").as[String] |@|
        (c --\ "url").as[String]
      )((x,y,z,w) => Github.Asset(x,y,z,w))
    )

  implicit lazy val GithubOrg: CodecJson[Github.OrgKey] =
    casecodec2(Github.OrgKey.apply, Github.OrgKey.unapply)("id", "login")

  implicit lazy val GithubUser: CodecJson[Github.User] =
    casecodec4(Github.User.apply, Github.User.unapply
      )("login", "avatar_url", "name", "email")

  implicit val timestampCodec: CodecJson[java.time.Instant] = CodecJson(
    (i: java.time.Instant) => i.toEpochMilli.asJson,
    c => for {
      instant <- (c --\ "timestamp").as[Long]
    } yield java.time.Instant.ofEpochMilli(instant)
  )

  implicit val auditLogEncoder: CodecJson[audit.AuditLog] =
    casecodec7(audit.AuditLog.apply, audit.AuditLog.unapply)("id", "timestamp", "releaseId", "event", "category", "action", "login")

  implicit val manualDeployEncoder: CodecJson[Datacenter.ManualDeployment] =
    casecodec7(Datacenter.ManualDeployment.apply, Datacenter.ManualDeployment.unapply)(
      "datacenter", "namespace", "service_type", "version", "hash", "description", "port"
    )

  implicit val NamspaceRoutingGraphEncoder: EncodeJson[(Namespace,routing.RoutingGraph)] =
    EncodeJson { (t: (Namespace, routing.RoutingGraph)) =>
      val (n,g) = t
      ("name" := n.name.asString) ->:
      ("graph" := g.nodes.map(node =>
        ("name" := node.stackName.toString) ->:
        ("dependencies" := g.outs(node).map(_._2.stackName.toString)) ->:
        jEmptyObject)
      ) ->: jEmptyObject
    }

  implicit lazy val DeploymentSummaryEncoder: EncodeJson[scheduler.DeploymentSummary] =
    EncodeJson((ds: scheduler.DeploymentSummary) =>
      ("running"   := ds.running) ->:
      ("pending"   := ds.pending) ->:
      ("completed" := ds.completed) ->:
      ("failed"    := ds.failed) ->:
      jEmptyObject
    )

  implicit val HealthCheckEncoder: EncodeJson[health.HealthCheck] =
    EncodeJson[health.HealthCheck] { hs => jString(health.HealthCheck.toString(hs)) }

  implicit lazy val HealthStatusEncoder: EncodeJson[HealthStatus] =
    EncodeJson((h: HealthStatus) =>
      ("name"    := h.details.getOrElse("unspecified")) ->:
      ("status"  := h.status) ->:
      ("node"    := h.node) ->:
      ("check_id" := h.id) ->:
      jEmptyObject
    )

  implicit lazy val RuntimeSummaryEncoder: EncodeJson[Nelson.RuntimeSummary] =
    EncodeJson((rs: Nelson.RuntimeSummary) =>
      ("scheduler" := rs.deployment) ->:
      ("consul_health" := rs.health) ->:
      ("current_status" := rs.currentStatus.toString) ->:
      ("expires_at" := rs.expiresAt) ->:
      jEmptyObject
    )

  implicit val NamespaceNameDecoder: DecodeJson[NamespaceName] =
    DecodeJson.optionDecoder(_.string.flatMap(s =>
      NamespaceName.fromString(s).toOption), "NamespaceName")

  final case class NamespaceNameJson(
    namespace: NamespaceName
  )

  implicit val NamespaceNameJsonDecoder: DecodeJson[NamespaceNameJson] =
    DecodeJson[NamespaceNameJson](c =>
      for {
        ns <- (c --\ "namespace").as[NamespaceName]
      } yield NamespaceNameJson(ns)
    )

  implicit lazy val CommitUnitDecode: DecodeJson[Nelson.CommitUnit] =
    DecodeJson(c => for {
      u <- (c --\ "unit").as[String]
      v <- (c --\ "version").as[String]
      t <- (c --\ "target").as[NamespaceName]
      vv <- Version.fromString(v).map(DecodeResult.ok)
              .getOrElse(DecodeResult.fail(s"unable to parse $v into a version", c.history))
    } yield Nelson.CommitUnit(u,vv,t))

  implicit lazy val TrafficShiftEncoder: EncodeJson[Datacenter.TrafficShift] =
    EncodeJson((ts: Datacenter.TrafficShift) =>
      ("from" := ts.from) ->:
      ("to" := ts.to) ->:
      ("start" := ts.start) ->:
      ("end" := ts.end) ->:
      ("reverse" := ts.reverse) ->:
      ("policy" := ts.policy.ref) ->:
      jEmptyObject
    )

  /*
   * Encode a map as a transposed JSON list of maps, such that each map has (klabel: key) and (vlabel: value) entries.
   */
  def encodeTransposeMap[K, V](klabel: Symbol, vlabel: Symbol)(implicit ek: EncodeJson[K], ev: EncodeJson[V]): EncodeJson[Map[K, V]] = EncodeJson { m =>
    m.toList.map { case (k, v) =>
      (vlabel.name := v.asJson) ->:
      (klabel.name := k.asJson) ->:
      jEmptyObject
    }.asJson
  }

  def encodeTransposeZMap[K, V](klabel: Symbol, vlabel: Symbol)(implicit ek: EncodeJson[K], ev: EncodeJson[V]): EncodeJson[K ==>> V] = EncodeJson { m =>
    m.toList.map { case (k, v) =>
      (vlabel.name := v.asJson) ->:
      (klabel.name := k.asJson) ->:
      jEmptyObject
    }.asJson
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy