def _Word(self, node, fieldname):
        value = node[0]
        if fieldname:
            like = False
            try:
                if value.endswith('*'):
                    value = value.replace('*', '%')
                    like = True
            except TypeError:
                # Hack around field values containing parens
                # The node[0] is a non-string if that's the case.
                node[0] = '(' + value[0] + ')'
                return self._Word(node, fieldname)

            if fieldname == 'ftitle':
                fieldname = 'title'
            if fieldname == 'fbag':
                fieldname = 'bag'

            if fieldname == 'bag':
                if like:
                    expression = (sTiddler.bag.like(value))
                else:
                    expression = (sTiddler.bag == value)
            elif fieldname == 'title':
                if like:
                    expression = (sTiddler.title.like(value))
                else:
                    expression = (sTiddler.title == value)
            elif fieldname == 'id':
                bag, title = value.split(':', 1)
                expression = and_(sTiddler.bag == bag,
                        sTiddler.title == title)
            elif fieldname == 'tag':
                if self.in_and:
                    tag_alias = aliased(sTag)
                    self.query = self.query.join(tag_alias)
                    if like:
                        expression = (tag_alias.tag.like(value))
                    else:
                        expression = (tag_alias.tag == value)
                else:
                    if not self.joined_tags:
                        self.query = self.query.join(sTag)
                        if like:
                            expression = (sTag.tag.like(value))
                        else:
                            expression = (sTag.tag == value)
                        self.joined_tags = True
                    else:
                        if like:
                            expression = (sTag.tag.like(value))
                        else:
                            expression = (sTag.tag == value)
            elif fieldname == 'near' and self.geo:
                # proximity search on geo.long, geo.lat based on
                # http://cdent.tiddlyspace.com/bags/cdent_public/tiddlers/Proximity%20Search.html
                try:
                    lat, long, radius = [float(item)
                            for item in value.split(',', 2)]
                except ValueError, exc:
                    raise StoreError(
                            'failed to parse search query, malformed near: %s'
                            % exc)
                field_alias1 = aliased(sField)
                field_alias2 = aliased(sField)
                distance = label(u'greatcircle', (6371000
                    * func.acos(
                        func.cos(
                            func.radians(lat))
                        * func.cos(
                            func.radians(field_alias2.value))
                        * func.cos(
                            func.radians(field_alias1.value)
                            - func.radians(long))
                        + func.sin(
                            func.radians(lat))
                        * func.sin(
                            func.radians(field_alias2.value)))))
                self.query = self.query.add_columns(distance)
                self.query = self.query.join(field_alias1)
                self.query = self.query.join(field_alias2)
                self.query = self.query.having(
                        u'greatcircle < %s' % radius).order_by('greatcircle')
                expression = and_(field_alias1.name == u'geo.long',
                        field_alias2.name == u'geo.lat')
                self.limit = 20  # XXX: make this passable
            elif fieldname == '_limit':
                try:
                    self.limit = int(value)
                except ValueError:
                    pass
                self.query = self.query.order_by(
                        sRevision.modified.desc())
                expression = None
            elif fieldname == 'text':
                if not self.joined_text:
                    self.query = self.query.join(sText)
                    self.joined_text = True
                if self.fulltext:
                    expression = (text_(
                        'MATCH(text.text) '
                        + "AGAINST('%s' in boolean mode)" % value))
                else:
                    value = '%' + value + '%'
                    expression = sText.text.like(value)
            elif fieldname in ['modifier', 'modified', 'type']:
                if like:
                    expression = (getattr(sRevision,
                        fieldname).like(value))
                else:
                    expression = (getattr(sRevision,
                        fieldname) == value)
            else:
                if self.in_and:
                    field_alias = aliased(sField)
                    self.query = self.query.join(field_alias)
                    expression = (field_alias.name == fieldname)
                    if like:
                        expression = and_(expression,
                                field_alias.value.like(value))
                    else:
                        expression = and_(expression,
                                field_alias.value == value)
                else:
                    if not self.joined_fields:
                        self.query = self.query.join(sField)
                        expression = (sField.name == fieldname)
                        if like:
                            expression = and_(expression,
                                    sField.value.like(value))
                        else:
                            expression = and_(expression,
                                    sField.value == value)
                        self.joined_fields = True
                    else:
                        expression = (sField.name == fieldname)
                        if like:
                            expression = and_(expression,
                                    sField.value.like(value))
                        else:
                            expression = and_(expression,
                                    sField.value == value)
                        self.joined_fields = True
                    else:
                        expression = (sField.name == fieldname)
                        if like:
                            expression = and_(expression,
                                    sField.value.like(value))
                        else:
                            expression = and_(expression,
                                    sField.value == value)
        else:
            if not self.joined_text:
                self.query = self.query.join(sText)
                self.joined_text = True
            if self.fulltext:
                expression = (text_(
                    'MATCH(text.text) '
                    + "AGAINST('%s' in boolean mode)" % value))
            else:
                value = '%' + value + '%'
                expression = sText.text.like(value)
        return expression

    def _Field(self, node, fieldname):
        return self._Word(node[1], node[0])

    def _Group(self, node, fieldname):
        expressions = []
        for subnode in node:
            expressions.append(self._eval(subnode, fieldname))
        return and_(*expressions)