|
| 1 | +# How is datasette-pytables made? |
| 2 | + |
| 3 | +Datasette-PyTables is an external connector for [Datasette](https://github.com/simonw/datasette). Datasette publish data in SQLite files to the Internet with a JSON API, and this connector provides a way to do the same with PyTables files. |
| 4 | + |
| 5 | +Using a modified version of Datasette, [Datasette-Core](https://github.com/PyTables/datasette-core), we can load external connectors that allow us to access to any data container. For this, the connectors need a certain structure. |
| 6 | + |
| 7 | +Reviewing datasette-pytables code, you will see how to make other connectors for your needs. |
| 8 | + |
| 9 | +## Tables inspection |
| 10 | + |
| 11 | +First of all, we need to export a special method called `inspect` that receives the path of the file as an argument and returns a tuple formed by a dictionary with tables info, a list with views name and a string identifying the connector. |
| 12 | + |
| 13 | +Each entry in the dictionary for tables info has the next structure: |
| 14 | + |
| 15 | + tables['table_name'] = { |
| 16 | + 'name': 'table_name', |
| 17 | + 'columns': ['c1', 'c2'], |
| 18 | + 'primary_keys': [], |
| 19 | + 'count': 100, |
| 20 | + 'label_column': None, |
| 21 | + 'hidden': False, |
| 22 | + 'fts_table': None, |
| 23 | + 'foreign_keys': {'incoming': [], 'outgoing': []} |
| 24 | + |
| 25 | +This structure is used for PyTables. Maybe, in your case, you will need things like primary keys or foreign keys. |
| 26 | + |
| 27 | +## Returning results |
| 28 | + |
| 29 | +Datasette runs through SQL queries, so your connector has to accept these queries and execute them. The next class and methods are needed: |
| 30 | + |
| 31 | + class Connection: |
| 32 | + def __init__(self, path): |
| 33 | + ... |
| 34 | + |
| 35 | + def execute(self, sql, params=None, truncate=False, page_size=None, max_returned_rows=None): |
| 36 | + ... |
| 37 | + |
| 38 | +The `execute` method receives: |
| 39 | + |
| 40 | +* sql: the query |
| 41 | +* params: a dictionary with the params used in the query |
| 42 | +* truncate: a boolean saying if the returned data can be separated in pages or not |
| 43 | +* page_size: the number of rows a page can contain |
| 44 | +* max_returned_rows: the maximum number of rows Datasette expects |
| 45 | + |
| 46 | +We need to parse the query because PyTables has his own style for queries, but other databases could work with the SQL queries without requiring any parsing. |
| 47 | + |
| 48 | +Sometimes, Datasette make queries to `sqlite_master`; you need to keep it in mind. |
| 49 | + |
| 50 | +The `execute` method has to return a tuple with: |
| 51 | + |
| 52 | +* a list of rows (Datasette expects something like SQLite rows) |
| 53 | +* a boolean saying if the data is truncated, i.e., if we return all the rows or there are more rows than the maximum indicated in max_returned_rows |
| 54 | +* a tuple with the description of the columns in the form (('c1',), ('c2',), ...) |
| 55 | + |
| 56 | +## Rows format |
| 57 | + |
| 58 | +Datasette receives the results from the queries with SQLite row instances, so we need to return our rows in a similar way. |
| 59 | + |
| 60 | +For example, if we have the next query: |
| 61 | + |
| 62 | + SELECT name FROM persons |
| 63 | + |
| 64 | +we need to return an object that allows to do things that: |
| 65 | + |
| 66 | + row[0] == 'Susan' |
| 67 | + row['name'] == 'Susan' |
| 68 | + [c for c in row] == ['Susan'] |
| 69 | + json.dumps(row) |
| 70 | + |
| 71 | +We extend `list` class to get it, but if you respect the requirements for rows, you can develop your own implementation. |
0 commit comments