diff --git a/docs/python-api.rst b/docs/python-api.rst
index 1f9c6c5..420cbde 100644
--- a/docs/python-api.rst
+++ b/docs/python-api.rst
@@ -52,6 +52,17 @@ You can also iterate through the table objects themselves using the ``.tables``
>>> db.tables
[
]
+Listing rows
+============
+
+To iterate through dictionaries for each of the rows in a table, use ``.rows``::
+
+ >>> db = sqlite_utils.Database("dogs.db")
+ >>> for row in db["dogs"].rows:
+ ... print(row)
+ {'id': 1, 'age': 4, 'name': 'Cleo'}
+ {'id': 2, 'age': 2, 'name': 'Pancakes'}
+
Creating tables
===============
diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py
index d770cfa..37a95f8 100644
--- a/sqlite_utils/db.py
+++ b/sqlite_utils/db.py
@@ -134,6 +134,15 @@ class Table:
).fetchall()
return [Column(*row) for row in rows]
+ @property
+ def rows(self):
+ if not self.exists:
+ return []
+ cursor = self.db.conn.execute("select * from [{}]".format(self.name))
+ columns = [c[0] for c in cursor.description]
+ for row in cursor:
+ yield dict(zip(columns, row))
+
@property
def pks(self):
return [column.name for column in self.columns if column.is_pk]
diff --git a/tests/test_introspect.py b/tests/test_introspect.py
index 81a29c6..73bcd24 100644
--- a/tests/test_introspect.py
+++ b/tests/test_introspect.py
@@ -46,6 +46,12 @@ def test_columns(existing_db):
]
+def test_rows(existing_db):
+ assert [{"text": "one"}, {"text": "two"}, {"text": "three"}] == list(
+ existing_db["foo"].rows
+ )
+
+
def test_schema(existing_db):
assert "CREATE TABLE foo (text TEXT)" == existing_db["foo"].schema