예제 #1
0
파일: factoid.py 프로젝트: rsnyman/ibid
    def search(self, event, limit, search_type, pattern, start):
        limit = limit and min(int(limit), self.limit) or self.default
        start = start and max(int(start) - 1, 0) or 0

        search_type = search_type and search_type.lower() or u""

        origpattern = pattern
        m = self.regex_re.match(pattern)
        is_regex = False
        if m:
            pattern = m.group(1)
            is_regex = bool(m.group(2))

        # Hack: We replace $arg with _%, but this won't match a partial
        # "$arg" string
        if is_regex:
            filter_op = get_regexp_op(event.session)
            name_pattern = pattern.replace(r'\$arg', '_%')
        else:
            filter_op = lambda x, y: x.like(y, escape='#')
            pattern = '%%%s%%' % escape_like_re.sub(r'#\1', pattern)
            name_pattern = pattern.replace('$arg', '#_#%')

        query = event.session.query(Factoid)\
                             .join(Factoid.names).add_entity(FactoidName)\
                             .join(Factoid.values)

        if search_type.startswith('fact'):
            query = query.filter(filter_op(FactoidName.name, name_pattern))
        elif search_type.startswith('value'):
            query = query.filter(filter_op(FactoidValue.value, pattern))
        else:
            query = query.filter(
                or_(filter_op(FactoidName.name, name_pattern),
                    filter_op(FactoidValue.value, pattern)))

        # Pre-evalute the iterable or the if statement will be True in SQLAlchemy 0.4. LP: #383286
        matches = [match for match in query.all()]

        bounded_matches = matches[start:start + limit]
        if bounded_matches:
            event.addresponse(u'; '.join(
                u'%s [%s]' % (fname.name, len(factoid.values))
                for factoid, fname in bounded_matches))
        elif len(matches):
            event.addresponse(
                u"I could only find %(number)d things that matched '%(pattern)s'",
                {
                    u'number': len(matches),
                    u'pattern': origpattern,
                })
        else:
            event.addresponse(u"I couldn't find anything that matched '%s'" %
                              origpattern)
예제 #2
0
    def search(self, event, limit, search_type, pattern, start):
        limit = limit and min(int(limit), self.limit) or self.default
        start = start and max(int(start) - 1, 0) or 0

        search_type = search_type and search_type.lower() or u""

        origpattern = pattern
        m = self.regex_re.match(pattern)
        is_regex = False
        if m:
            pattern = m.group(1)
            is_regex = bool(m.group(2))

        # Hack: We replace $arg with _%, but this won't match a partial
        # "$arg" string
        if is_regex:
            filter_op = get_regexp_op(event.session)
            name_pattern = pattern.replace(r'\$arg', '_%')
        else:
            filter_op = lambda x, y: x.like(y, escape='#')
            pattern = '%%%s%%' % escape_like_re.sub(r'#\1', pattern)
            name_pattern = pattern.replace('$arg', '#_#%')

        query = event.session.query(Factoid)\
                             .join(Factoid.names).add_entity(FactoidName)\
                             .join(Factoid.values)

        if search_type.startswith('fact'):
            query = query.filter(filter_op(FactoidName.name, name_pattern))
        elif search_type.startswith('value'):
            query = query.filter(filter_op(FactoidValue.value, pattern))
        else:
            query = query.filter(or_(filter_op(FactoidName.name, name_pattern),
                                     filter_op(FactoidValue.value, pattern)))

        # Pre-evalute the iterable or the if statement will be True in SQLAlchemy 0.4. LP: #383286
        matches = [match for match in query.all()]

        bounded_matches = matches[start:start+limit]
        if bounded_matches:
            event.addresponse(u'; '.join(
                u'%s [%s]' % (fname.name, len(factoid.values))
                for factoid, fname in bounded_matches))
        elif len(matches):
            event.addresponse(u"I could only find %(number)d things that matched '%(pattern)s'", {
                u'number': len(matches),
                u'pattern': origpattern,
            })
        else:
            event.addresponse(u"I couldn't find anything that matched '%s'" % origpattern)
예제 #3
0
def get_factoid(session, name, number, pattern, is_regex, all=False,
                literal=False):
    """session: SQLAlchemy session
    name: Factoid name (can contain arguments unless literal query)
    number: If not None, restrict to factoid[number] (or factoid[number:] for literal queries)
    pattern: If not None, restrict to factoids matching this pattern (cannot be used in conjuction with number)
    is_regex: Pattern is a real regex
    all: Return a random factoid from the set if False
    literal: Match factoid name literally (implies all)
    if all or literal, a list is returned; otherwise a single factoid is returned
    if nothing is found, either an empty list or None is returned
    """
    assert not (number and pattern), u'number and pattern cannot be used together'
    if literal:
        all = True # as mentioned in the docstring
    # First pass for exact matches, if necessary again for wildcard matches
    if literal:
        passes = (False,)
    else:
        passes = (False, True)
    for wild in passes:
        factoid = None
        query = session.query(Factoid)\
                .add_entity(FactoidName).join(Factoid.names)\
                .add_entity(FactoidValue).join(Factoid.values)
        if wild:
            # Reversed LIKE because factoid name contains SQL wildcards if
            # factoid supports arguments
            query = query.filter(
                    'lower(:fact) LIKE lower(name) ESCAPE :escape'
                ).params(fact=name, escape='\\')
        else:
            query = query.filter(FactoidName.name == escape_name(name))
        # For normal matches, restrict to the subset applicable
        if not literal:
            query = query.filter(FactoidName.wild == wild)

        if pattern:
            if is_regex:
                op = get_regexp_op(session)
                query = query.filter(op(FactoidValue.value, pattern))
            else:
                pattern = '%%%s%%' % escape_like_re.sub(r'#\1', pattern)
                query = query.filter(func.lower(FactoidValue.value)
                                     .like(pattern, escape='#'))

        if number is not None:
            number = max(0, int(number) - 1)
            try:
                # The .all() is to ensure the result is a list.
                # It gets len()ed later
                if literal:
                    return query.order_by(FactoidValue.id).all()[number:]
                else:
                    factoid = query.order_by(FactoidValue.id).all()[number]
            except IndexError:
                continue
        if all:
            if factoid is not None:
                return [factoid]
            else:
                factoid = query.all()
        else:
            factoid = factoid or query.order_by(func.random()).first()
        if factoid:
            return factoid
    if all:
        return []
    return None
예제 #4
0
파일: factoid.py 프로젝트: rsnyman/ibid
def get_factoid(session,
                name,
                number,
                pattern,
                is_regex,
                all=False,
                literal=False):
    """session: SQLAlchemy session
    name: Factoid name (can contain arguments unless literal query)
    number: If not None, restrict to factoid[number] (or factoid[number:] for literal queries)
    pattern: If not None, restrict to factoids matching this pattern (cannot be used in conjuction with number)
    is_regex: Pattern is a real regex
    all: Return a random factoid from the set if False
    literal: Match factoid name literally (implies all)
    if all or literal, a list is returned; otherwise a single factoid is returned
    if nothing is found, either an empty list or None is returned
    """
    assert not (number
                and pattern), u'number and pattern cannot be used together'
    if literal:
        all = True  # as mentioned in the docstring
    # First pass for exact matches, if necessary again for wildcard matches
    if literal:
        passes = (False, )
    else:
        passes = (False, True)
    for wild in passes:
        factoid = None
        query = session.query(Factoid)\
                .add_entity(FactoidName).join(Factoid.names)\
                .add_entity(FactoidValue).join(Factoid.values)
        if wild:
            # Reversed LIKE because factoid name contains SQL wildcards if
            # factoid supports arguments
            query = query.filter(
                'lower(:fact) LIKE lower(name) ESCAPE :escape').params(
                    fact=name, escape='\\')
        else:
            query = query.filter(FactoidName.name == escape_name(name))
        # For normal matches, restrict to the subset applicable
        if not literal:
            query = query.filter(FactoidName.wild == wild)

        if pattern:
            if is_regex:
                op = get_regexp_op(session)
                query = query.filter(op(FactoidValue.value, pattern))
            else:
                pattern = '%%%s%%' % escape_like_re.sub(r'#\1', pattern)
                query = query.filter(
                    func.lower(FactoidValue.value).like(pattern, escape='#'))

        if number is not None:
            number = max(0, int(number) - 1)
            try:
                # The .all() is to ensure the result is a list.
                # It gets len()ed later
                if literal:
                    return query.order_by(FactoidValue.id).all()[number:]
                else:
                    factoid = query.order_by(FactoidValue.id).all()[number]
            except IndexError:
                continue
        if all:
            if factoid is not None:
                return [factoid]
            else:
                factoid = query.all()
        else:
            factoid = factoid or query.order_by(func.random()).first()
        if factoid:
            return factoid
    if all:
        return []
    return None