From 3b0ac0e820a41df9aea3d026bd8675f2df7cc9f0 Mon Sep 17 00:00:00 2001 From: Tobias Lindaaker Date: Thu, 13 Apr 2017 13:47:14 +0200 Subject: [PATCH 1/2] Specify how Map Projections work in Cypher --- .../CIP2017-02-07-Map-Projection.adoc | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 cip/1.accepted/CIP2017-02-07-Map-Projection.adoc diff --git a/cip/1.accepted/CIP2017-02-07-Map-Projection.adoc b/cip/1.accepted/CIP2017-02-07-Map-Projection.adoc new file mode 100644 index 0000000000..3ffe6e451d --- /dev/null +++ b/cip/1.accepted/CIP2017-02-07-Map-Projection.adoc @@ -0,0 +1,121 @@ += CIP2017-02-07 Map Projection +:numbered: +:toc: +:toc-placement: macro +:source-highlighter: codemirror + +*Author:* Tobias Lindaaker + +toc::[] + +== Map Projection + +Map projection takes a map or entity (node or relationship) and creates a map based on selected properties from map or entity. +The map projection largely reuses the map syntax of curly braces and comma separated entries. +But the projection entries are just a single identifier starting with a dot (.). +The projected map entries use the same key in the projected map as in the source map. + +The following example: + +[source, cypher] +---- +someMap {.alpha, .beta} +---- + +is thus equivalent to: + +[source, cypher] +---- +{alpha: someMap.alpha, beta: someMap.beta} +---- + +In order to be further useful, map projection allow other types of selectors to augment the projected map. + +Projected maps are also allowed as a `ReturnItem` in the `RETURN` and `WITH` clauses, in this case the projected map occurs without a preceding variable and instead projects variables from the current scope into a map. +While both _property selectors_ and _variable selectors_ are syntactically allowed in this case, the semantics of both of these selectors are equivalent. + +=== Selectors + +There are four different types of entries allowed in a map projection: + +• *Property selector* - includes a property from the original map into the projected map using the same key in the projected map as in the original map. + This selector optionally also allows further projection of a nested map, if the selected property is a map or entity. +• *Variable selector* - includes an entry into the projected map based on a variable in the current scope. + The key for the entry in the projected map will be the same as the name of the variable. + This selector optionally also allows further projection of a nested map, if the selected variable is a map or entity. +• *Literal entry* - includes a entry into the projected map using the regular map entry syntax, i.e. with the value being explicitly different from the key. + In this case the value can be any arbitrary expression, just like in a regular map literal. +• *All properties selector* - includes all properties from the original map or entity into the projected map. + + The all properties selector also allows marking properties for exclusion that would otherwise have been included by the selector. + + If any properties explicitly stated in the map projection through another selector type conflicts with a property in the original map, the explicitly stated entry takes precedence and the value from that expression overrides the value from the original map. + +Note that while it is typically superfluous to use both an _all properties selector_ and explicit _property selectors_, this is syntactically allowed. +Sometimes this might be the most convenient way to express the desired projection, since the explicit _property selector_ allows further projection of the nested property, and this value takes precedence over the _all properties selector_. + +=== Syntax + +The EBNF syntax of map projection takes the following place in the Cypher syntax: + +[source, ebnf] +---- +Atom = … | MapProjection | … ; + +MapProjection = Variable, ProjectedMap ; + +ProjectedMap = '{', (AllPropertiesSelector | ProjectionEntry), {',', ProjectionEntry}, '}' ; + +ProjectionEntry = LiteralEntry + | PropertySelector + | VariableSelector + ; +LiteralEntry = PropertyKeyName, ':', Expression ; +PropertySelector = '.', PropertyKeyName, [ProjectedMap] ; +VariableSelector = Variable, [ProjectedMap] ; +AllPropertiesSelector = '*', {'-', PropertyKeyName} ; + +ReturnItem = Expression + | (Expression, 'AS', Variable) + | (ProjectedMap, 'AS', Variable) + ; +---- + +=== Examples + +[source, cypher] +.Fetch name and address for a person +---- +MATCH (person:Person{userId=$user})-[:ADDRESS]->(address) +RETURN person {.firstName, .lastName, id: $user, + address {.streetAddress, .city, .postalCode} } +---- + +.Example result +---- ++----------------------------------------------------------------------------------------+ +| person | ++----------------------------------------------------------------------------------------+ +| {firstName: "Sherlock", lastName: "Holmes", id: "0099CC", | +| address: {streetAddress: "221B Baker Street", city: "London", postalCode: "NW1 6XE"}} | ++----------------------------------------------------------------------------------------+ +---- + +[source, cypher] +.Bind variables into a map +---- +MATCH (group:Group{name:$groupName})<-[:MEMBER_OF]-(member)-[:KNOWS]-(friend)-[:ADDRESS]->(address) +RETURN member.name, collect( {friend{.name},address{.city}} ) AS friends +---- + +.Example result +---- ++-------------+---------------------------------------------------------------+ +| member.name | friends | ++-------------+---------------------------------------------------------------+ +| John Doe | • {friend: {name:"Heather Taylor"}, address:{city:"Miami"}} | +| | • {friend: {name:"Leroy Jenkins"}, address:{city:"New York"}} | ++-------------+---------------------------------------------------------------+ +| Eve Longman | • {friend: {name:"Mickey Mouse"}, address:{city:"Orlando"}} | +| | • {friend: {name:"Leroy Jenkins"}, address:{city:"New York"}} | +| | • {friend: {name:"Minnie Mouse"}, address:{city:"Orlando"}} | ++-------------+---------------------------------------------------------------+ +---- From d01aadd892d4e1db957352b1fd2286064ebcd9ca Mon Sep 17 00:00:00 2001 From: Tobias Lindaaker Date: Tue, 18 Apr 2017 18:15:42 +0200 Subject: [PATCH 2/2] Stylistic changes for the style gods --- .../CIP2017-02-07-Map-Projection.adoc | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/cip/1.accepted/CIP2017-02-07-Map-Projection.adoc b/cip/1.accepted/CIP2017-02-07-Map-Projection.adoc index 3ffe6e451d..93d5ff6e4d 100644 --- a/cip/1.accepted/CIP2017-02-07-Map-Projection.adoc +++ b/cip/1.accepted/CIP2017-02-07-Map-Projection.adoc @@ -10,9 +10,8 @@ toc::[] == Map Projection -Map projection takes a map or entity (node or relationship) and creates a map based on selected properties from map or entity. -The map projection largely reuses the map syntax of curly braces and comma separated entries. -But the projection entries are just a single identifier starting with a dot (.). +Map projection takes a map or entity (node or relationship) and creates a map based on selected properties from that map or entity. +The map projection largely reuses the map syntax of curly braces and comma separated entries, with the exception that the projection entries only use a single identifier starting with a dot (`.`). The projected map entries use the same key in the projected map as in the source map. The following example: @@ -29,7 +28,7 @@ is thus equivalent to: {alpha: someMap.alpha, beta: someMap.beta} ---- -In order to be further useful, map projection allow other types of selectors to augment the projected map. +In order to be further useful, map projections allow other types of selectors (see section on "Selectors" below) to augment the projected map. Projected maps are also allowed as a `ReturnItem` in the `RETURN` and `WITH` clauses, in this case the projected map occurs without a preceding variable and instead projects variables from the current scope into a map. While both _property selectors_ and _variable selectors_ are syntactically allowed in this case, the semantics of both of these selectors are equivalent. @@ -58,7 +57,7 @@ The EBNF syntax of map projection takes the following place in the Cypher syntax [source, ebnf] ---- -Atom = … | MapProjection | … ; +Atom = ... | MapProjection | ... ; MapProjection = Variable, ProjectedMap ; @@ -84,7 +83,7 @@ ReturnItem = Expression [source, cypher] .Fetch name and address for a person ---- -MATCH (person:Person{userId=$user})-[:ADDRESS]->(address) +MATCH (person:Person {userId:$user})-[:ADDRESS]->(address) RETURN person {.firstName, .lastName, id: $user, address {.streetAddress, .city, .postalCode} } ---- @@ -94,28 +93,28 @@ RETURN person {.firstName, .lastName, id: $user, +----------------------------------------------------------------------------------------+ | person | +----------------------------------------------------------------------------------------+ -| {firstName: "Sherlock", lastName: "Holmes", id: "0099CC", | -| address: {streetAddress: "221B Baker Street", city: "London", postalCode: "NW1 6XE"}} | +| {firstName: 'Sherlock', lastName: 'Holmes', id: '0099CC', | +| address: {streetAddress: '221B Baker Street', city: 'London', postalCode: 'NW1 6XE'}} | +----------------------------------------------------------------------------------------+ ---- [source, cypher] .Bind variables into a map ---- -MATCH (group:Group{name:$groupName})<-[:MEMBER_OF]-(member)-[:KNOWS]-(friend)-[:ADDRESS]->(address) -RETURN member.name, collect( {friend{.name},address{.city}} ) AS friends +MATCH (group:Group {name: $groupName})<-[:MEMBER_OF]-(member)-[:KNOWS]-(friend)-[:ADDRESS]->(address) +RETURN member.name, collect({friend{.name}, address{.city}}) AS friends ---- .Example result ---- -+-------------+---------------------------------------------------------------+ -| member.name | friends | -+-------------+---------------------------------------------------------------+ -| John Doe | • {friend: {name:"Heather Taylor"}, address:{city:"Miami"}} | -| | • {friend: {name:"Leroy Jenkins"}, address:{city:"New York"}} | -+-------------+---------------------------------------------------------------+ -| Eve Longman | • {friend: {name:"Mickey Mouse"}, address:{city:"Orlando"}} | -| | • {friend: {name:"Leroy Jenkins"}, address:{city:"New York"}} | -| | • {friend: {name:"Minnie Mouse"}, address:{city:"Orlando"}} | -+-------------+---------------------------------------------------------------+ ++-------------+------------------------------------------------------------------+ +| member.name | friends | ++-------------+------------------------------------------------------------------+ +| John Doe | • {friend: {name: 'Heather Taylor'}, address: {city: 'Miami'}} | +| | • {friend: {name: 'Leroy Jenkins'}, address: {city: 'New York'}} | ++-------------+------------------------------------------------------------------+ +| Eve Longman | • {friend: {name: 'Mickey Mouse'}, address: {city: 'Orlando'}} | +| | • {friend: {name: 'Leroy Jenkins'}, address: {city: 'New York'}} | +| | • {friend: {name: 'Minnie Mouse'}, address: {city: 'Orlando'}} | ++-------------+------------------------------------------------------------------+ ----