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

bnayae commented Jan 29, 2020

Copy link
Copy Markdown
Author
public static class PropFactory
{ 
    public static FluentCypher P<T>(
        Expression<Func<T, dynamic>>? with = null,
        Func<string, bool>? convention = null,
        Expression<Func<T, dynamic>>? exclude = null)
    {
        throw new NotImplementedException();
    }

    // Some naming problem because params array & optional parameter don't  mixed well
    public static FluentCypher P_<T>(params Expression<Func<T, dynamic>>[] exclude)
    {
        throw new NotImplementedException();
    }
    public string void Try()
    {
        P<IArgumentProvider>(with: f => f.ArgumentCount);
        P<IArgumentProvider>(convention: n => !n.StartsWith("X"));
        P<IArgumentProvider>(exclude: f => f.ArgumentCount);
        P_<TimeoutException>(f => f.Data, f => f.HelpLink);
    }
}

@bnayae

bnayae commented Jan 29, 2020

Copy link
Copy Markdown
Author

other option
public static class PropFactory
{
public static ICypherPropertiesBuilder P(
Expression<Func<T, dynamic>>? with = null,
Func<string, bool>? convention = null,
Expression<Func<T, dynamic>>? exclude = null)
{
throw new NotImplementedException();
}
public string void Try()
{
P(with: f => f.AmbientLabels).With(f => f.Concurrency.eTagName);
P(convention: n => !n.StartsWith("X")).With(f => f.Pluralization);
P(exclude: f => f.AmbientLabels.Values);
}
}
public interface ICypherPropertiesBuilder
{
ICypherPropertiesBuilder With(
Expression<Func<T, dynamic>> with);
ICypherPropertiesBuilder ByConvention(
Func<string, bool> convention);
FluentCypher All(
Expression<Func<T, dynamic>> exclude);
}

@bnayae

bnayae commented Jan 29, 2020

Copy link
Copy Markdown
Author
public static class P
{
    public static ICypherPropertiesBuilder<T> As<T>()
    {
        throw new NotImplementedException();
    }
}
class Tmp
{
    public void Temp()
    {
        P.As<ICypherConfig>().With(f => f.Concurrency.eTagName)
                             .With(f => f.AmbientLabels)
                             .ByConvention(n => n.StartsWith("eT"));
        P.As<ICypherConfig>().ByConvention(n => !n.StartsWith("X"))
                             .With(f => f.Pluralization);
        P.As<ICypherConfig>().All(exclude => exclude.AmbientLabels.Values);
    }
}

public interface ICypherPropertiesBuilder<T>
{
    ICypherPropertiesBuilder<T> With(
        Expression<Func<T, dynamic>> with);
    ICypherPropertiesBuilder<T> ByConvention(
        Func<string, bool> convention);
    FluentCypher All(
        Expression<Func<T, dynamic>> exclude);
}

@bnayae

bnayae commented Jan 29, 2020

Copy link
Copy Markdown
Author

.Scope(P.As().With(f => f.Concurrency.eTagName)
.With(f => f.AmbientLabels),
p => (n,Label, p)

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

@bnayae

bnayae commented Jan 29, 2020

Copy link
Copy Markdown
Author

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

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

@bnayae

bnayae commented Feb 2, 2020

Copy link
Copy Markdown
Author

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