Why am I doing this?
One of the most awesomest things about F# is Type Providers. There are Type Providers for, like, everything. A while ago I found a Neo4j Type Provider built by Pete Bayne, who was kind enough to help me a bit when I was having trouble getting the code to compile. I did end up making some small changes to get it to work. Here is how I did it.
I will outline the changes I made, example usage, and some tests I wrote using the Type Provider.
The source code
You can get the original source code on Pete Bayne's BitBucket.
Read about it on this blog post.
Pete used Readify's Neo4jClient to query the database. This was great because I am familiar with that client and so I could follow the code pretty easily. Phew! I might actually understand what is going on.
At first I couldn't get it to compile, but I tweeted Pete and he said I should make sure that Neo4j was running. I did this, felt really dumb, and got a lot further. I was almost there. The next problem was syntax. Neo4j was telling me that the parens were required, like this:
Parentheses are required to identify nodes in patterns, i.e. (n) (line 1, column 7 (offset: 6))
"MATCH n RETURN n LIMIT 25"
So I made the following changes to the graph module.
The changes are on the left and the original is on the right.
I got it to compile. Now I can try using it. I was so excited!
Using the type provider
I cloned from Pete's repo on BitBucket and pushed it onto my Github. You can find tests using the Type Provider in my GraphIVR project. I will talk about how I used it in my GraphIVR project in my next post. Here I will give some examples of using the Type Provider alone.
First you need to instantiate the type like this.
[<Literal>]
let ConnectionString = @"http://localhost:7474/db/data" //the db should be populated
type IVRSchema = Haumohio.Neo4j.Schema< ConnectionString >
You can get at your graph's labels like this (see my previous post on the IVR graph).
let startLabel = IVRSchema.Labels.START
You can get at a label's property fields like this.
let endIdField = IVRSchema.Props.END.id
You can get at a relationship type like this.
let successRelationship = IVRSchema.Rels.SUCCESS
You can get at a node as an object like this.
let entryNode = IVRSchema.Proxies.ENTRY
Putting it all together you can do something like this to get a list of related nodes. In this case the path is from an entry node to the next entry node through the success relationship. Here I am using Neo4jClient.
type IVRSchema = Haumohio.Neo4j.Schema< ConnectionString >
let db = new Neo4jClient.GraphClient(Uri(ConnectionString))
db.Connect()
let data =
db.Cypher
.Match(sprintf "(s:%s)-[r:%s]->(e:%s)" IVRSchema.Labels.START IVRSchema.Rels.GOTO IVRSchema.Labels.ENTRY)
.Return(fun (s:ICypherResultItem) (e:ICypherResultItem) -> (s.As<IVRSchema.Proxies.START>(), e.As<IVRSchema.Proxies.ENTRY>()))
.Results
let sNode, eNode = data |> Seq.head
Thoughts
This is a nice way to work with your database's schema and it will naturally update as the source database changes.
I |> heart TypeProviders
Full Stack .NET Programmer and Ham