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

org.neo4j.cypher.testing.impl.http.HttpStatementResult.scala Maven / Gradle / Ivy

/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [https://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.cypher.testing.impl.http

import org.neo4j.cypher.testing.api.StatementResult
import org.neo4j.cypher.testing.impl.http.HttpStatementResult.Notification
import org.neo4j.cypher.testing.impl.http.HttpStatementResult.Result
import org.neo4j.cypher.testing.impl.shared.NotificationImpl
import org.neo4j.exceptions.Neo4jException
import org.neo4j.graphdb
import org.neo4j.graphdb.GqlStatusObject
import org.neo4j.graphdb.InputPosition
import org.neo4j.kernel.api.exceptions.Status
import org.neo4j.test.server.HTTP

import scala.jdk.CollectionConverters.CollectionHasAsScala
import scala.util.Failure
import scala.util.Success
import scala.util.Try

case class HttpStatementResult(result: Result, notifications: Seq[Notification]) extends StatementResult {

  private val cols = result.columns

  override def columns(): Seq[String] = cols

  override def records(): Seq[Record] = result.data.map(r => cols.zip(r.row).toMap)

  override def consume(): Unit = ()

  override def getNotifications(): List[graphdb.Notification] =
    notifications
      .map(n =>
        NotificationImpl.fromRaw(
          n.code,
          n.title,
          n.description,
          n.severity,
          Option(n.position)
            .map(pos => new InputPosition(pos.offset, pos.line, pos.column))
            .getOrElse(InputPosition.empty),
          n.category
        )
      )
      .toList

  override def getGqlStatusObjects(): Iterable[GqlStatusObject] = ???
  override def iterator(): Iterator[Map[String, AnyRef]] = ???
  override def close(): Unit = {}
}

object HttpStatementResult {
  case class Response(results: Seq[Result], errors: Seq[Error], notifications: Option[Seq[Notification]])
  case class Error(code: String, message: String)

  case class Notification(
    code: String,
    title: String,
    description: String,
    severity: String,
    position: Position,
    category: String
  )
  case class Position(offset: Int, line: Int, column: Int)
  case class Result(columns: Seq[String], data: Seq[Row])
  case class Row(row: Seq[AnyRef])

  def fromResponse(response: HTTP.Response): HttpStatementResult = {
    val content = response.rawContent()

    def failUnableToDecode(exception: Throwable): Nothing =
      throw new Exception(s"Unable to decode json: $content", exception)

    def failNoResults(): Nothing =
      throw new Exception(s"Response contained no results: $content")

    def failMultipleResults(): Nothing =
      throw new Exception(s"Response contained multiple results: $content")

    val (result, notifications) = Try(HttpJson.read[Response](content)) match {
      case Failure(exception) => failUnableToDecode(exception)
      case Success(response) => response match {
          case Response(Seq(result), Seq(), notifications) => (result, notifications)
          case Response(_, Seq(error), _)                  => serverError(error)
          case Response(Seq(), _, _)                       => failNoResults()
          case Response(_, _, _)                           => failMultipleResults()
        }
    }

    HttpStatementResult(result, notifications.getOrElse(Seq.empty))
  }

  private def serverError(e: HttpStatementResult.Error): Nothing = {
    Status.Code.all.asScala.find(status => status.code.serialize == e.code) match {
      case Some(statusVal) => throw new Neo4jException(e.message) {
          override def status(): Status = statusVal
        }
      case None => throw new RuntimeException(e.message)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy