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/.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/Sample.py b/Sample.py new file mode 100644 index 0000000..15f3ab4 --- /dev/null +++ b/Sample.py @@ -0,0 +1,67 @@ +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""" +"""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" + +# 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/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..e085ebc --- /dev/null +++ b/entity/document/Document.py @@ -0,0 +1,169 @@ +from abc import ABCMeta, abstractmethod + + +class Document: + __metaclass__ = ABCMeta + + @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_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") + + @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_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..4f17faa --- /dev/null +++ b/entity/document/DocumentBuilder.py @@ -0,0 +1,156 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentBuilder: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + 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 + 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_map(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 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): + 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 + 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/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/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..06f27e4 --- /dev/null +++ b/entity/document/DocumentMutation.py @@ -0,0 +1,209 @@ +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): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + 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 + 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 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/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/DocumentStore.py b/entity/document/DocumentStore.py new file mode 100644 index 0000000..6ebe45c --- /dev/null +++ b/entity/document/DocumentStore.py @@ -0,0 +1,120 @@ +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_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, condition=None, query_string=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def insert_or_replace(self, doc=None, _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_by_id(self, _id): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def delete_document(self, doc=None, field_as_key=None, doc_stream=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_document(self, document, field_as_key=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + 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") + + @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..fedb498 --- /dev/null +++ b/entity/document/DocumentStream.py @@ -0,0 +1,35 @@ +from abc import ABCMeta, abstractmethod + + +class DocumentStream: + """ 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.""" + + __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 + 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/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/json/Json.py b/entity/json/Json.py new file mode 100644 index 0000000..c13e33d --- /dev/null +++ b/entity/json/Json.py @@ -0,0 +1,78 @@ +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: + 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 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 AttributeError + + @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 JsonDocumentStream required !!! iterator impl + return Json.new_document_stream(input_stream=byte_array).iterator() + + @staticmethod + def new_document_builder(options=None): + """Returns a new instance of JSON DocumentBuilder.""" + if options is None: + return JsonDocumentBuilder() + else: + # 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 + 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 new file mode 100644 index 0000000..9f0da12 --- /dev/null +++ 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/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/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 new file mode 100644 index 0000000..a9ced7d --- /dev/null +++ b/entity/json/JsonList.py @@ -0,0 +1,5 @@ + + +class JsonList(list): + def __init__(self, json_value=None): + super(JsonList, self).__init__() diff --git a/entity/json/JsonOptions.py b/entity/json/JsonOptions.py new file mode 100644 index 0000000..d39ec4d --- /dev/null +++ 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/json/JsonUtils.py b/entity/json/JsonUtils.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/json/JsonValue.py b/entity/json/JsonValue.py new file mode 100644 index 0000000..c8f819e --- /dev/null +++ b/entity/json/JsonValue.py @@ -0,0 +1,205 @@ +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 JsonValue(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: + self.obj_value = ODate.from_days_since_epoch(self.json_value) + return self.obj_value + + def get_map(self): + self.check_type(ValueType.MAP) + # TODO added get_map implementation after JSONDocument will done + # 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) + + def get_type(self): + return self.value_type + + def get_interval(self): + self.check_type(ValueType.INTERVAL) + if self.obj_value is None: + self.obj_value = OInterval(self.json_value) + return self.obj_value + + def get_list(self): + self.check_type(ValueType.ARRAY) + # TODO added get_map implementation after JSONList will done + # TODO TEST IT + json_list = JsonList(json_value=self) + return json_list + + 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: + self.obj_value = OTime.from_millis_of_day(millis_of_day=self.json_value) + return self.obj_value + + 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: + 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 + 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 + + @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 + + # 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) diff --git a/entity/json/JsonValueBuilder.py b/entity/json/JsonValueBuilder.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..67503fa --- /dev/null +++ b/entity/o_types/ODate.py @@ -0,0 +1,102 @@ +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(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.__date = None + self.__days_since_epoch = days_since_epoch + else: + raise UnsupportedConstructorException + + @property + def epoch_date(self): + return self.__EPOCH_DATE + + @property + def start_of_day(self): + return self.__START_OF_DAY + + @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 + + # 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 + + 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) + + # 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): + return self.to_date_str() + + def __cmp__(self, other): + if not isinstance(self, type(other)): + raise TypeError + return self.days_since_epoch - other.days_since_epoch + + def __hash__(self): + return self.__days_since_epoch + + 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/OInterval.py b/entity/o_types/OInterval.py new file mode 100644 index 0000000..01085f4 --- /dev/null +++ b/entity/o_types/OInterval.py @@ -0,0 +1,74 @@ +from entity.exceptions.UnsupportedConstructorException import UnsupportedConstructorException +from entity.o_types 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 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.__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): + 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 is other: + return True + if other is None: + return False + if not isinstance(self, type(other)): + 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..00b1bdc --- /dev/null +++ b/entity/o_types/OTime.py @@ -0,0 +1,116 @@ +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: + 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: + 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), type(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-01 " + 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 + + + + + + diff --git a/entity/o_types/OTimestamp.py b/entity/o_types/OTimestamp.py new file mode 100644 index 0000000..8784491 --- /dev/null +++ b/entity/o_types/OTimestamp.py @@ -0,0 +1,119 @@ +import datetime +import dateutil.parser + +from entity.exceptions import UnsupportedConstructorException + + +class OTimestamp: + __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: + 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) + 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(date), type(datetime.datetime)): + 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) + + @staticmethod + def parse(date_time_str): + return OTimestamp(date=dateutil.parser.parse(date_time_str)) + + 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/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/storage/Connection.py b/entity/storage/Connection.py new file mode 100644 index 0000000..8582a52 --- /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, obj=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/ConnectionManager.py b/entity/storage/ConnectionManager.py new file mode 100644 index 0000000..0510792 --- /dev/null +++ b/entity/storage/ConnectionManager.py @@ -0,0 +1,16 @@ +from abc import ABCMeta, abstractmethod + + +class ConnectionManager: + __metaclass__ = ABCMeta + + def __init__(self): + pass + + @abstractmethod + def get_connection(self, url, options=None): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def check_url(self, url): + raise NotImplementedError("Should have implemented this") \ No newline at end of file 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 new file mode 100644 index 0000000..68a46b6 --- /dev/null +++ b/entity/values/Value.py @@ -0,0 +1,157 @@ +from abc import ABCMeta, abstractmethod +from aenum import Enum + + +class Value: + __metaclass__ = ABCMeta + + @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") + + @abstractmethod + def get_interval_as_long(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_map(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_list(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def get_obj(self): + raise NotImplementedError("Should have implemented this") + + @abstractmethod + def as_reader(self): + raise NotImplementedError("Should have implemented this") + + # TODO investigate is we can add binary analog (java.nia.ByteBuffer) + # @abstractmethod + # def get_binary(self): + # raise NotImplementedError("Should have implemented this") + + +# TODO Python2 doesn't have enum. Impelement method for convert ValueType numeric field to string like 2 -> "BOOLEAN" +class ValueType(Enum): + # NULL = Value.type_code_null + NULL = 1 + + # BOOLEAN = Value.type_code_boolean + BOOLEAN = 2 + + # STRING = Value.type_code_string + STRING = 3 + + # BYTE = Value.type_code_byte + BYTE = 4 + + # INT = Value.type_code_int + INT = 5 + + # LONG = Value.type_code_long + LONG = 6 + + # FLOAT = Value.type_code_float + FLOAT = 7 + + # DECIMAL = Value.type_code_decimal + DECIMAL = 8 + + # DATE = Value.type_code_date + DATE = 9 + + # TIME = Value.type_code_time + TIME = 10 + + # TIMESTAMP = Value.get_timestamp + TIMESTAMP = 11 + + # INTERVAL = Value.type_code_interval + INTERVAL = 12 + + # BINARY = Value.type_code_binary + BINARY = 13 + + # MAP = Value.type_code_map + MAP = 14 + + # ARRAY = Value.type_code_array + ARRAY = 15 + + @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 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 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/o_types_test/test_odate.py b/test/o_types_test/test_odate.py new file mode 100644 index 0000000..b4422b7 --- /dev/null +++ b/test/o_types_test/test_odate.py @@ -0,0 +1,75 @@ +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): + 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) + + 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_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) diff --git a/test/o_types_test/test_otime.py b/test/o_types_test/test_otime.py new file mode 100644 index 0000000..84b06b8 --- /dev/null +++ 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 new file mode 100644 index 0000000..0bdd028 --- /dev/null +++ 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) 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)