added unique constraint assertion tools

This commit is contained in:
2024-04-09 08:56:28 -05:00
parent 2b2ff8e4ab
commit 1b47be09de
4 changed files with 90 additions and 3 deletions

View File

@@ -1,13 +1,18 @@
{ {
"name": "utility-closet", "name": "utility-closet",
"version": "0.0.1", "version": "0.0.2",
"main": "index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/innocuous-symmetry/utility-closet.git"
},
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"test": "vitest" "test": "vitest"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "Mikayla Dobson",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"csv-parse": "^5.5.5", "csv-parse": "^5.5.5",

10
pkg/index.ts Normal file
View File

@@ -0,0 +1,10 @@
export * from "./async";
export * from "./csv";
export * from "./dom";
export * from "./logger";
export * from "./obj";
export * from "./queue";
export * from "./time";
export * from "./types";
export * from "./unique";
export * from "./validators";

22
pkg/unique.ts Normal file
View File

@@ -0,0 +1,22 @@
import { z } from "zod";
export type AssertUniqueType<T extends Record<string, unknown>> = z.ZodEffects<z.ZodArray<z.ZodType<T>>, T[], unknown>;
export function generateUniqueValidator<T extends Record<string, unknown>>(validator: z.ZodType<T>, ...keys: (keyof T)[]) {
return validator.array().refine((val) => {
for (const key of keys ?? []) {
const values = val.map((item) => item[key as keyof T]);
return values.length === new Set(values).size;
}
}, {
message: "Encountered duplicate values in unique field"
}) satisfies AssertUniqueType<T>;
}
export function assertUniqueKeys<T extends Record<string, unknown>>(data: T[], validator: z.ZodType<T>, ...keys: (keyof T)[]) {
return generateUniqueValidator(validator, ...keys).parse(data) satisfies T[];
}
export async function assertUniqueKeysAsync<T extends Record<string, unknown>>(data: T[], validator: z.ZodType<T>, ...keys: (keyof T)[]) {
return generateUniqueValidator(validator, ...keys).parseAsync(data) satisfies Promise<T[]>;
}

50
tests/unique.test.ts Normal file
View File

@@ -0,0 +1,50 @@
import { describe, it, expect } from 'vitest';
import { z } from 'zod';
import { assertUniqueKeys } from "../pkg/unique";
describe("assert unique", () => {
it("should assert unique keys in a homogenous array", () => {
const data = [
{ id: 1, name: "John" },
{ id: 2, name: "Doe" },
{ id: 3, name: "Jane" },
];
const validator = z.object({
id: z.number(),
name: z.string(),
});
expect(
() => assertUniqueKeys(data, validator, "id")
).not.toThrow();
})
it("should reject arrays violating unique key constraints", () => {
const data = [
{ id: 1, name: "John" },
{ id: 1, name: "Doe" },
{ id: 1, name: "Jane" },
];
const validator = z.object({
id: z.number(),
name: z.string(),
});
expect(
() => assertUniqueKeys(data, validator, "id")
).toThrowError("Encountered duplicate values in unique field");
})
it("should only allow record types", () => {
const data = [
2, 3, 4, 5, "foo", "bar", true
];
const validator = z.union([z.number(), z.string(), z.boolean()]);
expect(
// @ts-expect-error
() => assertUniqueKeys(data, validator)
).toThrow();
})
})