Skip to content

Commit 7e88c86

Browse files
authored
Upgrade/0.14.0 (#13)
* Updated README with instructions detailing proto client file generation. * Updated proto client. Updated the gRPC Python client files and adjusted the Cottontail DB Python client and affected tests. * Bumped versions.
1 parent cc05a05 commit 7e88c86

File tree

7 files changed

+321
-3943
lines changed

7 files changed

+321
-3943
lines changed

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
# Setup Cottontail DB service container
2121
services:
2222
cottontail:
23-
image: vitrivr/cottontaildb:0.14.1
23+
image: vitrivr/cottontaildb:0.15.0
2424
ports:
2525
- 1865:1865
2626
options: -it

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Python package workflow](https://github.com/Spiess/cottontaildb-python-client/actions/workflows/python-package.yml/badge.svg)](https://github.com/Spiess/cottontaildb-python-client/actions/workflows/python-package.yml)
55

66
A Cottontail DB gRPC client for Python. Built with [Cottontail DB Proto](https://github.com/vitrivr/cottontaildb-proto)
7-
version `0.13.0`. Comes with an interactive CLI for remote DB access.
7+
version `0.14.0`. Comes with an interactive CLI for remote DB access.
88

99
## Installation
1010

@@ -41,3 +41,24 @@ with CottontailDBClient('localhost', 1865) as client:
4141
]
4242
client.insert_batch('example_schema', 'example_entity', columns, values)
4343
```
44+
45+
## Developing
46+
47+
To update the gRPC client, regenerate `cottontaildb_pb2.py` and `cottontaildb_pb2_grpc.py` from the proto definitions
48+
file in the [Cottontail DB Proto](https://github.com/vitrivr/cottontaildb-proto) repository.
49+
50+
The following is an approximate guide on how to do so from a terminal:
51+
52+
```bash
53+
# Get the latest version of the Cottontail DB proto
54+
wget https://github.com/vitrivr/cottontaildb-proto/raw/master/src/main/protobuf/cottontail.proto
55+
# Install necessary python packages
56+
pip install grpcio grpcio-tools
57+
# Generate the gRPC client
58+
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. cottontail.proto
59+
# Update the client files (where PYTHON_CLIENT_PATH is the path to this repository)
60+
mv cottontail_pb2.py cottontail_pb2_grpc.py $PYTHON_CLIENT_PATH/cottontaildb_client/
61+
```
62+
63+
Finally, the line `import cottontail_pb2 as cottontail__pb2` in the file `cottontail_pb2_grpc.py` must be replaced
64+
with `from . import cottontail_pb2 as cottontail__pb2`.

cottontaildb_client/cottontail_pb2.py

Lines changed: 275 additions & 3886 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cottontaildb_client/cottontail_pb2_grpc.py

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -633,11 +633,6 @@ def __init__(self, channel):
633633
request_serializer=cottontail__pb2.QueryMessage.SerializeToString,
634634
response_deserializer=cottontail__pb2.QueryResponseMessage.FromString,
635635
)
636-
self.BatchQuery = channel.unary_stream(
637-
'/org.vitrivr.cottontail.grpc.DQL/BatchQuery',
638-
request_serializer=cottontail__pb2.BatchedQueryMessage.SerializeToString,
639-
response_deserializer=cottontail__pb2.QueryResponseMessage.FromString,
640-
)
641636
self.Ping = channel.unary_unary(
642637
'/org.vitrivr.cottontail.grpc.DQL/Ping',
643638
request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
@@ -664,13 +659,6 @@ def Query(self, request, context):
664659
context.set_details('Method not implemented!')
665660
raise NotImplementedError('Method not implemented!')
666661

667-
def BatchQuery(self, request, context):
668-
"""* Executes a batched query through Cottontail DB (not supported yet).
669-
"""
670-
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
671-
context.set_details('Method not implemented!')
672-
raise NotImplementedError('Method not implemented!')
673-
674662
def Ping(self, request, context):
675663
"""* Pings the endpoint
676664
"""
@@ -691,11 +679,6 @@ def add_DQLServicer_to_server(servicer, server):
691679
request_deserializer=cottontail__pb2.QueryMessage.FromString,
692680
response_serializer=cottontail__pb2.QueryResponseMessage.SerializeToString,
693681
),
694-
'BatchQuery': grpc.unary_stream_rpc_method_handler(
695-
servicer.BatchQuery,
696-
request_deserializer=cottontail__pb2.BatchedQueryMessage.FromString,
697-
response_serializer=cottontail__pb2.QueryResponseMessage.SerializeToString,
698-
),
699682
'Ping': grpc.unary_unary_rpc_method_handler(
700683
servicer.Ping,
701684
request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
@@ -747,23 +730,6 @@ def Query(request,
747730
options, channel_credentials,
748731
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
749732

750-
@staticmethod
751-
def BatchQuery(request,
752-
target,
753-
options=(),
754-
channel_credentials=None,
755-
call_credentials=None,
756-
insecure=False,
757-
compression=None,
758-
wait_for_ready=None,
759-
timeout=None,
760-
metadata=None):
761-
return grpc.experimental.unary_stream(request, target, '/org.vitrivr.cottontail.grpc.DQL/BatchQuery',
762-
cottontail__pb2.BatchedQueryMessage.SerializeToString,
763-
cottontail__pb2.QueryResponseMessage.FromString,
764-
options, channel_credentials,
765-
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
766-
767733
@staticmethod
768734
def Ping(request,
769735
target,

cottontaildb_client/cottontaildb_client.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from typing import List
66

77
from .cottontail_pb2 import SchemaName, CreateSchemaMessage, DropSchemaMessage, EntityName, ColumnDefinition, \
8-
EntityDefinition, CreateEntityMessage, Engine, InsertMessage, ColumnName, Scan, From, Type, ListSchemaMessage, \
8+
EntityDefinition, CreateEntityMessage, InsertMessage, ColumnName, Scan, From, Type, ListSchemaMessage, \
99
ListEntityMessage, EntityDetailsMessage, DropEntityMessage, TruncateEntityMessage, OptimizeEntityMessage, \
10-
IndexName, IndexDefinition, IndexType, CreateIndexMessage, DropIndexMessage, RebuildIndexMessage, UpdateMessage, \
10+
IndexName, IndexType, CreateIndexMessage, DropIndexMessage, RebuildIndexMessage, UpdateMessage, \
1111
DeleteMessage, Literal, Vector, FloatVector, BatchInsertMessage, Metadata, QueryMessage, Query
1212
from .cottontail_pb2_grpc import DDLStub, DMLStub, TXNStub, DQLStub
1313

@@ -170,12 +170,10 @@ def create_index(self, schema, entity, index, index_type: IndexType, columns: Li
170170
"""
171171
schema_name = SchemaName(name=schema)
172172
entity_name = EntityName(schema=schema_name, name=entity)
173-
index_name = IndexName(entity=entity_name, name=index)
174173
# TODO: map<string,string> params
175-
column_names = [ColumnName(entity=entity_name, name=c) for c in columns]
176-
index_def = IndexDefinition(name=index_name, type=index_type, columns=column_names)
177174
response = self._ddl.CreateIndex(
178-
CreateIndexMessage(metadata=Metadata(transactionId=self._tid), definition=index_def, rebuild=rebuild))
175+
CreateIndexMessage(metadata=Metadata(transactionId=self._tid), entity=entity_name, type=index_type,
176+
indexName=index, columns=columns, rebuild=rebuild))
179177
return self._parse_query_response(response)
180178

181179
def drop_index(self, schema, entity, index):
@@ -238,7 +236,8 @@ def get_entity_details(self, schema, entity):
238236
"""
239237
schema_name = SchemaName(name=schema)
240238
entity_name = EntityName(schema=schema_name, name=entity)
241-
response = self._ddl.EntityDetails(EntityDetailsMessage(metadata=Metadata(transactionId=self._tid), entity=entity_name))
239+
response = self._ddl.EntityDetails(
240+
EntityDetailsMessage(metadata=Metadata(transactionId=self._tid), entity=entity_name))
242241
entity_data = response.tuples[0]
243242
data_names = [c.name.name for c in response.columns]
244243
name_index = data_names.index('dbo')
@@ -344,19 +343,22 @@ def ping(self):
344343
"""Sends a ping message to the endpoint. If method returns without exception endpoint is connected."""
345344
self._dql.Ping(Empty())
346345

347-
def query(self, schema, entity, projection, where):
346+
def query(self, schema, entity, projection, where, order=None, limit=None, skip=None):
348347
"""
349348
Queries the specified entity where the provided conditions are met and applies the given projection.
350349
351350
@param schema: the schema containing the queried entity
352351
@param entity: the entity being queried
353352
@param projection: the projection to be applied to the result
354353
@param where: where clause specifying the rows to return
354+
@param order: order by clause specifying the order of the result
355+
@param limit: maximum number of rows to return
356+
@param skip: number of rows to skip
355357
"""
356358
schema_name = SchemaName(name=schema)
357359
entity_name = EntityName(schema=schema_name, name=entity)
358360
from_kwarg = {'from': From(scan=Scan(entity=entity_name))}
359-
query = Query(**from_kwarg, projection=projection, where=where)
361+
query = Query(**from_kwarg, projection=projection, where=where, order=order, limit=limit, skip=skip)
360362
responses = self._dql.Query(QueryMessage(metadata=Metadata(transactionId=self._tid), query=query))
361363
return [r for response in responses for r in self._parse_query_response(response)]
362364

@@ -403,8 +405,7 @@ def _insert_helper(self, schema, entity, values):
403405
return InsertMessage(metadata=Metadata(transactionId=self._tid), **from_kwarg, elements=elements)
404406

405407

406-
def column_def(name: str, type_: Type, length: int = None, primary: bool = None, nullable: bool = None,
407-
engine: Engine = Engine.MAPDB):
408+
def column_def(name: str, type_: Type, length: int = None, primary: bool = None, nullable: bool = None):
408409
"""
409410
Creates a column definition.
410411
@@ -413,13 +414,11 @@ def column_def(name: str, type_: Type, length: int = None, primary: bool = None,
413414
@param length: data length for vector types
414415
@param primary: if this is a primary column of the entity
415416
@param nullable: if this column may be null
416-
@param engine: storage engine to use (currently only MapDB)
417417
@return: column definition
418418
"""
419419
kwargs = {
420420
'name': ColumnName(name=name),
421-
'type': type_,
422-
'engine': engine
421+
'type': type_
423422
}
424423
if length is not None:
425424
kwargs['length'] = length

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = cottontaildb-client
3-
version = 0.0.5
3+
version = 0.0.6
44
author = Florian Spiess
55
author_email = [email protected]
66
description = A Cottontail DB gRPC client.

tests/test_cottontaildb_client.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from cottontaildb_client import CottontailDBClient, column_def, Type, Literal, float_vector
66
from cottontaildb_client.cottontail_pb2 import Where, AtomicBooleanPredicate, ColumnName, AtomicBooleanOperand, \
7-
ComparisonOperator, Expressions, Expression, Projection, IndexType
7+
ComparisonOperator, Expressions, Expression, Projection, IndexType, EntityName, SchemaName
88

99
DB_HOST = 'localhost'
1010
DB_PORT = 1865
@@ -132,7 +132,7 @@ def test_create_rebuild_drop_index(self):
132132
self._batch_insert()
133133
details = self.client.get_entity_details(TEST_SCHEMA, TEST_ENTITY)
134134
self.assertEqual(len(details['indexes']), 0, 'unexpected number of indexes in entity before index creation')
135-
self.client.create_index(TEST_SCHEMA, TEST_ENTITY, TEST_INDEX, IndexType.HASH, [TEST_COLUMN_VALUE])
135+
self.client.create_index(TEST_SCHEMA, TEST_ENTITY, TEST_INDEX, IndexType.BTREE, [TEST_COLUMN_VALUE])
136136
details = self.client.get_entity_details(TEST_SCHEMA, TEST_ENTITY)
137137
self.assertEqual(len(details['indexes']), 1, 'index was not created')
138138
self.client.rebuild_index(TEST_SCHEMA, TEST_ENTITY, TEST_INDEX)
@@ -200,8 +200,8 @@ def _insert(self):
200200
self.client.insert(TEST_SCHEMA, TEST_ENTITY, values)
201201

202202
def _insert_vector(self):
203-
list = [0.2, 0.3, 0.5]
204-
values = {'id': Literal(stringData='test_0'), 'value': float_vector(*list)}
203+
value_list = [0.2, 0.3, 0.5]
204+
values = {'id': Literal(stringData='test_0'), 'value': float_vector(*value_list)}
205205
self.client.insert(TEST_SCHEMA, TEST_VECTOR_ENTITY, values)
206206

207207
def _batch_insert(self):
@@ -236,8 +236,11 @@ def _update_value_with_key(self, key, value):
236236
self.client.update(TEST_SCHEMA, TEST_ENTITY, where, updates)
237237

238238
def _query_value_with_key(self, key):
239-
projection = Projection(op=Projection.ProjectionOperation.SELECT,
240-
elements=[Projection.ProjectionElement(column=ColumnName(name=TEST_COLUMN_VALUE))])
239+
schema_name = SchemaName(name=TEST_SCHEMA)
240+
entity_name = EntityName(schema=schema_name, name=TEST_ENTITY)
241+
expression = Expression(column=ColumnName(entity=entity_name, name=TEST_COLUMN_VALUE))
242+
projection_element = Projection.ProjectionElement(expression=expression)
243+
projection = Projection(op=Projection.ProjectionOperation.SELECT, elements=[projection_element])
241244
where = Where(atomic=AtomicBooleanPredicate(
242245
left=ColumnName(name=TEST_COLUMN_ID),
243246
right=AtomicBooleanOperand(

0 commit comments

Comments
 (0)