<commit_before>"""
CursorWrapper (like django.db.backends.utils)
"""
import decimal
import logging
import warnings
from typing import Any, Callable, Tuple, TypeVar, Union, overload

from django.db import models, NotSupportedError
from django.db.models.sql import subqueries, Query, RawQuery

from salesforce.backend import DJANGO_30_PLUS
from salesforce.dbapi.driver import (
    DatabaseError, InternalError, SalesforceWarning, merge_dict,
    register_conversion, arg_to_json)
from salesforce.fields import NOT_UPDATEABLE, NOT_CREATEABLE

if not DJANGO_30_PLUS:
    # a "do nothing" stub for Django < 3.0, where is no decorator @async_unsafe
    F = TypeVar('F', bound=Callable)
    F2 = TypeVar('F2', bound=Callable)

    @overload
    def async_unsafe(message: F) -> F:
        ...

    @overload
    def async_unsafe(message: str) -> Callable[[F2], F2]:
        ...

    def async_unsafe(message: Union[F, str]) -> Union[F, Callable[[F2], F2]]:
        def decorator(func: F2) -> F2:
            return func

        # If the message is actually a function, then be a no-arguments decorator.
        if callable(message):
            func = message
            message = 'You cannot call this from an async context - use a thread or sync_to_async.'
            return decorator(func)
        return decorator
else:

    from django.utils.asyncio import (  # type: ignore[import,no-redef] # noqa pylint:disable=unused-import,ungrouped-imports
        async_unsafe
    )

log = logging.getLogger(__name__)


DJANGO_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f-00:00'

MIGRATIONS_QUERY_TO_BE_IGNORED = "SELECT django_migrations.app, django_migrations.name FROM django_migrations"


def extract_values(query):
    """
    Extract values from insert or update query.
    Supports bulk_create
    """
    if isinstance(query, subqueries.UpdateQuery):
        row = query.values
        return extract_values_inner(row, query)
    if isinstance(query, subqueries.InsertQuery):
        ret = []
        for row in query.objs:
            ret.append(extract_values_inner(row, query))
        return ret
    raise NotSupportedError


def extract_values_inner(row, query):
    d = dict()
    fields = query.model._meta.fields
    for _, field in enumerate(fields):
        sf_read_only = getattr(field, 'sf_read_only', 0)
        if field.get_internal_type() == 'AutoField':
            continue
        if isinstance(query, subqueries.UpdateQuery):
            if (sf_read_only & NOT_UPDATEABLE) != 0:
                continue
            value_or_empty = [value for qfield, model, value in query.values if qfield.name == field.name]
            if value_or_empty:
                [value] = value_or_empty
            else:
                assert len(query.values) < len(fields), \
                    "Match name can miss only with an 'update_fields' argument."
                continue
            if hasattr(value, 'default'):
                warnings.warn(
                    "The field '{}.{}' has not been saved again with DEFAULTED_ON_CREATE value. "
                    "It is better to set a real value to it or to refresh it from the database "
                    "or restrict updated fields explicitly by 'update_fields='."
                    .format(field.model._meta.object_name, field.name),
                    SalesforceWarning
                )
                continue
        elif isinstance(query, subqueries.InsertQuery):
            value = getattr(row, field.attname)
            if (sf_read_only & NOT_CREATEABLE) != 0 or hasattr(value, 'default'):
                continue  # skip not createable or DEFAULTED_ON_CREATE
        else:
            raise InternalError('invalid query type')
        d[field.column] = arg_to_json(value)
    return d


class CursorWrapper:
    """
    A wrapper that emulates the behavior of a database cursor.

    This is the class that is actually responsible for making connections
    to the SF REST API
    """

    # pylint:disable=too-many-instance-attributes,too-many-public-methods
    def __init__(self, db):
        """
        Connect to the Salesforce API.
        """<commit_msg>Fix typo if a field with DEFAULTED_ON_CREATE is saved again without refresh<commit_after>"""
CursorWrapper (like django.db.backends.utils)
"""
import decimal
import logging
import warnings
from typing import Any, Callable, Tuple, TypeVar, Union, overload

from django.db import models, NotSupportedError
from django.db.models.sql import subqueries, Query, RawQuery

from salesforce.backend import DJANGO_30_PLUS
from salesforce.dbapi.driver import (
    DatabaseError, InternalError, SalesforceWarning, merge_dict,
    register_conversion, arg_to_json)
from salesforce.fields import NOT_UPDATEABLE, NOT_CREATEABLE

if not DJANGO_30_PLUS:
    # a "do nothing" stub for Django < 3.0, where is no decorator @async_unsafe
    F = TypeVar('F', bound=Callable)
    F2 = TypeVar('F2', bound=Callable)

    @overload
    def async_unsafe(message: F) -> F:
        ...

    @overload
    def async_unsafe(message: str) -> Callable[[F2], F2]:
        ...

    def async_unsafe(message: Union[F, str]) -> Union[F, Callable[[F2], F2]]:
        def decorator(func: F2) -> F2:
            return func

        # If the message is actually a function, then be a no-arguments decorator.
        if callable(message):
            func = message
            message = 'You cannot call this from an async context - use a thread or sync_to_async.'
            return decorator(func)
        return decorator
else:

    from django.utils.asyncio import (  # type: ignore[import,no-redef] # noqa pylint:disable=unused-import,ungrouped-imports
        async_unsafe
    )

log = logging.getLogger(__name__)


DJANGO_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f-00:00'

MIGRATIONS_QUERY_TO_BE_IGNORED = "SELECT django_migrations.app, django_migrations.name FROM django_migrations"


def extract_values(query):
    """
    Extract values from insert or update query.
    Supports bulk_create
    """
    if isinstance(query, subqueries.UpdateQuery):
        row = query.values
        return extract_values_inner(row, query)
    if isinstance(query, subqueries.InsertQuery):
        ret = []
        for row in query.objs:
            ret.append(extract_values_inner(row, query))
        return ret
    raise NotSupportedError


def extract_values_inner(row, query):
    d = dict()
    fields = query.model._meta.fields
    for _, field in enumerate(fields):
        sf_read_only = getattr(field, 'sf_read_only', 0)
        if field.get_internal_type() == 'AutoField':
            continue
        if isinstance(query, subqueries.UpdateQuery):
            if (sf_read_only & NOT_UPDATEABLE) != 0:
                continue
            value_or_empty = [value for qfield, model, value in query.values if qfield.name == field.name]
            if value_or_empty:
                [value] = value_or_empty
            else:
                assert len(query.values) < len(fields), \
                    "Match name can miss only with an 'update_fields' argument."
                continue
            if hasattr(value, 'default'):
                warnings.warn(
                    "The field '{}.{}' has been saved again with DEFAULTED_ON_CREATE value. "
                    "It is better to set a real value to it or to refresh it from the database "
                    "or restrict updated fields explicitly by 'update_fields='."
                    .format(field.model._meta.object_name, field.name),
                    SalesforceWarning
                )
                continue
        elif isinstance(query, subqueries.InsertQuery):
            value = getattr(row, field.attname)
            if (sf_read_only & NOT_CREATEABLE) != 0 or hasattr(value, 'default'):
                continue  # skip not createable or DEFAULTED_ON_CREATE
        else:
            raise InternalError('invalid query type')
        d[field.column] = arg_to_json(value)
    return d


class CursorWrapper:
    """
    A wrapper that emulates the behavior of a database cursor.

    This is the class that is actually responsible for making connections
    to the SF REST API
    """

    # pylint:disable=too-many-instance-attributes,too-many-public-methods
    def __init__(self, db):
        """
        Connect to the Salesforce API.
        """
{'fraction_non_alphanumeric': 0.08875029983209402, 'fraction_numerical': 0.005037179179659391, 'mean_word_length': 2.467359667359667, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, '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': '6858573', 'n_tokens_mistral': 2433, 'n_tokens_neox': 2346, 'n_words': 698}