Beispiel #1
0
class DocDB(object):
    """Creates instances of DocDB. Each instance will have a db connection.

    Extracted from web2py docs:
    ---------------------------
    Here are examples of connection strings for specific types of supported back-end databases
    (in all cases, we assume the database is running from localhost on its default port and is named "test"):

    SQLite	sqlite://storage.db
    MySQL	mysql://username:password@localhost/test
    PostgreSQL	postgres://username:password@localhost/test
    MSSQL	mssql://username:password@localhost/test
    FireBird	firebird://username:password@localhost/test
    Oracle	oracle://username/password@test
    DB2	db2://username:password@test
    Ingres	ingres://username:password@localhost/test
    Informix	informix://username:password@test
    Google App Engine/SQL	google:sql
    Google App Engine/NoSQL	google:datastore

    Notice that in SQLite the database consists of a single file. If it does not exist, it is created.
    This file is locked every time it is accessed. In the case of MySQL, PostgreSQL, MSSQL, FireBird,
    Oracle, DB2, Ingres and Informix the database "test" MUST exist.

    """

    def __init__(self, conn='sqlite://temp.db', pool_size=0, migrate=True):
        """
        Generates a connection with the given DB.
        @connection: system path to the sqlite file to use or DB connection string. If None given,
        a default temp.db file will be created.
        """
        if '://' not in conn:
            print """Connection string needed!\n \
                  Some examples:\n \
                  SQLite  sqlite://storage.db
                  MySQL   mysql://username:password@localhost/test \
                  PostgreSQL  postgres://username:password@localhost/test
            """
            sys.exit(2)
        self._conn = conn
        self._db = DAL(conn, folder=PATH, pool_size=pool_size)
        self._db.define_table('documents',
                   Field('key'),
                   Field('data', 'text'),
                   Field('valid', 'boolean'),
                   migrate = migrate)

        if not self._db(self._db.documents).count():
            try:
                self._db.executesql('CREATE INDEX keyx ON documents (key)') #CREATE INDEX IF NOT EXISTS
            except Exception:
                self._db.rollback()

    def get(self, key):
        """
        Searches and returns the doc for a given key.
        """
        db = self._db
        doc = db((db.documents.key==key) & (db.documents.valid==True)).select(db.documents.data).first()
        if doc:
            return json.loads(doc['data'])
        return None

    def set(self, key, doc):
        """
        Inserts a document (doc) into the DB.
        @doc: can be of any python data structure (string, number, dict, list, ...
        """
        db = self._db
        data = json.dumps(doc)
        db((db.documents.key==key) & (db.documents.valid==True)).update(valid=False)
        db.documents.insert(key=key, data=data, valid=True)
        db.commit()
        return True

    def mset(self, docs):
        """
        Inserts a set of documents into the DB.
        Example:
            >>> l = [('key1', {'key': 'value'}), ('key2', {'key': 'value'}), ('key3', {'key': 'value'})]
            >>> db.mset(*l)
        """
        db = self._db
        counter = 0
        for doc in docs:
            key, data = doc
            data = json.dumps(data)
            db((db.documents.key==key) & (db.documents.valid==True)).update(valid=False)
            db.documents.insert(key=key, data=data, valid=True)
            counter += 1
            if counter > 1000:
                db.commit()
                counter = 0
        db.commit()
        return True

    def versions(self, key):
        """
        Lists all the documents related to a key.
        """
        db = self._db
        results = []
        for doc in db(db.documents.key == key).select():
            id, data, valid = doc['id'], json.loads(doc['data']), doc['valid']
            results.append((id, data, valid))
        return results

    def revert(self, key, version):
        """
        Reverts to a previous version of the document.
        """
        db = self._db
        vers = self.versions(key)
        for doc in vers:
            id, data, valid = doc
            if id == version:
                db((db.documents.key==key) & (db.documents.valid==True)).update(valid=False)
                db(db.documents.id==id).update(valid=True)
                db.commit()
                return True
        return False

    def info(self):
        """
        Returns a dict with info about the current DB (including db filesize, number of keys, etc.).
        """
        dbsize = -1
        db = self._db
        if "postgres" in self._conn:
            dbsize = db.executesql("SELECT pg_size_pretty(pg_database_size('%s'));" % self.dbname)[0][0]
        num_keys = db(db.documents.valid==True).count()
        return dict(keys=num_keys, dbsize=dbsize)

    def keys(self):
        """
        Returns a list of ALL the keys in the current DB.
        """
        db = self._db
        return [doc['key'] for doc in db(db.documents.valid==True).select(db.documents.key)]

    def flushall(self):
        """
        Deletes ALL the content from the DB.
        TODO: Use truncate.
        """
        self._db.documents.truncate()
        self._db.commit()
        #self.__init__()
        return True

    def compact(self, key=None):
        """
        Deletes ALL the versions for a given document or the entire DB.
        """
        db = self._db
        if key:
            db((db.documents.key==key) & (db.documents.valid==False)).delete()
        else:
            db(db.documents.valid==False).delete()
        db.commit()
        return True

    def __contains__(self, item):
        if self.get(item): return True
        return False

    def __getitem__(self, item):
        return self.get(item)

    def __setitem__(self, key, doc):
        return self.set(key, doc)

    def __delitem__(self, key):
        self._db.execute('UPDATE document SET valid == 0 WHERE key == ?', (key,))
        self._db.commit()
        return True