Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SET account relation #6

Open
jpham2023 opened this issue Jul 12, 2023 · 0 comments
Open

SET account relation #6

jpham2023 opened this issue Jul 12, 2023 · 0 comments

Comments

@jpham2023
Copy link

jpham2023 commented Jul 12, 2023

Summary: Model data that should only be able to happen once per user for a given target document or account (e.g. follow a user, like a post, etc).

Details:

SET account relation complements the SINGLE and LIST account relations by creating a new type of relation that must be unique per combination of account + field of document.

Use Cases

This allows to model relations such as friend requests, following, likes, etc. that are not unique per account + model combination as for the SINGLE relation, but unique per account + model + document field.

For example a friend request or following model would have a target did: DID! representing the unique value, or postID: StreamID! to represent a like.

This new type of account relation will allow to model social relations such as following and friend requests to target DIDs, as well as individual interactions with documents such as toggling favorites, votes and similar patterns.

SET account relation is needed for associating data to a user who is not the document owner.

GraphQL schema definition

Account to account

type Follow @createModel(accountRelation: SET, accountRelationField: "following") {
  follower: DID! @documentAccount # The controller of the document is the follower
  following: DID!
}

# Automatically generated object to represent the account relations
type CeramicAccount {
  # "inverse" account relations must be explicitly defined
  followers: [Follow] @accountRelationTo(field: "following")

}

Account to document

# Add PostMeta model

type Post @loadModel(id: "...") {}

type PostMeta @createModel(accountRelation: SET, accountRelationField: "postID") {
  postID: StreamID! @documentReference(model: "Post")
  coverImage: URI!
}

# Add view to existing model

type Post @loadModel(id: "...") {
  # This is a 0-1 relation with the account DID provided at runtime
  meta: PostMeta @accountRelationFrom(field: "postID")
}

Model definition

type ModelAccountRelation =
  // Existing types
  | { type: 'single' }
  | { type: 'list' }
  // Added type
  | { type: 'set', field: string }

type ModelDefinition = {
  // ... existing fields
  // changed field:
  accountRelation: ModelAccountRelation
}

Stream handling logic

  • When creating the document stream, the value of all the field defined in the set relation is set as the unique value of the stream metadata
  • When the stream gets updated, the field defined as the account relation should be treated as immutable and an error should be thrown if the client attempts any mutation of its value
  • New mutations and associated indexing logic would be needed to “remove”/unset the relation.

Generated GraphQL schema

type Follow {
  follower: CeramicAccount!
  following: CeramicAccount!
}

type FollowEdge {
  cursor: String!
  node: Follow
}

type FollowConnection {
  edges: [FollowEdge]
  pageInfo: ...
}

type Post {
  text: String!
  meta: PostMeta
}

type PostMeta {
  postID: StreamID!
  coverImage: URI!
}

type CeramicAccount {
  # Automatically generated based on the account relation
  followSet: FollowConnection!
  # Explicitly added to the composite
  followers: FollowConnection!
  follows: Follow
}

Example queries

query NewFollowers($did: DID!) {
  node(id: $did) {
    ...on CeramicAccount {
      followers(last: 10) {
        edges {
          node {
            id # Follower DID
            # Query if the follower also follows a known DID
            followsBob: follows(account: "did:pkh:...") {
              id
            }
            # "viewer" is replaced by the viewer DID in the client
            followsMe: follows(account: "viewer") {
              id
            }
          }
        }
      }
    }
  }
}

query PostWithMeta($postID: ID!) {
  node(id: $postID) {
    ...on Post {
      text
      # "documentAccount" is replaced by the document controller DID in the client
      meta(account: "documentAccount") {
        coverImage
      }
    }
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

No branches or pull requests

1 participant