Skip to content

Commit

Permalink
fix: add maxDepth to getFieldFilterFromPath
Browse files Browse the repository at this point in the history
  • Loading branch information
Birkbjo committed Sep 14, 2023
1 parent dbc4f82 commit 0f6efc0
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 11 deletions.
9 changes: 7 additions & 2 deletions src/constants/sectionListViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,13 @@ const modelListViewsConfig = {
dataElement: {
columns: {
available: ['zeroIsSignificant', 'categoryCombo'],
default: ['name', 'domainType', 'valueType', 'lastUpdated'],
default: [
'name',
'domainType',
'valueType',
'lastUpdated',
'sharing.public',
],
},
filters: {
default: ['name', 'domainType', 'valueType'],
Expand All @@ -92,7 +98,6 @@ const toModelPropertyDescriptor = (
const availableDescriptor = available?.find(
(prop) => prop.path === propertyConfig
)
console.log({ availableDescriptor })

return (
availableDescriptor || {
Expand Down
29 changes: 29 additions & 0 deletions src/lib/models/path.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,34 @@ describe('path', () => {
const result = getFieldFilterFromPath(path)
expect(result).toBe('user[address[city]]')
})

it('should drop nested fields if maxDepth is 0', () => {
const path = 'sharing.public'
const result = getFieldFilterFromPath(path, 0)
expect(result).toBe('sharing')

const pathArr = ['sharing', 'public']
const resultArr = getFieldFilterFromPath(pathArr, 0)
expect(resultArr).toBe(result)
})

it('should drop nested fields according to maxDepth', () => {
const path = 'sharing.public'

const result = getFieldFilterFromPath(path, 1)

expect(result).toBe('sharing[public]')

const deCatComboPath = 'dataElement.categoryCombo.id'
const resultDepth1 = getFieldFilterFromPath(deCatComboPath, 1)

expect(resultDepth1).toBe('dataElement[categoryCombo]')

const resultDepth2 = getFieldFilterFromPath(deCatComboPath, 2)
expect(resultDepth2).toBe('dataElement[categoryCombo[id]]')

const resultDepth3 = getFieldFilterFromPath(deCatComboPath, 3)
expect(resultDepth3).toBe('dataElement[categoryCombo[id]]')
})
})
})
45 changes: 36 additions & 9 deletions src/lib/models/path.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
export const stringToPathArray = (str: string): string[] => str.split('.')

const resolvePath = (path: string | string[]): string[] => {
return typeof path === 'string' ? stringToPathArray(path) : path
return typeof path === 'string'
? stringToPathArray(path)
: path.filter((p) => !!p) // filter out empty strings
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getIn = (object: any, path: string | string[]) => {
const pathArray = resolvePath(path)

Expand All @@ -17,14 +20,38 @@ export const getIn = (object: any, path: string | string[]) => {
return current
}

export const getFieldFilterFromPath = (path: string | string[]): string => {
const pathParts = resolvePath(path)
if (pathParts.length === 1) {
return pathParts[0]
}
/**
* Transforms a path like dataElement.id into a field filter of the form `dataElement[id]`
* @param path the path to transform, a dot-delimited string or an array of strings
* @param maxDepth the maximum number of nested fields to allow. If the path is deeper than this, the parts after the depth will be dropped.
* Set this to 0 to create field-filters without the nested parts. Can be useful if the API does not support nested field-filters
* for a particular request.
* @returns
*/
export const getFieldFilterFromPath = (
path: string | string[],
maxDepth = 10
): string => {
const recur = (path: string[], depth: number): string => {
const pathParts = resolvePath(path)

if (pathParts.length === 0) {
return ''
}
if (pathParts.length === 1) {
return pathParts[0]
}

const [currentPart, ...rest] = pathParts

const [currentPart, ...rest] = pathParts
const nestedFilter = getFieldFilterFromPath(rest)
if (depth >= maxDepth) {
return currentPart
}

const nestedFilter = recur(rest, depth + 1)

return `${currentPart}[${nestedFilter}]`
}

return `${currentPart}[${nestedFilter}]`
return recur(resolvePath(path), 0)
}
57 changes: 57 additions & 0 deletions src/lib/models/typePath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//@ts-nocheck

Check failure on line 1 in src/lib/models/typePath.ts

View workflow job for this annotation

GitHub Actions / lint

Do not use "@ts-nocheck" because it alters compilation errors

import type { DataElement, IdentifiableObject } from '../../types/generated'

type Split<S extends string, D extends string = '.'> = string extends S
? string[]
: S extends ''
? []
: S extends `${infer T}${D}${infer U}`
? [T, ...Split<U, D>]
: [S]

type SS = Split<'access'>

type PathsForModel<Model> = Values<{
[key in keyof Model]: key extends string
? Model[key] extends object
? [key] | readonly [key, Flatten<PathsForModel<Model[key]>>]
: key
: never
}>

type Values<T> = T[keyof T]

type PFM = PathsForModel<DataElement>
type Acc = Extract<PFM, readonly ['access', any]>
type accz = Acc[1]
type Flatten<T> = T extends (infer U)[] ? (U extends any[] ? Flatten<U> : U) : T

type TypeForPath<Model, Paths extends string[]> = Paths extends [
infer Head,
...infer Tail extends string[]
]
? Head extends keyof Model
? TypeForPath<Model[Head], Tail>
: never
: Model

type A = TypeForPath<DataElement, ['access', 'data']>

type IsPathFor<Path extends string, Model> = TypeForPath<
Model,
Split<Path>
> extends [never]
? never
: string

type IPF = IsPathFor<'accesss.data', DataElement>

type AllPathsFor = {
path: PathsForModel<DataElement>
}

type arr = []
const obj = {
path: ['valueTypeOptions'],
} satisfies AllPathsFor

0 comments on commit 0f6efc0

Please sign in to comment.