Skip to content

[validator] Add built-in unique comparison validator constraint #170

@imdhemy

Description

@imdhemy

We should add a built-in unique constraint under comparison constraints to validate that array elements are unique.

Proposal

Add a new built-in constraint named unique with options shaped like the existing built-ins, including shared validator metadata such as groups:

type UniqueOptions = ConstraintOptions & {
  message?: string;
  normalizer?: (value: unknown) => unknown;
  fields?: string[];
};

Example usage:

const rules = {
  tags: [{ unique: {} }],
  emails: [{ unique: { normalizer: value => typeof value === 'string' ? value.trim() : value } }],
  coordinates: [{ unique: { fields: ['latitude', 'longitude'] } }],
  usernames: [{ unique: { groups: ['create'] } }],
};

Expected behavior

  • unique should live in the comparison constraint group.
  • It should be exported from the validator constraints public API and registered in builtInConstraints.
  • It should support shared validator metadata exposed through ConstraintOptions, including groups.
  • It should validate arrays for duplicate elements.
  • By default, comparison should be strict, so '7' and 7 are considered different values.
  • It should return no violations when all array elements are unique.
  • It should return one violation when at least one duplicate is found.
  • It should support a custom message option, consistent with the existing constraints.
  • normalizer should be applied to each array element before uniqueness is checked.
  • fields should allow uniqueness checks based on a combination of fields for arrays of objects.
  • It should preserve current optional-field semantics used by other constraints: undefined should be considered valid unless presence is enforced separately.
  • null handling should be defined explicitly and covered by tests. [Failure, as null is not a list]
  • undefined handling should be defined explicitly and covered by tests. [ByPass validation]
  • Non-array values should be handled explicitly and covered by tests.

Default message

A sensible default would be:

This collection should contain only unique elements.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions