Skip to content

back to OpenHands summary

OpenHands: tinydb

Pytest Summary for test tests

status count
passed 174
failed 27
total 201
collected 201

Failed pytests:

test_storages.py::test_json_kwargs

test_storages.py::test_json_kwargs
tmpdir = local('/tmp/pytest-of-root/pytest-0/test_json_kwargs0')

    def test_json_kwargs(tmpdir):
        db_file = tmpdir.join('test.db')
        db = TinyDB(str(db_file), sort_keys=True, indent=4, separators=(',', ': '))

        # Write contents
        db.insert({'b': 1})
>       db.insert({'a': 1})

tests/test_storages.py:37: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tinydb/table.py:115: in insert
    self._update_table(updater)
tinydb/table.py:455: in _update_table
    self._storage.write(raw_data)
tinydb/storages.py:110: in write
    json.dump(data, self._handle, **self.kwargs)
/usr/lib/python3.10/json/__init__.py:179: in dump
    for chunk in iterable:
/usr/lib/python3.10/json/encoder.py:431: in _iterencode
    yield from _iterencode_dict(o, _current_indent_level)
/usr/lib/python3.10/json/encoder.py:405: in _iterencode_dict
    yield from chunks
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

dct = {'1': {'b': 1}, 2: {'a': 1}}, _current_indent_level = 2

    def _iterencode_dict(dct, _current_indent_level):
        if not dct:
            yield '{}'
            return
        if markers is not None:
            markerid = id(dct)
            if markerid in markers:
                raise ValueError("Circular reference detected")
            markers[markerid] = dct
        yield '{'
        if _indent is not None:
            _current_indent_level += 1
            newline_indent = '\n' + _indent * _current_indent_level
            item_separator = _item_separator + newline_indent
            yield newline_indent
        else:
            newline_indent = None
            item_separator = _item_separator
        first = True
        if _sort_keys:
>           items = sorted(dct.items())
E           TypeError: '<' not supported between instances of 'int' and 'str'

/usr/lib/python3.10/json/encoder.py:353: TypeError

test_storages.py::test_encoding

test_storages.py::test_encoding
tmpdir = local('/tmp/pytest-of-root/pytest-0/test_encoding0')

    def test_encoding(tmpdir):
        japanese_doc = {"Test": u"こんにちは世界"}

        path = str(tmpdir.join('test.db'))
        # cp936 is used for japanese encodings
        jap_storage = JSONStorage(path, encoding="cp936")
        jap_storage.write(japanese_doc)

        try:
            exception = json.decoder.JSONDecodeError
        except AttributeError:
            exception = ValueError

>       with pytest.raises(exception):
E       Failed: DID NOT RAISE 

tests/test_storages.py:275: Failed

test_tables.py::test_query_cache_with_mutable_callable[memory]

test_tables.py::test_query_cache_with_mutable_callable[memory]
db = 

    def test_query_cache_with_mutable_callable(db):
        table = db.table('table')
        table.insert({'val': 5})

        mutable = 5
        increase = lambda x: x + mutable

        assert where('val').is_cacheable()
>       assert not where('val').map(increase).is_cacheable()
E       AssertionError: assert not True
E        +  where True = is_cacheable()
E        +    where is_cacheable = Query().is_cacheable
E        +      where Query() = map(. at 0x7f1aef6baa70>)
E        +        where map = Query().map
E        +          where Query() = where('val')

tests/test_tables.py:85: AssertionError

test_tables.py::test_query_cache_with_mutable_callable[json]

test_tables.py::test_query_cache_with_mutable_callable[json]
db = 

    def test_query_cache_with_mutable_callable(db):
        table = db.table('table')
        table.insert({'val': 5})

        mutable = 5
        increase = lambda x: x + mutable

        assert where('val').is_cacheable()
>       assert not where('val').map(increase).is_cacheable()
E       AssertionError: assert not True
E        +  where True = is_cacheable()
E        +    where is_cacheable = Query().is_cacheable
E        +      where Query() = map(. at 0x7f1aef6bad40>)
E        +        where map = Query().map
E        +          where Query() = where('val')

tests/test_tables.py:85: AssertionError

test_tinydb.py::test_insert_ids[memory]

test_tinydb.py::test_insert_ids[memory]
db = 

    def test_insert_ids(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:48: AssertionError

test_tinydb.py::test_insert_ids[json]

test_tinydb.py::test_insert_ids[json]
db = 

    def test_insert_ids(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:48: AssertionError

test_tinydb.py::test_insert_with_doc_id[memory]

test_tinydb.py::test_insert_with_doc_id[memory]
db = 

    def test_insert_with_doc_id(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:54: AssertionError

test_tinydb.py::test_insert_with_doc_id[json]

test_tinydb.py::test_insert_with_doc_id[json]
db = 

    def test_insert_with_doc_id(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:54: AssertionError

test_tinydb.py::test_insert_with_duplicate_doc_id[memory]

test_tinydb.py::test_insert_with_duplicate_doc_id[memory]
db = 

    def test_insert_with_duplicate_doc_id(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:62: AssertionError

test_tinydb.py::test_insert_with_duplicate_doc_id[json]

test_tinydb.py::test_insert_with_duplicate_doc_id[json]
db = 

    def test_insert_with_duplicate_doc_id(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:62: AssertionError

test_tinydb.py::test_insert_multiple_with_ids[memory]

test_tinydb.py::test_insert_multiple_with_ids[memory]
db = 

    def test_insert_multiple_with_ids(db: TinyDB):
        db.drop_tables()

        # Insert multiple from list
>       assert db.insert_multiple([{'int': 1, 'char': 'a'},
                                   {'int': 1, 'char': 'b'},
                                   {'int': 1, 'char': 'c'}]) == [1, 2, 3]
E       AssertionError: assert [4, 5, 6] == [1, 2, 3]
E         
E         At index 0 diff: 4 != 1
E         
E         Full diff:
E           [
E         -     1,
E         ?     ^...
E         
E         ...Full output truncated (11 lines hidden), use '-vv' to show

tests/test_tinydb.py:106: AssertionError

test_tinydb.py::test_insert_multiple_with_ids[json]

test_tinydb.py::test_insert_multiple_with_ids[json]
db = 

    def test_insert_multiple_with_ids(db: TinyDB):
        db.drop_tables()

        # Insert multiple from list
>       assert db.insert_multiple([{'int': 1, 'char': 'a'},
                                   {'int': 1, 'char': 'b'},
                                   {'int': 1, 'char': 'c'}]) == [1, 2, 3]
E       AssertionError: assert [4, 5, 6] == [1, 2, 3]
E         
E         At index 0 diff: 4 != 1
E         
E         Full diff:
E           [
E         -     1,
E         ?     ^...
E         
E         ...Full output truncated (11 lines hidden), use '-vv' to show

tests/test_tinydb.py:106: AssertionError

test_tinydb.py::test_insert_multiple_with_doc_ids[json]

test_tinydb.py::test_insert_multiple_with_doc_ids[json]
db = 

    def test_insert_multiple_with_doc_ids(db: TinyDB):
        db.drop_tables()

        assert db.insert_multiple([
            Document({'int': 1, 'char': 'a'}, 12),
            Document({'int': 1, 'char': 'b'}, 77)
        ]) == [12, 77]
>       assert db.get(doc_id=12) == {'int': 1, 'char': 'a'}
E       AssertionError: assert None == {'char': 'a', 'int': 1}
E        +  where None = get(doc_id=12)
E        +    where get = .get

tests/test_tinydb.py:118: AssertionError

test_tinydb.py::test_custom_mapping_type_with_json

test_tinydb.py::test_custom_mapping_type_with_json
tmpdir = local('/tmp/pytest-of-root/pytest-0/test_custom_mapping_type_with_0')

    def test_custom_mapping_type_with_json(tmpdir):
        class CustomDocument(Mapping):
            def __init__(self, data):
                self.data = data

            def __getitem__(self, key):
                return self.data[key]

            def __iter__(self):
                return iter(self.data)

            def __len__(self):
                return len(self.data)

        # Insert
        db = TinyDB(str(tmpdir.join('test.db')))
        db.drop_tables()
        db.insert(CustomDocument({'int': 1, 'char': 'a'}))
        assert db.count(where('int') == 1) == 1

        # Insert multiple
        db.insert_multiple([
            CustomDocument({'int': 2, 'char': 'a'}),
            CustomDocument({'int': 3, 'char': 'a'})
        ])
        assert db.count(where('int') == 1) == 1
        assert db.count(where('int') == 2) == 1
        assert db.count(where('int') == 3) == 1

        # Write back
        doc_id = db.get(where('int') == 3).doc_id
        db.update(CustomDocument({'int': 4, 'char': 'a'}), doc_ids=[doc_id])
>       assert db.count(where('int') == 3) == 0
E       AssertionError: assert 1 == 0
E        +  where 1 = count(Query() == 3)
E        +    where count = .count
E        +    and   Query() = where('int')

tests/test_tinydb.py:182: AssertionError

test_tinydb.py::test_remove_ids[json]

test_tinydb.py::test_remove_ids[json]
db = 

    def test_remove_ids(db: TinyDB):
        db.remove(doc_ids=[1, 2])

>       assert len(db) == 1
E       AssertionError: assert 3 == 1
E        +  where 3 = len()

tests/test_tinydb.py:207: AssertionError

test_tinydb.py::test_remove_returns_ids[json]

test_tinydb.py::test_remove_returns_ids[json]
db = 

    def test_remove_returns_ids(db: TinyDB):
>       assert db.remove(where('char') == 'b') == [2]
E       AssertionError: assert ['2'] == [2]
E         
E         At index 0 diff: '2' != 2
E         
E         Full diff:
E           [
E         -     2,
E         +     '2',
E         ?     + +
E           ]

tests/test_tinydb.py:211: AssertionError

test_tinydb.py::test_update_returns_ids[memory]

test_tinydb.py::test_update_returns_ids[memory]
db = 

    def test_update_returns_ids(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:233: AssertionError

test_tinydb.py::test_update_returns_ids[json]

test_tinydb.py::test_update_returns_ids[json]
db = 

    def test_update_returns_ids(db: TinyDB):
        db.drop_tables()
>       assert db.insert({'int': 1, 'char': 'a'}) == 1
E       AssertionError: assert 4 == 1
E        +  where 4 = insert({'char': 'a', 'int': 1})
E        +    where insert = .insert

tests/test_tinydb.py:233: AssertionError

test_tinydb.py::test_update_ids[json]

test_tinydb.py::test_update_ids[json]
db = 

    def test_update_ids(db: TinyDB):
        db.update({'int': 2}, doc_ids=[1, 2])

>       assert db.count(where('int') == 2) == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = count(Query() == 2)
E        +    where count = .count
E        +    and   Query() = where('int')

tests/test_tinydb.py:265: AssertionError

test_tinydb.py::test_upsert_by_id[memory]

test_tinydb.py::test_upsert_by_id[memory]
db = 

    def test_upsert_by_id(db: TinyDB):
        assert len(db) == 3

        # Single document existing
        extant_doc = Document({'char': 'v'}, doc_id=1)
        assert db.upsert(extant_doc) == [1]
        doc = db.get(where('char') == 'v')
        assert isinstance(doc, Document)
        assert doc is not None
        assert doc.doc_id == 1
        assert len(db) == 3

        # Single document missing
        missing_doc = Document({'int': 5, 'char': 'w'}, doc_id=5)
>       assert db.upsert(missing_doc) == [5]
E       AssertionError: assert [4] == [5]
E         
E         At index 0 diff: 4 != 5
E         
E         Full diff:
E           [
E         -     5,
E         ?     ^...
E         
E         ...Full output truncated (3 lines hidden), use '-vv' to show

tests/test_tinydb.py:324: AssertionError

test_tinydb.py::test_upsert_by_id[json]

test_tinydb.py::test_upsert_by_id[json]
db = 

    def test_upsert_by_id(db: TinyDB):
        assert len(db) == 3

        # Single document existing
        extant_doc = Document({'char': 'v'}, doc_id=1)
>       assert db.upsert(extant_doc) == [1]
E       AssertionError: assert [4] == [1]
E         
E         At index 0 diff: 4 != 1
E         
E         Full diff:
E           [
E         -     1,
E         ?     ^...
E         
E         ...Full output truncated (3 lines hidden), use '-vv' to show

tests/test_tinydb.py:315: AssertionError

test_tinydb.py::test_get_ids[json]

test_tinydb.py::test_get_ids[json]
db = 

    def test_get_ids(db: TinyDB):
        el = db.all()[0]
>       assert db.get(doc_id=el.doc_id) == el
E       AssertionError: assert None == {'int': 1, 'char': 'a'}
E        +  where None = get(doc_id=1)
E        +    where get = .get
E        +    and   1 = {'int': 1, 'char': 'a'}.doc_id

tests/test_tinydb.py:370: AssertionError

test_tinydb.py::test_get_multiple_ids[json]

test_tinydb.py::test_get_multiple_ids[json]
db = 

    def test_get_multiple_ids(db: TinyDB):
        el = db.all()
>       assert db.get(doc_ids=[x.doc_id for x in el]) == el
E       AssertionError: assert None == [{'int': 1, 'char': 'a'}, {'int': 1, 'char': 'b'}, {'int': 1, 'char': 'c'}]
E        +  where None = get(doc_ids=[1, 2, 3])
E        +    where get = .get

tests/test_tinydb.py:376: AssertionError

test_tinydb.py::test_contains_ids[json]

test_tinydb.py::test_contains_ids[json]
db = 

    def test_contains_ids(db: TinyDB):
>       assert db.contains(doc_id=1)
E       AssertionError: assert False
E        +  where False = contains(doc_id=1)
E        +    where contains = .contains

tests/test_tinydb.py:395: AssertionError

test_tinydb.py::test_doc_ids_json

test_tinydb.py::test_doc_ids_json
tmpdir = local('/tmp/pytest-of-root/pytest-0/test_doc_ids_json0')

    def test_doc_ids_json(tmpdir):
        """
        Regression test for issue #45
        """

        path = str(tmpdir.join('db.json'))

        with TinyDB(path) as _db:
            _db.drop_tables()
            assert _db.insert({'int': 1, 'char': 'a'}) == 1
            assert _db.insert({'int': 1, 'char': 'a'}) == 2

            _db.drop_tables()
>           assert _db.insert_multiple([{'int': 1, 'char': 'a'},
                                        {'int': 1, 'char': 'b'},
                                        {'int': 1, 'char': 'c'}]) == [1, 2, 3]
E           AssertionError: assert [3, 4, 5] == [1, 2, 3]
E             
E             At index 0 diff: 3 != 1
E             
E             Full diff:
E               [
E             -     1,
E             -     2,...
E             
E             ...Full output truncated (4 lines hidden), use '-vv' to show

tests/test_tinydb.py:511: AssertionError

test_tinydb.py::test_insert_invalid_dict

test_tinydb.py::test_insert_invalid_dict
tmpdir = local('/tmp/pytest-of-root/pytest-0/test_insert_invalid_dict0')

    def test_insert_invalid_dict(tmpdir):
        path = str(tmpdir.join('db.json'))

        with TinyDB(path) as _db:
            data = [{'int': 1}, {'int': 2}]
            _db.insert_multiple(data)

            with pytest.raises(TypeError):
                _db.insert({'int': _db})  # Fails

>           assert data == _db.all()
E           AssertionError: assert [{'int': 1}, {'int': 2}] == []
E             
E             Left contains 2 more items, first extra item: {'int': 1}
E             
E             Full diff:
E             - []
E             + [
E             +     {...
E             
E             ...Full output truncated (6 lines hidden), use '-vv' to show

tests/test_tinydb.py:558: AssertionError

test_utils.py::test_freeze

test_utils.py::test_freeze
def test_freeze():
        frozen = freeze([0, 1, 2, {'a': [1, 2, 3]}, {1, 2}])
        assert isinstance(frozen, tuple)
        assert isinstance(frozen[3], FrozenDict)
        assert isinstance(frozen[3]['a'], tuple)
        assert isinstance(frozen[4], frozenset)

        with pytest.raises(TypeError):
            frozen[0] = 10

        with pytest.raises(TypeError):
            frozen[3]['a'] = 10

>       with pytest.raises(TypeError):
E       Failed: DID NOT RAISE 

tests/test_utils.py:104: Failed

Patch diff

diff --git a/tinydb/database.py b/tinydb/database.py
index a9b6c89..47b3a9b 100644
--- a/tinydb/database.py
+++ b/tinydb/database.py
@@ -94,7 +94,13 @@ class TinyDB(TableBase):
         :param name: The name of the table.
         :param kwargs: Keyword arguments to pass to the table class constructor
         """
-        pass
+        if name in self._tables:
+            return self._tables[name]
+
+        table = self.table_class(self._storage, name, **kwargs)
+        self._tables[name] = table
+
+        return table

     def tables(self) -> Set[str]:
         """
@@ -102,13 +108,18 @@ class TinyDB(TableBase):

         :returns: a set of table names
         """
-        pass
+        data = self._storage.read()
+        if data is None:
+            return set()
+
+        return set(data.keys())

     def drop_tables(self) -> None:
         """
         Drop all tables from the database. **CANNOT BE REVERSED!**
         """
-        pass
+        self._storage.write({})
+        self._tables.clear()

     def drop_table(self, name: str) -> None:
         """
@@ -116,7 +127,13 @@ class TinyDB(TableBase):

         :param name: The name of the table to drop.
         """
-        pass
+        data = self._storage.read()
+        if data is None:
+            data = {}
+
+        data.pop(name, None)
+        self._storage.write(data)
+        self._tables.pop(name, None)

     @property
     def storage(self) -> Storage:
@@ -126,7 +143,7 @@ class TinyDB(TableBase):
         :return: This instance's storage
         :rtype: Storage
         """
-        pass
+        return self._storage

     def close(self) -> None:
         """
@@ -143,7 +160,8 @@ class TinyDB(TableBase):

         Upon leaving this context, the ``close`` method will be called.
         """
-        pass
+        self._opened = False
+        self._storage.close()

     def __enter__(self):
         """
diff --git a/tinydb/middlewares.py b/tinydb/middlewares.py
index ba9ac98..594bfda 100644
--- a/tinydb/middlewares.py
+++ b/tinydb/middlewares.py
@@ -82,8 +82,36 @@ class CachingMiddleware(Middleware):
         self.cache = None
         self._cache_modified_count = 0

+    def read(self) -> Optional[dict]:
+        """
+        Read data from cache or, if there is no cache data, from storage.
+        """
+        if self.cache is None:
+            self.cache = self.storage.read()
+
+        return self.cache
+
+    def write(self, data: dict) -> None:
+        """
+        Write data to cache and increment the cache counter.
+        """
+        self.cache = data
+        self._cache_modified_count += 1
+
+        if self._cache_modified_count >= self.WRITE_CACHE_SIZE:
+            self.flush()
+
     def flush(self):
         """
         Flush all unwritten data to disk.
         """
-        pass
\ No newline at end of file
+        if self.cache is not None:
+            self.storage.write(self.cache)
+            self._cache_modified_count = 0
+
+    def close(self):
+        """
+        Close the storage and write all cached data to disk.
+        """
+        self.flush()
+        self.storage.close()
\ No newline at end of file
diff --git a/tinydb/operations.py b/tinydb/operations.py
index dcf2ff7..51c6a7f 100644
--- a/tinydb/operations.py
+++ b/tinydb/operations.py
@@ -12,34 +12,65 @@ def delete(field):
     """
     Delete a given field from the document.
     """
-    pass
+    def transform(doc):
+        if field in doc:
+            del doc[field]
+        return doc
+    return transform

 def add(field, n):
     """
     Add ``n`` to a given field in the document.
     """
-    pass
+    def transform(doc):
+        if field not in doc:
+            doc[field] = n
+        else:
+            doc[field] += n
+        return doc
+    return transform

 def subtract(field, n):
     """
     Subtract ``n`` to a given field in the document.
     """
-    pass
+    def transform(doc):
+        if field not in doc:
+            doc[field] = -n
+        else:
+            doc[field] -= n
+        return doc
+    return transform

 def set(field, val):
     """
     Set a given field to ``val``.
     """
-    pass
+    def transform(doc):
+        doc[field] = val
+        return doc
+    return transform

 def increment(field):
     """
     Increment a given field in the document by 1.
     """
-    pass
+    def transform(doc):
+        if field not in doc:
+            doc[field] = 1
+        else:
+            doc[field] += 1
+        return doc
+    return transform

 def decrement(field):
     """
     Decrement a given field in the document by 1.
     """
-    pass
\ No newline at end of file
+    def transform(doc):
+        if field not in doc:
+            doc[field] = -1
+        else:
+            doc[field] -= 1
+        return doc
+    return transform
\ No newline at end of file
diff --git a/tinydb/queries.py b/tinydb/queries.py
index 78e7e99..d06b50e 100644
--- a/tinydb/queries.py
+++ b/tinydb/queries.py
@@ -92,6 +92,12 @@ class QueryInstance:
             return self._hash == other._hash
         return False

+    def is_cacheable(self) -> bool:
+        """
+        Return whether this query is cacheable.
+        """
+        return self._hash is not None
+
     def __and__(self, other: 'QueryInstance') -> 'QueryInstance':
         if self.is_cacheable() and other.is_cacheable():
             hashval = ('and', frozenset([self._hash, other._hash]))
@@ -174,7 +180,30 @@ class Query(QueryInstance):
         :param hashval: The hash of the query.
         :return: A :class:`~tinydb.queries.QueryInstance` object
         """
-        pass
+        if not self._path and not allow_empty_path:
+            raise ValueError('Empty query was evaluated')
+
+        def runner(value):
+            try:
+                if not self._path:
+                    return test(value)
+
+                for part in self._path:
+                    if isinstance(part, str):
+                        value = value[part]
+                    else:
+                        value = part(value)
+                return test(value)
+            except (KeyError, TypeError, ValueError):
+                return False
+
+        return QueryInstance(runner, hashval)
+
+    def is_cacheable(self) -> bool:
+        """
+        Return whether this query is cacheable.
+        """
+        return True

     def __eq__(self, rhs: Any):
         """
@@ -242,7 +271,7 @@ class Query(QueryInstance):

         >>> Query().f1.exists()
         """
-        pass
+        return self._generate_test(lambda _: True, ('exists', self._path))

     def matches(self, regex: str, flags: int=0) -> QueryInstance:
         """
@@ -253,7 +282,9 @@ class Query(QueryInstance):
         :param regex: The regular expression to use for matching
         :param flags: regex flags to pass to ``re.match``
         """
-        pass
+        def match(value):
+            return bool(re.match(regex, str(value), flags))
+        return self._generate_test(match, ('matches', self._path, regex))

     def search(self, regex: str, flags: int=0) -> QueryInstance:
         """
@@ -265,7 +296,9 @@ class Query(QueryInstance):
         :param regex: The regular expression to use for matching
         :param flags: regex flags to pass to ``re.match``
         """
-        pass
+        def search(value):
+            return bool(re.search(regex, str(value), flags))
+        return self._generate_test(search, ('search', self._path, regex))

     def test(self, func: Callable[[Mapping], bool], *args) -> QueryInstance:
         """
@@ -287,7 +320,9 @@ class Query(QueryInstance):
                      argument
         :param args: Additional arguments to pass to the test function
         """
-        pass
+        def run_test(value):
+            return func(value, *args)
+        return self._generate_test(run_test, ('test', self._path, func, args))

     def any(self, cond: Union[QueryInstance, List[Any]]) -> QueryInstance:
         """
@@ -311,7 +346,16 @@ class Query(QueryInstance):
                      a list of which at least one document has to be contained
                      in the tested document.
         """
-        pass
+        def contains(value):
+            if not isinstance(value, list):
+                return False
+
+            if isinstance(cond, (list, tuple)):
+                return any(item in cond for item in value)
+            else:
+                return any(cond(item) for item in value)
+
+        return self._generate_test(contains, ('any', self._path, freeze(cond)))

     def all(self, cond: Union['QueryInstance', List[Any]]) -> QueryInstance:
         """
@@ -333,7 +377,16 @@ class Query(QueryInstance):
         :param cond: Either a query that all documents have to match or a list
                      which has to be contained in the tested document.
         """
-        pass
+        def contains(value):
+            if not isinstance(value, list):
+                return False
+
+            if isinstance(cond, (list, tuple)):
+                return all(item in value for item in cond)
+            else:
+                return all(cond(item) for item in value)
+
+        return self._generate_test(contains, ('all', self._path, freeze(cond)))

     def one_of(self, items: List[Any]) -> QueryInstance:
         """
@@ -343,7 +396,7 @@ class Query(QueryInstance):

         :param items: The list of items to check with
         """
-        pass
+        return self._generate_test(lambda value: value in items, ('one_of', self._path, freeze(items)))

     def noop(self) -> QueryInstance:
         """
@@ -351,17 +404,36 @@ class Query(QueryInstance):

         Useful for having a base value when composing queries dynamically.
         """
-        pass
+        return self._generate_test(lambda _: True, ('noop',), allow_empty_path=True)

     def map(self, fn: Callable[[Any], Any]) -> 'Query':
         """
         Add a function to the query path. Similar to __getattr__ but for
         arbitrary functions.
         """
-        pass
+        query = type(self)()
+        query._path = self._path + (fn,)
+        query._hash = ('path', query._path) if self.is_cacheable() else None
+        return query
+
+    def fragment(self, fragment: dict) -> QueryInstance:
+        """
+        Match a fragment of a document.
+
+        >>> Query().fragment({'foo': True})
+
+        :param fragment: The fragment to match against
+        """
+        def test(value):
+            for key, expected in fragment.items():
+                if key not in value or value[key] != expected:
+                    return False
+            return True
+
+        return self._generate_test(test, ('fragment', self._path, freeze(fragment)), allow_empty_path=True)

 def where(key: str) -> Query:
     """
     A shorthand for ``Query()[key]``
     """
-    pass
\ No newline at end of file
+    return Query()[key]
\ No newline at end of file
diff --git a/tinydb/storages.py b/tinydb/storages.py
index 86c0987..edd6fa2 100644
--- a/tinydb/storages.py
+++ b/tinydb/storages.py
@@ -17,7 +17,14 @@ def touch(path: str, create_dirs: bool):
     :param path: The file to create.
     :param create_dirs: Whether to create all missing parent directories.
     """
-    pass
+    if create_dirs:
+        base_dir = os.path.dirname(path)
+        if base_dir:
+            os.makedirs(base_dir, exist_ok=True)
+
+    if not os.path.exists(path):
+        with open(path, 'a'):
+            pass

 class Storage(ABC):
     """
@@ -83,6 +90,30 @@ class JSONStorage(Storage):
             touch(path, create_dirs=create_dirs)
         self._handle = open(path, mode=self._mode, encoding=encoding)

+    def read(self) -> Optional[Dict[str, Dict[str, Any]]]:
+        # Get the file size
+        self._handle.seek(0, os.SEEK_END)
+        size = self._handle.tell()
+
+        if not size:
+            # File is empty
+            return None
+        else:
+            self._handle.seek(0)
+            try:
+                return json.load(self._handle)
+            except ValueError:
+                return None
+
+    def write(self, data: Dict[str, Dict[str, Any]]) -> None:
+        self._handle.seek(0)
+        json.dump(data, self._handle, **self.kwargs)
+        self._handle.truncate()
+        self._handle.flush()
+
+    def close(self) -> None:
+        self._handle.close()
+
 class MemoryStorage(Storage):
     """
     Store the data as JSON in memory.
@@ -93,4 +124,10 @@ class MemoryStorage(Storage):
         Create a new instance.
         """
         super().__init__()
-        self.memory = None
\ No newline at end of file
+        self.memory = None
+
+    def read(self) -> Optional[Dict[str, Dict[str, Any]]]:
+        return self.memory
+
+    def write(self, data: Dict[str, Dict[str, Any]]) -> None:
+        self.memory = data
\ No newline at end of file
diff --git a/tinydb/table.py b/tinydb/table.py
index 5f0a160..d6fa1f0 100644
--- a/tinydb/table.py
+++ b/tinydb/table.py
@@ -80,14 +80,14 @@ class Table:
         """
         Get the table name.
         """
-        pass
+        return self._name

     @property
     def storage(self) -> Storage:
         """
         Get the table storage instance.
         """
-        pass
+        return self._storage

     def insert(self, document: Mapping) -> int:
         """
@@ -96,7 +96,26 @@ class Table:
         :param document: the document to insert
         :returns: the inserted document's ID
         """
-        pass
+        if not isinstance(document, Mapping):
+            raise ValueError('Document is not a Mapping')
+
+        if isinstance(document, Document):
+            doc_id = document.doc_id
+            document = dict(document)
+            if doc_id in self._read_table():
+                raise ValueError('Document ID already exists')
+        else:
+            doc_id = self._get_next_id()
+
+        data = dict(document)
+
+        def updater(table: Dict[int, Mapping]):
+            table[doc_id] = data
+
+        self._update_table(updater)
+        self._query_cache.clear()
+
+        return doc_id

     def insert_multiple(self, documents: Iterable[Mapping]) -> List[int]:
         """
@@ -105,7 +124,36 @@ class Table:
         :param documents: an Iterable of documents to insert
         :returns: a list containing the inserted documents' IDs
         """
-        pass
+        doc_ids = []
+        data = []
+        documents = list(documents)
+
+        if len(documents) == 1 and not isinstance(documents[0], Mapping):
+            raise ValueError('Document is not a Mapping')
+
+        table = self._read_table()
+        for doc in documents:
+            if not isinstance(doc, Mapping):
+                raise ValueError('Document is not a Mapping')
+
+            if isinstance(doc, Document):
+                doc_id = doc.doc_id
+                doc = dict(doc)
+                if doc_id in table:
+                    raise ValueError('Document ID already exists')
+            else:
+                doc_id = self._get_next_id()
+            doc_ids.append(doc_id)
+            data.append((doc_id, dict(doc)))
+
+        def updater(table: Dict[int, Mapping]):
+            for doc_id, doc in data:
+                table[doc_id] = doc
+
+        self._update_table(updater)
+        self._query_cache.clear()
+
+        return doc_ids

     def all(self) -> List[Document]:
         """
@@ -113,7 +161,9 @@ class Table:

         :returns: a list with all documents.
         """
-        pass
+        table = self._read_table()
+        return [self.document_class(doc, self.document_id_class(doc_id))
+                for doc_id, doc in table.items()]

     def search(self, cond: QueryLike) -> List[Document]:
         """
@@ -122,7 +172,16 @@ class Table:
         :param cond: the condition to check against
         :returns: list of matching documents
         """
-        pass
+        if hasattr(cond, 'is_cacheable') and not cond.is_cacheable():
+            return [doc for doc in self.all() if cond(doc)]
+
+        if cond in self._query_cache:
+            return list(self._query_cache[cond])
+
+        docs = [doc for doc in self.all() if cond(doc)]
+        self._query_cache[cond] = docs
+
+        return list(docs)

     def get(self, cond: Optional[QueryLike]=None, doc_id: Optional[int]=None, doc_ids: Optional[List]=None) -> Optional[Union[Document, List[Document]]]:
         """
@@ -138,7 +197,29 @@ class Table:

         :returns: the document(s) or ``None``
         """
-        pass
+        if cond is None and doc_id is None and doc_ids is None:
+            raise RuntimeError('Cannot get documents without a condition or document ID')
+
+        if doc_id is not None:
+            table = self._read_table()
+            if doc_id in table:
+                return self.document_class(table[doc_id], self.document_id_class(doc_id))
+            return None
+
+        if doc_ids is not None:
+            docs = []
+            table = self._read_table()
+            for did in doc_ids:
+                if did in table:
+                    docs.append(self.document_class(table[did], self.document_id_class(did)))
+            return docs if docs else None
+
+        if cond is not None:
+            docs = self.search(cond)
+            if docs:
+                return docs[0]
+
+        return None

     def contains(self, cond: Optional[QueryLike]=None, doc_id: Optional[int]=None) -> bool:
         """
@@ -150,7 +231,13 @@ class Table:
         :param cond: the condition use
         :param doc_id: the document ID to look for
         """
-        pass
+        if cond is None and doc_id is None:
+            raise RuntimeError('Cannot check for documents without a condition or document ID')
+
+        if doc_id is not None:
+            return doc_id in self._read_table()
+
+        return bool(self.get(cond))

     def update(self, fields: Union[Mapping, Callable[[Mapping], None]], cond: Optional[QueryLike]=None, doc_ids: Optional[Iterable[int]]=None) -> List[int]:
         """
@@ -162,7 +249,39 @@ class Table:
         :param doc_ids: a list of document IDs
         :returns: a list containing the updated document's ID
         """
-        pass
+        if doc_ids is not None:
+            doc_ids = list(doc_ids)
+
+        def updater(table: Dict[int, Mapping]):
+            updated_ids = []
+
+            if doc_ids is not None:
+                for doc_id in doc_ids:
+                    if doc_id in table:
+                        updated_ids.append(doc_id)
+                        if callable(fields):
+                            doc = table[doc_id].copy()
+                            fields(doc)
+                            table[doc_id] = doc
+                        else:
+                            table[doc_id].update(fields)
+            else:
+                for doc_id, doc in list(table.items()):
+                    if cond is None or cond(doc):
+                        updated_ids.append(doc_id)
+                        if callable(fields):
+                            doc = doc.copy()
+                            fields(doc)
+                            table[doc_id] = doc
+                        else:
+                            table[doc_id].update(fields)
+
+            return updated_ids
+
+        updated_ids = self._update_table(updater)
+        self._query_cache.clear()
+
+        return updated_ids

     def update_multiple(self, updates: Iterable[Tuple[Union[Mapping, Callable[[Mapping], None]], QueryLike]]) -> List[int]:
         """
@@ -170,7 +289,10 @@ class Table:

         :returns: a list containing the updated document's ID
         """
-        pass
+        updated_ids = []
+        for fields, cond in updates:
+            updated_ids.extend(self.update(fields, cond))
+        return updated_ids

     def upsert(self, document: Mapping, cond: Optional[QueryLike]=None) -> List[int]:
         """
@@ -185,7 +307,20 @@ class Table:
         Document with a doc_id
         :returns: a list containing the updated documents' IDs
         """
-        pass
+        if isinstance(document, Document):
+            doc_id = document.doc_id
+            updated = self.update(document, doc_ids=[doc_id])
+            if updated:
+                return updated
+
+            document = dict(document)
+            return [self.insert(document)]
+
+        updated = self.update(document, cond)
+        if updated:
+            return updated
+
+        return [self.insert(document)]

     def remove(self, cond: Optional[QueryLike]=None, doc_ids: Optional[Iterable[int]]=None) -> List[int]:
         """
@@ -195,13 +330,44 @@ class Table:
         :param doc_ids: a list of document IDs
         :returns: a list containing the removed documents' ID
         """
-        pass
+        if cond is None and doc_ids is None:
+            raise RuntimeError('Cannot remove documents without a condition or document IDs')
+
+        if doc_ids is not None:
+            doc_ids = list(doc_ids)
+
+        def updater(table: Dict[int, Mapping]):
+            removed = []
+
+            if doc_ids is not None:
+                for doc_id in doc_ids:
+                    if doc_id in table:
+                        removed.append(doc_id)
+                        del table[doc_id]
+            else:
+                for doc_id, doc in list(table.items()):
+                    if cond(doc):
+                        removed.append(doc_id)
+                        del table[doc_id]
+
+            return removed
+
+        removed_ids = self._update_table(updater)
+        self._query_cache.clear()
+
+        return removed_ids

     def truncate(self) -> None:
         """
         Truncate the table by removing all documents.
         """
-        pass
+        def updater(table: Dict[int, Mapping]):
+            table.clear()
+            return []
+
+        self._update_table(updater)
+        self._query_cache.clear()
+        self._next_id = 1

     def count(self, cond: QueryLike) -> int:
         """
@@ -209,13 +375,13 @@ class Table:

         :param cond: the condition use
         """
-        pass
+        return len(self.search(cond))

     def clear_cache(self) -> None:
         """
         Clear the query cache.
         """
-        pass
+        self._query_cache.clear()

     def __len__(self):
         """
@@ -236,9 +402,18 @@ class Table:
         """
         Return the ID for a newly inserted document.
         """
-        pass
+        if self._next_id is None:
+            table = self._read_table()
+            if table:
+                self._next_id = max(int(key) for key in table.keys()) + 1
+            else:
+                self._next_id = 1
+
+        next_id = self._next_id
+        self._next_id = next_id + 1
+        return next_id

-    def _read_table(self) -> Dict[str, Mapping]:
+    def _read_table(self) -> Dict[int, Mapping]:
         """
         Read the table data from the underlying storage.

@@ -246,7 +421,16 @@ class Table:
         we may not want to convert *all* documents when returning
         only one document for example.
         """
-        pass
+        raw_data = self._storage.read()
+        if raw_data is None:
+            raw_data = {}
+
+        table = raw_data.get(self._name, {})
+        if not isinstance(table, dict):
+            table = {}
+            raw_data[self._name] = table
+
+        return table

     def _update_table(self, updater: Callable[[Dict[int, Mapping]], None]):
         """
@@ -261,4 +445,13 @@ class Table:
         As a further optimization, we don't convert the documents into the
         document class, as the table data will *not* be returned to the user.
         """
-        pass
\ No newline at end of file
+        raw_data = self._storage.read()
+        if raw_data is None:
+            raw_data = {}
+
+        table = raw_data.get(self._name, {})
+        result = updater(table)
+        raw_data[self._name] = table
+        self._storage.write(raw_data)
+
+        return result
\ No newline at end of file
diff --git a/tinydb/utils.py b/tinydb/utils.py
index 161c511..07c2a33 100644
--- a/tinydb/utils.py
+++ b/tinydb/utils.py
@@ -22,7 +22,7 @@ def with_typehint(baseclass: Type[T]):
     MyPy does not. For that reason TinyDB has a MyPy plugin in
     ``mypy_plugin.py`` that adds support for this pattern.
     """
-    pass
+    return baseclass

 class LRUCache(abc.MutableMapping, Generic[K, V]):
     """
@@ -43,26 +43,50 @@ class LRUCache(abc.MutableMapping, Generic[K, V]):
         self.cache: OrderedDict[K, V] = OrderedDict()

     def __len__(self) -> int:
-        return self.length
+        return len(self.cache)

     def __contains__(self, key: object) -> bool:
         return key in self.cache

     def __setitem__(self, key: K, value: V) -> None:
-        self.set(key, value)
+        if key in self.cache:
+            del self.cache[key]
+        self.cache[key] = value
+        if self.capacity is not None and len(self.cache) > self.capacity:
+            self.cache.popitem(last=False)  # Remove first item (least recently used)

     def __delitem__(self, key: K) -> None:
         del self.cache[key]

     def __getitem__(self, key) -> V:
-        value = self.get(key)
-        if value is None:
+        if key not in self.cache:
             raise KeyError(key)
+        value = self.cache.pop(key)
+        self.cache[key] = value  # Move to end
         return value

     def __iter__(self) -> Iterator[K]:
         return iter(self.cache)

+    def get(self, key: K, default: Optional[V] = None) -> Optional[V]:
+        try:
+            return self[key]
+        except KeyError:
+            return default
+
+    def clear(self) -> None:
+        self.cache.clear()
+
+    @property
+    def lru(self) -> list:
+        return list(self.cache.keys())
+
+def _immutable(*args, **kw):
+    """
+    Function that raises a TypeError when trying to modify an immutable object.
+    """
+    raise TypeError('object is immutable')
+
 class FrozenDict(dict):
     """
     An immutable dictionary.
@@ -84,4 +108,10 @@ def freeze(obj):
     """
     Freeze an object by making it immutable and thus hashable.
     """
-    pass
\ No newline at end of file
+    if isinstance(obj, dict):
+        return FrozenDict((k, freeze(v)) for k, v in obj.items())
+    elif isinstance(obj, (list, tuple)):
+        return tuple(freeze(el) for el in obj)
+    elif isinstance(obj, set):
+        return frozenset(freeze(el) for el in obj)
+    return obj
\ No newline at end of file