Traverse outgoing relation on StreamID field

I want to create a model (let’s call it Link) with a polymorphic reference any model, i.e. has a link: StreamID! field. With this, it’s easy to pick up these links on any target model with a @relationFrom(model: "Link", property: "link") directive.

What I’m wondering is if it’s possible to follow the outgoing relation on Link somehow?

A little code example here to illustrate what I mean:

type Link 
  @createModel(accountRelation: LIST, description: "Link to things")
{
  source: DID! @documentAccount
  targetID: StreamID!
  # not possible because no generic type exists
  target: Any! @relationDocument(property: "targetID")
  # maybe possible with union support, but needs to be changed every time a
  # new type of target needs to be linked
  target2: (Union Target = A | B | C)! @relationDocument(property: "targetID")
}

type MyType 
  @createModel(accountRelation: LIST, description: "A thing"
{
  # easy peasy
  incomingLinks: [Link] @relationFrom(model: "Link", property: "targetID")
}

Below is an example of where the query stops short. Since the targetID field in the linkIndex query is typed StreamID there is no type to traverse into (no known fields). One can re-use the resulting streamID in a second round-trip in a node(id: xyz) { ...on MyType } and match it on the expected type, or try them all and see what returns. Is there no way of combining these?

# Is there a way of connecting the lower node() query with the upper one
# to continue traversal?
query {
  linkIndex(first: 10) {
    edges {
      node {
        targetID
      }
    }
  }
  node(id: "TARGET ID GOES HERE") {
    ... on MyType {
      title
    }
    ...on OtherType {
     cid
    }
}

So,
a) Is it impossible to traverse a StreamID typed field?
b) If so, is there workaround (without having to do additional round trips) to resolve polymorphic links?

Hi,

As you wrote, unions would probably not be a great fit for this because they would be static at the time the model is created.
One project we have in the backlog is to support interfaces, which would act as sort of abstract models that can’t have documents directly associated to them, but can define fields that need to be supported by models implementing the interface, this could look something like this:

type Link @createModel(...) {
  targetID: StreamID!
  # the target here uses the Node interface that can represent any uniquely identified entity (account or document) supported by ComposeDB 
  target: Node @relationDocument(property: "targetID")
  # ... other fields
}

# All documents implicitly implement the Node interface
type MyType @createModel(...) {
  incomingLinks: [Node] @relationFrom(model: "Link", property: "targetID")
  # ... other fields
}

Then it could be queried as follows:

query {
  linkIndex(first: 10) {
    edges {
      node {
        targetID
        target {
          ...on MyType {
            # MyType fields
          }
        }
      }
    }
  }
}

Unlike unions, the advantage here is that you could add other models over time that would be implicitly supported by the Link type.

Here Node is a special interface because it’s already supported in some ways by ComposeDB, our project to support interfaces isn’t specifically made to support this use-case, but if you think that could be a solution for you I think this case could be handled as part of the larger project?

Hey Paul,

Yeah, this looks spot-on for what I need!

I’m a bit confused regarding the special-case Node interface in the example, is it already supported when creating models or are you just using it as an example? Because the schema compiler isn’t having it :slight_smile:

No it’s not supported yet, but that would probably be part of our work to support model interfaces.

2 Likes

Just a heads-up, I tried out this pull request that @paul merged recently – it works super, exactly as described above. It will allow us to simplify our architecture and save a ton of time. Here’s a screenshot showing it in action. Big thanks :pray:

5 Likes

Amazing! We are very glad it’s a significant improvement for you guys! Thank you for sharing this :blush:

1 Like