Skip to content

Commit

Permalink
Allow any order for validateColumns
Browse files Browse the repository at this point in the history
The new COLUMN_MISSING error is used to indicate missing columns.
Additional columns are allowed.
  • Loading branch information
mint-thompson committed Jan 3, 2024
1 parent e0a5af1 commit 314867d
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 56 deletions.
63 changes: 17 additions & 46 deletions src/versions/1.1/csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ const ERRORS = {
`Received ${actual} columns, less than the required number ${expected}`,
COLUMN_NAME: (actual: string, expected: string, format: string) =>
`Column is "${actual}" and should be "${expected}" for ${format} format`,
COLUMN_MISSING: (column: string, format: string) =>
`Column ${column} is missing, but it is required for ${format} format`,
NOTES_COLUMN: (column: string) =>
`The last column should be "additional_generic_notes", is "${column}"`,
ALLOWED_VALUES: (column: string, value: string, allowedValues: string[]) =>
Expand Down Expand Up @@ -157,64 +159,32 @@ export function validateHeaderRow(
/** @private */
export function validateColumns(columns: string[]): CsvValidationError[] {
const rowIndex = 2
const errors: CsvValidationError[] = []

const tall = isTall(columns)

const baseColumns = getBaseColumns(columns)
const wideColumns = getWideColumns(columns)
const tallColumns = getTallColumns(columns)
const schemaFormat = tall ? "tall" : "wide"
const totalColumns = baseColumns.concat(tall ? tallColumns : wideColumns)
const remainingColumns = baseColumns.concat(tall ? tallColumns : wideColumns)

if (columns.length < totalColumns.length) {
return [
csvErr(
rowIndex,
0,
undefined,
ERRORS.COLUMN_COUNT(columns.length, baseColumns.length)
),
]
}

totalColumns.forEach((column, index) => {
if (!sepColumnsEqual(columns[index], column)) {
errors.push(
csvErr(
rowIndex,
index,
column,
ERRORS.COLUMN_NAME(columns[index], column, schemaFormat)
)
)
columns.forEach((column) => {
const matchingColumnIndex = remainingColumns.findIndex((requiredColumn) =>
sepColumnsEqual(column, requiredColumn)
)
if (matchingColumnIndex > -1) {
remainingColumns.splice(matchingColumnIndex, 1)
}
})

if (!tall) {
errors.push(...validateWideColumns(columns))
}

return errors
}

/** @private */
export function validateWideColumns(columns: string[]): CsvValidationError[] {
const rowIndex = 2
const errors: CsvValidationError[] = []

if (columns[columns.length - 1] !== "additional_generic_notes") {
errors.push(
csvErr(
rowIndex,
columns.length - 1,
"additional_generic_notes",
ERRORS.NOTES_COLUMN(columns[columns.length - 1])
)
return remainingColumns.map((requiredColumn) => {
return csvErr(
rowIndex,
columns.length,
requiredColumn,
ERRORS.COLUMN_MISSING(requiredColumn, schemaFormat)
)
}

return errors
})
}

/** @private */
Expand Down Expand Up @@ -524,6 +494,7 @@ export function getWideColumns(columns: string[]): string[] {
...payersPlansColumns.slice(0, 2),
...MIN_MAX_COLUMNS,
...payersPlansColumns.slice(2),
"additional_generic_notes",
]
}

Expand Down
68 changes: 58 additions & 10 deletions test/csv.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import test from "ava"
import {
validateHeaderColumns,
validateHeaderRow,
validateWideColumns,
validateColumns,
validateTallFields,
validateWideFields,
Expand Down Expand Up @@ -133,19 +132,68 @@ test("validateColumns tall", (t) => {
...getTallColumns([]),
"test",
]).length,
9
1
)
})

test("validateWideColumns", (t) => {
// Currently only checking for the order of additional_generic_notes
test("validateColumns wide", (t) => {
const columns = [
...BASE_COLUMNS,
...MIN_MAX_COLUMNS,
"code | 1",
"code | 1 | type",
"standard_charge | Payer | Plan",
"standard_charge | Payer | Plan | percent",
"standard_charge | Payer | Plan | contracting_method",
"additional_payer_notes | Payer | Plan",
"additional_generic_notes",
]
t.is(validateColumns(columns).length, 0)
// any order is fine
const reverseColumns = [...columns].reverse()
t.is(validateColumns(reverseColumns).length, 0)
// extra payer and plan are fine
t.is(
validateWideColumns([
...BASE_COLUMNS,
...MIN_MAX_COLUMNS,
"standard_charge | Payer | Plan",
"additional_generic_notes",
"standard_charge | Payer | Plan | pct",
validateColumns([
...columns,
"standard_charge | Payer | Plan 2",
"standard_charge | Payer | Plan 2 | percent",
"standard_charge | Payer | Plan 2 | contracting_method",
"additional_payer_notes | Payer | Plan 2",
"standard_charge | Another Payer | Plan",
"standard_charge | Another Payer | Plan | percent",
"standard_charge | Another Payer | Plan | contracting_method",
"additional_payer_notes | Another Payer | Plan",
]).length,
0
)
// missing percent is an error
t.is(
validateColumns([
...columns,
"standard_charge | Payer | Plan 2",
"standard_charge | Payer | Plan 2 | contracting_method",
"additional_payer_notes | Payer | Plan 2",
]).length,
1
)
// missing contracting_method is an error
t.is(
validateColumns([
...columns,
"standard_charge | Payer | Plan 2",
"standard_charge | Payer | Plan 2 | percent",
"additional_payer_notes | Payer | Plan 2",
]).length,
1
)
// missing additional_payer_notes is an error
t.is(
validateColumns([
...columns,
"standard_charge | Payer | Plan 2",
"standard_charge | Payer | Plan 2 | percent",
"standard_charge | Payer | Plan 2 | contracting_method",
]).length,
1
)
Expand Down

0 comments on commit 314867d

Please sign in to comment.