Example #1
0
 def getCount(cls, db, where = None):
     """Request number of records in this table.
     """
     cls.checkTable(db)
     count = cls.COUNT(where)
     count = db.select(count, from_ = cls).value(0, count)
     logger.debug('Model.getCount(%s, db= %s, where= %s) = %s' % (cls, db, where, count))
     return count
Example #2
0
    def __new__(cls, name, bases, attrs):
        NewModel = type.__new__(cls, name, bases, attrs)

        NewModel._name = NewModel.__dict__.get('_name', name.lower()) # db table name

        if NewModel._name is None: # we need only Model subclasses; if db table name is None - __new__ is called for Model itself
            return NewModel # return without any processing

        logger.debug('Finishing initialization of model `%s`' % NewModel)

        # assure each class has its own attribute, because by default _indexes is inherited from the parent class
        NewModel._indexes = list(NewModel._indexes)

        attrs = OrderedDict(inspect.getmembers(NewModel))
        fields = []
        for fieldName, field in attrs.items():
            if isinstance(field, orm.fields.Field):
                fields.append((fieldName, field))

        # sort by definition order (as __dict__ is unsorted) - for field recreation order
        fields = OrderedDict(sorted(fields, key = lambda f: f[1]._id))

        for fieldName, field in fields.items():
            if not fieldName.islower() or fieldName.startswith('_'):
                raise orm.ModelError('Field `%s` in model `%s`: field names must be lowercase and '
                                     'must not start with `_`.' % (fieldName, name))

            # recreate the field - to handle correctly inheritance of Tables
            newField = field.__class__(name = fieldName, table = NewModel, label = field.label)
            try:
                newField._init_(*field._initArgs, **field._initKwargs) # and initialize it
            except Exception:
                print('Failed to init a field:', fieldName, field._initArgs, field._initKwargs)
                raise
            # each class has its own field object. Inherited and parent tables do not share field attributes
            setattr(NewModel, fieldName, newField)

        indexesDict = OrderedDict() # to filter duplicate indexes by index name
        for index in NewModel._indexes:
            if index.table is not NewModel: # inherited index
                if not isinstance(index, orm.Index):
                    raise orm.ModelError('Found a non Index in the _indexes.')
                if index.table is not NewModel:
                    # index was inherited from parent model - recreate it with fields from new model
                    indexFields = [orm.IndexField(NewModel[indexField.field.name], indexField.sortOrder, indexField.prefixLength)
                                   for indexField in index.indexFields] # replace fields by name with fields from new model
                    index = orm.Index(indexFields, index.type, index.name, index.method, **index.other)
                for indexField in index.indexFields:
                    if issubclass(NewModel, indexField.field.table):
                        indexField.field = NewModel[indexField.field.name] # to assure that field from this model, and from parent, is used
                    else:
                        raise orm.ModelError('Field `%s` in index is not from model `%s`.' % (indexField.field, NewModel))
            indexesDict[index.name] = index
        NewModel._indexes = indexesDict.values()
        NewModel._ordering = list()
        NewModel._checkedDbs = set()

        return NewModel
Example #3
0
 def _execute(self, *a, **b):
     query = a[0]
     logger.debug('DB query: %s' % query)
     t0 = time.time()
     try:
         result = self.cursor.execute(*a, **b)
     except Exception:
         logger.warning(query)
         raise
     self._timings.append((query, round(time.time() - t0, 4)))
     return result
Example #4
0
 def __init__(self, uri = '', connect = True, autocommit = True):
     """URI is already without protocol."""
     self.uri = uri
     logger.debug('Creating adapter for `%s`' % self)
     self._timings = []
     if connect:
         self.connection = self.connect()
         self.cursor = self.connection.cursor()
     else:
         self.connection = None
         self.cursor = None
     self.autocommit = autocommit
Example #5
0
 def getColumns(self, tableName):
     """Get columns of a table"""
     self.execute("PRAGMA table_info('%s')" % tableName) # name, type, notnull, dflt_value, pk
     columns = {}
     for row in self.cursor.fetchall():
         logger.debug('Found table column: %s, %s' % (tableName, row))
         typeName = row[2].lower()
         # INTEGER PRIMARY KEY fields are auto-generated in sqlite
         # INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
         autoincrement = bool(typeName == 'integer' and row[5])
         if 'int' in typeName or 'bool' in typeName: # booleans are sotred as ints in sqlite
             typeName = 'int'
         elif typeName not in ('blob', 'text'):
             raise TypeError('Unexpected data type: %s' % typeName)
         column = Column(type = typeName, field = None, name = row[1], default = row[4],
                         precision = 19, nullable = (not row[3]), autoincrement = autoincrement)
         columns[column.name] = column
         logger.debug('Reproduced table column: %s, %s' % (tableName, column))
     return columns
Example #6
0
    def checkTable(cls, db):
        """Check if corresponding table for this model exists in the db and has all necessary columns.
        Add checkTable call in very model method that uses a db.
        """
        assert isinstance(db, orm.GenericAdapter), 'Need a database adapter'
        if db.uri in cls._checkedDbs: # this db was already checked 
            return
        logger.debug('Model.checkTable: checking db table %s' % cls)
        tableName = cls._name
        if tableName not in db.getTables():
            cls._handleTableMissing(db)
#        import pprint
        modelColumns = {field.column.name: field.column for field in cls}
        dbColumns = db.getColumns(tableName)
#        logger.debug(pprint.pformat(list(column.str() for column in dbColumns.values())))
#        logger.debug(pprint.pformat(list(column.str() for column in modelColumns.values())))
        for columnName, column in modelColumns.items():
            dbColumn = dbColumns.pop(columnName, None)
            if not dbColumn: # model column is not found in the db
                print('Column in the db not found: %s' % column.str())
        logger.debug('CREATE TABLE query:\n%s' % db.getCreateTableQuery(cls))
        cls._checkedDbs.add(db.uri)
Example #7
0
 def get(cls, db, where, orderby = False, limit = False, select_related = False):
     """Get records from this table which fall under the given condition.
     @param db: adapter to use
     @param where: condition to filter
     @param order: list of field to sort by
     @param limit: tuple (from, to)
     @param select_related: whether to retrieve objects related by foreign keys in the same query
     """
     logger.debug("Model.get('%s', db= %s, where= %s, limit= %s)" % (cls, db, where, limit))
     cls.checkTable(db)
     orderby = orderby or cls._ordering # use default table ordering if no ordering passed
     fields = list(cls)
     from_ = [cls]
     recordFields = []
     if select_related:
         for i, field in enumerate(cls):
             if isinstance(field, orm.RecordField):
                 recordFields.append((i, field))
                 fields.extend(field.referTable)
                 from_.append(orm.LeftJoin(field.referTable, field == field.referTable.id))
     #print(db._select(*fields, from_ = from_, where = where, orderby = orderby, limit = limit))
     rows = db.select(*fields, from_ = from_, where = where, orderby = orderby, limit = limit)
     for row in rows:
         record = cls(db, *zip(cls, row))
         if select_related:
             fieldOffset = len(cls)
             for i, recordField in recordFields:
                 referTable = recordField.referTable
                 if row[i] is None: 
                     referRecord = None
                 else:
                     # if referRecord.id is None: # missing record !!! integrity error
                     referRecord = referTable(db, *zip(referTable, row[fieldOffset:]))
                 setattr(record, recordField.name, referRecord)
                 fieldOffset += len(referTable)
         yield record