Skip to content

Commit

Permalink
Merge pull request #357 from Mats-SX/escape-apostrophe
Browse files Browse the repository at this point in the history
Escape quotation marks in Cypher strings
  • Loading branch information
DarthMax authored Apr 19, 2018
2 parents 3d9a73b + 4e394ac commit dd3caba
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,31 +156,35 @@ object CypherValue {
*/
def toCypherString: String = {
this match {
case CypherString(s) => s"'$s'"
case CypherString(s) => s"'${escape(s)}'"
case CypherList(l) => l.map(_.toCypherString).mkString("[", ", ", "]")
case CypherMap(m) =>
m.toSeq
.sortBy(_._1)
.map { case (k, v) => s"$k: ${v.toCypherString}" }
.mkString("{", ", ", "}")
case CypherRelationship(_, _, _, relType, CypherMap(properties)) =>
case CypherRelationship(_, _, _, relType, props) =>
s"[:$relType${
if (properties.isEmpty) ""
else s" ${properties.toCypherString}"
if (props.isEmpty) ""
else s" ${props.toCypherString}"
}]"
case CypherNode(_, labels, CypherMap(properties)) =>
case CypherNode(_, labels, props) =>
val labelString =
if (labels.isEmpty) ""
else labels.toSeq.sorted.mkString(":", ":", "")
val propertyString = if (properties.isEmpty) ""
else s"${properties.toCypherString}"
val propertyString = if (props.isEmpty) ""
else s"${props.toCypherString}"
Seq(labelString, propertyString)
.filter(_.nonEmpty)
.mkString("(", " ", ")")
case _ => Objects.toString(value)
}
}

private def escape(str: String): String = {
str.replaceAllLiterally("'", "\\'").replaceAllLiterally("\"", "\\\"")
}

private[okapi] def isOrContainsNull: Boolean = isNull || {
this match {
case l: CypherList => l.value.exists(_.isOrContainsNull)
Expand Down Expand Up @@ -212,6 +216,8 @@ object CypherValue {
implicit class CypherMap(val value: Map[String, CypherValue]) extends AnyVal with MaterialCypherValue[Map[String, CypherValue]] {
override def unwrap: Map[String, Any] = value.map { case (k, v) => k -> v.unwrap }

def isEmpty: Boolean = value.isEmpty

def keys: Set[String] = value.keySet

def get(k: String): Option[CypherValue] = value.get(k)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@
* described as "implementation extensions to Cypher" or as "proposed changes to
* Cypher that are not yet approved by the openCypher community".
*/
package org.opencypher.okapi.api.value
package org.opencypher.spark.api.value

import org.opencypher.okapi.api.value.CypherValue._
import org.opencypher.spark.test.CAPSTestSuite
import org.opencypher.okapi.api.value.{CAPSNode, CAPSRelationship}
import org.opencypher.okapi.test.BaseTestSuite

class CAPSValueToStringTest extends CAPSTestSuite {
class CAPSValueToStringTest extends BaseTestSuite {

test("node") {
CAPSNode(1L, Set.empty, CypherMap.empty).toCypherString should equal("()")
Expand Down Expand Up @@ -64,4 +65,11 @@ class CAPSValueToStringTest extends CAPSTestSuite {
CypherMap("a" -> 1).toCypherString should equal("{a: 1}")
CypherMap("a" -> 1, "b" -> true).toCypherString should equal("{a: 1, b: true}")
}

test("should escape apostrophes in strings") {
CypherMap("street" -> "59 rue de l'Abbaye").toCypherString should equal("{street: '59 rue de l\\'Abbaye'}")
CypherMap("street" -> "59 rue de l\"Abbaye'").toCypherString should equal("{street: '59 rue de l\\\"Abbaye\\''}")
CAPSNode(1, Set.empty, CypherMap("street" -> "59 rue de l\"Abbaye'")).toCypherString should equal("({street: '59 rue de l\\\"Abbaye\\''})")
CAPSRelationship(1, 2, 3, "FOO", CypherMap("street" -> "59 rue de l\"Abbaye'")).toCypherString should equal("[:FOO {street: '59 rue de l\\\"Abbaye\\''}]")
}
}

0 comments on commit dd3caba

Please sign in to comment.