Commits

codernity  committed 583ecd1

Multiple keys in index (awaited/requested by many users).
Also extended test suite to cover that indexes. They exists for both.

  • Participants
  • Parent commits 17a8dd5

Comments (0)

Files changed (6)

File CodernityDB/__init__.py

 # limitations under the License.
 
 
-__version__ = '0.3.63'
+__version__ = '0.3.70'
 __license__ = "Apache 2.0"

File CodernityDB/hash_index.py

             self.storage = DummyStorage()
         self.storage.create()
 
+
+class IU_MultiHashIndex(IU_HashIndex):
+    """
+    Class that allows to index more than one key per database record.
+
+    It operates very well on GET/INSERT. It's not optimized for
+    UPDATE operations (will always readd everything)
+    """
+
+    def __init__(self, *args, **kwargs):
+        super(IU_MultiHashIndex, self).__init__(*args, **kwargs)
+
+    def insert(self, doc_id, key, start, size, status='o'):
+        if isinstance(key, (list, tuple)):
+            key = set(key)
+        elif not isinstance(key, set):
+            key = set([key])
+        ins = super(IU_MultiHashIndex, self).insert
+        for curr_key in key:
+            ins(doc_id, curr_key, start, size, status)
+        return True
+
+    def update(self, doc_id, key, u_start, u_size, u_status='o'):
+        if isinstance(key, (list, tuple)):
+            key = set(key)
+        elif not isinstance(key, set):
+            key = set([key])
+        upd = super(IU_MultiHashIndex, self).update
+        for curr_key in key:
+            upd(doc_id, curr_key, u_start, u_size, u_status)
+
+    def delete(self, doc_id, key, start=0, size=0):
+        if isinstance(key, (list, tuple)):
+            key = set(key)
+        elif not isinstance(key, set):
+            key = set([key])
+        delete = super(IU_MultiHashIndex, self).delete
+        for curr_key in key:
+            delete(doc_id, curr_key, start, size)
+
+    def get(self, key):
+        return super(IU_MultiHashIndex, self).get(key)
+
+    def make_key_value(self, data):
+        raise NotImplemented
+
+
 # classes for public use, done in this way because of
 # generation static files with indexes (_index directory)
 
     That class is designed to be used in custom indexes. It's designed to be **id** index.
     """
     pass
+
+
+class MultiHashIndex(IU_MultiHashIndex):
+    """
+    That class is designed to be used in custom indexes.
+    """

File CodernityDB/tree_index.py

         self._clear_cache()
 
 
+class IU_MultiTreeBasedIndex(IU_TreeBasedIndex):
+    """
+    Class that allows to index more than one key per database record.
+
+    It operates very well on GET/INSERT. It's not optimized for
+    UPDATE operations (will always readd everything)
+    """
+
+    def __init__(self, *args, **kwargs):
+        super(IU_MultiTreeBasedIndex, self).__init__(*args, **kwargs)
+
+    def insert(self, doc_id, key, start, size, status='o'):
+        if isinstance(key, (list, tuple)):
+            key = set(key)
+        elif not isinstance(key, set):
+            key = set([key])
+        ins = super(IU_MultiTreeBasedIndex, self).insert
+        for curr_key in key:
+            ins(doc_id, curr_key, start, size, status)
+        return True
+
+    def update(self, doc_id, key, u_start, u_size, u_status='o'):
+        if isinstance(key, (list, tuple)):
+            key = set(key)
+        elif not isinstance(key, set):
+            key = set([key])
+        upd = super(IU_MultiTreeBasedIndex, self).update
+        for curr_key in key:
+            upd(doc_id, curr_key, u_start, u_size, u_status)
+
+    def delete(self, doc_id, key, start=0, size=0):
+        if isinstance(key, (list, tuple)):
+            key = set(key)
+        elif not isinstance(key, set):
+            key = set([key])
+        delete = super(IU_MultiTreeBasedIndex, self).delete
+        for curr_key in key:
+            delete(doc_id, curr_key, start, size)
+
+    def get(self, key):
+        return super(IU_MultiTreeBasedIndex, self).get(key)
+
+    def make_key_value(self, data):
+        raise NotImplemented
+
+
+# classes for public use, done in this way because of
+# generation static files with indexes (_index directory)
+
+
 class TreeBasedIndex(IU_TreeBasedIndex):
+
+
+class MultiTreeBasedIndex(IU_MultiTreeBasedIndex):
+    """
+    It allows to index more than one key for record. (ie. prefix/infix/suffix search mechanizms)
+    That class is designed to be used in custom indexes.
+    """
     pass

File docs/quick.rst

 .. note::
    If you're |CodernityDB-HTTP-link| with |CodernityDB-PyClient-link|
    you should just change Database initialization (set host & port).
+
+
+.. _tables_colections_q2:
+
+Tables, collections...?
+-------------------------
+
+    OK, I got it, but can I store more than one data type in Database. Is there something like table or collection ?
+
+Plaese refer to :ref:`tables_colections_q` for this task.

File tests/misc/words.txt

+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque mollis lorem vel urna bibendum ultricies. Quisque vitae neque ac ipsum aliquet dictum. Quisque egestas magna sed urna pellentesque imperdiet. Nunc faucibus varius viverra. Pellentesque sagittis pulvinar faucibus. Nulla placerat pharetra sollicitudin. Quisque dolor mi, convallis et adipiscing id, tempor et tortor. Vestibulum et mi vitae sem malesuada tincidunt. Nullam malesuada nisi non est dignissim sed egestas dui ultrices. Aliquam ut velit dui, at semper dolor. Nam ultricies neque eu sem egestas porta convallis quam gravida. Nam vestibulum, lorem et vulputate lacinia, ipsum dui tempor orci, consequat porttitor enim quam id velit. Sed dapibus fermentum elementum. Curabitur at augue vitae libero ornare lacinia ut ut velit. Nam euismod pharetra egestas. Integer nec purus vitae nisi posuere vulputate.
+
+Vestibulum quis urna ligula. Duis fringilla nunc vitae velit aliquam ac varius nunc pulvinar. Praesent velit massa, lobortis in tempor vitae, mattis sit amet nunc. Integer eleifend fringilla viverra. Donec in velit ut sem imperdiet tempus non non metus. Nulla sodales est in purus ornare feugiat. Donec volutpat quam at est feugiat sed euismod dui viverra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer sed metus id mi lobortis.
+
+Codernity

File tests/shared.py

 # limitations under the License.
 
 from CodernityDB.database import Database, RecordDeleted, RecordNotFound
-from CodernityDB.database import DatabaseException, RevConflict, DatabasePathException, DatabaseConflict, PreconditionsException
+from CodernityDB.database import DatabaseException, RevConflict, DatabasePathException, DatabaseConflict, PreconditionsException, IndexConflict
 
-from CodernityDB.hash_index import HashIndex, UniqueHashIndex
-from CodernityDB.index import IndexException, TryReindexException, IndexNotFoundException, IndexPreconditionsException, IndexConflict
+from CodernityDB.hash_index import HashIndex, UniqueHashIndex, MultiHashIndex
+from CodernityDB.index import IndexException, TryReindexException, IndexNotFoundException, IndexPreconditionsException
 
-from CodernityDB.tree_index import TreeBasedIndex
+from CodernityDB.tree_index import TreeBasedIndex, MultiTreeBasedIndex
 
 from CodernityDB.debug_stuff import database_step_by_step
 
         return key
 
 
+class TreeMultiTest(MultiTreeBasedIndex):
+
+    custom_header = """from CodernityDB.tree_index import MultiTreeBasedIndex
+from itertools import izip"""
+
+    def __init__(self, *args, **kwargs):
+        kwargs['key_format'] = '16s'
+        super(TreeMultiTest, self).__init__(*args, **kwargs)
+        self.__l = kwargs.get('w_len', 2)
+
+    def make_key_value(self, data):
+        name = data['w']
+        l = self.__l
+        max_l = len(name)
+        out = set()
+        for x in xrange(l - 1, max_l):
+            m = (name, )
+            for y in xrange(0, x):
+                m += (name[y + 1:],)
+            out.update(set(''.join(x).rjust(16, '_').lower() for x in izip(*m)))  #ignore import error
+        return out, dict(name=name)
+
+    def make_key(self, key):
+        return key.rjust(16, '_').lower()
+
+
 class DB_Tests:
 
     def setup_method(self, method):
             db.add_index(CustomHashIndex(db.path, 'custom'))
         db.add_index(UniqueHashIndex(db.path, 'id'))
         db.add_index(CustomHashIndex(db.path, 'custom'))
+
+    def test_multi_index(self, tmpdir):
+        with open('tests/misc/words.txt', 'r') as f:
+            data = f.read().split()
+        words = map(lambda x: x.strip().replace('.', "").replace(',', ""), data)
+        db = self._db(os.path.join(str(tmpdir), 'db'))
+        db.create()
+        db.add_index(TreeMultiTest(db.path, 'words'))
+        for word in words:
+            db.insert(dict(w=word))
+        assert db.count(db.all, 'words') == 3245
+        assert db.get('words', 'Coder')['name'] == 'Codernity'
+        assert db.get('words', "dern")['name'] == "Codernity"
+        assert db.get('words', 'Codernity')['name'] == "Codernity"
+
+        u = db.get('words', 'Codernit', with_doc=True)
+        doc = u['doc']
+        doc['up'] = True
+        db.update(doc)
+        assert db.get('words', "dern")['name'] == "Codernity"
+
+        db.delete(doc)
+        with pytest.raises(RecordNotFound):
+            db.get('words', "Codern")