Skip to content

Commit

Permalink
[CP-3166] Refactored dataProviderSort to use type-safe comparison and…
Browse files Browse the repository at this point in the history
… modular helper functions
  • Loading branch information
dkarski committed Oct 8, 2024
1 parent eb92248 commit 6dd0940
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 36 deletions.
12 changes: 10 additions & 2 deletions libs/device/models/src/lib/feature/data-provider-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,21 @@ export type DataProviderField =
| z.infer<typeof enhancedFieldSchema>
| z.infer<typeof superEnhancedFieldSchema>

const sortDirectionSchema = z.union([z.literal("asc"), z.literal("desc")]);

export type sortDirection = z.infer<typeof sortDirectionSchema>

const sortOrderingPatternsSchema = z.array(regexSchema);

export type sortOrderingPatterns = z.infer<typeof sortOrderingPatternsSchema>

const sortSchema = z
.array(
z.object({
providerField: z.string(),
priority: z.number().nonnegative(),
direction: z.union([z.literal("asc"), z.literal("desc")]),
orderingPatterns: z.array(regexSchema).optional(),
direction: sortDirectionSchema,
orderingPatterns: sortOrderingPatternsSchema.optional(),
})
)
.optional()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import { cloneDeep } from "lodash"
import { DataProviderSortConfig, sortDirection, sortOrderingPatterns } from "device/models"
import { stringToRegex } from "./string-to-regex"

export const sortByPriority = (sortConfigs: DataProviderSortConfig) => {
if (!sortConfigs) return []
return cloneDeep(sortConfigs).sort((a, b) => a.priority - b.priority)
}

export const compareFields = (
fieldA: string,
fieldB: string,
direction: sortDirection
) => {
return direction === "asc"
? fieldA.localeCompare(fieldB)
: fieldB.localeCompare(fieldA)
}

export const compareWithOrderingPatterns = (
fieldA: string,
fieldB: string,
patterns: sortOrderingPatterns,
direction: sortDirection
) => {
const directionMultiplier = direction === "asc" ? 1 : -1

for (const pattern of patterns) {
const regex = stringToRegex(pattern)
const matchA = regex.test(fieldA)
const matchB = regex.test(fieldB)

if (matchA && !matchB) return -1 * directionMultiplier
if (!matchA && matchB) return 1 * directionMultiplier
}
return 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,49 @@
*/

import { DataProviderSortConfig } from "device/models"
import { stringToRegex } from "./string-to-regex"
import { cloneDeep, get } from "lodash"
import { get } from "lodash"
import {
compareFields,
compareWithOrderingPatterns,
sortByPriority,
} from "./data-provider-sort.helpers"

export const dataProviderSort = (
data: Record<string, unknown>[] = [],
sort?: DataProviderSortConfig
sortConfigs?: DataProviderSortConfig
) => {
if (!sort || !data) return data
const fieldsSortedByPriority = cloneDeep(sort).sort(
(a, b) => a.priority - b.priority
)
if (!sortConfigs || !data) return data

const sortedConfigs = sortByPriority(sortConfigs)

return data.sort((a, b) => {
let score = 0
for (const {
providerField,
direction,
orderingPatterns = [],
} of fieldsSortedByPriority) {
const fieldA = get(a, providerField) as string
const fieldB = get(b, providerField) as string
if (!fieldA || !fieldB) {
} of sortedConfigs) {
const fieldA = get(a, providerField)
const fieldB = get(b, providerField)

if (typeof fieldA !== "string" || typeof fieldB !== "string") {
continue
}

for (let i = 0; i < orderingPatterns.length; i++) {
const regex = stringToRegex(orderingPatterns[i])
const matchA = regex.test(fieldA)
const matchB = regex.test(fieldB)

if (matchA && !matchB) {
score = -1
break
}
if (!matchA && matchB) {
score = 1
break
}
const regexComparison = compareWithOrderingPatterns(
fieldA,
fieldB,
orderingPatterns,
direction
)
if (regexComparison !== 0) {
return regexComparison
}
if (score === 0) {
score =
direction === "asc"
? fieldA.localeCompare(fieldB)
: fieldB.localeCompare(fieldA)
if (score !== 0) {
break
}

const fieldComparison = compareFields(fieldA, fieldB, direction)
if (fieldComparison !== 0) {
return fieldComparison
}
}
return score
return 0
})
}

0 comments on commit 6dd0940

Please sign in to comment.