Skip to content

Instantly share code, notes, and snippets.

@owanturist
Created July 7, 2016 13:30
Show Gist options
  • Save owanturist/670f6580b5e400ba7f18298b92c76f8e to your computer and use it in GitHub Desktop.
Save owanturist/670f6580b5e400ba7f18298b92c76f8e to your computer and use it in GitHub Desktop.
Simple elm-app with normalized store
module Main exposing (main)
import Html.App
import Html exposing (Html, div, ul, li, form, input, button, strong, text)
import Html.Events exposing (onSubmit, onInput)
import Html.Attributes exposing (type', value)
import Dict exposing (Dict)
-- MODEL
type alias Todo =
{ id : Int
, title : String
}
type alias Model =
{ ids : Int
, nextTodo : String
, data : Dict String (Dict Int Todo)
, list : List Int
}
-- UPDATE
type Msg
= CreateTodo
| ChangeNextTodo String
update : Msg -> Model -> Model
update msg ({ ids, nextTodo, data, list } as model) =
case msg of
CreateTodo ->
let
newTodo =
Todo ids nextTodo
foo maybeTodos =
Just
<| case maybeTodos of
Just todos ->
Dict.insert ids newTodo todos
Nothing ->
Dict.fromList [ ( ids, newTodo ) ]
newData =
Dict.update "todos" foo data
in
{ model
| ids = ids + 1
, nextTodo = ""
, data = newData
, list = list ++ [ ids ]
}
ChangeNextTodo newNextTodo ->
{ model | nextTodo = newNextTodo }
-- VIEW
buildTodosList : Model -> List Todo
buildTodosList { data, list } =
let
todosStore =
Maybe.withDefault Dict.empty (Dict.get "todos" data)
in
List.foldl
(\todoId acc ->
case (Dict.get todoId todosStore) of
Just todo ->
acc ++ [ todo ]
Nothing ->
acc
)
[]
list
view : Model -> Html Msg
view model =
div []
[ form
[ onSubmit CreateTodo
]
[ input
[ type' "text"
, value model.nextTodo
, onInput ChangeNextTodo
]
[]
, button [ type' "submit" ] [ text "Add Todo" ]
]
, ul [] (List.map viewTodo (buildTodosList model))
]
viewTodo : Todo -> Html Msg
viewTodo { id, title } =
li []
[ strong [] [ text (toString id) ]
, text (" " ++ title)
]
-- MAIN
main : Program Never
main =
Html.App.beginnerProgram
{ model = Model 0 "" Dict.empty []
, view = view
, update = update
}
@owanturist
Copy link
Author

В общем, хочется, чтобы данные в сторе хранились в нормальной форме:

Есть ветвь в сторе, отвечающая за данные, судя по всему это Dict String (Dict Int a), где строка - имя множества сущностей. На реальном проекте сущности это - пользователи, статьи, комментарии и т.д., в гисте - тудушки Dict Int Todo и пока не знаю как туда же запихать списки туду (сейчас он один), хранящий лишь последовательность id Todo.

В дальнейшем, там где это необходимо, происходит денормализация данных, и они попадают во вьюху.

Затык происходит на строке - я не знаю как в типах описать тот факт, что у меня словари второго уровня, хранящие множества сущностей, могут содержать различные типы данных. Схематично, вот что бы я хотел увидеть

type alias Todo =
    { id: Int
    , title: String
    }

type alias TodoList =
    { id: Int
    , todos: List Todo
    }

type alias Data =
    Dict String (Dict Int {- что тут надо написать чтобы было как хочется? -})

{-
    {
        todos: Dict Int Todo,
        lists: Dict Int TodoLists
    }
-}

@owanturist
Copy link
Author

owanturist commented Jul 8, 2016

короч, не получится сделать так, как хотелось бы

type alias Todo =
    { id : Int
    , title : String
    }


type alias TodoList =
    { id : Int
    , todos : List Int
    }

data =
    Dict.fromList
        [ ( "todos"
          , Dict.fromList
                [ ( 1, Todo 1 "foo" )
                , ( 2, Todo 2 "bar" )
                , ( 3, Todo 3 "bar" )
                , ( 4, Todo 4 "bar" )
                ]
          )
        , ( "todoLists"
          , Dict.fromList
                [ ( 1, TodoList 1 [ 1, 2, 3 ] )
                , ( 2, TodoList 2 [ 3, 4 ] )
                ]
          )
        ]

Не смотря на то, что data - словарь словарей, типы хранимые во вложенных словарях должны быть одинаковыми. Очень грустно

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment