Fix addColumn routing for schema-defined DynamicTable columns#811
Fix addColumn routing for schema-defined DynamicTable columns#811ehennestad wants to merge 14 commits intomainfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #811 +/- ##
==========================================
+ Coverage 95.25% 95.32% +0.06%
==========================================
Files 209 212 +3
Lines 7508 7587 +79
==========================================
+ Hits 7152 7232 +80
+ Misses 356 355 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
f23615e to
58250b0
Compare
|
@bendichter @rly @oruebel Would appreciate input on the conceptual issue here. Strictly speaking, we are not adding the An alternative would be to disallow timeIntervals.start_time = types.hdmf_common.VectorData('data', 1) |
There was a problem hiding this comment.
Pull request overview
Fixes DynamicTable.addColumn so newly added columns are stored in the correct location: schema-backed columns populate their corresponding class properties, while non-schema columns continue to go into vectordata. This prevents inconsistent state in DynamicTable subclasses with schema-defined column properties (e.g., types.core.TimeIntervals).
Changes:
- Add column storage resolution logic to route columns to either a schema property or
vectordata, and explicitly error on collisions with non-column properties. - Update vararg column insertion to use resolved storage targets and to detect pre-existing columns across both properties and
vectordata. - Add unit tests covering schema property routing, non-schema routing, wrong-type errors, and invalid property collisions.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
+types/+util/+dynamictable/resolveColumnStorage.m |
New resolver that decides whether a column name maps to a schema-backed property or should go to vectordata, and throws on non-column collisions. |
+types/+util/+dynamictable/addVarargColumn.m |
Uses the resolver to select storage targets, expands “already exists” detection, and assigns columns accordingly. |
+tests/+unit/dynamicTableTest.m |
Adds focused unit coverage for property-backed columns, vectordata columns, wrong-type routing behavior, and collision errors. |
+matnwb/+common/+validation/mustBeVectorData.m |
Adds an arguments-block validator used by the new resolver. |
+matnwb/+common/+validation/mustBeDynamicTable.m |
Adds an arguments-block validator used by the new resolver. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function tf = canAssignToProperty(dynamicTable, columnName, columnData) | ||
| dummyTable = feval(class(dynamicTable)); | ||
| dummyColumn = feval(class(columnData)); | ||
| tf = tryAssignToProperty(dummyTable, columnName, dummyColumn); | ||
| end | ||
|
|
||
| function tf = isSchemaColumnProperty(dynamicTable, columnName) | ||
| dummyTable = feval(class(dynamicTable)); | ||
| dummyColumns = getDummyColumnObjects(); | ||
|
|
There was a problem hiding this comment.
resolveColumnStorage instantiates new dummy table/column objects (and potentially multiple dummy column objects) per column via feval(class(...)). This can add noticeable overhead when adding many columns. Consider caching a dummy table/dummy column set per DynamicTable class (e.g., with persistent storage keyed by class(dynamicTable)), or passing a prebuilt dummy table/dummy columns into the resolver when adding multiple columns.
There was a problem hiding this comment.
Not concerned about overhead here. If that surfaces as a real world issue, it should be fixed then. A more stable long term fix is to improve the generated classes to use property validation in the property blocks, that way the metaclass object can be inspected instead of creating dummy objects.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…gColumn loop Agent-Logs-Url: https://github.com/NeurodataWithoutBorders/matnwb/sessions/51c0bb70-037c-4f1b-abb0-e1e472e71a17 Co-authored-by: ehennestad <17237719+ehennestad@users.noreply.github.com>
…rodataWithoutBorders/matnwb into fix-dynamic-table-add-column
Motivation
DynamicTable.addColumnalways stored added columns invectordata, which left DynamicTable subclasses with schema-defined column properties in an inconsistent state. For tables such astypes.core.TimeIntervals, adding a column likestart_timeshould populate the corresponding property rather than only updating the vectordata set.This change updates column insertion to resolve the correct storage location for each added column. Schema-backed columns are routed to their matching property, generic columns still go to
vectordata, and collisions with non-column properties now fail explicitly. The update also adds focused unit coverage for property-backed columns, generic columns, and invalid property collisions.Todo
addColumnshould not work for table properties at allHow to test the behavior?
Example 1: Adding description column:
This should fail because description is a
DynamicTablenon-column propertyBefore:
a
VectorDataobject with name "description" was added to the vectordata set.After:
Example 2: Adding
start_timecolumn toTimeIntervals:Before:
A
VectorDataobject with name "start_time" was added to the vectordata set, not thestart_timeproperty.After:
The
VectorDataobject is now added to thestart_timeproperty.Updated unitest:
Checklist
fix #XXwhereXXis the issue number?