3

There is a JSON file, it has been converted to JSON-schema and the schema definition in ReasonML type. Please help to comment the following issues.

  1. Is it a good choose to use JSON schema as a table/schema definition? It seems it is a de-facto standard to define tables/schemas. If it is not the suggested method, please suggest me a method to resolve this issue.
  2. Is it possible to define type dynamically? I would save all tables/schemas definition and data into a single JSON file. When I decode the JSON file, all definition and data should be defined as type in OCaml/ReasonML simultaneously. There is an alternative that I can convert all tables/schemas into type by coding but I would make these as flexible as possible.

Thank you.

List 1 :Stocks.json

[
    {
        "code": "AAPL.US",
        "timestamp": 1584388800,
        "gmtoffset": 0,
        "open": 241.95,
        "high": 259.08,
        "low": 240,
        "close": 242.21,
        "volume": 80605865,
        "previousClose": 277.97,
        "change": -35.76,
        "change_p": -12.865
    },
    {
        "code": "ABPL.US",
        "timestamp": 1584388800,
        "gmtoffset": 0,
        "open": 241.95,
        "high": 259.08,
        "low": 240,
        "close": 242.21,
        "volume": 80605865,
        "previousClose": 277.97,
        "change": -35.76,
        "change_p": -12.865
    }
]

List 2: According to the standard of json-schema.org, JSON Schema was generated from List 1.

{
    "$schema": "http://json-schema.org/draft-07/schema",
    "$id": "http://example.com/example.json",
    "type": "array",
    "readOnly": false,
    "writeOnly": false,
    "uniqueItems": false,
    "minItems": 0,
    "minContains": 1,
    "title": "The Root Schema",
    "description": "The root schema comprises the entire JSON document.",
    "additionalItems": true,
    "items": {
        "$id": "#/items",
        "type": "object",
        "readOnly": false,
        "writeOnly": false,
        "minProperties": 0,
        "title": "The Items Schema",
        "description": "An explanation about the purpose of this instance.",
        "default": {},
        "examples": [
            {
                "code": "AAPL.US",
                "previousClose": 277.97,
                "timestamp": 1584388800.0,
                "change": -35.76,
                "close": 242.21,
                "open": 241.95,
                "gmtoffset": 0.0,
                "volume": 80605865.0,
                "low": 240.0,
                "high": 259.08,
                "change_p": -12.865
            },
            {
                "volume": 80605865.0,
                "low": 240.0,
                "high": 259.08,
                "change_p": -12.865,
                "previousClose": 277.97,
                "code": "ABPL.US",
                "timestamp": 1584388800.0,
                "open": 241.95,
                "close": 242.21,
                "change": -35.76,
                "gmtoffset": 0.0
            }
        ],
        "additionalProperties": true,
        "required": [
            "code",
            "timestamp",
            "gmtoffset",
            "open",
            "high",
            "low",
            "close",
            "volume",
            "previousClose",
            "change",
            "change_p"
        ],
        "properties": {
            "code": {
                "$id": "#/items/properties/code",
                "type": "string",
                "readOnly": false,
                "writeOnly": false,
                "minLength": 0,
                "title": "The Code Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": "",
                "examples": [
                    "AAPL.US"
                ]
            },
            "timestamp": {
                "$id": "#/items/properties/timestamp",
                "type": "integer",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Timestamp Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    1584388800
                ]
            },
            "gmtoffset": {
                "$id": "#/items/properties/gmtoffset",
                "type": "integer",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Gmtoffset Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    0
                ]
            },
            "open": {
                "$id": "#/items/properties/open",
                "type": "number",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Open Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    241.95
                ]
            },
            "high": {
                "$id": "#/items/properties/high",
                "type": "number",
                "readOnly": false,
                "writeOnly": false,
                "title": "The High Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    259.08
                ]
            },
            "low": {
                "$id": "#/items/properties/low",
                "type": "integer",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Low Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    240
                ]
            },
            "close": {
                "$id": "#/items/properties/close",
                "type": "number",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Close Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    242.21
                ]
            },
            "volume": {
                "$id": "#/items/properties/volume",
                "type": "integer",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Volume Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    80605865
                ]
            },
            "previousClose": {
                "$id": "#/items/properties/previousClose",
                "type": "number",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Previousclose Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    277.97
                ]
            },
            "change": {
                "$id": "#/items/properties/change",
                "type": "number",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Change Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    -35.76
                ]
            },
            "change_p": {
                "$id": "#/items/properties/change_p",
                "type": "number",
                "readOnly": false,
                "writeOnly": false,
                "title": "The Change_p Schema",
                "description": "An explanation about the purpose of this instance.",
                "default": 0,
                "examples": [
                    -12.865
                ]
            }
        }
    }
}

List 3: Corresponding ReasonML Type.

 type position = {
    symbol: string,
    holding: int,
    pprice: float,
  };

  type account = {
    name: string,
    max_ind_holding: float,
    pos: list(position),
  };
madeinQuant
  • 1,721
  • 1
  • 18
  • 29
  • "When I decode the JSON file, all definition and data should be defined as type in OCaml/ReasonML simultaneously" - could you add an example of the JSON schema and corresponding types definitions you'd like to get out of the box, please? – Konstantin Strukov Mar 17 '20 at 11:19
  • @KonstantinStrukov, thanks for you comment. The List1 - List3 are examples for you reference. List 2 is generated by List 1, and List 3 is the corresponding type-definitions. Please feel free to comment. – madeinQuant Mar 18 '20 at 03:04
  • @KonstantinStrukov, I found that GraphQL is more popular. There is a online page which provide service to convert JSON into GraphQL schema. "https://matheusr42.github.io/json-to-graphql-schema-online/" – madeinQuant Mar 18 '20 at 04:26

1 Answers1

2

I also tried a similar thing and didn't find a tl;dr-Solution. So, i cannot provide you one.

Anyways, i can recommend 2 half-solutions, maybe adding up to a whole one:

1. graphql-codegen As you mentioned GraphQL, using schema-ast-plugin together with reason-plugin you can go from your JSON-schema to ReasonML Types. (see Note at the end)

2. quicktype which can generate types for a lot of languages. Unfortunately, ReasonML is still missing. But you can find progress and instructions on how to add a new language here: Language request: OCaml / Reason

3. Combine 1&2 for JSON as your starting point

You could try to go from JSON to typescript(or any other language supported by graphql-codegen) and than typescript (or language x) to GraphQL using graphql-codegen-typescript and finally from typescript to ReasonML :)

I know, none of this is convenient and involves reading/testing a lot, but i hope you find it helpful and at least come closer to your goal.

Note: If you are compiling to JS using bucklescript 7: graphql-codegen-reason was not updated a while. So it doesn't take advantage of bucklescript 7's new feature to compile records directly into JS-Objects. Instead it uses Js.t, which i find unnecessary and annoying, as you could have more clean types. I tried to change it, but I'm still too inexperienced in ReasonML, so it does only work for specific cases and is full of bugs. Therefore, not published anywhere. If your interested nevertheless, i can push it (no guarantees as you can guess :) ). Just let me know.

farukg
  • 523
  • 4
  • 12
  • Thanks for your help. I found that closure is more natural than SQL to query data, so I want to implement a simple database in term of closure (ReasonML/OCaml) perspective. As I know, MongoDB JSON format is able to exported data into Oracle NoSQL, it may not be exactly the same but some basic principles are similar(import/export schema into JSON, parsing JSON and creating schema etc). I am not an experienced functional programmer, there are still a lot of things I don't know. Please feel to comment and to suggest me. Thank you. – madeinQuant Mar 19 '20 at 05:07
  • @farkg There is a link for your reference "https://www.strv.com/blog/guide-native-reasonml" – madeinQuant Jun 30 '20 at 14:04