Description: 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:
 .
 [...]
 .
 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
Author: Antonio Larrosa <antonio.larrosa@gmail.com>
Date: Wed, 5 May 2021 13:45:02 +0200
Origin: https://github.com/pecan/pecan/commit/a520bd544c0b02a02dbf692b8d6e2f7a503ee6d4
Debian-Bug: https://bugs.debian.org/997350

diff --git a/pecan/jsonify.py b/pecan/jsonify.py
index 5b74877..c5cbc15 100644
--- a/pecan/jsonify.py
+++ b/pecan/jsonify.py
@@ -33,6 +33,19 @@ class RowProxy(object):  # noqa
             pass
 
 
+try:
+    from sqlalchemy.engine.cursor import LegacyCursorResult, LegacyRow
+except ImportError:  # pragma no cover
+    # dummy classes since we don't have SQLAlchemy installed
+    # or we're using SQLAlchemy < 1.4
+
+    class LegacyCursorResult(object):  # noqa
+        pass
+
+    class LegacyRow(object):  # noqa
+        pass
+
+
 #
 # encoders
 #
@@ -100,6 +113,11 @@ def default(self, obj):
             if props['count'] < 0:
                 props['count'] = len(props['rows'])
             return props
+        elif isinstance(obj, LegacyCursorResult):
+            rows = [dict(row._mapping) for row in obj.fetchall()]
+            return {'count': len(rows), 'rows': rows}
+        elif isinstance(obj, LegacyRow):
+            return dict(obj._mapping)
         elif isinstance(obj, RowProxy):
             return dict(obj)
         elif isinstance(obj, webob_dicts):
