X-Git-Url: https://git.jsancho.org/?p=mojodb.git;a=blobdiff_plain;f=mojo.py;fp=mojo.py;h=0000000000000000000000000000000000000000;hp=f3aa74456056a7d0c84eb8cb076bb502dc05e444;hb=792f961fb96bb8533e540970c54f43b958d77296;hpb=f63673b9ed08886c9ac1582f94f0e63103985497 diff --git a/mojo.py b/mojo.py deleted file mode 100644 index f3aa744..0000000 --- a/mojo.py +++ /dev/null @@ -1,286 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# mojo, a Python library for implementing document based databases -# Copyright (C) 2013-2014 by Javier Sancho Fernandez -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -import cPickle -import uuid - - -class Connection(object): - def __init__(self, *args, **kwargs): - self._db_con = None - - def __getattr__(self, db_name): - return Database(self, db_name) - - def __getitem__(self, *args, **kwargs): - return self.__getattr__(*args, **kwargs) - - def __repr__(self): - return "Connection(%s)" % self._db_con - - def _get_databases(self): - return [] - - def database_names(self): - try: - return [unicode(x) for x in self._get_databases()] - except: - return [] - - def _get_tables(self, db_name): - return [] - - def collection_names(self, db_name): - try: - return list(set([unicode(x.split('$')[0]) for x in filter(lambda x: '$' in x, self._get_tables(db_name))])) - except: - return [] - - def _count_rows(self, db_name, table_name): - return 0 - - def _count(self, db_name, table_name): - try: - return self._count_rows(db_name, table_name + '$_id') - except: - return 0 - - def _create_database(self, db_name): - return None - - def _create_table(self, db_name, table_name, fields): - # [{'name': 'id', 'type': 'char', 'size': 20, 'primary': True}] - return None - - def _get_cursor(self, db_name, query): - # {'select': [('t1$_id', 'id'), {'select': [('t1$c1', 'value')], 'from': ['t1$c1'], 'where': [(('t1$c1', 'id'), '=', ('t1$_id', 'id'))]}], 'from': ['t1$_id']} - return None - - def _next(self, cursor): - return None - - def _insert(self, db_name, table_name, values): - return None - - def commit(self): - pass - - def rollback(self): - pass - - -class Database(object): - def __init__(self, connection, db_name): - self.connection = connection - self.db_name = unicode(db_name) - - def __getattr__(self, table_name): - return Collection(self, table_name) - - def __getitem__(self, *args, **kwargs): - return self.__getattr__(*args, **kwargs) - - def __repr__(self): - return "Database(%r, %r)" % (self.connection, self.db_name) - - def _create_database(self): - return self.connection._create_database(self.db_name) - - def exists(self): - return (self.db_name in self.connection.database_names()) - - def collection_names(self): - return self.connection.collection_names(self.db_name) - - -class Collection(object): - def __init__(self, database, table_name): - self.database = database - self.table_name = unicode(table_name) - - def __repr__(self): - return "Collection(%r, %r)" % (self.database, self.table_name) - - def exists(self): - return (self.database.exists() and self.table_name in self.database.collection_names()) - - def _create_table(self): - fields = [ - {'name': 'id', 'type': 'char', 'size': 32, 'primary': True}, - ] - return self.database.connection._create_table(self.database.db_name, '%s$_id' % self.table_name, fields) - - def _create_field(self, field_name): - fields = [ - {'name': 'id', 'type': 'char', 'size': 32, 'primary': True}, - {'name': 'value', 'type': 'text', 'null': False}, - {'name': 'number', 'type': 'float'}, - ] - return self.database.connection._create_table(self.database.db_name, '%s$%s' % (self.table_name, field_name), fields) - - def _get_fields(self): - tables = self.database.connection._get_tables(self.database.db_name) - return [unicode(x[x.find('$')+1:]) for x in filter(lambda x: x.startswith('%s$' % self.table_name), tables)] - - def count(self): - return self.database.connection._count(self.database.db_name, self.table_name) - - def find(self, *args, **kwargs): - return Cursor(self, *args, **kwargs) - - def insert(self, doc_or_docs): - if not self.database.db_name in self.database.connection.database_names(): - self.database._create_database() - if not self.table_name in self.database.collection_names(): - self._create_table() - - if not type(doc_or_docs) in (list, tuple): - docs = [doc_or_docs] - else: - docs = doc_or_docs - for doc in docs: - if not '_id' in doc: - doc['_id'] = uuid.uuid4().hex - self._insert_document(doc) - - if type(doc_or_docs) in (list, tuple): - return [d['_id'] for d in docs] - else: - return docs[0]['_id'] - - def _insert_document(self, doc): - table_id = '%s$_id' % self.table_name - fields = self._get_fields() - self.database.connection._insert(self.database.db_name, table_id, {'id': doc['_id']}) - for f in doc: - if f == '_id': - continue - if not f in fields: - self._create_field(f) - table_f = '%s$%s' % (self.table_name, f) - values = { - 'id': doc['_id'], - 'value': cPickle.dumps(doc[f]), - } - if type(doc[f]) in (int, float): - values['number'] = doc[f] - self.database.connection._insert(self.database.db_name, table_f, values) - - -class Cursor(object): - def __init__(self, collection, spec=None, fields=None, **kwargs): - if spec and not type(spec) is dict: - raise Exception("spec must be an instance of dict") - - self.collection = collection - self.spec = spec - if self.collection.exists(): - self.fields = self._get_fields(fields) - self.cursor = self._get_cursor() - else: - self.fields = None - self.cursor = None - - def __iter__(self): - return self - - def _get_fields(self, fields): - set_all_fields = set(self.collection._get_fields()) - if fields is None: - res_fields = list(set_all_fields) - elif type(fields) is dict: - fields_without_id = filter(lambda x: x[0] != '_id', fields.iteritems()) - if fields_without_id[0][1]: - first = True - res_fields = set() - else: - first = False - res_fields = set(set_all_fields) - for f in fields_without_id: - if f[1] and f[0] in set_all_fields: - if first: - res_fields.add(f[0]) - else: - raise Exception("You cannot currently mix including and excluding fields. Contact us if this is an issue.") - elif not f[1]: - if not first: - res_fields.discard(f[0]) - else: - raise Exception("You cannot currently mix including and excluding fields. Contact us if this is an issue.") - if '_id' in fields and not fields['_id']: - res_fields.discard('_id') - else: - res_fields.add('_id') - res_fields = list(res_fields) - else: - set_fields = set(list(fields)) - set_fields.add('_id') - res_fields = list(set_all_fields.intersection(set_fields)) - - return res_fields - - def _get_cursor(self): - query = {} - table_id = '%s$_id' % self.collection.table_name - - query['select'] = [(table_id, 'id')] - for f in filter(lambda x: x != '_id', self.fields): - table_f = '%s$%s' % (self.collection.table_name, f) - q = self._get_cursor_field(table_id, table_f) - query['select'].append(q) - - query['from'] = [table_id] - - if self.spec: - query['where'] = [] - for k, v in self.spec.iteritems(): - table_f = '%s$%s' % (self.collection.table_name, k) - field_q = self._get_cursor_field(table_id, table_f) - query['where'].append((field_q, '=', v)) - - return self.collection.database.connection._get_cursor(self.collection.database.db_name, query) - - def _get_cursor_field(self, table_id, table_field): - return { - 'select': [(table_field, 'value')], - 'from': [table_field], - 'where': [((table_field, 'id'), '=', (table_id, 'id'))], - } - - def next(self): - if self.cursor is None: - raise StopIteration - - if self.cursor: - res = self.collection.database.connection._next(self.cursor) - if res is None: - raise StopIteration - else: - document = {} - if '_id' in self.fields: - document['_id'] = res[0] - fields_without_id = filter(lambda x: x != '_id', self.fields) - for i in xrange(len(fields_without_id)): - if not res[i + 1] is None: - document[fields_without_id[i]] = cPickle.loads(res[i + 1]) - return document - else: - return None