Skip to content

Instantly share code, notes, and snippets.

@bnayae
Last active February 2, 2020 13:44
Show Gist options
  • Select an option

  • Save bnayae/df7c6a597c5e15b0f83426fc1e9fab26 to your computer and use it in GitHub Desktop.

Select an option

Save bnayae/df7c6a597c5e15b0f83426fc1e9fab26 to your computer and use it in GitHub Desktop.
Cypher Builder: Simple Statement

Option 1

.Pattern<Foo, Bar>((n , r) => n("n", "label", exclude: f => f.Name)) - r["r","type", convention: x => x != nameof(Bar.Date)] > n("n1")
.Pattern<Foo, Bar>((n , r) => n("n", "label", f => f.Name, f => f.Date)) - r["r","type", nameof(Foo.Date), nameof(Foo.Id)] > n("n1")

Option 2

.Pattern<Foo, Bar>((n , r) => n(n1 => n1.label, exclude: f => f.Name)) - r[r1 => r1.type, convention: x => x != nameof(Bar.Date)] > n("n1")

Option 3

Func<Foo, dynamics> exclude = f => f.Name;
var props = P.All<Foo>(exclude);
var relProps = {nameof(Foo.Date), nameof(Foo.Id)};
var n1 = C.Pattern("n", "label", props));
var r = C.Pattern.All((_, r) =>  r["r","type", relProps]);
var n2 = C.Pattern.Convention((n, _) => n(x2 => xs != "Date"));
var pattern = n1 - r > n2;

Option 4

Func<Foo, dynamics> exclude = f => f.Name;
Func<Foo, bool> convention = n => n != nameof(f.Date);
var props = P.All<Foo>(exclude);
var relProps = {nameof(Foo.Date), nameof(Foo.Id)};
var n1 = C.Pattern.Node("n", "Label").Exac(props);
var r = C.Pattern.Relation<Bar>["r"].All(n => n != nameof(Bar.Age));
var n2 = C.Pattern.Node<Foo>("n").Convention(convention);
var pattern = n1 - r > n2;

Option 5

Func<Foo, dynamics> exclude = f => f.Name;
Func<Foo, bool> convention = n => n != nameof(f.Date);
var props = P.All<Foo>(exclude);
var relProps = {nameof(Foo.Date), nameof(Foo.Id)};
var n1 = C.Node("n", "Label").Exac(props);
var r = C.Relation<Bar>["r"].All(n => n != nameof(Bar.Age));
var n2 = C.Node<Foo>("n").Convention(convention);
var pattern = n1 - r > n2;
@bnayae
Copy link
Author

bnayae commented Jan 29, 2020

(n,Label, P{eTagName, AmbientLabels} )

// cypher
(n:Label {n.eTagName = $eTagName, n.AmbientLabels = $AmbientLabels}

@bnayae
Copy link
Author

bnayae commented Feb 2, 2020

Properties requirements

Patterns

The properties pattern is also relevant for WHERE & SET (the pattern are same while the Cypher out come is different).
Some of the patterns may use generics.
The samples ahead will assume the existence of the following declarations:

        public static ILabel Person => throw new NotImplementedException();
        public static IType KNOWS => throw new NotImplementedException();
        public static IProperty PropA => throw new NotImplementedException();
        public static IProperty PropB => throw new NotImplementedException();

Specify array of names

// suggested API
P(n => N(n, Person, new {PropA, PropB} )  // CYPHER: (n:Person {PropA: $PropA, PropB: $PropB}
// with generic factory
P<Foo>(n => N(n, new {n.PropA, n.PropB} ) // the label is typeof(Foo).Name (this is the default when label doesn't declared )
P<Foo>(n => N(n, n.GetType, Person, new {n.PropA, n.PropB} ) // the label is n.GetType = typeof(Foo).Name + Person i.e. Foo:Person
P<Foo>(n => N(n, Person, new {n.PropA, n.PropB} ) // the label is  Person (ignore the generics auto label, the generic is used by the parameters)

Property materialization

The default form of property materialization (rendering) is:

P(n => N(n, Person, new {PropA, PropB} )  
CYPHER: (n:Person {PropA: $PropA, PropB: $PropB}

But there are other cases where the $ sign shouldn't be render like

UNWIND $items AS item
 (n:Person {PropA: item.PropA, PropB: item.PropB}

Prefix is another requirements, where the same property name appear multiple time but should map to different parameter:
Option 1:

P(n1 => n2 => n2_ => N(n, Person, new {PropA, PropB} )  - R[] > N(n2, Person, Pre(n2_,  new {PropA, PropB} )))
CYPHER: (n1:Person {PropA: $PropA, PropB: $PropB} - [] -> (n2:Person {PropA: $n2_PropA, PropB: $n2_PropB)

Option 2 (use value tuple):

P(n1 => n2 => n2_ => N(n, Person, new {PropA, PropB} )  - R[] > N(n2, Person,  new {(n2_, PropA), (n2_, PropB)} ))
CYPHER: (n1:Person {PropA: $PropA, PropB: $PropB} - [] -> (n2:Person {PropA: $n2_PropA, PropB: $n2_PropB)

Nested expression

// Reuse with scope (can be thought as nesting patterns)
P<Foo, Bar>(p => new {p1.PropA, p1.PropB},  // from Foo
                     p2 => new { p2.ProbC },                 // from Bar
                     n1 => n2 => N(n1, Person, p) - R[_, KNOWS] > N(n2, Person, p)
) // CYPHER: (n1:Person {PropA: $PropA, PropB: $PropB}) - [:KNOW] -> (n2:Person {PropA: $PropA, PropB: $PropB})

SET note

When the patterns apply to CREATE, MERGE, SET there are more options like

CREATE (n:Person $map) // entity parameter
MATCH (n:Person {Id: $map.Id})
SET n += $map

Combined with UNWIND

UNWIND $items AS item
MATCH (n:Person {Id: item.Id}) // NO $ SIGN
SET n += item

All / Exclude

Generics patterns can be used for mapping all Type's properties or most of them excluding a few

// Reuse with scope (can be thought as nesting patterns)
P<Foo>(n  => N(n, all: n, exclude: f => f.Id) 
// Or
P<Foo>(n  => N(n, ALL(exclude: f => f.Id)) 
) // CYPHER: (n:Foo {PropA: $PropA, PropB: $PropB}) // anything except Id

By Convention

Generics patterns can be used for mapping Type's properties by convention using delegate

// Reuse with scope (can be thought as nesting patterns)
P<Foo>(n  => N(n, convention: name => name.EndsWith("B") 
) // CYPHER: (n:Foo {PropB: $PropB}) // anything except Id

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment