class StatBucket(item.Item): """ Obsolete. Only present for schema compatibility. Do not use. """ schemaVersion = 2 type = attributes.text(doc="A stat name, such as 'messagesReceived'") value = attributes.ieee754_double(default=0.0, doc='Total number of events for this time period') interval = attributes.text(doc='A time period, e.g. "quarter-hour" or "minute" or "day"') index = attributes.integer(doc='The position in the round-robin list for non-daily stats') time = attributes.timestamp(doc='When this bucket was last updated') attributes.compoundIndex(interval, type, index) attributes.compoundIndex(index, interval)
class Header(item.Item): """ Database resident representation of a MIME header. """ typeName = 'quotient_mime_header' schemaVersion = 1 message = attributes.reference( "A reference to the stored top-level L{xquotient.exmess.Message} " "object to which this header pertains.", reftype=exmess.Message, whenDeleted=attributes.reference.CASCADE) part = attributes.reference( "A reference to the stored MIME part object to which this header " "directly pertains.") name = attributes.text("The name of this header. What it is called.", allowNone=False) value = attributes.text("The decoded value of this header.", allowNone=False) index = attributes.integer("The position of this header within a part.", indexed=True, allowNone=False) # This compound index matches the getHeader[s] query and is critical for # interactive performance. attributes.compoundIndex(part, name)
class TestItem(item.Item): schemaVersion = 1 typeName = 'TestItem' foo = attributes.integer(indexed=True, default=10) bar = attributes.text() baz = attributes.timestamp() other = attributes.reference() booleanT = attributes.boolean() booleanF = attributes.boolean() activated = attributes.inmemory() checkactive = attributes.inmemory() checked = attributes.inmemory() myStore = attributes.reference() attributes.compoundIndex(bar, baz) def activate(self): self.activated = True if getattr(self, 'checkactive', False): assert isinstance(self.other, TestItem), repr(self.other) assert self.other != self, repr(self.other) self.checked = True
class MultiColumnSortHelper(Item): columnOne = integer() columnTwo = integer() compoundIndex(columnOne, columnTwo)
class SingleColumnSortHelper(Item): mainColumn = integer(indexed=True) other = integer() compoundIndex(mainColumn, other)
class SearchEntry(Item): """ An entry in the search index. Each combination of the attributes on this item forms a unique entry in the index. The primary querying operation supported is matching on the C{(searchClass, environment, indexType, searchValue)} portion, with exact or prefix matching on the I{searchValue} component depending on the I{searchClass} component. "Separate" indexes are keyed by C{(searchClass, environment, indexType)}. I{environment} and I{indexType} are separated as a convenience to clients as separating them allows for easily differentiating between application environments at a global configuration level, as well as between different indexes within the application. """ searchClass = text(doc=""" The search "class" that this entry belongs to; must be a value from L{SearchClasses}. """, allowNone=False) environment = text(doc=""" The environment in which this entry exists. Usually something like C{u'prod'}. """, allowNone=False) indexType = text(doc=""" The index type for this index entry. Usually something like C{u'idNumber'}. """, allowNone=False) searchValue = text(doc=""" The search value that this entry should match. """, allowNone=False) searchType = text(doc=""" The search type that this entry should match. """, allowNone=False) result = text(doc=""" The search result that should be returned when this entry matches. """, allowNone=False) compoundIndex(searchClass, environment, indexType, searchValue, searchType, result) compoundIndex(searchClass, environment, indexType, result, searchType) _searchNoise = compile(u'[^\w,]', UNICODE) @classmethod def _normalize(cls, value): """ Normalize a search value. @type value: L{unicode} @param value: The value to normalize. @rtype: L{unicode} @return: The normalized value. """ return cls._searchNoise.sub(u'', casefold(normalize('NFC', value))) @classmethod def search(cls, store, searchClass, environment, indexType, searchValue, searchType=None, limit=200): """ Return entries matching the given search. @see: L{SearchEntry} """ with METRIC_SEARCH_QUERY_LATENCY.labels(searchClass.value, environment, indexType).time(): criteria = [] searchValue = cls._normalize(searchValue) if searchClass == SearchClasses.EXACT: criteria.append(SearchEntry.searchValue == searchValue) elif searchClass == SearchClasses.PREFIX: criteria.append( SearchEntry.searchValue.startswith(searchValue)) else: raise RuntimeError( 'Invalid search class: {!r}'.format(searchClass)) if searchValue == u'': METRIC_SEARCH_REJECTED.labels(searchClass.value, environment, indexType).inc() return [] criteria.extend([ SearchEntry.searchClass == searchClass.value, SearchEntry.environment == environment, SearchEntry.indexType == indexType, ]) if searchType is not None: criteria.append(SearchEntry.searchType == searchType) query = store.query(SearchEntry, AND(*criteria), limit=limit) return [{ u'result': item.result, u'type': item.searchType } for item in query] @classmethod def insert(cls, store, searchClass, environment, indexType, result, searchType, searchValue): """ Insert an entry into the search index. @see: L{SearchEntry} """ with METRIC_SEARCH_INSERT_LATENCY.labels(searchClass.value, environment, indexType).time(): searchValue = cls._normalize(searchValue) entry = store.findUnique( SearchEntry, AND(SearchEntry.searchClass == searchClass.value, SearchEntry.environment == environment, SearchEntry.indexType == indexType, SearchEntry.result == result, SearchEntry.searchType == searchType), None) if entry is None: if searchValue != u'': SearchEntry(store=store, searchClass=searchClass.value, environment=environment, indexType=indexType, result=result, searchType=searchType, searchValue=searchValue) else: if searchValue == u'': entry.deleteFromStore() else: entry.searchValue = searchValue @classmethod def remove(cls, store, searchClass, environment, indexType, result, searchType): """ Remove an entry from the search index. @see: L{SearchEntry} """ with METRIC_SEARCH_DELETE_LATENCY.labels(searchClass.value, environment, indexType).time(): store.query( SearchEntry, AND(SearchEntry.searchClass == searchClass.value, SearchEntry.environment == environment, SearchEntry.indexType == indexType, SearchEntry.result == result, SearchEntry.searchType == searchType)).deleteFromStore()
class LookupEntry(Item): """ An entry in the lookup index. Each combination of C{(environment, indexType, key)} identifies a unique item in the index. """ environment = text(doc=""" The environment in which this entry exists. Usually something like C{u'prod'}. """, allowNone=False) indexType = text(doc=""" The index type for this index entry. Usually something like C{u'idNumber'}. """, allowNone=False) key = text(doc=""" The key for this index entry. """, allowNone=False) value = bytes(doc=""" The value for this index entry. """, allowNone=False, default=b'') compoundIndex(environment, indexType, key) @classmethod def get(cls, store, environment, indexType, key): """ Get the value of an index entry. @type store: L{axiom.store.Store} @param store: The store to use. @type environment: L{unicode} @param environment: The environment. @type indexType: L{unicode} @param indexType: The type. @type key: L{unicode} @param key: The key. @raises KeyError: if the entry does not exist. """ with METRIC_LOOKUP_QUERY_LATENCY.labels(environment, indexType).time(): return store.findUnique( cls, AND(cls.environment == environment, cls.indexType == indexType, cls.key == key)).value @classmethod def set(cls, store, environment, indexType, key, value): """ Set the value of an index entry. If the entry already exists in the index, the previous value will be overwritten. @type store: L{axiom.store.Store} @param store: The store to use. @type environment: L{unicode} @param environment: The environment. @type indexType: L{unicode} @param indexType: The type. @type key: L{unicode} @param key: The key. @type value: L{bytes} @param value: The value to set. """ with METRIC_LOOKUP_INSERT_LATENCY.labels(environment, indexType).time(): item = store.findOrCreate( cls, environment=environment, indexType=indexType, key=key) item.value = value