└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # `dhallql` -- a query language for the web 2 | 3 | `dhallql` is a query language for the web - much like GraphQL. This project is 4 | in its infancy, and we're currently in the design phase. 5 | 6 | ## Proposal 7 | 8 | In `dhallql` the main query expression is a function of type `Root -> A` - `Root` 9 | is a type defined by the API, and `A` is the type of data that the client wishes 10 | to retrieve. 11 | 12 | `Root` provides access to "root resources", usually as a record of functions, 13 | and `A` is a type built using these root resources to derive a subset of 14 | information that the client wants to work with. 15 | 16 | As an example, let's consider the query for the first 100 hundred repositories 17 | of the user `ocharles` on some GitHub. Our GitHub `dhallql` API gives us the 18 | following `Root` type: 19 | 20 | ``` dhall 21 | let T = https://dhallql.github.com/Types.dhall 22 | 23 | in { user : { name : Text } → Optional T.User } 24 | ``` 25 | 26 | That is, `Root` is a record type, with one field `user`, who's type is 27 | `{name : Text} -> Optional T.User`. 28 | 29 | This alone gives us the ability to query for users. To get the `ocharles` 30 | `User`, we would send: 31 | 32 | ``` dhall 33 | λ(root : http://dhallql.github.com/Root.dhall) → root.user { name = "ocharles" } 34 | ``` 35 | 36 | But that's not quite what we want. If we inspect `Types.dhall`, we see that we 37 | can pull information out of `User`s: 38 | 39 | ``` dhall 40 | let Repository = { name : Text } 41 | 42 | in let RepositoryConnection = { nodes : List Repository } 43 | 44 | in let User = { repositories : < first : Natural > → RepositoryConnection } 45 | 46 | in { Repository = 47 | Repository 48 | , RepositoryConnection = 49 | RepositoryConnection 50 | , User = 51 | User 52 | } 53 | ``` 54 | 55 | `User` values are records that have a `repositories` function, which gives us a 56 | `RepositoryConnection`, and this has a list of `Repository`s. Thus our query is 57 | just a Dhall expression that turns a `User` into a list of repository names: 58 | 59 | ``` dhall 60 | let prelude = https://prelude.dhall-lang.org/package.dhall 61 | 62 | in λ(queries : https://dhallql.github.com/Root.dhall) 63 | → prelude.`Optional`.map 64 | T.User 65 | (List { name : Text }) 66 | ( λ(user : T.User) 67 | → prelude.`List`.map 68 | T.Repository 69 | { name : Text } 70 | (λ(repo : T.Repository) → { name = repo.name }) 71 | (user.repositories < first = 100 >).nodes 72 | ) 73 | (root.user { name = "ocharles" }) 74 | ``` 75 | 76 | In this more complicated query we're importing the Dhall prelude to get access 77 | to `map` for `List` and `Optional`. We then query 78 | `root.user { name = "ocharles"}` and map over its return value. If there is such 79 | a user, we call `.repositories` asking for the first 100 repositories. We then 80 | extract just the `name` field of repositories giving us a final query that maps 81 | `ocharles` into a list of repository names. 82 | --------------------------------------------------------------------------------