PyMySQLで任意のDictCursorを作って、NULLのときにNoneを返さない方法

# 前置き

PyMySQL使ってますか?
え?ORM使ってるからそんなもん使わない?

まぁまぁ、ORMはORMでめんどくさいときがあるじゃないですか。
チョクでSQL書いたら楽なときもあるでしょ?


# でPyMySQL

```python
import pymysql.cursors

# Connect to the database
connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             db='db',
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)

with connection.cursor() as cursor:
        # Create a new record
        sql = "SELECT * from users where first_name = 'bob'"
        cursor.execute(sql, connection)

```

とか。

`cursorclass=pymysql.cursors.DictCursor` ってのが便利です。

```python

{'name': 'bob', 'id': 1}

```

のようにDictを返してくれるからです。

でもこれ。NULLがあるとこうなるんですわ。

```python

[{'first_name': 'bob', 'last_name': 'smith', 'id': 1, 'phone_num': None},
{'first_name': 'bob', 'last_name': 'jones', 'id': 2, 'phone_num': None}]

```

`None` じゃなくて`"NULL"`って返してほしい。
`NULL`のときは`"NULL"`って返せって仕様書にあるんだもん。

んで戻り値を`for i in ...:` とかやって置き換えてませんか?

# ソースコード

[DictCursor](https://github.com/PyMySQL/PyMySQL/blob/37fd1e1b0126d75d80eef59c053f80634b09bd75/pymysql/cursors.py#L383)ってなにやってんの?

```python
class DictCursor(DictCursorMixin, Cursor):
    """A cursor which returns results as a dictionary"""
```

なんも。
[DictCursorMixin](https://github.com/PyMySQL/PyMySQL/blob/37fd1e1b0126d75d80eef59c053f80634b09bd75/pymysql/cursors.py#L359)は?

```python
class DictCursorMixin(object):
    # You can override this to use OrderedDict or other dict-like types.
    dict_type = dict
```

「Dict-likeでオーバーライドしてね!」と。

[テスト](https://github.com/PyMySQL/PyMySQL/blob/37fd1e1b0126d75d80eef59c053f80634b09bd75/pymysql/tests/test_DictCursor.py#L77)でもやってるからやっていいんでしょうね

# じゃあ

```python
d = {"foo": "bar", "baz": None}

assert d["baz"] == "NULL"
```

こういうDict作ればいいんじゃね?

```python
class MyDict(dict):
    def __init__(self):
        # なんか処理する

```

とりあえずこんな感じ? [dunder](https://dbader.org/blog/python-dunder-methods)いじくりたいのですが、dictってどんな実装になってるんでしょうね・・・・

[ここみると](https://stackoverflow.com/questions/5334284/where-is-the-source-code-for-the-python-dict-type)・・・ソースがCなので読めないっす。(つよつよな方は読めるんでしょうが・・・)

「OrderedDictとか入れてね」ってソースにあるのでOrderdDictのソースを・・・

[OrderedDict](https://github.com/python/cpython/blob/master/Lib/collections/__init__.py#L94)でもいいかな

```python
class OrderedDict(dict):
    def __init__(self, other=(), /, **kwds):
        # (略)
        self.__update(other, **kwds)
```

updateは[こっち?](https://github.com/python/cpython/blob/290f5ae9977488d0faa0890d596aeed88e97355f/Tools/pynche/TypeinViewer.py#L126)だけどいまいちよくわかんないので適当に実装します。

# まとめ

```python
class MyDict(dict):
    def __init__(self, other=None):
        super().__init__()
        self._update(other)

    def _update(self, other=None):
        if other is not None:
            for h, i in other:
                if i:
                    self[h] = i
                else:
                    self[h] = "NULL"

class MyDictCursor(cursors.DictCursor):
    dict_type = MyDict

connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             db='db',
                             charset='utf8mb4',
                             cursorclass=MyDict)
```

んでこうなると。

```python
[{'first_name': 'bob', 'last_name': 'smith', 'id': 1, 'phone_num': "NULL"},
{'first_name': 'bob', 'last_name': 'jones', 'id': 2, 'phone_num': "NULL"}]
```