Last active
January 25, 2019 20:39
-
-
Save kgoggin/079bcbbee9d5540c4aa840b4b18b208c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let verifyGraphQLType = (~typeName, json) => | |
switch (json->Js.Json.decodeObject) { | |
| None => | |
Js.log({j|Unable to decode $typeName object|j}); | |
raise(Not_found); | |
| Some(root) => | |
switch (root->Js.Dict.get("__typeName")) { | |
| None => | |
Js.log("Provided object is not a GraphQL object"); | |
raise(Not_found); | |
| Some(name) => | |
switch (name->Js.Json.decodeString) { | |
| Some(name) when name == typeName => root | |
| _ => | |
Js.log({j|Provided object is not $typeName type|j}); | |
raise(Not_found); | |
} | |
} | |
}; | |
external toJSON: 'base => Js.Json.t = "%identity"; | |
external fromJSON: Js.Json.t => 'base = "%identity"; | |
type graphQLDecoder('root, 'scalar) = | |
(~typeName: string, ~fieldName: string, 'root) => 'scalar; | |
let getField = (~fieldName, ~typeName, data) => | |
switch (data->toJSON->verifyGraphQLType(~typeName)->Js.Dict.get(fieldName)) { | |
| None => | |
Js.log( | |
{j|Field $fieldName was not present on provided $typeName object. Did you forget to fetch it?|j}, | |
); | |
raise(Not_found); | |
| Some(result) => result->fromJSON | |
}; | |
let getArray: graphQLDecoder('root, array('a)) = | |
(~typeName, ~fieldName, data) => { | |
let arr = getField(~fieldName, ~typeName, data); | |
arr->Belt.Array.map(fromJSON); | |
}; | |
let makeDecoder = | |
(~typeName, ~fieldName, ~decoder: Js.Json.t => 'scalar, json) => | |
switch (getField(~fieldName, ~typeName, json)->decoder) { | |
| None => | |
Js.log( | |
{j|Unable to decode field $fieldName on $typeName object as a String.|j}, | |
); | |
raise(Not_found); | |
| Some(value) => value | |
}; | |
let getString: graphQLDecoder('root, string) = | |
makeDecoder(~decoder=Js.Json.decodeString); | |
let getFloat: graphQLDecoder('root, float) = | |
makeDecoder(~decoder=Js.Json.decodeNumber); | |
let getEnum = (~typeName, ~fieldName, ~decoder, json) => { | |
let str = getString(~typeName, ~fieldName, json); | |
switch (str->decoder) { | |
| None => | |
Js.log( | |
{j|Unknown enum value $str was provided for field $fieldName on $typeName|j}, | |
); | |
raise(Not_found); | |
| Some(value) => value | |
}; | |
}; | |
type query = Js.Json.t; | |
type organizationTransactionsConnection; | |
type organizationTransactionEdge; | |
type financialTransaction; | |
type field('root, 'base) = 'root => 'base; | |
module Query = { | |
type t = query; | |
let typeName = "Query"; | |
let organization: field(t, organizationTransactionsConnection) = | |
getField(~fieldName="organization", ~typeName); | |
}; | |
module OrganizationTransactionsConnection = { | |
type t = organizationTransactionsConnection; | |
let typeName = "OrganizationTransactionsConnection"; | |
let edges: field(t, array(organizationTransactionEdge)) = | |
getArray(~fieldName="edges", ~typeName); | |
}; | |
module OrganizationTransactionEdge = { | |
type t = organizationTransactionEdge; | |
let typeName = "OrganizationTransactionEdge"; | |
let cursor: field(t, string) = getString(~fieldName="cursor", ~typeName); | |
let node: field(t, financialTransaction) = | |
getField(~fieldName="node", ~typeName); | |
}; | |
[@bs.deriving jsConverter] | |
type transactionStatus = [ | `PENDING | `SETTLED]; | |
module FinancialTransaction = { | |
type t = financialTransaction; | |
let typeName = "FinancialTransaction"; | |
let id: field(t, string) = getString(~fieldName="id", ~typeName); | |
let amount: field(t, float) = getFloat(~fieldName="amount", ~typeName); | |
let status: field(t, transactionStatus) = | |
getEnum(~fieldName="status", ~typeName, ~decoder=transactionStatusFromJs); | |
}; | |
let data = {|{ | |
"__typeName": "Query", | |
"organization": { | |
"__typeName": "OrganizationTransactionsConnection", | |
"edges": [ | |
{"__typeName": "OrganizationTransactionEdge", "node": { | |
"__typeName": "FinancialTransaction", | |
"amount": 12.34, | |
"id": "123abc", | |
"status": "PENDING" | |
}} | |
] | |
} | |
}|}; | |
let amounts = | |
(data |> Json.parseOrRaise) | |
->Query.organization | |
->OrganizationTransactionsConnection.edges | |
->Belt.Array.map(edge => | |
edge->OrganizationTransactionEdge.node->FinancialTransaction.amount | |
); | |
Js.log(amounts); | |
/* This throws a bsb error because we're trying to pass | |
an edge where we should be passing a connection */ | |
let organization = | |
(data |> Json.parseOrRaise) | |
->Query.organization | |
->OrganizationTransactionEdge.node; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment