Add websearch_to_tsquery support (#1339)
This commit is contained in:
committed by
Steve Chávez
parent
ea97055449
commit
e639c77aa2
@@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- #1243, Add websearch_to_tsquery support - @herulume
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -287,7 +287,8 @@ ftsOperators :: M.HashMap Operator SqlFragment
|
|||||||
ftsOperators = M.fromList [
|
ftsOperators = M.fromList [
|
||||||
("fts", "@@ to_tsquery"),
|
("fts", "@@ to_tsquery"),
|
||||||
("plfts", "@@ plainto_tsquery"),
|
("plfts", "@@ plainto_tsquery"),
|
||||||
("phfts", "@@ phraseto_tsquery")
|
("phfts", "@@ phraseto_tsquery"),
|
||||||
|
("wfts", "@@ websearch_to_tsquery")
|
||||||
]
|
]
|
||||||
|
|
||||||
data OpExpr = OpExpr Bool Operation deriving (Eq, Show)
|
data OpExpr = OpExpr Bool Operation deriving (Eq, Show)
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import Test.Hspec
|
|||||||
import Test.Hspec.Wai
|
import Test.Hspec.Wai
|
||||||
import Test.Hspec.Wai.JSON
|
import Test.Hspec.Wai.JSON
|
||||||
|
|
||||||
import Protolude hiding (get)
|
import PostgREST.Types (PgVersion, pgVersion112)
|
||||||
|
import Protolude hiding (get)
|
||||||
import SpecHelper
|
import SpecHelper
|
||||||
|
|
||||||
|
spec :: PgVersion -> SpecWith Application
|
||||||
spec :: SpecWith Application
|
spec actualPgVersion =
|
||||||
spec =
|
|
||||||
describe "and/or params used for complex boolean logic" $ do
|
describe "and/or params used for complex boolean logic" $ do
|
||||||
context "used with GET" $ do
|
context "used with GET" $ do
|
||||||
context "or param" $ do
|
context "or param" $ do
|
||||||
@@ -80,6 +80,19 @@ spec =
|
|||||||
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" },
|
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" },
|
||||||
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}
|
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}
|
||||||
]|] { matchHeaders = [matchContentTypeJson] }
|
]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
|
when (actualPgVersion >= pgVersion112) $
|
||||||
|
it "can handle wfts (websearch_to_tsquery)" $
|
||||||
|
get "/tsearch?or=(text_search_vector.plfts(german).Art,text_search_vector.plfts(french).amusant,text_search_vector.not.wfts(english).impossible)"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[
|
||||||
|
{"text_search_vector": "'also':2 'fun':3 'possibl':8" },
|
||||||
|
{"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" },
|
||||||
|
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" },
|
||||||
|
{"text_search_vector": "'art':4 'spass':5 'unmog':7" }
|
||||||
|
]|]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "can handle cs and cd" $
|
it "can handle cs and cd" $
|
||||||
get "/entities?or=(arr.cs.{1,2,3},arr.cd.{1})&select=id" `shouldRespondWith`
|
get "/entities?or=(arr.cs.{1,2,3},arr.cd.{1})&select=id" `shouldRespondWith`
|
||||||
[json|[{ "id": 1 },{ "id": 3 }]|] { matchHeaders = [matchContentTypeJson] }
|
[json|[{ "id": 1 },{ "id": 3 }]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ import Test.Hspec.Wai.JSON
|
|||||||
|
|
||||||
import Text.Heredoc
|
import Text.Heredoc
|
||||||
|
|
||||||
import Protolude hiding (get)
|
import PostgREST.Types (PgVersion, pgVersion112)
|
||||||
|
import Protolude hiding (get)
|
||||||
import SpecHelper
|
import SpecHelper
|
||||||
|
|
||||||
spec :: SpecWith Application
|
spec :: PgVersion -> SpecWith Application
|
||||||
spec = do
|
spec actualPgVersion = do
|
||||||
|
|
||||||
describe "Querying a table with a column called count" $
|
describe "Querying a table with a column called count" $
|
||||||
it "should not confuse count column with pg_catalog.count aggregate" $
|
it "should not confuse count column with pg_catalog.count aggregate" $
|
||||||
@@ -119,6 +120,29 @@ spec = do
|
|||||||
[json| [ {"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" }] |]
|
[json| [ {"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" }] |]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
|
when (actualPgVersion >= pgVersion112) $ do
|
||||||
|
it "finds matches with websearch_to_tsquery" $
|
||||||
|
get "/tsearch?text_search_vector=wfts.The%20Fat%20Rats" `shouldRespondWith`
|
||||||
|
[json| [ {"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" }] |]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
|
it "can use boolean operators(and, or, -) in websearch_to_tsquery" $ do
|
||||||
|
get "/tsearch?text_search_vector=wfts.fun%20and%20possible"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json| [ {"text_search_vector": "'also':2 'fun':3 'possibl':8"}] |]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
get "/tsearch?text_search_vector=wfts.impossible%20or%20possible"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json| [
|
||||||
|
{"text_search_vector": "'fun':5 'imposs':9 'kind':3"},
|
||||||
|
{"text_search_vector": "'also':2 'fun':3 'possibl':8"}]
|
||||||
|
|]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
get "/tsearch?text_search_vector=wfts.fun%20and%20-possible"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json| [ {"text_search_vector": "'fun':5 'imposs':9 'kind':3"}] |]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "finds matches with different dictionaries" $ do
|
it "finds matches with different dictionaries" $ do
|
||||||
get "/tsearch?text_search_vector=fts(french).amusant" `shouldRespondWith`
|
get "/tsearch?text_search_vector=fts(french).amusant" `shouldRespondWith`
|
||||||
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
|
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
|
||||||
@@ -127,6 +151,12 @@ spec = do
|
|||||||
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
|
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
|
when (actualPgVersion >= pgVersion112) $
|
||||||
|
get "/tsearch?text_search_vector=wfts(french).amusant%20impossible"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "can be negated with not operator" $ do
|
it "can be negated with not operator" $ do
|
||||||
get "/tsearch?text_search_vector=not.fts.impossible%7Cfat%7Cfun" `shouldRespondWith`
|
get "/tsearch?text_search_vector=not.fts.impossible%7Cfat%7Cfun" `shouldRespondWith`
|
||||||
[json| [
|
[json| [
|
||||||
@@ -145,6 +175,13 @@ spec = do
|
|||||||
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4"},
|
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4"},
|
||||||
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}]|]
|
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}]|]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
when (actualPgVersion >= pgVersion112) $
|
||||||
|
get "/tsearch?text_search_vector=not.wfts(english).impossible%20or%20fat%20or%20fun"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json| [
|
||||||
|
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4"},
|
||||||
|
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}]|]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "matches with computed column" $
|
it "matches with computed column" $
|
||||||
get "/items?always_true=eq.true&order=id.asc" `shouldRespondWith`
|
get "/items?always_true=eq.true&order=id.asc" `shouldRespondWith`
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ import Test.Hspec.Wai.JSON
|
|||||||
import Text.Heredoc
|
import Text.Heredoc
|
||||||
|
|
||||||
import PostgREST.Types (PgVersion, pgVersion100, pgVersion109,
|
import PostgREST.Types (PgVersion, pgVersion100, pgVersion109,
|
||||||
pgVersion110, pgVersion114, pgVersion95)
|
pgVersion110, pgVersion112, pgVersion114,
|
||||||
|
pgVersion95)
|
||||||
import Protolude hiding (get)
|
import Protolude hiding (get)
|
||||||
import SpecHelper
|
import SpecHelper
|
||||||
|
|
||||||
@@ -531,6 +532,10 @@ spec actualPgVersion =
|
|||||||
get "/rpc/get_tsearch?text_search_vector=not.fts(english).fun%7Crat" `shouldRespondWith`
|
get "/rpc/get_tsearch?text_search_vector=not.fts(english).fun%7Crat" `shouldRespondWith`
|
||||||
[json|[{"text_search_vector":"'amus':5 'fair':7 'impossibl':9 'peu':4"},{"text_search_vector":"'art':4 'spass':5 'unmog':7"}]|]
|
[json|[{"text_search_vector":"'amus':5 'fair':7 'impossibl':9 'peu':4"},{"text_search_vector":"'art':4 'spass':5 'unmog':7"}]|]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
when (actualPgVersion >= pgVersion112) $
|
||||||
|
get "/rpc/get_tsearch?text_search_vector=wfts.impossible" `shouldRespondWith`
|
||||||
|
[json|[{"text_search_vector":"'fun':5 'imposs':9 'kind':3"}]|]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
it "should work with an argument of custom type in public schema" $
|
it "should work with an argument of custom type in public schema" $
|
||||||
get "/rpc/test_arg?my_arg=something" `shouldRespondWith`
|
get "/rpc/test_arg?my_arg=something" `shouldRespondWith`
|
||||||
|
|||||||
+2
-2
@@ -91,12 +91,12 @@ main = do
|
|||||||
, ("Feature.DeleteSpec" , Feature.DeleteSpec.spec)
|
, ("Feature.DeleteSpec" , Feature.DeleteSpec.spec)
|
||||||
, ("Feature.InsertSpec" , Feature.InsertSpec.spec actualPgVersion)
|
, ("Feature.InsertSpec" , Feature.InsertSpec.spec actualPgVersion)
|
||||||
, ("Feature.JsonOperatorSpec" , Feature.JsonOperatorSpec.spec actualPgVersion)
|
, ("Feature.JsonOperatorSpec" , Feature.JsonOperatorSpec.spec actualPgVersion)
|
||||||
, ("Feature.QuerySpec" , Feature.QuerySpec.spec)
|
, ("Feature.QuerySpec" , Feature.QuerySpec.spec actualPgVersion)
|
||||||
, ("Feature.RpcSpec" , Feature.RpcSpec.spec actualPgVersion)
|
, ("Feature.RpcSpec" , Feature.RpcSpec.spec actualPgVersion)
|
||||||
, ("Feature.RangeSpec" , Feature.RangeSpec.spec)
|
, ("Feature.RangeSpec" , Feature.RangeSpec.spec)
|
||||||
, ("Feature.SingularSpec" , Feature.SingularSpec.spec)
|
, ("Feature.SingularSpec" , Feature.SingularSpec.spec)
|
||||||
, ("Feature.StructureSpec" , Feature.StructureSpec.spec)
|
, ("Feature.StructureSpec" , Feature.StructureSpec.spec)
|
||||||
, ("Feature.AndOrParamsSpec" , Feature.AndOrParamsSpec.spec)
|
, ("Feature.AndOrParamsSpec" , Feature.AndOrParamsSpec.spec actualPgVersion)
|
||||||
] ++ extraSpecs
|
] ++ extraSpecs
|
||||||
|
|
||||||
hspec $ do
|
hspec $ do
|
||||||
|
|||||||
Reference in New Issue
Block a user