heroku/force — pull request #7 by ryanbrainard (2013-10-27 21:04:02+00:00)
Title: Add support for parent relationship SOQL queries

SOQL supports relationship queries, which returns an object graph needs to be traversed to display correctly. Currently, `force` prints out relationship query results like this:

```
$ force select "id, account.createdby.name from contact where name = 'Mary Martini' order by id limit 2"
Id | Account
--------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
00360000013beouAAA | map[attributes:map[type:Account url:/services/data/v20.0/sobjects/Account/0016000000uLxRtAAK] CreatedBy:map[attributes:map[type:User url:/services/data/v20.0/sobjects/User/00560000000wX0aAAE] Name:Ryan Brainard]]
00360000013bepsAAA |
--------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(2 records)
```

This pull request fixes this by traversing the object graph in the returned results, so that it looks like this:

```
$ force select "id, account.createdby.name from contact where name = 'Mary Martini' order by id limit 2"
Id | Account.CreatedBy.Name
--------------------+------------------------
00360000013beouAAA | Ryan Brainard
00360000013bepsAAA |
--------------------+------------------------
(2 records)
```

A few notes on this change:

- This only fixes parent relationship queries. Child relationship queries remain broken, but I hope to get to those as well. They will require nested table and will be trickier.

- Because the relationships are only returned for records that actually have them, all records have to be inspected for relationships (not just the first row) to collect the column names in the printed table.

- Any transient relationships that only exist for traversing to a higher level are not displayed in the table. For example, if someone queries for `Account.CreatedBy.Name`, `Account` and `Account.CreatedBy` are removed because they were only used to traverse to `Account.CreatedBy.Name`.