<commit_before>#
# Copyright 2013, Couchbase, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License")
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from collections import namedtuple
from copy import deepcopy
from warnings import warn

from couchbase.exceptions import ArgumentError, CouchbaseError, ViewEngineError
from couchbase.views.params import ViewQuery, SpatialQuery, QueryBase
from couchbase._pyport import basestring
import couchbase._libcouchbase as C
from couchbase._bootstrap import MAX_URI_LENGTH

class AlreadyQueriedError(CouchbaseError):
    """Thrown when iterating over a View which was already iterated over"""


ViewRow = namedtuple('ViewRow', ['key', 'value', 'docid', 'doc'])
"""
Default class for a single row.
"""

SpatialRow = namedtuple('SpatialRow',
                        ['key', 'value', 'geometry', 'docid', 'doc'])
"""
Default class for a spatial row
"""


class RowProcessor(object):
    """
    This class contains the handling and conversion functions between
    multiple rows and the means by which they are returned from the
    view iterator.

    This class should be overidden if you are:

    * Using a custom row class
        This saves on processing time and memory by converting from the raw
        results rather than having to unpack from the default class. This
        class returns a :class:`ViewRow` object by default. (This can also
        be overridden using the :attr:`rowclass` attribute)

    * Fetching multiple documents for each row
        You can use the :meth:`~couchbase.bucket.Bucket.get_multi`
        method to efficiently fetch multiple docs beforehand for the entire
        page.

    .. attribute:: rowclass

        Class or function to call for each result (row) received. This
        is called as ``rowclass(key, value, docid, doc)``

        * ``key`` is the key as returned by the first argument to the
            view function's ``emit``.
        * ``value`` is the value returned as the second argument to the
            view function's ``emit``, or the value of the ``reduce``
            function
        * ``docid`` is the ID of the document itself (as stored by one
            of the :meth:`~couchbase.bucket.Bucket.upsert` family of
            methods).
            If ``reduce`` was set to true for the view, this will always
            be None.
        * ``doc`` is the document itself - Only valid if ``include_docs``
            is set to true - in which case a
            :class:`~couchbase.connection.Result` object is passed.
            If ``reduce`` was set to true for the view, this will always
            be None
            Otherwise, ``None`` is passed instead.

        By default, the :class:`ViewRow` is used.
    """
    def __init__(self, rowclass=ViewRow):
        self.rowclass = rowclass

    def handle_rows(self, rows, *_):
        """
        Preprocesses a page of rows.

        :param list rows: A list of rows. Each row is a JSON object containing
            the decoded JSON of the view as returned from the server
        :param connection: The connection object (pass to the :class:`View`
            constructor)
        :param include_docs: Whether to include documents in the return value.
            This is ``True`` or ``False`` depending on what was passed to the
            :class:`View` constructor

        :return: an iterable. When the iterable is exhausted, this method will
            be called again with a new 'page'.
        """
        for row in rows:
            yield self.rowclass(row['key'], row['value'],
                                row.get('id'), row.get('__DOCRESULT__'))


class SpatialRowProcessor(RowProcessor):
    def __init__(self, rowclass=SpatialRow):
        super(SpatialRowProcessor, self).__init__(rowclass)

    def handle_rows(self, rows, *_):
        for row in rows:
            yield self.rowclass(row['key'], row['value'], row['geometry'],
                                row.get('id'), row.get('__DOCRESULT__'))


class View(object):
    def __init__(self, parent, design, view, row_processor=None,
                 include_docs=False, query=None, streaming=True, **params):
        """
        Construct a iterable which can be used to iterate over view query
        results.

        :param parent: The parent Bucket object
        :type parent: :class:`~couchbase.bucket.Bucket`<commit_msg>Add get_row_doc function to extract doc from row<commit_after>#
# Copyright 2013, Couchbase, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License")
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from collections import namedtuple
from copy import deepcopy
from warnings import warn

from couchbase.exceptions import ArgumentError, CouchbaseError, ViewEngineError
from couchbase.views.params import ViewQuery, SpatialQuery, QueryBase
from couchbase._pyport import basestring
import couchbase._libcouchbase as C
from couchbase._bootstrap import MAX_URI_LENGTH

class AlreadyQueriedError(CouchbaseError):
    """Thrown when iterating over a View which was already iterated over"""


ViewRow = namedtuple('ViewRow', ['key', 'value', 'docid', 'doc'])
"""
Default class for a single row.
"""

SpatialRow = namedtuple('SpatialRow',
                        ['key', 'value', 'geometry', 'docid', 'doc'])
"""
Default class for a spatial row
"""


class RowProcessor(object):
    """
    This class contains the handling and conversion functions between
    multiple rows and the means by which they are returned from the
    view iterator.

    This class should be overidden if you are:

    * Using a custom row class
        This saves on processing time and memory by converting from the raw
        results rather than having to unpack from the default class. This
        class returns a :class:`ViewRow` object by default. (This can also
        be overridden using the :attr:`rowclass` attribute)

    * Fetching multiple documents for each row
        You can use the :meth:`~couchbase.bucket.Bucket.get_multi`
        method to efficiently fetch multiple docs beforehand for the entire
        page.

    .. attribute:: rowclass

        Class or function to call for each result (row) received. This
        is called as ``rowclass(key, value, docid, doc)``

        * ``key`` is the key as returned by the first argument to the
            view function's ``emit``.
        * ``value`` is the value returned as the second argument to the
            view function's ``emit``, or the value of the ``reduce``
            function
        * ``docid`` is the ID of the document itself (as stored by one
            of the :meth:`~couchbase.bucket.Bucket.upsert` family of
            methods).
            If ``reduce`` was set to true for the view, this will always
            be None.
        * ``doc`` is the document itself - Only valid if ``include_docs``
            is set to true - in which case a
            :class:`~couchbase.connection.Result` object is passed.
            If ``reduce`` was set to true for the view, this will always
            be None
            Otherwise, ``None`` is passed instead.

        By default, the :class:`ViewRow` is used.
    """
    def __init__(self, rowclass=ViewRow):
        self.rowclass = rowclass

    def handle_rows(self, rows, *_):
        """
        Preprocesses a page of rows.

        :param list rows: A list of rows. Each row is a JSON object containing
            the decoded JSON of the view as returned from the server
        :param connection: The connection object (pass to the :class:`View`
            constructor)
        :param include_docs: Whether to include documents in the return value.
            This is ``True`` or ``False`` depending on what was passed to the
            :class:`View` constructor

        :return: an iterable. When the iterable is exhausted, this method will
            be called again with a new 'page'.
        """
        for row in rows:
            yield self.rowclass(row['key'], row['value'],
                                row.get('id'), get_row_doc(row))


class SpatialRowProcessor(RowProcessor):
    def __init__(self, rowclass=SpatialRow):
        super(SpatialRowProcessor, self).__init__(rowclass)

    def handle_rows(self, rows, *_):
        for row in rows:
            yield self.rowclass(row['key'], row['value'], row['geometry'],
                                row.get('id'), get_row_doc(row))


def get_row_doc(row_json):
    """
    Gets the document for the given parsed JSON row.

    Use this function in custom :class:`~.RowProcessor`
    implementations to extract the actual document. The document
    itself is stored within a private field of the row itself, and
    should only be accessed by this function.

    :param dict row_json: The parsed row (passed to the processor)
    :return: The document, or None
    """
    return row_json.get('__DOCRESULT__')


class View(object):
    def __init__(self, parent, design, view, row_processor=None,
                 include_docs=False, query=None, streaming=True, **params):
        """
        Construct a iterable which can be used to iterate over view query
        results.

        :param parent: The parent Bucket object
        :type parent: :class:`~couchbase.bucket.Bucket`
{'fraction_non_alphanumeric': 0.08393873944629884, 'fraction_numerical': 0.0015707834282348322, 'mean_word_length': 2.7397209985315714, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '1752434', 'n_tokens_mistral': 2665, 'n_tokens_neox': 2577, 'n_words': 1159}