Repository: pydantic/pydantic

Issue:
pydantic.utils.to_camel() is actually to_pascal()
### Checks

* [ y ] I added a descriptive title to this issue
* [ y ] I have searched (google, github) for similar issues and couldn't find anything
* [ y ] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

# Bug

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.8.1
            pydantic compiled: True
                 install path: /home/schlerp/projects/pelt-studio/venv/lib/python3.8/site-packages/pydantic
               python version: 3.8.5 (default, Sep  4 2020, 07:30:14)  [GCC 7.3.0]
                     platform: Linux-5.15.2-zen1-1-zen-x86_64-with-glibc2.10
     optional deps. installed: ['typing-extensions']
```

Camel case and pascal case are similar however, they differ by the capitalisation of the first letter. The current implementation of camel_case in pydantic us actually pascal case and not camel case at all. I suggest renaming this and also implementing a camel case. See below for code expressing the issue and suggested fix.

**Pascal Case** (aka init case or upper camel case)
All spaces/underscores removed and the start of every word is capitalised.

**Camel Case** (aka lower camel case)
All spaces and underscores removed and the start of every word, is capitalised, except the first word which is always lower case.


Issue:
```py
from pydantic.utils import to_camel

valid_pascal = "PascalCase"
valid_camel = "camelCase"

example = to_camel("i_shouldnt_be_capitalised")

assert valid_pascal == to_camel("pascal_case")
assert valid_camel != to_camel("camel_case")
```

suggested fix, rename `to_camel()` -> `to_pascal()`, and write new `to_camel()` function:

```py
def to_pascal(string: str) -> str:
    return "".join(word.capitalize() for word in string.split("_"))


def to_camel(string: str) -> str:
    if len(string) >= 1:
        pascal_string = to_pascal(string)
        return pascal_string[0].lower() + pascal_string[1:]
    return string.lower()

```

Alternatively, if there is code which will break because it is dependent on the `camel_case()` function remaining pascal case, then i propose we implement a new function called `to_lower_camel()` which implements the first letter lower case variant:

```py
def to_camel(string: str) -> str:
    return "".join(word.capitalize() for word in string.split("_"))


def to_lower_camel(string: str) -> str:
    if len(string) >= 1:
        pascal_string = to_camel(string)
        return pascal_string[0].lower() + pascal_string[1:]
    return string.lower()

```



Discussion:
after a debate today with a fellow programmer I had my eyes opened to the fact that pascal case is a type of camel case... so the naming isn't wrong.

I think ill submit a PR of the second option, as I'm sure I'm not the only one that would make use of the `to_lower_camel()` function.

Resolving patch:
diff --git a/pydantic/utils.py b/pydantic/utils.py
--- a/pydantic/utils.py
+++ b/pydantic/utils.py
@@ -303,6 +303,13 @@ def to_camel(string: str) -> str:
     return ''.join(word.capitalize() for word in string.split('_'))
 
 
+def to_lower_camel(string: str) -> str:
+    if len(string) >= 1:
+        pascal_string = to_camel(string)
+        return pascal_string[0].lower() + pascal_string[1:]
+    return string.lower()
+
+
 T = TypeVar('T')
 
 


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -37,6 +37,7 @@
     lenient_issubclass,
     path_type,
     smart_deepcopy,
+    to_lower_camel,
     truncate,
     unique_list,
 )
@@ -528,6 +529,18 @@ def test_undefined_pickle():
     assert undefined2 is Undefined
 
 
+def test_on_lower_camel_zero_length():
+    assert to_lower_camel('') == ''
+
+
+def test_on_lower_camel_one_length():
+    assert to_lower_camel('a') == 'a'
+
+
+def test_on_lower_camel_many_length():
+    assert to_lower_camel('i_like_turtles') == 'iLikeTurtles'
+
+
 def test_limited_dict():
     d = LimitedDict(10)
     d[1] = '1'