module Unison.Sqlite.Utils (likeEscape) where

import Data.Text (Text)
import Data.Text qualified as Text

-- | Escape special characters for "LIKE" matches.
--
-- Prepared statements prevent sql injection, but it's still possible some user
-- may be able to craft a query using a fake "hash" that would let them see more than they
-- ought to.
--
-- You still need to provide the escape char in the sql query, E.g.
--
-- @@
--   SELECT * FROM table
--     WHERE txt LIKE ? ESCAPE '\'
-- @@
--
-- >>> likeEscape '\\' "Nat.%"
-- "Nat.\%"
likeEscape :: Char -> Text -> Text
likeEscape :: Char -> Text -> Text
likeEscape Char
'%' Text
_ = [Char] -> Text
forall a. HasCallStack => [Char] -> a
error [Char]
"Can't use % or _ as escape characters"
likeEscape Char
'_' Text
_ = [Char] -> Text
forall a. HasCallStack => [Char] -> a
error [Char]
"Can't use % or _ as escape characters"
likeEscape Char
escapeChar Text
pat =
  ((Char -> Text) -> Text -> Text) -> Text -> (Char -> Text) -> Text
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Char -> Text) -> Text -> Text
Text.concatMap Text
pat \case
    Char
'%' -> [Char] -> Text
Text.pack [Char
escapeChar, Char
'%']
    Char
'_' -> [Char] -> Text
Text.pack [Char
escapeChar, Char
'_']
    Char
c
      | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
escapeChar -> [Char] -> Text
Text.pack [Char
escapeChar, Char
escapeChar]
      | Bool
otherwise -> Char -> Text
Text.singleton Char
c