added unique constraint assertion tools
This commit is contained in:
11
package.json
11
package.json
@@ -1,13 +1,18 @@
|
||||
{
|
||||
"name": "utility-closet",
|
||||
"version": "0.0.1",
|
||||
"main": "index.js",
|
||||
"version": "0.0.2",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/innocuous-symmetry/utility-closet.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "vitest"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"author": "Mikayla Dobson",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"csv-parse": "^5.5.5",
|
||||
|
||||
10
pkg/index.ts
Normal file
10
pkg/index.ts
Normal 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
22
pkg/unique.ts
Normal 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
50
tests/unique.test.ts
Normal 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();
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user