diff --git a/package.json b/package.json index 37c53cb..1d75f36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@molgenis/vip-report-api", - "version": "3.3.1", + "version": "3.4.0", "description": "TypeScript Report API for Variant Call Format (VCF) Report Templates", "scripts": { "build": "tsc --build", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 007643c..8941dea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: 5.4 +lockfileVersion: 5.3 specifiers: '@molgenis/vip-report-vcf': ^1.1.0 @@ -19,12 +19,12 @@ dependencies: devDependencies: '@types/node': 17.0.36 - '@typescript-eslint/eslint-plugin': 5.27.0_dszb5tb7atwkjjijmmov4qhi7i - '@typescript-eslint/parser': 5.27.0_xztl6dhthcahlo6akmb2bmjmle + '@typescript-eslint/eslint-plugin': 5.27.0_1cb21ecc3f04eca4a509631d5e40e8fa + '@typescript-eslint/parser': 5.27.0_eslint@8.16.0+typescript@4.7.2 c8: 7.11.3 eslint: 8.16.0 eslint-config-prettier: 8.5.0_eslint@8.16.0 - eslint-plugin-prettier: 4.0.0_j7rsahgqtkecno6yauhsgsglf4 + eslint-plugin-prettier: 4.0.0_4fe3201cd09a8826bbd8050f2348cb2f husky: 8.0.1 prettier: 2.6.2 typescript: 4.7.2 @@ -136,7 +136,7 @@ packages: resolution: {integrity: sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==} dev: true - /@typescript-eslint/eslint-plugin/5.27.0_dszb5tb7atwkjjijmmov4qhi7i: + /@typescript-eslint/eslint-plugin/5.27.0_1cb21ecc3f04eca4a509631d5e40e8fa: resolution: {integrity: sha512-DDrIA7GXtmHXr1VCcx9HivA39eprYBIFxbQEHI6NyraRDxCGpxAFiYQAT/1Y0vh1C+o2vfBiy4IuPoXxtTZCAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -147,10 +147,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.27.0_xztl6dhthcahlo6akmb2bmjmle + '@typescript-eslint/parser': 5.27.0_eslint@8.16.0+typescript@4.7.2 '@typescript-eslint/scope-manager': 5.27.0 - '@typescript-eslint/type-utils': 5.27.0_xztl6dhthcahlo6akmb2bmjmle - '@typescript-eslint/utils': 5.27.0_xztl6dhthcahlo6akmb2bmjmle + '@typescript-eslint/type-utils': 5.27.0_eslint@8.16.0+typescript@4.7.2 + '@typescript-eslint/utils': 5.27.0_eslint@8.16.0+typescript@4.7.2 debug: 4.3.4 eslint: 8.16.0 functional-red-black-tree: 1.0.1 @@ -163,7 +163,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.27.0_xztl6dhthcahlo6akmb2bmjmle: + /@typescript-eslint/parser/5.27.0_eslint@8.16.0+typescript@4.7.2: resolution: {integrity: sha512-8oGjQF46c52l7fMiPPvX4It3u3V3JipssqDfHQ2hcR0AeR8Zge+OYyKUCm5b70X72N1qXt0qgHenwN6Gc2SXZA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -191,7 +191,7 @@ packages: '@typescript-eslint/visitor-keys': 5.27.0 dev: true - /@typescript-eslint/type-utils/5.27.0_xztl6dhthcahlo6akmb2bmjmle: + /@typescript-eslint/type-utils/5.27.0_eslint@8.16.0+typescript@4.7.2: resolution: {integrity: sha512-vpTvRRchaf628Hb/Xzfek+85o//zEUotr1SmexKvTfs7czXfYjXVT/a5yDbpzLBX1rhbqxjDdr1Gyo0x1Fc64g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -201,7 +201,7 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/utils': 5.27.0_xztl6dhthcahlo6akmb2bmjmle + '@typescript-eslint/utils': 5.27.0_eslint@8.16.0+typescript@4.7.2 debug: 4.3.4 eslint: 8.16.0 tsutils: 3.21.0_typescript@4.7.2 @@ -236,7 +236,7 @@ packages: - supports-color dev: true - /@typescript-eslint/utils/5.27.0_xztl6dhthcahlo6akmb2bmjmle: + /@typescript-eslint/utils/5.27.0_eslint@8.16.0+typescript@4.7.2: resolution: {integrity: sha512-nZvCrkIJppym7cIbP3pOwIkAefXOmfGPnCM0LQfzNaKxJHI6VjI8NC662uoiPlaf5f6ymkTy9C3NQXev2mdXmA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -683,7 +683,7 @@ packages: eslint: 8.16.0 dev: true - /eslint-plugin-prettier/4.0.0_j7rsahgqtkecno6yauhsgsglf4: + /eslint-plugin-prettier/4.0.0_4fe3201cd09a8826bbd8050f2348cb2f: resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==} engines: {node: '>=6.0.0'} peerDependencies: diff --git a/src/Api.d.ts b/src/Api.d.ts index 8374e9d..0f36b87 100644 --- a/src/Api.d.ts +++ b/src/Api.d.ts @@ -1,5 +1,4 @@ import { Metadata as RecordMetadata, Record } from "@molgenis/vip-report-vcf/src/Vcf"; -import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser"; export interface Api { getRecordsMeta(): Promise; @@ -39,7 +38,7 @@ export interface Params { } export interface SortOrder { - property: string | FieldMetadata; + property: string | string[]; compare?: "asc" | "desc" | CompareFn; } diff --git a/src/ApiClient.ts b/src/ApiClient.ts index 90309a8..394fd0c 100644 --- a/src/ApiClient.ts +++ b/src/ApiClient.ts @@ -21,7 +21,6 @@ import { SortOrder, } from "./Api"; import { Metadata as RecordMetadata, Record } from "@molgenis/vip-report-vcf/src/Vcf"; -import { FieldMetadata, NestedFieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser"; import { compareAsc, compareDesc } from "./compare"; export interface ReportData { @@ -231,43 +230,8 @@ function getCompareFn(sortOrder: SortOrder): CompareFn { return compareFn; } -class UnknownFieldError extends Error { - constructor(fieldId: string, path: Path) { - super(`unknown field '${fieldId}' in path '[${path.join(",")}]'`); - this.name = "UnknownFieldError"; - } -} - type Path = (string | number)[]; -function getPath(property: string | FieldMetadata): Path { - if (typeof property === "string") { - return [property]; - } - - const path = []; - let field: FieldMetadata = property; - do { - const parent = field.parent; - if (parent && parent.number.count !== 1) { - const index = (parent.nested as NestedFieldMetadata).items.findIndex((item) => field.id === item.id); - if (index === -1) { - throw new UnknownFieldError(field.id, path); - } - path.push(index); - } else { - path.push(field.id); - } - - if (parent) field = parent; - else break; - } while (true); - path.push("n"); - path.reverse(); - - return path; -} - function getValue(item: Item, path: Path): CompareValue { let value: unknown = item.data; for (const token of path) { @@ -289,7 +253,7 @@ function sort(resources: Item[], sortOrders: SortOrder[]) resources.sort((a, b) => { let val = 0; for (const sortOrder of sortOrders) { - const path = getPath(sortOrder.property); + const path = typeof sortOrder.property === "string" ? [sortOrder.property] : sortOrder.property; const valueA = getValue(a, path); const valueB = getValue(b, path); diff --git a/src/__tests__/ApiClient.test.ts b/src/__tests__/ApiClient.test.ts index b2d5707..b831ed6 100644 --- a/src/__tests__/ApiClient.test.ts +++ b/src/__tests__/ApiClient.test.ts @@ -6,7 +6,6 @@ import { readFileSync } from "fs"; import { Record } from "@molgenis/vip-report-vcf/src/Vcf"; import path from "path"; import { parseVcf } from "@molgenis/vip-report-vcf/src/VcfParser"; -import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser"; let api: ApiClient; @@ -120,43 +119,6 @@ const record1: Item = { }, }; -const nString1Meta: FieldMetadata = { - id: "n_string1", - number: { - type: "NUMBER", - count: 1, - }, - type: "STRING", - description: "n_string1 description", -}; - -const nString2Meta: FieldMetadata = { - id: "n_string2", - number: { - type: "NUMBER", - count: 1, - }, - type: "STRING", - description: "n_string2 description", -}; - -const nObject0Meta: FieldMetadata = { - id: "n_object0", - number: { - type: "OTHER", - }, - type: "STRING", - description: "n_object0 description", - nested: { - items: [], - separator: ",", - }, -}; - -nString1Meta.parent = nObject0Meta; -nString2Meta.parent = nObject0Meta; -nObject0Meta.nested?.items.push(nString1Meta, nString2Meta); - beforeEach(() => { const reportData = { metadata: { @@ -441,15 +403,7 @@ test("get - one record using composed and query", async () => { test("get - all records sorted on n.n_bool0", async () => { const params: Params = { sort: { - property: { - id: "n_bool0", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool0 description", - }, + property: ["n", "n_bool0"], }, }; const records = await api.getRecords(params); @@ -459,15 +413,7 @@ test("get - all records sorted on n.n_bool0", async () => { test("get - all records sorted on n.n_bool1", async () => { const params: Params = { sort: { - property: { - id: "n_bool1", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool1 description", - }, + property: ["n", "n_bool1"], }, }; const records = await api.getRecords(params); @@ -477,15 +423,7 @@ test("get - all records sorted on n.n_bool1", async () => { test("get - all records sorted on n.n_bool2", async () => { const params: Params = { sort: { - property: { - id: "n_bool2", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool2 description", - }, + property: ["n", "n_bool2"], }, }; const records = await api.getRecords(params); @@ -495,15 +433,7 @@ test("get - all records sorted on n.n_bool2", async () => { test("get - all records sorted on n.n_bool3", async () => { const params: Params = { sort: { - property: { - id: "n_bool3", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool3 description", - }, + property: ["n", "n_bool3"], }, }; const records = await api.getRecords(params); @@ -513,15 +443,7 @@ test("get - all records sorted on n.n_bool3", async () => { test("get - all records sorted on n.n_bool4", async () => { const params: Params = { sort: { - property: { - id: "n_bool4", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool4 description", - }, + property: ["n", "n_bool4"], }, }; const records = await api.getRecords(params); @@ -531,15 +453,7 @@ test("get - all records sorted on n.n_bool4", async () => { test("get - all records sorted on n.n_bool5", async () => { const params: Params = { sort: { - property: { - id: "n_bool5", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool5 description", - }, + property: ["n", "n_bool5"], }, }; const records = await api.getRecords(params); @@ -549,15 +463,7 @@ test("get - all records sorted on n.n_bool5", async () => { test("get - all records sorted on n.n_bool6", async () => { const params: Params = { sort: { - property: { - id: "n_bool6", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool6 description", - }, + property: ["n", "n_bool6"], }, }; const records = await api.getRecords(params); @@ -567,15 +473,7 @@ test("get - all records sorted on n.n_bool6", async () => { test("get - all records sorted on n.n_bool7", async () => { const params: Params = { sort: { - property: { - id: "n_bool7", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool7 description", - }, + property: ["n", "n_bool7"], }, }; const records = await api.getRecords(params); @@ -585,15 +483,7 @@ test("get - all records sorted on n.n_bool7", async () => { test("get - all records sorted on n.n_bool8", async () => { const params: Params = { sort: { - property: { - id: "n_bool8", - number: { - type: "NUMBER", - count: 1, - }, - type: "FLAG", - description: "n_bool8 description", - }, + property: ["n", "n_bool8"], }, }; const records = await api.getRecords(params); @@ -603,15 +493,7 @@ test("get - all records sorted on n.n_bool8", async () => { test("get - all records sorted on n.n_number0", async () => { const params: Params = { sort: { - property: { - id: "n_number0", - number: { - type: "NUMBER", - count: 1, - }, - type: "INTEGER", - description: "n_number0 description", - }, + property: ["n", "n_number0"], }, }; const records = await api.getRecords(params); @@ -621,15 +503,7 @@ test("get - all records sorted on n.n_number0", async () => { test("get - all records sorted on n.n_number1", async () => { const params: Params = { sort: { - property: { - id: "n_number1", - number: { - type: "NUMBER", - count: 1, - }, - type: "INTEGER", - description: "n_number1 description", - }, + property: ["n", "n_number1"], }, }; const records = await api.getRecords(params); @@ -639,15 +513,7 @@ test("get - all records sorted on n.n_number1", async () => { test("get - all records sorted on n.n_number2", async () => { const params: Params = { sort: { - property: { - id: "n_number2", - number: { - type: "NUMBER", - count: 1, - }, - type: "INTEGER", - description: "n_number2 description", - }, + property: ["n", "n_number2"], }, }; const records = await api.getRecords(params); @@ -657,15 +523,7 @@ test("get - all records sorted on n.n_number2", async () => { test("get - all records sorted on n.n_string0", async () => { const params: Params = { sort: { - property: { - id: "n_string0", - number: { - type: "NUMBER", - count: 1, - }, - type: "STRING", - description: "n_string0 description", - }, + property: ["n", "n_string0"], }, }; const records = await api.getRecords(params); @@ -675,15 +533,7 @@ test("get - all records sorted on n.n_string0", async () => { test("get - all records sorted on n.n_string3", async () => { const params: Params = { sort: { - property: { - id: "n_string3", - number: { - type: "NUMBER", - count: 1, - }, - type: "STRING", - description: "n_string3 description", - }, + property: ["n", "n_string3"], }, }; const records = await api.getRecords(params); @@ -693,15 +543,7 @@ test("get - all records sorted on n.n_string3", async () => { test("get - all records sorted on n.n_string4", async () => { const params: Params = { sort: { - property: { - id: "n_string4", - number: { - type: "NUMBER", - count: 1, - }, - type: "STRING", - description: "n_string4 description", - }, + property: ["n", "n_string4"], }, }; const records = await api.getRecords(params); @@ -711,14 +553,7 @@ test("get - all records sorted on n.n_string4", async () => { test("get - all records sorted on n.n_array0", async () => { const params: Params = { sort: { - property: { - id: "n_array0", - number: { - type: "OTHER", - }, - type: "STRING", - description: "n_string0 description", - }, + property: ["n", "n_array0"], compare: "asc", }, }; @@ -729,7 +564,7 @@ test("get - all records sorted on n.n_array0", async () => { test("get - all records sorted on n.n_object0.n_string2 ascending", async () => { const params: Params = { sort: { - property: nString2Meta, + property: ["n", "n_object0", "1"], compare: "asc", }, }; @@ -740,7 +575,7 @@ test("get - all records sorted on n.n_object0.n_string2 ascending", async () => test("get - all records sorted on n.n_object0.n_string2 descending", async () => { const params: Params = { sort: { - property: nString2Meta, + property: ["n", "n_object0", "1"], compare: "desc", }, }; @@ -751,14 +586,7 @@ test("get - all records sorted on n.n_object0.n_string2 descending", async () => test("get - all records sorted on n.n_object0 throws an error", async () => { const params: Params = { sort: { - property: { - id: "n_object0", - number: { - type: "OTHER", - }, - type: "STRING", - description: "n_object0 description", - }, + property: ["n", "n_object0"], }, }; await expect(api.getRecords(params)).rejects.toThrow("can't compare values of type 'object'.");