trompamusic/ce-api

schema: how to model a field which can be a URL or an object

Closed this issue · 4 comments

In the Annotation schema, we have some fields (e.g. target) which are defined as a URL.
However, sometimes these urls refer to items which exist in the CE database. In this case, I think it makes sense that we represent this as a relation in the neo4j database.

In this case, we may have a MediaObject with the following fields:

  • id
  • url (repository that this file is on)
  • contentUrl (link to the raw MEI file)

we may want our target to refer to "measure 3 within the raw mei file represented by this node". In this case I'm thinking of modelling it like this:

interface AnnotationTargetInterface {
    "http://purl.org/dc/elements/1.1/identifier,https://schema.org/identifier"
    identifier: ID
}

type AnnotationURLTarget implements AnnotationTargetInterface {
    "http://purl.org/dc/elements/1.1/identifier,https://schema.org/identifier"
    identifier: ID
    url: URL!
}

type AnnotationCETarget implements AnnotationTargetInterface {
    "http://purl.org/dc/elements/1.1/identifier,https://schema.org/identifier"
    identifier: ID
    "the node in the database"
    target: Thing!
    "the field in the above target which contains the actual url"
    field: String!
    "an optional fragment to select an item in the target url, e.g. '#measure-3'"
    fragment: String
}

type Annotation {
    ...
    target: [AnnotationTargetInterface] @relation(name: "ANNOTATION_TARGET", direction: "OUT")
    ...
}

This has one downside - if I want the target to be a URL external to TROMPA, we still have to create a node (AnnotationURLTarget) for it. It may be possible to use a Union here, but I was unable to work out how to make a union of a base type and a relation.

Do you have any other suggestions as to how we could model this?

Related to this - is the preference to have a separate file in the schema directory for each type and interface, or can we combine related types together in a single file?

The proposed schema looks good to me.

Related to this - is the preference to have a separate file in the schema directory for each type and interface, or can we combine related types together in a single file?

We currently have a separate file for each type, but this probably because most of the types have a lot of properties. I don't mind defining multiple types in a single file.

This has one downside - if I want the target to be a URL external to TROMPA, we still have to create a node (AnnotationURLTarget) for it. It may be possible to use a Union here, but I was unable to work out how to make a union of a base type and a relation.

Interfaced relations is the prefered way for relations with multiple types. See the usage ofLegalPersonInterface for example. Before the update (relationship bug), all relationship properties were defined with unions like so:

union AnnotationTargetInterfaced = AnnotationURLTarget | AnnotationCETarget;

I also have two questions:

  • Since there are different properties for the URL and CE target, is it needed to make them two separate types?
  • If two separate types will be used; shouldn't the AnnotationURLTarget have the fragment property as well?

Interfaced relations is the prefered way for relations with multiple types. See the usage ofLegalPersonInterface for example.

Great. So the way which I'm doing it seems OK to you? (it's not clear to me if this was just a comment or if you were suggesting to do something slightly differently)

Since there are different properties for the URL and CE target, is it needed to make them two separate types?

I did think about that, but my preference is to use the type system to enforce these fields, instead of having all fields on a single type and then having a different behaviour depending on what field is set. Doing it like this makes it more difficult to validate the message before sending it

If two separate types will be used; shouldn't the AnnotationURLTarget have the fragment property as well?

My idea is that a url on AnnotationURLTarget could be a full url with fragment if necessary, e.g. http://example.com/audio.mp3#t=30.5
The only reason it's different on the AnnotationCETarget is because for example a contentUrl on a MediaObject will be to the full document, but an annotation needs an (optional) fragment as well.

Great. So the way which I'm doing it seems OK to you? (it's not clear to me if this was just a comment or if you were suggesting to do something slightly differently)

Yes, as discussed, I think this approach fits best with the current CE schema. Thanks for the explanation and examples.