mirror of
https://github.com/simonw/datasette.git
synced 2026-05-31 14:16:59 +02:00
Refactor ColumnType: register classes, return instances with config
- register_column_types() now returns classes instead of instances
- ColumnType.__init__ takes optional config=, baking it into the instance
- get_column_type() returns a ColumnType instance (or None) instead of a
(name, config) tuple
- get_column_types() returns {col: ColumnType instance} instead of tuples
- Remove get_column_type_class() - no longer needed
- render_cell/validate/transform_value methods no longer take config arg;
use self.config instead
- render_cell hook takes column_type (ColumnType or None) instead of
column_type + column_type_config
https://claude.ai/code/session_01SvPEPqHgURTWESRp28pTC3
This commit is contained in:
parent
8af98c24c2
commit
dd9b83301c
11 changed files with 227 additions and 243 deletions
|
|
@ -922,13 +922,16 @@ await .get_column_type(database, resource, column)
|
|||
``column`` - string
|
||||
The name of the column.
|
||||
|
||||
Returns a ``(column_type_name, config)`` tuple for the specified column. ``column_type_name`` is a string like ``"email"`` or ``"url"``, and ``config`` is a dict or ``None``. If no column type is assigned, returns ``(None, None)``.
|
||||
Returns a :ref:`ColumnType <column_types>` instance with ``.config`` populated for the specified column, or ``None`` if no column type is assigned.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ct_name, config = await datasette.get_column_type(
|
||||
ct = await datasette.get_column_type(
|
||||
"mydb", "mytable", "email_col"
|
||||
)
|
||||
if ct:
|
||||
print(ct.name) # "email"
|
||||
print(ct.config) # None or {...}
|
||||
|
||||
.. _datasette_get_column_types:
|
||||
|
||||
|
|
@ -940,12 +943,13 @@ await .get_column_types(database, resource)
|
|||
``resource`` - string
|
||||
The name of the table or view.
|
||||
|
||||
Returns a dictionary mapping column names to ``(column_type_name, config)`` tuples for all columns that have assigned types on the given resource.
|
||||
Returns a dictionary mapping column names to :ref:`ColumnType <column_types>` instances (with ``.config`` populated) for all columns that have assigned types on the given resource.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ct_map = await datasette.get_column_types("mydb", "mytable")
|
||||
# {"email_col": ("email", None), "site": ("url", None)}
|
||||
for col_name, ct in ct_map.items():
|
||||
print(col_name, ct.name, ct.config)
|
||||
|
||||
.. _datasette_set_column_type:
|
||||
|
||||
|
|
@ -995,22 +999,6 @@ Removes the column type assignment for the specified column.
|
|||
"mydb", "mytable", "location"
|
||||
)
|
||||
|
||||
.. _datasette_get_column_type_class:
|
||||
|
||||
.get_column_type_class(column_type_name)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``column_type_name`` - string
|
||||
The name of the column type, e.g. ``"email"``.
|
||||
|
||||
Returns the registered ``ColumnType`` instance for the given name, or ``None`` if no plugin has registered a column type with that name. This is a synchronous method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ct = datasette.get_column_type_class("email")
|
||||
if ct:
|
||||
print(ct.description) # "Email address"
|
||||
|
||||
.. _datasette_add_database:
|
||||
|
||||
.add_database(db, name=None, route=None)
|
||||
|
|
@ -2049,6 +2037,14 @@ The internal database schema is as follows:
|
|||
value text,
|
||||
unique(database_name, resource_name, column_name, key)
|
||||
);
|
||||
CREATE TABLE column_types (
|
||||
database_name TEXT NOT NULL,
|
||||
resource_name TEXT NOT NULL,
|
||||
column_name TEXT NOT NULL,
|
||||
column_type TEXT NOT NULL,
|
||||
config TEXT,
|
||||
PRIMARY KEY (database_name, resource_name, column_name)
|
||||
);
|
||||
|
||||
.. [[[end]]]
|
||||
|
||||
|
|
|
|||
|
|
@ -474,8 +474,8 @@ Examples: `datasette-publish-fly <https://datasette.io/plugins/datasette-publish
|
|||
|
||||
.. _plugin_hook_render_cell:
|
||||
|
||||
render_cell(row, value, column, table, pks, database, datasette, request, column_type, column_type_config)
|
||||
----------------------------------------------------------------------------------------------------------
|
||||
render_cell(row, value, column, table, pks, database, datasette, request, column_type)
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
Lets you customize the display of values within table cells in the HTML table view.
|
||||
|
||||
|
|
@ -503,11 +503,8 @@ Lets you customize the display of values within table cells in the HTML table vi
|
|||
``request`` - :ref:`internals_request`
|
||||
The current request object
|
||||
|
||||
``column_type`` - string or None
|
||||
The name of the :ref:`column type <column_types>` assigned to this column, or ``None`` if no column type is assigned.
|
||||
|
||||
``column_type_config`` - dict or None
|
||||
The configuration dict for the assigned column type, or ``None``.
|
||||
``column_type`` - :ref:`ColumnType <column_types>` instance or None
|
||||
The :ref:`ColumnType <column_types>` instance assigned to this column (with ``.config`` populated), or ``None`` if no column type is assigned. You can access ``column_type.name``, ``column_type.config``, etc.
|
||||
|
||||
If a column has a :ref:`column type <column_types>` assigned and that column type's ``render_cell`` method returns a non-``None`` value, it will take priority over this plugin hook.
|
||||
|
||||
|
|
@ -1002,7 +999,7 @@ The permission system then uses this query along with rules from plugins to dete
|
|||
register_column_types(datasette)
|
||||
--------------------------------
|
||||
|
||||
Return a list of :ref:`ColumnType <column_types>` instances to register custom column types. Column types define how values in specific columns are rendered, validated, and transformed.
|
||||
Return a list of :ref:`ColumnType <column_types>` **classes** (not instances) to register custom column types. Column types define how values in specific columns are rendered, validated, and transformed.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
@ -1023,7 +1020,6 @@ Return a list of :ref:`ColumnType <column_types>` instances to register custom c
|
|||
database,
|
||||
datasette,
|
||||
request,
|
||||
config,
|
||||
):
|
||||
if value:
|
||||
return markupsafe.Markup(
|
||||
|
|
@ -1032,14 +1028,12 @@ Return a list of :ref:`ColumnType <column_types>` instances to register custom c
|
|||
).format(color=markupsafe.escape(value))
|
||||
return None
|
||||
|
||||
async def validate(self, value, config, datasette):
|
||||
async def validate(self, value, datasette):
|
||||
if value and not value.startswith("#"):
|
||||
return "Color must start with #"
|
||||
return None
|
||||
|
||||
async def transform_value(
|
||||
self, value, config, datasette
|
||||
):
|
||||
async def transform_value(self, value, datasette):
|
||||
# Normalize to uppercase
|
||||
if isinstance(value, str):
|
||||
return value.upper()
|
||||
|
|
@ -1048,7 +1042,7 @@ Return a list of :ref:`ColumnType <column_types>` instances to register custom c
|
|||
|
||||
@hookimpl
|
||||
def register_column_types(datasette):
|
||||
return [ColorColumnType()]
|
||||
return [ColorColumnType]
|
||||
|
||||
Each ``ColumnType`` subclass must define the following class attributes:
|
||||
|
||||
|
|
@ -1060,16 +1054,16 @@ Each ``ColumnType`` subclass must define the following class attributes:
|
|||
|
||||
And the following methods, all optional:
|
||||
|
||||
``render_cell(self, value, column, table, database, datasette, request, config)``
|
||||
``render_cell(self, value, column, table, database, datasette, request)``
|
||||
Return an HTML string to render this cell value, or ``None`` to fall through to the default ``render_cell`` plugin hook chain. When a column type provides rendering, it takes priority over the ``render_cell`` plugin hook.
|
||||
|
||||
``validate(self, value, config, datasette)``
|
||||
``validate(self, value, datasette)``
|
||||
Validate a value before it is written via the insert, update, or upsert API endpoints. Return ``None`` if valid, or a string error message if invalid. Null values and empty strings skip validation.
|
||||
|
||||
``transform_value(self, value, config, datasette)``
|
||||
``transform_value(self, value, datasette)``
|
||||
Transform a value before it appears in JSON API output. Return the transformed value. The default implementation returns the value unchanged.
|
||||
|
||||
The ``config`` argument passed to these methods is the parsed JSON config dict for the specific column assignment, or ``None`` if no config was provided.
|
||||
Per-column configuration is available via ``self.config`` in all methods. When a column type is looked up for a specific column (via :ref:`get_column_type <datasette_get_column_type>` or :ref:`get_column_types <datasette_get_column_types>`), the returned instance has ``config`` set to the parsed JSON config dict for that column assignment, or ``None`` if no config was provided.
|
||||
|
||||
Column types are assigned to columns via the ``column_types`` key in :ref:`table configuration <metadata_tables>`:
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue