@@ -70,7 +70,8 @@ if Code.ensure_loaded?(Postgrex) do
70
70
case Postgrex . prepare_execute ( conn , name , sql , params , opts ) do
71
71
{ :error , % Postgrex.Error { postgres: % { pg_code: "22P02" , message: message } } = error } ->
72
72
context = """
73
- . If you are trying to query a JSON field, the parameter must be interpolated. Instead of
73
+ . If you are trying to query a JSON field, the parameter may need to be interpolated. \
74
+ Instead of
74
75
75
76
p.json["field"] == "value"
76
77
@@ -684,16 +685,7 @@ if Code.ensure_loaded?(Postgrex) do
684
685
end
685
686
686
687
defp expr ( { :json_extract_path , _ , [ expr , path ] } , sources , query ) do
687
- path =
688
- intersperse_map ( path , ?, , fn
689
- binary when is_binary ( binary ) ->
690
- [ ?" , escape_json_key ( binary ) , ?" ]
691
-
692
- integer when is_integer ( integer ) ->
693
- Integer . to_string ( integer )
694
- end )
695
-
696
- [ ?( , expr ( expr , sources , query ) , "#>'{" , path , "}')" ]
688
+ json_extract_path ( expr , path , sources , query )
697
689
end
698
690
699
691
defp expr ( { :filter , _ , [ agg , filter ] } , sources , query ) do
@@ -717,6 +709,18 @@ if Code.ensure_loaded?(Postgrex) do
717
709
718
710
defp expr ( { :count , _ , [ ] } , _sources , _query ) , do: "count(*)"
719
711
712
+ defp expr ( { :== , _ , [ { :json_extract_path , _ , [ expr , path ] } = left , right ] } , sources , query )
713
+ when is_binary ( right ) or is_integer ( right ) do
714
+ case Enum . split ( path , - 1 ) do
715
+ { path , [ last ] } when is_binary ( last ) ->
716
+ extracted = json_extract_path ( expr , path , sources , query )
717
+ [ ?( , extracted , "@>'{" , escape_json ( last ) , ": " , escape_json ( right ) | "}')" ]
718
+
719
+ _ ->
720
+ [ maybe_paren ( left , sources , query ) , " = " | maybe_paren ( right , sources , query ) ]
721
+ end
722
+ end
723
+
720
724
defp expr ( { fun , _ , args } , sources , query ) when is_atom ( fun ) and is_list ( args ) do
721
725
{ modifier , args } =
722
726
case args do
@@ -770,6 +774,15 @@ if Code.ensure_loaded?(Postgrex) do
770
774
error! ( query , "unsupported expression: #{ inspect ( expr ) } " )
771
775
end
772
776
777
+ defp json_extract_path ( expr , [ ] , sources , query ) do
778
+ expr ( expr , sources , query )
779
+ end
780
+
781
+ defp json_extract_path ( expr , path , sources , query ) do
782
+ path = intersperse_map ( path , ?, , & escape_json / 1 )
783
+ [ ?( , expr ( expr , sources , query ) , "#>'{" , path , "}')" ]
784
+ end
785
+
773
786
defp type_unless_typed ( % Ecto.Query.Tagged { } , _type ) , do: [ ]
774
787
defp type_unless_typed ( _ , type ) , do: [ ?: , ?: | type ]
775
788
@@ -1328,10 +1341,17 @@ if Code.ensure_loaded?(Postgrex) do
1328
1341
:binary . replace ( value , "'" , "''" , [ :global ] )
1329
1342
end
1330
1343
1331
- defp escape_json_key ( value ) when is_binary ( value ) do
1332
- value
1333
- |> escape_string ( )
1334
- |> :binary . replace ( "\" " , "\\ \" " , [ :global ] )
1344
+ defp escape_json ( value ) when is_binary ( value ) do
1345
+ escaped =
1346
+ value
1347
+ |> escape_string ( )
1348
+ |> :binary . replace ( "\" " , "\\ \" " , [ :global ] )
1349
+
1350
+ [ ?" , escaped , ?" ]
1351
+ end
1352
+
1353
+ defp escape_json ( value ) when is_integer ( value ) do
1354
+ Integer . to_string ( value )
1335
1355
end
1336
1356
1337
1357
defp ecto_to_db ( { :array , t } ) , do: [ ecto_to_db ( t ) , ?[ , ?] ]
0 commit comments