Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request - add uniqueItems and sorted properties to array type #72

Open
MarcelOldenkamp opened this issue May 8, 2023 · 0 comments

Comments

@MarcelOldenkamp
Copy link

MarcelOldenkamp commented May 8, 2023

Similar to the existing properties minLength and minLength add support for properties uniqueItems and sorted.

  • Sorted should accept a selector function to specify the value to sort on (perhaps also sort order).
  • uniqueItems boolean true (or perhaps an optional selector function to only enforce uniqueness of a specific value)?

With this feature we would no longer need to define custom types like:

/**
 * An array with length > 0 and distinct values.
 * Allows custom comparator function to specify 'distinct' values, defaults to 'isEqual', which performs a deep comparison between two values for equality comparison.
 * Note that although array length is validated, the array element(s) itself may still be falsy (undefined etc.) depending on the elementType.
 * WARNING: Be sure to document the distinct behavior in de OpenApiMetadata of the type you are using this with so API consumers are aware
 * of this restriction
 * @param elementType the type of the array elements.
 */
type NonEmptyDistinctArray<T> = Branded<T[], 'NonEmptyDistinctArray'>;
function NonEmptyDistinctArray<T>(elementType: Type<T>, comparatorFn: Comparator<T> = isEqual): Type<NonEmptyDistinctArray<T>> {
    const type = NonEmptyArray<T>(elementType)
        // Set the brand to plain `NonEmptyDistinctArray`:
        .withConstraint('NonEmptyDistinctArray', value => {
            return uniqWith(value, comparatorFn).length === value.length || 'no duplicate values allowed';
        });
    // But set the runtime name to be more specific:
    Object.defineProperty(type, 'name', { value: `NonEmptyDistinctArray<${elementType.name}>` });
    return type;
}

type NonEmptyDistinctSortedDates<T> = Branded<T[], 'NonEmptyDistinctSortedDates' | 'NonEmptyDistinctArray'>;
function NonEmptyDistinctSortedDates<T extends ISODate>(elementType: Type<T>) {
    const type = NonEmptyDistinctArray<T>(elementType)
        // Set the brand to plain `NonEmptyDistinctSortedDates`:
        .withConstraint('NonEmptyDistinctSortedDates', value => {
            return value.every(pairwise((next, prev) => !prev || next > prev)) || 'should be sorted by date';
        });
    // But set the runtime name to be more specific:
    Object.defineProperty(type, 'name', { value: `SortedByDate<${elementType.name}>` });
    return type;
}

with:

/**
 * An array with length > 0.
 * Note that although array length is validated, the array element(s) itself may still be falsy (undefined etc.) depending on the elementType.
 * @param elementType the type of the array elements.
 */
export function NonEmptyArray<T>(elementType: Type<T>): Type<T[]> {
    return array(elementType).withConfig(`NonEmptyArray<${elementType.name}>`, {
        minLength: 1,
        customMessage: `expected at least one ${elementType.name}`,
    });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant