Skip to content

Commit

Permalink
storing indirect relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielfalcao committed Aug 27, 2017
1 parent 65a4ad8 commit 2855db5
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 45 deletions.
61 changes: 51 additions & 10 deletions plural/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,32 +176,41 @@ def create_vertex(self, vertex, **obj):
path_templates = {
'incoming': '{to}/incoming/{label}/{from}',
'outgoing': '{from}/outgoing/{label}/{to}',
'indirect': '___indirect___/{from}/{label}/{to}',
'indirect': '{}/indirect/{label}/{}',
}
vertex_path_template = path_templates[RelationhipModel.direction]

ctx = {
'label': label
}
if RelationhipModel.direction == 'incoming':
direction = RelationhipModel.direction
# self.add_spo(object_path, object_hash, vertex_data)

if direction == 'incoming':
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)

elif RelationhipModel.direction == 'outgoing':
elif 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)

vertex_path = vertex_path_template.format(**ctx)
self.add_spo(vertex_path, from_uuid, to_uuid)
elif direction == 'indirect':
from_uuid = target.uuid
to_uuid = origin.uuid

path = vertex_path_template.format(target_name, origin_name, **ctx)
self.add_spo(path, from_uuid, to_uuid)

path = vertex_path_template.format(origin_name, target_name, **ctx)
self.add_spo(path, to_uuid, from_uuid)

return RelationhipModel.from_data(vertex, **original_obj)

Expand Down Expand Up @@ -322,6 +331,19 @@ def get_edge_by_uuid(self, edge_name, uuid):
blob = self.repository[edge_blob_id]
return Edge.from_data(edge_name, **self.deserialize(blob.data))

def get_vertex_by_uuid(self, vertex_name, uuid):
"""retrieves a vertex by id
:param vertex_name: the vertex name or type
:param uuid: the uuid value
"""
vertex_name = resolve_vertex_name(vertex_name)
pattern = os.sep.join([vertex_name, '_ids', uuid])
for entry in self.glob(pattern):
vertex_blob_id = self.repository[entry.oid].data
blob = self.repository[vertex_blob_id]
return Vertex.from_data(vertex_name, **self.deserialize(blob.data))

def match_edges_by_index(self, edge_name, field_name, match_callback):
"""retrieves multiple edges by indexed field
Expand All @@ -341,6 +363,25 @@ def match_edges_by_index(self, edge_name, field_name, match_callback):
Definition = Edge.definition(edge_name)
yield Definition(**data)

def match_vertices_by_index(self, vertex_name, field_name, match_callback):
"""retrieves multiple vertices by indexed field
:param vertex_name: the vertex name or type
:param uuid: the uuid value
"""
vertex_name = resolve_vertex_name(vertex_name)
pattern = os.sep.join([vertex_name or '*', 'indexes', '*'])
# for index, oid in filter(lambda (index, oid): field_name in index, self.glob(pattern)):
for index, oid in self.trace_path(self.glob(pattern)):
path, blob_id = os.path.split(index)
vertex_name = path.split(os.sep)[0]
value = self.repository[oid].data
if match_callback(value):
blob = self.repository[blob_id]
data = self.deserialize(blob.data)
Definition = Vertex.definition(vertex_name)
yield Definition(**data)

def commit(self, query=None):
"""creates a commit with the staged objects"""
author = None
Expand Down
2 changes: 1 addition & 1 deletion tests/edges.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class Car(Vehicle):
vertices = [
incoming_vertex('sold_by', 'Person').through(CarSale),
outgoing_vertex('bought_by', 'Person').through(CarPurchase),
indirect_vertex('deal', 'Car').through(CarDeal),
indirect_vertex('deal', 'Person').through(CarDeal),
]


Expand Down
96 changes: 63 additions & 33 deletions tests/unit/test_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from pygit2 import GIT_FILEMODE_BLOB
from mock import patch, call, MagicMock
from mock import patch, call, MagicMock, ANY

from plural.store import PluralStore
from tests.edges import Car
from tests.edges import Person
from tests.vertices import CarPurchase
from tests.vertices import CarSale
from tests.vertices import CarDeal
from .scenarios import with_graph_store


Expand Down Expand Up @@ -219,7 +220,7 @@ def test_create_edge(context, add_spo, git_object_hash):
@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')
('PluralStore.create_vertex() should add spos for incoming links')

git_object_hash.return_value = 'git-object-hash'
tesla = Car(uuid='car-uuid', brand='Tesla')
Expand All @@ -246,34 +247,63 @@ def test_create_vertex_incoming(context, add_spo, git_object_hash):
])


# @with_graph_store('/path/to/folder')
# @patch('plural.store.pygit2.hash')
# @patch('plural.store.PluralStore.add_spo')
# def test_create_vertex_outgoing(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')
# elon = Person(uuid='elon-uuid', name='Elon Musk')

# sale = context.store.create_vertex(
# CarSale,
# uuid='sales-uuid',
# origin=elon,
# target=tesla,
# contract_signed_at='2017-08-18 00:31:45',
# payment_received_at='2017-07-04 15:25:35',
# )

# sale.should.be.a(CarSale)
# sale.to_dict().should.be.a(dict)

# add_spo.assert_has_calls([
# call('Car/outgoing/sold_by/Person', 'uuid', 'elon-uuid'),
# call('CarSale/indexes/contract_signed_at', 'git-object-hash', 'contract-signed-at'),
# call('CarSale/indexes/payment_sent_at', 'git-object-hash', 'payment-sent-at'),
# call('CarSale/indexes/uuid', 'git-object-hash', 'sale-uuid'),
# call('CarSale/objects', 'git-object-hash', sale.to_json()),
# call('CarSale/_ids', 'sale-uuid', 'git-object-hash'),
# call('CarSale/_uuids', 'git-object-hash', 'sale-uuid')
# ])
@with_graph_store('/path/to/folder')
@patch('plural.store.pygit2.hash')
@patch('plural.store.PluralStore.add_spo')
def test_create_vertex_outgoing(context, add_spo, git_object_hash):
('PluralStore.create_vertex() should add spos for outgoing links')

git_object_hash.return_value = 'git-object-hash'
tesla = Car(uuid='car-uuid', brand='Tesla')
elon = Person(uuid='elon-uuid', name='Elon Musk')

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

add_spo.assert_has_calls([
call('CarSale/indexes/contract_signed_at', 'git-object-hash', '2017-08-18 00:31:45'),
call('CarSale/indexes/payment_received_at', 'git-object-hash', '2017-07-04 15:25:35'),
call('CarSale/indexes/uuid', 'git-object-hash', 'sale-uuid'),
call('CarSale/_ids', 'sale-uuid', 'git-object-hash'),
call('CarSale/_uuids', 'git-object-hash', 'sale-uuid'),
call('Car/outgoing/sold_by/Person', 'car-uuid', 'elon-uuid')
])


@with_graph_store('/path/to/folder')
@patch('plural.store.pygit2.hash')
@patch('plural.store.PluralStore.add_spo')
def test_create_vertex_indirect(context, add_spo, git_object_hash):
('PluralStore.create_vertex() should add spos for indirect links')

git_object_hash.return_value = 'git-object-hash'
chuck = Person(uuid='chuck-uuid', name='Chuck Norris')
elon = Person(uuid='elon-uuid', name='Elon Musk')

deal = context.store.create_vertex(
CarDeal,
uuid='deal-uuid',
origin=elon,
target=chuck,
delivered_at='2017-07-04 15:25:35',
)
deal.should.be.a(CarDeal)
deal.to_dict().should.be.a(dict)

add_spo.assert_has_calls([
call('CarDeal/indexes/delivered_at', 'git-object-hash', '2017-07-04 15:25:35'),
call('CarDeal/indexes/uuid', 'git-object-hash', 'deal-uuid'),
call('CarDeal/_ids', 'deal-uuid', 'git-object-hash'),
call('CarDeal/_uuids', 'git-object-hash', 'deal-uuid'),
# call('CarDeal/objects', 'git-object-hash', ANY),
call('Person/indirect/dealed_with/Person', 'chuck-uuid', 'elon-uuid'),
call('Person/indirect/dealed_with/Person', 'elon-uuid', 'chuck-uuid'),
])
4 changes: 3 additions & 1 deletion tests/vertices.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from plural import IncomingVertex
from plural import IndirectVertex
from plural import OutgoingVertex
from plural import codec

Expand All @@ -38,7 +39,8 @@ class CarSale(OutgoingVertex):
}


class CarDeal(OutgoingVertex):
class CarDeal(IndirectVertex):
label, target = 'dealed_with', 'Person'
indexes = {'delivered_at'}
fields = {
'delivered_at': codec.DateTime,
Expand Down

0 comments on commit 2855db5

Please sign in to comment.