Skip to content

Commit

Permalink
Merge pull request prisma#4522 from prisma/ErrorOnInvalidWhereUnique
Browse files Browse the repository at this point in the history
Invalid WhereUnique Bug
  • Loading branch information
do4gr authored May 14, 2019
2 parents 050aaf9 + d6a03d3 commit 122302e
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ object APIErrors {
extends ClientApiError(s"No Node for the model ${where.model.name} with value ${where.value} for ${where.field.name} found.", 3039)

case class NullProvidedForWhereError(modelName: String)
extends ClientApiError(s"You provided an invalid argument for the where selector on $modelName.", 3040)
extends ClientApiError(s"You provided an invalid argument for the where selector on $modelName. Please provide exactly one unique field and value.", 3040)

case class NodesNotConnectedError(relation: Relation, parent: Model, parentWhere: Option[NodeSelector], child: Model, childWhere: Option[NodeSelector])
extends ClientApiError(pathErrorMessage(relation, parent, parentWhere, child, childWhere), 3041)
Expand Down Expand Up @@ -138,6 +138,12 @@ object APIErrors {
3044
)

case class TwoManyUniquesForWhereError(modelName: String)
extends ClientApiError(
s"You provided more than one field for the unique selector on $modelName. If you want that behavior you can use the many query and combine fields with AND / OR.",
3045
)

case class ExecuteRawError(e: SQLException) extends ClientApiError(e.getMessage, e.getErrorCode)

def pathErrorMessageNative(relation: String, parent: String, parentWhere: Option[NodeSelectorInfo], child: String, childWhere: Option[NodeSelectorInfo]) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,18 @@ case class CoolArgs(raw: Map[String, Any]) {
}

def extractNodeSelector(model: Model): NodeSelector = {
raw.asInstanceOf[Map[String, Option[Any]]].collectFirst {
val map = raw.asInstanceOf[Map[String, Option[Any]]]
val uniquesWithValues = map.collect {
case (fieldName, Some(value)) =>
NodeSelector(model,
model.getScalarFieldByName_!(fieldName),
GCAnyConverter(model.getFieldByName_!(fieldName).typeIdentifier, isList = false).toGCValue(value).get)
} getOrElse {
throw APIErrors.NullProvidedForWhereError(model.name)
}

uniquesWithValues.size match {
case 0 => throw APIErrors.NullProvidedForWhereError(model.name)
case 1 => uniquesWithValues.head
case _ => throw APIErrors.TwoManyUniquesForWhereError(model.name)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.prisma.api.filters.nonEmbedded

import com.prisma.IgnoreMongo
import com.prisma.api.ApiSpecBase
import com.prisma.shared.models.Project
import com.prisma.shared.schema_dsl.SchemaDsl
import org.scalatest.{FlatSpec, Matchers}

class WhereUniqueSpec extends FlatSpec with Matchers with ApiSpecBase {

val project: Project = SchemaDsl.fromStringV11() { """
|type User {
| id: ID! @id
| unique: Int! @unique
| email: String! @unique
|}""" }

database.setup(project)

server
.query(
s"""mutation{createUser(
| data: {
| unique:2,
| email: "[email protected]"
|})
|{id}
|}
""",
project
)

// We cannot express that we expect exactly one field in the WhereUniqueInput in GraphQL, we therefore will error at runtime
// and hint at the correct way to use the api

"Providing 0 unique fields" should "error" in {
server.queryThatMustFail(
s"""query{user(where: {}){unique}}""",
project,
errorCode = 3040,
errorContains = """You provided an invalid argument for the where selector on User. Please provide exactly one unique field and value."""
)
}

"Providing 1 unique field" should "work" in {
server.query(s"""query{user(where: {email: "[email protected]"}){unique}}""", project).toString should be("""{"data":{"user":{"unique":2}}}""")
}

"Providing more than 1 unique field" should "error" in {
server.queryThatMustFail(
s"""query{user(where: {id:"wrong", email: "[email protected]"}){unique}}""",
project,
errorCode = 3045,
errorContains =
"""You provided more than one field for the unique selector on User. If you want that behavior you can use the many query and combine fields with AND / OR."""
)
}

"Using two unique fields with the many query" should "work with an implicit AND" in {
server.query(s"""query{users(where: {unique:2, email: "[email protected]"}){unique}}""", project).toString should be("""{"data":{"users":[{"unique":2}]}}""")
}

"Using two unique fields with the many query" should "work with an explicit AND" in {
server.query(s"""query{users(where: {AND: [{unique:2}, {email: "[email protected]"}]}){unique}}""", project).toString should be(
"""{"data":{"users":[{"unique":2}]}}""")
}

"Using two unique fields with the many query" should "work with an explicit OR" taggedAs (IgnoreMongo) in {
server.query(s"""query{users(where: {OR: [{unique:2}, {email: "does not exist"}]}){unique}}""", project).toString should be(
"""{"data":{"users":[{"unique":2}]}}""")
}

"Using two unique fields with the many query" should "work with an explicit OR 2" taggedAs (IgnoreMongo) in {
server.query(s"""query{users(where: {OR: [{unique:24235}, {email: "[email protected]"}]}){unique}}""", project).toString should be(
"""{"data":{"users":[{"unique":2}]}}""")
}
}

0 comments on commit 122302e

Please sign in to comment.