Add support for selecting by column
This commit is contained in:
@@ -120,20 +120,25 @@ createWriteStatement qi selectQuery mutateQuery isSingle Full
|
||||
| otherwise = asJsonF
|
||||
|
||||
addRelations :: Schema -> [Relation] -> Maybe ReadRequest -> ReadRequest -> Either Text ReadRequest
|
||||
addRelations schema allRelations parentNode node@(Node n@(query, (table, _)) forest) =
|
||||
addRelations schema allRelations parentNode node@(Node readNode@(query, (name, _)) forest) =
|
||||
case parentNode of
|
||||
Nothing -> Node (query, (table, Nothing)) <$> updatedForest
|
||||
(Just (Node (_, (parentTable, _)) _)) -> Node <$> (addRel n <$> rel) <*> updatedForest
|
||||
(Just (Node (Select{from=[parentTable]}, (_, _)) _)) -> Node <$> (addRel readNode <$> rel) <*> updatedForest
|
||||
where
|
||||
rel = note ("no relation between " <> table <> " and " <> parentTable)
|
||||
$ findRelation schema table parentTable
|
||||
<|> findRelation schema parentTable table
|
||||
rel = note ("no relation between " <> parentTable <> " and " <> name)
|
||||
$ findRelationTable schema name parentTable
|
||||
<|> findRelationTable schema parentTable name
|
||||
<|> findRelationColumn schema parentTable name
|
||||
addRel :: (ReadQuery, (NodeName, Maybe Relation)) -> Relation -> (ReadQuery, (NodeName, Maybe Relation))
|
||||
addRel (q, (t, _)) r = (q, (t, Just r))
|
||||
addRel (q, (n, _)) r = (q {from=fromRelation}, (n, Just r))
|
||||
where fromRelation = map (\t -> if t == n then tableName (relTable r) else t) (from q)
|
||||
|
||||
_ -> Node (query, (name, Nothing)) <$> updatedForest
|
||||
where
|
||||
updatedForest = mapM (addRelations schema allRelations (Just node)) forest
|
||||
findRelation s t1 t2 =
|
||||
find (\r -> s == (tableSchema . relTable) r && t1 == (tableName . relTable) r && t2 == (tableName . relFTable) r) allRelations
|
||||
findRelationTable s t1 t2 =
|
||||
find (\r -> s == tableSchema (relTable r) && t1 == tableName (relTable r) && t2 == tableName (relFTable r)) allRelations
|
||||
findRelationColumn s t c =
|
||||
find (\r -> s == tableSchema (relTable r) && s == tableSchema (relFTable r) && t == tableName (relFTable r) && length (relFColumns r) == 1 && c == (colName . head . relFColumns) r) allRelations
|
||||
|
||||
addJoinConditions :: Schema -> ReadRequest -> Either Text ReadRequest
|
||||
addJoinConditions schema (Node (query, (n, r)) forest) =
|
||||
@@ -218,11 +223,12 @@ requestToCountQuery schema (DbRead (Node (Select _ _ conditions _, (mainTbl, _))
|
||||
requestToQuery :: Schema -> DbRequest -> SqlQuery
|
||||
requestToQuery _ (DbMutate (Insert _ (PayloadParseError _))) = undefined
|
||||
requestToQuery _ (DbMutate (Update _ (PayloadParseError _) _)) = undefined
|
||||
requestToQuery schema (DbRead (Node (Select colSelects tbls conditions ord, (mainTbl, _)) forest)) =
|
||||
requestToQuery schema (DbRead (Node (Select colSelects tbls conditions ord, (nodeName, maybeRelation)) forest)) =
|
||||
query
|
||||
where
|
||||
-- TODO! the folloing helper functions are just to remove the "schema" part when the table is "source" which is the name
|
||||
-- of our WITH query part
|
||||
mainTbl = fromMaybe nodeName (tableName . relTable <$> maybeRelation)
|
||||
tblSchema tbl = if tbl == sourceCTEName then "" else schema
|
||||
qi = QualifiedIdentifier (tblSchema mainTbl) mainTbl
|
||||
toQi t = QualifiedIdentifier (tblSchema t) t
|
||||
@@ -253,28 +259,27 @@ requestToQuery schema (DbRead (Node (Select colSelects tbls conditions ord, (mai
|
||||
intercalate " AND " ( map (pgFmtCondition qi ) joinConditions )
|
||||
where
|
||||
joinConditions = filter (filterParentConditions t) conditions
|
||||
filterParentConditions parentTable (Filter _ _ (VForeignKey (QualifiedIdentifier "" t) _)) =
|
||||
parentTable == t
|
||||
filterParentConditions parentTable (Filter _ _ (VForeignKey (QualifiedIdentifier "" t) _)) = parentTable == t
|
||||
filterParentConditions _ _ = False
|
||||
getQueryParts :: Tree ReadNode -> ([(SqlFragment, TableName)], [SqlFragment]) -> ([(SqlFragment,TableName)], [SqlFragment])
|
||||
getQueryParts (Node n@(_, (table, Just (Relation {relType=Child}))) forst) (j,s) = (j,sel:s)
|
||||
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
|
||||
<> "), '[]') AS " <> table
|
||||
<> "), '[]') AS " <> pgFmtIdent name
|
||||
where subquery = requestToQuery schema (DbRead (Node n forst))
|
||||
getQueryParts (Node n@(_, (table, Just (Relation {relType=Parent}))) forst) (j,s) = (joi:j,sel:s)
|
||||
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 "<>table --TODO must be singular
|
||||
sel = "row_to_json(" <> table <> ".*) AS "<>pgFmtIdent name --TODO must be singular
|
||||
joi = ("( " <> subquery <> " ) AS " <> table, table)
|
||||
where subquery = requestToQuery schema (DbRead (Node n forst))
|
||||
getQueryParts (Node n@(_, (table, Just (Relation {relType=Many}))) forst) (j,s) = (j,sel:s)
|
||||
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
|
||||
<> "), '[]') AS " <> table
|
||||
<> "), '[]') AS " <> pgFmtIdent name
|
||||
where subquery = requestToQuery schema (DbRead (Node n forst))
|
||||
--the following is just to remove the warning
|
||||
--getQueryParts is not total but requestToQuery is called only after addJoinConditions which ensures the only
|
||||
|
||||
@@ -106,10 +106,10 @@ type Cast = Text
|
||||
type NodeName = Text
|
||||
type SelectItem = (Field, Maybe Cast)
|
||||
type Path = [Text]
|
||||
data ReadQuery = Select { select::[SelectItem], from::[Text], flt_::[Filter], order::Maybe [OrderTerm] } deriving (Show, Eq)
|
||||
data MutateQuery = Insert { in_::Text, qPayload::Payload }
|
||||
| Delete { in_::Text, where_::[Filter] }
|
||||
| Update { in_::Text, qPayload::Payload, where_::[Filter] } deriving (Show, Eq)
|
||||
data ReadQuery = Select { select::[SelectItem], from::[TableName], flt_::[Filter], order::Maybe [OrderTerm] } deriving (Show, Eq)
|
||||
data MutateQuery = Insert { in_::TableName, qPayload::Payload }
|
||||
| Delete { in_::TableName, where_::[Filter] }
|
||||
| Update { in_::TableName, qPayload::Payload, where_::[Filter] } deriving (Show, Eq)
|
||||
data Filter = Filter {field::Field, operator::Operator, value::FValue} deriving (Show, Eq)
|
||||
type ReadNode = (ReadQuery, (NodeName, Maybe Relation))
|
||||
type ReadRequest = Tree ReadNode
|
||||
|
||||
@@ -224,7 +224,11 @@ spec struct pool = around (withApp cfgDefault struct pool) $ do
|
||||
|
||||
it "detect relations in views from exposed schema that are based on tables in private schema and have columns renames" $
|
||||
get "/articles?id=eq.1&select=id,articleStars{users{*}}" `shouldRespondWith`
|
||||
[str|[{"id":1,"articlestars":[{"users":{"id":1,"name":"Angela Martin"}},{"users":{"id":2,"name":"Michael Scott"}},{"users":{"id":3,"name":"Dwight Schrute"}}]}]|]
|
||||
[str|[{"id":1,"articleStars":[{"users":{"id":1,"name":"Angela Martin"}},{"users":{"id":2,"name":"Michael Scott"}},{"users":{"id":3,"name":"Dwight Schrute"}}]}]|]
|
||||
|
||||
it "can select by column name" $
|
||||
get "/projects?id=in.1,3&select=id,name,client_id,client_id{id,name}" `shouldRespondWith`
|
||||
"[{\"id\":1,\"name\":\"Windows 7\",\"client_id\":1,\"client_id\":{\"id\":1,\"name\":\"Microsoft\"}},{\"id\":3,\"name\":\"IOS\",\"client_id\":2,\"client_id\":{\"id\":2,\"name\":\"Apple\"}}]"
|
||||
|
||||
|
||||
describe "Plurality singular" $ do
|
||||
|
||||
Reference in New Issue
Block a user