Cypherスタイルガイド

出典：https://neo4j.com/docs/cypher-manual/current/styleguide/

:::note
この付録には、Cypherクエリを作成する際の推奨スタイルを記載しています。
:::

この付録では、次の内容について説明します。
* 一般的な推奨事項
* インデントと改行
* 大文字/小文字
* スペース
* パターン
* メタ文字

スタイルガイドの目的は、コードをできるだけ読みやすくし、保守コストの削減に貢献することです。
ラベル、リレーションシップのタイプ、プロパティの命名規則と推奨事項については、[命名規則と推奨事項](https://neo4j.com/docs/cypher-manual/current/syntax/naming/)を参照してください。

# 一般的な推奨事項
* Cypher構文を散文で記述する場合は、モノスペースフォントを使用し、スタイルガイドに従ってください。
> Clean Codeはシンプルで直接的なもの。Clean Codeは散文のようなコードだ -- Grady Booch. 
* ラベルおよびリレーションシップタイプを参照する場合は、`:`を含めてください。
例：`:Label`、`:REL_TYPE`
* 関数を参照する場合は、キャメルケースを使用し、`()`を使用します。引数は通常含みません。
例：`:shortestPath()`
* Cypher文を別ファイルに保存する場合は、拡張子`.cypher`を使用します。

# インデントと改行
* 新しい句は新しい行で開始します。

```Cypher:BAD
MATCH(n)WHERE n.name CONTAINS's'RETURN n.name
```
```Cypher:GOOD
MATCH (n)
WHERE n.name CONTAINS 's'
RETURN n.name
```
* `ON CREATE`と`ON MATCH`は半角スペース2個でインデントします。`ON CREATE`と`ON MATCH`の両方が存在する場合は、`ON CREATE`を先に記述します。
```Cypher:BAD
MERGE (n) ON CREATE SET n.prop = 0
MERGE (a:A)-[:T]-(b:B)
ON MATCH SET b.name = 'you'
ON CREATE SET a.name = 'me'
RETURN a.prop
```
```Cypher:GOOD
MERGE (n)
  ON CREATE SET n.prop = 0
MERGE (a:A)-[:T]-(b:B)
  ON CREATE SET a.name = 'me'
  ON MATCH SET b.name = 'you'
RETURN a.prop
```
* サブクエリは`{`の後に記述しますが、新しい行で半角スペース2個分インデントします。`}`は単独で記述します。
```Cypher:BAD
//例1
MATCH (a:A)
WHERE
  EXISTS { MATCH (a)-->(b:B) WHERE b.prop = $param }
RETURN a.foo

//例2
MATCH (a:A)
WHERE EXISTS
{MATCH (a)-->(b:B)
WHERE b.prop = $param}
RETURN a.foo
```
```Cypher:GOOD
MATCH (a:A)
WHERE EXISTS {
  MATCH (a)-->(b:B)
  WHERE b.prop = $param
}
RETURN a.foo
```

* 簡易サブクエリは改行しないでください。
```Cypher:BAD
MATCH (a:A)
WHERE EXISTS {
  (a)-->(b:B)
}
RETURN a.prop
```
```Cypher:GOOD
MATCH (a:A)
WHERE EXISTS { (a)-->(b:B) }
RETURN a.prop
```

# 小文字/大文字の使い分け
* キーワードは大文字で記述します。
```Cypher:BAD
match (p:Person)
where p.name starts with 'Ma'
return p.name
```
```Cypher:GOOD
MATCH (p:Person)
WHERE p.name STARTS WITH 'Ma'
RETURN p.name
```

* NULL値は小文字で記述します。
```Cypher:BAD
WITH NULL AS n1, Null AS n2
RETURN n1 IS NULL AND n2 IS NOT NULL
```
```Cypher:GOOD
WITH null AS n1, null as n2
RETURN n1 IS NULL AND n2 IS NOT NULL
```

* ブールリテラル(`true`および`false`)は小文字で記述します。
```Cypher:BAD
WITH TRUE AS b1, False AS b2
RETURN b1 AND b2
```
```Cypher:GOOD
WITH true AS b1, false AS b2
RETURN b1 AND b2
```

* 次の場合はキャメルケースを使用します。
  * 関数
  * プロパティ
  * 変数
  * パラメータ
```Cypher:BAD
CREATE (N {Prop: 0})
WITH RAND() AS Rand, $pArAm AS MAP
RETURN Rand, MAP.property_key, Count(N)
```
```Cypher:GOOD
CREATE (n {prop: 0})
WITH rand() AS rand, $param AS map
RETURN rand, map.propertyKey, count(n)
```
# スペース
* リテラルマップの場合:
  * `{`と最初のキーの間にはスペースを入れません。
  * キーと`:`の間にはスペースを入れません。
  * `:`と値の間にはスペースを入れます。
  * 値と`:`の間にはスペースを入れません。
  * `,`と次のキーの間にはスペースを入れます。
  * 最後の値と`}`の間にはスペースを入れません。

```Cypher:BAD
WITH { key1 :'value' ,key2  :  42 } AS map
RETURN map
```
```Cypher:GOOD
WITH {key1: 'value', key2: 42} AS map
RETURN map
```

* パターン内のラベル/タイプ述部とプロパティ述部の間には、1つのスペースを入れます。
```Cypher:BAD
MATCH (p:Person{property: -1})-[:KNOWS   {since: 2016}]->()
RETURN p.name
```
```Cypher:GOOD
MATCH (p:Person {property: -1})-[:KNOWS {since: 2016}]->()
RETURN p.name
```
* パターンにスペースは入れません。
```Cypher:BAD
MATCH (:Person) --> (:Vehicle)
RETURN count(*)
```
```Cypher:GOOD
MATCH (:Person)-->(:Vehicle)
RETURN count(*)
```

* 演算子の前後はスペースで覆います。
```Cypher:BAD
MATCH p=(s)-->(e)
WHERE s.name<>e.name
RETURN length(p)
```
```Cypher:GOOD
MATCH p = (s)-->(e)
WHERE s.name <> e.name
RETURN length(p)
```

* ラベル述部にスペースは入れません。
```Cypher:BAD
MATCH (person    : Person  :  Owner  )
RETURN person.name
```
```Cypher:GOOD
MATCH (person:Person:Owner)
RETURN person.name
```

* リストおよび列挙では、各`,`の後にスペースを使用します。
```Cypher:BAD
MATCH (),()
WITH ['a','b',3.14] AS list
RETURN list,2,3,4
```
```Cypher:GOOD
MATCH (), ()
WITH ['a', 'b', 3.14] AS list
RETURN list, 2, 3, 4
```

* 関数呼び出し括弧内にパディングスペースは入れません。
```Cypher:BAD
RETURN split( 'original', 'i' )
```
```Cypher:GOOD
RETURN split('original', 'i')
```
* 簡易サブクエリ式ではパディングスペースを使用します。
```Cypher:BAD
MATCH (a:A)
WHERE EXISTS {(a)-->(b:B)}
RETURN a.prop
```
```Cypher:GOOD
MATCH (a:A)
WHERE EXISTS { (a)-->(b:B) }
RETURN a.prop
```

# パターン
* パターンの途中で改行する場合は、矢印の後で行います。
```Cypher:BAD
MATCH (:Person)-->(vehicle:Car)-->(:Company)
      <--(:Country)
RETURN count(vehicle)
```
```Cypher:GOOD
MATCH (:Person)-->(vehicle:Car)-->(:Company)<--
      (:Country)
RETURN count(vehicle)
```

* 変数を使用しない場合は、匿名ノードとリレーションシップを使用します。
```Cypher:BAD
CREATE (a:End {prop: 42}),
       (b:End {prop: 3}),
       (c:Begin {prop: id(a)})
```
```Cypher:GOOD
CREATE (a:End {prop: 42}),
       (:End {prop: 3}),
       (:Begin {prop: id(a)})
```

* 繰り返し変数を避けるために、パターンを連結します。
```Cypher:BAD
MATCH (:Person)-->(vehicle:Car), (vehicle:Car)-->(:Company)
RETURN count(vehicle)
```
```Cypher:GOOD
MATCH (:Person)-->(vehicle:Car)-->(:Company)
RETURN count(vehicle)
```

* 名前付きノードは匿名ノードの前に配置します。
```Cypher:BAD
MATCH ()-->(vehicle:Car)-->(manufacturer:Company)
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
```
```Cypher:GOOD
MATCH (manufacturer:Company)<--(vehicle:Car)<--()
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
```

* アンカーノードは`MATCH`句の先頭に置きます。
```Cypher:BAD
MATCH (:Person)-->(vehicle:Car)-->(manufacturer:Company)
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
```
```Cypher:GOOD
MATCH (manufacturer:Company)<--(vehicle:Car)<--(:Person)
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
```

* リレーションシップのパターンは、左から右向きのものを優先します。
```Cypher:BAD
MATCH (:Country)-->(:Company)<--(vehicle:Car)<--(:Person)
RETURN vehicle.mileage
```
```Cypher:GOOD
MATCH (:Person)-->(vehicle:Car)-->(:Company)<--(:Country)
RETURN vehicle.mileage
```

# メタ文字
* リテラル文字列値には`'`を使用します。
```Cypher:BAD
RETURN "Cypher"
```
```Cypher:GOOD
RETURN 'Cypher'
```

ただし、`'`を含むリテラル文字列の場合は、このルールを無視します。文字列に`'` ,`"`の文字が含まれる場合、エスケープ`\`の数が最も少なくなるよう記述します。タイの場合は、`'`を使用します。
```Cypher:BAD
RETURN 'Cypher\'s a nice language', "Mats' quote: \"statement\""
```
```Cypher:GOOD
RETURN "Cypher's a nice language", 'Mats\' quote: "statement"'
```

* 文字やキーワードをエスケープするために`` ` ``を使用する必要はありません。
```Cypher:BAD
MATCH (`odd-ch@racter$`:`Spaced Label` {`&property`: 42})
RETURN labels(`odd-ch@racter$`)
```
```Cypher:GOOD
MATCH (node:NonSpacedLabel {property: 42})
RETURN labels(node)
```

* 文の末尾にセミコロンを使用しないでください。
```Cypher:BAD
RETURN 1;
```
```Cypher:GOOD
RETURN 1
```