Repository: innobi/pantab (python)

Issue:
frames_from_hyper not pulling when there's no data in the table.  
**Describe the bug**
I'm simply trying to pull all the frames from a hyper file (which I unfortunately can't give you).  But I think the problem is that one of the tables doesn't have any rows. Which then errors out [here](https://github.com/innobi/pantab/blob/f6a9fbb3f73cd51ada79e5d6d6aa114aea77dc98/pantab/_reader.py#L50) with 

``` py
ValueError: Length mismatch: Expected axis has 0 elements, new values have 60 elements
```

df in the line above is an empty dataframe.  

This is a problem because it's screwing up my other reads. 

**Expected behavior**
It gives me a blank dataframe with the proper columns but no data.  

Could skip it too, but that seems worse.  


**Desktop (please complete the following information):**
 - OS: windows10




Pull request description:
[bug] fix empty read query df
We've also ran into this problem. We believe pantab shouldn't error given an empty df.

As usual this is Red-Green tested... and covered

closes #163 


Patch:
diff --git a/pantab/_reader.py b/pantab/_reader.py
index 8aa0cc1..a9ea5e2 100644
--- a/pantab/_reader.py
+++ b/pantab/_reader.py
@@ -46,7 +46,8 @@ def _read_query_result(
     # Call native library to read tuples from result set
     dtype_strs = tuple(dtypes.values())
     df = pd.DataFrame(libpantab.read_hyper_query(result._Result__cdata, dtype_strs))
-
+    if df.empty:
+        return pd.DataFrame({col: pd.Series(dtype="object") for col in dtypes})
     df.columns = dtypes.keys()
     # TODO: remove this hackery...
     for k, v in dtypes.items():


Test patch:
diff --git a/pantab/tests/test_reader.py b/pantab/tests/test_reader.py
index 05e4280..377b29d 100644
--- a/pantab/tests/test_reader.py
+++ b/pantab/tests/test_reader.py
@@ -1,3 +1,5 @@
+from sqlite3 import connect
+
 import pandas as pd
 import pandas.testing as tm
 import pytest
@@ -112,3 +114,19 @@ def test_read_query(df, tmp_hyper):
     expected = expected.astype({"i": "Int16", "_i2": "string"})
 
     tm.assert_frame_equal(result, expected)
+
+
+def test_empty_read_query(df: pd.DataFrame, tmp_hyper):
+    """
+    red-green for empty query results
+    """
+    # sql cols need to base case insensitive & unique
+    df = df[pd.Series(df.columns).apply(lambda s: s.lower()).drop_duplicates()]
+    conn = connect(":memory:")
+    table_name = "test"
+    df.to_sql(name=table_name, con=conn, index=False)
+    pantab.frame_to_hyper(df, tmp_hyper, table=table_name)
+    query = f"SELECT * FROM {table_name} limit 0"
+    expected = pd.read_sql_query(query, conn)
+    result = pantab.frame_from_hyper_query(tmp_hyper, query)
+    tm.assert_frame_equal(result, expected)