• Alex Kalderimis's avatar
    Packages to use composition, not inheritance · 671d5b51
    Alex Kalderimis authored
    GraphQL does not have inheritance, so it is an anti-pattern to use
    it to model polymorphism in our models.
    
    The correct approach is to model polymorphism as implementation of
    interfaces. Here there is a single `PackageType` interface, and
    then different implementations of that.
    
    Since the package types only differ in their metadata, we move the
    polymorphism down to the metadata fields, which an empty interface,
    implemented by metadata types.
    
    One thing that had to change was the `Query.package` field,
    which was previously `Query.package_composer_details`. This must change
    since the implementation of the lookup does not perform any type
    checking, and thus we cannot type the return value as a composer
    package. This would be an illegal and ill-typed down-cast. A good
    analogy for this is having a Java collection of
    
    ```java
    // yes, Cucumbers are fruits - look it up
    List<Fruit> bowl = List.of(new Apple(), new Banana(), new Cucumber())
    ```
    
    And then expecting to get an apple without a cast:
    
    ```java
    Apple fruit = bowl.get(0) // bad
    ```
    
    This code would fail to compile in Java, and it is equally illegal
    in GraphQL, without the appropriate casting.
    
    We mark the composer metadata type as an orphan since it is only refered
    to as an implementation of the broader metadata type.
    
    We also split the type of packages into a top-level one, which is able
    to refer to versions, and a leaf node which may not. This prevents
    unbounded mutual cyclic recursion.
    
    Return successfully for all packages
    
    We can gradually add more specific package types, but it is important
    to always succeed with the data we can return.
    671d5b51
package_spec.rb 2.48 KB