diff --git a/src/Utils/Api.elm b/src/Utils/Api.elm index 3b3b6b7bd9e87fce279e8888dded79f7c6de7c4a..b8eb2e5a68ed54d1059914144d99d440b81036c7 100644 --- a/src/Utils/Api.elm +++ b/src/Utils/Api.elm @@ -1,67 +1,92 @@ module Utils.Api exposing (..) import Types exposing (..) -import Json.Encode exposing (object) -import Json.Decode as Decode exposing (..) +import Json.Encode as E exposing (..) +import Json.Decode as D exposing (..) + +encodeNullable : (value -> E.Value) -> Maybe value -> E.Value +encodeNullable valueEncoder maybeValue = + case maybeValue of + Just value -> + valueEncoder value + + Nothing -> + E.null + +encodeGraph : Graph -> E.Value +encodeGraph graph = + object + [ ("window", encodeWindow graph.window) + , ("functions", E.list encodeMathFunction graph.functions) + ] + +encodeWindow : Window -> E.Value +encodeWindow window = + object + [ ("xMin", E.int window.xMin) + , ("xMax", E.int window.xMax) + , ("yMin", E.int window.yMin) + , ("yMax", E.int window.yMax) + ] -encodeMathFunction : MathFunction -> Json.Encode.Value +encodeMathFunction : MathFunction -> E.Value encodeMathFunction mathFunction = case mathFunction of Const x -> - object [ ( "type", Json.Encode.string "Const" ), ( "value", Json.Encode.float x ) ] + object [ ( "type", E.string "Const" ), ( "value", E.float x ) ] X -> - object [ ( "type", Json.Encode.string "X" ) ] + object [ ( "type", E.string "X" ) ] Add f1 f2 -> - object [ ( "type", Json.Encode.string "Add" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] + object [ ( "type", E.string "Add" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] Sub f1 f2 -> - object [ ( "type", Json.Encode.string "Sub" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] + object [ ( "type", E.string "Sub" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] Mul f1 f2 -> - object [ ( "type", Json.Encode.string "Mul" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] + object [ ( "type", E.string "Mul" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] Div f1 f2 -> - object [ ( "type", Json.Encode.string "Div" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] + object [ ( "type", E.string "Div" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] Pow f1 f2 -> - object [ ( "type", Json.Encode.string "Pow" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] + object [ ( "type", E.string "Pow" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] Log f1 f2 -> - object [ ( "type", Json.Encode.string "Log" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] + object [ ( "type", E.string "Log" ), ( "left", encodeMathFunction f1 ), ( "right", encodeMathFunction f2 ) ] Ln f -> - object [ ( "type", Json.Encode.string "Ln" ), ( "argument", encodeMathFunction f ) ] + object [ ( "type", E.string "Ln" ), ( "argument", encodeMathFunction f ) ] Neg f -> - object [ ( "type", Json.Encode.string "Neg" ), ( "argument", encodeMathFunction f ) ] + object [ ( "type", E.string "Neg" ), ( "argument", encodeMathFunction f ) ] Sin f -> - object [ ( "type", Json.Encode.string "Sin" ), ( "argument", encodeMathFunction f ) ] + object [ ( "type", E.string "Sin" ), ( "argument", encodeMathFunction f ) ] Cos f -> - object [ ( "type", Json.Encode.string "Cos" ), ( "argument", encodeMathFunction f ) ] + object [ ( "type", E.string "Cos" ), ( "argument", encodeMathFunction f ) ] Tan f -> - object [ ( "type", Json.Encode.string "Tan" ), ( "argument", encodeMathFunction f ) ] + object [ ( "type", E.string "Tan" ), ( "argument", encodeMathFunction f ) ] Exp f -> - object [ ( "type", Json.Encode.string "Exp" ), ( "argument", encodeMathFunction f ) ] + object [ ( "type", E.string "Exp" ), ( "argument", encodeMathFunction f ) ] decodeMathFunctionInit : Decoder MathFunction decodeMathFunctionInit = - field "type" Decode.string |> andThen decodeMathFunction + field "type" D.string |> andThen decodeMathFunction decodeMathFunction : String -> Decoder MathFunction decodeMathFunction type_ = case type_ of "Const" -> - field "value" Decode.float |> map Const + field "value" D.float |> map Const "X" -> - Decode.succeed X + D.succeed X "Add" -> map2 Add (field "left" decodeMathFunctionInit) (field "right" decodeMathFunctionInit) @@ -100,65 +125,118 @@ decodeMathFunction type_ = map Exp (field "argument" decodeMathFunctionInit) _ -> - Decode.fail ("Unknown MathFunction type: " ++ type_) + D.fail ("Unknown MathFunction type: " ++ type_) decodeGraph : Decoder Graph decodeGraph = map2 Graph (field "window" decodeWindow) - (field "functions" (list decodeMathFunctionInit)) + (field "functions" (D.list decodeMathFunctionInit)) decodeWindow : Decoder Window decodeWindow = map4 Window - (field "xMin" int) - (field "yMin" int) - (field "xMax" int) - (field "yMax" int) + (field "xMin" D.int) + (field "yMin" D.int) + (field "xMax" D.int) + (field "yMax" D.int) partialMCQDecoder : Decoder PartialQuestionType partialMCQDecoder = - Decode.map2 (\choices correct -> PartialMCQ { choices = choices, correct = correct }) - (Decode.field "choices" (Decode.list Decode.string)) - (Decode.field "correct" (Decode.list Decode.string)) + D.map2 (\choices correct -> PartialMCQ { choices = choices, correct = correct }) + (D.field "choices" (D.list D.string)) + (D.field "correct" (D.list D.string)) partialSCQDecoder : Decoder PartialQuestionType partialSCQDecoder = - Decode.map2 (\choices correct -> PartialSCQ { choices = choices, correct = correct }) - (Decode.field "choices" (Decode.list Decode.string)) - (Decode.field "correct" Decode.string) + D.map2 (\choices correct -> PartialSCQ { choices = choices, correct = correct }) + (D.field "choices" (D.list D.string)) + (D.field "correct" D.string) partialInputDecoder : Decoder PartialQuestionType partialInputDecoder = - Decode.map2 (\correct sensitive -> PartialInput { correct = correct, sensitive = sensitive }) - (Decode.field "correct" (Decode.list Decode.string)) - (Decode.field "sensitive" Decode.bool) + D.map2 (\correct sensitive -> PartialInput { correct = correct, sensitive = sensitive }) + (D.field "correct" (D.list D.string)) + (D.field "sensitive" D.bool) partialQuestionTypeDecoder : Decoder PartialQuestionType partialQuestionTypeDecoder = - Decode.oneOf - [ Decode.field "MCQ" partialMCQDecoder - , Decode.field "SCQ" partialSCQDecoder - , Decode.field "Input" partialInputDecoder + D.oneOf + [ D.field "MCQ" partialMCQDecoder + , D.field "SCQ" partialSCQDecoder + , D.field "Input" partialInputDecoder ] partialQuestionDecoder : Decoder PartialQuestion partialQuestionDecoder = - Decode.map6 PartialQuestion - (Decode.field "task" Decode.string) - (Decode.field "hint" (Decode.maybe Decode.string)) - (Decode.field "explanation" (Decode.maybe Decode.string)) - (Decode.field "image" (Decode.maybe Decode.string)) - (Decode.field "graph" (Decode.maybe decodeGraph)) - (Decode.field "questionType" partialQuestionTypeDecoder) + D.map6 PartialQuestion + (D.field "task" D.string) + (D.field "hint" (D.maybe D.string)) + (D.field "explanation" (D.maybe D.string)) + (D.field "image" (D.maybe D.string)) + (D.field "graph" (D.maybe decodeGraph)) + (D.field "questionType" partialQuestionTypeDecoder) partialQuizDecoder : Decoder PartialQuiz partialQuizDecoder = - Decode.map4 PartialQuiz - (Decode.field "id" Decode.string) - (Decode.field "name" Decode.string) - (Decode.field "duration" (Decode.maybe Decode.int)) - (Decode.field "questions" (Decode.list partialQuestionDecoder)) + D.map4 PartialQuiz + (D.field "id" D.string) + (D.field "name" D.string) + (D.field "duration" (D.maybe D.int)) + (D.field "questions" (D.list partialQuestionDecoder)) + +partialQuestionTypeEncoder : PartialQuestionType -> E.Value +partialQuestionTypeEncoder questionType = + case questionType of + PartialMCQ { choices, correct } -> + object + [ ( "MCQ", + object + [ ( "choices", E.list E.string choices ) + , ( "correct", E.list E.string correct ) + ] + ) + ] + + PartialSCQ { choices, correct } -> + object + [ ( "SCQ", + object + [ ( "choices", E.list E.string choices ) + , ( "correct", E.string correct ) + ] + ) + ] + + PartialInput { correct, sensitive } -> + object + [ ( "Input", + object + [ ( "correct", E.list E.string correct ) + , ( "sensitive", E.bool sensitive ) + ] + ) + ] + +partialQuestionEncoder : PartialQuestion -> E.Value +partialQuestionEncoder question = + object + [ ( "task", E.string question.task ) + , ( "hint", encodeNullable E.string question.hint ) + , ( "explanation", encodeNullable E.string question.explanation ) + , ( "image", encodeNullable E.string question.image ) + , ( "graph", encodeNullable encodeGraph question.graph ) + , ( "questionType", partialQuestionTypeEncoder question.questionType ) + ] + +partialQuizEncoder : PartialQuiz -> E.Value +partialQuizEncoder quiz = + object + [ ( "id", E.string quiz.id ) + , ( "name", E.string quiz.name ) + , ( "duration", encodeNullable E.int quiz.duration ) + , ( "questions", E.list partialQuestionEncoder quiz.questions ) + ] transformPartialQuiz : PartialQuiz -> Quiz transformPartialQuiz partialQuiz =