@@ -9,19 +9,62 @@ import {
99 ZodObject ,
1010 ZodEffects ,
1111 ZodOptional ,
12+ ZodNullable ,
13+ ZodType ,
1214} from 'zod' ;
1315
1416import { Entity } from '../../../types' ;
15- import { FieldWithType , TypeField } from '../../orm' ;
17+ import {
18+ FieldWithType ,
19+ PropsFieldItem ,
20+ PropsForField ,
21+ TypeField ,
22+ } from '../../orm' ;
1623import { ObjectTyped } from '../../utils' ;
1724import { nonEmptyObject } from '../zod-utils' ;
1825
26+ const literalSchema = z . union ( [ z . string ( ) , z . number ( ) , z . boolean ( ) ] ) ;
27+
28+ const getZodSchemaForJson = ( isNull : boolean ) => {
29+ const tmpSchema = isNull ? literalSchema . nullable ( ) : literalSchema ;
30+ const jsonSchema : any = z . lazy ( ( ) =>
31+ z . union ( [
32+ tmpSchema ,
33+ z . array ( jsonSchema . nullable ( ) ) ,
34+ z . record ( jsonSchema . nullable ( ) ) ,
35+ ] )
36+ ) ;
37+
38+ return jsonSchema ;
39+ } ;
40+
41+ type Literal = ReturnType < typeof getZodSchemaForJson > ;
42+
43+ type Json = Literal | { [ key : string ] : Json } | Json [ ] ;
44+
45+ type ZodTypeForArray =
46+ | ZodString
47+ | ZodDate
48+ | ZodEffects < ZodNumber , number , unknown >
49+ | ZodBoolean ;
50+ type ZodArrayType =
51+ | ZodArray < ZodTypeForArray , 'many' >
52+ | ZodNullable < ZodArray < ZodTypeForArray , 'many' > > ;
53+
1954type TypeMapToZod = {
20- [ TypeField . array ] : ZodOptional < ZodArray < ZodString , 'many' > > ;
21- [ TypeField . date ] : ZodOptional < ZodDate > ;
22- [ TypeField . number ] : ZodOptional < ZodNumber > ;
23- [ TypeField . boolean ] : ZodOptional < ZodBoolean > ;
24- [ TypeField . string ] : ZodOptional < ZodString | ZodEnum < [ string , ...string [ ] ] > > ;
55+ [ TypeField . array ] : ZodOptional < ZodArrayType > ;
56+ [ TypeField . date ] : ZodOptional < ZodDate | ZodNullable < ZodDate > > ;
57+ [ TypeField . number ] : ZodOptional <
58+ | ZodEffects < ZodNumber , number , unknown >
59+ | ZodNullable < ZodEffects < ZodNumber , number , unknown > >
60+ > ;
61+ [ TypeField . boolean ] : ZodOptional < ZodBoolean | ZodNullable < ZodBoolean > > ;
62+ [ TypeField . string ] : ZodOptional <
63+ | ZodString
64+ | ZodEnum < [ string , ...string [ ] ] >
65+ | ZodNullable < ZodString | ZodEnum < [ string , ...string [ ] ] > >
66+ > ;
67+ [ TypeField . object ] : ZodType < Json > | ZodNullable < ZodType < Json > > ;
2568} ;
2669
2770type ZodShapeAttributes < E extends Entity > = Omit <
@@ -35,28 +78,92 @@ export type ZodAttributesSchema<E extends Entity> = ZodEffects<
3578 ZodObject < ZodShapeAttributes < E > , 'strict' >
3679> ;
3780
81+ function getZodSchemaForArray ( props : PropsFieldItem ) : ZodTypeForArray {
82+ if ( ! props ) return z . string ( ) ;
83+ let zodSchema : ZodTypeForArray ;
84+ switch ( props . type ) {
85+ case 'number' :
86+ case 'real' :
87+ case 'integer' :
88+ case 'bigint' :
89+ case 'double' :
90+ case 'numeric' :
91+ case Number :
92+ zodSchema = z . preprocess ( ( x ) => Number ( x ) , z . number ( ) ) ;
93+ break ;
94+ case 'date' :
95+ case Date :
96+ zodSchema = z . coerce . date ( ) ;
97+ break ;
98+ case 'boolean' :
99+ case Boolean :
100+ zodSchema = z . boolean ( ) ;
101+ break ;
102+ default :
103+ zodSchema = z . string ( ) ;
104+ }
105+
106+ return zodSchema ;
107+ }
108+
38109export const zodAttributesSchema = < E extends Entity > (
39- fieldWithType : FieldWithType < E >
110+ fieldWithType : FieldWithType < E > ,
111+ propsDb : PropsForField < E >
40112) : ZodAttributesSchema < E > => {
41113 const shape = ObjectTyped . entries ( fieldWithType ) . reduce (
42114 ( acum , [ props , type ] : [ keyof FieldWithType < E > , TypeField ] ) => {
43115 let zodShema : TypeMapToZod [ typeof type ] ;
116+ const propsDbType = propsDb [ props ] ;
44117 switch ( type ) {
45- case TypeField . array :
46- zodShema = z . string ( ) . array ( ) . optional ( ) ;
118+ case TypeField . array : {
119+ const tmpSchema = getZodSchemaForArray ( propsDbType ) . array ( ) ;
120+ zodShema = (
121+ propsDbType && propsDbType . isNullable
122+ ? tmpSchema . nullable ( )
123+ : tmpSchema
124+ ) . optional ( ) ;
125+ break ;
126+ }
127+ case TypeField . date : {
128+ const tmpSchema = z . coerce . date ( ) ;
129+ zodShema = (
130+ propsDbType && propsDbType . isNullable
131+ ? tmpSchema . nullable ( )
132+ : tmpSchema
133+ ) . optional ( ) ;
47134 break ;
48- case TypeField . date :
49- zodShema = z . coerce . date ( ) . optional ( ) ;
135+ }
136+ case TypeField . number : {
137+ const tmpSchema = z . preprocess ( ( x ) => Number ( x ) , z . number ( ) ) ;
138+ zodShema = (
139+ propsDbType && propsDbType . isNullable
140+ ? tmpSchema . nullable ( )
141+ : tmpSchema
142+ ) . optional ( ) ;
50143 break ;
51- case TypeField . number :
52- zodShema = z . number ( ) . optional ( ) ;
144+ }
145+ case TypeField . boolean : {
146+ const tmpSchema = z . boolean ( ) ;
147+ zodShema = (
148+ propsDbType && propsDbType . isNullable
149+ ? tmpSchema . nullable ( )
150+ : tmpSchema
151+ ) . optional ( ) ;
53152 break ;
54- case TypeField . boolean :
55- zodShema = z . boolean ( ) . optional ( ) ;
153+ }
154+ case TypeField . object : {
155+ zodShema = getZodSchemaForJson ( propsDbType . isNullable ) . optional ( ) ;
56156 break ;
57- case TypeField . string :
58- zodShema = z . string ( ) . optional ( ) ;
157+ }
158+ case TypeField . string : {
159+ const tmpSchema = z . string ( ) ;
160+ zodShema = (
161+ propsDbType && propsDbType . isNullable
162+ ? tmpSchema . nullable ( )
163+ : tmpSchema
164+ ) . optional ( ) ;
59165 break ;
166+ }
60167 }
61168
62169 return {
0 commit comments