From 71dab115c9be7670878545671454060a1f5c758d Mon Sep 17 00:00:00 2001 From: Diogo Biazus Date: Wed, 2 Dec 2015 15:23:10 -0500 Subject: [PATCH 1/4] Uses qualified column name in order by clause to allow computed columns --- src/PostgREST/QueryBuilder.hs | 24 +++++++++++------------- test/Feature/QuerySpec.hs | 6 +++++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/PostgREST/QueryBuilder.hs b/src/PostgREST/QueryBuilder.hs index 9b9481ea9..b819c2562 100644 --- a/src/PostgREST/QueryBuilder.hs +++ b/src/PostgREST/QueryBuilder.hs @@ -200,6 +200,17 @@ requestToQuery schema (DbRead (Node (Select colSelects tbls conditions ord, (mai ("WHERE " <> intercalate " AND " ( map (pgFmtCondition qi ) conditions )) `emptyOnNull` conditions, orderF (fromMaybe [] ord) ] + orderF ts = + if null ts + then "" + else "ORDER BY " <> clause + where + clause = intercalate "," (map queryTerm ts) + queryTerm :: OrderTerm -> Text + queryTerm t = " " + <> cs (pgFmtColumn qi $ otTerm t) <> " " + <> (cs.show) (otDirection t) <> " " + <> maybe "" (cs.show) (otNullOrder t) <> " " (withs, selects) = foldr getQueryParts ([],[]) forest getQueryParts :: Tree ReadNode -> ([(SqlFragment, Text)], [SqlFragment]) -> ([(SqlFragment,Text)], [SqlFragment]) getQueryParts (Node n@(_, (table, Just (Relation {relType=Child}))) forst) (w,s) = (w,sel:s) @@ -337,19 +348,6 @@ getJoinConditions (Relation t cols ft fcs typ lt lc1 lc2) = emptyOnNull :: Text -> [a] -> Text emptyOnNull val x = if null x then "" else val -orderF :: [OrderTerm] -> SqlFragment -orderF ts = - if null ts - then "" - else "ORDER BY " <> clause - where - clause = intercalate "," (map queryTerm ts) - queryTerm :: OrderTerm -> Text - queryTerm t = " " - <> cs (pgFmtIdent $ otTerm t) <> " " - <> (cs.show) (otDirection t) <> " " - <> maybe "" (cs.show) (otNullOrder t) <> " " - insertableValue :: JSON.Value -> SqlFragment insertableValue JSON.Null = "null" insertableValue v = (<> "::unknown") . pgFmtLit $ unquoted v diff --git a/test/Feature/QuerySpec.hs b/test/Feature/QuerySpec.hs index f4bca6c20..f238af540 100644 --- a/test/Feature/QuerySpec.hs +++ b/test/Feature/QuerySpec.hs @@ -130,7 +130,11 @@ spec = [json| [{"text_search_vector":"'baz':1 'qux':2"}] |] it "matches with computed column" $ - get "/items?always_true=eq.true" `shouldRespondWith` + get "/items?always_true=eq.true&order=id.asc" `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}] |] + + it "order by computed column" $ + get "/items?order=always_true.asc,id.asc" `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}] |] it "matches filtering nested items" $ From 1266bad2f8fd99ba501e6705ec7b9cd20b0bc142 Mon Sep 17 00:00:00 2001 From: Diogo Biazus Date: Wed, 2 Dec 2015 15:27:27 -0500 Subject: [PATCH 2/4] Adds another note about computed coulmns to the docs --- docs/api/reading.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/api/reading.md b/docs/api/reading.md index ea2a4460a..dd35df6da 100644 --- a/docs/api/reading.md +++ b/docs/api/reading.md @@ -171,6 +171,11 @@ If you care where nulls are sorted, add `nullsfirst` or `nullslast`: GET /people?order=age.nullsfirst ``` +You can also use [computed +columns](http://www.postgresql.org/docs/current/interactive/xfunc-sql.html#XFUNC-SQL-COMPOSITE-FUNCTIONS) +to order the results, even though the computed +columns will not appear in the output. + ### Limiting and Pagination #### Pagination by Limit-Offset From c2e3dd716c4c3ed220b420c24a191d9bef5c43dd Mon Sep 17 00:00:00 2001 From: Diogo Biazus Date: Wed, 2 Dec 2015 15:28:27 -0500 Subject: [PATCH 3/4] Updates CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9322aa69c..7d851ccb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Miscalculation of time used for expiring tokens - @calebmer - Remove bcrypt dependency to fix Windows build - @begriffs +### Added +- Allow order by computed columns - @diogob + ## [0.3.0.1] - 2015-11-27 ### Fixed From 65e7744858db3f3bf199aa0f0a588a41c594f457 Mon Sep 17 00:00:00 2001 From: Diogo Biazus Date: Wed, 2 Dec 2015 17:12:37 -0500 Subject: [PATCH 4/4] Uses anti_id computed column to make test case clearer --- test/Feature/QuerySpec.hs | 2 +- test/fixtures/schema.sql | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/Feature/QuerySpec.hs b/test/Feature/QuerySpec.hs index f238af540..99ec84403 100644 --- a/test/Feature/QuerySpec.hs +++ b/test/Feature/QuerySpec.hs @@ -134,7 +134,7 @@ spec = [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}] |] it "order by computed column" $ - get "/items?order=always_true.asc,id.asc" `shouldRespondWith` + get "/items?order=anti_id.desc" `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}] |] it "matches filtering nested items" $ diff --git a/test/fixtures/schema.sql b/test/fixtures/schema.sql index 1d65862a6..c73d66a83 100755 --- a/test/fixtures/schema.sql +++ b/test/fixtures/schema.sql @@ -462,6 +462,11 @@ CREATE FUNCTION public.always_true(test.items) RETURNS boolean ALTER FUNCTION public.always_true(test.items) OWNER TO postgrest_test; +CREATE FUNCTION public.anti_id(test.items) RETURNS bigint +LANGUAGE sql STABLE +AS $$ SELECT $1.id * -1 $$; + +ALTER FUNCTION public.anti_id(test.items) OWNER TO postgrest_test; ALTER TABLE ONLY authors_only