Skip to content

Instantly share code, notes, and snippets.

@kgoggin
Last active January 25, 2019 20:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kgoggin/079bcbbee9d5540c4aa840b4b18b208c to your computer and use it in GitHub Desktop.
Save kgoggin/079bcbbee9d5540c4aa840b4b18b208c to your computer and use it in GitHub Desktop.
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