datasette==0.51.1
authorJavier Sancho <jsf@jsancho.org>
Sat, 21 Nov 2020 19:15:49 +0000 (20:15 +0100)
committerJavier Sancho <jsf@jsancho.org>
Sat, 21 Nov 2020 19:15:49 +0000 (20:15 +0100)
datasette_pytables/__init__.py
tests/test_api.py
tests/test_html.py

index 1cb22a8..7b4d33c 100644 (file)
@@ -26,30 +26,50 @@ class PyTablesConnector(dc.Connector):
         'binary_or': '|',
     }
 
+    def _serialize_table_name(self, table_name):
+        return table_name.replace('/', '%')
+
+    def _deserialize_table_name(self, table_name):
+        return table_name.replace('%', '/')
+
     def table_names(self):
         return [
-            node._v_pathname
+            self._serialize_table_name(node._v_pathname)
             for node in self.conn.h5file
             if not(isinstance(node, tables.group.Group))
         ]
 
     def table_count(self, table_name):
-        table = self.conn.h5file.get_node(table_name)
+        table = self.conn.h5file.get_node(self._deserialize_table_name(table_name))
         return int(table.nrows)
 
     def table_info(self, table_name):
-        table = self.conn.h5file.get_node(table_name)
-        colnames = ['value']
+        table = self.conn.h5file.get_node(self._deserialize_table_name(table_name))
+        columns = [
+            {
+                'name': 'value',
+                'type': table.dtype.name,
+            }
+        ]
         if isinstance(table, tables.table.Table):
-            colnames = table.colnames
+            columns = [
+                {
+                    'name': colname,
+                    'type': table.coltypes[colname],
+                }
+                for colname in table.colnames
+            ]
 
         return [
             {
-                'idx': idx,
-                'name': colname,
-                'primary_key': False,
+                'cid': cid,
+                'name': column['name'],
+                'type': column['type'],
+                'notnull': True,
+                'default_value': None,
+                'is_pk': False,
             }
-            for idx, colname in enumerate(colnames)
+            for cid, column in enumerate(columns)
         ]
 
     def hidden_table_names(self):
@@ -69,12 +89,13 @@ class PyTablesConnector(dc.Connector):
 
     def table_exists(self, table_name):
         try:
-            self.conn.h5file.get_node(table_name)
+            self.conn.h5file.get_node(self._deserialize_table_name(table_name))
             return True
         except:
             return False
 
     def table_definition(self, table_type, table_name):
+        table_name = self._deserialize_table_name(table_name)
         table = self.conn.h5file.get_node(table_name)
         colnames = ['value']
         if isinstance(table, tables.table.Table):
@@ -107,7 +128,7 @@ class PyTablesConnector(dc.Connector):
             # Pytables does not support subqueries
             parsed_sql['from'] = parsed_sql['from']['value']['from']
 
-        table = self.conn.h5file.get_node(parsed_sql['from'])
+        table = self.conn.h5file.get_node(self._deserialize_table_name(parsed_sql['from']))
         table_rows = []
         fields = parsed_sql['select']
         colnames = ['value']
index 71c9262..eb0453a 100644 (file)
@@ -15,7 +15,7 @@ def test_database_page(app_client):
     data = response.json
     assert 'test_tables' == data['database']
     assert [{
-        'name': '/array1',
+        'name': '%array1',
         'columns': ['value'],
         'primary_keys': [],
         'count': 2,
@@ -24,7 +24,7 @@ def test_database_page(app_client):
         'foreign_keys': {'incoming': [], 'outgoing': []},
         'private': False,
     }, {
-        'name': '/group1/array2',
+        'name': '%group1%array2',
         'columns': ['value'],
         'primary_keys': [],
         'count': 10000,
@@ -33,7 +33,7 @@ def test_database_page(app_client):
         'foreign_keys': {'incoming': [], 'outgoing': []},
         'private': False,
     }, {
-        'name': '/group1/table1',
+        'name': '%group1%table1',
         'columns': ['identity', 'idnumber', 'speed'],
         'primary_keys': [],
         'count': 10000,
@@ -42,7 +42,7 @@ def test_database_page(app_client):
         'foreign_keys': {'incoming': [], 'outgoing': []},
         'private': False,
     }, {
-        'name': '/group2/multi',
+        'name': '%group2%multi',
         'columns': ['value'],
         'primary_keys': [],
         'count': 10,
@@ -51,7 +51,7 @@ def test_database_page(app_client):
         'foreign_keys': {'incoming': [], 'outgoing': []},
         'private': False,
     }, {
-        'name': '/group2/table2',
+        'name': '%group2%table2',
         'columns': ['identity', 'idnumber', 'speed'],
         'primary_keys': [],
         'count': 10000,
@@ -64,13 +64,13 @@ def test_database_page(app_client):
 def test_custom_sql(app_client):
     response = app_client.get(
         '/test_tables.json?' + urlencode({
-            'sql': 'select identity from [/group1/table1]',
+            'sql': 'select identity from [%group1%table1]',
             '_shape': 'objects'
         }),
     )
     data = response.json
     assert {
-        'sql': 'select identity from [/group1/table1]',
+        'sql': 'select identity from [%group1%table1]',
         'params': {}
     } == data['query']
     assert 1000 == len(data['rows'])
@@ -87,13 +87,13 @@ def test_custom_sql(app_client):
 def test_custom_complex_sql(app_client):
     response = app_client.get(
         '/test_tables.json?' + urlencode({
-            'sql': 'select identity from [/group1/table1] where speed > 100 and idnumber < 55',
+            'sql': 'select identity from [%group1%table1] where speed > 100 and idnumber < 55',
             '_shape': 'objects',
         }),
     )
     data = response.json
     assert {
-        'sql': 'select identity from [/group1/table1] where speed > 100 and idnumber < 55',
+        'sql': 'select identity from [%group1%table1] where speed > 100 and idnumber < 55',
         'params': {},
     } == data['query']
     assert 4 == len(data['rows'])
@@ -110,13 +110,13 @@ def test_custom_complex_sql(app_client):
 def test_custom_pytables_sql(app_client):
     response = app_client.get(
         '/test_tables.json?' + urlencode({
-            'sql': 'select identity from [/group1/table1] where (speed > 100) & (speed < 500)',
+            'sql': 'select identity from [%group1%table1] where (speed > 100) & (speed < 500)',
             '_shape': 'objects',
         }),
     )
     data = response.json
     assert {
-        'sql': 'select identity from [/group1/table1] where (speed > 100) & (speed < 500)',
+        'sql': 'select identity from [%group1%table1] where (speed > 100) & (speed < 500)',
         'params': {},
     } == data['query']
     assert 199 == len(data['rows'])
@@ -139,11 +139,11 @@ def test_invalid_custom_sql(app_client):
 
 def test_table_json(app_client):
     response = app_client.get(
-        '/test_tables/%2Fgroup2%2Ftable2.json?_shape=objects',
+        '/test_tables/%group2%table2.json?_shape=objects',
     )
     assert response.status == 200
     data = response.json
-    assert data['query']['sql'] == 'select identity, idnumber, speed from [/group2/table2] limit 51'
+    assert data['query']['sql'] == 'select identity, idnumber, speed from [%group2%table2] limit 51'
     assert data['rows'][3:6] == [{
         'identity': 'This is particle:  3',
         'idnumber': 3,
@@ -170,7 +170,7 @@ def test_table_not_exists_json(app_client):
 
 def test_table_shape_arrays(app_client):
     response = app_client.get(
-        '/test_tables/%2Fgroup2%2Ftable2.json?_shape=arrays',
+        '/test_tables/%group2%table2.json?_shape=arrays',
     )
     assert [
         ['This is particle:  6', 6, 12.0],
@@ -179,7 +179,7 @@ def test_table_shape_arrays(app_client):
 
 def test_table_shape_objects(app_client):
     response = app_client.get(
-        '/test_tables/%2Fgroup2%2Ftable2.json?_shape=objects',
+        '/test_tables/%group2%table2.json?_shape=objects',
     )
     assert [{
         'identity': 'This is particle:  6',
@@ -193,7 +193,7 @@ def test_table_shape_objects(app_client):
 
 def test_table_shape_array(app_client):
     response = app_client.get(
-        '/test_tables/%2Fgroup2%2Ftable2.json?_shape=array',
+        '/test_tables/%group2%table2.json?_shape=array',
     )
     assert [{
         'identity': 'This is particle:  6',
@@ -207,7 +207,7 @@ def test_table_shape_array(app_client):
 
 def test_table_shape_invalid(app_client):
     response = app_client.get(
-        '/test_tables/%2Fgroup2%2Ftable2.json?_shape=invalid',
+        '/test_tables/%group2%table2.json?_shape=invalid',
     )
     assert {
         'ok': False,
@@ -217,10 +217,10 @@ def test_table_shape_invalid(app_client):
     } == response.json
 
 @pytest.mark.parametrize('path, expected_rows, expected_pages', [
-    ('/test_tables/%2Farray1.json', 2, 1),
-    ('/test_tables/%2Farray1.json?_size=1', 2, 2),
-    ('/test_tables/%2Fgroup1%2Farray2.json?_size=1000', 10000, 10),
-    ('/test_tables/%2Fgroup2%2Fmulti.json?_size=5', 10, 2),
+    ('/test_tables/%array1.json', 2, 1),
+    ('/test_tables/%array1.json?_size=1', 2, 2),
+    ('/test_tables/%group1%array2.json?_size=1000', 10000, 10),
+    ('/test_tables/%group2%multi.json?_size=5', 10, 2),
 ])
 def test_paginate_tables_and_arrays(app_client, path, expected_rows, expected_pages):
     fetched = []
index 30ecce1..3e1c9ed 100644 (file)
@@ -12,17 +12,17 @@ def test_database_page(app_client_with_hash):
     assert 'test_tables' in response.text
 
 def test_table(app_client):
-    response = app_client.get('/test_tables/%2Fgroup1%2Ftable1')
+    response = app_client.get('/test_tables/%group1%table1')
     assert response.status == 200
 
 def test_table_row(app_client):
-    response = app_client.get('/test_tables/%2Fgroup1%2Ftable1/50')
+    response = app_client.get('/test_tables/%group1%table1/50')
     assert response.status == 200
 
 def test_array(app_client):
-    response = app_client.get('/test_tables/%2Fgroup1%2Farray2')
+    response = app_client.get('/test_tables/%group1%array2')
     assert response.status == 200
 
 def test_array_row(app_client):
-    response = app_client.get('/test_tables/%2Fgroup1%2Farray2/1050')
+    response = app_client.get('/test_tables/%group1%array2/1050')
     assert response.status == 200