Giter Site home page Giter Site logo

dapper-magician / neo4j-clj Goto Github PK

View Code? Open in Web Editor NEW

This project forked from gorillalabs/neo4j-clj

0.0 0.0 0.0 577 KB

Clojure bindings for Bolt / the Java Neo4j driver, complete with Joplin support for managing database migrations.

License: MIT License

Clojure 100.00%

neo4j-clj's Introduction

neo4j-clj

Clojuresque client to Neo4j database, based upon the bolt protocol.

Clojars Project Build Status Dependencies Status Downloads

neo4j-clj is a clojure client library to the Neo4j graph database, relying on the Bolt protocol.

Features

This library provides a clojuresque way to deal with connections, sessions, transactions and Cypher queries.

Status

neo4j-clj is in active use at our own projects, but it's not a feature complete client library in every possible sense.

You might choose to issue new feature requests, or clone the repo to add the feature and create a PR.

We appreciate any help on the open source projects we provide. See Development section below for more info on how to build your own version.

Example usage

Throughout the examples, we assume you're having a Neo4j instance up and running. See our Neo4j survival guide for help on that.

You can clone our repository and run the example for yourself.

(ns example.core
  (:require [neo4j-clj.core :as db])
  (:import (java.net URI)))

(def local-db
  (db/connect (URI. "bolt://localhost:7687")
              "neo4j"
              "YA4jI)Y}D9a+y0sAj]T5s|C5qX!w.T0#u<be5w6X[p"))

(db/defquery create-user
  "CREATE (u:user $user)")

(db/defquery get-all-users
  "MATCH (u:user) RETURN u as user")

(defn -main
  "Example usage of neo4j-clj"
  [& args]

  ;; Using a session
  (with-open [session (db/get-session local-db)]
    (create-user session {:user {:first-name "Luke" :last-name "Skywalker"}}))

  ;; Using a transaction
  (db/with-transaction local-db tx
    ;; print, as query result has to be consumed inside session
    (println (get-all-users tx))))

If you do run stuff on the REPL, make sure to consume the results from the query before closing session/transaction - like I did with println. Use doall or whatever suits you, because otherwise you'll run into issues.

In-depth look

Connection

First of all, you need to connect to the database.

(db/connect (URI. "bolt://localhost:7687") ; bolt API URI
            "neo4j" ; username
            "YA4jI)Y}D9a+y0sAj]T5s|C5qX!w.T0#u<be5w6X[p" ; password
)

Session

Everything on the Bolt protocol is organized in a session. neo4j-clj uses the standard with-open to handle lexical-scoped sessions.

(with-open [session (db/get-session local-db)]
  ;; ... use session here
  )

Transaction

neo4j-clj can also handle transactions (on top of sessions) by utilizing a with-transaction-macro.

(db/with-transaction local-db tx
   ;; run queries within transaction
)

local-db is the Neo4j instance you're connected to. tx is the symbol the transaction is bound to. You might use the tx transaction for query functions.

You do not need to have everything inside a with-transaction block, as all statements in a session are wrapped in transactions anyhow (see Sessions and Transactions).

You fail transactions by throwing an Exception.

Cypher queries

You create new queries using defquery. We strongly belief that using Cypher as a String directly in your code comes with a couple of advantages.

Both paramaters and return values are transformed from Clojure datastructures into Neo4j types. That transformation is done transparently, so you won't have to deal with that.

Parameters

For some / most queries you need to supply some parameters. Just include a variable into your Cypher query using the $ notation or the {} notation, and provide a Clojure map of variables to the query:

(db/defquery users-by-age "MATCH (u:User {age: $age}) RETURN u as user")
(users-by-age tx {:age 42})

is equivalent to

(db/defquery users-by-age "MATCH (u:User {age: {age}}) RETURN u as user")
(users-by-age tx {:age 42})

A query will always return a collection. Here, it will return ({:user {...}}), i.e. a collection of maps with the user-key populated.

Think of it as a map per result row.

You can have more than one parameter in your map:

(db/defquery create-user "CREATE (u:User {name: $name, age: $age})")
(create-user tx {:name "..." :age 42})

And you can also nest paramters:

(db/defquery create-user "CREATE (u:User $user)")
(create-user tx {:user {:name "..." :age 42}})

and un-nest them as necessary:

(db/defquery create-user "CREATE (u:User {name : {user}.name})")
(create-user tx {:user {:name "..." :age 42}})

Return values

The result of a query is a list, even if your query returns a single item. Each "result row" is one map in that sequence returned.

The values are provided using the ususal Clojure datastructures, no need to wrap/unwrap stuff. That's handled for you by neo4j-clj.

I'd like to elaborarte a little on the handling of node/edge labels. You can run a query labels like this:

(db/defquery get-users "MATCH (u:User) RETURN u as user,labels(u) as labels")
(get-users tx)

and this will return a collection of maps with two keys: user and labels where labels are a collection of labels associated with the nodes. At the moment, labels are not sets! It's up to you to convert collections into appropriate types yourself (because we just do not know on the neo4j-clj level), and this is especially true for labels.

Joplin integration

neo4j-clj comes equipped with support for Joplin for datastore migration and seeding.

As we do not force our users into Joplin dependencies, you have to add [joplin.core "0.3.10"] to your projects dependencies yourself.

Caveats

Neo4j cannot cope with dashes really well (you need to escape them), so the Clojure kebab-case style is not really acceptable.

Development

We appreciate any help on our open source projects. So, feel free to fork and clone this repository.

We use leiningen. So, after you've cloned your repo you should be able to run 'lein test' to run the tests sucessfully.

Testing

For testing purposes, we provide access to the Neo4j in-memory database feature, which we address using the bolt protocol.

To do so, you need to add a dependency to [org.neo4j.test/neo4j-harness "4.0.0"] to your project and require the neo4j-clj.in-memory namespace.

(def test-db
  (neo4j-clj.in-memory/create-in-memory-connection))
;; instead of (neo4j/connect url user password)

So, you can easily run tests on your stuff without requiring an external database.

neo4j-clj's People

Contributors

abhi18av avatar c-goetz avatar chrisbetz avatar cloojure avatar jenslehnhoff avatar maxlorenz avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.