Skip to content

Commit 27373e0

Browse files
authored
Merge pull request #234 from effigies/feat/sidecar-columns
feat: Unify schema and sidecar-defined column validation
2 parents 43d4e6d + 07726aa commit 27373e0

File tree

4 files changed

+326
-122
lines changed

4 files changed

+326
-122
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<!--
2+
A new scriv changelog fragment.
3+
4+
Uncomment the section that is right (remove the HTML comment wrapper).
5+
For top level release notes, leave all the headers commented out.
6+
-->
7+
8+
<!--
9+
### Added
10+
11+
- A bullet item for the Added category.
12+
13+
-->
14+
### Changed
15+
16+
- Improved handling of TSV columns with sidecar definitions.
17+
`"Format"`, `"Minimum"` and `"Maximum"` keys are now supported.
18+
19+
<!--
20+
### Fixed
21+
22+
- A bullet item for the Fixed category.
23+
24+
-->
25+
<!--
26+
### Deprecated
27+
28+
- A bullet item for the Deprecated category.
29+
30+
-->
31+
<!--
32+
### Removed
33+
34+
- A bullet item for the Removed category.
35+
36+
-->
37+
<!--
38+
### Security
39+
40+
- A bullet item for the Security category.
41+
42+
-->
43+
<!--
44+
### Infrastructure
45+
46+
- A bullet item for the Infrastructure category.
47+
48+
-->

src/schema/applyRules.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ export function evalCheck(src: string, context: BIDSContext) {
9494
* We associate theys keys from a rule object to a function adds an
9595
* issue to the context if the rule evaluation fails.
9696
*/
97-
// @ts-expect-error
9897
const evalMap: Record<
9998
keyof GenericRule,
10099
(
@@ -105,9 +104,13 @@ const evalMap: Record<
105104
) => boolean | void
106105
> = {
107106
checks: evalRuleChecks,
107+
// @ts-expect-error
108108
columns: evalColumns,
109+
// @ts-expect-error
109110
additional_columns: evalAdditionalColumns,
111+
// @ts-expect-error
110112
initial_columns: evalInitialColumns,
113+
// @ts-expect-error
111114
index_columns: evalIndexColumns,
112115
fields: evalJsonCheck,
113116
}

src/schema/tables.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ const schemaDefs = {
2626
index_columns: ['filename'],
2727
additional_columns: 'allowed',
2828
},
29+
Participants: {
30+
selectors: ['path == "/participants.tsv"'],
31+
initial_columns: ['participant_id'],
32+
columns: {
33+
participant_id: 'required',
34+
age: 'recommended',
35+
sex: 'recommended',
36+
strain_rrid: 'recommended',
37+
},
38+
index_columns: ['participant_id'],
39+
additional_columns: 'allowed',
40+
},
2941
},
3042
made_up: {
3143
MadeUp: {
@@ -93,6 +105,67 @@ Deno.test('tables eval* tests', async (t) => {
93105
assertEquals(context.dataset.issues.size, 0)
94106
})
95107

108+
await t.step('verify column override behavior', () => {
109+
const context = {
110+
path: '/participants.tsv',
111+
extension: '.tsv',
112+
sidecar: {
113+
participant_id: {
114+
Description: 'A participant identifier',
115+
Format: 'string',
116+
},
117+
age: {
118+
Description: 'Age in weeks',
119+
Format: 'number',
120+
},
121+
sex: {
122+
Description: 'Phenotypic sex',
123+
Format: 'string',
124+
Levels: {
125+
'F': { Description: 'Female' },
126+
'M': { Description: 'Male' },
127+
'O': { Description: 'Other' },
128+
},
129+
},
130+
strain_rrid: {
131+
Description: 'Invalid override',
132+
Format: 'integer',
133+
},
134+
},
135+
sidecarKeyOrigin: {
136+
participant_id: '/participants.json',
137+
age: '/participants.json',
138+
sex: '/participants.json',
139+
strain_rrid: '/participants.json',
140+
},
141+
columns: {
142+
participant_id: ['sub-01', 'sub-02', 'sub-03'],
143+
age: ['10', '20', '30'],
144+
sex: ['M', 'F', 'f'],
145+
strain_rrid: ['RRID:SCR_012345', 'RRID:SCR_012345', 'n/a'],
146+
},
147+
dataset: { issues: new DatasetIssues() },
148+
}
149+
const rule = schemaDefs.rules.tabular_data.modality_agnostic.Participants
150+
evalColumns(rule, context, schema, 'rules.tabular_data.modality_agnostic.Participants')
151+
152+
// participant_id column definition is compatible with schema
153+
// age and sex may be overridden
154+
// strain_rrid can't be redefined to numeric
155+
let issues = context.dataset.issues.get({ code: 'TSV_COLUMN_TYPE_REDEFINED' })
156+
assertEquals(issues.length, 1)
157+
assertEquals(issues[0].subCode, 'strain_rrid')
158+
assertEquals(issues[0].issueMessage, 'Format "integer" must be rrid')
159+
160+
// Overriding the default sex definition uses the provided values
161+
// Values in the default definition may raise issues
162+
issues = context.dataset.issues.get({ code: 'TSV_VALUE_INCORRECT_TYPE_NONREQUIRED' })
163+
assertEquals(issues.length, 1)
164+
assertEquals(issues[0].subCode, 'sex')
165+
assertEquals(issues[0].line, 4)
166+
assertEquals(issues[0].issueMessage, "'f'")
167+
})
168+
96169
await t.step('verify column ordering', () => {
97170
const context = {
98171
path: '/sub-01/sub-01_scans.tsv',

0 commit comments

Comments
 (0)