From b041a090de9ad69d6377b3fb7d256bd4929c3f44 Mon Sep 17 00:00:00 2001 From: dshylov Date: Thu, 18 Jan 2018 18:11:46 +0200 Subject: [PATCH 01/12] MAPRDB-397 Investigate and implement client API interfaces for Python language support. Added abstract classes as init commit for ticket. --- .gitignore | 13 +++ entity/Table.py | 0 entity/document/Document.py | 124 ++++++++++++++++++++++++++ entity/document/DocumentBuilder.py | 96 ++++++++++++++++++++ entity/document/DocumentListener.py | 20 +++++ entity/document/DocumentMutation.py | 53 +++++++++++ entity/document/DocumentStore.py | 80 +++++++++++++++++ entity/document/DocumentStream.py | 28 ++++++ entity/document/document_constants.py | 3 + entity/storage/Connection.py | 44 +++++++++ entity/storage/DriverManager.py | 24 +++++ 11 files changed, 485 insertions(+) create mode 100644 .gitignore create mode 100644 entity/Table.py create mode 100644 entity/document/Document.py create mode 100644 entity/document/DocumentBuilder.py create mode 100644 entity/document/DocumentListener.py create mode 100644 entity/document/DocumentMutation.py create mode 100644 entity/document/DocumentStore.py create mode 100644 entity/document/DocumentStream.py create mode 100644 entity/document/document_constants.py create mode 100644 entity/storage/Connection.py create mode 100644 entity/storage/DriverManager.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485b27d --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.project +.classpath +.checkstyle +.settings/ +.idea/ +*.log +*.lck +*.iml +target/ +*.DS_Store +*.patch +*~ +git.properties diff --git a/entity/Table.py b/entity/Table.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/document/Document.py b/entity/document/Document.py new file mode 100644 index 0000000..927b5e2 --- /dev/null +++ b/entity/document/Document.py @@ -0,0 +1,124 @@ +from abc import ABCMeta, abstractmethod + + +class Document: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def set_id(self, _id): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_id(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_id_string(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_id_binary(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def size(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def empty(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_array(self, field_path, values): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_null(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def delete(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_string(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_boolean(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_byte(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_short(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_int(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_long(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_float(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_double(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_decimal(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_time(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_date(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_timestamp(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_binary(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_interval(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_value(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_map(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_list(self, field_path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def as_reader(self, field_path=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def as_map(self): + raise NotImplementedError("Should have implemented this") diff --git a/entity/document/DocumentBuilder.py b/entity/document/DocumentBuilder.py new file mode 100644 index 0000000..29b6d58 --- /dev/null +++ b/entity/document/DocumentBuilder.py @@ -0,0 +1,96 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentBuilder: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def put(self, field, value, offset=None, length=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_decimal(self, field, value, scale=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_date(self, field, days): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_time(self, field, millis): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_timestamp(self, field, time_millis): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_new_interval(self, field, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_new_map(self, field): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_new_array(self, field): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_null(self, field): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_array_index(self, index): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add(self, value, offset=None, length=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_decimal(self, decimal_value, scale=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_null(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_new_array(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_new_map(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_time(self, millis): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_date(self, days): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_timestamp(self, time_millis): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_interval(self, duration_in_ms): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def end_array(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_map(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_document(self): + raise NotImplementedError("Should have implemented this") diff --git a/entity/document/DocumentListener.py b/entity/document/DocumentListener.py new file mode 100644 index 0000000..9dab135 --- /dev/null +++ b/entity/document/DocumentListener.py @@ -0,0 +1,20 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentListener: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def document_arrived(self, doc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def failed(self, exception): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def eos(self): + raise NotImplementedError("Should have implemented this") \ No newline at end of file diff --git a/entity/document/DocumentMutation.py b/entity/document/DocumentMutation.py new file mode 100644 index 0000000..00e89bb --- /dev/null +++ b/entity/document/DocumentMutation.py @@ -0,0 +1,53 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentMutation: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def empty(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_null(self, path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set(self, path, value=None, doc=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_collection(self, path, collection): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_null(self, path): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def append(self, path, value, offset=None, len=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def merge(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment(self, path, inc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def decrement(self, path, dec): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def delete(self, path): + raise NotImplementedError("Should have implemented this") + diff --git a/entity/document/DocumentStore.py b/entity/document/DocumentStore.py new file mode 100644 index 0000000..d5353af --- /dev/null +++ b/entity/document/DocumentStore.py @@ -0,0 +1,80 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentStore: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def is_read_only(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def flush(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def begin_tracking_writes(self, previous_writes_context=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def end_tracking_writes(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def clear_tracked_writes(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def find_by_id(self, _id, field_paths=None, condition=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def find(self, query=None, field_paths=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def find_query(self, query=None, field_paths=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def insert_or_replace(self, doc, _id=None, field_as_key=None, doc_stream=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def update(self, _id, mutation): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def delete(self, _id=None, doc=None, field_as_key=None, doc_stream=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def insert(self, _id=None, doc=None, field_as_key=None, doc_stream=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def insert(self, _id=None, doc=None, field_as_key=None, doc_stream=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment(self, _id, field, inc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def check_and_mutate(self, _id, query_condition, mutation): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def check_and_delete(self, _id, condition): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def check_and_replace(self, _id, condition, doc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def close(self): + raise NotImplementedError("Should have implemented this") \ No newline at end of file diff --git a/entity/document/DocumentStream.py b/entity/document/DocumentStream.py new file mode 100644 index 0000000..3b13d19 --- /dev/null +++ b/entity/document/DocumentStream.py @@ -0,0 +1,28 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentStream: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def stream_to(self, doc_listener): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def iterator(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def document_readers(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def close(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_query_plan(self): + raise NotImplementedError("Should have implemented this") \ No newline at end of file diff --git a/entity/document/document_constants.py b/entity/document/document_constants.py new file mode 100644 index 0000000..46fd7d8 --- /dev/null +++ b/entity/document/document_constants.py @@ -0,0 +1,3 @@ +DOCUMENT_KEY = "$$document" +ID_KEY = "_id" +ID_FIELD = "" #TODO Implement FieldPath like in OJAI \ No newline at end of file diff --git a/entity/storage/Connection.py b/entity/storage/Connection.py new file mode 100644 index 0000000..663d5d8 --- /dev/null +++ b/entity/storage/Connection.py @@ -0,0 +1,44 @@ +from abc import ABCMeta, abstractmethod + + +class Connection: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def get_store(self, store_name, options=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_value_buffer(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def new_document(self, json_string=None, json_map=None, bean=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def new_document_builder(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def new_mutation(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def new_condition(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def new_query(self, query_json=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_driver(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def close(self): + raise NotImplementedError("Should have implemented this") diff --git a/entity/storage/DriverManager.py b/entity/storage/DriverManager.py new file mode 100644 index 0000000..9747404 --- /dev/null +++ b/entity/storage/DriverManager.py @@ -0,0 +1,24 @@ +from abc import ABCMeta, abstractmethod + + +class DriverManager: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def get_driver(self, url): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_connection(self, url, options=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def register_driver(self, driver): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def check_url(self, url): + raise NotImplementedError("Should have implemented this") \ No newline at end of file From e5aee886db05d361920ac916d88b8c976dfb7e01 Mon Sep 17 00:00:00 2001 From: dshylov Date: Fri, 19 Jan 2018 18:42:36 +0200 Subject: [PATCH 02/12] MAPRDB-397 Investigate and implement client API interfaces for Python language support. Added set of functions for different data types --- entity/document/Document.py | 56 +++++++++- entity/document/DocumentBuilder.py | 64 ++++++++++- entity/document/DocumentMutation.py | 162 +++++++++++++++++++++++++++- entity/document/DocumentStore.py | 66 +++++++++++- 4 files changed, 334 insertions(+), 14 deletions(-) diff --git a/entity/document/Document.py b/entity/document/Document.py index 927b5e2..7f27fe8 100644 --- a/entity/document/Document.py +++ b/entity/document/Document.py @@ -35,6 +35,58 @@ def empty(self): def set(self, field_path, value): raise NotImplementedError("Should have implemented this") + @abstractmethod + def set_boolean(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_byte(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_long(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_float(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_decimal(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_time(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_date(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_timestamp(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_interval(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_byte_array(self, field_path, value, offset=None, length=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_map(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_document(self, field_path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_value_obj(self, field_path, value): + raise NotImplementedError("Should have implemented this") + @abstractmethod def set_array(self, field_path, values): raise NotImplementedError("Should have implemented this") @@ -59,10 +111,6 @@ def get_boolean(self, field_path): def get_byte(self, field_path): raise NotImplementedError("Should have implemented this") - @abstractmethod - def get_short(self, field_path): - raise NotImplementedError("Should have implemented this") - @abstractmethod def get_int(self, field_path): raise NotImplementedError("Should have implemented this") diff --git a/entity/document/DocumentBuilder.py b/entity/document/DocumentBuilder.py index 29b6d58..4f17faa 100644 --- a/entity/document/DocumentBuilder.py +++ b/entity/document/DocumentBuilder.py @@ -8,7 +8,27 @@ def __init__(self): pass @abstractmethod - def put(self, field, value, offset=None, length=None): + def put(self, field, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_float(self, field, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_byte(self, field, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_byte_array(self, field, value, offset=None, length=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_date(self, field, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_time(self, field, value): raise NotImplementedError("Should have implemented this") @abstractmethod @@ -31,6 +51,10 @@ def put_timestamp(self, field, time_millis): def put_new_interval(self, field, value): raise NotImplementedError("Should have implemented this") + @abstractmethod + def put_map(self, field, value): + raise NotImplementedError("Should have implemented this") + @abstractmethod def put_new_map(self, field): raise NotImplementedError("Should have implemented this") @@ -43,12 +67,48 @@ def put_new_array(self, field): def put_null(self, field): raise NotImplementedError("Should have implemented this") + @abstractmethod + def put_document(self, field, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def put_value_obj(self, field, value): + raise NotImplementedError("Should have implemented this") + @abstractmethod def set_array_index(self, index): raise NotImplementedError("Should have implemented this") @abstractmethod - def add(self, value, offset=None, length=None): + def add(self, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_boolean(self, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_byte(self, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_long(self, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_float(self, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_byte_array(self, value, offset=None, length=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_document(self, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def add_value_obj(self, value): raise NotImplementedError("Should have implemented this") @abstractmethod diff --git a/entity/document/DocumentMutation.py b/entity/document/DocumentMutation.py index 00e89bb..06f27e4 100644 --- a/entity/document/DocumentMutation.py +++ b/entity/document/DocumentMutation.py @@ -16,11 +16,59 @@ def set_null(self, path): raise NotImplementedError("Should have implemented this") @abstractmethod - def set(self, path, value=None, doc=None): + def set(self, path, value): raise NotImplementedError("Should have implemented this") @abstractmethod - def set_collection(self, path, collection): + def set_string(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_boolean(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_byte(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_long(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_float(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_date(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_time(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_timestamp(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_interval(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_list(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_map(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_document(self, path, doc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_value_obj(self, path, value): raise NotImplementedError("Should have implemented this") @abstractmethod @@ -32,21 +80,129 @@ def set_or_replace(self, path, value): raise NotImplementedError("Should have implemented this") @abstractmethod - def append(self, path, value, offset=None, len=None): + def set_or_replace_value_obj(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_boolean(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_byte(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_long(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_float(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_string(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_decimal(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_date(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_time(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_timestamp(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_interval(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_list(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_map(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def set_or_replace_doc(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def append(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def append_list(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def append_string(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def append_byte_array(self, path, value, offset=None, length=None): raise NotImplementedError("Should have implemented this") @abstractmethod def merge(self, path, value): raise NotImplementedError("Should have implemented this") + @abstractmethod + def merge_document(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def merge_map(self, path, value): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment(self, path, inc): + raise NotImplementedError("Should have implemented this") + @abstractmethod def increment(self, path, inc): raise NotImplementedError("Should have implemented this") + @abstractmethod + def increment_float(self, path, inc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment_byte(self, path, inc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment_decimal(self, path, inc): + raise NotImplementedError("Should have implemented this") + @abstractmethod def decrement(self, path, dec): raise NotImplementedError("Should have implemented this") + @abstractmethod + def decrement(self, path, dec): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def decrement_float(self, path, dec): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def decrement_byte(self, path, dec): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def decrement_decimal(self, path, dec): + raise NotImplementedError("Should have implemented this") + @abstractmethod def delete(self, path): raise NotImplementedError("Should have implemented this") diff --git a/entity/document/DocumentStore.py b/entity/document/DocumentStore.py index d5353af..7e87d3d 100644 --- a/entity/document/DocumentStore.py +++ b/entity/document/DocumentStore.py @@ -27,42 +27,98 @@ def end_tracking_writes(self): def clear_tracked_writes(self): raise NotImplementedError("Should have implemented this") + @abstractmethod + def find_by_id_value_obj(self, _id, field_paths=None, condition=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def find_by_id_string(self, _id, field_paths=None, condition=None): + raise NotImplementedError("Should have implemented this") + @abstractmethod def find_by_id(self, _id, field_paths=None, condition=None): raise NotImplementedError("Should have implemented this") @abstractmethod - def find(self, query=None, field_paths=None): + def find(self, query=None, field_paths=None, condition=None): raise NotImplementedError("Should have implemented this") @abstractmethod - def find_query(self, query=None, field_paths=None): + def find_query(self, query): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def find_query_string(self, query): raise NotImplementedError("Should have implemented this") @abstractmethod def insert_or_replace(self, doc, _id=None, field_as_key=None, doc_stream=None): raise NotImplementedError("Should have implemented this") + @abstractmethod + def insert_or_replace_document_stream(self, doc_stream, _id=None, field_as_key=None): + raise NotImplementedError("Should have implemented this") + @abstractmethod def update(self, _id, mutation): raise NotImplementedError("Should have implemented this") @abstractmethod - def delete(self, _id=None, doc=None, field_as_key=None, doc_stream=None): + def delete_by_id(self, _id): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def delete_document(self, doc, field_as_key=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def delete_document_stream(self, doc_stream, field_as_key=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def insert_document_with_id(self, _id, document): raise NotImplementedError("Should have implemented this") @abstractmethod - def insert(self, _id=None, doc=None, field_as_key=None, doc_stream=None): + def insert_document(self, document, field_as_key=None): raise NotImplementedError("Should have implemented this") @abstractmethod - def insert(self, _id=None, doc=None, field_as_key=None, doc_stream=None): + def insert_document_stream(self, document_stream, field_as_key=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def replace_document_with_id(self, _id, document): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def replace_document(self, document, field_as_key=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def replace_document_stream(self, document_stream, field_as_key=None): raise NotImplementedError("Should have implemented this") @abstractmethod def increment(self, _id, field, inc): raise NotImplementedError("Should have implemented this") + @abstractmethod + def increment_int(self, _id, field, inc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment_float(self, _id, field, inc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment_decimal(self, _id, field, inc): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def increment_byte(self, _id, field, inc): + raise NotImplementedError("Should have implemented this") + @abstractmethod def check_and_mutate(self, _id, query_condition, mutation): raise NotImplementedError("Should have implemented this") From bbc01c97a107420029d8c725021da25ad35c3360 Mon Sep 17 00:00:00 2001 From: dshylov Date: Sun, 21 Jan 2018 17:17:49 +0200 Subject: [PATCH 03/12] MAPRDB-397 Investigate and implement client API interfaces for Python language support. Removed functions for driver. Rename DriverManager to ConnectionManager. --- .idea/vcs.xml | 6 ++++++ .../storage/{DriverManager.py => ConnectionManager.py} | 10 +--------- 2 files changed, 7 insertions(+), 9 deletions(-) create mode 100644 .idea/vcs.xml rename entity/storage/{DriverManager.py => ConnectionManager.py} (57%) diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/entity/storage/DriverManager.py b/entity/storage/ConnectionManager.py similarity index 57% rename from entity/storage/DriverManager.py rename to entity/storage/ConnectionManager.py index 9747404..0510792 100644 --- a/entity/storage/DriverManager.py +++ b/entity/storage/ConnectionManager.py @@ -1,24 +1,16 @@ from abc import ABCMeta, abstractmethod -class DriverManager: +class ConnectionManager: __metaclass__ = ABCMeta def __init__(self): pass - @abstractmethod - def get_driver(self, url): - raise NotImplementedError("Should have implemented this") - @abstractmethod def get_connection(self, url, options=None): raise NotImplementedError("Should have implemented this") - @abstractmethod - def register_driver(self, driver): - raise NotImplementedError("Should have implemented this") - @abstractmethod def check_url(self, url): raise NotImplementedError("Should have implemented this") \ No newline at end of file From 692ac299ff162d9456a36799158262d517df1c06 Mon Sep 17 00:00:00 2001 From: dshylov Date: Mon, 22 Jan 2018 00:48:37 +0200 Subject: [PATCH 04/12] MAPRDB-397 Investigate and implement client API interfaces for Python language support. Added part of Value interface and create O*types* files --- entity/document/DocumentImpl.py | 126 ++++++++++++++++++++++++++++++ entity/types/ODate.py | 0 entity/types/OInterval.py | 0 entity/types/OTime.py | 0 entity/types/OTimestamp.py | 0 entity/values/Value.py | 133 ++++++++++++++++++++++++++++++++ 6 files changed, 259 insertions(+) create mode 100644 entity/document/DocumentImpl.py create mode 100644 entity/types/ODate.py create mode 100644 entity/types/OInterval.py create mode 100644 entity/types/OTime.py create mode 100644 entity/types/OTimestamp.py create mode 100644 entity/values/Value.py diff --git a/entity/document/DocumentImpl.py b/entity/document/DocumentImpl.py new file mode 100644 index 0000000..8ddd265 --- /dev/null +++ b/entity/document/DocumentImpl.py @@ -0,0 +1,126 @@ +from Document import Document + + +class DocumentImpl(Document): + def get_byte(self, field_path): + pass + + def set_boolean(self, field_path, value): + pass + + def set_byte_array(self, field_path, value, offset=None, length=None): + pass + + def get_map(self, field_path): + pass + + def set_time(self, field_path, value): + pass + + def get_id(self): + pass + + def get_value(self, field_path): + pass + + def get_long(self, field_path): + pass + + def get_date(self, field_path): + pass + + def set_interval(self, field_path, value): + pass + + def set_map(self, field_path, value): + pass + + def get_boolean(self, field_path): + pass + + def set_byte(self, field_path, value): + pass + + def get_list(self, field_path): + pass + + def size(self): + pass + + def get_decimal(self, field_path): + pass + + def get_interval(self, field_path): + pass + + def get_double(self, field_path): + pass + + def empty(self): + pass + + def get_int(self, field_path): + pass + + def as_map(self): + pass + + def get_binary(self, field_path): + pass + + def set(self, field_path, value): + pass + + def set_value_obj(self, field_path, value): + pass + + def set_id(self, _id): + pass + + def set_date(self, field_path, value): + pass + + def get_time(self, field_path): + pass + + def delete(self, field_path): + pass + + def set_timestamp(self, field_path, value): + pass + + def set_decimal(self, field_path, value): + pass + + def get_timestamp(self, field_path): + pass + + def get_float(self, field_path): + pass + + def set_null(self, field_path): + pass + + def set_document(self, field_path, value): + pass + + def get_id_binary(self): + pass + + def as_reader(self, field_path=None): + pass + + def get_id_string(self): + pass + + def get_string(self, field_path): + pass + + def set_long(self, field_path, value): + pass + + def set_array(self, field_path, values): + pass + + def set_float(self, field_path, value): + pass diff --git a/entity/types/ODate.py b/entity/types/ODate.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/types/OInterval.py b/entity/types/OInterval.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/types/OTime.py b/entity/types/OTime.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/types/OTimestamp.py b/entity/types/OTimestamp.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/values/Value.py b/entity/values/Value.py new file mode 100644 index 0000000..795ddce --- /dev/null +++ b/entity/values/Value.py @@ -0,0 +1,133 @@ +from abc import ABCMeta, abstractmethod + + +class Value: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + __TYPE_CODE_NULL = 1 + __TYPE_CODE_BOOLEAN = 2 + __TYPE_CODE_STRING = 3 + __TYPE_CODE_BYTE = 4 + __TYPE_CODE_INT = 5 + __TYPE_CODE_LONG = 6 + __TYPE_CODE_FLOAT = 7 + __TYPE_CODE_DECIMAL = 8 + __TYPE_CODE_DATE = 9 + __TYPE_CODE_TIME = 10 + __TYPE_CODE_TIMESTAMP = 11 + __TYPE_CODE_INTERVAL = 12 + __TYPE_CODE_BINARY = 13 + __TYPE_CODE_MAP = 14 + __TYPE_CODE_ARRAY = 15 + + @property + def type_code_boolean(self): + return self.__TYPE_CODE_BOOLEAN + + @property + def type_code_null(self): + return self.__TYPE_CODE_NULL + + @property + def type_code_string(self): + return self.__TYPE_CODE_STRING + + @property + def type_code_byte(self): + return self.__TYPE_CODE_BYTE + + @property + def type_code_int(self): + return self.__TYPE_CODE_INT + + @property + def type_code_long(self): + return self.__TYPE_CODE_LONG + + @property + def type_code_float(self): + return self.__TYPE_CODE_FLOAT + + @property + def type_code_decimal(self): + return self.__TYPE_CODE_DECIMAL + + @property + def type_code_date(self): + return self.__TYPE_CODE_DATE + + @property + def type_code_time(self): + return self.__TYPE_CODE_TIME + + @property + def type_code_timestamp(self): + return self.__TYPE_CODE_TIMESTAMP + + @property + def type_code_interval(self): + return self.__TYPE_CODE_INTERVAL + + @property + def type_code_binary(self): + return self.__TYPE_CODE_BINARY + + @property + def type_code_map(self): + return self.__TYPE_CODE_MAP + + @property + def type_code_array(self): + return self.__TYPE_CODE_ARRAY + + + class ValueType(object): + + def __init__(self, value_type): + self.__value = value_type + + NULL = Value.type_code_null + + BOOLEAN = Value.type_code_boolean + + STRING = Value.type_code_string + + BYTE = Value.type_code_byte + + INT = Value.type_code_int + + LONG = Value.type_code_long + + FLOAT = Value.type_code_float + + DECIMAL = Value.type_code_decimal + + DATE = Value.type_code_date + + TIME = Value.type_code_time + + INTERVAL = Value.type_code_interval + + BINARY = Value.type_code_binary + + MAP = Value.type_code_map + + ARRAY = Value.type_code_array + + @staticmethod + def __is_scalar__(value): + return value != Value.ValueType.MAP and value != Value.ValueType.ARRAY + + @staticmethod + def __is_numeric__(value): + return Value.ValueType.BYTE <= value <= Value.ValueType.DECIMAL + + + + + + + From b0a7f0db12f64da29b55f270222e1748ed2ad385 Mon Sep 17 00:00:00 2001 From: dshylov Date: Tue, 23 Jan 2018 18:49:40 +0200 Subject: [PATCH 05/12] MAPRDB-397 Investigate and implement client API interfaces for Python language support. MAPRDB-459 Implement ValueImpl class and subclasses like OTime, ODate, etc.. Added part of ValueImpl, OInterval --- entity/{types/ODate.py => json/Json.py} | 0 .../OInterval.py => json/JsonDocument.py} | 0 entity/{types/OTime.py => json/JsonList.py} | 0 .../OTimestamp.py => json/JsonOptions.py} | 0 entity/json/JsonUtils.py | 0 entity/o_types/ODate.py | 7 + entity/o_types/OInterval.py | 71 +++++++ entity/o_types/OTime.py | 0 entity/o_types/OTimestamp.py | 5 + entity/o_types/constants.py | 12 ++ entity/values/Value.py | 138 ++++++++++--- entity/values/ValueImpl.py | 189 ++++++++++++++++++ 12 files changed, 396 insertions(+), 26 deletions(-) rename entity/{types/ODate.py => json/Json.py} (100%) rename entity/{types/OInterval.py => json/JsonDocument.py} (100%) rename entity/{types/OTime.py => json/JsonList.py} (100%) rename entity/{types/OTimestamp.py => json/JsonOptions.py} (100%) create mode 100644 entity/json/JsonUtils.py create mode 100644 entity/o_types/ODate.py create mode 100644 entity/o_types/OInterval.py create mode 100644 entity/o_types/OTime.py create mode 100644 entity/o_types/OTimestamp.py create mode 100644 entity/o_types/constants.py create mode 100644 entity/values/ValueImpl.py diff --git a/entity/types/ODate.py b/entity/json/Json.py similarity index 100% rename from entity/types/ODate.py rename to entity/json/Json.py diff --git a/entity/types/OInterval.py b/entity/json/JsonDocument.py similarity index 100% rename from entity/types/OInterval.py rename to entity/json/JsonDocument.py diff --git a/entity/types/OTime.py b/entity/json/JsonList.py similarity index 100% rename from entity/types/OTime.py rename to entity/json/JsonList.py diff --git a/entity/types/OTimestamp.py b/entity/json/JsonOptions.py similarity index 100% rename from entity/types/OTimestamp.py rename to entity/json/JsonOptions.py diff --git a/entity/json/JsonUtils.py b/entity/json/JsonUtils.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/o_types/ODate.py b/entity/o_types/ODate.py new file mode 100644 index 0000000..7eb3f78 --- /dev/null +++ b/entity/o_types/ODate.py @@ -0,0 +1,7 @@ +from datetime import datetime + + +class ODate: + + def __init__(self): + pass diff --git a/entity/o_types/OInterval.py b/entity/o_types/OInterval.py new file mode 100644 index 0000000..76ae274 --- /dev/null +++ b/entity/o_types/OInterval.py @@ -0,0 +1,71 @@ +import constants + + +class OInterval: + """An immutable class which encapsulates a time interval.""" + + __SERIAL_VERSION_UID = 0x228372f2047c1511L + + __APPROX_DAYS_IN_YEAR = ((365 * 4) + 1) / 4.0 + + __APPROX_DAYS_IN_MONTH = __APPROX_DAYS_IN_YEAR / 12 + + def __init__(self, milli_seconds=None, years=None, months=None, days=None, + seconds=None, iso8601DurationPattern=None): + if all([milli_seconds, years, months, days, seconds]): + self.__milli_seconds = milli_seconds + self.__seconds = seconds + self.__days = days + self.__months = months + self.__years = years + total_days = long(((years * self.__APPROX_DAYS_IN_YEAR) + (months + self.__APPROX_DAYS_IN_MONTH) + days)) + self.__time_duration = constants.MILLISECONDS_PER_DAY * total_days + seconds * 1000 + milli_seconds + elif milli_seconds is not None: + self.__time_duration = long(milli_seconds) + self.__milli_seconds = int(milli_seconds % 1000) + self.__seconds = int(milli_seconds / constants.MILLISECONDS_PER_DAY) / 1000 + self.__days = int(milli_seconds / constants.MILLISECONDS_PER_DAY) + self.__months = 0 + self.__years = 0 + elif iso8601DurationPattern is not None: + # FIXME: parse the string as per ISO 8601 duration and time stamps format + self.__init__(0, 0, 0, 0, 0) + + @property + def years(self): + return self.__years + + @property + def months(self): + return self.__months + + @property + def days(self): + return self.__days + + @property + def seconds(self): + return self.__seconds + + @property + def milli_seconds(self): + return self.__milli_seconds + + @property + def time_duration(self): + return self.__time_duration + + def __hash__(self): + __result = 31 * 1 * int(self.time_duration ^ (self.time_duration >> 2)) + return __result + + def __eq__(self, other): + if self == other: + return True + if other is None: + return False + if not isinstance(other, self): + return False + if self.time_duration != other.time_duration: + return False + return True diff --git a/entity/o_types/OTime.py b/entity/o_types/OTime.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/o_types/OTimestamp.py b/entity/o_types/OTimestamp.py new file mode 100644 index 0000000..3dec690 --- /dev/null +++ b/entity/o_types/OTimestamp.py @@ -0,0 +1,5 @@ + + +class OTimestamp: + def __init__(self): + pass diff --git a/entity/o_types/constants.py b/entity/o_types/constants.py new file mode 100644 index 0000000..d09d4ed --- /dev/null +++ b/entity/o_types/constants.py @@ -0,0 +1,12 @@ + +# A long value equal to the number of milliseconds in a second +MILLISECONDS_PER_SECOND = 1000 + +# A long value equal to the number of milliseconds in a minute. +MILLISECONDS_PER_MINUTE = 60 * MILLISECONDS_PER_SECOND + +# A long value equal to the number of milliseconds in an hour. +MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE + +# A long value equal to the number of milliseconds in a day. +MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR diff --git a/entity/values/Value.py b/entity/values/Value.py index 795ddce..70228a3 100644 --- a/entity/values/Value.py +++ b/entity/values/Value.py @@ -4,9 +4,6 @@ class Value: __metaclass__ = ABCMeta - def __init__(self): - pass - __TYPE_CODE_NULL = 1 __TYPE_CODE_BOOLEAN = 2 __TYPE_CODE_STRING = 3 @@ -83,51 +80,140 @@ def type_code_map(self): def type_code_array(self): return self.__TYPE_CODE_ARRAY + # @staticmethod + # def is_scalar(value): + # return value != Value.type_code_map and value != Value.type_code_array + # + # @staticmethod + # def is_numeric(value): + # return Value.type_code_byte <= value <= Value.type_code_decimal + + + @abstractmethod + def get_type(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_byte(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_int(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_long(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_float(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_decimal(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_boolean(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_string(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_timestamp(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_timestamp_as_long(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_date(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_date_as_int(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_time(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_time_as_int(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_interval(self): + raise NotImplementedError("Should have implemented this") - class ValueType(object): + @abstractmethod + def get_interval_as_long(self): + raise NotImplementedError("Should have implemented this") - def __init__(self, value_type): - self.__value = value_type + @abstractmethod + def get_map(self): + raise NotImplementedError("Should have implemented this") - NULL = Value.type_code_null + @abstractmethod + def get_list(self): + raise NotImplementedError("Should have implemented this") - BOOLEAN = Value.type_code_boolean + @abstractmethod + def get_obj(self): + raise NotImplementedError("Should have implemented this") - STRING = Value.type_code_string + @abstractmethod + def as_reader(self): + raise NotImplementedError("Should have implemented this") - BYTE = Value.type_code_byte + # TODO investigate is we can add binary analog (java.nia.ByteBuffer) + # @abstractmethod + # def get_binary(self): + # raise NotImplementedError("Should have implemented this") - INT = Value.type_code_int - LONG = Value.type_code_long +# TODO Python2 doesn't have enum. Impelement method for convert ValueType numeric field to string like 2 -> "BOOLEAN" +class ValueType(object): + def __init__(self, value_type): + self.__value = value_type - FLOAT = Value.type_code_float + NULL = Value.type_code_null - DECIMAL = Value.type_code_decimal + BOOLEAN = Value.type_code_boolean - DATE = Value.type_code_date + STRING = Value.type_code_string - TIME = Value.type_code_time + BYTE = Value.type_code_byte - INTERVAL = Value.type_code_interval + INT = Value.type_code_int - BINARY = Value.type_code_binary + LONG = Value.type_code_long - MAP = Value.type_code_map + FLOAT = Value.type_code_float - ARRAY = Value.type_code_array + DECIMAL = Value.type_code_decimal - @staticmethod - def __is_scalar__(value): - return value != Value.ValueType.MAP and value != Value.ValueType.ARRAY + DATE = Value.type_code_date - @staticmethod - def __is_numeric__(value): - return Value.ValueType.BYTE <= value <= Value.ValueType.DECIMAL + TIME = Value.type_code_time + TIMESTAMP = Value.get_timestamp + INTERVAL = Value.type_code_interval + BINARY = Value.type_code_binary + MAP = Value.type_code_map + ARRAY = Value.type_code_array + @staticmethod + def __is_scalar__(value): + return value != Value.type_code_map and value != Value.type_code_array + @staticmethod + def __is_numeric__(value): + return Value.type_code_byte <= value <= Value.type_code_decimal \ No newline at end of file diff --git a/entity/values/ValueImpl.py b/entity/values/ValueImpl.py new file mode 100644 index 0000000..fe58b6b --- /dev/null +++ b/entity/values/ValueImpl.py @@ -0,0 +1,189 @@ +from Value import Value, ValueType +from entity.o_types.OInterval import OInterval + + +class ValueImpl(Value): + + def __init__(self, value_type=None, json_value=None, obj_value=None): + self.value_type = value_type + self.json_value = json_value + self.obj_value = obj_value + self.key = None + + def set_key(self, key): + self.key = key + + def get_key(self): + return self.key + + def check_type(self, value_type): + if self.value_type != value_type: + raise TypeError("Value is of type " + self.value_type + " but requested type is " + value_type) + return + + def set_prim_value(self, value): + self.json_value = value + + def set_obj_value(self, value): + # TODO added chat that value is object. Which objects acceptable? + # Only ValueType objects? ValueType object don't store as enum in python + self.obj_value = value + + def get_obj(self): + switcher = { + 1: self.obj_value, + 2: self.get_boolean(), + 3: self.obj_value, + 4: self.get_byte(), + 5: self.get_int(), + 6: self.get_long(), + 7: self.get_float(), + 8: self.obj_value, + 9: self.get_date(), + 10: self.get_time(), + 11: self.get_timestamp(), + 12: self.get_interval(), + 13: self.obj_value, + 14: self, + 15: self + } + return switcher.get(self.value_type, TypeError("Invalid type " + self.value_type)) + + def get_date(self): + self.check_type(ValueType.DATE) + if self.obj_value is None: + # TODO implement ODate class + pass + + def get_map(self): + self.check_type(ValueType.MAP) + # TODO added get_map implementation after JSONDocument will done + pass + + def get_time_as_int(self): + return int(self.json_value) + + def get_type(self): + return self.value_type + + def get_interval(self): + self.check_type(ValueType.INTERVAL) + if self.obj_value is None: + # TODO implement OTimeStamp class + # self.obj_value = OInterval(self.json_value) + pass + return self.obj_value + + def get_list(self): + self.check_type(ValueType.ARRAY) + # TODO added get_map implementation after JSONList will done + pass + + def get_byte(self): + switcher = { + ValueType.BYTE: self.int_to_byte(self.json_value), + ValueType.INT: self.get_int(), + ValueType.LONG: self.get_long(), + ValueType.FLOAT: self.get_float(), + # TODO convert decimal to byte + ValueType.DECIMAL: self.get_decimal() + } + return switcher.get(self.value_type, TypeError("Expected a numeric type, found: " + self.value_type)) + + def get_time(self): + self.check_type(ValueType.TIME) + if self.obj_value is None: + # TODO implement OTime class + pass + + def get_long(self): + switcher = { + ValueType.LONG: self.json_value, + ValueType.BYTE: self.get_byte(), + ValueType.INT: self.get_int(), + ValueType.FLOAT: long(self.get_float()), + # TODO convert decimal to long + ValueType.DECIMAL: long(self.get_decimal()) + } + return switcher.get(self.value_type, TypeError("Expected a numeric type, found: " + self.value_type)) + + def get_int(self): + switcher = { + ValueType.INT: self.byte_to_int(self.json_value), + ValueType.BYTE: self.get_byte(), + ValueType.FLOAT: int(self.get_float()), + # TODO convert decimal to int + ValueType.DECIMAL: int(self.get_decimal()) + } + return switcher.get(self.value_type, TypeError("Expected a numeric type, found: " + self.value_type)) + + def as_reader(self): + # TODO required JsonDOMDocumentReader implementation + pass + + def get_date_as_int(self): + return int(self.json_value) + + def get_boolean(self): + self.check_type(ValueType.BOOLEAN) + return self.json_value != 0 + + def get_timestamp(self): + self.check_type(ValueType.TIMESTAMP) + if self.obj_value is None: + # TODO implement OTimeStamp class + pass + + def get_decimal(self): + # TODO check and implement get_decimal like java BigDecimal + pass + + def get_string(self): + self.check_type(ValueType.STRING) + return str(self.obj_value) + + def get_float(self): + switcher = { + # TODO check how to convert long to float + ValueType.FLOAT: float(self.json_value), + ValueType.BYTE: self.get_byte(), + ValueType.INT: float(self.get_int()), + ValueType.LONG: float(self.get_long()), + # TODO convert decimal to float + ValueType.DECIMAL: int(self.get_decimal()) + } + return switcher.get(self.value_type, TypeError("Expected a numeric type, found: " + self.value_type)) + + def get_interval_as_long(self): + return long(self.json_value) + + def get_timestamp_as_long(self): + return self.json_value + + # TODO Implement method which convert int to byte + def int_to_byte(self, value): + pass + + # TODO Implement method which convert byte to int + def byte_to_int(self, value): + pass + + # TODO check get_binary and how we can implement it + + # TODO check is shallowCopy method required + def shallow_copy(self): + pass + + # this OJAI object serialized as JSON string using the default options + # TODO options param required JsonOptions implementation + def as_json_string(self, options=None): + # TODO returns org.ojai.json.JSON.toJsonString implementation. + pass + + # TODO required as_json_string method! + # def __str__(self): + # return self.as_json_string() + + # TODO check eq impl + # def __eq__(self, o): + # return super(ValueImpl, self).__eq__(o) From 088c95e95c8e89f769b76f7f33ad92caa778497b Mon Sep 17 00:00:00 2001 From: dshylov Date: Wed, 24 Jan 2018 18:56:29 +0200 Subject: [PATCH 06/12] MAPRDB-459 Implement ValueImpl class and subclasses like OTime, ODate, etc.. Added unit test for OInterval, minor changes in other classes and sample code. --- Sample.py | 20 ++++++++ .../UnsupportedConstructorException.py | 2 + entity/o_types/OInterval.py | 13 +++-- entity/storage/Connection.py | 2 +- entity/values/ValueImpl.py | 4 +- test/o_types_test/test_ointerval.py | 47 +++++++++++++++++++ 6 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 Sample.py create mode 100644 entity/exceptions/UnsupportedConstructorException.py create mode 100644 test/o_types_test/test_ointerval.py diff --git a/Sample.py b/Sample.py new file mode 100644 index 0000000..cfca537 --- /dev/null +++ b/Sample.py @@ -0,0 +1,20 @@ +from entity.document.Document import Document +from entity.document.DocumentStore import DocumentStore +from entity.storage.ConnectionManager import ConnectionManager +from entity.storage.Connection import Connection + + +"""Example for customer may works with Python client""" +connection = Connection(ConnectionManager.get_connection(url="ojai:mapr:user@password")) + +store = DocumentStore(connection.get_store(store_name="/test_name")) + + +# Json string or json map (probably json object) +json_document = "json string" + +new_document = connection.new_document(json_document) + +store.insert_or_replace(new_document) + +store.close() diff --git a/entity/exceptions/UnsupportedConstructorException.py b/entity/exceptions/UnsupportedConstructorException.py new file mode 100644 index 0000000..b00b254 --- /dev/null +++ b/entity/exceptions/UnsupportedConstructorException.py @@ -0,0 +1,2 @@ +class UnsupportedConstructorException(Exception): + pass diff --git a/entity/o_types/OInterval.py b/entity/o_types/OInterval.py index 76ae274..01085f4 100644 --- a/entity/o_types/OInterval.py +++ b/entity/o_types/OInterval.py @@ -1,4 +1,5 @@ -import constants +from entity.exceptions.UnsupportedConstructorException import UnsupportedConstructorException +from entity.o_types import constants class OInterval: @@ -20,16 +21,18 @@ def __init__(self, milli_seconds=None, years=None, months=None, days=None, self.__years = years total_days = long(((years * self.__APPROX_DAYS_IN_YEAR) + (months + self.__APPROX_DAYS_IN_MONTH) + days)) self.__time_duration = constants.MILLISECONDS_PER_DAY * total_days + seconds * 1000 + milli_seconds - elif milli_seconds is not None: + elif milli_seconds is not None and years is None and months is None and days is None and seconds is None: self.__time_duration = long(milli_seconds) self.__milli_seconds = int(milli_seconds % 1000) - self.__seconds = int(milli_seconds / constants.MILLISECONDS_PER_DAY) / 1000 + self.__seconds = int((milli_seconds % constants.MILLISECONDS_PER_DAY) / 1000) self.__days = int(milli_seconds / constants.MILLISECONDS_PER_DAY) self.__months = 0 self.__years = 0 elif iso8601DurationPattern is not None: # FIXME: parse the string as per ISO 8601 duration and time stamps format self.__init__(0, 0, 0, 0, 0) + else: + raise UnsupportedConstructorException("This params set is not supported for the OInterval init") @property def years(self): @@ -60,11 +63,11 @@ def __hash__(self): return __result def __eq__(self, other): - if self == other: + if self is other: return True if other is None: return False - if not isinstance(other, self): + if not isinstance(self, type(other)): return False if self.time_duration != other.time_duration: return False diff --git a/entity/storage/Connection.py b/entity/storage/Connection.py index 663d5d8..8582a52 100644 --- a/entity/storage/Connection.py +++ b/entity/storage/Connection.py @@ -16,7 +16,7 @@ def get_value_buffer(self): raise NotImplementedError("Should have implemented this") @abstractmethod - def new_document(self, json_string=None, json_map=None, bean=None): + def new_document(self, json_string=None, json_map=None, obj=None): raise NotImplementedError("Should have implemented this") @abstractmethod diff --git a/entity/values/ValueImpl.py b/entity/values/ValueImpl.py index fe58b6b..67c10da 100644 --- a/entity/values/ValueImpl.py +++ b/entity/values/ValueImpl.py @@ -69,9 +69,7 @@ def get_type(self): def get_interval(self): self.check_type(ValueType.INTERVAL) if self.obj_value is None: - # TODO implement OTimeStamp class - # self.obj_value = OInterval(self.json_value) - pass + self.obj_value = OInterval(self.json_value) return self.obj_value def get_list(self): diff --git a/test/o_types_test/test_ointerval.py b/test/o_types_test/test_ointerval.py new file mode 100644 index 0000000..91570da --- /dev/null +++ b/test/o_types_test/test_ointerval.py @@ -0,0 +1,47 @@ +from __future__ import unicode_literals + +from entity.o_types.OInterval import OInterval + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class OIntervalTest(unittest.TestCase): + + def test_instance_millis(self): + # check than 2 instance with the same constructor are equals + instance1 = OInterval(milli_seconds=86754099) + instance2 = OInterval(milli_seconds=86754099) + self.assertTrue(instance1.__eq__(instance2)) + + self.assertEqual(instance1.time_duration, long(86754099)) + from entity.o_types.constants import MILLISECONDS_PER_DAY + self.assertEqual(instance1.seconds, int((86754099 % MILLISECONDS_PER_DAY) / 1000)) + self.assertEqual(instance1.days, int(86754099 / MILLISECONDS_PER_DAY)) + self.assertEqual(instance1.years, 0) + self.assertEqual(instance1.months, 0) + + def test_instance_full(self): + instance = OInterval(milli_seconds=999, years=3, months=4, days=6, seconds=59) + + self.assertEqual(instance.milli_seconds, 999) + self.assertEqual(instance.years, 3) + self.assertEqual(instance.months, 4) + self.assertEqual(instance.days, 6) + self.assertEqual(instance.seconds, 59) + + # Test check that __hash__ works correct + def test_instance_hash(self): + instance1 = OInterval(milli_seconds=86754099) + instance2 = OInterval(milli_seconds=86754099) + instance3 = OInterval(milli_seconds=86754098) + + self.assertEqual(instance1.__hash__(), instance2.__hash__()) + self.assertFalse(instance1.__hash__() == instance3.__hash__()) + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(OIntervalTest) + unittest.TextTestRunner(verbosity=2).run(suite) From bda32ba745fd9badb1be095e622ca4b614db1a3f Mon Sep 17 00:00:00 2001 From: dshylov Date: Thu, 25 Jan 2018 19:25:19 +0200 Subject: [PATCH 07/12] MAPRDB-459 Implement ValueImpl class and subclasses like OTime, ODate, etc.. Added OTime and ODate implementation --- entity/o_types/ODate.py | 96 +++++++++++++++++++++++++++++++-- entity/o_types/OTime.py | 115 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+), 3 deletions(-) diff --git a/entity/o_types/ODate.py b/entity/o_types/ODate.py index 7eb3f78..2276e0b 100644 --- a/entity/o_types/ODate.py +++ b/entity/o_types/ODate.py @@ -1,7 +1,97 @@ -from datetime import datetime +import datetime +import dateutil.parser + +from entity.exceptions import UnsupportedConstructorException class ODate: + serial_version_uid = 0xaffa9a5dfe3ff863L + + __EPOCH_DATE = datetime.datetime(1970, 1, 1) + __START_OF_DAY = datetime.time(0, 0, 0) + + def __init__(self, year=None, month=None, day_of_month=None, epoch=None, date=None, days_since_epoch=None): + if all([year, month, day_of_month]) and epoch is None and date is None: + self.__date = datetime.datetime(year, month, day_of_month) + elif date is not None: + if type(date) is not datetime.datetime: + raise TypeError("date should be datetime.date type or comparable to it") + self.__date = date + elif epoch is not None: + self.__date = datetime.datetime.fromtimestamp(epoch) + elif days_since_epoch is not None: + self.__days_since_epoch = day_of_month + else: + raise UnsupportedConstructorException + + self.__days_since_epoch = (self.__date - self.__EPOCH_DATE).days + + @property + def epoch_date(self): + return self.__EPOCH_DATE + + @property + def start_of_day(self): + return self.__START_OF_DAY + + @property + def date(self): + return self.__date + + @property + def days_since_epoch(self): + return self.__days_since_epoch + + @staticmethod + def from_days_since_epoch(days_since_epoch): + return ODate(days_since_epoch=days_since_epoch) + + @staticmethod + def parse(date_str): + return ODate(date=dateutil.parser.parse(date_str)) + + def __get_date(self): + if self.__date is None: + # self.__date = self.__EPOCH_DATE + datetime.datetime.fromtimestamp(self.__days_since_epoch) + self.__date = self.__EPOCH_DATE + datetime.timedelta(self.__days_since_epoch) + return self.__date + + def get_year(self): + return self.__get_date().year + + def get_month(self): + return self.__get_date().month + + def get_day_of_month(self): + return self.__get_date().day + + def to_days_since_epoch(self): + return self.__days_since_epoch + + def to_date_str(self): + return self.to_string("%Y-%m-%d") + + def to_string(self, pattern): + return self.__get_date().strftime(pattern) + + def __str__(self): + self.to_date_str() + + def __cmp__(self, other): + if type(other) is not self: + raise TypeError + return self.days_since_epoch - other.days_since_epoch + + def __hash__(self): + return self.__days_since_epoch - def __init__(self): - pass + def __eq__(self, other): + if self is other: + return True + if other is None: + return False + if not isinstance(self, type(other)): + return False + if self.days_since_epoch != other.days_since_epoch: + return False + return True diff --git a/entity/o_types/OTime.py b/entity/o_types/OTime.py index e69de29..f60f640 100644 --- a/entity/o_types/OTime.py +++ b/entity/o_types/OTime.py @@ -0,0 +1,115 @@ +import datetime +import dateutil.parser + +from entity.exceptions import UnsupportedConstructorException + + +class OTime: + + __serial_version_uid = 0xaffa9a5dfe3ff863L + __EPOCH_DATE = datetime.datetime(1970, 1, 1) + + def __init__(self, epoch=None, hour_of_day=None, minutes=None, + seconds=None, ms=None, date=None, millis_of_day=None): + if epoch is not None: + self.__time = datetime.datetime.fromtimestamp(epoch).time() + self.__millis_of_day = long((self.__time.hour * 60 * 60 + self.__time.second) + * 1000 + self.__time.microsecond / 1000.0) + elif all([hour_of_day, minutes, seconds]) is not None: + if ms is None: + self.__time = datetime.time(hour=hour_of_day, minute=minutes, second=seconds, microsecond=0) + else: + self.__time = datetime.time(hour=hour_of_day, minute=minutes, second=seconds, microsecond=ms) + self.__millis_of_day = long((self.__time.hour * 60 * 60 + self.__time.second) + * 1000 + self.__time.microsecond / 1000.0) + elif date is not None: + if not isinstance(type(date), datetime.datetime): + raise TypeError + self.__time = date.time() + self.__millis_of_day = long((self.__time.hour * 60 * 60 + self.__time.second) + * 1000 + self.__time.microsecond / 1000.0) + elif millis_of_day is not None: + self.__time = None + self.__millis_of_day = millis_of_day + else: + raise UnsupportedConstructorException + + @property + def epoch_date(self): + return self.__EPOCH_DATE + + @property + def time(self): + return self.__time + + @property + def millis_of_day(self): + return self.__millis_of_day + + @staticmethod + def parse(time_str): + return OTime(date=dateutil.parser.parse("1970-01-01T"+time_str)) + + @staticmethod + def from_millis_of_day(millis_of_day): + return OTime(millis_of_day=millis_of_day) + + def __get_time(self): + if self.time is None: + self.__time = datetime.datetime.fromtimestamp(self.millis_of_day).time() + return self.__time + + def get_hour(self): + return self.__get_time().hour + + def get_minute(self): + return self.__get_time().minute + + def get_second(self): + return self.__get_time().second + + def get_millis(self): + return self.__get_time().microsecond / 1000 + + def to_date(self): + return datetime.datetime.combine(self.__EPOCH_DATE.date(), self.__time) + + def to_time_in_millis(self): + return self.__millis_of_day + + def time_to_str(self): + if self.millis_of_day % 1000 == 0: + return self.to_str("%H:%M:%S") + else: + return self.to_str("%H:%M:%S:%f") + + def to_str(self, pattern): + return self.__get_time().strftime(pattern) + + def __str__(self): + self.time_to_str() + + def __hash__(self): + return self.millis_of_day + + def __cmp__(self, other): + if type(other) is not self: + raise TypeError + return self.millis_of_day - other.millis_of_day + + def __eq__(self, other): + if self is other: + return True + if other is None: + return False + if not isinstance(self, type(other)): + return False + if self.millis_of_day != other.millis_of_day: + return False + return True + + + + + + From efc72f1a9c7a20cf074989c884f2930eb30328f1 Mon Sep 17 00:00:00 2001 From: dshylov Date: Fri, 26 Jan 2018 11:55:42 +0200 Subject: [PATCH 08/12] Remove part of deprecated methods --- entity/document/DocumentStore.py | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/entity/document/DocumentStore.py b/entity/document/DocumentStore.py index 7e87d3d..6ebe45c 100644 --- a/entity/document/DocumentStore.py +++ b/entity/document/DocumentStore.py @@ -40,23 +40,11 @@ def find_by_id(self, _id, field_paths=None, condition=None): raise NotImplementedError("Should have implemented this") @abstractmethod - def find(self, query=None, field_paths=None, condition=None): + def find(self, query=None, field_paths=None, condition=None, query_string=None): raise NotImplementedError("Should have implemented this") @abstractmethod - def find_query(self, query): - raise NotImplementedError("Should have implemented this") - - @abstractmethod - def find_query_string(self, query): - raise NotImplementedError("Should have implemented this") - - @abstractmethod - def insert_or_replace(self, doc, _id=None, field_as_key=None, doc_stream=None): - raise NotImplementedError("Should have implemented this") - - @abstractmethod - def insert_or_replace_document_stream(self, doc_stream, _id=None, field_as_key=None): + def insert_or_replace(self, doc=None, _id=None, field_as_key=None, doc_stream=None): raise NotImplementedError("Should have implemented this") @abstractmethod @@ -68,11 +56,7 @@ def delete_by_id(self, _id): raise NotImplementedError("Should have implemented this") @abstractmethod - def delete_document(self, doc, field_as_key=None): - raise NotImplementedError("Should have implemented this") - - @abstractmethod - def delete_document_stream(self, doc_stream, field_as_key=None): + def delete_document(self, doc=None, field_as_key=None, doc_stream=None): raise NotImplementedError("Should have implemented this") @abstractmethod From dd5d22c72503f356aa17334d2facb0a2b0c5385c Mon Sep 17 00:00:00 2001 From: dshylov Date: Fri, 26 Jan 2018 16:07:11 +0200 Subject: [PATCH 09/12] MAPRDB-459 Implement ValueImpl class and subclasses like OTime, ODate, etc.. Added ODate implementation. --- entity/o_types/ODate.py | 9 ++- entity/o_types/OTimestamp.py | 116 ++++++++++++++++++++++++++- test/o_types_test/test_odate.py | 22 +++++ test/o_types_test/test_otime.py | 0 test/o_types_test/test_otimestamp.py | 0 5 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 test/o_types_test/test_odate.py create mode 100644 test/o_types_test/test_otime.py create mode 100644 test/o_types_test/test_otimestamp.py diff --git a/entity/o_types/ODate.py b/entity/o_types/ODate.py index 2276e0b..769c08f 100644 --- a/entity/o_types/ODate.py +++ b/entity/o_types/ODate.py @@ -56,12 +56,15 @@ def __get_date(self): self.__date = self.__EPOCH_DATE + datetime.timedelta(self.__days_since_epoch) return self.__date + # Return the years of this datetime def get_year(self): return self.__get_date().year + # Return the month of this datetime def get_month(self): return self.__get_date().month + # Return the day of month of this datetime def get_day_of_month(self): return self.__get_date().day @@ -74,8 +77,12 @@ def to_date_str(self): def to_string(self, pattern): return self.__get_date().strftime(pattern) + # return date with time set to 0 + def to_date(self): + return datetime.datetime.combine(self.__get_date().date(), self.start_of_day) + def __str__(self): - self.to_date_str() + return self.to_date_str() def __cmp__(self, other): if type(other) is not self: diff --git a/entity/o_types/OTimestamp.py b/entity/o_types/OTimestamp.py index 3dec690..c355950 100644 --- a/entity/o_types/OTimestamp.py +++ b/entity/o_types/OTimestamp.py @@ -1,5 +1,117 @@ +import datetime +import dateutil.parser + +from entity.exceptions import UnsupportedConstructorException class OTimestamp: - def __init__(self): - pass + __serial_version_uid = 0x3800c3b7b7f0e008L + __epoch = datetime.datetime.utcfromtimestamp(0) + # TODO Is UTC_CHRONOLOGY must return current time in UTC time zone? and must be created only once with instance? + __UTC_CHRONOLOGY = datetime.datetime.utcfromtimestamp(0) + + """ Two types of OTimestamp init: + First params set: + year - the year + month_of_year - the month of the year, from 1 to 12 + day_of_month - the day of the month, from 1 to 31 + hour_of_day - the hour of the day, from 0 to 23 + minute_of_hour - the minute of the hour, from 0 to 59 + second_of_minute - the second of the minute, from 0 to 59 + millis_of_second - the millisecond of the second, from 0 to 999 + Second: + date - the Date to extract fields from""" + + def __init__(self, year=None, month_of_year=None, day_of_month=None, hour_of_day=None, minute_of_hour=None, + second_of_minute=None, millis_of_second=None, date=None, millis_since_epoch=None): + if all([year, month_of_year, day_of_month, hour_of_day, + minute_of_hour, second_of_minute, millis_of_second]) is not None: + self.__date_time = datetime.datetime(year=year, month=month_of_year, day=day_of_month, + hour=hour_of_day, minute=minute_of_hour, second=second_of_minute, + microsecond=millis_of_second * 1000) + self.__millis_since_epoch = (self.__date_time - self.__epoch).total_seconds() * 1000.0 + elif millis_since_epoch is not None: + self.__date_time = None + self.__millis_since_epoch = millis_since_epoch + elif date is not None: + if not isinstance(type(datetime.datetime), type(date)): + raise TypeError + self.__date_time = date + self.__millis_since_epoch = (self.__date_time - self.__epoch).total_seconds() * 1000.0 + else: + raise UnsupportedConstructorException + + @property + def millis_since_epoch(self): + return self.__millis_since_epoch + + @property + def date_time(self): + return self.__date_time + + def get_year(self): + return (self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch)).year + + def get_month(self): + return (self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch)).month + + def get_day_of_month(self): + return (self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch)).day + + def get_hour(self): + return (self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch)).hour + + def get_minute(self): + return (self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch)).minute + + def get_second(self): + return (self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch)).second + + def get_millis(self): + return (self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch)).microsecond / 1000 + + def __get_date_time(self): + if self.__date_time is None: + self.__date_time = self.__UTC_CHRONOLOGY + datetime.timedelta(milliseconds=self.millis_since_epoch) + return self.date_time + + # Create datetime object from millis since epoch + def to_date(self): + return datetime.datetime.fromtimestamp(self.millis_since_epoch/1000.0) + + # Returns the ISO8601 format timestamp string in UTC. + def to_utc_str(self): + return self.__get_date_time().utcnow().isoformat() + + # Returns the ISO8601 format timestamp string in local time zone. + def to_local_str(self): + return self.__get_date_time().now().isoformat() + + def to_str(self, pattern): + return self.__get_date_time().strftime(pattern) + + def __str__(self): + return self.to_utc_str() + + def __cmp__(self, other): + if type(other) is not self or type(other) is not type(datetime.datetime): + raise TypeError + return self.millis_since_epoch - other.millis_since_epoch + + def __hash__(self): + return int(self.millis_since_epoch ^ (self.millis_since_epoch >> 32)) + + def __eq__(self, other): + if self is other: + return True + if other is None: + return False + if not isinstance(self, type(other)): + return False + if self.millis_since_epoch != other.millis_since_epoch: + return False + return True + + + + diff --git a/test/o_types_test/test_odate.py b/test/o_types_test/test_odate.py new file mode 100644 index 0000000..d714ebf --- /dev/null +++ b/test/o_types_test/test_odate.py @@ -0,0 +1,22 @@ +from __future__ import unicode_literals + +from entity.o_types.ODate import ODate + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class ODateTest(unittest.TestCase): + + def test_days_from_epoch(self): + pass + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(ODateTest) + unittest.TextTestRunner(verbosity=2).run(suite) + + + diff --git a/test/o_types_test/test_otime.py b/test/o_types_test/test_otime.py new file mode 100644 index 0000000..e69de29 diff --git a/test/o_types_test/test_otimestamp.py b/test/o_types_test/test_otimestamp.py new file mode 100644 index 0000000..e69de29 From 2a90e6f6e2cc08209e8904d0f909ddf17d58e1be Mon Sep 17 00:00:00 2001 From: dshylov Date: Fri, 26 Jan 2018 20:01:13 +0200 Subject: [PATCH 10/12] MAPRDB-459 Implement ValueImpl class and subclasses like OTime, ODate, etc.. Added tests for OTime, ODate, OTimestamp. Added new implemented types to ValueImpl. --- entity/o_types/ODate.py | 16 ++++---- entity/o_types/OTime.py | 7 ++-- entity/o_types/OTimestamp.py | 18 ++++---- entity/values/ValueImpl.py | 15 ++++--- test/o_types_test/test_odate.py | 61 ++++++++++++++++++++++++++-- test/o_types_test/test_otime.py | 60 +++++++++++++++++++++++++++ test/o_types_test/test_otimestamp.py | 60 +++++++++++++++++++++++++++ 7 files changed, 207 insertions(+), 30 deletions(-) diff --git a/entity/o_types/ODate.py b/entity/o_types/ODate.py index 769c08f..67503fa 100644 --- a/entity/o_types/ODate.py +++ b/entity/o_types/ODate.py @@ -8,24 +8,26 @@ class ODate: serial_version_uid = 0xaffa9a5dfe3ff863L __EPOCH_DATE = datetime.datetime(1970, 1, 1) - __START_OF_DAY = datetime.time(0, 0, 0) + __START_OF_DAY = datetime.time(hour=0, minute=0, second=0) def __init__(self, year=None, month=None, day_of_month=None, epoch=None, date=None, days_since_epoch=None): if all([year, month, day_of_month]) and epoch is None and date is None: self.__date = datetime.datetime(year, month, day_of_month) + self.__days_since_epoch = (self.__date - self.__EPOCH_DATE).days elif date is not None: if type(date) is not datetime.datetime: raise TypeError("date should be datetime.date type or comparable to it") self.__date = date + self.__days_since_epoch = (self.__date - self.__EPOCH_DATE).days elif epoch is not None: self.__date = datetime.datetime.fromtimestamp(epoch) + self.__days_since_epoch = (self.__date - self.__EPOCH_DATE).days elif days_since_epoch is not None: - self.__days_since_epoch = day_of_month + self.__date = None + self.__days_since_epoch = days_since_epoch else: raise UnsupportedConstructorException - self.__days_since_epoch = (self.__date - self.__EPOCH_DATE).days - @property def epoch_date(self): return self.__EPOCH_DATE @@ -34,10 +36,6 @@ def epoch_date(self): def start_of_day(self): return self.__START_OF_DAY - @property - def date(self): - return self.__date - @property def days_since_epoch(self): return self.__days_since_epoch @@ -85,7 +83,7 @@ def __str__(self): return self.to_date_str() def __cmp__(self, other): - if type(other) is not self: + if not isinstance(self, type(other)): raise TypeError return self.days_since_epoch - other.days_since_epoch diff --git a/entity/o_types/OTime.py b/entity/o_types/OTime.py index f60f640..00b1bdc 100644 --- a/entity/o_types/OTime.py +++ b/entity/o_types/OTime.py @@ -15,7 +15,8 @@ def __init__(self, epoch=None, hour_of_day=None, minutes=None, self.__time = datetime.datetime.fromtimestamp(epoch).time() self.__millis_of_day = long((self.__time.hour * 60 * 60 + self.__time.second) * 1000 + self.__time.microsecond / 1000.0) - elif all([hour_of_day, minutes, seconds]) is not None: + # elif all([hour_of_day, minutes, seconds]) is not None: + elif hour_of_day is not None and minutes is not None and seconds is not None: if ms is None: self.__time = datetime.time(hour=hour_of_day, minute=minutes, second=seconds, microsecond=0) else: @@ -23,7 +24,7 @@ def __init__(self, epoch=None, hour_of_day=None, minutes=None, self.__millis_of_day = long((self.__time.hour * 60 * 60 + self.__time.second) * 1000 + self.__time.microsecond / 1000.0) elif date is not None: - if not isinstance(type(date), datetime.datetime): + if not isinstance(type(date), type(datetime.datetime)): raise TypeError self.__time = date.time() self.__millis_of_day = long((self.__time.hour * 60 * 60 + self.__time.second) @@ -48,7 +49,7 @@ def millis_of_day(self): @staticmethod def parse(time_str): - return OTime(date=dateutil.parser.parse("1970-01-01T"+time_str)) + return OTime(date=dateutil.parser.parse("1970-01-01 " + time_str)) @staticmethod def from_millis_of_day(millis_of_day): diff --git a/entity/o_types/OTimestamp.py b/entity/o_types/OTimestamp.py index c355950..8784491 100644 --- a/entity/o_types/OTimestamp.py +++ b/entity/o_types/OTimestamp.py @@ -24,8 +24,10 @@ class OTimestamp: def __init__(self, year=None, month_of_year=None, day_of_month=None, hour_of_day=None, minute_of_hour=None, second_of_minute=None, millis_of_second=None, date=None, millis_since_epoch=None): - if all([year, month_of_year, day_of_month, hour_of_day, - minute_of_hour, second_of_minute, millis_of_second]) is not None: + # if all([year, month_of_year, day_of_month, hour_of_day, + # minute_of_hour, second_of_minute, millis_of_second]) is not None: + if (year is not None and month_of_year is not None and day_of_month is not None and hour_of_day is not None + and minute_of_hour is not None and second_of_minute is not None and millis_of_second is not None): self.__date_time = datetime.datetime(year=year, month=month_of_year, day=day_of_month, hour=hour_of_day, minute=minute_of_hour, second=second_of_minute, microsecond=millis_of_second * 1000) @@ -34,7 +36,7 @@ def __init__(self, year=None, month_of_year=None, day_of_month=None, hour_of_day self.__date_time = None self.__millis_since_epoch = millis_since_epoch elif date is not None: - if not isinstance(type(datetime.datetime), type(date)): + if not isinstance(type(date), type(datetime.datetime)): raise TypeError self.__date_time = date self.__millis_since_epoch = (self.__date_time - self.__epoch).total_seconds() * 1000.0 @@ -77,7 +79,7 @@ def __get_date_time(self): # Create datetime object from millis since epoch def to_date(self): - return datetime.datetime.fromtimestamp(self.millis_since_epoch/1000.0) + return datetime.datetime.fromtimestamp(self.millis_since_epoch / 1000.0) # Returns the ISO8601 format timestamp string in UTC. def to_utc_str(self): @@ -90,6 +92,10 @@ def to_local_str(self): def to_str(self, pattern): return self.__get_date_time().strftime(pattern) + @staticmethod + def parse(date_time_str): + return OTimestamp(date=dateutil.parser.parse(date_time_str)) + def __str__(self): return self.to_utc_str() @@ -111,7 +117,3 @@ def __eq__(self, other): if self.millis_since_epoch != other.millis_since_epoch: return False return True - - - - diff --git a/entity/values/ValueImpl.py b/entity/values/ValueImpl.py index 67c10da..25de6ac 100644 --- a/entity/values/ValueImpl.py +++ b/entity/values/ValueImpl.py @@ -1,5 +1,8 @@ from Value import Value, ValueType +from entity.o_types.ODate import ODate from entity.o_types.OInterval import OInterval +from entity.o_types.OTime import OTime +from entity.o_types.OTimestamp import OTimestamp class ValueImpl(Value): @@ -52,8 +55,8 @@ def get_obj(self): def get_date(self): self.check_type(ValueType.DATE) if self.obj_value is None: - # TODO implement ODate class - pass + self.obj_value = ODate.from_days_since_epoch(self.json_value) + return self.obj_value def get_map(self): self.check_type(ValueType.MAP) @@ -91,8 +94,8 @@ def get_byte(self): def get_time(self): self.check_type(ValueType.TIME) if self.obj_value is None: - # TODO implement OTime class - pass + self.obj_value = OTime.from_millis_of_day(millis_of_day=self.json_value) + return self.obj_value def get_long(self): switcher = { @@ -129,8 +132,8 @@ def get_boolean(self): def get_timestamp(self): self.check_type(ValueType.TIMESTAMP) if self.obj_value is None: - # TODO implement OTimeStamp class - pass + self.obj_value = OTimestamp(millis_since_epoch=self.json_value) + return self.obj_value def get_decimal(self): # TODO check and implement get_decimal like java BigDecimal diff --git a/test/o_types_test/test_odate.py b/test/o_types_test/test_odate.py index d714ebf..b4422b7 100644 --- a/test/o_types_test/test_odate.py +++ b/test/o_types_test/test_odate.py @@ -11,12 +11,65 @@ class ODateTest(unittest.TestCase): def test_days_from_epoch(self): - pass + days = 99 + o_date = ODate(days_since_epoch=days) + o_date_clone = ODate(days_since_epoch=days) + self.assertTrue(o_date.__eq__(o_date_clone)) + self.assertEqual(o_date.__cmp__(o_date_clone), 0) + self.assertEqual(o_date.__hash__(), o_date_clone.__hash__()) + self.assertEqual(o_date.to_date_str(), "1970-04-10") + self.assertEqual(o_date.get_year(), 1970) + self.assertEqual(o_date.get_month(), 4) + self.assertEqual(o_date.get_day_of_month(), 10) + self.assertEqual(o_date.to_date().time().hour, 0) + self.assertEqual(o_date.to_date().time().minute, 0) + self.assertEqual(o_date.to_date().time().second, 0) + def test_o_date_parse(self): + o_date = ODate.parse("1970-04-10") + self.assertEqual(o_date.days_since_epoch, 99) + self.assertEqual(o_date.get_year(), 1970) + self.assertEqual(o_date.get_month(), 4) + self.assertEqual(o_date.get_day_of_month(), 10) + self.assertEqual(o_date.to_date().time().hour, 0) + self.assertEqual(o_date.to_date().time().minute, 0) + self.assertEqual(o_date.to_date().time().second, 0) -if __name__ == '__main__': - suite = unittest.TestLoader().loadTestsFromTestCase(ODateTest) - unittest.TextTestRunner(verbosity=2).run(suite) + def test_concrete_date(self): + o_date = ODate(year=1970, month=4, day_of_month=10) + self.assertEqual(o_date.days_since_epoch, 99) + self.assertEqual(o_date.get_year(), 1970) + self.assertEqual(o_date.get_month(), 4) + self.assertEqual(o_date.get_day_of_month(), 10) + self.assertEqual(o_date.to_date().time().hour, 0) + self.assertEqual(o_date.to_date().time().minute, 0) + self.assertEqual(o_date.to_date().time().second, 0) + + def test_o_date_epoch(self): + epoch = 8546400 + o_date = ODate(epoch=epoch) + days = 99 + o_date_clone = ODate(days_since_epoch=days) + self.assertTrue(o_date.__eq__(o_date_clone)) + self.assertEqual(o_date.__cmp__(o_date_clone), 0) + self.assertEqual(o_date.__hash__(), o_date_clone.__hash__()) + self.assertEqual(o_date.get_year(), o_date_clone.get_year()) + self.assertEqual(o_date.get_month(), o_date_clone.get_month()) + self.assertEqual(o_date.get_day_of_month(), o_date_clone.get_day_of_month()) + def test_o_date_datetime(self): + import datetime + date = datetime.datetime(year=1970, month=4, day=10, hour=5, minute=15, second=55) + o_date = ODate(date=date) + self.assertEqual(o_date.days_since_epoch, 99) + self.assertEqual(o_date.get_year(), 1970) + self.assertEqual(o_date.get_month(), 4) + self.assertEqual(o_date.get_day_of_month(), 10) + self.assertEqual(o_date.to_date().time().hour, 0) + self.assertEqual(o_date.to_date().time().minute, 0) + self.assertEqual(o_date.to_date().time().second, 0) +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(ODateTest) + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/test/o_types_test/test_otime.py b/test/o_types_test/test_otime.py index e69de29..84b06b8 100644 --- a/test/o_types_test/test_otime.py +++ b/test/o_types_test/test_otime.py @@ -0,0 +1,60 @@ +from __future__ import unicode_literals + +from entity.o_types.OTime import OTime + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class OTimeTest(unittest.TestCase): + + def test_days_from_epoch(self): + epoch = 8587555 + o_time = OTime(epoch=epoch) + self.assertEqual(o_time.get_hour(), 12) + self.assertEqual(o_time.get_minute(), 25) + self.assertEqual(o_time.get_second(), 55) + self.assertEqual(o_time.get_millis(), 0) + parse_o_time = OTime.parse(time_str="12:25:55") + self.assertEqual(parse_o_time.get_hour(), o_time.get_hour()) + self.assertEqual(parse_o_time.get_minute(), o_time.get_minute()) + self.assertEqual(parse_o_time.get_second(), o_time.get_second()) + self.assertTrue(o_time.__eq__(parse_o_time)) + self.assertEqual(o_time.to_str("%H:%M:%S"), "12:25:55") + self.assertEqual(o_time.time_to_str(), "12:25:55") + + def test_o_time_from_time(self): + o_time = OTime(hour_of_day=12, minutes=25, seconds=55) + self.assertEqual(o_time.get_hour(), 12) + self.assertEqual(o_time.get_minute(), 25) + self.assertEqual(o_time.get_second(), 55) + self.assertEqual(o_time.get_millis(), 0) + parse_o_time = OTime.parse(time_str="12:25:55") + self.assertEqual(parse_o_time.get_hour(), o_time.get_hour()) + self.assertEqual(parse_o_time.get_minute(), o_time.get_minute()) + self.assertEqual(parse_o_time.get_second(), o_time.get_second()) + self.assertTrue(o_time.__eq__(parse_o_time)) + self.assertEqual(o_time.to_str("%H:%M:%S"), "12:25:55") + self.assertEqual(o_time.time_to_str(), "12:25:55") + + def test_o_time_from_date(self): + import datetime + o_time = OTime(date=datetime.datetime(year=1970, month=1, day=1, hour=12, minute=25, second=55)) + self.assertEqual(o_time.get_hour(), 12) + self.assertEqual(o_time.get_minute(), 25) + self.assertEqual(o_time.get_second(), 55) + self.assertEqual(o_time.get_millis(), 0) + parse_o_time = OTime.parse(time_str="12:25:55") + self.assertEqual(parse_o_time.get_hour(), o_time.get_hour()) + self.assertEqual(parse_o_time.get_minute(), o_time.get_minute()) + self.assertEqual(parse_o_time.get_second(), o_time.get_second()) + self.assertTrue(o_time.__eq__(parse_o_time)) + self.assertEqual(o_time.to_str("%H:%M:%S"), "12:25:55") + self.assertEqual(o_time.time_to_str(), "12:25:55") + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(OTimeTest) + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/test/o_types_test/test_otimestamp.py b/test/o_types_test/test_otimestamp.py index e69de29..0bdd028 100644 --- a/test/o_types_test/test_otimestamp.py +++ b/test/o_types_test/test_otimestamp.py @@ -0,0 +1,60 @@ +from __future__ import unicode_literals + +from entity.o_types.OTimestamp import OTimestamp + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class OTimestampTest(unittest.TestCase): + + def test_days_from_epoch(self): + o_timestamp = OTimestamp(year=1970, month_of_year=4, day_of_month=10, hour_of_day=12, + minute_of_hour=25, second_of_minute=55, millis_of_second=600) + o_timestamp_clone = OTimestamp(year=1970, month_of_year=4, day_of_month=10, hour_of_day=12, + minute_of_hour=25, second_of_minute=55, millis_of_second=600) + + self.assertEqual(o_timestamp.get_year(), 1970) + self.assertEqual(o_timestamp.get_month(), 4) + self.assertEqual(o_timestamp.get_day_of_month(), 10) + self.assertEqual(o_timestamp.get_hour(), 12) + self.assertEqual(o_timestamp.get_minute(), 25) + self.assertEqual(o_timestamp.get_second(), 55) + self.assertEqual(o_timestamp.get_millis(), 600) + self.assertTrue(o_timestamp.__eq__(o_timestamp_clone)) + + def test_o_timestamp_from_millis_epoch(self): + o_timestamp = OTimestamp(millis_since_epoch=8598355000) + self.assertEqual(o_timestamp.get_year(), 1970) + self.assertEqual(o_timestamp.get_month(), 4) + self.assertEqual(o_timestamp.get_day_of_month(), 10) + self.assertEqual(o_timestamp.get_hour(), 12) + self.assertEqual(o_timestamp.get_minute(), 25) + self.assertEqual(o_timestamp.get_second(), 55) + + def test_o_timestamp_from_date(self): + import datetime + date = datetime.datetime(year=1970, month=4, day=10, hour=12, minute=25, second=55) + o_timestamp = OTimestamp(date=date) + self.assertEqual(o_timestamp.get_year(), 1970) + self.assertEqual(o_timestamp.get_month(), 4) + self.assertEqual(o_timestamp.get_day_of_month(), 10) + self.assertEqual(o_timestamp.get_hour(), 12) + self.assertEqual(o_timestamp.get_minute(), 25) + self.assertEqual(o_timestamp.get_second(), 55) + + def test_parse_timestamp_to_o_timestamp(self): + o_timestamp = OTimestamp.parse("April 10 1970 12:25:55") + self.assertEqual(o_timestamp.get_year(), 1970) + self.assertEqual(o_timestamp.get_month(), 4) + self.assertEqual(o_timestamp.get_day_of_month(), 10) + self.assertEqual(o_timestamp.get_hour(), 12) + self.assertEqual(o_timestamp.get_minute(), 25) + self.assertEqual(o_timestamp.get_second(), 55) + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(OTimestampTest) + unittest.TextTestRunner(verbosity=2).run(suite) From 2566a289ad1e543f424769b340eb21089f7fb56b Mon Sep 17 00:00:00 2001 From: dshylov Date: Mon, 29 Jan 2018 19:01:52 +0200 Subject: [PATCH 11/12] Added samples, methods for byte and minor changes in Json classes. --- Sample.py | 55 +++++++++++++++++++++++++++--- entity/json/Json.py | 50 +++++++++++++++++++++++++++ entity/json/JsonDocumentBuilder.py | 6 ++++ entity/json/JsonList.py | 3 ++ entity/values/ValueImpl.py | 23 +++++++++---- 5 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 entity/json/JsonDocumentBuilder.py diff --git a/Sample.py b/Sample.py index cfca537..15f3ab4 100644 --- a/Sample.py +++ b/Sample.py @@ -5,16 +5,63 @@ """Example for customer may works with Python client""" +"""Create a connection, get store, insert new document into store""" +# create a connection by path:user@password connection = Connection(ConnectionManager.get_connection(url="ojai:mapr:user@password")) +# Get a store and keep it as DocumentStore object store = DocumentStore(connection.get_store(store_name="/test_name")) +# Json string or json map +json_string = "json string" -# Json string or json map (probably json object) -json_document = "json string" - -new_document = connection.new_document(json_document) +# Create new document from json_document +new_document = connection.new_document(json_string) +# Insert new document into the store store.insert_or_replace(new_document) +# close +store.close() +connection.close() + + +"""Create a connection, get store, find document by id""" +# create a connection by path:user@password +connection = Connection(ConnectionManager.get_connection(url="ojai:mapr:user@password")) + +# Get a store and keep it as DocumentStore object +store = DocumentStore(connection.get_store(store_name="/test_name")) + +# Fetch document from store by id +json_document = store.find_by_id("id_005") + +# close store.close() +connection.close() + + +"""Create a connection, get store, create a query, execute find query and got through document stream""" +# create a connection by path:user@password +connection = Connection(ConnectionManager.get_connection(url="ojai:mapr:user@password")) + +# Get a store and keep it as DocumentStore object +store = DocumentStore(connection.get_store(store_name="/test_name")) + +# Build query +query = connection.new_query().select("_id", "city").build() + +# fetch all document from store by query +document_stream = store.find_query(query) + +# go to fetched records and pritnt them +for document in document_stream.result: + print document + + +# close +store.close() +connection.close() + + + diff --git a/entity/json/Json.py b/entity/json/Json.py index e69de29..de90980 100644 --- a/entity/json/Json.py +++ b/entity/json/Json.py @@ -0,0 +1,50 @@ +from entity.json import JsonDocument + +from entity.json.JsonDocumentBuilder import JsonDocumentBuilder + + +class Json: + def __init__(self): + pass + + @staticmethod + def new_document(json_string=None, json_map=None): + """Returns a new, empty Document or from the specified JSON string or map.""" + if json_string is None and json_map is None: + return JsonDocument() + elif json_string is not None and type(json_string) is str: + byte_array = bytearray(json_string) + # TODO newDocumentStream required + pass + elif json_map is not None and type(json_map) is map: + # TODO JsonValueBuilder required + pass + else: + raise TypeError + + @staticmethod + def get_value_builder(): + """Returns a ValueBuilder object.""" + # TODO added implementation after JsonValueBuilder was added. + pass + + @staticmethod + def new_document_reader(json_string): + """Returns a new instance of the JSON DocumentReader.""" + byte_array = bytearray(json_string) + # todo newDocumentStream required + + @staticmethod + def new_document_builder(options=None): + """Returns a new instance of JSON DocumentBuilder.""" + if options is None: + return JsonDocumentBuilder() + else: + # todo required JsonDocumentBuilder + pass + + @staticmethod + def new_document_stream(input_stream=None, field_path_type_map=None, event_delegate=None, + fs=None, path=None): + # TODO + pass diff --git a/entity/json/JsonDocumentBuilder.py b/entity/json/JsonDocumentBuilder.py new file mode 100644 index 0000000..d5e7ef7 --- /dev/null +++ b/entity/json/JsonDocumentBuilder.py @@ -0,0 +1,6 @@ +from entity.document.DocumentBuilder import DocumentBuilder + + +class JsonDocumentBuilder(DocumentBuilder): + def __init__(self): + pass diff --git a/entity/json/JsonList.py b/entity/json/JsonList.py index e69de29..ae14873 100644 --- a/entity/json/JsonList.py +++ b/entity/json/JsonList.py @@ -0,0 +1,3 @@ +class JsonList(list): + def __init__(self): + pass diff --git a/entity/values/ValueImpl.py b/entity/values/ValueImpl.py index 25de6ac..8de8f89 100644 --- a/entity/values/ValueImpl.py +++ b/entity/values/ValueImpl.py @@ -161,13 +161,22 @@ def get_interval_as_long(self): def get_timestamp_as_long(self): return self.json_value - # TODO Implement method which convert int to byte - def int_to_byte(self, value): - pass - - # TODO Implement method which convert byte to int - def byte_to_int(self, value): - pass + @staticmethod + def int_to_byte(value, length): + result = [] + for i in range(0, length): + result.append(value >> (i * 8) & 0xff) + result.reverse() + + return result + + @staticmethod + def byte_to_int(value): + result = 0 + + for b in value: + result = result * 256 + int(b) + return result # TODO check get_binary and how we can implement it From eebec189f7356b33b3f8de40e77403e1fa30de08 Mon Sep 17 00:00:00 2001 From: dshylov Date: Tue, 30 Jan 2018 20:18:33 +0200 Subject: [PATCH 12/12] Provided changes into Value class, change ValueType enum, added test for ValueType enum. Added part of Json . Added abstract classes. --- entity/document/Document.py | 3 - entity/document/DocumentReader.py | 9 ++ entity/document/DocumentStream.py | 13 +- entity/json/Json.py | 42 ++++- entity/json/JsonDocument.py | 132 +++++++++++++++ entity/json/JsonDocumentStream.py | 34 ++++ entity/json/JsonList.py | 6 +- entity/json/JsonOptions.py | 72 +++++++++ .../ValueImpl.py => json/JsonValue.py} | 14 +- entity/json/JsonValueBuilder.py | 0 entity/utils/Documents.py | 13 ++ entity/values/Value.py | 152 ++++++------------ entity/values/ValueBuilder.py | 5 + test/json/test_jsonvalue.py | 11 ++ test/values/test_type.py | 41 +++++ 15 files changed, 421 insertions(+), 126 deletions(-) create mode 100644 entity/document/DocumentReader.py create mode 100644 entity/json/JsonDocumentStream.py rename entity/{values/ValueImpl.py => json/JsonValue.py} (94%) create mode 100644 entity/json/JsonValueBuilder.py create mode 100644 entity/utils/Documents.py create mode 100644 entity/values/ValueBuilder.py create mode 100644 test/json/test_jsonvalue.py create mode 100644 test/values/test_type.py diff --git a/entity/document/Document.py b/entity/document/Document.py index 7f27fe8..e085ebc 100644 --- a/entity/document/Document.py +++ b/entity/document/Document.py @@ -4,9 +4,6 @@ class Document: __metaclass__ = ABCMeta - def __init__(self): - pass - @abstractmethod def set_id(self, _id): raise NotImplementedError("Should have implemented this") diff --git a/entity/document/DocumentReader.py b/entity/document/DocumentReader.py new file mode 100644 index 0000000..f894c0c --- /dev/null +++ b/entity/document/DocumentReader.py @@ -0,0 +1,9 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentReader: + __metaclass__ = ABCMeta + + def __init__(self): + pass + diff --git a/entity/document/DocumentStream.py b/entity/document/DocumentStream.py index 3b13d19..fedb498 100644 --- a/entity/document/DocumentStream.py +++ b/entity/document/DocumentStream.py @@ -2,21 +2,28 @@ class DocumentStream: - __metaclass__ = ABCMeta + """ A stream of documents. + Implements Iterable but only one call is allows to iterator() + or readerIterator(). Only one of these iterators can be retrieved + from the stream.""" - def __init__(self): - pass + __metaclass__ = ABCMeta @abstractmethod def stream_to(self, doc_listener): + """Streams all the documents in this {@code DocumentStream} to the specified + listener. + doc_listener : a DocumentListener which is notified of JsonDocuments as they arrive""" raise NotImplementedError("Should have implemented this") @abstractmethod def iterator(self): + """Returns an iterator over a set of JsonDocument""" raise NotImplementedError("Should have implemented this") @abstractmethod def document_readers(self): + """Returns an Iterable over a set of DocumentReader.""" raise NotImplementedError("Should have implemented this") @abstractmethod diff --git a/entity/json/Json.py b/entity/json/Json.py index de90980..c13e33d 100644 --- a/entity/json/Json.py +++ b/entity/json/Json.py @@ -1,6 +1,9 @@ -from entity.json import JsonDocument +from entity.json.JsonDocument import JsonDocument from entity.json.JsonDocumentBuilder import JsonDocumentBuilder +from entity.json.JsonDocumentStream import JsonDocumentStream +from entity.json.JsonOptions import Options +from entity.utils.Documents import Documents class Json: @@ -14,13 +17,13 @@ def new_document(json_string=None, json_map=None): return JsonDocument() elif json_string is not None and type(json_string) is str: byte_array = bytearray(json_string) - # TODO newDocumentStream required - pass + # TODO JsonDocumentStream required!!! iterator impl + return Json.new_document_stream(input_stream=byte_array).iterator() elif json_map is not None and type(json_map) is map: # TODO JsonValueBuilder required pass else: - raise TypeError + raise AttributeError @staticmethod def get_value_builder(): @@ -32,7 +35,8 @@ def get_value_builder(): def new_document_reader(json_string): """Returns a new instance of the JSON DocumentReader.""" byte_array = bytearray(json_string) - # todo newDocumentStream required + # todo JsonDocumentStream required !!! iterator impl + return Json.new_document_stream(input_stream=byte_array).iterator() @staticmethod def new_document_builder(options=None): @@ -40,11 +44,35 @@ def new_document_builder(options=None): if options is None: return JsonDocumentBuilder() else: - # todo required JsonDocumentBuilder + # todo required JsonDocumentBuilder, options!! pass @staticmethod def new_document_stream(input_stream=None, field_path_type_map=None, event_delegate=None, fs=None, path=None): # TODO - pass + if fs is None and path is None: + return JsonDocumentStream(input_stream=input_stream, + field_path_type_map=field_path_type_map, + event_delegate=event_delegate) + elif fs is not None and path is not None: + return JsonDocumentStream.new_document_stream(fs=fs, path=path, + field_path_type_map=field_path_type_map, + event_delegate=event_delegate) + else: + raise AttributeError("Unexpected input params set") + + # TODO encode method skipped, bean required + + @staticmethod + def to_json_string(document=None, options=None, document_reader=None): + if document is not None: + document_reader = document.as_reader() + + if options is None: + options = Options.DEFAULT + # TODO JsonDocumentBuilder and DocumentReader required!!! + + @staticmethod + def write_reader_to_builder(document_reader, document_builder): + Documents.write_reader_to_builder(document_reader=document_reader, document_builder=document_builder) diff --git a/entity/json/JsonDocument.py b/entity/json/JsonDocument.py index e69de29..9f0da12 100644 --- a/entity/json/JsonDocument.py +++ b/entity/json/JsonDocument.py @@ -0,0 +1,132 @@ +from entity.document.Document import Document +from entity.json.JsonValue import JsonValue + + +class JsonDocument(Document): + __json_stream_document_reader = None + + def __init__(self, json_value=None): + self.json_value = json_value + + def set_id(self, _id): + pass + + def get_id(self): + pass + + def get_id_string(self): + pass + + def get_id_binary(self): + pass + + def size(self): + pass + + def empty(self): + pass + + def set(self, field_path, value): + pass + + def set_boolean(self, field_path, value): + pass + + def set_byte(self, field_path, value): + pass + + def set_long(self, field_path, value): + pass + + def set_float(self, field_path, value): + pass + + def set_decimal(self, field_path, value): + pass + + def set_time(self, field_path, value): + pass + + def set_date(self, field_path, value): + pass + + def set_timestamp(self, field_path, value): + pass + + def set_interval(self, field_path, value): + pass + + def set_byte_array(self, field_path, value, offset=None, length=None): + pass + + def set_map(self, field_path, value): + pass + + def set_document(self, field_path, value): + pass + + def set_value_obj(self, field_path, value): + pass + + def set_array(self, field_path, values): + pass + + def set_null(self, field_path): + pass + + def delete(self, field_path): + pass + + def get_string(self, field_path): + pass + + def get_boolean(self, field_path): + pass + + def get_byte(self, field_path): + pass + + def get_int(self, field_path): + pass + + def get_long(self, field_path): + pass + + def get_float(self, field_path): + pass + + def get_double(self, field_path): + pass + + def get_decimal(self, field_path): + pass + + def get_time(self, field_path): + pass + + def get_date(self, field_path): + pass + + def get_timestamp(self, field_path): + pass + + def get_binary(self, field_path): + pass + + def get_interval(self, field_path): + pass + + def get_value(self, field_path): + pass + + def get_map(self, field_path): + pass + + def get_list(self, field_path): + pass + + def as_reader(self, field_path=None): + pass + + def as_map(self): + pass diff --git a/entity/json/JsonDocumentStream.py b/entity/json/JsonDocumentStream.py new file mode 100644 index 0000000..1b70441 --- /dev/null +++ b/entity/json/JsonDocumentStream.py @@ -0,0 +1,34 @@ +from entity.document.DocumentStream import DocumentStream + + +class JsonDocumentStream(DocumentStream): + + __input_stream = None + __json_parser = None + __read_started = None + __iterator_opened = None + + __field_path_type_map = None + __event_delegate = None + + def __init__(self, input_stream=None, field_path_type_map=None, event_delegate=None): + pass + + def stream_to(self, doc_listener): + pass + + def iterator(self): + pass + + def document_readers(self): + pass + + def close(self): + pass + + def get_query_plan(self): + pass + + @staticmethod + def new_document_stream(fs, path, field_path_type_map=None, event_delegate=None): + pass diff --git a/entity/json/JsonList.py b/entity/json/JsonList.py index ae14873..a9ced7d 100644 --- a/entity/json/JsonList.py +++ b/entity/json/JsonList.py @@ -1,3 +1,5 @@ + + class JsonList(list): - def __init__(self): - pass + def __init__(self, json_value=None): + super(JsonList, self).__init__() diff --git a/entity/json/JsonOptions.py b/entity/json/JsonOptions.py index e69de29..d39ec4d 100644 --- a/entity/json/JsonOptions.py +++ b/entity/json/JsonOptions.py @@ -0,0 +1,72 @@ +class JsonOptions: + + """This class encapsulates various options to configure a JSON serializer for Documents. + Currently, it supports the following options: + Pretty Print: off by default. + With Tags: on by default""" + + __pretty = False + __with_tags = False + + def __init__(self): + pass + + def is_pretty(self): + return self.__pretty + + # TODO test it careful + def __check_mutation_of_constants(self): + if Options.DEFAULT == self or Options.WITH_TAGS == self: + raise AttributeError + + def set_pretty(self, pretty): + self.__check_mutation_of_constants() + self.__pretty = pretty + return self + + def pretty(self): + self.__check_mutation_of_constants() + self.__pretty = True + return self + + # TODO deprecated??? + def compact(self): + self.__check_mutation_of_constants() + self.__pretty = False + return self + + def is_with_tags(self, with_tags): + self.__check_mutation_of_constants() + self.__with_tags = with_tags + return self + + def with_tags(self): + self.__check_mutation_of_constants() + self.__with_tags = True + return self + + def without_tags(self): + self.__check_mutation_of_constants() + self.__with_tags = False + return self + + def __str__(self): + return "\"pretty\"" + self.__pretty + ", \"with_tags\": " + self.__with_tags + + +class Options: + + def __init__(self): + pass + + __DEFAULT = JsonOptions() + __WITH_TAGS = JsonOptions().with_tags() + + @property + def DEFAULT(self): + return self.__DEFAULT + + @property + def WITH_TAGS(self): + return self.__WITH_TAGS + diff --git a/entity/values/ValueImpl.py b/entity/json/JsonValue.py similarity index 94% rename from entity/values/ValueImpl.py rename to entity/json/JsonValue.py index 8de8f89..c8f819e 100644 --- a/entity/values/ValueImpl.py +++ b/entity/json/JsonValue.py @@ -1,11 +1,12 @@ -from Value import Value, ValueType +from entity.values.Value import Value, ValueType +from entity.json.JsonList import JsonList from entity.o_types.ODate import ODate from entity.o_types.OInterval import OInterval from entity.o_types.OTime import OTime from entity.o_types.OTimestamp import OTimestamp -class ValueImpl(Value): +class JsonValue(Value): def __init__(self, value_type=None, json_value=None, obj_value=None): self.value_type = value_type @@ -61,7 +62,10 @@ def get_date(self): def get_map(self): self.check_type(ValueType.MAP) # TODO added get_map implementation after JSONDocument will done - pass + # TODO Test it + from entity.json.JsonDocument import JsonDocument + doc = JsonDocument(json_value=self) + return doc def get_time_as_int(self): return int(self.json_value) @@ -78,7 +82,9 @@ def get_interval(self): def get_list(self): self.check_type(ValueType.ARRAY) # TODO added get_map implementation after JSONList will done - pass + # TODO TEST IT + json_list = JsonList(json_value=self) + return json_list def get_byte(self): switcher = { diff --git a/entity/json/JsonValueBuilder.py b/entity/json/JsonValueBuilder.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/utils/Documents.py b/entity/utils/Documents.py new file mode 100644 index 0000000..e2cfc49 --- /dev/null +++ b/entity/utils/Documents.py @@ -0,0 +1,13 @@ + +class Documents: + + def __init__(self): + pass + + @staticmethod + def write_reader_to_builder(document_reader, document_builder): + pass + + @staticmethod + def equals(document1, document2): + pass diff --git a/entity/values/Value.py b/entity/values/Value.py index 70228a3..68a46b6 100644 --- a/entity/values/Value.py +++ b/entity/values/Value.py @@ -1,94 +1,10 @@ from abc import ABCMeta, abstractmethod +from aenum import Enum class Value: __metaclass__ = ABCMeta - __TYPE_CODE_NULL = 1 - __TYPE_CODE_BOOLEAN = 2 - __TYPE_CODE_STRING = 3 - __TYPE_CODE_BYTE = 4 - __TYPE_CODE_INT = 5 - __TYPE_CODE_LONG = 6 - __TYPE_CODE_FLOAT = 7 - __TYPE_CODE_DECIMAL = 8 - __TYPE_CODE_DATE = 9 - __TYPE_CODE_TIME = 10 - __TYPE_CODE_TIMESTAMP = 11 - __TYPE_CODE_INTERVAL = 12 - __TYPE_CODE_BINARY = 13 - __TYPE_CODE_MAP = 14 - __TYPE_CODE_ARRAY = 15 - - @property - def type_code_boolean(self): - return self.__TYPE_CODE_BOOLEAN - - @property - def type_code_null(self): - return self.__TYPE_CODE_NULL - - @property - def type_code_string(self): - return self.__TYPE_CODE_STRING - - @property - def type_code_byte(self): - return self.__TYPE_CODE_BYTE - - @property - def type_code_int(self): - return self.__TYPE_CODE_INT - - @property - def type_code_long(self): - return self.__TYPE_CODE_LONG - - @property - def type_code_float(self): - return self.__TYPE_CODE_FLOAT - - @property - def type_code_decimal(self): - return self.__TYPE_CODE_DECIMAL - - @property - def type_code_date(self): - return self.__TYPE_CODE_DATE - - @property - def type_code_time(self): - return self.__TYPE_CODE_TIME - - @property - def type_code_timestamp(self): - return self.__TYPE_CODE_TIMESTAMP - - @property - def type_code_interval(self): - return self.__TYPE_CODE_INTERVAL - - @property - def type_code_binary(self): - return self.__TYPE_CODE_BINARY - - @property - def type_code_map(self): - return self.__TYPE_CODE_MAP - - @property - def type_code_array(self): - return self.__TYPE_CODE_ARRAY - - # @staticmethod - # def is_scalar(value): - # return value != Value.type_code_map and value != Value.type_code_array - # - # @staticmethod - # def is_numeric(value): - # return Value.type_code_byte <= value <= Value.type_code_decimal - - @abstractmethod def get_type(self): raise NotImplementedError("Should have implemented this") @@ -176,44 +92,66 @@ def as_reader(self): # TODO Python2 doesn't have enum. Impelement method for convert ValueType numeric field to string like 2 -> "BOOLEAN" -class ValueType(object): - def __init__(self, value_type): - self.__value = value_type +class ValueType(Enum): + # NULL = Value.type_code_null + NULL = 1 - NULL = Value.type_code_null + # BOOLEAN = Value.type_code_boolean + BOOLEAN = 2 - BOOLEAN = Value.type_code_boolean + # STRING = Value.type_code_string + STRING = 3 - STRING = Value.type_code_string + # BYTE = Value.type_code_byte + BYTE = 4 - BYTE = Value.type_code_byte + # INT = Value.type_code_int + INT = 5 - INT = Value.type_code_int + # LONG = Value.type_code_long + LONG = 6 - LONG = Value.type_code_long + # FLOAT = Value.type_code_float + FLOAT = 7 - FLOAT = Value.type_code_float + # DECIMAL = Value.type_code_decimal + DECIMAL = 8 - DECIMAL = Value.type_code_decimal + # DATE = Value.type_code_date + DATE = 9 - DATE = Value.type_code_date + # TIME = Value.type_code_time + TIME = 10 - TIME = Value.type_code_time + # TIMESTAMP = Value.get_timestamp + TIMESTAMP = 11 - TIMESTAMP = Value.get_timestamp + # INTERVAL = Value.type_code_interval + INTERVAL = 12 - INTERVAL = Value.type_code_interval + # BINARY = Value.type_code_binary + BINARY = 13 - BINARY = Value.type_code_binary + # MAP = Value.type_code_map + MAP = 14 - MAP = Value.type_code_map + # ARRAY = Value.type_code_array + ARRAY = 15 - ARRAY = Value.type_code_array + @staticmethod + def __check_value(value_type): + value_dict = {ValueType.NULL: 1, ValueType.BOOLEAN: 2, ValueType.STRING: 3, ValueType.BYTE: 4, ValueType.INT: 5, + ValueType.LONG: 6, ValueType.FLOAT: 7, ValueType.DECIMAL: 8, ValueType.DATE: 9, + ValueType.TIME: 10, ValueType.TIMESTAMP: 11, ValueType.INTERVAL: 12, + ValueType.BINARY: 13, ValueType.MAP: 14, ValueType.ARRAY: 15} + return value_dict[value_type] @staticmethod - def __is_scalar__(value): - return value != Value.type_code_map and value != Value.type_code_array + def is_scalar(value): + return ValueType.__check_value(value) != ValueType.__check_value(ValueType.MAP)\ + and ValueType.__check_value(value) != ValueType.__check_value(ValueType.ARRAY) @staticmethod - def __is_numeric__(value): - return Value.type_code_byte <= value <= Value.type_code_decimal \ No newline at end of file + def is_numeric(value): + return ValueType.__check_value(ValueType.BYTE) <= ValueType.__check_value(value)\ + <= ValueType.__check_value(ValueType.DECIMAL) diff --git a/entity/values/ValueBuilder.py b/entity/values/ValueBuilder.py new file mode 100644 index 0000000..291898c --- /dev/null +++ b/entity/values/ValueBuilder.py @@ -0,0 +1,5 @@ +from abc import ABCMeta, abstractmethod + + +class ValueBuilder: + __metaclass__ = ABCMeta \ No newline at end of file diff --git a/test/json/test_jsonvalue.py b/test/json/test_jsonvalue.py new file mode 100644 index 0000000..25abbc1 --- /dev/null +++ b/test/json/test_jsonvalue.py @@ -0,0 +1,11 @@ +from __future__ import unicode_literals + +from entity.o_types.OInterval import OInterval +from entity.values import Value +from entity.values.Value import ValueType + +try: + import unittest2 as unittest +except ImportError: + import unittest + diff --git a/test/values/test_type.py b/test/values/test_type.py new file mode 100644 index 0000000..445ff8a --- /dev/null +++ b/test/values/test_type.py @@ -0,0 +1,41 @@ +from __future__ import unicode_literals + +from entity.o_types.OInterval import OInterval +from entity.values import Value +from entity.values.Value import ValueType + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class ValueTypeTest(unittest.TestCase): + + def test_value_type(self): + self.assertFalse(ValueType.is_numeric(ValueType.NULL)) + self.assertFalse(ValueType.is_numeric(ValueType.BOOLEAN)) + self.assertFalse(ValueType.is_numeric(ValueType.STRING)) + self.assertTrue(ValueType.is_numeric(ValueType.BYTE)) + self.assertTrue(ValueType.is_numeric(ValueType.INT)) + self.assertTrue(ValueType.is_numeric(ValueType.LONG)) + self.assertTrue(ValueType.is_numeric(ValueType.FLOAT)) + self.assertTrue(ValueType.is_numeric(ValueType.DECIMAL)) + self.assertFalse(ValueType.is_numeric(ValueType.DATE)) + self.assertFalse(ValueType.is_numeric(ValueType.TIME)) + self.assertFalse(ValueType.is_numeric(ValueType.TIMESTAMP)) + self.assertFalse(ValueType.is_numeric(ValueType.INTERVAL)) + self.assertFalse(ValueType.is_numeric(ValueType.BINARY)) + self.assertFalse(ValueType.is_numeric(ValueType.MAP)) + self.assertFalse(ValueType.is_numeric(ValueType.ARRAY)) + + self.assertFalse(ValueType.is_scalar(ValueType.MAP)) + self.assertFalse(ValueType.is_scalar(ValueType.ARRAY)) + + self.assertEqual(ValueType.ARRAY, ValueType.ARRAY) + self.assertNotEqual(ValueType.ARRAY, ValueType.MAP) + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(ValueTypeTest) + unittest.TextTestRunner(verbosity=2).run(suite)