.. _TDB:


.. currentmodule:: tokyo.cabinet


===============================
Table Database --- :class:`TDB`
===============================

    .. versionadded:: 0.4.0


:class:`TDB`
============

.. class:: TDB

    Example::

        from tokyo.cabinet import *

        tdb = TDB()

        # if need be, you should call tune/setcache/setxmsiz/setdfunit before
        # open, ex. with default values:
        tdb.tune(0, -1, -1, 0)
        tdb.setcache(0, 0, 0)
        tdb.setxmsiz(0)
        tdb.setdfunit(0)

        # open the database
        tdb.open("casket.tct", TDBOWRITER | TDBOCREAT)

        # store records
        for key, value in [
                           ("foo", {"age": "30", "name": "John", "sex": "m"}),
                           ("bar", {"age": "56", "name": "Paul", "sex": "m"}),
                           ("baz", {"age": "22", "name": "Ella", "sex": "f"})
                          ]:
            tdb[key] = value

        # retrieve one record
        print(tdb["foo"])

        # traverse records
        for key in tdb:
            print(key, tdb[key])

        # close the database
        tdb.close()

    .. note::
        For all methods taking either a *key* argument or a pair *(key, value)*,
        *key* must be either :class:`str` (Python2) or :class:`bytes` (Python3)
        and *value* must be a :class:`dict`.

        All items in *value* must be pairs of :class:`str` (Python2) or
        :class:`bytes` (Python3). Empty keys in *value* **are not allowed**.

    .. seealso::
        `The Table Database API
        <http://1978th.net/tokyocabinet/spex-en.html#tctdbapi>`_


    .. describe:: len(tdb)

        Return the number of records in the database *tdb*.


    .. describe:: tdb[key]

        Return the value of *tdb*'s record corresponding to *key*. Raises
        :exc:`KeyError` if *key* is not in the database.


    .. describe:: tdb[key] = value

        Set ``tdb[key]`` to *value*.


    .. describe:: del tdb[key]

        Remove ``tdb[key]`` from *tdb*.  Raises :exc:`KeyError` if *key* is not
        in the database.


    .. describe:: key in tdb

        Return ``True`` if *tdb* has a key *key*, else ``False``.


    .. describe:: key not in tdb

        Equivalent to ``not key in tdb``.


    .. describe:: iter(tdb)

        Return an iterator over the keys of the database.


    .. method:: tune(bnum, apow, fpow, opts)

        Tune a database.

        :param bnum: the number of elements in a bucket array. If specified as
            0 or as a negative value, the default value (131071) is used.
        :param apow: (power of 2) TODO. If specified as a negative value, the
            default value (4) is used (means: 2**4).
        :param fpow: (power of 2) TODO. If specified as a negative value, the
            default value (10) is used (means 2**10).
        :param opts: options, see `TDB.tune()/TDB.optimize() options`_.

        .. note::
            Tuning an open database is an invalid operation.


    .. method:: setcache(rcnum, lcnum, ncnum)

        Set the cache size.

        :param rcnum: the maximum number of records to be cached. If specified
            as 0 or as a negative value, caching is disabled (default).
        :param lcnum: the maximum number of leaf nodes to be cached. If
            specified as 0 or as a negative value, the default value (4096) is
            used (for indexes).
        :param ncnum: the maximum number of non-leaf nodes to be cached. If
            specified as 0 or as a negative value, the default value (512) is
            used (for indexes).

        .. note::
            Setting the cache size on an open database is an invalid operation.


    .. method:: setxmsiz(xmsiz)

        Set the extra mapped memory size.

        :param xmsiz: the amount of extra mapped memory (in what unit?). If
            specified as 0 or as a negative value, the extra mapped memory is
            disabled. Default is 67108864 (unit?).

        .. note::
            Setting the extra memory size on an open database is an invalid
            operation.


    .. method:: setdfunit(dfunit)

        Set auto defragmentation's unit step number.

        :param dfunit: the unit step number(?). If specified as 0 or as a
            negative value, auto defragmentation is disabled (default).

        .. note::
            Setting this on an open database is an invalid operation.


    .. method:: open(path, mode)

        Open a database.

        :param path: path to the database file.
        :param mode: mode, see `TDB.open() modes`_


    .. method:: close

        Close the database.

        .. note::
            TDBs are closed when garbage-collected.


    .. method:: clear

        Remove all records from the database.


    .. method:: copy(path)

        Copy the database file.

        :param path: path to the destination file.


    .. method:: begin

        Begin a transaction.


    .. method:: commit

        Commit a transaction.


    .. method:: abort

        Abort a transaction.


    .. method:: get(key)

        Return the value corresponding to *key*. Equivalent to ``tdb[key]``.


    .. method:: remove(key)

        Delete a record from the database. Equivalent to ``del tdb[key]``.


    .. method:: put(key, value)

        Store a record in the database. Equivalent to ``tdb[key] = value``.


    .. method:: putkeep(key, value)

        Store a record in the database, unlike the standard forms
        (``tdb[key] = value`` or :meth:`put`), this method raises
        :exc:`KeyError` if *key* is already in the database.


    .. method:: putcat(key, value)

        Merge a value with an existing one, **does not override existing items**
        in current value. If there is no corresponding record, a new record is
        stored.


    .. method:: sync

        Flush modifications to the database file.


    .. method:: searchkeys(prefix[, max])

        Return a frozenset of keys starting with *prefix*. If given, *max* is
        the maximum number of keys to fetch, if omitted or specified as a
        negative value no limit is applied.


    .. method:: setindex(column, type)

        Add an index to a column.

        :param column: name of the column. An empty string means *key*.
        :type column: :class:`str` (Python2)/:class:`bytes` (Python3)
        :param type: index type, see `TDB.setindex() types`_.


    .. method:: uid

        Return a new unique id.


    .. method:: query

        Return a query object (:class:`TDBQuery`). See `Querying a Table
        Database --- TDBQuery`_.


    .. staticmethod:: metasearch(queries, type)

        Combine queries and return the result set as a tuple of keys.

        :param queries: a sequence of :class:`TDBQuery`.
        :param type: type of combination, see `TDB.metasearch() types`_.


    .. method:: optimize([bnum=0[, apow=-1[, fpow=-1[, opts=255]]]])

        Optimize a database.

        :param bnum: the number of elements in a bucket array. If specified as 0
            or as a negative value, the default value (twice the number of
            records) is used.
        :param apow: (power of 2) TODO. If specified as a negative value, the
            current setting is kept.
        :param fpow: (power of 2) TODO. If specified as a negative value, the
            current setting is kept.
        :param opts: options, see `TDB.tune()/TDB.optimize() options`_. If
            specified as 255 (:const:`UINT8_MAX`), the current setting is kept.

        .. note::
            Optimizing a read only database, or during a transaction, is an
            invalid operation.


    Methods :meth:`keys`, :meth:`values` and :meth:`items` are not yet
    implemented (mainly because I didn't settle on how to do it: should they
    return :class:`Iterable`, :class:`Iterator`, :class:`MappingView`, etc.?).
    Any help would be greatly appreciated in this matter.

    For the time being, for those of you who really need these methods, it's
    trivial to implement them in python. Here is an example using generators::

        from tokyo.cabinet import TDB as _TDB

        class TDB(_TDB):

            def keys(self):
                return (key for key in self)

            def values(self):
                return (self[key] for key in self)

            def items(self):
                return ((key, self[key]) for key in self)


    .. attribute:: path

        The path to the database file.


    .. attribute:: size

        The size in bytes of the database file.


:meth:`TDB.open` modes
======================

.. data:: TDBOREADER

    Open a database in read-only mode.

.. data:: TDBOWRITER

    Open a database in read-write mode.


The following constants can only be combined with :const:`TDBOWRITER` :

* .. data:: TDBOCREAT

      Create a new database file if it does not exists.

* .. data:: TDBOTRUNC

      Create a new database file even if one already exists (truncates existing
      file).

* .. data:: TDBOTSYNC

      Sync the database file on every transaction.


The following constants can be combined with either :const:`TDBOREADER` or
:const:`TDBOWRITER` :

* .. data:: TDBONOLCK

      Opens the database file without file locking.

* .. data:: TDBOLCKNB

      Locking is performed without blocking.


:meth:`TDB.tune`/:meth:`TDB.optimize` options
=============================================

.. data:: TDBTLARGE

    The size of the database can be larger than 2GB.

.. data:: TDBTDEFLATE

    Each record is compressed with Deflate encoding.

.. data:: TDBTBZIP

    Each record is compressed with BZIP2 encoding.

.. data:: TDBTTCBS

    Each record is compressed with TCBS encoding.


.. _tdb_setindex_types:

:meth:`TDB.setindex` types
==========================

.. data:: TDBITLEXICAL

    String index.

.. data:: TDBITDECIMAL

    Numeric index.

.. data:: TDBITTOKEN

    Token index.

.. data:: TDBITQGRAM

    Q-gram index.

.. data:: TDBITOPT

    Optimize the index.

.. data:: TDBITVOID

    Remove the index.

.. data:: TDBITKEEP

    Fail if the index already exists.


.. _tdb_metasearch_types:

:meth:`TDB.metasearch` types
============================

.. data:: TDBMSUNION

    Union.

.. data:: TDBMSISECT

    Intersection.

.. data:: TDBMSDIFF

    Difference.


Querying a Table Database --- :class:`TDBQuery`
===============================================


.. class:: TDBQuery

    When first returned by :meth:`TDB.query` a query result set potentially
    includes all keys contained in the database. You can narrow down a search by
    calling :meth:`filter` and limit the number of results with :meth:`limit`.


    .. method:: filter(column, condition, expr)

        Filter the result set on the condition expressed by the parameters.

        :param column: name of the column. An empty string means *key*.
        :type column: :class:`str` (Python2)/:class:`bytes` (Python3)
        :param condition: see `TDBQuery.filter() conditions`_.
        :param expr: expression.
        :type expr: :class:`str` (Python2)/:class:`bytes` (Python3)

        .. note::
            Calling :meth:`filter` multiple times with different conditions is
            equivalent to applying a logical ``AND`` between the conditions.


    .. method:: sort(column, type)

        Sort the result set.

        :param column: name of the column. An empty string means *key*.
        :type column: :class:`str` (Python2)/:class:`bytes` (Python3)
        :param type: sort type (and direction), see `TDBQuery.sort() types`_.


    .. method:: limit([max[, skip]])

        Limit the number of keys in the result set.

        :param max: the maximum number of keys to return. If specified as a
            negative value no limit is applied.
        :param skip: the number of keys to skip (from the beginning). If
            specified as a 0 or as a negative value no skipping is done.


    .. method:: search

        Execute the query and return the result set as a tuple of keys.


    .. method:: remove

        Remove all records corresponding to the result set from the database.


    .. method:: process(callback)

        Apply *callback* to each record in the result set.

        :param callback: *callback* must be a callable that accept a pair *key*,
         *value* as its arguments. *callback* can return one, or a combination,
         of :ref:`these constants <tdbquery_process_callback_return_consts>` to
         trigger post-processing or to stop iterating.


    .. attribute:: hint

        TODO.


.. _tdbquery_filter_conditions:

:meth:`TDBQuery.filter` conditions
==================================

*value* refers to ``tdb[key][column]`` if *column* is not an empty string
otherwise *value* is *key* (that will need a better description).

String conditions :

.. data:: TDBQCSTREQ

    ::

        value == expr

.. data:: TDBQCSTRINC

    ::

        expr in value #substring test

.. data:: TDBQCSTRBW

    ::

        value.startswith(expr)

.. data:: TDBQCSTREW

    ::

        value.endswith(expr)

.. data:: TDBQCSTRAND

    if *expr* is expressed as ``"expr1,expr2"``::

        expr1 in value and expr2 in value

.. data:: TDBQCSTROR

    if *expr* is expressed as ``"expr1,expr2"``::

        expr1 in value or expr2 in value

.. data:: TDBQCSTROREQ

    if *expr* is expressed as ``"expr1,expr2"``::

        value == expr1 or value == expr2

.. data:: TDBQCSTRRX

    *expr* is a regular expression.

Numeric conditions :

.. data:: TDBQCNUMEQ

    ::

        value == expr

.. data:: TDBQCNUMGT

    ::

        value > expr

.. data:: TDBQCNUMGE

    ::

        value >= expr

.. data:: TDBQCNUMLT

    ::

        value < expr

.. data:: TDBQCNUMLE

    ::

        value <= expr

.. data:: TDBQCNUMBT

    if *expr* is expressed as ``"expr1,expr2"``::

        value >= min(expr1, expr2) and value <= max(expr1, expr2)

.. data:: TDBQCNUMOREQ

    if *expr* is expressed as ``"expr1,expr2"``::

        value == expr1 or value == expr2

Full-text search :

.. data:: TDBQCFTSPH

    TODO.

.. data:: TDBQCFTSAND

    TODO.

.. data:: TDBQCFTSOR

    TODO.

.. data:: TDBQCFTSEX

    TODO.

All conditions above can be combined with the following :

.. data:: TDBQCNEGATE

    Negate the condition.

.. data:: TDBQCNOIDX

    Do not use the column index (if one has been set).


.. _tdbquery_sort_types:

:meth:`TDBQuery.sort` types
===========================

.. data:: TDBQOSTRASC

    Alphabetical, ascending.

.. data:: TDBQOSTRDESC

    Alphabetical, descending.

.. data:: TDBQONUMASC

    Numerical, ascending.

.. data:: TDBQONUMDESC

    Numerical, descending.


.. _tdbquery_process_callback_return_consts:

:meth:`TDBQuery.process` post-processing constants
==================================================

.. data:: TDBQPPUT

    Store a modified *value*.

.. data:: TDBQPOUT

    Remove the record.

.. data:: TDBQPSTOP

    Stop iterating over the records.
