Skip to content
This repository was archived by the owner on Oct 9, 2023. It is now read-only.

Commit b348bc9

Browse files
author
Ganeshwara Hananda
authored
RPC implementation for sending match aggregate, match group, and match group aggregate queries (#148)
## What is the goal of this PR? We have implemented RPC support for sending match aggregate, match group, and match group aggregate queries to server ## What are the changes implemented in this PR? 1. Update `@graknlabs_protocol` to the version that supports the new queries. 2. Support processing the new queries
1 parent e42ecc6 commit b348bc9

File tree

12 files changed

+185
-42
lines changed

12 files changed

+185
-42
lines changed

dependencies/graknlabs/artifacts.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ def graknlabs_grakn_core_artifacts():
2727
artifact_name = "grakn-core-server-{platform}-{version}.{ext}",
2828
tag_source = deployment["artifact.release"],
2929
commit_source = deployment["artifact.snapshot"],
30-
commit = "81653e39fa681d20b37fdba13f158a0d1c1a6c2e",
30+
commit = "118eee244a4949c629de0277804155ebd4b316be",
3131
)

grakn/concept/answer/concept_map.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@
2323

2424
from grakn.common.exception import GraknClientException
2525
from grakn.concept.proto import concept_proto_reader
26-
from grakn.concept.answer.answer import Answer
2726
from grakn.concept.concept import Concept
2827

2928

30-
class ConceptMap(Answer):
29+
class ConceptMap:
3130

3231
_THING = "thing"
3332

@@ -63,10 +62,6 @@ def __hash__(self):
6362
def _of(concept_map_proto: answer_proto.ConceptMap):
6463
variable_map = {}
6564
for res_var in concept_map_proto.map:
66-
res_concept = concept_map_proto.map[res_var]
67-
if res_concept.HasField(ConceptMap._THING):
68-
concept = concept_proto_reader.thing(res_concept.thing)
69-
else:
70-
concept = concept_proto_reader.type_(res_concept.type)
65+
concept = concept_proto_reader.concept(concept_map_proto.map[res_var])
7166
variable_map[res_var] = concept
7267
return ConceptMap(variable_map)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
20+
import graknprotocol.protobuf.answer_pb2 as answer_proto
21+
from grakn.concept.answer import concept_map
22+
from grakn.concept.proto.concept_proto_reader import concept
23+
24+
class ConceptMapGroup:
25+
def __init__(self, owner, concept_maps):
26+
self._owner = owner
27+
self._concept_maps = concept_maps
28+
29+
def owner(self):
30+
return self._owner
31+
32+
def concept_maps(self):
33+
return self._concept_maps
34+
35+
36+
def _of(concept_map_group_proto: answer_proto.ConceptMapGroup):
37+
return ConceptMapGroup(concept(concept_map_group_proto.owner), map(lambda cm: concept_map._of(cm), concept_map_group_proto.concept_maps))

grakn/concept/answer/numeric.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
20+
import graknprotocol.protobuf.answer_pb2 as answer_proto
21+
22+
from grakn.common.exception import GraknClientException
23+
24+
25+
class Numeric:
26+
def __init__(self, int_value, float_value):
27+
self._int_value = int_value
28+
self._float_value = float_value
29+
30+
def is_int(self):
31+
return self._int_value is not None
32+
33+
def is_float(self):
34+
return self._float_value is not None
35+
36+
def is_nan(self):
37+
return not self.is_int() and not self.is_float()
38+
39+
def as_float(self):
40+
if (self.is_float()):
41+
return self._float_value
42+
else:
43+
raise GraknClientException("Illegal casting operation to 'float'.")
44+
45+
def as_int(self):
46+
if (self.is_int()):
47+
return self._int_value
48+
else:
49+
raise GraknClientException("Illegal casting operation to 'int'.")
50+
51+
52+
def _of(numeric_proto: answer_proto.Numeric):
53+
numeric_case = numeric_proto.WhichOneof("value")
54+
if numeric_case == "long_value":
55+
return Numeric(numeric_proto.long_value, None)
56+
elif numeric_case == "double_value":
57+
return Numeric(None, numeric_proto.double_value)
58+
elif numeric_case == "nan":
59+
return Numeric(None, None)
60+
else:
61+
raise GraknClientException("The answer type '" + numeric_case + "' was not recognised.")

grakn/concept/answer/answer.py renamed to grakn/concept/answer/numeric_group.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,20 @@
1818
#
1919

2020
import graknprotocol.protobuf.answer_pb2 as answer_proto
21+
from grakn.concept.answer import numeric
22+
from grakn.concept.proto.concept_proto_reader import concept
2123

22-
from grakn.common.exception import GraknClientException
23-
from grakn.concept.answer import concept_map
24+
class NumericGroup:
25+
def __init__(self, owner, numeric):
26+
self._owner = owner
27+
self._numeric = numeric
2428

29+
def owner(self):
30+
return self._owner
2531

26-
class Answer(object):
32+
def numeric(self):
33+
return self._numeric
2734

28-
_CONCEPT_MAP = "concept_map"
2935

30-
31-
def _of(proto_answer: answer_proto.Answer):
32-
answer_case = proto_answer.WhichOneof("answer")
33-
if answer_case == Answer._CONCEPT_MAP:
34-
return concept_map._of(proto_answer.concept_map)
35-
raise GraknClientException("The answer type " + answer_case + " was not recognised.")
36+
def _of(numeric_group_proto: answer_proto.NumericGroup):
37+
return NumericGroup(concept(numeric_group_proto.owner), numeric._of(numeric_group_proto.number))

grakn/concept/proto/concept_proto_reader.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import graknprotocol.protobuf.concept_pb2 as concept_proto
2121

2222
from grakn.common.exception import GraknClientException
23+
from grakn.concept.answer.concept_map import ConceptMap
2324
from grakn.concept.thing.attribute import BooleanAttribute, LongAttribute, DoubleAttribute, StringAttribute, \
2425
DateTimeAttribute
2526
from grakn.concept.thing.entity import Entity
@@ -32,6 +33,14 @@
3233
from grakn.concept.type.thing_type import ThingType
3334

3435

36+
def concept(con_proto: concept_proto.Concept):
37+
if con_proto.HasField(ConceptMap._THING):
38+
concept = thing(con_proto.thing)
39+
else:
40+
concept = type_(con_proto.type)
41+
return concept
42+
43+
3544
def thing(thing_proto: concept_proto.Thing):
3645
if thing_proto.encoding == concept_proto.Thing.Encoding.Value("ENTITY"):
3746
return Entity._of(thing_proto)

grakn/query/query_manager.py

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import graknprotocol.protobuf.transaction_pb2 as transaction_proto
2424

2525
from grakn import grakn_proto_builder
26-
from grakn.concept.answer import concept_map
26+
from grakn.concept.answer import concept_map, concept_map_group, numeric, numeric_group
2727
from grakn.options import GraknOptions
2828

2929

@@ -34,45 +34,65 @@ def __init__(self, transaction):
3434

3535
def match(self, query: str, options=GraknOptions()):
3636
request = query_proto.Query.Req()
37-
match_req = query_proto.Graql.Match.Req()
37+
match_req = query_proto.Query.Match.Req()
3838
match_req.query = query
3939
request.match_req.CopyFrom(match_req)
4040
return map(lambda answer_proto: concept_map._of(answer_proto), self._iterate_query(request, lambda res: res.query_res.match_res.answers, options))
4141

42+
def match_aggregate(self, query: str, options=GraknOptions()):
43+
request = query_proto.Query.Req()
44+
match_aggregate_req = query_proto.Query.MatchAggregate.Req()
45+
match_aggregate_req.query = query
46+
request.match_aggregate_req.CopyFrom(match_aggregate_req)
47+
return self._iterate_query(request, lambda res: [numeric._of(res.query_res.match_aggregate_res.answer)], options)
48+
49+
def match_group(self, query: str, options=GraknOptions()):
50+
request = query_proto.Query.Req()
51+
match_group_req = query_proto.Query.MatchGroup.Req()
52+
match_group_req.query = query
53+
request.match_group_req.CopyFrom(match_group_req)
54+
return map(
55+
lambda cmg_proto: concept_map_group._of(cmg_proto),
56+
self._iterate_query(request, lambda res: res.query_res.match_group_res.answers, options)
57+
)
58+
59+
def match_group_aggregate(self, query: str, options=GraknOptions()):
60+
request = query_proto.Query.Req()
61+
match_group_aggregate_req = query_proto.Query.MatchGroupAggregate.Req()
62+
match_group_aggregate_req.query = query
63+
request.match_group_aggregate_req.CopyFrom(match_group_aggregate_req)
64+
return map(
65+
lambda numeric_group_proto: numeric_group._of(numeric_group_proto),
66+
self._iterate_query(request, lambda res: res.query_res.match_group_aggregate_res.answers, options)
67+
)
68+
4269
def insert(self, query: str, options=GraknOptions()):
4370
request = query_proto.Query.Req()
44-
insert_req = query_proto.Graql.Insert.Req()
71+
insert_req = query_proto.Query.Insert.Req()
4572
insert_req.query = query
4673
request.insert_req.CopyFrom(insert_req)
4774
return map(lambda answer_proto: concept_map._of(answer_proto), self._iterate_query(request, lambda res: res.query_res.insert_res.answers, options))
4875

4976
def delete(self, query: str, options=GraknOptions()):
5077
request = query_proto.Query.Req()
51-
delete_req = query_proto.Graql.Delete.Req()
78+
delete_req = query_proto.Query.Delete.Req()
5279
delete_req.query = query
5380
request.delete_req.CopyFrom(delete_req)
54-
return self._run_query(request, options)
81+
return self._iterate_query(request, lambda res: [], options)
5582

5683
def define(self, query: str, options=GraknOptions()):
5784
request = query_proto.Query.Req()
58-
define_req = query_proto.Graql.Define.Req()
85+
define_req = query_proto.Query.Define.Req()
5986
define_req.query = query
6087
request.define_req.CopyFrom(define_req)
61-
return self._run_query(request, options)
88+
return self._iterate_query(request, lambda res: [], options)
6289

6390
def undefine(self, query: str, options=GraknOptions()):
6491
request = query_proto.Query.Req()
65-
undefine_req = query_proto.Graql.Undefine.Req()
92+
undefine_req = query_proto.Query.Undefine.Req()
6693
undefine_req.query = query
6794
request.undefine_req.CopyFrom(undefine_req)
68-
return self._run_query(request, options)
69-
70-
def _run_query(self, query_req: query_proto.Query.Req, options: GraknOptions):
71-
req = transaction_proto.Transaction.Req()
72-
query_req.options.CopyFrom(grakn_proto_builder.options(options))
73-
req.query_req.CopyFrom(query_req)
74-
# Using stream makes this request asynchronous.
75-
return self._transaction._stream(req)
95+
return self._iterate_query(request, lambda res: [], options)
7696

7797
def _iterate_query(self, query_req: query_proto.Query.Req, response_reader: Callable[[transaction_proto.Transaction.Res], List], options: GraknOptions):
7898
req = transaction_proto.Transaction.Req()

requirements.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717
# under the License.
1818
#
1919

20-
2120
## Configuration options
2221

2322
# --extra-index-url https://repo.grakn.ai/repository/pypi-snapshot/simple # Allow importing of snapshots
2423

2524

2625
## Dependencies
2726

28-
graknprotocol==2.0.0a4
27+
graknprotocol==2.0.0a5
2928
grpcio==1.33.2
3029
protobuf==3.6.1
3130
six>=1.11.0

tests/integration/test_concept.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from grakn.client import GraknClient, SessionType, TransactionType, ValueType
2424
from grakn.common.exception import GraknClientException
25-
from test.integration.base import test_base, GraknServer
25+
from tests.integration.base import test_base, GraknServer
2626

2727

2828
class TestConcept(test_base):

tests/integration/test_connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import unittest
2121
from grakn.client import GraknClient, SessionType, TransactionType
22-
from test.integration.base import test_base, GraknServer
22+
from tests.integration.base import test_base, GraknServer
2323

2424

2525
class TestConnection(test_base):

0 commit comments

Comments
 (0)