tests for &select= feature and support for casting columns (usefull when extracting subfields from json columns)

This commit is contained in:
Ruslan Talpa
2015-09-05 15:05:53 +03:00
parent 6c16395dfb
commit 9c8ac2a489
5 changed files with 75 additions and 9 deletions
+6 -2
View File
@@ -141,9 +141,13 @@ select table params =
cols = filter ((>0) . T.length) $ map T.strip $ T.split (==',') $ cs columnsParam
selectTerm :: QualifiedIdentifier -> T.Text -> PStmt
selectTerm table col = B.Stmt (pgFmtJsonbPath table (cs col) <> asT jsonbPath) empty True
selectTerm table col =
case T.splitOn "::" col of
[colName,castTo] -> B.Stmt ("CAST (" <> pgFmtJsonbPath table (cs colName) <> " AS " <> castTo <> " )" <> asT (jsonbPath colName)) empty True
_-> B.Stmt (pgFmtJsonbPath table (cs col) <> asT (jsonbPath col)) empty True
where
jsonbPath = parseJsonbPath $ cs col
jsonbPath :: T.Text -> Maybe JsonbPath
jsonbPath c = parseJsonbPath $ cs c
asT (Just (DoubleArrow _ (KeyIdentifier key))) = " AS " <> pgFmtIdent key
asT _ = ""
+33 -1
View File
@@ -11,13 +11,14 @@ import SpecHelper
spec :: Spec
spec =
beforeAll (clearTable "items" >> createItems 15)
. beforeAll (clearTable "complex_items" >> createComplexItems)
. beforeAll (clearTable "nullable_integer" >> createNullInteger)
. beforeAll (
clearTable "no_pk" >>
createNulls 2 >>
createLikableStrings >>
createJsonData)
. afterAll_ (clearTable "items" >> clearTable "no_pk" >> clearTable "simple_pk")
. afterAll_ (clearTable "items" >> clearTable "complex_items" >> clearTable "no_pk" >> clearTable "simple_pk")
. around withApp $ do
describe "Querying a table with a column called count" $
@@ -129,6 +130,37 @@ spec =
get "/items?always_true=eq.true" `shouldRespondWith`
[json| [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15}] |]
describe "Shaping response with select parameter" $ do
it "selectStar works in absense of parameter" $
get "/complex_items?id=eq.3" `shouldRespondWith`
"[{\"id\":3,\"name\":\"Three\",\"settings\":{\"foo\":{\"int\":1,\"bar\":\"baz\"}}}]"
it "one simple column" $
get "/complex_items?select=id" `shouldRespondWith`
[json| [{"id":1},{"id":2},{"id":3}] |]
it "one simple column with casting (text)" $
get "/complex_items?select=id::text" `shouldRespondWith`
[json| [{"id":"1"},{"id":"2"},{"id":"3"}] |]
it "json column" $
get "/complex_items?id=eq.1&select=settings" `shouldRespondWith`
[json| [{"settings":{"foo":{"int":1,"bar":"baz"}}}] |]
it "json subfield one level with casting (json)" $
get "/complex_items?id=eq.1&select=settings->>foo::json" `shouldRespondWith`
[json| [{"foo":{"int":1,"bar":"baz"}}] |] -- the value of foo here is of type "text"
it "json subfield two levels (string)" $
get "/complex_items?id=eq.1&select=settings->foo->>bar" `shouldRespondWith`
[json| [{"bar":"baz"}] |]
it "json subfield two levels with casting (int)" $
get "/complex_items?id=eq.1&select=settings->foo->>int::integer" `shouldRespondWith`
[json| [{"int":1}] |] -- the value in the db is an int, but here we expect a string for now
describe "ordering response" $ do
it "by a column asc" $
get "/items?id=lte.2&order=id.asc"
+1
View File
@@ -15,6 +15,7 @@ spec = around withApp $ do
request methodGet "/" [] ""
`shouldRespondWith` [json| [
{"schema":"1","name":"auto_incrementing_pk","insertable":true}
, {"schema":"1","name":"complex_items","insertable":true}
, {"schema":"1","name":"compound_pk","insertable":true}
, {"schema":"1","name":"has_count_column","insertable":false}
, {"schema":"1","name":"has_fk","insertable":true}
+13
View File
@@ -13,6 +13,7 @@ import Data.Monoid
import Data.Text hiding (map)
import qualified Data.Vector as V
import Control.Monad (void)
import Control.Applicative
import Network.HTTP.Types.Header (Header, ByteRange, renderByteRange,
hRange, hAuthorization, hAccept)
@@ -118,6 +119,18 @@ createItems n = do
txn = mapM_ H.unitEx stmts
stmts = map [H.stmt|insert into "1".items (id) values (?)|] [1..n]
createComplexItems :: IO ()
createComplexItems = do
pool <- testPool
void . liftIO $ H.session pool $ H.tx Nothing txn
where
txn = mapM_ H.unitEx stmts
stmts = getZipList $ [H.stmt|insert into "1".complex_items (id, name, settings) values (?,?,?)|]
<$> ZipList ([1..3]::[Int])
<*> ZipList (["One", "Two", "Three"]::[Text])
<*> ZipList ([jobj,jobj,jobj])
jobj = (J.object [("foo", J.object [("int", J.Number 1),("bar", J.String "baz")])])
createNulls :: Int -> IO ()
createNulls n = do
pool <- testPool
+22 -6
View File
@@ -47,7 +47,7 @@ SET search_path = postgrest, pg_catalog;
CREATE FUNCTION check_role_exists() RETURNS trigger
LANGUAGE plpgsql
AS $$
begin
begin
if not exists (select 1 from pg_roles as r where r.rolname = new.rolname) then
raise foreign_key_violation using message = 'Cannot create user with unknown role: ' || new.rolname;
return null;
@@ -64,7 +64,7 @@ CREATE FUNCTION update_owner() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.owner = current_user;
NEW.owner = current_user;
RETURN NEW;
END;
$$;
@@ -75,8 +75,8 @@ ALTER FUNCTION postgrest.update_owner() OWNER TO postgrest_test;
CREATE FUNCTION set_authors_only_owner() RETURNS trigger
LANGUAGE plpgsql
AS $$
begin
NEW.owner = current_setting('user_vars.user_id');
begin
NEW.owner = current_setting('user_vars.user_id');
RETURN NEW;
end
$$;
@@ -170,7 +170,7 @@ ALTER TABLE "1".has_fk_id_seq OWNER TO postgrest_test;
ALTER SEQUENCE has_fk_id_seq OWNED BY has_fk.id;
CREATE MATERIALIZED VIEW "1".materialized_view AS
SELECT
SELECT
version();
ALTER TABLE "1".materialized_view OWNER TO postgrest_test;
@@ -201,6 +201,15 @@ CREATE TABLE items (
ALTER TABLE "1".items OWNER TO postgrest_test;
CREATE TABLE complex_items (
id bigint NOT NULL,
name text,
settings json
);
ALTER TABLE "1".complex_items OWNER TO postgrest_test;
CREATE SEQUENCE items_id_seq
START WITH 1
@@ -407,7 +416,7 @@ ALTER FUNCTION public.always_true("1".items) OWNER TO postgrest_test;
ALTER TABLE ONLY authors_only
ADD CONSTRAINT authors_only_pkey PRIMARY KEY (secret);
CREATE TRIGGER insert_insertable_view_with_join INSTEAD OF INSERT ON "1".insertable_view_with_join FOR EACH ROW EXECUTE PROCEDURE "1".insert_insertable_view_with_join();
@@ -437,6 +446,8 @@ ALTER TABLE ONLY has_fk
ALTER TABLE ONLY items
ADD CONSTRAINT items_pkey PRIMARY KEY (id);
ALTER TABLE ONLY complex_items
ADD CONSTRAINT complex_items_pkey PRIMARY KEY (id);
ALTER TABLE ONLY menagerie
@@ -539,6 +550,11 @@ REVOKE ALL ON TABLE items FROM postgrest_test;
GRANT ALL ON TABLE items TO postgrest_test;
GRANT ALL ON TABLE items TO postgrest_anonymous;
REVOKE ALL ON TABLE complex_items FROM PUBLIC;
REVOKE ALL ON TABLE complex_items FROM postgrest_test;
GRANT ALL ON TABLE complex_items TO postgrest_test;
GRANT ALL ON TABLE complex_items TO postgrest_anonymous;
REVOKE ALL ON FUNCTION getitemrange(bigint, bigint) FROM PUBLIC;
REVOKE ALL ON FUNCTION getitemrange(bigint, bigint) FROM postgrest_test;