= Improvements to our data models Usually implemented in the `/model.py` files. In the current situation (1.0.x/1.1.1), we have different APIs and different conventions for the different models. We should try to be more consistent. == Representation of data === Standardize missing values For tickets, when a field is unset, we currently put the value back to the empty string. This was not always the case, as we used to reset it to `None` / `NULL` which is still what we do in some situations (retargeting tickets to no milestone after a milestone delete/close). See #7691 and #11018. We should standardize on `NULL` again. When retrieving `NULL` values from the database, we get `None` in Python. If needed, we can carry on this distinct meaning yet manipulate it as a string by converting `None` to the special value [apidoc:api/trac_util_text#trac.util.text.empty empty]. See e.g. what we do for [source:trunk/trac/ticket/model.py@11111:127,137#L110 ticket fields]. === `NOT NULL` columns Validation of the ticket summary is done in the [browser:tags/trac-1.0.12/trac/ticket/web_ui.py@:1247-1250#L1246 IRequestHandler], to avoid creating a ticket with an empty summary. The schema could be changed to use `NOT NULL` in the column specification since the empty string is [browser:tags/trac-1.0.12/trac/ticket/model.py#L372 replaced with NULL]. Alternatively, a `TracError` could be raised in the `Ticket` model when `insert`ing or `update`ing a ticket with an empty summary (#12458). === Class methods Class methods, one example being `select`, are used for table-wide queries. The signature of the `select` method is not consistent across all classes. The `Milestone` class has an [browser:/trunk/trac/ticket/model.py?rev=13060&marks=1129#L1121 include_completed] parameter in the `select` method. We could reconcile the inconsistency by having `where`, `limit` and `order_by` parameters on each method, with the parameters directly mapping to phrases in the SQL query. This would make the methods more generally useful to plugin developers. Not only is the interface inconsistent, but also the return value. In most cases a generator is returned by `select`, however some `select` methods return a list: * [browser:trunk/trac/ticket/model.py@13060:1137#L1128​] * [browser:trunk/trac/ticket/model.py@13060:1234#L1222​]