anchor.diff:          od_group => EffGroups, od_space => EffSpaces,
           od_share => EffShares, od_provider => EffProviders,
           od_handle_service => EffHServices, od_handle => EffHandles
  -    }.
  -
  -
  -update_eff_relations(#od_user{} = User, AggregatedParentRelations) ->
  +    };
  +eff_relations(top_down, #od_group{} = Group) ->
  +    #od_group{
  +        eff_parents = EffGroups, eff_spaces = EffSpaces,
  +        eff_shares = EffShares, eff_providers = EffProviders,
  +        eff_handle_services = EffHServices, eff_handles = EffHandles
  +    } = Group,
       #{
           od_group => EffGroups, od_space => EffSpaces,
           od_share => EffShares, od_provider => EffProviders,
           od_handle_service => EffHServices, od_handle => EffHandles
  -    } = AggregatedParentRelations,
  +    };
  +eff_relations(top_down, #od_space{}) ->
  +    #{}.
  +
  +
  +update_eff_relations(bottom_up, #od_group{} = Group, EffNeighbours) ->
  +    #{od_user := EffUsers, od_group := EffGroups} = EffNeighbours,
  +    Group#od_group{eff_users = EffUsers, eff_children = EffGroups};
  +update_eff_relations(bottom_up, #od_space{} = Space, EffNeighbours) ->
  +    #{od_user := EffUsers, od_group := EffGroups} = EffNeighbours,
  +    Space#od_space{eff_users = EffUsers, eff_groups = EffGroups};
  +update_eff_relations(bottom_up, #od_share{} = Share, EffNeighbours) ->
  +    #{od_user := EffUsers, od_group := EffGroups} = EffNeighbours,
  +    Share#od_share{eff_users = EffUsers, eff_groups = EffGroups};
  +update_eff_relations(bottom_up, #od_provider{} = Provider, EffNeighbours) ->
  +    #{od_user := EffUsers, od_group := EffGroups} = EffNeighbours,
  +    Provider#od_provider{eff_users = EffUsers, eff_groups = EffGroups};
  +update_eff_relations(bottom_up, #od_handle_service{} = HService, EffNeighbours) ->
  +    #{od_user := EffUsers, od_group := EffGroups} = EffNeighbours,
  +    HService#od_handle_service{eff_users = EffUsers, eff_groups = EffGroups};
  +update_eff_relations(bottom_up, #od_handle{} = Handle, EffNeighbours) ->
  +    #{od_user := EffUsers, od_group := EffGroups} = EffNeighbours,
  +    Handle#od_handle{eff_users = EffUsers, eff_groups = EffGroups};
  +
  +update_eff_relations(top_down, #od_user{} = User, EffNeighbours) ->
  +    #{
  +        od_group := EffGroups, od_space := EffSpaces,
  +        od_share := EffShares, od_provider := EffProviders,
  +        od_handle_service := EffHServices, od_handle := EffHandles
  +    } = EffNeighbours,
       User#od_user{
           eff_groups = EffGroups, eff_spaces = EffSpaces,
           eff_shares = EffShares, eff_providers = EffProviders,
           eff_handle_services = EffHServices, eff_handles = EffHandles
  -    }.
  -
  -
  -extract_children(#od_space{users = Users, groups = Groups}) ->
  -    #{users => Users, groups => Groups}.
  -
  -
  +    };
  +update_eff_relations(top_down, #od_group{} = Group, EffNeighbours) ->
  +    #{
  +        od_group := EffGroups, od_space := EffSpaces,
  +        od_share := EffShares, od_provider := EffProviders,
  +        od_handle_service := EffHServices, od_handle := EffHandles
  +    } = EffNeighbours,
  +    Group#od_group{
  +        eff_parents = EffGroups, eff_spaces = EffSpaces,
  +        eff_shares = EffShares, eff_providers = EffProviders,
  +        eff_handle_services = EffHServices, eff_handles = EffHandles
  +    };
  +update_eff_relations(top_down, #od_space{} = Space, _) ->
  +    Space.
  +
  +
  +%%refresh_entity_top_down(ModelType, EntityId) ->
  +%%    {ok, #document{value = Entity}} = ModelType:get(EntityId),
  +%%    ParentRelations = extract_parents(Entity),
  +%%    ToAggregate = parents_to_aggregate_from(ModelType),
  +%%    EffRelations = lists:flatmap(
  +%%        fun(ParentType) ->
  +%%            Parents = maps:get(ParentType, ParentRelations),
  +%%            lists:map(
  +%%                fun(ParentId) ->
  +%%                    aggregate_from_parent(ModelType, ParentType, ParentId)
  +%%                end, Parents)
  +%%        end, ToAggregate),
  +%%    AggregatedParentRelations = lists:foldl(
  +%%        fun(RelationsMap, AccMapOuter) ->
  +%%            lists:foldl(
  +%%                fun({ModelType, Entities}, AccMapInner) ->
  +%%                    NewEntities = ordsets:union(
  +%%                        ordsets:from_list(Entities),
  +%%                        maps:get(ModelType, RelationsMap, [])
  +%%                    ),
  +%%                    AccMapInner#{ModelType => NewEntities}
  +%%                end, AccMapOuter, maps:to_list(RelationsMap))
  +%%        end, #{}, [ParentRelations | EffRelations]),
  +%%    % Check if parents should be marked dirty
  +%%    case AggregatedParentRelations =:= eff_relations(Entity) of
  +%%        true ->
  +%%            % Nothing changed, no action is needed
  +%%            ok;
  +%%        false ->
  +%%            % Mark all children as dirty
  +%%            ChildrenRelations = extract_children(Entity),
  +%%            lists:foreach(
  +%%                fun({ModelType, Entities}) ->
  +%%                    lists:foreach(
  +%%                        fun(EntityId) ->
  +%%                            ModelType:update(EntityId, fun(E) ->
  +%%                                {ok, mark_dirty(top_down, true, ModelType, EntityId, E)}
  +%%                            end)
  +%%                        end, Entities)
  +%%                end, maps:to_list(ChildrenRelations))
  +%%    end,
  +%%    % Update the record marking it not dirty and setting newly calculated
  +%%    % effective relations.
  +%%    {ok, _} = ModelType:update(EntityId, fun(Ent) ->
  +%%        {ok, mark_dirty(top_down, false, ModelType, EntityId, update_eff_relations(
  +%%            Ent, AggregatedParentRelations
  +%%        ))}
  +%%    end),
  +%%    ok.
  +
  +%%% TODO should return lists without privs
  +%%extract_parents(#od_user{} = User) ->
  +%%    #od_user{
  +%%        groups = Groups, spaces = Spaces,
  +%%        handle_services = HServices, handles = Handles
  +%%    } = User,
  +%%    #{
  +%%        od_group => Groups, od_space => Spaces,
  +%%        od_handle_service => HServices, od_handle => Handles
  +%%    }.
  +%%
  +%%
  +%%parents_to_aggregate_from(od_user) ->
  +%%    [od_space, od_group].
  +%%
  +%%aggregate_from_parent(od_user, od_space, SpaceId) ->
  +%%    {ok, #document{value = #od_space{
  +%%        providers_supports = Providers,
  +%%        shares = Shares
  +%%    }}} = od_space:get(SpaceId),
  +%%    #{od_provider => element(1, Providers), od_share => Shares};
  +%%aggregate_from_parent(od_user, od_group, GroupId) ->
  +%%    {ok, #document{value = #od_group{
  +%%        eff_parents = EffGroups,
  +%%        eff_spaces = EffSpaces,
  +%%        eff_shares = EffShares,
  +%%        eff_providers = EffProviders,
  +%%        eff_handle_services = EffHServices,
  +%%        eff_handles = EffHandles
  +%%    }}} = od_group:get(GroupId),
  +%%    #{
  +%%        od_group => EffGroups, od_space => EffSpaces,
  +%%        od_share => EffShares, od_provider => EffProviders,
  +%%        od_handle_service => EffHServices, od_handle => EffHandles
  +%%    }.
  +%%
  +%%
  +%%eff_relations(#od_user{} = User) ->
  +%%    #od_user{
  +%%        eff_groups = EffGroups, eff_spaces = EffSpaces,
  +%%        eff_shares = EffShares, eff_providers = EffProviders,
  +%%        eff_handle_services = EffHServices, eff_handles = EffHandles
  +%%    } = User,
  +%%    #{
  +%%        od_group => EffGroups, od_space => EffSpaces,
  +%%        od_share => EffShares, od_provider => EffProviders,
  +%%        od_handle_service => EffHServices, od_handle => EffHandles
  +%%    }.
  +%%
  +%%
  +%%update_eff_relations(#od_user{} = User, AggregatedParentRelations) ->
  +%%    #{
  +%%        od_group => EffGroups, od_space => EffSpaces,
  +%%        od_share => EffShares, od_provider => EffProviders,
  +%%        od_handle_service => EffHServices, od_handle => EffHandles
  +%%    } = AggregatedParentRelations,
  +%%    User#od_user{
  +%%        eff_groups = EffGroups, eff_spaces = EffSpaces,
  +%%        eff_shares = EffShares, eff_providers = EffProviders,
  +%%        eff_handle_services = EffHServices, eff_handles = EffHandles
  +%%    }.
  +%%
  +%%
  +%%extract_children(#od_space{users = Users, groups = Groups}) ->
  +%%    #{users => Users, groups => Groups}.
   
   
   %%refresh_entity_bottom_up(od_group, GroupId) ->
  
positive.code:     Space#od_space{providers_supports = lists:keydelete(ProviderId, 1, Providers)}.
  
  
  refresh_entity(WhichWay, ModelType, EntityId) ->
      OtherWay = case WhichWay of
          top_down -> bottom_up;
          bottom_up -> top_down
      end,
      {ok, #document{value = Entity}} = ModelType:get(EntityId),
      Neighbours = extract_neighbours(WhichWay, Entity),
  
  
  
  refresh_entity_top_down(ModelType, EntityId) ->
      {ok, #document{value = Entity}} = ModelType:get(EntityId),
      ParentRelations = extract_parents(Entity),
      ToAggregate = parents_to_aggregate_from(ModelType),
      EffRelations = lists:flatmap(
          fun(ParentType) ->
              Parents = maps:get(ParentType, ParentRelations),
              lists:map(
                  fun(ParentId) ->
                      aggregate_from_parent(ModelType, ParentType, ParentId)
                  end, Parents)
          end, ToAggregate),
      AggregatedParentRelations = lists:foldl(
          fun(RelationsMap, AccMapOuter) ->
              lists:foldl(
                  fun({ModelType, Entities}, AccMapInner) ->
                      NewEntities = ordsets:union(
                          ordsets:from_list(Entities),
                          maps:get(ModelType, RelationsMap, [])
                      ),
                      AccMapInner#{ModelType => NewEntities}
                  end, AccMapOuter, maps:to_list(RelationsMap))
          end, #{}, [ParentRelations | EffRelations]),
      % Check if parents should be marked dirty
      case AggregatedParentRelations =:= eff_relations(Entity) of
          true ->
              % Nothing changed, no action is needed
              ok;
          false ->
              % Mark all children as dirty
              ChildrenRelations = extract_children(Entity),
              lists:foreach(
                  fun({ModelType, Entities}) ->
                      lists:foreach(
                          fun(EntityId) ->
                              ModelType:update(EntityId, fun(E) ->
                                  {ok, mark_dirty(top_down, true, ModelType, EntityId, E)}
                              end)
                          end, Entities)
                  end, maps:to_list(ChildrenRelations))
      end,
      % Update the record marking it not dirty and setting newly calculated
      % effective relations.
      {ok, _} = ModelType:update(EntityId, fun(Ent) ->
          {ok, mark_dirty(top_down, false, ModelType, EntityId, update_eff_relations(
              Ent, AggregatedParentRelations
          ))}
      end),
      ok.
  
  % TODO should return lists without privs
  extract_parents(#od_user{} = User) ->
      #od_user{
          groups = Groups, spaces = Spaces,
          handle_services = HServices, handles = Handles
      } = User,
      #{
          od_group => Groups, od_space => Spaces,
          od_handle_service => HServices, od_handle => Handles
      }.
  
  extract_neighbours(top_down, #od_user{} = User) ->
      #od_user{
          groups = Groups, spaces = Spaces,
  
negative.code:             NewState = case {WhichWay, Flag} of
                  {bottom_up, true} ->
                      ?emergency("bottom-up dirty: ~p#~s", [Model, Id]),
                      EffGraphState#entity_graph_state{
                          bottom_up_dirty = lists:sort([{Priority, Model, Id} | BottomUpDirty])
                      };
                  {bottom_up, false} ->
                      ?emergency("bottom-up clean: ~s", [Id]),
                      EffGraphState#entity_graph_state{
                          bottom_up_dirty = lists:keydelete(Id, 3, BottomUpDirty)
                      };
                  {top_down, true} ->
                      ?emergency("top-down dirty: ~p#~s", [Model, Id]),
                      EffGraphState#entity_graph_state{
                          top_down_dirty = lists:sort([{Priority, Model, Id} | TopDownDirty])
                      };
                  {top_down, false} ->
                      ?emergency("top-down clean: ~s", [Id]),
                      EffGraphState#entity_graph_state{
                          top_down_dirty = lists:keydelete(Id, 3, TopDownDirty)
                      }
              end,
              {ok, NewState#entity_graph_state{dirty = true}}
          end),
      set_dirty_flag(WhichWay, Flag, Entity).
  
  