Skip to content

Commit

Permalink
storing vertices
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielfalcao committed Aug 20, 2017
1 parent e88be8d commit 6b1ea5d
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 70 deletions.
3 changes: 3 additions & 0 deletions plural/models/edges.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def resolve_edge_name(edge):
:param edge: an :py:class:`Edge` instance or string
:returns: a string
"""
if isinstance(edge, Element):
edge = edge.__class__

if is_edge_subclass(edge):
return edge.__name__
elif edge is None:
Expand Down
1 change: 1 addition & 0 deletions plural/models/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def to_dict(self):
return dict([(k, self.encode_field(k, v)) for k, v in self.__data__.items()])

def to_json(self, **kw):
kw['sort_keys'] = True
kw['default'] = AutoCodec().encode
return json.dumps(self.to_dict(), **kw)

Expand Down
2 changes: 0 additions & 2 deletions plural/models/meta/edges.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

from collections import defaultdict
from collections import OrderedDict
from plural.models.meta.vertices import VertexFactory
from plural.models.element import Element
from plural.exceptions import InvalidEdgeDefinition

Expand Down Expand Up @@ -98,7 +97,6 @@ def __init__(cls, name, bases, members):

codecs.update(getattr(cls, 'fields', {}))
cls.indexes = fields
cls.v = VertexFactory(cls)
cls.__fields__ = {'uuid'}.union(fields)
cls.__data__ = {}
cls.__codecs__ = dict([(n, Codec()) for n, Codec in codecs.items()])
Expand Down
16 changes: 0 additions & 16 deletions plural/models/meta/vertices.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,3 @@ class incoming_vertex(VertexDefinition):
class indirect_vertex(VertexDefinition):
"""represents the declaration of an indirect vertex"""
direction = 'indirect'


class VertexFactory(object):
def __init__(self, edge):
self.target = edge

def incoming(self, fields, reverse_label):
return incoming_vertex(fields=fields, reverse_label=reverse_label,
target=self.target)

def outgoing(self, fields, reverse_label):
return outgoing_vertex(fields=fields, reverse_label=reverse_label,
origin=self.target)

def indirect(self, fields, reverse_label):
return indirect_vertex(fields=fields, reverse_label=reverse_label)
3 changes: 3 additions & 0 deletions plural/models/vertices.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ def resolve_vertex_name(vertex):
:param vertex: an :py:class:`Vertex` instance or string
:returns: a string
"""
if isinstance(vertex, Element):
vertex = vertex.__class__

if is_vertex_subclass(vertex):
return vertex.__name__

Expand Down
46 changes: 43 additions & 3 deletions plural/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def serialize(self, obj):
:returns: ``string``
"""
default = AutoCodec().encode
return "\n".join([line.rstrip() for line in json.dumps(obj, sort_keys=True, indent=2, default=default).split('\n')])
return json.dumps(obj, sort_keys=True, default=default)

def deserialize(self, string):
"""deserialize a string into an object, meant for internal use only.
Expand Down Expand Up @@ -150,6 +150,10 @@ def create_vertex(self, vertex, **obj):
id_path = os.path.join(vertex, '_ids')
uuid_path = os.path.join(vertex, '_uuids')

original_obj = obj.copy()
origin = obj.pop('origin')
target = obj.pop('target')

indexes = {}
for key in obj.keys():
value = obj.get(key, None)
Expand All @@ -159,11 +163,47 @@ def create_vertex(self, vertex, **obj):
predicate_path = os.path.join(vertex, 'indexes', key)
predicate_ids.append(self.add_spo(predicate_path, object_hash, value))

self.add_spo(object_path, object_hash, vertex_data)
self.add_spo(id_path, vertex_uuid, object_hash)
self.add_spo(uuid_path, object_hash, vertex_uuid)

return Vertex.from_data(vertex, **obj)
origin_name = resolve_edge_name(origin)
target_name = resolve_edge_name(target)
RelationhipModel = Vertex.definition(vertex)

label = RelationhipModel.label
# call('Car/incoming/bought_by/Person', 'chuck-uuid', 'car-uuid'),
# call('___vertices___/Car/bought_by/Person', 'chuck-uuid', 'car-uuid'),
path_templates = {
'incoming': '{to}/incoming/{label}/{from}',
'outgoing': '{from}/outgoing/{label}/{to}',
'indirect': '___indirect___/{from}/{label}/{to}',
}
vertex_path_template = path_templates[RelationhipModel.direction]

ctx = {
'label': label
}
if RelationhipModel.direction == 'incoming':
from_uuid = origin.uuid
ctx['from'] = origin_name
to_uuid = target.uuid
ctx['to'] = target_name

elif RelationhipModel.direction == 'outgoing':
from_uuid = target.uuid
ctx['from'] = target_name
to_uuid = origin.uuid
ctx['to'] = origin_name
else:
from_uuid = origin.uuid
ctx['from'] = origin_name
to_uuid = target.uuid
ctx['to'] = target_name

vertex_path = vertex_path_template.format(**ctx)
self.add_spo(vertex_path, from_uuid, to_uuid)

return RelationhipModel.from_data(vertex, **original_obj)

def create_edge(self, edge, **obj):
"""creates a staged edge entry including its indexed fields.
Expand Down
36 changes: 18 additions & 18 deletions tests/functional/test_file_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,28 +73,28 @@ def test_create_edge(context):
docs2,
})
sorted(list_file_tree(store.path)).should.equal(sorted([
u'Document/_ids/1c3b00da1c3b00da1c3b00da1c3b00da',
u'Document/_ids/deadbeefdeadbeefdeadbeefdeadbeef',
u'Document/_uuids/7fab47d1e50cfe3682a12acfce2f5208d619d5f6',
u'Document/_uuids/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/indexes/content/7fab47d1e50cfe3682a12acfce2f5208d619d5f6',
u'Document/indexes/content/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/indexes/title/7fab47d1e50cfe3682a12acfce2f5208d619d5f6',
u'Document/indexes/title/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/indexes/uuid/7fab47d1e50cfe3682a12acfce2f5208d619d5f6',
u'Document/indexes/uuid/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/objects/7fab47d1e50cfe3682a12acfce2f5208d619d5f6',
u'Document/objects/d5af9edffb41a006f51f80695f2cf3a841f8cf96'
'Document/_ids/1c3b00da1c3b00da1c3b00da1c3b00da',
'Document/_ids/deadbeefdeadbeefdeadbeefdeadbeef',
'Document/_uuids/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/_uuids/fae1f98f713ead9b174a8d953ded3f70c42e6542',
'Document/indexes/content/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/indexes/content/fae1f98f713ead9b174a8d953ded3f70c42e6542',
'Document/indexes/title/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/indexes/title/fae1f98f713ead9b174a8d953ded3f70c42e6542',
'Document/indexes/uuid/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/indexes/uuid/fae1f98f713ead9b174a8d953ded3f70c42e6542',
'Document/objects/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/objects/fae1f98f713ead9b174a8d953ded3f70c42e6542',
]))
store.delete(docs2)
store.commit()
sorted(list_file_tree(store.path)).should.equal(sorted([
u'Document/_ids/deadbeefdeadbeefdeadbeefdeadbeef',
u'Document/_uuids/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/indexes/content/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/indexes/title/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/indexes/uuid/d5af9edffb41a006f51f80695f2cf3a841f8cf96',
u'Document/objects/d5af9edffb41a006f51f80695f2cf3a841f8cf96'
'Document/_ids/deadbeefdeadbeefdeadbeefdeadbeef',
'Document/_uuids/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/indexes/content/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/indexes/title/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/indexes/uuid/c5a61004c0bab3a5ee1244e719ade9ebd381f892',
'Document/objects/c5a61004c0bab3a5ee1244e719ade9ebd381f892'
]))


Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ def test_edge_from_dict_get_attribute():
foobar.should.have.property('name').being.equal('Foo Bar')
foobar.should.have.property('birthdate').being.equal('1973/07/04')
foobar.should.have.property('uuid').being.equal('woot')
hash(foobar).should.equal(6193599141153582213)
hash(foobar).should.equal(-4530108406577435520)
hasattr(foobar, '__invalid__').should.be.false
hasattr(foobar, 'invalid').should.be.false

foobar.to_json().should.equal(json.dumps(foobar.to_dict()))
foobar.to_json().should.equal(json.dumps(foobar.to_dict(), sort_keys=True))
bytes(foobar).should.match('^Person[{]')
repr(foobar).should.match('^tests.edges.Person[{]')
foobar.should.equal(foobar)
Expand Down
58 changes: 29 additions & 29 deletions tests/unit/test_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def test_serialize(context):
'foo': 'bar',
})

result.should.equal('{\n "foo": "bar"\n}')
result.should.equal('{"foo": "bar"}')


@with_graph_store('/path/to/folder')
Expand Down Expand Up @@ -209,41 +209,41 @@ def test_create_edge(context, add_spo, git_object_hash):
call('Car/indexes/nickname', 'git-object-hash', 'Lightning'),
call('Car/indexes/brand', 'git-object-hash', 'Tesla'),
call('Car/indexes/uuid', 'git-object-hash', 'generated-uuid4'),
call('Car/objects', 'git-object-hash', '{\n "brand": "Tesla",\n "max_speed": "160.4",\n "model": "Model S",\n "nickname": "Lightning",\n "uuid": "generated-uuid4"\n}'),
call('Car/objects', 'git-object-hash', tesla.to_json()),
call('Car/_ids', 'generated-uuid4', 'git-object-hash'),
call('Car/_uuids', 'git-object-hash', 'generated-uuid4'),
])


# @with_graph_store('/path/to/folder')
# @patch('plural.store.pygit2.hash')
# @patch('plural.store.PluralStore.add_spo')
# def test_create_vertex_incoming(context, add_spo, git_object_hash):
# ('PluralStore.create_vertex() should add spos for its indexes')

# git_object_hash.return_value = 'git-object-hash'
# tesla = Car(uuid='car-uuid', brand='Tesla')
# chuck = Person(uuid='chuck-uuid', name='Chuck Norris')
@with_graph_store('/path/to/folder')
@patch('plural.store.pygit2.hash')
@patch('plural.store.PluralStore.add_spo')
def test_create_vertex_incoming(context, add_spo, git_object_hash):
('PluralStore.create_vertex() should add spos for its indexes')

# purchase = context.store.create_vertex(
# CarPurchase,
# uuid='purchase-uuid',
# origin=chuck,
# target=tesla,
# contract_signed_at='2017-08-18 00:31:45',
# payment_sent_at='2017-07-04 15:25:35',
# )
# purchase.should.be.a(CarPurchase)
# purchase.to_dict().should.be.a(dict)
git_object_hash.return_value = 'git-object-hash'
tesla = Car(uuid='car-uuid', brand='Tesla')
chuck = Person(uuid='chuck-uuid', name='Chuck Norris')

purchase = context.store.create_vertex(
CarPurchase,
uuid='purchase-uuid',
origin=chuck,
target=tesla,
contract_signed_at='2017-08-18 00:31:45',
payment_sent_at='2017-07-04 15:25:35',
)
purchase.should.be.a(CarPurchase)
purchase.to_dict().should.be.a(dict)

# add_spo.assert_has_calls([
# call('CarPurchase/_ids', 'purchase-uuid', 'git-object-hash'),
# call('CarPurchase/_uuids', 'git-object-hash', 'purchase-uuid'),
# call('CarPurchase/indexes/contract_signed_at', 'git-object-hash', 'contract-signed-at'),
# call('CarPurchase/indexes/payment_sent_at', 'git-object-hash', 'payment-sent-at'),
# call('CarPurchase/indexes/uuid', 'git-object-hash', 'purchase-uuid'),
# call('vertices/bought_by/_uuids', 'chuck-uuid', purchase.to_json()),
# ])
add_spo.assert_has_calls([
call('CarPurchase/indexes/contract_signed_at', 'git-object-hash', '2017-08-18 00:31:45'),
call('CarPurchase/indexes/uuid', 'git-object-hash', 'purchase-uuid'),
call('CarPurchase/indexes/payment_sent_at', 'git-object-hash', '2017-07-04 15:25:35'),
call('CarPurchase/_ids', 'purchase-uuid', 'git-object-hash'),
call('CarPurchase/_uuids', 'git-object-hash', 'purchase-uuid'),
call('Car/incoming/bought_by/Person', 'chuck-uuid', 'car-uuid')
])


# @with_graph_store('/path/to/folder')
Expand Down
4 changes: 4 additions & 0 deletions tests/vertices.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@


class CarPurchase(IncomingVertex):
label, target = 'bought_by', 'Person'
indexes = {'contract_signed_at', 'payment_sent_at'}
fields = {
'contract_signed_at': codec.DateTime,
Expand All @@ -29,6 +30,7 @@ class CarPurchase(IncomingVertex):


class CarSale(OutgoingVertex):
label, target = 'sold_by', 'Person'
indexes = {'contract_signed_at', 'payment_received_at'}
fields = {
'contract_signed_at': codec.DateTime,
Expand All @@ -44,6 +46,7 @@ class CarDeal(OutgoingVertex):


class AuthoredDocument(IncomingVertex):
label, target = 'authored_by', 'Author'
indexes = {'created_at', 'modified_at'}
fields = {
'created_at': codec.DateTime,
Expand All @@ -52,6 +55,7 @@ class AuthoredDocument(IncomingVertex):


class TaggedDocument(OutgoingVertex):
label, target = 'tagged_by', 'Tag'
indexes = {'created_at'}
fields = {
'created_at': codec.DateTime,
Expand Down

0 comments on commit 6b1ea5d

Please sign in to comment.