The goal of the project is to build a small interpreter for a JSON-based DSL that performs some simple analytics on a data set.
We have included basic UI boilerplate in this project to help you get started quickly. This way, you can focus your attention on implementing the application logic. We expect you to spend a few hours on this project, but don't worry if you don't finish everything within that timeframe. Please let us know which areas you weren't able to complete and how you plan to finish them if given more time.
- The example expressions are correctly interpreted and give the correct result
- Syntactically invalid DSLs are handled and the user made aware (i.e. malformed JSON)
- Syntactically valid DSLs which do not adhere to the schema are handled the user made aware
- Valid DSL expressions that fail on either attribute or security look-up are handled and the user made aware
The data set comprises 3 small csv files, securities.json
,
attributes.json
and facts.json
. There are 10 securities and 10 attributes, and for each
security and each attribute, there is one fact. I.e. there is a one-to-many relationship between
securities and facts, and attributes and facts. These are located in the data
directory in the root of then project.
export interface Security {
id: number;
symbol: string;
}
export interface Attribute {
id: number;
name: string;
}
export interface Fact {
securityId: number;
attributeId: number;
value: number;
}
A query in our DSL has the basic format:
{
"security": <String>,
"expression": <Expression>
}
The security property contains a single string, which is the symbol of a security the user wishes to evaluate an expression for.
The expression field contains a single expression, which the user wishes to evaluate for the
chosen security. An expression contains an operator (the fn
property), and the arguments to
that operator has other properties. The arguments to operators can either be the name of an
attribute, a number, or another expression.
You only have to implement one operator, though it should be clear in your solution how it might be possible to extend the interpreter to include additional operators. Please choose one of the following operators to implement:
Operator | Arguments | Behaviour |
---|---|---|
+ | a, b | Adds a and b |
- | a, b | Subtracts b from a |
* | a, b | Multiplies a and b |
/ | a, b | Divides a by b |
Here are some example queries, demonstrating what each operator looks like and what the different parameters can be:
This one uses the *
operator and makes use of one attribute name and an integer as its arguments:
{
"expression": { "fn": "*", "a": "sales", "b": 2 },
"security": "ABC"
}
This one uses the /
operator and makes uses two attribute names as arguments:
{
"expression": { "fn": "/", "a": "price", "b": "eps" },
"security": "BCD"
}
This one uses the -
operator and the arguments are two expressions, which in turn use the -
operator and attribute names as arguments:
{
"expression": {
"fn": "-",
"a": { "fn": "-", "a": "eps", "b": "shares" },
"b": { "fn": "-", "a": "assets", "b": "liabilities" }
},
"security": "CDE"
}
This is a Next.js project bootstrapped with create-next-app
.
First, run the development server:
npm run dev
# or
yarn dev
Open http://localhost:3000 with your browser to see the result.
You can start editing the page by modifying pages/index.tsx
. The page auto-updates as you edit the file.