| t | | t | |
| <table align="right"><tr><td><div class="toc"> | | |
| Contents: | | |
| <ul> | | |
| <ul> | | |
| <li><a href="#Table_types">Table types</a></li> | | |
| <ul> | | |
| <li><a href="#commonalities_and_differences">commonalities and differences</a></li> | | |
| </ul> | | |
| <li><a href="#Form_creation">Form creation</a></li> | | |
| <li><a href="#Schema_determination">Schema determination</a></li> | | |
| <ul> | | |
| <li><a href="#Field_attributes">Field attributes</a></li> | | |
| <ul> | | |
| <li><a href="#Field_color">Field color</a></li> | | |
| </ul> | | |
| </ul> | | |
| <li><a href="#Current_Code">Current Code</a></li> | | |
| <li><a href="#New_Code_(Refactor_ideas)">New Code (Refactor ideas)</a></li> | | |
| <li><a href="#Interface_A_-_between_table.py_and_db">Interface A - between table.py and db</a></li> | | |
| <li><a href="#Interface_B_-_between_db_and_tbwiki_engine">Interface B - between db and tbwiki_engine</a></li> | | |
| </ul> | | |
| </ul> | | |
| </div></td></tr></table> | | |
| <p> | | |
| This page describes the TBWiki table architecture | | |
| <p> | | |
| Table data is managed in the TBWiki with the table module. | | |
| <p> | | |
| <h2><a name="Table_types">Table types</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Table_types">edit section</a>]</font></span> | | |
| </h2> | | |
| The table code recognizes three distinct table types: | | |
| <ul><li>attribute databases | | |
| <li>row-column databases | | |
| <li>scraped databases | | |
| </ul> | | |
| <p> | | |
| Attribute databases consist of records which have name-value | | |
| pairs. These are usually read from multiple TBWiki page files. | | |
| <p> | | |
| Row-column databases consist of values which are associated | | |
| with each other by row and column (similar to a relational | | |
| database). These are usually read from a single TBWiki page file | | |
| Currently, the data is formatted in MoinMoin table markup. | | |
| <p> | | |
| Writing code to handle these two different types of tables | | |
| is challenging. | | |
| <p> | | |
| <h3><a name="commonalities_and_differences">commonalities and differences</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=commonalities_and_differences">edit section</a>]</font></span> | | |
| </h3> | | |
| Here are some commonalities and differences between the two | | |
| database types: | | |
| <ul><li>attr dbs have sparse field values (not every record has every field) | | |
| <li>attr dbs are parsed from multiple files | | |
| <li>attr dbs have to keep track of which record came from which file | | |
| <li>attr dbs have NO inherent record or field ordering | | |
| </ul> | | |
| <p> | | |
| <ul><li>row-col dbs have no identifying record-id (this has to be synthesized | | |
| from the row position) | | |
| <li>row-col dbs have inherent record and field ordering (row and col position) | | |
| </ul> | | |
| <p> | | |
| Another possible database is the web-scraped database. | | |
| <p> | | |
| This database has records and fields which are "scraped" from | | |
| existing TBWiki pages or from external web sites. | | |
| <ul><li>scraped dbs have sparse field values | | |
| <li>scraped dbs have non-editable fields | | |
| </ul> | | |
| <p> | | |
| <h2><a name="Form_creation">Form creation</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Form_creation">edit section</a>]</font></span> | | |
| </h2> | | |
| The current table code can create simple data entry forms for | | |
| a database that consists of fields on type "single-line text". | | |
| <p> | | |
| The current table code supports user-specified data entry forms. | | |
| <p> | | |
| Forms for displaying the database and for adding or editing records | | |
| are expressed as multi-line strings with python string variables | | |
| where the field values or field form elements are to be placed. | | |
| The rest of the form is expressed in HTML (not TBWiki markup). | | |
| <p> | | |
| For example, if a database 'People' has 'Name' and 'Phone' fields, a form | | |
| for outputting this could look like this: | | |
| <pre> | | |
| """<table> | | |
| <tr><td>Name</td><td>Phone</td></tr> | | |
| <tr><td>%(Name)s</td><td>%(Phone)s</td></tr> | | |
| </table>""" | | |
| [This example is not complete.] | | |
| </pre> | | |
| How do you specify the start, record portion and end of a formspec?? | | |
| <p> | | |
| <hr size=2> | | |
| A record data entry form might look like this: | | |
| <pre> | | |
| Name: %(NameField)s | | |
| Phone: %(PhoneField)s | | |
| %(SaveButton)s %(CancelButton)s | | |
| </pre> | | |
| <p> | | |
| Forms can be stored as TBWiki pages, with the names: | | |
| PeopleAddForm or PeopleEditForm. | | |
| <p> | | |
| It would be nice to auto-detect form elements for checkboxes, radio | | |
| buttons, selects, and multi-line text. | | |
| <p> | | |
| (Maybe use schema-by-example...???) | | |
| <p> | | |
| <h2><a name="Schema_determination">Schema determination</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Schema_determination">edit section</a>]</font></span> | | |
| </h2> | | |
| Field names are autodetected from the table data itself. | | |
| <p> | | |
| Field attributes, such as type (which can influence the type of form element | | |
| used for inputing that field), possible values, and others, are expressed | | |
| in a configuration block. These are referred to internally as the field_db. | | |
| <p> | | |
| Here's a sample field_db block: | | |
| <pre> | | |
| field=Description | | |
| type=TextArea | | |
| | | |
| field=Status | | |
| type=Select | | |
| possible_values="""not done | | |
| in progress | | |
| done""" | | |
| colors="""not done:red | | |
| in progress:yellow | | |
| done:green""" | | |
| </pre> | | |
| <p> | | |
| <h3><a name="Field_attributes">Field attributes</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Field_attributes">edit section</a>]</font></span> | | |
| </h3> | | |
| Possible types are: | | |
| <ul><li>Text | | |
| <li>TextArea | | |
| <li>Select | | |
| <li>Radio | | |
| <li>Checkbox | | |
| </ul> | | |
| <p> | | |
| Field attributes currently implemented are: | | |
| <ul><li>type | | |
| <li>possible_values | | |
| <li>colors | | |
| </ul> | | |
| <p> | | |
| <h4><a name="Field_color">Field color</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Field_color">edit section</a>]</font></span> | | |
| </h4> | | |
| The syntax for colors is: | | |
| colors="""<cexpr>:<color> | | |
| <cexpr2>:<color2> | | |
| ...""" | | |
| <p> | | |
| <cexpr> can be a straight value, or an boolean expression. | | |
| If it is a boolean expression, it must start with an open paren, '(', | | |
| and do some comparison on the variable 'value'. A <cexpr> which is | | |
| a straight variable is converted into the expression: | | |
| "(value=="<variable>")" | | |
| <p> | | |
| The following are some examples: | | |
| <pre>colors="""not done: red | | |
| done:green""" | | |
| </pre> | | |
| <p> | | |
| <pre>colors="""(int(value)<5):green | | |
| (int(value)>=6):red""" | | |
| </pre> | | |
| <p> | | |
| Field attributes that I've thought about, but are not implemented yet are: | | |
| <ul><li>constraints - complex expression-oriented constraints, such as "one of", "in range", or "re.match" | | |
| <li>display_attrs - more complex display attributes (besides just bgcolor) | | |
| </ul> | | |
| <p> | | |
| <h2><a name="Current_Code">Current Code</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Current_Code">edit section</a>]</font></span> | | |
| </h2> | | |
| table.py | | |
| <p> | | |
| functions: | | |
| <ul><li>def print_error(msg): | | |
| <li>def generate_field_input(col_name, field_type, value): | | |
| <li>class form_field_generator_class(): | | |
| <ul><li>def __init__(self, record, col_map, field_type_hints=None): | | |
| <li>def __getitem__(self, key): | | |
| </ul><li>def cell_trans(value): | | |
| <li>def value_trans(value): | | |
| <li>class table_class(): | | |
| <ul><li>def __init__(self, source_spec, page_name="(no page name)"): | | |
| <li>def add_or_edit_numbered_record(self, record, record_id=""): | | |
| <li>def remove_numbered_record(self, record_id): | | |
| <li>def set_col_output_list(self, order=None): | | |
| <li>def set_row_output_list(self, order=None): | | |
| <li>def set_row_filter(self, filter): | | |
| <li>def filter_match(self, record): | | |
| <li>def show(self): | | |
| <li>def add_to_message(self, message): | | |
| <li>def html_string(self): | | |
| <li>def show_form(self, form_spec=None, record_id=None): | | |
| <li>def show_record_form(self, form_spec=None, record_id=None): | | |
| <li>def show_edit_table_form(self, form_spec=None): | | |
| <li>def edit_link(self): | | |
| </ul><li>def get_table(req, args): | | |
| <li>def get_form_spec(req, tb, form, source_spec, operation): | | |
| <li>def add_row_form(req): | | |
| <li>def edit_table(req): | | |
| <li>def parse_moin_table(tb, data, source_spec): | | |
| <li>def read_moin_table_file(tb, data_dir, source_spec): | | |
| <li>def read_moin_table_from_page(tb, data_dir, source_spec): | | |
| <li>def read_attrdb_file(file_path, source_spec): | | |
| <li>def load_schema(tb): | | |
| <li>def db_from_attrdb_files(tb, data_dir, source_spec): | | |
| <li>def save_attrs_to_file(tb, record): | | |
| <li>def save_attrdb(tb): | | |
| <li>def remove_attrdb_file(tb, record_id): | | |
| <li>def render_moin_table(tb): | | |
| <li>def get_table_type(source_spec): | | |
| <li>def get_table_data(req, data_dir, source_spec, page_name): | | |
| <li>def save_table_data(data_dir, source_spec, tb): | | |
| <li>def action(req): | | |
| </ul> | | |
| <p> | | |
| <h2><a name="New_Code_(Refactor_ideas)">New Code (Refactor ideas)</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=New_Code_(Refactor_ideas)">edit section</a>]</font></span> | | |
| </h2> | | |
| Split code into: | | |
| <ul><li>db read | | |
| <li>db present | | |
| <li>db edit | | |
| <li>db write | | |
| </ul> | | |
| <p> | | |
| Allow different presentation modules and different editing modules: | | |
| <ul><li>present as a list of records | | |
| <li>present as a table | | |
| <li>add a single record | | |
| <li>edit a single record | | |
| <li>edit as a table | | |
| </ul> | | |
| <p> | | |
| [Describe different interfaces here] | | |
| <p> | | |
| <h2><a name="Interface_A_-_between_table.py_and_db">Interface A - between table.py and db</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Interface_A_-_between_table.py_and_db">edit section</a>]</font></span> | | |
| </h2> | | |
| <ul><li>db_read() | | |
| <li>db_write() | | |
| <li>db_get_record(record_id) | | |
| <li>db_update_record(record, record_id) | | |
| <li>db_add_record(record, record_id) | | |
| <li>db_remove_record(record_id) | | |
| <li>db_backup()?? | | |
| </ul> | | |
| <p> | | |
| <h2><a name="Interface_B_-_between_db_and_tbwiki_engine">Interface B - between db and tbwiki_engine</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/Table_Architecture?action=edit§ion=Interface_B_-_between_db_and_tbwiki_engine">edit section</a>]</font></span> | | |
| </h2> | | |
| <ul><li>read_page(page_name[, page_namespace??]) | | |
| <li>write_page(page_name[, page_namespace??]) | | |
| <li>make_backup(page_name[, page_namespace??]) | | |
| <li>read_page_item(page_name, item_name) | | |
| <li>write_page_item(page_name, item_name, content) | | |
| </ul> | | |
| <p> | | |