Support SQLAlchemy 1.4.x
Support SQLAlchemy 1.4.x

SQLAlchemy 1.4 is returning new types, LegacyCursorResult and LegacyRow,
which are not JSON serializable and this makes tests fail with:

```
======================================================================
ERROR: test_result_proxy (pecan.tests.test_jsonify.TestJsonifySQLAlchemyGenericEncoder)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/tests/test_jsonify.py", line 220, in test_result_proxy
    result = encode(self.result_proxy)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 133, in encode
    return _instance.encode(obj)
  File "/usr/lib64/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib64/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 127, in default
    return jsonify(obj)
  File "/usr/lib64/python3.6/functools.py", line 807, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 122, in jsonify
    return _default.default(obj)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 108, in default
    return JSONEncoder.default(self, obj)
  File "/usr/lib64/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'LegacyCursorResult' is not JSON serializable

======================================================================
ERROR: test_row_proxy (pecan.tests.test_jsonify.TestJsonifySQLAlchemyGenericEncoder)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/tests/test_jsonify.py", line 227, in test_row_proxy
    result = encode(self.row_proxy)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 133, in encode
    return _instance.encode(obj)
  File "/usr/lib64/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib64/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 127, in default
    return jsonify(obj)
  File "/usr/lib64/python3.6/functools.py", line 807, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 122, in jsonify
    return _default.default(obj)
  File "/home/abuild/rpmbuild/BUILD/pecan-1.3.3/pecan/jsonify.py", line 108, in default
    return JSONEncoder.default(self, obj)
  File "/usr/lib64/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'LegacyRow' is not JSON serializable
```

The SQLALchemy migration guide at [1] says:
```
For mapping-like behaviors from a Row object, including support for
these methods as well as a key-oriented __contains__ operator, the API
going forward will be to first access a special attribute Row._mapping,
which will then provide a complete mapping interface to the row, rather
than a tuple interface.
```

This commit fixes this by handling these new returned classes as a
special case and using _mapping to convert them to dicts.

[1] https://docs.sqlalchemy.org/en/14/changelog/migration_14.html#rowproxy-is-no-longer-a-proxy-is-now-called-row-and-behaves-like-an-enhanced-named-tuple

pecan/pecan,pecan/pecan,ryanpetrello/pecan,ryanpetrello/pecan