# json-query : CS316 Coursework 2023 This is the repository for the CS316 coursework for 2023. This coursework is worth 50% of your mark for the course. The other 50% is from the class test in Week 6 (or the redemption test in Week 9). ## Description The goal of this coursework project is to construct a small command line Haskell program for querying data stored in [JavaScript Object Notation](https://en.wikipedia.org/wiki/JSON) (JSON). The tool we will make is a simplified version of [jq](https://jqlang.github.io/jq/). The basic structure of the project has been written for you. To get a basic mark you need to fill in the missing implementations. This will get you an implementation that can read in JSON files, filter them according to a fixed query, and print out the results. To get a higher mark, you need to implement some automated testing and extensions to the basic project. See below for details. ## Getting Started The whole repository is structured as a [Cabal](https://haskell.org/cabal) project in a Git repository. Get started by **first** forking the repository on GitLab, and **then** cloning your fork. The project is structured into library code in [src](src/) and the main program in [app/Main.hs](app/Main.hs). There is also space for tests in [test/Spec.hs](test/Spec.hs). Data files are stored in [data/](data/). To build the whole project, use the following command when in the project directory: ``` $ cabal build ``` This will build the project. If this fails, please contact [Robert Atkey](robert.atkey@strath.ac.uk), or use Mattermost. To execute the program, use: ``` $ cabal run json-query -- data/hills.csv ``` If you have just started, this will fail with an error reporting that the `execute` function has not yet been implemented. Time to start implementing! During development, it is often easier to test functions interactively via `ghci`. To load the library definitions in `src` into GHCi use: ``` $ cabal repl ``` (`repl` stands for Read-Eval-Print-Loop.) When in `cabal repl`, you can access definitions in each module either as `<ModuleName>.<name>` (e.g., `JSONOutput.output`), or by writing `import <ModuleName>` and then using the names directly. ### Running the test suite The test suite in the skeleton project is empty. To run it, use the command: ``` $ cabal test ``` It should tell you that the tests FAILED with `"Test suite not yet implemented"`. ## Expected Functionality Once the unimplemented functions are implemented, the sample program ought to read in the JSON file `data/hills.json` and list out all the records in that file that have a country field of `"S"`. The output should look like: ``` $ cabal run json-query -- data/hills.json {"Name": "Ben Chonzie", "Country": "S", "Height": 931} {"Name": "Creagan na Beinne", "Country": "S", "Height": 888} {"Name": "Creag Uchdag", "Country": "S", "Height": 879} {"Name": "Auchnafree Hill", "Country": "S", "Height": 789} {"Name": "Shee of Ardtalnaig [Ciste Buide a' Claidheimh]", "Country": "S", "Height": 759} {"Name": "Beinn na Gainimh", "Country": "S", "Height": 729} {"Name": "Meall Buidhe", "Country": "S", "Height": 719} {"Name": "Creag Ruadh", "Country": "S", "Height": 712} {"Name": "Meall Dearg", "Country": "S", "Height": 690} {"Name": "Creag Each", "Country": "S", "Height": 673} < ... list of hills in Scotland with their heights in metres ...> ``` The query to be run is hard coded in [app/Main.hs](app/Main.hs). To change the query (e.g., to list all the hills and mountains in England), then you need to change the definition of `query` in this file. Obviously, it would be better if the query was not fixed at compile time and the user was able to enter their own query. See below for possibly extensions to the basic system. ## Project Structure - [CS316Coursework.cabal](CS316Coursework.cabal) : the description of this project for the [Cabal](https://haskell.org/cabal) build system. If you want to add any additional dependencies to the project then you will need to add them in here. - [app/](app/) - [app/Main.hs](app/Main.hs) : contains the source code for the main `json-query` executable. - [data/](data/) - [data/hills.json](data/hills.json) : the Database of British and Irish Hills (names, countries, and heights only). - [LICENSE](LICENSE) : the License for this software. Fill in your name, if you wish. - [README.md](README.md) : This file - [src/](src/) : The modules making up the main library of code for this project. - [src/JSON.hs](src/JSON.hs) : definition of the `JSON` datatype, and some accessor functions for extracting values from `JSON` values. See the documentation comments for how these functions work. - [src/JSONInput.hs](src/JSONInput.hs) : functions for parsing JSON files, based on the worked example from Week 8. You will not need to edit this for the basic project. - [src/JSONOutput.hs](src/JSONOutput.hs) : functions for outputing JSON values in JSON format. You will need to edit this file to implement the basic project. - [src/JSONTransformer.hs](src/JSONTransformer.hs) : functions for filtering and transforming JSOn values. You will need to edit this file to implement the basic project. - [src/QueryLanguage.hs](src/QueryLanguage.hs) : implementation of a JQ-style query language for filtering JSON. You will need to complete the unimplemented function in this file for the basic project. - [src/ParserCombinators.hs](src/ParserCombinators.hs) : a library for implementing parsers. You will probably not need to edit this file. See the Week 8 notes for more information on how parsers work. - [src/Result.hs](src/Result.hs) : a datatype for results that may be either successful or a failure. You will not need to edit this file. - [test/](test/) - [test/Spec.hs](test/Spec.hs) : file to write tests in. You will have to fill this in to get credit for the tests. ## Marking Scheme The project is marked out of 50. The marks start being relatively easy to get, and progress to being harder. - **10 marks** Completion of the basic missing parts in the given implementation. Specifically this is: 1. The unimplemented function in [src/JSONOutput.hs](src/JSONOutput.hs): `renderString`, `renderJSON`. 2. The unimplemented functions in [src/JSONTransformer.hs](src/JSONTransformer.hs) : `string`, `int`, `elements`, `field`, `pipe`, `equal`, `select`. 3. The unimplemented function in [src/QueryLanguage.hs](src/QueryLanguage.hs): `execute`. Each function has a documentation block above it describing the intended functionality. To get all ten marks, your code will need to be robust to user input, and reasonably well written and concise. - **5 marks** A test suite. Fill in the file `test/Spec.hs` with tests for the functions you have written, so that failing tests are reported appropriately. You can either write a list of tests by hand, or use a unit testing framework like [HUnit](https://hackage.haskell.org/package/HUnit). For more marks, explore property based testing using [QuickCheck](https://hackage.haskell.org/package/QuickCheck). You should document your test suite to say what is being tested by each test. For advice on how to use these testing frameworks, please ask on Mattermost or in the labs. - **35 marks** Additional features. You can add any additional features as we see fit to add. Here are some suggestions: - Letting the user specify the query on the command line. You will need to write a parser for queries, and work out how to read them from the command line. - Doing error checking and reporting during query execution. For example, the query defined in `Main` references a field called `Country`. If the field doesn't exist, then it returns no results. Maybe it should return an error instead? Hint: Alter the type `Transformer` in the `JSONTransformer` module to be `JSON -> Result [JSON]`, and then fix all the type errors that result. - Additional features in the query language. - The only comparison operator in the query language is an equality test. Try adding some more (e.g., `>`, `>=`, `<`, `<=`, for example). - Allow for construction of JSON values as well as just filtering. See the [`jq` documentation](https://jqlang.github.io/jq/) for how this is done in `jq`. See also the paper by Wallace and Runciman linked to in the `JSONTransformer` module, which makes a similar language for querying XML files. - Alternative output formats (Comma Separated Values, Tab Separated Values, HTML, ...). You will marked on: - Documentation and User Interface of the additional feature - The complexity of the implementation - The robustness and good coding style of the additional feature ## Submission Make sure that your final submission is pushed to your GitLab repository. Submit a small **text** file containing a link to your repository on GitLab and any additional information you want to add to describe what you have done. You should also include the following statement: *The code in my GitLab repository is entirely my own work, except where it is from the original project skeleton or has been clearly stated. No code has been copied from classmates. I understand this code will be checked with plagiarism checkers. I give permission for the source code to be inspected on CIS servers.* Standard late submission and illness rules apply. If you are ill you must certify on Pegasus and request an extension before the deadline using a MyPlace extension request. ## Credits The database of hills in [data/hills.json](data/hills.json) is a copy of the [Database of British and Irish Hills](http://www.hills-database.co.uk/downloads.html), v17.2, CSV version. The original file is very large, so I have limited it to just the names, countries, and height in metres, and converted it to JSON.