packages feed

postgrest 0.3.0.2 → 0.3.0.3

raw patch · 6 files changed

+43/−20 lines, 6 files

Files

postgrest.cabal view
@@ -2,7 +2,7 @@ description:           Reads the schema of a PostgreSQL database and creates RESTful routes                        for the tables and views, supporting all HTTP verbs that security                        permits.-version:               0.3.0.2+version:               0.3.0.3 synopsis:              REST API for any Postgres database license:               MIT license-file:          LICENSE
src/PostgREST/DbStructure.hs view
@@ -127,12 +127,14 @@ addParentRelations (rel@(Relation t c ft fc _ _ _ _):rels) = Relation ft fc t c Parent Nothing Nothing Nothing : rel : addParentRelations rels  addManyToManyRelations :: [Relation] -> [Relation]-addManyToManyRelations rels = rels ++ mapMaybe link2Relation links+addManyToManyRelations rels = rels ++ addMirrorRelation (mapMaybe link2Relation links)   where     links = join $ map (combinations 2) $ filter (not . null) $ groupWith groupFn $ filter ( (==Child). relType) rels     groupFn :: Relation -> Text     groupFn (Relation{relTable=Table{tableSchema=s, tableName=t}}) = s<>"_"<>t     combinations k ns = filter ((k==).length) (subsequences ns)+    addMirrorRelation [] = []+    addMirrorRelation (rel@(Relation t c ft fc _ lt lc1 lc2):rels') = Relation ft fc t c Many lt lc2 lc1 : rel : addMirrorRelation rels'     link2Relation [       Relation{relTable=lt, relColumns=lc1, relFTable=t,  relFColumns=c},       Relation{             relColumns=lc2, relFTable=ft, relFColumns=fc}
src/PostgREST/QueryBuilder.hs view
@@ -129,7 +129,6 @@       where         rel = note ("no relation between " <> parentTable <> " and " <> name)             $  findRelationByTable schema name parentTable-           <|> findRelationByTable schema parentTable name            <|> findRelationByColumn schema parentTable name         addRel :: (ReadQuery, (NodeName, Maybe Relation)) -> Relation -> (ReadQuery, (NodeName, Maybe Relation))         addRel (q, (n, _)) r = (q {from=fromRelation}, (n, Just r))@@ -272,20 +271,20 @@     getQueryParts (Node n@(_, (name, Just (Relation {relType=Child,relTable=Table{tableName=table}}))) forst) (j,s) = (j,sel:s)       where         sel = "COALESCE(("-           <> "SELECT array_to_json(array_agg(row_to_json("<>table<>"))) "-           <> "FROM (" <> subquery <> ") " <> table+           <> "SELECT array_to_json(array_agg(row_to_json("<>pgFmtIdent table<>"))) "+           <> "FROM (" <> subquery <> ") " <> pgFmtIdent table            <> "), '[]') AS " <> pgFmtIdent name            where subquery = requestToQuery schema (DbRead (Node n forst))     getQueryParts (Node n@(_, (name, Just (Relation {relType=Parent,relTable=Table{tableName=table}}))) forst) (j,s) = (joi:j,sel:s)       where-        sel = "row_to_json(" <> table <> ".*) AS "<>pgFmtIdent name --TODO must be singular-        joi = ("( " <> subquery <> " ) AS " <> table, table)+        sel = "row_to_json(" <> pgFmtIdent table <> ".*) AS "<>pgFmtIdent name --TODO must be singular+        joi = ("( " <> subquery <> " ) AS " <> pgFmtIdent table, table)           where subquery = requestToQuery schema (DbRead (Node n forst))     getQueryParts (Node n@(_, (name, Just (Relation {relType=Many,relTable=Table{tableName=table}}))) forst) (j,s) = (j,sel:s)       where         sel = "COALESCE (("-           <> "SELECT array_to_json(array_agg(row_to_json("<>table<>"))) "-           <> "FROM (" <> subquery <> ") " <> table+           <> "SELECT array_to_json(array_agg(row_to_json("<>pgFmtIdent table<>"))) "+           <> "FROM (" <> subquery <> ") " <> pgFmtIdent table            <> "), '[]') AS " <> pgFmtIdent name            where subquery = requestToQuery schema (DbRead (Node n forst))     --the following is just to remove the warning
test/Feature/InsertSpec.hs view
@@ -23,7 +23,7 @@ spec :: DbStructure -> H.Pool P.Postgres -> Spec spec struct pool = beforeAll_ resetDb $ around (withApp cfgDefault struct pool) $ do   describe "Posting new record" $ do-    after_ (clearTable "menagerie") . context "disparate csv types" $ do+    context "disparate csv types" $ do       it "accepts disparate json types" $ do         p <- post "/menagerie"           [json| {@@ -57,7 +57,7 @@       context "with no pk supplied" $ do-      context "into a table with auto-incrementing pk" . after_ (clearTable "auto_incrementing_pk") $+      context "into a table with auto-incrementing pk" $         it "succeeds with 201 and link" $ do           p <- post "/auto_incrementing_pk" [json| { "non_nullable_string":"not null"} |]           liftIO $ do@@ -76,7 +76,7 @@           post "/simple_pk" [json| { "extra":"foo"} |]             `shouldRespondWith` 400 -      context "into a table with no pk" . after_ (clearTable "no_pk") $ do+      context "into a table with no pk" $ do         it "succeeds with 201 and a link including all fields" $ do           p <- post "/no_pk" [json| { "a":"foo", "b":"bar" } |]           liftIO $ do@@ -111,7 +111,7 @@             simpleHeaders p `shouldSatisfy` matchHeader hLocation "/no_pk\\?a=is.null&b=eq.foo"             simpleStatus p `shouldBe` created201 -    context "with compound pk supplied" . after_ (clearTable "compound_pk") $+    context "with compound pk supplied" $       it "builds response location header appropriately" $         post "/compound_pk" [json| { "k1":12, "k2":42 } |]           `shouldRespondWith` ResponseMatcher {@@ -124,7 +124,7 @@       it "fails with 400 and error" $         post "/simple_pk" "}{ x = 2" `shouldRespondWith` 400 -    context "jsonb" . after_ (clearTable "json") $ do+    context "jsonb" $ do       it "serializes nested object" $ do         let inserted = [json| { "data": { "foo":"bar" } } |]         request methodPost "/json"@@ -162,7 +162,7 @@    describe "CSV insert" $ do -    after_ (clearTable "menagerie") . context "disparate csv types" $+    context "disparate csv types" $       it "succeeds with multipart response" $ do         pendingWith "Decide on what to do with CSV insert"         let inserted = [str|integer,double,varchar,boolean,date,money,enum@@ -185,7 +185,7 @@         --   simpleBody p `shouldBe` "Content-Type: application/json\nLocation: /menagerie?integer=eq.13\n\n\n--postgrest_boundary\nContent-Type: application/json\nLocation: /menagerie?integer=eq.12\n\n"         --   simpleStatus p `shouldBe` created201 -    after_ (clearTable "no_pk") . context "requesting full representation" $ do+    context "requesting full representation" $ do       it "returns full details of inserted record" $         request methodPost "/no_pk"                      [("Content-Type", "text/csv"), ("Accept", "text/csv"),  ("Prefer", "return=representation")]@@ -220,7 +220,7 @@           }  -    after_ (clearTable "no_pk") . context "with wrong number of columns" $+    context "with wrong number of columns" $       it "fails for too few" $ do         p <- request methodPost "/no_pk" [("Content-Type", "text/csv")] "a,b\nfoo,bar\nbaz"         liftIO $ simpleStatus p `shouldBe` badRequest400@@ -255,7 +255,7 @@               [json| { "k1":12, "k2":42 } |]                 `shouldRespondWith` 400 -        context "specifying every column in the table" . after_ (clearTable "compound_pk") $ do+        context "specifying every column in the table" $ do           it "can create a new record" $ do             pendingWith "Decide on PUT usefullness"             p <- request methodPut "/compound_pk?k1=eq.12&k2=eq.42" []@@ -287,7 +287,7 @@               let record = head rows               compoundExtra record `shouldBe` Just 5 -      context "with an auto-incrementing primary key" . after_ (clearTable "auto_incrementing_pk") $+      context "with an auto-incrementing primary key"$          it "succeeds with 204" $ do           pendingWith "Decide on PUT usefullness"
test/Feature/QuerySpec.hs view
@@ -214,6 +214,11 @@       get "/tasks?select=id,users{id}" `shouldRespondWith`         [str|[{"id":1,"users":[{"id":1},{"id":3}]},{"id":2,"users":[{"id":1}]},{"id":3,"users":[{"id":1}]},{"id":4,"users":[{"id":1}]},{"id":5,"users":[{"id":2},{"id":3}]},{"id":6,"users":[{"id":2}]},{"id":7,"users":[{"id":2}]},{"id":8,"users":[]}]|] ++    it "requesting many<->many relation reverse" $+      get "/users?select=id,tasks{id}" `shouldRespondWith`+        [str|[{"id":1,"tasks":[{"id":1},{"id":2},{"id":3},{"id":4}]},{"id":2,"tasks":[{"id":5},{"id":6},{"id":7}]},{"id":3,"tasks":[{"id":1},{"id":5}]}]|]+     it "requesting parents and children on views" $       get "/projects_view?id=eq.1&select=id, name, clients{*}, tasks{id, name}" `shouldRespondWith`         [str|[{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}]|]@@ -382,3 +387,18 @@       it "returns proper json" $         post "/rpc/sayhello" [json| { "name": "world" } |] `shouldRespondWith`           [json| [{"sayhello":"Hello, world"}] |]++  describe "weird requests" $ do+    it "can query as normal" $ do+      get "/Escap3e;" `shouldRespondWith`+        [json| [{"so6meIdColumn":1},{"so6meIdColumn":2},{"so6meIdColumn":3},{"so6meIdColumn":4},{"so6meIdColumn":5}] |]+      get "/ghostBusters" `shouldRespondWith`+        [json| [{"escapeId":1},{"escapeId":3},{"escapeId":5}] |]++    it "will embed a collection" $+      get "/Escap3e;?select=ghostBusters{*}" `shouldRespondWith`+        [json| [{"ghostBusters":[{"escapeId":1}]},{"ghostBusters":[]},{"ghostBusters":[{"escapeId":3}]},{"ghostBusters":[]},{"ghostBusters":[{"escapeId":5}]}] |]++    it "will embed using a column" $+      get "/ghostBusters?select=escapeId{*}" `shouldRespondWith`+        [json| [{"escapeId":{"so6meIdColumn":1}},{"escapeId":{"so6meIdColumn":3}},{"escapeId":{"so6meIdColumn":5}}] |]
test/Feature/StructureSpec.hs view
@@ -18,13 +18,15 @@     it "lists views in schema" $       request methodGet "/" [] ""         `shouldRespondWith` [json| [-          {"schema":"test","name":"articleStars","insertable":true}+          {"schema":"test","name":"Escap3e;","insertable":true}+        , {"schema":"test","name":"articleStars","insertable":true}         , {"schema":"test","name":"articles","insertable":true}         , {"schema":"test","name":"auto_incrementing_pk","insertable":true}         , {"schema":"test","name":"clients","insertable":true}         , {"schema":"test","name":"comments","insertable":true}         , {"schema":"test","name":"complex_items","insertable":true}         , {"schema":"test","name":"compound_pk","insertable":true}+        , {"schema":"test","name":"ghostBusters","insertable":true}         , {"schema":"test","name":"has_count_column","insertable":false}         , {"schema":"test","name":"has_fk","insertable":true}         , {"schema":"test","name":"insertable_view_with_join","insertable":true}