We modeled user relationships as a simple UserRelation object:
class UserRelation { User _from; User _to; RelationState _state; }
Where RelationState is an enumeration describing states (usually it is more than friendship)
enum RelationState { BLOCKED, NONE, PENDING_FRIEND, FRIEND; }
Actually, we also use this enumeration for authorization, for example. on user profiles.
enum RelationState implements IRole { BLOCKED, NONE(BLOCKED), PENDING_FRIEND(NONE), FRIEND(PENDING_FRIEND); private final List<IRole> _impliedRoles; private final List<String> _roleStrings; private RelationState(final IRole... impliedRoles) { HashSet<IRole> set = new HashSet<IRole>(); for (final IRole impliedRole : impliedRoles) { set.add(impliedRole); set.addAll(impliedRole.getImpliedRoles()); } _impliedRoles = Collections.unmodifiableList(new ArrayList<IRole>(set)); ArrayList<String> list = new ArrayList<String>(getImpliedRoles().size() + 1); list.add(getName()); for (final IRole implied : getImpliedRoles()) { list.add(implied.getName()); } _roleStrings = Collections.unmodifiableList(list); } public List<IRole> getImpliedRoles() { return _impliedRoles; } public String getName() { return name(); } public boolean hasRole(final IRole role) { return this == role || _impliedRoles.contains(role); } public List<String> getRoleStrings() { return _roleStrings; } } public interface IRole { public List<? extends IRole> getImpliedRoles(); public String getName(); public boolean hasRole(final IRole role); public List<String> getRoleStrings(); }
The easiest way is to have two objects for each (symmetric) relationship (for example, the friendship used on facebook), and only one object for asymmetric relationships (for example, followers used on twitter or blocked users). Although this may seem overhead in the first place, using two objects certainly simplifies the query.
I think that part of AppEngine itself should be pretty straight forward.
source share