示例#1
0
文件: search.py 项目: Syfaro/weasyl
def _find_without_media(userid, rating, limit,
                        search, within, cat, subcat, backid, nextid):
    type_code, type_letter, table, select, subtype = _TABLE_INFORMATION[search.find]

    # Begin statement
    statement_with = ""
    statement_from = ["FROM {table} content INNER JOIN profile ON content.userid = profile.userid"]
    statement_where = ["WHERE content.rating <= %(rating)s AND content.settings !~ '[fhm]'"]
    statement_group = []

    if search.find == "submit":
        statement_from.append("INNER JOIN submission_tags ON content.submitid = submission_tags.submitid")

    if search.required_includes:
        if search.find == "submit":
            statement_from.append("AND submission_tags.tags @> %(required_includes)s")
        else:
            statement_from.append("INNER JOIN searchmap{find} ON targetid = content.{select}")
            statement_where.append("AND searchmap{find}.tagid = ANY (%(required_includes)s)")
            statement_group.append(
                "GROUP BY content.{select}, profile.username HAVING COUNT(searchmap{find}.tagid) = %(required_include_count)s")

    # Submission category or subcategory
    if search.find == "submit":
        if subcat:
            statement_where.append("AND content.subtype = %(subcategory)s")
        elif cat:
            statement_where.append("AND content.subtype >= %(category)s AND content.subtype < %(category)s + 1000")

    if userid:
        if within == "notify":
            # Search within notifications
            statement_from.append("INNER JOIN welcome ON welcome.targetid = content.{select}")
            statement_where.append("AND welcome.userid = %(userid)s")
            statement_where.append({
                "submit": "AND welcome.type IN (2010, 2030, 2040)",
                "char": "AND welcome.type = 2050",
                "journal": "AND welcome.type IN (1010, 1020)",
            }[search.find])
        elif within == "fave":
            # Search within favorites
            statement_from.append("INNER JOIN favorite ON favorite.targetid = content.{select}")
            statement_where.append("AND favorite.userid = %(userid)s AND favorite.type = %(type)s")
        elif within == "friend":
            # Search within friends content
            statement_from.append(
                "INNER JOIN frienduser ON (frienduser.userid, frienduser.otherid) = (%(userid)s, content.userid)"
                " OR (frienduser.userid, frienduser.otherid) = (content.userid, %(userid)s)")
        elif within == "follow":
            # Search within following content
            statement_from.append(
                "INNER JOIN watchuser ON (watchuser.userid, watchuser.otherid) = (%(userid)s, content.userid)")

        # Search within rating
        if search.ratings:
            statement_where.append("AND content.rating = ANY (%(ratings)s)")

        # Blocked tags and ignored users
        statement_where.append("""
            AND NOT EXISTS (
                SELECT 0 FROM ignoreuser
                WHERE userid = %(userid)s
                    AND otherid = content.userid)
        """)

        if search.find == "submit":
            statement_with = """
                WITH
                    bg AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 10),
                    bm AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 20),
                    ba AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 30),
                    bp AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 40)
            """

            statement_where.append("""
                AND NOT submission_tags.tags && (SELECT tags FROM bg)
                AND (content.rating < 20 OR NOT submission_tags.tags && (SELECT tags FROM bm))
                AND (content.rating < 30 OR NOT submission_tags.tags && (SELECT tags FROM ba))
                AND (content.rating < 40 OR NOT submission_tags.tags && (SELECT tags FROM bp))
            """)
        else:
            statement_where.append("""
                AND NOT EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid IN (SELECT tagid FROM blocktag WHERE userid = %(userid)s AND rating <= content.rating))
            """)

    if search.possible_includes:
        if search.find == "submit":
            statement_where.append("AND submission_tags.tags && %(possible_includes)s")
        else:
            statement_where.append("""
                AND EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid = ANY (%(possible_includes)s)
                )
            """)

    if search.required_excludes:
        if search.find == "submit":
            statement_where.append("AND NOT submission_tags.tags && %(required_excludes)s")
        else:
            statement_where.append("""
                AND NOT EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid = ANY (%(required_excludes)s)
                )
            """)

    if search.required_user_includes:
        statement_from.append("INNER JOIN login login_include ON content.userid = login_include.userid")
        statement_where.append("AND login_include.login_name = ANY (%(required_user_includes)s)")

    if search.required_user_excludes:
        statement_from.append("INNER JOIN login login_exclude ON content.userid = login_exclude.userid")
        statement_where.append("AND login_exclude.login_name != ALL (%(required_user_excludes)s)")

    def make_statement(statement_select, statement_additional_where, statement_order):
        return " ".join([
            statement_with,
            statement_select,
            " ".join(statement_from),
            " ".join(statement_where),
            statement_additional_where,
            " ".join(statement_group),
            statement_order,
        ]).format(
            table=table,
            find=search.find,
            select=select,
            subtype=subtype,
            title_field="char_name" if search.find == "char" else "title"
        )

    pagination_filter = (
        "AND content.{select} > %(backid)s" if backid else
        "AND content.{select} < %(nextid)s" if nextid else
        "")

    statement = make_statement(
        """
        SELECT
            content.{select}, content.{title_field} AS title, content.rating, content.unixtime, content.userid,
            content.settings, profile.username, {subtype} as subtype
        """,
        pagination_filter,
        "ORDER BY content.{{select}} {order} LIMIT %(limit)s".format(order="" if backid else "DESC"))

    all_names = (
        search.possible_includes |
        search.required_includes |
        search.required_excludes)

    tag_ids = searchtag.get_ids(all_names)

    def get_ids(names):
        return [tag_ids.get(name, -1) for name in names]

    params = {
        "possible_includes": get_ids(search.possible_includes),
        "required_includes": get_ids(search.required_includes),
        "required_excludes": get_ids(search.required_excludes),
        "required_user_includes": list(search.required_user_includes),
        "required_user_excludes": list(search.required_user_excludes),
        "type": type_letter,
        "userid": userid,
        "rating": rating,
        "ratings": list(search.ratings),
        "category": cat,
        "subcategory": subcat,
        "limit": limit,
        "count_limit": COUNT_LIMIT,
        "backid": backid,
        "nextid": nextid,
        "required_include_count": len(search.required_includes),
    }

    query = d.engine.execute(statement, params)

    ret = [{
        "contype": type_code,
        select: i[select],
        "title": i.title,
        "subtype": i.subtype,
        "rating": i.rating,
        "unixtime": i.unixtime,
        "userid": i.userid,
        "username": i.username,
        "settings": i.settings,
    } for i in query]

    if backid:
        # backid is the item after the last item (display-order-wise) on the
        # current page; the query will select items from there backwards,
        # including the current page. Subtract the number of items on the
        # current page to account for this, and add the maximum number of items
        # on a page to the count limit so it still comes out to the count limit
        # after subtracting if the limit is reached.
        back_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", pagination_filter, " LIMIT %(count_limit)s + %(limit)s) _"),
            params) - len(ret)
    elif nextid:
        # nextid is the item before the first item (display-order-wise) on the
        # current page; the query will select items from there backwards, so
        # the current page is not included and no subtraction or modification
        # of the limit is necessary.
        back_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", "AND content.{select} >= %(nextid)s", " LIMIT %(count_limit)s) _"),
            params)
    else:
        # The first page is being displayed; there’s nothing to go back to.
        back_count = 0

    if backid:
        # backid is the item after the last item (display-order-wise) on the
        # current page; the query will select items from there forwards, so the
        # current page is not included and no subtraction or modification of
        # the limit is necessary.
        next_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", "AND content.{select} <= %(backid)s", " LIMIT %(count_limit)s) _"),
            params)

        # The ORDER BY is reversed when a backid is specified in order to LIMIT
        # to the nearest items with a larger backid rather than the smallest
        # ones, so reverse the items back to display order here.
        return list(reversed(ret)), next_count, back_count
    else:
        # This is either the first page or a page based on a nextid. In both
        # cases, the query will include the items in the current page in the
        # count, so subtract the number of items on the current page to give a
        # count of items after this page, and add the maximum number of items
        # on a page to the count limit so it still comes out to the count limit
        # after subtracting if the limit is reached.
        next_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", pagination_filter, " LIMIT %(count_limit)s + %(limit)s) _"),
            params) - len(ret)

        return ret, next_count, back_count
示例#2
0
def _find_without_media(userid, rating, limit, search, within, cat, subcat,
                        backid, nextid):
    type_code, type_letter, table, select, subtype = _TABLE_INFORMATION[
        search.find]

    # Begin statement
    statement_with = ""
    statement_from = [
        "FROM {table} content INNER JOIN profile ON content.userid = profile.userid"
    ]
    statement_where = [
        "WHERE content.rating <= %(rating)s AND content.settings !~ '[fhm]'"
    ]
    statement_group = []

    if search.find == "submit":
        statement_from.append(
            "INNER JOIN submission_tags ON content.submitid = submission_tags.submitid"
        )

    if search.required_includes:
        if search.find == "submit":
            statement_from.append(
                "AND submission_tags.tags @> %(required_includes)s")
        else:
            statement_from.append(
                "INNER JOIN searchmap{find} ON targetid = content.{select}")
            statement_where.append(
                "AND searchmap{find}.tagid = ANY (%(required_includes)s)")
            statement_group.append(
                "GROUP BY content.{select}, profile.username HAVING COUNT(searchmap{find}.tagid) = %(required_include_count)s"
            )

    # Submission category or subcategory
    if search.find == "submit":
        if subcat:
            statement_where.append("AND content.subtype = %(subcategory)s")
        elif cat:
            statement_where.append(
                "AND content.subtype >= %(category)s AND content.subtype < %(category)s + 1000"
            )

    if userid:
        if within == "notify":
            # Search within notifications
            statement_from.append(
                "INNER JOIN welcome ON welcome.targetid = content.{select}")
            statement_where.append("AND welcome.userid = %(userid)s")
            statement_where.append({
                "submit":
                "AND welcome.type IN (2010, 2030, 2040)",
                "char":
                "AND welcome.type = 2050",
                "journal":
                "AND welcome.type IN (1010, 1020)",
            }[search.find])
        elif within == "fave":
            # Search within favorites
            statement_from.append(
                "INNER JOIN favorite ON favorite.targetid = content.{select}")
            statement_where.append(
                "AND favorite.userid = %(userid)s AND favorite.type = %(type)s"
            )
        elif within == "friend":
            # Search within friends content
            statement_from.append(
                "INNER JOIN frienduser ON (frienduser.userid, frienduser.otherid) = (%(userid)s, content.userid)"
                " OR (frienduser.userid, frienduser.otherid) = (content.userid, %(userid)s)"
            )
        elif within == "follow":
            # Search within following content
            statement_from.append(
                "INNER JOIN watchuser ON (watchuser.userid, watchuser.otherid) = (%(userid)s, content.userid)"
            )

        # Search within rating
        if search.ratings:
            statement_where.append("AND content.rating = ANY (%(ratings)s)")

        # Blocked tags and ignored users
        statement_where.append("""
            AND NOT EXISTS (
                SELECT 0 FROM ignoreuser
                WHERE userid = %(userid)s
                    AND otherid = content.userid)
        """)

        if search.find == "submit":
            statement_with = """
                WITH
                    bg AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 10),
                    bm AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 20),
                    ba AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 30),
                    bp AS (SELECT COALESCE(array_agg(tagid), ARRAY[]::INTEGER[]) AS tags FROM blocktag WHERE userid = %(userid)s AND rating = 40)
            """

            statement_where.append("""
                AND NOT submission_tags.tags && (SELECT tags FROM bg)
                AND (content.rating < 20 OR NOT submission_tags.tags && (SELECT tags FROM bm))
                AND (content.rating < 30 OR NOT submission_tags.tags && (SELECT tags FROM ba))
                AND (content.rating < 40 OR NOT submission_tags.tags && (SELECT tags FROM bp))
            """)
        else:
            statement_where.append("""
                AND NOT EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid IN (SELECT tagid FROM blocktag WHERE userid = %(userid)s AND rating <= content.rating))
            """)

    if search.possible_includes:
        if search.find == "submit":
            statement_where.append(
                "AND submission_tags.tags && %(possible_includes)s")
        else:
            statement_where.append("""
                AND EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid = ANY (%(possible_includes)s)
                )
            """)

    if search.required_excludes:
        if search.find == "submit":
            statement_where.append(
                "AND NOT submission_tags.tags && %(required_excludes)s")
        else:
            statement_where.append("""
                AND NOT EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid = ANY (%(required_excludes)s)
                )
            """)

    if search.required_user_includes:
        statement_from.append(
            "INNER JOIN login login_include ON content.userid = login_include.userid"
        )
        statement_where.append(
            "AND login_include.login_name = ANY (%(required_user_includes)s)")

    if search.required_user_excludes:
        statement_from.append(
            "INNER JOIN login login_exclude ON content.userid = login_exclude.userid"
        )
        statement_where.append(
            "AND login_exclude.login_name != ALL (%(required_user_excludes)s)")

    def make_statement(statement_select, statement_additional_where,
                       statement_order):
        return " ".join([
            statement_with,
            statement_select,
            " ".join(statement_from),
            " ".join(statement_where),
            statement_additional_where,
            " ".join(statement_group),
            statement_order,
        ]).format(
            table=table,
            find=search.find,
            select=select,
            subtype=subtype,
            title_field="char_name" if search.find == "char" else "title")

    pagination_filter = ("AND content.{select} > %(backid)s" if backid else
                         "AND content.{select} < %(nextid)s" if nextid else "")

    statement = make_statement(
        """
        SELECT
            content.{select}, content.{title_field} AS title, content.rating, content.unixtime, content.userid,
            content.settings, profile.username, {subtype} as subtype
        """, pagination_filter,
        "ORDER BY content.{{select}} {order} LIMIT %(limit)s".format(
            order="" if backid else "DESC"))

    all_names = (search.possible_includes | search.required_includes
                 | search.required_excludes)

    tag_ids = searchtag.get_ids(all_names)

    def get_ids(names):
        return [tag_ids.get(name, -1) for name in names]

    params = {
        "possible_includes": get_ids(search.possible_includes),
        "required_includes": get_ids(search.required_includes),
        "required_excludes": get_ids(search.required_excludes),
        "required_user_includes": list(search.required_user_includes),
        "required_user_excludes": list(search.required_user_excludes),
        "type": type_letter,
        "userid": userid,
        "rating": rating,
        "ratings": list(search.ratings),
        "category": cat,
        "subcategory": subcat,
        "limit": limit,
        "count_limit": COUNT_LIMIT,
        "backid": backid,
        "nextid": nextid,
        "required_include_count": len(search.required_includes),
    }

    query = d.engine.execute(statement, params)

    ret = [{
        "contype": type_code,
        select: i[select],
        "title": i.title,
        "subtype": i.subtype,
        "rating": i.rating,
        "unixtime": i.unixtime,
        "userid": i.userid,
        "username": i.username,
        "settings": i.settings,
    } for i in query]

    if backid:
        # backid is the item after the last item (display-order-wise) on the
        # current page; the query will select items from there backwards,
        # including the current page. Subtract the number of items on the
        # current page to account for this, and add the maximum number of items
        # on a page to the count limit so it still comes out to the count limit
        # after subtracting if the limit is reached.
        back_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", pagination_filter,
                           " LIMIT %(count_limit)s + %(limit)s) _"),
            params) - len(ret)
    elif nextid:
        # nextid is the item before the first item (display-order-wise) on the
        # current page; the query will select items from there backwards, so
        # the current page is not included and no subtraction or modification
        # of the limit is necessary.
        back_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1",
                           "AND content.{select} >= %(nextid)s",
                           " LIMIT %(count_limit)s) _"), params)
    else:
        # The first page is being displayed; there’s nothing to go back to.
        back_count = 0

    if backid:
        # backid is the item after the last item (display-order-wise) on the
        # current page; the query will select items from there forwards, so the
        # current page is not included and no subtraction or modification of
        # the limit is necessary.
        next_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1",
                           "AND content.{select} <= %(backid)s",
                           " LIMIT %(count_limit)s) _"), params)

        # The ORDER BY is reversed when a backid is specified in order to LIMIT
        # to the nearest items with a larger backid rather than the smallest
        # ones, so reverse the items back to display order here.
        return list(reversed(ret)), next_count, back_count
    else:
        # This is either the first page or a page based on a nextid. In both
        # cases, the query will include the items in the current page in the
        # count, so subtract the number of items on the current page to give a
        # count of items after this page, and add the maximum number of items
        # on a page to the count limit so it still comes out to the count limit
        # after subtracting if the limit is reached.
        next_count = d.engine.scalar(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", pagination_filter,
                           " LIMIT %(count_limit)s + %(limit)s) _"),
            params) - len(ret)

        return ret, next_count, back_count
示例#3
0
def select(userid, rating, limit, search, within, cat, subcat, backid, nextid):
    type_code, type_letter, table, select, subtype = _table_information[
        search.find]

    # Begin statement
    statement_from = [
        "FROM {table} content INNER JOIN profile ON content.userid = profile.userid"
    ]
    statement_where = [
        "WHERE content.rating <= %(rating)s AND content.settings !~ '[fhm]'"
    ]
    statement_group = []

    if search.find == "submit":
        statement_from.append(
            "INNER JOIN submission_tags ON content.submitid = submission_tags.submitid"
        )

    if search.required_includes:
        if search.find == "submit":
            statement_from.append(
                "AND submission_tags.tags @> %(required_includes)s")
        else:
            statement_from.append(
                "INNER JOIN searchmap{find} ON targetid = content.{select}")
            statement_where.append(
                "AND searchmap{find}.tagid = ANY (%(required_includes)s)")
            statement_group.append(
                "GROUP BY content.{select}, profile.username HAVING COUNT(searchmap{find}.tagid) = %(required_include_count)s"
            )

    # Submission category or subcategory
    if search.find == "submit":
        if subcat:
            statement_where.append("AND content.subtype = %(subcategory)s")
        elif cat:
            statement_where.append(
                "AND content.subtype >= %(category)s AND content.subtype < %(category)s + 1000"
            )

    if userid:
        if within == "notify":
            # Search within notifications
            statement_from.append(
                "INNER JOIN welcome ON welcome.targetid = content.{select}")
            statement_where.append("AND welcome.userid = %(userid)s")
            statement_where.append({
                "submit":
                "AND welcome.type IN (2010, 2030, 2040)",
                "char":
                "AND welcome.type = 2050",
                "journal":
                "AND welcome.type IN (1010, 1020)",
            }[search.find])
        elif within == "fave":
            # Search within favorites
            statement_from.append(
                "INNER JOIN favorite ON favorite.targetid = content.{select}")
            statement_where.append(
                "AND favorite.userid = %(userid)s AND favorite.type = %(type)s"
            )
        elif within == "friend":
            # Search within friends content
            statement_from.append(
                "INNER JOIN frienduser ON (frienduser.userid, frienduser.otherid) = (%(userid)s, content.userid)"
                " OR (frienduser.userid, frienduser.otherid) = (content.userid, %(userid)s)"
            )
        elif within == "follow":
            # Search within following content
            statement_from.append(
                "INNER JOIN watchuser ON (watchuser.userid, watchuser.otherid) = (%(userid)s, content.userid)"
            )

    # Search within rating
    if userid and search.ratings:
        statement_where.append("AND content.rating = ANY (%(ratings)s)")

    # Blocked tags and ignored users
    if userid:
        statement_where.append("""
            AND NOT EXISTS (
                SELECT 0 FROM ignoreuser
                WHERE userid = %(userid)s
                    AND otherid = content.userid)
            AND NOT EXISTS (
                SELECT 0 FROM searchmap{find}
                WHERE targetid = content.{select}
                    AND tagid IN (SELECT tagid FROM blocktag WHERE userid = %(userid)s AND rating <= content.rating))
        """)

    if search.possible_includes:
        if search.find == "submit":
            statement_where.append(
                "AND submission_tags.tags && %(possible_includes)s")
        else:
            statement_where.append("""
                AND EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid = ANY (%(possible_includes)s)
                )
            """)

    if search.required_excludes:
        if search.find == "submit":
            statement_where.append(
                "AND NOT submission_tags.tags && %(required_excludes)s")
        else:
            statement_where.append("""
                AND NOT EXISTS (
                    SELECT 0 FROM searchmap{find}
                    WHERE targetid = content.{select}
                        AND tagid = ANY (%(required_excludes)s)
                )
            """)

    if search.required_user_includes:
        statement_from.append(
            "INNER JOIN login login_include ON content.userid = login_include.userid"
        )
        statement_where.append(
            "AND login_include.login_name = ANY (%(required_user_includes)s)")

    if search.required_user_excludes:
        statement_from.append(
            "INNER JOIN login login_exclude ON content.userid = login_exclude.userid"
        )
        statement_where.append(
            "AND login_exclude.login_name != ALL (%(required_user_excludes)s)")

    def make_statement(statement_select, statement_additional_where,
                       statement_order):
        return " ".join([
            statement_select,
            " ".join(statement_from),
            " ".join(statement_where),
            statement_additional_where,
            " ".join(statement_group),
            statement_order,
        ]).format(
            table=table,
            find=search.find,
            select=select,
            subtype=subtype,
            title_field="char_name" if search.find == "char" else "title")

    pagination_filter = ("AND content.{select} > %(backid)s" if backid else
                         "AND content.{select} < %(nextid)s" if nextid else "")

    statement = make_statement(
        """
        SELECT
            content.{select}, content.{title_field} AS title, content.rating, content.unixtime, content.userid,
            content.settings, profile.username, {subtype} as subtype
        """, pagination_filter,
        "ORDER BY content.{{select}} {order} LIMIT %(limit)s".format(
            order="" if backid else "DESC"))

    all_names = (search.possible_includes | search.required_includes
                 | search.required_excludes)

    tag_ids = searchtag.get_ids(all_names)

    def get_ids(names):
        return [tag_ids.get(name, -1) for name in names]

    params = {
        "possible_includes": get_ids(search.possible_includes),
        "required_includes": get_ids(search.required_includes),
        "required_excludes": get_ids(search.required_excludes),
        "required_user_includes": list(search.required_user_includes),
        "required_user_excludes": list(search.required_user_excludes),
        "type": type_letter,
        "userid": userid,
        "rating": rating,
        "ratings": list(search.ratings),
        "category": cat,
        "subcategory": subcat,
        "limit": limit,
        "backid": backid,
        "nextid": nextid,
        "required_include_count": len(search.required_includes),
    }

    query = d.engine.execute(statement, **params)

    ret = [{
        "contype": type_code,
        select: i[select],
        "title": i.title,
        "subtype": i.subtype,
        "rating": i.rating,
        "unixtime": i.unixtime,
        "userid": i.userid,
        "username": i.username,
        "settings": i.settings,
    } for i in query]

    if search.find == "submit":
        media.populate_with_submission_media(ret)
    elif search.find == "char":
        for r in ret:
            r["sub_media"] = character.fake_media_items(
                r["charid"], r["userid"], d.get_sysname(r["username"]),
                r["settings"])
    elif search.find == "journal":
        media.populate_with_user_media(ret)

    if backid:
        back_count = d.engine.execute(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", pagination_filter,
                           ") _"), **params).scalar() - len(ret)
    elif nextid:
        back_count = (d.engine.execute(
            make_statement("SELECT COUNT(*) FROM (SELECT 1",
                           "AND content.{select} >= %(nextid)s", ") _"),
            **params).scalar())
    else:
        back_count = 0

    if backid:
        next_count = (d.engine.execute(
            make_statement("SELECT COUNT(*) FROM (SELECT 1",
                           "AND content.{select} <= %(backid)s", ") _"),
            **params).scalar())
        return list(reversed(ret)), next_count, back_count
    else:
        next_count = d.engine.execute(
            make_statement("SELECT COUNT(*) FROM (SELECT 1", pagination_filter,
                           ") _"), **params).scalar() - len(ret)
        return ret, next_count, back_count