<commit_before>from typing import (
    Dict,
    Iterable,
)

from fireant.dataset.totals import scrub_totals_from_share_results
from fireant.reference_helpers import reference_alias
from fireant.utils import (
    alias_selector,
    immutable,
)
from .query_builder import (
    QueryBuilder,
    QueryException,
    ReferenceQueryBuilderMixin,
    WidgetQueryBuilderMixin,
    add_hints,
)
from .. import special_cases
from ..execution import fetch_data
from ..field_helper import initialize_orders
from ..finders import (
    find_and_group_references_for_dimensions,
    find_metrics_for_widgets,
    find_operations_for_widgets,
    find_share_dimensions,
)
from ..pagination import paginate
from ..sql_transformer import make_slicer_query_with_totals_and_references


class DataSetQueryBuilder(
    ReferenceQueryBuilderMixin, WidgetQueryBuilderMixin, QueryBuilder
):
    """
    Data Set queries consist of widgets, dimensions, filters, orders by and references. At least one or more widgets
    is required. All others are optional.
    """

    def __init__(self, dataset):
        super(DataSetQueryBuilder, self).__init__(dataset, dataset.table)
        self._totals_dimensions = set()
        self._apply_filter_to_totals = []

    def __call__(self, *args, **kwargs):
        return self

    @immutable
    def filter(self, *filters, apply_to_totals=True):
        """
        Add one or more filters when building a dataset query.

        :param filters:
            Filters to add to the query
        :param apply_to_totals:
            Whether filters should apply to totals or not
        :return:
            A copy of the query with the filters added.
        """
        self._filters += [f for f in filters]
        self._apply_filter_to_totals += [apply_to_totals] * len(filters)

    @property
    def reference_groups(self):
        return list(
            find_and_group_references_for_dimensions(
                self._dimensions, self._references
            ).values()
        )

    @property
    def sql(self):
        """
        Serialize this query builder to a list of Pypika/SQL queries. This function will return one query for every
        combination of reference and rolled up dimension (including null options).

        This collects all of the metrics in each widget, dimensions, and filters and builds a corresponding pypika query
        to fetch the data.  When references are used, the base query normally produced is wrapped in an outer query and
        a query for each reference is joined based on the referenced dimension shifted.

        :return: a list of Pypika's Query subclass instances.
        """
        # First run validation for the query on all widgets
        self._validate()

        metrics = find_metrics_for_widgets(self._widgets)
        operations = find_operations_for_widgets(self._widgets)
        share_dimensions = find_share_dimensions(self._dimensions, operations)
        orders = initialize_orders(self._orders, self._dimensions)

        return make_slicer_query_with_totals_and_references(
            self.dataset,
            self.dataset.database,
            self.table,
            self.dataset.joins,
            self._dimensions,
            metrics,
            operations,
            self._filters,
            self._references,
            orders,
            share_dimensions=share_dimensions,
        )

    def fetch(self, hint=None) -> Iterable[Dict]:
        """
        Fetch the data for this query and transform it into the widgets.

        :param hint:
            A query hint label used with database vendors which support it. Adds a label comment to the query.
        :return:
            A list of dict (JSON) objects containing the widget configurations.
        """
        queries = add_hints(self.sql, hint)

        operations = find_operations_for_widgets(self._widgets)
        share_dimensions = find_share_dimensions(self._dimensions, operations)

        data_frame = fetch_data(
            self.dataset.database,
            queries,
            self._dimensions,
            share_dimensions,
            self.reference_groups,
        )

        # Apply operations
        for operation in operations:
            for reference in [None] + self._references:
                df_key = alias_selector(reference_alias(operation, reference))
                data_frame[df_key] = operation.apply(data_frame, reference)

        data_frame = scrub_totals_from_share_results(data_frame, self._dimensions)
        data_frame = special_cases.apply_operations_to_data_frame(
            operations, data_frame
        )
        data_frame = paginate(
            data_frame,
            self._widgets,
            orders=self._orders,
            limit=self._limit,
            offset=self._offset,
        )

        # Apply transformations
        return [
            widget.transform(
                data_frame, self.dataset, self._dimensions, self._references
            )
            for widget in self._widgets
        ]

    def plot(self):
        try:<commit_msg>Fixed the fetch function in DataSetQueryBuilder to handle queries where no order is specified<commit_after>from typing import (
    Dict,
    Iterable,
)

from fireant.dataset.totals import scrub_totals_from_share_results
from fireant.reference_helpers import reference_alias
from fireant.utils import (
    alias_selector,
    immutable,
)
from .query_builder import (
    QueryBuilder,
    QueryException,
    ReferenceQueryBuilderMixin,
    WidgetQueryBuilderMixin,
    add_hints,
)
from .. import special_cases
from ..execution import fetch_data
from ..field_helper import initialize_orders
from ..finders import (
    find_and_group_references_for_dimensions,
    find_metrics_for_widgets,
    find_operations_for_widgets,
    find_share_dimensions,
)
from ..pagination import paginate
from ..sql_transformer import make_slicer_query_with_totals_and_references


class DataSetQueryBuilder(
    ReferenceQueryBuilderMixin, WidgetQueryBuilderMixin, QueryBuilder
):
    """
    Data Set queries consist of widgets, dimensions, filters, orders by and references. At least one or more widgets
    is required. All others are optional.
    """

    def __init__(self, dataset):
        super(DataSetQueryBuilder, self).__init__(dataset, dataset.table)
        self._totals_dimensions = set()
        self._apply_filter_to_totals = []

    def __call__(self, *args, **kwargs):
        return self

    @immutable
    def filter(self, *filters, apply_to_totals=True):
        """
        Add one or more filters when building a dataset query.

        :param filters:
            Filters to add to the query
        :param apply_to_totals:
            Whether filters should apply to totals or not
        :return:
            A copy of the query with the filters added.
        """
        self._filters += [f for f in filters]
        self._apply_filter_to_totals += [apply_to_totals] * len(filters)

    @property
    def reference_groups(self):
        return list(
            find_and_group_references_for_dimensions(
                self._dimensions, self._references
            ).values()
        )

    @property
    def sql(self):
        """
        Serialize this query builder to a list of Pypika/SQL queries. This function will return one query for every
        combination of reference and rolled up dimension (including null options).

        This collects all of the metrics in each widget, dimensions, and filters and builds a corresponding pypika query
        to fetch the data.  When references are used, the base query normally produced is wrapped in an outer query and
        a query for each reference is joined based on the referenced dimension shifted.

        :return: a list of Pypika's Query subclass instances.
        """
        # First run validation for the query on all widgets
        self._validate()

        metrics = find_metrics_for_widgets(self._widgets)
        operations = find_operations_for_widgets(self._widgets)
        share_dimensions = find_share_dimensions(self._dimensions, operations)
        orders = initialize_orders(self._orders, self._dimensions)

        return make_slicer_query_with_totals_and_references(
            self.dataset,
            self.dataset.database,
            self.table,
            self.dataset.joins,
            self._dimensions,
            metrics,
            operations,
            self._filters,
            self._references,
            orders,
            share_dimensions=share_dimensions,
        )

    def fetch(self, hint=None) -> Iterable[Dict]:
        """
        Fetch the data for this query and transform it into the widgets.

        :param hint:
            A query hint label used with database vendors which support it. Adds a label comment to the query.
        :return:
            A list of dict (JSON) objects containing the widget configurations.
        """
        queries = add_hints(self.sql, hint)

        operations = find_operations_for_widgets(self._widgets)
        share_dimensions = find_share_dimensions(self._dimensions, operations)
        orders = initialize_orders(self._orders, self._dimensions)

        data_frame = fetch_data(
            self.dataset.database,
            queries,
            self._dimensions,
            share_dimensions,
            self.reference_groups,
        )

        # Apply operations
        for operation in operations:
            for reference in [None] + self._references:
                df_key = alias_selector(reference_alias(operation, reference))
                data_frame[df_key] = operation.apply(data_frame, reference)

        data_frame = scrub_totals_from_share_results(data_frame, self._dimensions)
        data_frame = special_cases.apply_operations_to_data_frame(
            operations, data_frame
        )
        data_frame = paginate(
            data_frame,
            self._widgets,
            orders=orders,
            limit=self._limit,
            offset=self._offset,
        )

        # Apply transformations
        return [
            widget.transform(
                data_frame, self.dataset, self._dimensions, self._references
            )
            for widget in self._widgets
        ]

    def plot(self):
        try:
{'fraction_non_alphanumeric': 0.062070301152319166, 'fraction_numerical': 0.0, 'mean_word_length': 2.3762667538411244, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1684268', 'n_tokens_mistral': 2716, 'n_tokens_neox': 2649, 'n_words': 791}