Skip to content

gen-graphql: is_a is not mapped to an interface, so slot_usage narrowing breaks covariance and abstract classes become interfaces nothing implements #66

Open

Description

@jdsika

GraphqlGenerator derives implements from mixins alone. is_a is not mapped to a GraphQL interface at all. Three consequences follow, all visible in the biolink reference snapshot after #63:

1. Interface field covariance — about a hundred validation errors. A class narrowing an inherited slot with slot_usage emits the narrowed type, while the interface it implements keeps the wide one:

Interface field Association.subject expects type NamedThing! but BehaviorToBehavioralFeatureAssociation.subject is type Behavior!

GraphQL does allow a covariant field type, but only when the narrowed type is a subtype in GraphQL's own terms, which requires the is_a hierarchy to be expressed as interfaces. It is not, so the narrowed type is unrelated and the check fails.

2. Interfaces that nothing implements. An abstract class that is never mixed into another becomes an interface with no implementing object type — 20 of the 62 interfaces in the biolink output. Two of them are used as field ranges, so those fields can never resolve at execution time:

OrganismalEntityAsAModelOfDiseaseAssociation.subject: OrganismalEntity!   # OrganismalEntity is an interface nothing implements
ContributorAssociation.subject: InformationContentEntity!

3. A mixins: target that is not declared abstract or mixin stays an object type. The class mixing it in then declares implements against a non-interface:

classes:
  Concrete:
    attributes: {a: {range: string}}
  User:
    mixins: [Concrete]
    attributes: {b: {range: string}}
Type User must only implement Interface types, it cannot implement Concrete.

This reaches LinkML's own meta.yaml:

Type AnonymousEnumExpression must only implement Interface types, it cannot implement EnumExpression.
Type EnumDefinition must only implement Interface types, it cannot implement EnumExpression.

Before #63 the same schemas failed earlier, with a syntax error, so this is newly visible rather than new.

All three share one root: how a LinkML class hierarchy should map onto GraphQL interfaces. Mapping is_a to implements would fix 1 and 2 and would be the natural place to decide 3 (promote any mixins: target to an interface, or drop the implements clause for a concrete one). It needs a modelling decision, which is why #63 documents it rather than fixing it.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions