Last active
January 23, 2016 16:08
-
-
Save OkayX6/c89c2c499940d99d2767 to your computer and use it in GitHub Desktop.
Neo4j simplified query AST in F# - Prototype - Non compileable!!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| open Neo4jClient | |
| let client = new GraphClient(Uri("http://localhost:7474/db/data"), "login", "password") | |
| client.Connect() | |
| // Using Neo4jKey attribute to identify Node "primary key" | |
| let getUserNodeUsingPredefinedKey (id: string) = | |
| let userVar = Var.Make<UserNode>(Some "user", id) // This is how to define it | |
| let query = | |
| ReadQuery.Create( | |
| // Matches | |
| MatchClause.Create([Node userVar]), | |
| // Optional Matches | |
| MatchClause.Create([]), | |
| // Return expr | |
| <@ fun (user: ICypherResultItem) -> user.As<UserNode>() @>) | |
| client.Cypher | |
| |> ReadQuery.Execute query | |
| |> Seq.item 0 | |
| let getUserNodeUsingWhereClause (id: string) = | |
| let userVar = Var.Make<UserNode>("user") | |
| let query = | |
| ReadQuery.Create( | |
| // Matches | |
| MatchClause.Create( | |
| [Node userVar], | |
| <@ fun (user: UserNode) -> user.FacebookId = id @>), // WHERE clause of the MATCH | |
| // Optional Matches | |
| MatchClause.Create([]), | |
| // Return expr | |
| <@ fun (user: ICypherResultItem) -> user.As<UserNode>() @>) | |
| client.Cypher | |
| |> ReadQuery.Execute query | |
| |> Seq.item 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| type Neo4jKeyAttribute() = | |
| inherit Attribute() | |
| [<CLIMutable>] | |
| type UserNode = | |
| { [<Neo4jKey>] FacebookId : string } | |
| type Var = | |
| { Name: Option<string> | |
| Type: Option<Type> | |
| Key: Option<string * obj> } | |
| static member Make<'T>() = | |
| { Name = None | |
| Type = Some typeof<'T> | |
| Key = None } | |
| static member Make<'T>(name: string) = | |
| { Name = Some name | |
| Type = Some typeof<'T> | |
| Key = None } | |
| static member Make<'T>(name: Option<string>, keyValue: obj) = | |
| { Name = name | |
| Type = Some typeof<'T> | |
| Key = Some (Cypher.getNeo4jKeyName(typeof<'T>), keyValue) } | |
| member x.GenerateMatchExpr() = | |
| [| | |
| x.Name |> Option.defaultOrGet "" | |
| x.Type |> Option.defaultOrApply (fun typ -> (+) ":" typ.Name) "" | |
| x.Key |> Option.defaultOrApply (fun (name, value) -> sprintf " {%s:%A}" name value) "" | |
| |] | |
| |> String.concat "" | |
| type GraphElt = | |
| | Node of node:Var | |
| | RelToRight of src:Var * relation:Var * dest:Var | |
| | RelToLeft of dest:Var * relation:Var * src:Var | |
| member x.GenerateMatchExpr() = | |
| match x with | |
| | Node v -> sprintf "(%s)" (v.GenerateMatchExpr()) | |
| | RelToRight(v1, rel, v2) -> | |
| sprintf "(%s)-[%s]->(%s)" (v1.GenerateMatchExpr()) (rel.GenerateMatchExpr()) (v2.GenerateMatchExpr()) | |
| | RelToLeft(v1, rel, v2) -> | |
| sprintf "(%s)<-[%s]-(%s)" (v1.GenerateMatchExpr()) (rel.GenerateMatchExpr()) (v2.GenerateMatchExpr()) | |
| type MatchClause private | |
| (matches: GraphElt list, whereGenerator: (ICypherFluentQuery -> ICypherFluentQuery) option) = | |
| member val Matches = matches | |
| member val WhereGenerator = whereGenerator | |
| static member Create(matches: GraphElt list) = | |
| MatchClause(matches, None) | |
| static member Create(matches: GraphElt list, whereMatches: Expr<'T1 -> bool>) = | |
| MatchClause(matches, Some (fun q -> q.Where(toLambdaExpression<Func<'T1,_>> whereMatches))) | |
| static member Create(matches: GraphElt list, whereMatches: Expr<'T1 -> 'T2 -> bool>) = | |
| MatchClause(matches, Some (fun q -> q.Where(toLambdaExpression<Func<'T1,'T2,_>> whereMatches))) | |
| static member Create(matches: GraphElt list, whereMatches: Expr<'T1 -> 'T2 -> 'T3 -> bool>) = | |
| MatchClause(matches, Some (fun q -> q.Where(toLambdaExpression<Func<'T1,'T2,'T3,_>> whereMatches))) | |
| static member Create(matches: GraphElt list, whereMatches: Expr<'T1 -> 'T2 -> 'T3 -> 'T4 -> bool>) = | |
| MatchClause(matches, Some (fun q -> q.Where(toLambdaExpression<Func<'T1,'T2,'T3,'T4,_>> whereMatches))) | |
| type ReadQuery<'TRes> = | |
| // [MATCH WHERE] | |
| // [OPTIONAL MATCH WHERE] | |
| // [WITH [ORDER BY] [SKIP] [LIMIT]] | |
| // RETURN [ORDER BY] [SKIP] [LIMIT] | |
| private Query of | |
| matchClause: MatchClause * | |
| optionalMatchClause: MatchClause * | |
| returnExpr: Expr | |
| with | |
| static member Create(matchClause, optMatchClause, returnExpr: Expr<ICypherResultItem -> 'TRes>) = | |
| ReadQuery<'TRes>.Query(matchClause, optMatchClause, returnExpr) | |
| static member Create(matchClause, optMatchClause, returnExpr: Expr<ICypherResultItem -> ICypherResultItem -> 'TRes>) = | |
| ReadQuery<'TRes>.Query(matchClause, optMatchClause, returnExpr) | |
| static member Create(matchClause, optMatchClause, returnExpr: Expr<ICypherResultItem -> ICypherResultItem -> ICypherResultItem -> 'TRes>) = | |
| ReadQuery<'TRes>.Query(matchClause, optMatchClause, returnExpr) | |
| static member Create(matchClause, optMatchClause, returnExpr: Expr<ICypherResultItem -> ICypherResultItem -> ICypherResultItem -> ICypherResultItem -> 'TRes>) = | |
| ReadQuery<'TRes>.Query(matchClause, optMatchClause, returnExpr) | |
| static member Create(matchClause, optMatchClause, returnExpr: Expr<ICypherResultItem -> ICypherResultItem -> ICypherResultItem -> ICypherResultItem -> ICypherResultItem -> 'TRes>) = | |
| ReadQuery<'TRes>.Query(matchClause, optMatchClause, returnExpr) | |
| static member Execute (query: ReadQuery<'TRes>) (cypher: ICypherFluentQuery) = | |
| let (Query(matchClause, optMatchClause, returnExpr)) = query | |
| let argNames = getReturnExprArgNames returnExpr | |
| let argCount = argNames.Length | |
| let generateReturnExpr = (returnOverloads<'TRes>()).[argCount] | |
| let allMatchVarNames: Set<string> = | |
| Set.union | |
| (getAllMatchVarNames matchClause) | |
| (getAllMatchVarNames optMatchClause) | |
| if not <| Set.isSubset (Set.ofArray argNames) allMatchVarNames then | |
| invalidArg "query" "The return expression contains variables that are not in your match clause" | |
| cypher | |
| |> generateMatchExpr matchClause | |
| |> generateWhereExpr matchClause | |
| |> generateMatchExpr optMatchClause | |
| |> generateWhereExpr optMatchClause | |
| |> generateReturnExpr returnExpr | |
| |> Cypher.getResults |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment