Skip to content

Commit

Permalink
Fix infinitely recursive type in drizzle-valibot
Browse files Browse the repository at this point in the history
  • Loading branch information
L-Mario564 committed Dec 17, 2024
1 parent 2e49ebc commit 6f8a6cc
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 69 deletions.
98 changes: 31 additions & 67 deletions drizzle-valibot/src/column.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,23 @@ export type ExtractAdditionalProperties<TColumn extends Column> = {
fixedLength: TColumn['_']['columnType'] extends 'PgChar' | 'MySqlChar' | 'PgHalfVector' | 'PgVector' | 'PgArray'
? true
: false;
arrayPipelines: [];
};

type RemovePipeIfNoElements<T extends v.SchemaWithPipe<[any, ...any[]]>> = T extends
infer TPiped extends { pipe: [any, ...any[]] } ? TPiped['pipe'][1] extends undefined ? T['pipe'][0] : TPiped
: never;
type GetLengthAction<T extends Record<string, any>, TType extends string | ArrayLike<unknown>> =
T['fixedLength'] extends true ? v.LengthAction<TType, number, undefined>
: v.MaxLengthAction<TType, number, undefined>;

type BuildArraySchema<
TWrapped extends v.GenericSchema,
TPipelines extends any[][],
> = TPipelines extends [infer TFirst extends any[], ...infer TRest extends any[][]]
? BuildArraySchema<RemovePipeIfNoElements<v.SchemaWithPipe<[v.ArraySchema<TWrapped, undefined>, ...TFirst]>>, TRest>
: TPipelines extends [infer TFirst extends any[]]
? BuildArraySchema<RemovePipeIfNoElements<v.SchemaWithPipe<[v.ArraySchema<TWrapped, undefined>, ...TFirst]>>, []>
: TWrapped;
type GetArraySchema<T extends Column> = v.ArraySchema<
GetValibotType<
T['_']['data'],
T['_']['dataType'],
T['_']['columnType'],
GetEnumValuesFromColumn<T>,
GetBaseColumn<T>,
ExtractAdditionalProperties<T>
>,
undefined
>;

export type GetValibotType<
TData,
Expand All @@ -53,51 +55,22 @@ export type GetValibotType<
TEnumValues extends [string, ...string[]] | undefined,
TBaseColumn extends Column | undefined,
TAdditionalProperties extends Record<string, any>,
> = TColumnType extends 'PgHalfVector' | 'PgVector' ? RemovePipeIfNoElements<
v.SchemaWithPipe<
RemoveNeverElements<[
v.ArraySchema<v.NumberSchema<undefined>, undefined>,
TAdditionalProperties['max'] extends number
? TAdditionalProperties['fixedLength'] extends true ? v.LengthAction<number[], number, undefined>
: v.MaxLengthAction<number[], number, undefined>
: never,
]>
> = TColumnType extends 'PgHalfVector' | 'PgVector' ? TAdditionalProperties['max'] extends number ? v.SchemaWithPipe<
[v.ArraySchema<v.NumberSchema<undefined>, undefined>, GetLengthAction<TAdditionalProperties, number[]>]
>
>
: v.ArraySchema<v.NumberSchema<undefined>, undefined>
: TColumnType extends 'PgUUID' ? v.SchemaWithPipe<[v.StringSchema<undefined>, v.UuidAction<string, undefined>]>
// PG array handling start
// Nesting `GetValibotType` within `v.ArraySchema` will cause infinite recursion
// The workaround is to accumulate all the array validations (done via `arrayPipelines` in `TAdditionalProperties`) and then build the schema afterwards
: TAdditionalProperties['arrayFinished'] extends true ? GetValibotType<
TData,
TDataType,
TColumnType,
TEnumValues,
TBaseColumn,
Omit<TAdditionalProperties, 'arrayFinished'>
> extends infer TSchema extends v.GenericSchema ? BuildArraySchema<TSchema, TAdditionalProperties['arrayPipelines']>
: never
: TBaseColumn extends Column ? GetValibotType<
TBaseColumn['_']['data'],
TBaseColumn['_']['dataType'],
TBaseColumn['_']['columnType'],
GetEnumValuesFromColumn<TBaseColumn>,
GetBaseColumn<TBaseColumn>,
Omit<ExtractAdditionalProperties<TBaseColumn>, 'arrayPipelines'> & {
arrayPipelines: [
RemoveNeverElements<[
TAdditionalProperties['max'] extends number
? TAdditionalProperties['fixedLength'] extends true
? v.LengthAction<Assume<TBaseColumn['_']['data'], any[]>[], number, undefined>
: v.MaxLengthAction<Assume<TBaseColumn['_']['data'], any[]>[], number, undefined>
: never,
]>,
...TAdditionalProperties['arrayPipelines'],
];
arrayFinished: GetBaseColumn<TBaseColumn> extends undefined ? true : false;
}
: TColumnType extends 'PgBinaryVector' ? v.SchemaWithPipe<
RemoveNeverElements<[
v.StringSchema<undefined>,
v.RegexAction<string, undefined>,
TAdditionalProperties['max'] extends number ? GetLengthAction<TAdditionalProperties, string> : never,
]>
>
// PG array handling end
: TBaseColumn extends Column ? TAdditionalProperties['max'] extends number ? v.SchemaWithPipe<
[GetArraySchema<TBaseColumn>, GetLengthAction<TAdditionalProperties, TBaseColumn['_']['data'][]>]
>
: GetArraySchema<TBaseColumn>
: ArrayHasAtLeastOneValue<TEnumValues> extends true
? v.EnumSchema<EnumValuesToEnum<Assume<TEnumValues, [string, ...string[]]>>, undefined>
: TData extends infer TTuple extends [any, ...any[]] ? v.TupleSchema<
Expand Down Expand Up @@ -147,19 +120,10 @@ export type GetValibotType<
v.MaxValueAction<bigint, bigint, undefined>,
]>
: TData extends boolean ? v.BooleanSchema<undefined>
: TData extends string ? RemovePipeIfNoElements<
v.SchemaWithPipe<
RemoveNeverElements<[
v.StringSchema<undefined>,
TColumnType extends 'PgBinaryVector' ? v.RegexAction<string, undefined>
: never,
TAdditionalProperties['max'] extends number
? TAdditionalProperties['fixedLength'] extends true ? v.LengthAction<string, number, undefined>
: v.MaxLengthAction<string, number, undefined>
: never,
]>
>
>
: TData extends string
? TAdditionalProperties['max'] extends number
? v.SchemaWithPipe<[v.StringSchema<undefined>, GetLengthAction<TAdditionalProperties, string>]>
: v.StringSchema<undefined>
: v.AnySchema;

type HandleSelectColumn<
Expand Down
3 changes: 1 addition & 2 deletions drizzle-valibot/src/schema.types.internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ export type BuildSchema<
TType extends 'select' | 'insert' | 'update',
TColumns extends Record<string, any>,
TRefinements extends Record<string, any> | undefined,
> // @ts-ignore false-positive
= v.ObjectSchema<
> = v.ObjectSchema<
Simplify<
RemoveNever<
{
Expand Down

0 comments on commit 6f8a6cc

Please sign in to comment.