{"id":24894796,"url":"https://github.com/gorillalabs/neo4j-clj","last_synced_at":"2025-05-16T13:05:13.179Z","repository":{"id":48560761,"uuid":"88048916","full_name":"gorillalabs/neo4j-clj","owner":"gorillalabs","description":"Clojure bindings for Bolt / the Java Neo4j driver, complete with Joplin support for managing database migrations.","archived":false,"fork":false,"pushed_at":"2025-03-26T13:43:42.000Z","size":603,"stargazers_count":94,"open_issues_count":3,"forks_count":14,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-16T13:05:09.863Z","etag":null,"topics":["bolt","clojure","neo4j","neo4j-driver"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gorillalabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-04-12T12:24:58.000Z","updated_at":"2025-04-06T18:39:29.000Z","dependencies_parsed_at":"2024-06-21T20:18:57.861Z","dependency_job_id":"d48bd8fe-fb14-40e3-881b-3b1276c337f5","html_url":"https://github.com/gorillalabs/neo4j-clj","commit_stats":{"total_commits":111,"total_committers":12,"mean_commits":9.25,"dds":0.5765765765765766,"last_synced_commit":"732ec67a35428b7b9812e037d1465c743216a8cd"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorillalabs%2Fneo4j-clj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorillalabs%2Fneo4j-clj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorillalabs%2Fneo4j-clj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorillalabs%2Fneo4j-clj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gorillalabs","download_url":"https://codeload.github.com/gorillalabs/neo4j-clj/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254535827,"owners_count":22087399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bolt","clojure","neo4j","neo4j-driver"],"created_at":"2025-02-01T19:14:35.842Z","updated_at":"2025-05-16T13:05:13.108Z","avatar_url":"https://github.com/gorillalabs.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# neo4j-clj\nClojuresque client to Neo4j database, based upon the bolt protocol.\n\n[![Clojars Project](https://img.shields.io/clojars/v/gorillalabs/neo4j-clj.svg)](https://clojars.org/gorillalabs/neo4j-clj)\n[![Build Status](https://travis-ci.org/gorillalabs/neo4j-clj.svg)](https://travis-ci.org/gorillalabs/neo4j-clj)\n[![Dependencies Status](https://versions.deps.co/gorillalabs/neo4j-clj/status.svg)](https://versions.deps.co/gorillalabs/neo4j-clj)\n[![Downloads](https://versions.deps.co/gorillalabs/neo4j-clj/downloads.svg)](https://versions.deps.co/gorillalabs/neo4j-clj)\n\nneo4j-clj is a clojure client library to the [Neo4j graph database](https://neo4j.com/),\nrelying on the [Bolt protocol](https://boltprotocol.org/).\n\n\n## Features\n\nThis library provides a clojuresque way to deal with connections, sessions, transactions\nand [Cypher](https://www.opencypher.org/) queries.\n\n\n## Status\n\nneo4j-clj was in active use at our own projects, but not anymore. \nIt's not a feature complete client library in every possible sense, and it\nis not in active development anymore, but only as a hobby project.\n\nYou might choose to issue new feature requests,\nor clone the repo to add the feature and create a PR.\n\nWe appreciate any help on the open source projects we provide. See [Development section](#development) below for more info\non how to build your own version.\n\n\n## Example usage\n\nThroughout the examples, we assume you're having a Neo4j instance up and running.\nSee our [Neo4j survival guide](docs/neo4j.md) for help on that.\n\nYou can clone our repository and run the [example](example/) for yourself.\n\n\n```clojure\n(ns example.core\n  (:require [neo4j-clj.core :as db])\n  (:import (java.net URI)))\n\n(def local-db\n  (db/connect (URI. \"bolt://localhost:7687\")\n              \"neo4j\"\n              \"YA4jI)Y}D9a+y0sAj]T5s|C5qX!w.T0#u\u003cbe5w6X[p\"))\n\n(db/defquery create-user\n  \"CREATE (u:user $user)\")\n\n(db/defquery get-all-users\n  \"MATCH (u:user) RETURN u as user\")\n\n(defn -main\n  \"Example usage of neo4j-clj\"\n  [\u0026 args]\n\n  ;; Using a session\n  (with-open [session (db/get-session local-db)]\n    (create-user session {:user {:first-name \"Luke\" :last-name \"Skywalker\"}}))\n\n  ;; Using a transaction\n  (db/with-transaction local-db tx\n    ;; print, as query result has to be consumed inside session\n    (println (get-all-users tx))))\n```\n\nIf you do run stuff on the REPL, make sure to consume the results from the query before closing session/transaction - like I did with\nprintln. Use `doall` or whatever suits you, because otherwise you'll run into [issues](https://github.com/gorillalabs/neo4j-clj/issues/25).\n\n## In-depth look\n\n### Connection\n\nFirst of all, you need to connect to the database.\n\n```clojure\n(db/connect (URI. \"bolt://localhost:7687\") ; bolt API URI\n            \"neo4j\" ; username\n            \"YA4jI)Y}D9a+y0sAj]T5s|C5qX!w.T0#u\u003cbe5w6X[p\" ; password\n)\n```\n\n### Session\n\nEverything on the Bolt protocol is organized in a session. neo4j-clj uses the\nstandard `with-open` to handle lexical-scoped sessions.\n\n```clojure\n(with-open [session (db/get-session local-db)]\n  ;; ... use session here\n  )\n```\n\n### Transaction\n\nneo4j-clj can also handle transactions (on top of sessions) by utilizing a \n`with-transaction`-macro.\n\n```clojure\n(db/with-transaction local-db tx\n   ;; run queries within transaction\n)\n```\n\n`local-db` is the Neo4j instance you're connected to.\n`tx` is the symbol the transaction is bound to. You might use\nthe `tx` transaction for query functions. \n\nYou do not need to have everything inside a `with-transaction` block,\nas all statements in a session are wrapped in transactions anyhow\n(see [Sessions and Transactions](https://neo4j.com/docs/developer-manual/current/drivers/sessions-transactions/)). \n\nYou fail transactions by throwing an Exception.\n\n### Cypher queries\n\nYou create new queries using `defquery`. We strongly belief that using Cypher\nas a String directly in your code comes with a couple of advantages.\n\nBoth paramaters and return values are transformed from Clojure datastructures\ninto Neo4j types. That transformation is done transparently, so you won't have\nto deal with that.\n\n#### Parameters\n\nFor some / most queries you need to supply some parameters. Just include a\nvariable into your Cypher query using the `$` notation or the `{}` notation,\nand provide a Clojure map of variables to the query:\n\n\n```clojure\n(db/defquery users-by-age \"MATCH (u:User {age: $age}) RETURN u as user\")\n(users-by-age tx {:age 42})\n```\n\nis equivalent to\n\n```clojure\n(db/defquery users-by-age \"MATCH (u:User {age: {age}}) RETURN u as user\")\n(users-by-age tx {:age 42})\n```\n\nA query will always return a collection. Here, it will return `({:user {...}})`,\ni.e. a collection of maps with the user-key populated.\n\nThink of it as a map per result row.\n\nYou can have more than one parameter in your map:\n\n```clojure\n(db/defquery create-user \"CREATE (u:User {name: $name, age: $age})\")\n(create-user tx {:name \"...\" :age 42})\n```\n\nAnd you can also nest paramters:\n\n```clojure\n(db/defquery create-user \"CREATE (u:User $user)\")\n(create-user tx {:user {:name \"...\" :age 42}})\n```\nand un-nest them as necessary:\n\n```clojure\n(db/defquery create-user \"CREATE (u:User {name : {user}.name})\")\n(create-user tx {:user {:name \"...\" :age 42}})\n```\n\n\n\n\u003c!--\n\n```clojure\n(db/defquery get-users \"MATCH (u:User) RETURN u as user\")\n(get-users tx)\n;; =\u003e ({:user {...}})\n\n;; Extracted parameters\n(db/defquery create-user \"CREATE (u:User {name: $name, age: $age})\")\n(create-user tx {:name \"...\" :age 42})\n\n(db/defquery get-users \"MATCH (u:User) RETURN u.name as name, u.age as age\")\n(get-users tx)\n;; =\u003e ({:name \"...\" :age 42}, ...)\n```\n\n\n--\u003e\n\n#### Return values\n\nThe result of a query is a list, even if your query returns a single item. Each \"result row\" is one map in that sequence\nreturned. \n\nThe values are provided using the ususal Clojure datastructures, no need to wrap/unwrap stuff. That's handled for you by\nneo4j-clj.\n\nI'd like to elaborarte a little on the handling of node/edge labels. You can run a query labels like this:\n\n```clojure\n(db/defquery get-users \"MATCH (u:User) RETURN u as user,labels(u) as labels\")\n(get-users tx)\n```\n\nand this will return a collection of maps with two keys: `user` and `labels` where `labels` are a collection of labels\nassociated with the nodes. At the moment, `labels` are not sets! It's up to you to convert collections into appropriate\ntypes yourself (because we just do not know on the neo4j-clj level), and this is especially true for `labels`.\n\n## Joplin integration\n\nneo4j-clj comes equipped with support for [Joplin](https://github.com/juxt/joplin)\nfor datastore migration and seeding.\n\nAs we do not force our users into Joplin dependencies, you have to add [joplin.core \"0.3.10\"]\nto your projects dependencies yourself.\n\n## Caveats\n\nNeo4j cannot cope with dashes really well (you need to escape them),\nso the Clojure kebab-case style is not really acceptable.\n\n\n## Development\n\nWe appreciate any help on our open source projects. So, feel free to fork and clone this repository.\n\nWe use [leiningen](https://leiningen.org/). So, after you've cloned your repo you should be able to run 'lein test' to\nrun the tests sucessfully.\n\n### Testing\n\n\nFor testing purposes, we provide access to the Neo4j in-memory database feature, which we address using the bolt protocol.\n\nTo do so, you need to add a dependency to `[org.neo4j.test/neo4j-harness \"4.0.0\"]` to your project and require the\n`neo4j-clj.in-memory` namespace.\n\n```clojure\n(def test-db\n  (neo4j-clj.in-memory/create-in-memory-connection))\n;; instead of (neo4j/connect url user password)\n```\n\nSo, you can easily run tests on your stuff without requiring an external database.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgorillalabs%2Fneo4j-clj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgorillalabs%2Fneo4j-clj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgorillalabs%2Fneo4j-clj/lists"}