@@ -47,7 +47,7 @@ process(Input, #{} = Opts) ->
4747 (patch ,Flag ) when Flag == true ; Flag == false -> ok ;
4848 (extra_obj_key ,Flag ) when Flag == drop ; Flag == error -> ok ;
4949 (required_obj_keys ,Flag ) when Flag == drop ; Flag == error -> ok ;
50- (access_type ,Flag ) when Flag == read ; Flag == write -> ok ;
50+ (access_type ,Flag ) when Flag == read ; Flag == write ; Flag == raw -> ok ;
5151 (explain ,FlagList ) -> check_explain_keys (FlagList );
5252 (K ,V ) -> error ({unknown_option ,K ,V })
5353 end , Opts ),
@@ -88,6 +88,8 @@ prepare_type(#{oneOf := Types} = Type0) ->
8888 Type0 #{oneOf := [prepare_type (T ) || T <- Types ]};
8989prepare_type (#{type := <<" object" >>, properties := Props } = Type0 ) ->
9090 Type0 #{properties => maps :map (fun (_ , T ) -> prepare_type (T ) end , Props )};
91+ prepare_type (#{type := <<" array" >>, items := Items } = Type0 ) ->
92+ Type0 #{items => prepare_type (Items )};
9193prepare_type (#{} = Type0 ) ->
9294 % Convert format name to atom. This matches validators syntax
9395 Type1 = case Type0 of
@@ -205,13 +207,15 @@ encode3(#{discriminator := #{propertyName := DKey, mapping := DMap}} = Schema, O
205207 try binary_to_existing_atom (DValue ) catch error :badarg -> DValue end ;
206208 #{ADKey := DValue } when is_binary (DValue ) ->
207209 try binary_to_existing_atom (DValue ) catch error :badarg -> DValue end ;
208- #{} -> undefined
210+ #{} -> undefined ;
211+ {error , _ } -> Input_
209212 end
210213 end ,
211- ADvalue1 = DefaultFun (Input ),
214+ DiscrInput = maps :with ([DKey , ADKey ], Input ),
215+ ADvalue1 = DefaultFun (DiscrInput ),
212216 ADvalue2 = case ADvalue1 of
213217 undefined ->
214- Try = encode3 (hd (Types ), Opts #{apply_defaults => true , required_obj_keys => drop }, Input , Path ),
218+ Try = encode3 (hd (Types ), Opts #{apply_defaults => true , required_obj_keys => drop }, DiscrInput , Path ),
215219 DefaultFun (Try );
216220 _ ->
217221 ADvalue1
@@ -222,6 +226,9 @@ encode3(#{discriminator := #{propertyName := DKey, mapping := DMap}} = Schema, O
222226 encode3 (maps :without ([discriminator ], Schema ), Opts , Input , Path );
223227 {undefined , _ } ->
224228 {error , #{error => discriminator_missing , path => Path , propertyName => DKey }};
229+ {{error , _ }, _ } ->
230+ % this error comes from processing discriminator with first possible type, and may contain useful type error (e.g. not_string)
231+ ADvalue2 ;
225232 {_ , undefined } ->
226233 {error , #{error => discriminator_unmapped , path => Path , propertyName => DKey , value => ADvalue2 }};
227234 {_ , _ } ->
@@ -282,9 +289,11 @@ encode3(#{type := <<"object">>, properties := Properties} = Schema, #{query := Q
282289
283290 RequiredKeys = get_required_keys (Schema , Opts ),
284291 IsReadOnly = maps :get (readOnly , Prop , false ),
292+ IsWriteOnly = maps :get (writeOnly , Prop , false ),
285293 IsPrimary = maps :get ('x-primary-key' , Prop , false ),
286294 IsRequired = (lists :member (FieldBin , RequiredKeys ) orelse IsPrimary ),
287- IsWriteAccess = maps :get (access_type , Opts , read ) == write ,
295+ IsReadAccess = maps :get (access_type , Opts , raw ) == read ,
296+ IsWriteAccess = maps :get (access_type , Opts , raw ) == write ,
288297
289298 ApplyDefaults = maps :get (apply_defaults , Opts , false ),
290299 EffectiveValue = case {Input , Prop } of
@@ -315,9 +324,12 @@ encode3(#{type := <<"object">>, properties := Properties} = Schema, #{query := Q
315324 {ok , Null } when (Null == null orelse Null == undefined ) andalso
316325 not NullableProp andalso not Patching ->
317326 Obj ;
318- % Silently drop read only fields with write access
327+ % Silently drop readOnly fields on write
319328 {ok , _Value } when IsWriteAccess andalso IsReadOnly andalso (not IsRequired ) ->
320329 Obj ;
330+ % Silently drop writeOnly fields on read
331+ {ok , _Value } when IsReadAccess andalso IsWriteOnly andalso (not IsRequired ) ->
332+ Obj ;
321333 {ok , Value } ->
322334 case encode3 (Prop #{nullable => NullableProp }, Opts , Value , Path ++ [Field ]) of
323335 {error , _ } = E ->
@@ -450,6 +462,9 @@ encode3(#{const := Value}, #{auto_convert := Convert}, Input, Path) when is_atom
450462 _ -> {error , #{error => not_const2 , path => Path , input => Input , value => Value }}
451463 end ;
452464
465+ encode3 (#{const := Value }, #{}, Input , Path ) ->
466+ {error , #{error => not_const , path => Path , input => Input , value => Value }};
467+
453468encode3 (#{enum := Choices , type := <<" string" >>}, #{auto_convert := Convert }, Input , Path ) ->
454469 InputValue = case Input of
455470 _ when is_binary (Input ) -> Input ;
@@ -465,6 +480,7 @@ encode3(#{enum := Choices, type := <<"string">>}, #{auto_convert := Convert}, In
465480encode3 (#{type := <<" string" >>} = Spec , #{auto_convert := Convert } = Options , Input , Path ) ->
466481 {Input1 , InputForValidation } = case Input of
467482 _ when is_binary (Input ) -> {Input , Input };
483+ _ when is_boolean (Input ) -> {{error , #{error => not_string , path => Path , input => Input }}, undefined };
468484 _ when is_atom (Input ) andalso Convert -> {atom_to_binary (Input ), atom_to_binary (Input )};
469485 _ when is_atom (Input ) -> {Input , atom_to_binary (Input )};
470486 _ -> {{error , #{error => not_string , path => Path , input => Input }}, undefined }
@@ -473,11 +489,12 @@ encode3(#{type := <<"string">>} = Spec, #{auto_convert := Convert} = Options, In
473489 {error , _ } ->
474490 Input1 ;
475491 _ ->
492+ Length = string :length (InputForValidation ),
476493 case Spec of
477- #{minLength := MinLength } when size ( InputForValidation ) < MinLength ->
478- {error , #{error => too_short , path => Path , input => Input , min_length => MinLength }};
479- #{maxLength := MaxLength } when size ( InputForValidation ) > MaxLength ->
480- {error , #{error => too_long , path => Path , input => Input , max_length => MaxLength }};
494+ #{minLength := MinLength } when Length < MinLength ->
495+ {error , #{error => too_short , path => Path , input => Input , detail => Length , min_length => MinLength }};
496+ #{maxLength := MaxLength } when Length > MaxLength ->
497+ {error , #{error => too_long , path => Path , input => Input , detail => Length , max_length => MaxLength }};
481498 #{} ->
482499 Format = maps :get (format , Spec , undefined ),
483500 Validators = maps :get (validators , Options ),
0 commit comments