@@ -11,6 +11,7 @@ Squeal expressions are the atoms used to build statements.
11{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
11{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
12{-# LANGUAGE
12{-# LANGUAGE
13 AllowAmbiguousTypes
13 AllowAmbiguousTypes
14 , DeriveGeneric
15 , DeriveGeneric
15 , FlexibleContexts
16 , FlexibleContexts
16 , FlexibleInstances
17 , FlexibleInstances
@@ -25,6 +26,7 @@ Squeal expressions are the atoms used to build statements.
25 , TypeInType
26 , TypeInType
26 , TypeOperators
27 , TypeOperators
27 , UndecidableInstances
28 , UndecidableInstances
30module Squeal.PostgreSQL.Expression
32module Squeal.PostgreSQL.Expression
@@ -48,6 +50,7 @@ module Squeal.PostgreSQL.Expression
48 , unsafeBinaryOp
50 , unsafeBinaryOp
49 , unsafeUnaryOp
51 , unsafeUnaryOp
50 , unsafeFunction
52 , unsafeFunction
53+ , unsafeVariadicFunction
@@ -83,6 +86,53 @@ module Squeal.PostgreSQL.Expression
84 , charLength
87 , charLength
89+ -- ** json or jsonb operators
98+ -- *** jsonb only operators
125+ , jsonExtractPathAsText
126+ , jsonbExtractPathAsText
86 -- ** Aggregation
136 -- ** Aggregation
87 , unsafeAggregate, unsafeAggregateDistinct
137 , unsafeAggregate, unsafeAggregateDistinct
88 , sum_, sumDistinct
138 , sum_, sumDistinct
@@ -135,8 +185,10 @@ module Squeal.PostgreSQL.Expression
135import Control.Category
185import Control.Category
136import Control.DeepSeq
186import Control.DeepSeq
137import Data.ByteString (ByteString)
187import Data.ByteString (ByteString)
188+import Data.ByteString.Lazy (toStrict)
138import Data.Function ((&))
189import Data.Function ((&))
139−import Data.Semigroup
190+import Data.Semigroup hiding (All)
191+import qualified Data.Aeson as JSON
140import Data.Ratio
192import Data.Ratio
141import Data.String
193import Data.String
142import Generics.SOP hiding (from)
194import Generics.SOP hiding (from)
@@ -482,6 +534,16 @@ unsafeFunction
482unsafeFunction fun x = UnsafeExpression $
534unsafeFunction fun x = UnsafeExpression $
483 fun <> parenthesized (renderExpression x)
535 fun <> parenthesized (renderExpression x)
537+-- | Helper for defining variadic functions.
538+unsafeVariadicFunction
542+ -> NP (Expression schema relations grouping params) elems
543+ -> Expression schema relations grouping params ret
544+unsafeVariadicFunction fun x = UnsafeExpression $
545+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderExpression) x)))
485instance PGNum ty
547instance PGNum ty
486 => Num (Expression schema relations grouping params (nullity ty)) where
548 => Num (Expression schema relations grouping params (nullity ty)) where
487 (+) = unsafeBinaryOp "+"
549 (+) = unsafeBinaryOp "+"
@@ -870,6 +932,400 @@ like
870 -> Expression schema relations grouping params (nullity 'PGbool)
932 -> Expression schema relations grouping params (nullity 'PGbool)
871like = unsafeBinaryOp "LIKE"
933like = unsafeBinaryOp "LIKE"
935+{-----------------------------------------
936+ -- json and jsonb support
938+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
939+comments lifted directly from this page.
941+Table 9.44: json and jsonb operators
942+-----------------------------------------}
944+-- | Get JSON value (object field or array element) at a key.
946+ :: (PGjson_ json, PGjsonKey key)
947+ => Expression schema relations grouping params (nullity json)
948+ -> Expression schema relations grouping params (nullity key)
949+ -> Expression schema relations grouping params ('Null json)
950+(.->) = unsafeBinaryOp "->"
952+-- | Get JSON value (object field or array element) at a key, as text.
954+ :: (PGjson_ json, PGjsonKey key)
955+ => Expression schema relations grouping params (nullity json)
956+ -> Expression schema relations grouping params (nullity key)
957+ -> Expression schema relations grouping params ('Null 'PGtext)
958+(.->>) = unsafeBinaryOp "->>"
960+-- | Get JSON value at a specified path.
962+ :: (PGjson_ json, PGtextArray "(.#>)" path)
963+ => Expression schema relations grouping params (nullity json)
964+ -> Expression schema relations grouping params (nullity path)
965+ -> Expression schema relations grouping params ('Null json)
966+(.#>) = unsafeBinaryOp "#>"
968+-- | Get JSON value at a specified path as text.
970+ :: (PGjson_ json, PGtextArray "(.#>>)" path)
971+ => Expression schema relations grouping params (nullity json)
972+ -> Expression schema relations grouping params (nullity path)
973+ -> Expression schema relations grouping params ('Null 'PGtext)
974+(.#>>) = unsafeBinaryOp "#>>"
976+-- Additional jsonb operators
978+-- | Does the left JSON value contain the right JSON path/value entries at the
981+ :: Expression schema relations grouping params (nullity 'PGjsonb)
982+ -> Expression schema relations grouping params (nullity 'PGjsonb)
983+ -> Condition schema relations grouping params
984+(.@>) = unsafeBinaryOp "@>"
986+-- | Are the left JSON path/value entries contained at the top level within the
989+ :: Expression schema relations grouping params (nullity 'PGjsonb)
990+ -> Expression schema relations grouping params (nullity 'PGjsonb)
991+ -> Condition schema relations grouping params
992+(.<@) = unsafeBinaryOp "<@"
994+-- | Does the string exist as a top-level key within the JSON value?
996+ :: Expression schema relations grouping params (nullity 'PGjsonb)
997+ -> Expression schema relations grouping params (nullity 'PGtext)
998+ -> Condition schema relations grouping params
999+(.?) = unsafeBinaryOp "?"
1001+-- | Do any of these array strings exist as top-level keys?
1003+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1004+ -> Expression schema relations grouping params (nullity ('PGvararray ('NotNull 'PGtext)))
1005+ -> Condition schema relations grouping params
1006+(.?|) = unsafeBinaryOp "?|"
1008+-- | Do all of these array strings exist as top-level keys?
1010+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1011+ -> Expression schema relations grouping params (nullity ('PGvararray ('NotNull 'PGtext)))
1012+ -> Condition schema relations grouping params
1013+(.?&) = unsafeBinaryOp "?&"
1015+-- | Concatenate two jsonb values into a new jsonb value.
1017+ Semigroup (Expression schema relations grouping param (nullity 'PGjsonb)) where
1018+ (<>) = unsafeBinaryOp "||"
1020+-- | Delete a key or keys from a JSON object, or remove an array element.
1022+-- If the right operand is..
1024+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1025+-- are matched based on their key value.
1027+-- @ text[] @: Delete multiple key/value pairs or string elements
1028+-- from left operand. Key/value pairs are matched based on their key value.
1030+-- @ integer @: Delete the array element with specified index (Negative integers
1031+-- count from the end). Throws an error if top level container is not an array.
1033+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1034+ => Expression schema relations grouping params (nullity 'PGjsonb)
1035+ -> Expression schema relations grouping params (nullity key)
1036+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1037+(.-.) = unsafeBinaryOp "-"
1039+-- | Delete the field or element with specified path (for JSON arrays, negative
1040+-- integers count from the end)
1042+ :: PGtextArray "(#-.)" arrayty
1043+ => Expression schema relations grouping params (nullity 'PGjsonb)
1044+ -> Expression schema relations grouping params (nullity arrayty)
1045+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1046+(#-.) = unsafeBinaryOp "#-"
1048+{-----------------------------------------
1049+Table 9.45: JSON creation functions
1050+-----------------------------------------}
1052+-- | Literal binary JSON
1053+jsonbLit :: JSON.Value -> Expression schema relations grouping params (nullity 'PGjsonb)
1054+jsonbLit = cast jsonb . UnsafeExpression . singleQuotedUtf8 . toStrict . JSON.encode
1057+jsonLit :: JSON.Value -> Expression schema relations grouping params (nullity 'PGjson)
1058+jsonLit = cast json . UnsafeExpression . singleQuotedUtf8 . toStrict . JSON.encode
1060+-- | Returns the value as json. Arrays and composites are converted
1061+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1062+-- type to json, the cast function will be used to perform the conversion;
1063+-- otherwise, a scalar value is produced. For any scalar type other than a
1064+-- number, a Boolean, or a null value, the text representation will be used, in
1065+-- such a fashion that it is a valid json value.
1067+ :: Expression schema relations grouping params (nullity ty)
1068+ -> Expression schema relations grouping params (nullity 'PGjson)
1069+toJson = unsafeFunction "to_json"
1071+-- | Returns the value as jsonb. Arrays and composites are converted
1072+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1073+-- type to json, the cast function will be used to perform the conversion;
1074+-- otherwise, a scalar value is produced. For any scalar type other than a
1075+-- number, a Boolean, or a null value, the text representation will be used, in
1076+-- such a fashion that it is a valid jsonb value.
1078+ :: Expression schema relations grouping params (nullity ty)
1079+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1080+toJsonb = unsafeFunction "to_jsonb"
1082+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1083+-- becomes a JSON array of arrays.
1085+ :: PGarray "arrayToJson" arr
1086+ => Expression schema relations grouping params (nullity arr)
1087+ -> Expression schema relations grouping params (nullity 'PGjson)
1088+arrayToJson = unsafeFunction "array_to_json"
1090+-- | Returns the row as a JSON object.
1092+ :: Expression schema relations grouping params (nullity ('PGcomposite ty))
1093+ -> Expression schema relations grouping params (nullity 'PGjson)
1094+rowToJson = unsafeFunction "row_to_json"
1096+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1100+ => NP (Expression schema relations grouping params) elems
1101+ -> Expression schema relations grouping params (nullity 'PGjson)
1102+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1104+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1105+-- variadic argument list.
1108+ => NP (Expression schema relations grouping params) elems
1109+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1110+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1114+ => NP (Aliased (Expression schema relations grouping params)) elems
1117+ (`appEndo` []) . hcfoldMap (Proxy :: Proxy Top)
1118+ (\(col `As` name) -> Endo $ \xs ->
1119+ renderAliasString name : renderExpression col : xs)
1121+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1122+-- argument list. The elements of the argument list must alternate between text
1126+ => NP (Aliased (Expression schema relations grouping params)) elems
1127+ -> Expression schema relations grouping params (nullity 'PGjson)
1129+ = unsafeFunction "json_build_object"
1132+ . unsafeRowFunction
1134+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1135+-- variadic argument list. The elements of the argument list must alternate
1136+-- between text and values.
1139+ => NP (Aliased (Expression schema relations grouping params)) elems
1140+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1142+ = unsafeFunction "jsonb_build_object"
1145+ . unsafeRowFunction
1147+-- | Builds a JSON object out of a text array. The array must have either
1148+-- exactly one dimension with an even number of members, in which case they are
1149+-- taken as alternating key/value pairs, or two dimensions such that each inner
1150+-- array has exactly two elements, which are taken as a key/value pair.
1152+ :: PGarrayOf "jsonObject" arr ('NotNull 'PGtext)
1153+ => Expression schema relations grouping params (nullity arr)
1154+ -> Expression schema relations grouping params (nullity 'PGjson)
1155+jsonObject = unsafeFunction "json_object"
1157+-- | Builds a binary JSON object out of a text array. The array must have either
1158+-- exactly one dimension with an even number of members, in which case they are
1159+-- taken as alternating key/value pairs, or two dimensions such that each inner
1160+-- array has exactly two elements, which are taken as a key/value pair.
1162+ :: PGarrayOf "jsonbObject" arr ('NotNull 'PGtext)
1163+ => Expression schema relations grouping params (nullity arr)
1164+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1165+jsonbObject = unsafeFunction "jsonb_object"
1167+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1168+-- keys and one for values, that are zipped pairwise to create a JSON object.
1170+ :: ( PGarrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1171+ , PGarrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1172+ => Expression schema relations grouping params (nullity keysArray)
1173+ -> Expression schema relations grouping params (nullity valuesArray)
1174+ -> Expression schema relations grouping params (nullity 'PGjson)
1175+jsonZipObject ks vs =
1176+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1178+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1179+-- keys and one for values, that are zipped pairwise to create a binary JSON
1182+ :: ( PGarrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1183+ , PGarrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1184+ => Expression schema relations grouping params (nullity keysArray)
1185+ -> Expression schema relations grouping params (nullity valuesArray)
1186+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1187+jsonbZipObject ks vs =
1188+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1190+{-----------------------------------------
1191+Table 9.46: JSON processing functions
1192+-----------------------------------------}
1194+-- | Returns the number of elements in the outermost JSON array.
1196+ :: Expression schema relations grouping params (nullity 'PGjson)
1197+ -> Expression schema relations grouping params (nullity 'PGint4)
1198+jsonArrayLength = unsafeFunction "json_array_length"
1200+-- | Returns the number of elements in the outermost binary JSON array.
1202+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1203+ -> Expression schema relations grouping params (nullity 'PGint4)
1204+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1206+-- | Returns JSON value pointed to by the given path (equivalent to #>
1210+ => Expression schema relations grouping params (nullity 'PGjson)
1211+ -> NP (Expression schema relations grouping params) elems
1212+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1213+jsonExtractPath x xs =
1214+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1216+-- | Returns JSON value pointed to by the given path (equivalent to #>
1220+ => Expression schema relations grouping params (nullity 'PGjsonb)
1221+ -> NP (Expression schema relations grouping params) elems
1222+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1223+jsonbExtractPath x xs =
1224+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1226+-- | Returns JSON value pointed to by the given path (equivalent to #>
1227+-- operator), as text.
1228+jsonExtractPathAsText
1230+ => Expression schema relations grouping params (nullity 'PGjson)
1231+ -> NP (Expression schema relations grouping params) elems
1232+ -> Expression schema relations grouping params (nullity 'PGjson)
1233+jsonExtractPathAsText x xs =
1234+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1236+-- | Returns JSON value pointed to by the given path (equivalent to #>
1237+-- operator), as text.
1238+jsonbExtractPathAsText
1240+ => Expression schema relations grouping params (nullity 'PGjsonb)
1241+ -> NP (Expression schema relations grouping params) elems
1242+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1243+jsonbExtractPathAsText x xs =
1244+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1246+-- | Returns set of keys in the outermost JSON object.
1248+ :: Expression schema relations grouping params (nullity 'PGjson)
1249+ -> Expression schema relations grouping params (nullity 'PGtext)
1250+jsonObjectKeys = unsafeFunction "json_object_keys"
1252+-- | Returns set of keys in the outermost JSON object.
1254+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1255+ -> Expression schema relations grouping params (nullity 'PGtext)
1256+jsonbObjectKeys = unsafeFunction "jsonb_object_keys"
1258+-- | Returns the type of the outermost JSON value as a text string. Possible
1259+-- types are object, array, string, number, boolean, and null.
1261+ :: Expression schema relations grouping params (nullity 'PGjson)
1262+ -> Expression schema relations grouping params (nullity 'PGtext)
1263+jsonTypeof = unsafeFunction "json_typeof"
1265+-- | Returns the type of the outermost binary JSON value as a text string.
1266+-- Possible types are object, array, string, number, boolean, and null.
1268+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1269+ -> Expression schema relations grouping params (nullity 'PGtext)
1270+jsonbTypeof = unsafeFunction "jsonb_typeof"
1272+-- | Returns its argument with all object fields that have null values omitted.
1273+-- Other null values are untouched.
1275+ :: Expression schema relations grouping params (nullity 'PGjson)
1276+ -> Expression schema relations grouping params (nullity 'PGjson)
1277+jsonStripNulls = unsafeFunction "json_strip_nulls"
1279+-- | Returns its argument with all object fields that have null values omitted.
1280+-- Other null values are untouched.
1282+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1283+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1284+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1286+-- | @ jsonbSet target path new_value create_missing @
1288+-- Returns target with the section designated by path replaced by new_value,
1289+-- or with new_value added if create_missing is true ( default is true) and the
1290+-- item designated by path does not exist. As with the path orientated
1291+-- operators, negative integers that appear in path count from the end of JSON
1294+ :: PGtextArray "jsonbSet" arr
1295+ => Expression schema relations grouping params (nullity 'PGjsonb)
1296+ -> Expression schema relations grouping params (nullity arr)
1297+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1298+ -> Maybe (Expression schema relations grouping params (nullity 'PGbool))
1299+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1300+jsonbSet tgt path val createMissing = case createMissing of
1301+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1302+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1304+-- | @ jsonbInsert target path new_value insert_after @
1306+-- Returns target with new_value inserted. If target section designated by
1307+-- path is in a JSONB array, new_value will be inserted before target or after
1308+-- if insert_after is true (default is false). If target section designated by
1309+-- path is in JSONB object, new_value will be inserted only if target does not
1310+-- exist. As with the path orientated operators, negative integers that appear
1311+-- in path count from the end of JSON arrays.
1313+ :: PGtextArray "jsonbInsert" arr
1314+ => Expression schema relations grouping params (nullity 'PGjsonb)
1315+ -> Expression schema relations grouping params (nullity arr)
1316+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1317+ -> Maybe (Expression schema relations grouping params (nullity 'PGbool))
1318+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1319+jsonbInsert tgt path val insertAfter = case insertAfter of
1320+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1321+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1323+-- | Returns its argument as indented JSON text.
1325+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1326+ -> Expression schema relations grouping params (nullity 'PGtext)
1327+jsonbPretty = unsafeFunction "jsonb_pretty"
873{-----------------------------------------
1329{-----------------------------------------
874aggregation
1330aggregation
875-----------------------------------------}
1331-----------------------------------------}