@@ -42,7 +42,8 @@ module Data.Query (
4242 leaveGroupChat,
4343 getGroupChatForUser,
4444 getFaculty,
45− updateFaculty
45+ updateFaculty,
46+ getFacultyFromQuery
4647) where
4748
4849import Squeal.PostgreSQL
@@ -69,6 +70,7 @@ import Servant.Docs
6970import Data.Proxy
7071import Data.Vector (Vector, toList, fromList)
7172import Data.Text (Text)
73+import qualified Data.Text as T
7274import Data.Channel.NamedChannel
7375import Data.Channel.AnonymousChannel
7476import Data.Maybe (fromMaybe)
@@ -78,6 +80,9 @@ import Data.Message
7880import Server.Query.Dialog
7981import qualified Server.Query.Pagination as P
8082import Data.Faculty
83+import Data.ByteString (ByteString)
84+import Data.Foldable (fold)
85+import Data.Char
8186
8287-- MARK: Documentation
8388
@@ -447,6 +452,56 @@ getGroupChatForUserQ = selectStar $
447452 where_ (#groupChatId .== param @2) &
448453 where_ (#groupChatUsers .? param @1)
449454
455+getFacultySearchResultQ :: Query Schema (TuplePG (Only Text)) (RowPG Faculty)
456+getFacultySearchResultQ = selectStar (from (table #faculties) &
457+ where_ (vector @@ query) &
458+ orderBy [tsRankCd vector query & Desc])
459+ where
460+ vector = tsVector "russian" (textArrayToText [
461+ #facultyName,
462+ #facultyPath,
463+ #facultyCampusName,
464+ (arrayToText #facultyTags)])
465+ query = tsQuery (param @1)
466+
467+tsRankCd
468+ :: Expression schema from grouping params ('NotNull 'PGtext)
469+ -> Expression schema from grouping params ('NotNull 'PGtext)
470+ -> Expression schema from grouping params ('NotNull 'PGfloat4)
471+tsRankCd vector query = UnsafeExpression $
472+ "ts_rank_cd" <> parenthesized (commaSeparated . map renderExpression $ [vector, query])
473+
474+tsVector
475+ :: ByteString -- ^ Language
476+ -> Expression schema from grouping params ('NotNull 'PGtext)
477+ -> Expression schema from grouping params ('NotNull 'PGtext)
478+tsVector lang x = UnsafeExpression $
479+ "to_tsvector" <> parenthesized (commaSeparated [singleQuotedUtf8 lang, renderExpression x])
480+
481+tsQuery
482+ :: Expression schema from grouping params ('NotNull 'PGtext)
483+ -> Expression schema from grouping params ('NotNull 'PGtext)
484+tsQuery = unsafeFunction "to_tsquery"
485+
486+arrayToText
487+ :: Expression schema from grouping params ('NotNull ('PGvararray ('NotNull 'PGtext)))
488+ -> Expression schema from grouping params ('NotNull 'PGtext)
489+arrayToText x = UnsafeExpression $
490+ "array_to_string" <> parenthesized (commaSeparated [renderExpression x, "' '"])
491+
492+(@@)
493+ :: Expression schema from grouping params (nullity0 'PGtext)
494+ -> Expression schema from grouping params (nullity1 'PGtext)
495+ -> Expression schema from grouping params (nullity2 'PGbool)
496+(@@) = unsafeBinaryOp "@@"
497+
498+space :: Expression schema from grouping params ('NotNull 'PGtext)
499+space = UnsafeExpression "' '"
500+
501+textArrayToText
502+ :: [Expression schema from grouping params ('NotNull 'PGtext)]
503+ -> Expression schema from grouping params ('NotNull 'PGtext)
504+textArrayToText = fold . L.intersperse space
450505
451506-- MARK: FrontEnd Data Structures
452507
@@ -694,8 +749,15 @@ getGroupChatForUser uId gId = do
694749 (Just c) -> return c
695750 Nothing -> lift $ S.throwError S.err404
696751
752+getFacultyFromQuery :: T.Text -> StaticPQ [Faculty]
753+getFacultyFromQuery query =
754+ runQueryParams getFacultySearchResultQ (Only . queryFromText $ query) >>= getRows
755+
697756-- MARK: Utils
698757
758+queryFromText :: Text -> Text
759+queryFromText = T.unwords . L.intersperse "&" . map (`T.append` ":*") . filter (not . T.null) . T.split (not . isAlphaNum)
760+
699761directionToOperator
700762 :: P.PaginationDirection
701763 -> (ConditionOp schema0 from0 grouping0 params0 nullity0 nullity1 (ty :: PGType),