def first(self, **context): if self.isNull(): return None context = self.context(**context) try: with ReadLocker(self.__cacheLock): return self.__cache['first'][context] except KeyError: try: with ReadLocker(self.__cacheLock): return self.__cache['first'][context] except IndexError: return None except KeyError: try: with ReadLocker(self.__cacheLock): raw = self.__preload['first'][context] except KeyError: context.limit = 1 context.order = [(self.__model.schema().idColumn().name(), 'desc')] records = self.records(context=context) record = records[0] if records else None else: record = self._process([raw], context)[0] with WriteLocker(self.__cacheLock): self.__cache['first'][context] = record return record
def count(self, **context): if self.isNull(): return 0 context = self.context(**context) try: with ReadLocker(self.__cacheLock): return self.__cache['count'][context] except KeyError: try: with ReadLocker(self.__cacheLock): return len(self.__cache['records'][context]) except KeyError: optimized_context = context.copy() optimized_context.columns = [self.__model.schema().idColumn()] optimized_context.expand = None optimized_context.order = None try: with ReadLocker(self.__cacheLock): count = self.__preload['count'][context] except KeyError: try: with ReadLocker(self.__cacheLock): raw = self.__preload['records'][context] count = len(raw) except KeyError: conn = optimized_context.db.connection() count = conn.count(self.__model, optimized_context) with WriteLocker(self.__cacheLock): self.__cache['count'][context] = count return count
def changes(self, columns=None, recurse=True, flags=0, inflated=False): """ Returns a dictionary of changes that have been made to the data from this record. :return { <orb.Column>: ( <variant> old, <variant> new), .. } """ output = {} is_record = self.isRecord() schema = self.schema() columns = [schema.column(c) for c in columns] if columns else \ schema.columns(recurse=recurse, flags=flags).values() context = self.context(inflated=inflated) with ReadLocker(self.__dataLock): for col in columns: old, curr = self.__values.get(col.name(), (None, None)) if col.testFlag(col.Flags.ReadOnly): continue elif not is_record: old = None check_old = col.restore(old, context) check_curr = col.restore(curr, context) try: different = check_old != check_curr except StandardError: different = True if different: output[col] = (check_old, check_curr) return output
def value(self, key, default=None): """ Returns the value for the cached key for this instance. :return <variant> """ with ReadLocker(self._cacheLock): return self._cache.get(key)
def index(self, record, **context): context = self.context(**context) if not record: return -1 else: try: with ReadLocker(self.__cacheLock): return self.__cache['records'][context].index(record) except KeyError: return self.ids().index(record.id())
def current(threadId=None): """ Returns the current transaction for the system. :return <Transaction> || None """ threadId = threadId or threading.current_thread().ident with ReadLocker(Transaction._stackLock): stack = Transaction._stack.get(threadId) return stack[-1] if stack else None
def last(self, **context): if self.isNull(): return None context = self.context(**context) try: with ReadLocker(self.__cacheLock): return self.__cache['last'][context] except KeyError: try: with ReadLocker(self.__cacheLock): raw = self.__preload['last'][context] except KeyError: record = self.reversed().first(context=context) else: record = self._process([raw], context)[0] with WriteLocker(self.__cacheLock): self.__cache['last'][context] = record return record
def ids(self, **context): if self.isNull(): return [] context = self.context(**context) try: with ReadLocker(self.__cacheLock): return self.__cache['ids'][context] except KeyError: try: with ReadLocker(self.__cacheLock): ids = self.__preload['ids'][context] except KeyError: ids = self.records(columns=[self.__model.schema().idColumn()], returning='values', context=context) with WriteLocker(self.__cacheLock): self.__cache['ids'][context] = ids return ids
def copy(self, **context): context = self.context(**context) with ReadLocker(self.__cacheLock): records = self.__cache['records'].get(context) other = orb.Collection(records=records, preload=self.__preload, model=self.__model, record=self.__record, collector=self.__collector, context=context) return other
def records(self, **context): if self.isNull(): return [] context = self.context(**context) try: with ReadLocker(self.__cacheLock): return self.__cache['records'][context] except KeyError: try: with ReadLocker(self.__cacheLock): raw = self.__preload['records'][context] except KeyError: conn = context.db.connection() raw = conn.select(self.__model, context) records = self._process(raw, context) with WriteLocker(self.__cacheLock): self.__cache['records'][context] = records return records
def defaultContexts(cls): defaults = getattr(cls, '_{0}__defaults'.format(cls.__name__), None) if defaults is None: defaults = defaultdict(list) lock = ReadWriteLock() setattr(cls, '_{0}__defaults'.format(cls.__name__), defaults) setattr(cls, '_{0}__defaultsLock'.format(cls.__name__), lock) else: lock = getattr(cls, '_{0}__defaultsLock'.format(cls.__name__)) tid = threading.currentThread().ident with ReadLocker(lock): return defaults.get(tid) or []
def isCached(self, key): """ Returns whether or not the inputted key is cached. :param key | <hashable> :return <bool> """ if not self.isEnabled(): return False self._cleanup() with ReadLocker(self._cacheLock): return key in self._cache
def refine(self, createNew=True, **context): if not createNew: self.__context.update(context) return self else: context = self.context(**context) with ReadLocker(self.__cacheLock): records = self.__cache['records'].get(context) other = orb.Collection(records=records, model=self.__model, record=self.__record, collector=self.__collector, context=context) return other
def isRecord(self, db=None): """ Returns whether or not this database table record exists in the database. :return <bool> """ if db in (None, self.context().db): col = self.schema().column(self.schema().idColumn()) with ReadLocker(self.__dataLock): if col not in self.__loaded or self.__values[ col.name()][0] is None: return False return True else: return None
def select(self, table_or_join, lookup, options): if orb.Table.typecheck(table_or_join) or orb.View.typecheck( table_or_join): # ensure the primary record information is provided for orb.logger.setLevel(orb.logging.DEBUG)ions if lookup.columns and options.inflated: lookup.columns += [ col.name() for col in table_or_join.schema().primaryColumns() ] SELECT = self.sql().byName('SELECT') schema = table_or_join.schema() data = {} sql = SELECT(table_or_join, lookup=lookup, options=options, IO=data) # if we don't have any command to run, just return a blank list if not sql: return [] elif options.dryRun: print sql % data return [] else: with ReadLocker(self.__concurrencyLocks[schema.name()]): records = self.execute(sql, data)[0] store = self.sql().datastore() for record in records: for name, value in record.items(): column = schema.column(name) record[name] = store.restore(column, value) return records else: raise orb.errors.DatabaseError('JOIN NOT DEFINED')
def get(self, column, useMethod=True, **context): """ Returns the value for the column for this record. :param column | <orb.Column> || <str> default | <variant> inflated | <bool> :return <variant> """ if isinstance(column, (str, unicode)) and '.' in column: parts = column.split('.') sub_context = context.copy() sub_context['inflated'] = True value = self for part in parts[:-1]: if not value: return None value = value.get(part, useMethod=useMethod, **sub_context) if value: return value.get(parts[-1], useMethod=useMethod, **context) else: return None else: my_context = self.context() for k, v in my_context.raw_values.items(): if k not in orb.Context.QueryFields: context.setdefault(k, v) sub_context = orb.Context(**context) # normalize the given column col = self.schema().column(column, raise_=False) if not col: collector = self.schema().collector(column) if collector: try: return self.__cache[collector][sub_context] except KeyError: records = collector(self, useMethod=useMethod, context=sub_context) self.__cache[collector][sub_context] = records return records else: raise errors.ColumnNotFound(self.schema().name(), column) # lookup the shortuct value vs. the local one elif col.shortcut(): return self.get(col.shortcut(), **context) # don't inflate if the requested value is a field if column == col.field(): sub_context.inflated = False # call the getter method fot this record if one exists if useMethod: method = col.gettermethod() if method is not None: return method(self, context=sub_context) # grab the current value with ReadLocker(self.__dataLock): old_value, value = self.__values.get(col.name(), (None, None)) # return a reference when desired out_value = col.restore(value, sub_context) if isinstance(out_value, orb.Model) and not isinstance(value, orb.Model): with WriteLocker(self.__dataLock): self.__values[col.name()] = (old_value, out_value) return out_value
def isLoaded(self, **context): context = self.context(**context) with ReadLocker(self.__cacheLock): return context in self.__cache['records']
def isNull(self): with ReadLocker(self.__cacheLock): return self.__cache['records'].get( self.__context) is None and self.__model is None
def values(self, *columns, **context): if self.isNull(): return [] orig_context = context context = self.context(**orig_context) try: with ReadLocker(self.__cacheLock): return self.__cache['values'][(context, columns)] except KeyError: try: with ReadLocker(self.__cacheLock): records = self.__cache['records'][context] except KeyError: try: with ReadLocker(self.__cacheLock): raw = self.__preload['records'][context] except KeyError: context.columns = columns conn = context.db.connection() raw = conn.select(self.__model, context) schema = self.__model.schema() values = [] fields = [schema.column(col) for col in columns] for record in raw: if not context.inflated: record_values = [ record[field.field()] for field in fields ] else: record_values = [] for i, field in enumerate(fields): col = columns[i] raw_values = orig_context.copy() raw_values['distinct'] = None if isinstance( field, orb.ReferenceColumn ) and raw_values.get('inflated') is None: raw_values['inflated'] = col != field.field() val = field.restore( record[field.field()], context=orb.Context(**raw_values)) record_values.append(val) if len(fields) == 1: values.append(record_values[0]) else: values.append(record_values) with WriteLocker(self.__cacheLock): self.__cache['values'][(context, columns)] = values return values # use preloaded cache for values when possible else: if len(columns) == 1: return [ record.get(columns[0]) if record else None for record in records ] else: return [(record.get(c) for c in columns) for record in records]