# EctoNeo4j
[![Build Status](https://travis-ci.org/dominique-vassard/ecto_neo4j.svg?branch=master)](https://travis-ci.org/dominique-vassard/ecto_neo4j)
[![Coverage Status](https://coveralls.io/repos/github/dominique-vassard/ecto_neo4j/badge.svg?branch=master)](https://coveralls.io/github/dominique-vassard/ecto_neo4j?branch=master)
**WARNING: WIP. This project is not production-ready (yet)**
# Goal
## Ecto wrapper
Have a wrapper around Ecto in order to use `Ecto.*`-style functions.
With `EctoNeo4j`, it is possible to have a classic Ecto schema with its changeset and use
known Ecto Repo functions to persits data in a Neo4j database.
## Use Neo4j driver easily
EctoNeo4j allows you to not care about the `Bolt.Sips.conn()` reuired in all functions.
for example, instead of writing:
```
conn = Bolt.Sips.conn()
Bolt.Sips.query(conn, "RETURN 1 AS num")
```
you can simply write:
```
MyRepo.query("RETURN 1 AS num")
```
## Ultimate
The ultimate goal is to have also an extension of Ecto to manage relationship and have a kind of `EctoCypher` too.
# Requirements
`EctoNeo4j` requires `bolt_sips` in order to work.
`bolt_sips` should be defined as one of your project dependency.
More info bout `bolt_sips`: [https://github.com/florinpatrascu/bolt_sips](https://github.com/florinpatrascu/bolt_sips)
# Warning: about ids...
As you may know, it is strongly recommended to NOT rely on Neo4j internal ids, as they can be reaffected.
With Ecto.Schema, `id` can be managed automatically. `EctoNeo4j` allows to not change this way of working by
using a property called `nodeId` on created/updated nodes. This porprety is automically converted into `id` when
retrieving data from database.
# Usage
## Database config
See [https://github.com/florinpatrascu/bolt_sips#usage](https://github.com/florinpatrascu/bolt_sips#usage)
## Your repo
Add a module with the folling code:
```elixir
defmodule MyApp.MyRepo do
use EctoNeo4j.Repo
end
```
Add it to your supervision tree:
```elixir
defmodule MyApp.Application do
use Application
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
def start(_type, _args) do
# Define workers and child supervisors to be supervised
children = [
{MyApp.MyRepo, []}
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
```
Considering the following module:
```elixir
defmodule MyApp.Post do
use Ecto.Schema
import Ecto.Changeset
schema "Post" do
field(:title, :string)
field(:content, :string)
end
def changeset(test, params \\ %{}) do
test
|> cast(params, [:title, :desc])
|> validate_required([:content, :desc])
end
```
# Usage - What's currently available
Considering the following module:
```elixir
defmodule MyApp.Post do
use Ecto.Schema
import Ecto.Changeset
schema "Post" do
field(:title, :string)
field(:content, :string)
end
def changeset(test, params \\ %{}) do
test
|> cast(params, [:title, :desc])
|> validate_required([:content, :desc])
end
```
## Inserting
```elixir
data = %{title: "Hello World", content: "Neo4j is wonderful, isn't it?"}
changeset = MyApp.Post.changeset(%MyApp.Post{}, data)
MyRepo.insert(changeset)
```
`insert!/2` is also available
## Retrieving
### One result
```elixir
MyRepo.one(MyApp.Post)
# with a queryable
import Ecto.Query
query = from p in MyApp.Post, where: p.title == "Hello World", select: p.content
```
`one!/2` is also available.
### All results
```elixir
MyRepo.all(MyApp.Post)
# with a queryable
import Ecto.Query
query = from p in MyApp.Post, where: p.title == "Hello World", select: p.content
MyRepo.all(query)
```
### By id
```elixir
MyRepo.get(MyApp.Post, 3)
```
`get!/2` is also available.
# Updating
```elixir
MyRepo.get(MyApp.Post, 3)
|> MyApp.Post.changeset(%{title: "New title"})
|> MyRepo.update()
```
`update!/2` is also available.
# Deleting
```elixir
MyRepo.get(MyApp.Post, 3)
|> MyRepo.delete()
```
`delete!/2` is also available.
# Raw cypher query
```elixir
MyRepo.query("MATCH (p:Post {title: {title}})) RETURN p", %{title: "Searched"}
```
`query!/2` is also available.
# Queryable limitation
`Ecto.Query` is not yet fully compatible with `EctoNeo4j` as the translation work is in progress.
And in fact, some part have no meaning in Neo4j (join, etc.).
For now yo can use:
- where:
- only with `and`, `or`, `==`, `>`, `>=`, `<`, `<=`
- select
More to be covered soon.
# Roadmap
- [ ] Cover all Repo callbacks
- [ ] Better and easier usage
- [ ] Cover as many Ecto.Query as possible
- [ ] Ecto schema extension
- [ ] Complete cypher integration
# Can I contribute?
Yes, you can! Please, do!
Just fork, commit and submit pull requests!