domvas

domvas

Seraph, toolkit for data mapping and querying Neo4j

Hello,
I’m pleased and a bit proud to present you seraph a library to define schema and query Neo4j database.

Again?
Yes again…
Since I’ve started Elixir, I’ve seen here and there attempts to develop a library to use Neo4j nicely, and even an adapter to Ecto… released by me.
But nothing was satisfying enough and ecto_neo4j was, and is still, a big disappointment. ecto is relational database oriented, and there is more or less only one entity is this case: table. But when it comes to graph, you have two entities: node and relationship. Then all I’ve done with ecto_neo4j was to force this two entities and graph concepts into a relational shape. Code became awful because of hacks everywhere, usage was limited and so restricted that you can’t model you graph database as you wish.
Then I drop this project and start seraph.

seraph is heavily inspired by ecto because using ecto to work with database is joy. And I tried to bring this joy to Neo4j graph database.
It’s still the beginning, a LOT is missing but it’s a first (good?) step for a nice library to work with Neo4j with schema, nice query api, etc.

Hope you’ll enjoy it.

Testers and contributors

Because of the amount of work, help would be appreciated, so if you want to test, to add some features, write some docs, please do!

So, quickly, what you can do if you don’t want to read the docs.

Schema

a node schema is like this:

defmodule GraphApp.Blog.User do
  use Seraph.Schema.Node
  import Seraph.Changeset

  alias GraphApp.Blog.User
  alias GraphApp.Blog.Relationship
  alias GraphApp.Blog.Relationship.NoProperties

  node "User" do
    property :firstName, :string
    property :lastName, :string
    property :email, :string
    
    # You can define two relatinship with same type but pointing to different node
    # without problem
    outgoing_relationship("WROTE", GraphApp.Blog.Post, :posts, Relationship.Wrote,
      cardinality: :many
    )

    outgoing_relationship(
      "WROTE",
      GraphApp.Blog.Comment,
      :comments,
      NoProperties.UserToComment.Wrote,
      cardinality: :many
    )
    
    # A relationship can ends to the same node it starts 
    outgoing_relationship(
      "FOLLOWS",
      GraphApp.Blog.User,
      :followed,
      NoProperties.UserToUser.Follows,
      cardinality: :many
    )
  end

# classic changeset
  def changeset(%User{} = user, params \\ %{}) do
    user
    |> cast(params, [:firstName, :lastName, :email])
    |> validate_required([:firstName, :lastName, :email])
  end
end

a relationship schema:

defmodule GraphApp.Blog.Relationship.Wrote do
  use Seraph.Schema.Relationship

  @cardinality [outgoing: :one, incoming: :many]

  relationship "WROTE" do
    start_node GraphApp.Blog.User
    end_node GraphApp.Blog.Post

    property :when, :utc_datetime
  end
end

Atomic operation with Repo.*

Each entity has its Repo.* functions:

  • get
  • get_by
  • set
  • create

Query DSL

And you can write nice queries with the query api.

import Seraph.Query

query = match [{u, User}],
  where: [u.firstName == "John"],
  return: [u]

GraphApp.Repo.all(query)

----

match([
    {u, GraphApp.Blog.User, %{firstName: "Jim"}},
    {u2, GraphApp.Blog.User, %{firstName: "Jane"}},
    [{u}, [rel, GraphApp.Blog.Relationship.NoProperties.UserToUser.Follows], {u2}]
]) 
|> delete([rel]) 
|> GraphApp.Repo.execute()

Most Liked

swelham

swelham

Great work! I have been wanting this to exist for some time but never been able to get around to building it myself. I have some initial thoughts listed below that came to mind whilst looking through the guides and I will definitely be looking to contribute where I can.

  • Support a non global config. Allow the config to be specified per instance of Repo in the supervision tree. This provides more flexibility and if the user wants a global config they can still do it.
  • Default datetimes to utc_datetime_usec. I believe this plays better with Elixir’s datetime module (no need for Datetime.truncate everywhere) and I seem to remember reading that the ecto core team wish they did this but now can’t due to backwards compatibility.
  • Support having snake case schema fields. I see the rational in enforcing camel case but as it’s not idiomatic Elixir it will end up forcing some inconsistency in the user’s application. This seems more like a db implementation detail and I think it should be possible to support snake case fields and then convert to camel case in the queries when dealing with the db.

But honestly it’s looking really good so far!

domvas

domvas

For labels and types, it’s Neo4j’s recommendation and can be seen as a convention.
For properties, it’s based on what I’ve seen during my trainings and many talks / tutorials. So a majority of users has adopted this syntax but it’s not really a convention, then letting the end-user decide could be nice.
Having a field/2-like macro can be tricky to implement but not impossible then it will be implemented. It is in fact one the many features that still missing (like fragments…)

alaadahmed

alaadahmed

wow really nice work you have done @domvas, really appreciate your work, I am working on some big project that I intend to use neo4j for it. I am reading your guides and I am fascinated. I hope you still maintain this library and keep it up to date.

Where Next?

Popular in Announcing Top

martinthenth
Hello everybody :wave: Recently, some of my colleagues talked about database ids and uuids and their problems, and I remembered the pain...
New
seancribbs
Today I released a new dialyzer Mix task as the dialyzex package! At the time we started writing this task, the existing dialyzer integra...
New
josevalim
Hi everyone, We would like to announce that Plataformatec is working on a new MySQL driver called MyXQL. Our goal is to eventually integ...
New
oltarasenko
Dear Elixir community, After a year of development, bug fixes, and improvements, we are proudly ready to share the release of Crawly 0.1...
New
wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
ahamez
Hi everyone, I’ve been working on this protobuf library for 3 years. We use it in the company I work for, EasyMile, to communicate with ...
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
cjen07
parameterized pipe in elixir: |n> edit: negative index in |n> and mixed usage with |> are supported example: use ParamPipe ...
New
versilov
Could not wait for the missing Elixir ML libraries to appear, so, I wrote one myself, taking https://github.com/sdwolfz/exlearn as a foun...
New
tmbb
I’ve decided to create this topic to discuss optimization possibilities for something like Phoenix LiveView. I’ve created this topic unde...
144 10187 141
New

Other popular topics Top

ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31142 143
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement