feat(infra): orm f.enum() support (#9323)

This commit is contained in:
CatsJuice
2024-12-31 03:44:58 +00:00
parent 9c119e6505
commit 7c41775c7f
4 changed files with 36 additions and 6 deletions

View File

@@ -61,6 +61,7 @@ describe('Entity validations', () => {
id: f.string().primaryKey().default(nanoid),
name: f.string(),
color: f.string(),
status: f.enum('active', 'inactive').optional(),
},
});
@@ -130,4 +131,15 @@ describe('Entity validations', () => {
expect(tag.info).toBe(null);
});
});
test('should throw when trying to create entity with invalid enum value', () => {
const client = createTagsClient();
expect(() =>
// @ts-expect-error test
client.tags.create({ name: 'test', status: 'not-active' })
).toThrow(
"[Table(tags)]: Field 'status' value 'not-active' is not valid. Expected one of [active, inactive]."
);
});
});

View File

@@ -1,10 +1,11 @@
export type FieldType = 'string' | 'number' | 'boolean' | 'json';
export type FieldType = 'string' | 'number' | 'boolean' | 'json' | 'enum';
export interface FieldSchema<Type = unknown> {
type: FieldType;
optional: boolean;
isPrimaryKey: boolean;
default?: () => Type;
values?: Type[];
}
export type TableSchema = Record<string, FieldSchema>;
@@ -28,10 +29,12 @@ export class FieldSchemaBuilder<
optional: false,
isPrimaryKey: false,
default: undefined,
values: undefined,
};
constructor(type: FieldType) {
constructor(type: FieldType, values?: string[]) {
this.schema.type = type;
this.schema.values = values;
}
optional() {
@@ -56,7 +59,9 @@ export const f = {
number: () => new FieldSchemaBuilder<number>('number'),
boolean: () => new FieldSchemaBuilder<boolean>('boolean'),
json: <T = any>() => new FieldSchemaBuilder<T>('json'),
} satisfies Record<FieldType, () => FieldSchemaBuilder<any>>;
enum: <T extends string>(...values: T[]) =>
new FieldSchemaBuilder<T>('enum', values),
} as const;
export const t = {
document: <T extends TableSchemaBuilder>(schema: T) => {

View File

@@ -70,7 +70,14 @@ export const dataValidators = {
}
const typeGet = inputType(val);
if (!typeMatches(field.type, typeGet)) {
if (field.type === 'enum') {
if (!field.values?.includes(val)) {
throw new Error(
`[Table(${table.name})]: Field '${key}' value '${val}' is not valid. Expected one of [${field.values?.join(', ')}].`
);
}
} else if (!typeMatches(field.type, typeGet)) {
throw new Error(
`[Table(${table.name})]: Field '${key}' type mismatch. Expected ${field.type} got ${typeGet}.`
);
@@ -103,7 +110,13 @@ export const dataValidators = {
}
const typeGet = inputType(val);
if (!typeMatches(field.type, typeGet)) {
if (field.type === 'enum') {
if (!field.values?.includes(val)) {
throw new Error(
`[Table(${table.name})]: Field '${key}' value '${val}' is not valid. Expected one of [${field.values?.join(', ')}].`
);
}
} else if (!typeMatches(field.type, typeGet)) {
throw new Error(
`[Table(${table.name})]: Field '${key}' type mismatch. Expected type '${field.type}' but got '${typeGet}'.`
);