neolixir
A declarative ORM for the Neo4j graph database
Ivo Tzvetkov
Data stored in a graph instead of a table:
:Person
:Person
:knows
since: 2012
name: ‘Bob’�born: 1978
name: ‘Alice’�born: 1980
Traditional table-based model (SQL / NoSQL)
Id | Name | Born |
1 | ‘Bob’ | 1978 |
2 | ‘Alice’ | 1980 |
Id | PersonId | OtherId | Since |
1 | 1 | 2 | 2012 |
Person
Knows
Cypher query language:
match (bob:Person {name: ‘Bob’})-[:knows]->(alice:Person {name: ‘Alice’})
Cypher query language:
match (bob:Person {name: ‘Bob’})-[:knows]->(alice:Person {name: ‘Alice’})
with bob, alice
match (bob)-[:knows*1..6]->(other:Person)-[rel:knows]->(alice)
where rel.since > 2000
Dynamic definition with no formal schema (limited indexing and constraints):
:Person
:Person
:knows
since: 2012
name: ‘Bob’�born: 1978
name: ‘Alice’�born: 1980
Dynamic definition with no formal schema (limited indexing and constraints):
:Person
:Person
:knows
since: 2012
name: ‘Bob’�born: 1978
name: ‘Alice’�born: 1980
>>> from py2neo import Node, Relationship�>>> a = Node("Person", name="Alice")�>>> b = Node("Person", name="Bob")�>>> ab = Relationship(a, "knows", b)�>>> ab�(alice)-[:knows]->(bob)
Dynamic definition with no formal schema (limited indexing and constraints):
:Person
:Person
:knows
since: 2012
name: ‘Bob’�born: 1978
name: ‘Alice’�born: 1980
>>> from py2neo import Node, Relationship�>>> a = Node("Person", name="Alice")�>>> b = Node("Person", name="Bob")�>>> ab = Relationship(a, "knows", b)�>>> ab�(alice)-[:knows]->(bob)
Dynamic definition with no formal schema (limited indexing and constraints):
:Person
:Person
:knows
since: 2012
name: ‘Bob’�born: 1978
name: ‘Alice’�born: 1980
>>> from py2neo import Node, Relationship�>>> a = Node("Person", name="Alice")�>>> b = Node("Person", name="Bob")�>>> ab = Relationship(a, "knows", b)�>>> ab�(alice)-[:knows]->(bob)
A social platform to create and share rich learning activities:
Backend technology stack:
A social platform to create and share rich learning activities:
A social platform to create and share rich learning activities:
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
Declarative model definition
In [1]: from neolixir import *
In [2]: class Person(Node):
...: name = String()
...: born = Integer()
...: knows = RelOut('knows')
Declarative model definition
In [1]: from neolixir import *
In [2]: class Person(Node):
...: name = String()
...: born = Integer()
...: knows = RelOut('knows')
In [3]: bob = Person(name='Bob', born=1978)
In [4]: bob
Out[4]:
<Person (0x31073d0):
Id = None
Descriptors = ['born', 'knows', 'name']
Properties = {'born': 1978, 'name': u'Bob'}
>
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
Polymorphic inheritance
In [2]: class Person(Node):
...: name = String()
...: born = Integer()
...: knows = RelOut('knows')
In [5]: class Student(Person):
...: grade = Integer()
Polymorphic inheritance
In [2]: class Person(Node):
...: name = String()
...: born = Integer()
...: knows = RelOut('knows')
In [5]: class Student(Person):
...: grade = Integer()
In [6]: alice = Student(name='Alice', born=1980, grade=8)
In [7]: alice
Out[7]:
<Student (0x33eb890):
Id = None
Descriptors = ['born', 'grade', 'knows', 'name']
Properties = {'grade': 8, 'born': 1980, 'name': u'Alice'}
>
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
Relationship abstraction
In [3]: class Person(Node):
...: name = String()
...: knows = RelOut('knows')
Relationship abstraction
In [2]: class KnowsRel(Relationship):
...: __rel_type__ = 'knows'
...: since = DateTime()
In [3]: class Person(Node):
...: name = String()
...: knows = RelOut(KnowsRel)
Relationship abstraction
In [2]: class KnowsRel(Relationship):
...: __rel_type__ = 'knows'
...: since = DateTime()
In [3]: class Person(Node):
...: name = String()
...: knows = RelOut(KnowsRel)
In [4]: bob = Person(name='Bob')
In [5]: alice = Person(name='Alice')
In [6]: bob.knows.append(alice)
Out[6]: <KnowsRel (0x27e7810): (None)-[None:knows]->(None) {}>
Relationship abstraction
In [2]: class KnowsRel(Relationship):
...: __rel_type__ = 'knows'
...: since = DateTime()
In [3]: class Person(Node):
...: name = String()
...: knows = RelOut(KnowsRel)
In [4]: bob = Person(name='Bob')
In [5]: alice = Person(name='Alice')
In [6]: bob.knows.append(alice)
Out[6]: <KnowsRel (0x27e7810): (None)-[None:knows]->(None) {}>
In [7]: alice in bob.knows
Out[7]: True
Relationship abstraction
In [7]: bob.knows
Out[7]:
[<Person (0x27a9350):
Id = None
Descriptors = ['knows', 'name']
Properties = {'name': u'Alice'}
>]
Relationship abstraction
In [7]: bob.knows
Out[7]:
[<Person (0x27a9350):
Id = None
Descriptors = ['knows', 'name']
Properties = {'name': u'Alice'}
>]
In [8]: bob.knows.rels()
Out[8]: [<KnowsRel (0x27e7810): (None)-[None:knows]->(None) {}>]
Relationship abstraction
In [7]: bob.knows
Out[7]:
[<Person (0x27a9350):
Id = None
Descriptors = ['knows', 'name']
Properties = {'name': u'Alice'}
>]
In [8]: bob.knows.rels()
Out[8]: [<KnowsRel (0x27e7810): (None)-[None:knows]->(None) {}>]
In [9]: bob.knows.rel(alice).since = '2012-01-01'
In [10]: bob.knows.rel(alice)
Out[10]: <KnowsRel (0x27e7810): (None)-[None:knows]->(None) {'since': '2012-01-01 00:00:00'}>
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
Strongly-typed properties
Types: Boolean, String, Enum, Integer, Float, Numeric, DateTime
Strongly-typed properties
Types: Boolean, String, Enum, Integer, Float, Numeric, DateTime
In [2]: class Student(Node):
...: name = String()
...: born = DateTime()
...: gpa = Numeric()
...: graduated = Boolean(default=False)
Strongly-typed properties
Types: Boolean, String, Enum, Integer, Float, Numeric, DateTime
In [2]: class Student(Node):
...: name = String()
...: born = DateTime()
...: gpa = Numeric()
...: graduated = Boolean(default=False)
In [3]: bob = Student(name='Bob', born='1970-01-01', gpa='3.0')
In [4]: bob.name, bob.born, bob.gpa, bob.graduated
Out[4]: (u'Bob', datetime.datetime(1970, 1, 1, 0, 0), Decimal('3.0'), False)
Strongly-typed properties
Types: Boolean, String, Enum, Integer, Float, Numeric, DateTime
In [2]: class Student(Node):
...: name = String()
...: born = DateTime()
...: gpa = Numeric()
...: graduated = Boolean(default=False)
In [3]: bob = Student(name='Bob', born='1970-01-01', gpa='3.0')
In [4]: bob.name, bob.born, bob.gpa, bob.graduated
Out[4]: (u'Bob', datetime.datetime(1970, 1, 1, 0, 0), Decimal('3.0'), False)
In [5]: bob.name = 123; bob.name
Out[5]: u'123'
Strongly-typed properties
Types: Boolean, String, Enum, Integer, Float, Numeric, DateTime
In [2]: class Student(Node):
...: name = String()
...: born = DateTime()
...: gpa = Numeric()
...: graduated = Boolean(default=False)
In [3]: bob = Student(name='Bob', born='1970-01-01', gpa='3.0')
In [4]: bob.name, bob.born, bob.gpa, bob.graduated
Out[4]: (u'Bob', datetime.datetime(1970, 1, 1, 0, 0), Decimal('3.0'), False)
In [5]: bob.name = 123; bob.name
Out[5]: u'123'
In [8]: bob.gpa = 'foo'
ValueError: Invalid value for Numeric: foo
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
Session management
In [6]: bob
Out[6]:
<Person (0x22f5050):
Id = None
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob'}
>
Session management
In [6]: bob
Out[6]:
<Person (0x22f5050):
Id = None
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob'}
>
In [7]: metadata.session.commit()
In [8]: bob
Out[8]:
<Person (0x22f5050):
Id = 5433
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob', '__class__': 'Person'}
>
Session management
In [9]: bob.knows.append(Person(name='Alice'))
Out[9]: <Relationship (0x237ccd0): (5433)-[None:knows]->(None) {}>
Session management
In [9]: bob.knows.append(Person(name='Alice'))
Out[9]: <Relationship (0x237ccd0): (5433)-[None:knows]->(None) {}>
In [10]: metadata.session.commit()
In [11]: bob.knows.rels()
Out[11]: [<Relationship (0x237ccd0): (5433)-[2706:knows]->(5434) {'__class__': 'Relationship'}>]
Session management
In [9]: bob.knows.append(Person(name='Alice'))
Out[9]: <Relationship (0x237ccd0): (5433)-[None:knows]->(None) {}>
In [10]: metadata.session.commit()
In [11]: bob.knows.rels()
Out[11]: [<Relationship (0x237ccd0): (5433)-[2706:knows]->(5434) {'__class__': 'Relationship'}>]
In [12]: bob.knows
Out[12]:
[<Person (0x23851d0):
Id = 5434
Descriptors = ['knows', 'name']
Properties = {'name': u'Alice', '__class__': 'Person'}
>]
Session management
In [15]: bob
Out[15]:
<Person (0x22f5050):
Id = 5433
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob', '__class__': 'Person'}
>
Session management
In [15]: bob
Out[15]:
<Person (0x22f5050):
Id = 5433
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob', '__class__': 'Person'}
>
In [16]: Node.get(5433)
Out[16]:
<Person (0x22f5050):
Id = 5433
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob', '__class__': 'Person'}
>
Session management
In [16]: Node.get(5433)
Out[16]:
<Person (0x22f5050):
Id = 5433
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob', '__class__': 'Person'}
>
In [17]: metadata.session.clear()
Session management
In [16]: Node.get(5433)
Out[16]:
<Person (0x22f5050):
Id = 5433
Descriptors = ['knows', 'name']
Properties = {'name': u'Bob', '__class__': 'Person'}
>
In [17]: metadata.session.clear()
In [18]: Node.get(5433)
Out[18]:
<Person (0x23ad990):
Id = 5433
Descriptors = ['born', 'knows', 'name']
Properties = {u'name': u'Bob', u'__class__': u'Person'}
>
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
Query abstraction
In [21]: Person.query.count()
Out[21]: 2
Query abstraction
In [21]: Person.query.count()
Out[21]: 2
In [22]: Person.query.string
Out[22]: 'match (instance:Person) return instance'
Query abstraction
In [21]: Person.query.count()
Out[21]: 2
In [22]: Person.query.string
Out[22]: 'match (instance:Person) return instance'
In [23]: Person.query.append('where instance.name = "Bob" return instance').string
Out[23]: 'match (instance:Person) where instance.name = "Bob" return instance'
Query abstraction
In [21]: Person.query.count()
Out[21]: 2
In [22]: Person.query.string
Out[22]: 'match (instance:Person) return instance'
In [23]: Person.query.append('where instance.name = "Bob" return instance').string
Out[23]: 'match (instance:Person) where instance.name = "Bob" return instance'
In [24]: Person.query.append('where instance.name = "Bob" return instance').execute()
Out[24]:
[[<Person (0x23ad990):
Id = 5433
Descriptors = ['born', 'knows', 'name']
Properties = {u'name': u'Bob', u'__class__': u'Person'}
>]]
neolixir
An Object-Relational Mapping (ORM) abstraction for Neo4j:
neolixir
Current state:
In the near future:
https://github.com/ivotkv/neolixir
ivotkv@gmail.com