accordproject / concerto

Business schema language and runtime
https://concerto.accordproject.org
Apache License 2.0
121 stars 106 forks source link

Specialising vocabulary terms for properties #904

Open dselman opened 2 months ago

dselman commented 2 months ago

Feature Request 🛍️

It would be very useful to be able to specialise the vocabulary terms for concept properties, based on the concept inheritance tree.

Use Case

Take the model below, as an example.

namespace org.acme@1.0.0

enum Color {
    o RED
    o BLUE
    o GREEN
}

scalar SSN extends String default="000-00-0000"
scalar VIN extends String

asset Vehicle identified by vin {
    o VIN vin
    o Color color
}

map Address {
    o String
    o String
}

asset Truck extends Vehicle {
    o Double weight
}

asset Motorcycle extends Vehicle {
}

The term for Truck.color in US English should be The color of the truck while in GB English it should be The colour of the lorry, and similarly for Motocycle.color.

Note that this is only necessary for folks who would like to make the of the ... part explicit and encode it into the term for the property.

Possible Solution

VocabularyManager can check for a term attached to the current declaration (e.g. Truck) before looking on class declaration that declares the property (Vehicle).

Context

  1. Override terms for properties based on the inheritance hierarchy of their owning concepts.

Detailed Description

Updates to VocabularyManager.getTerm(s) and resolveTerm(s) to first check the class declaration specified in the arguments, before checking the class declaration that declares the property.

Updates to VocabularyManager.generateDecoratorCommands are conceptually more complex, as the @Term decorator must be attached to the declaration of the property.

E.g. the model that has the vocabulary (en-GB) applied is currently:

asset Vehicle identified by vin {
    o VIN vin
   @Term("The colour of the vehicle")
    o Color color
}

asset Truck extends Vehicle {
    o Double weight
}

asset Motorcycle extends Vehicle {
}

Because there is no declared property Truck.color or Motocycle.color there is nowhere in the model to put the specialised vocabulary terms.

The proposal is therefore to create a Decorator Command Set that creates the model below. The specialised terms have been hoisted onto the class declaration that specialises the term.

asset Vehicle identified by vin {
    o VIN vin
   @Term("The colour of the vehicle")
    o Color color
}

@Term_ color("The colour of the lorry")
asset Truck extends Vehicle {
    o Double weight
}

@Term_ color("The colour of the motorcycle")
asset Motorcycle extends Vehicle {
}

Note that this is equivalent to putting a custom term called color on the declaration. E.g.

locale: en
namespace: org.acme@1.0.0
declarations:
  - VIN: A vehicle identification number
  - Color: A color
  - Vehicle: A road vehicle
    properties:
      - vin: Vehicle Identification Number
        tooltip: VIN
      - model: Model of the vehicle
  - Truck: A truck
    description: A vehicle capable of carrying cargo
    tooltip: Truck
    color: The color of the truck
    properties:
      - weight: The weight of the truck
        description: The weight of the truck in KG
        tooltip: Truck weight
      - horsePower: The horse power of the truck
        description: The horse power of the truck
        tooltip: Truck HP
  - Address: Registered address of the vehicle
    properties:
      - KEY: vin of the vehicle
      - VALUE: address of the vehicle

QUESTION: Is this sufficient? Perhaps we don't need a code change at all to support this use case?

An alternative would be to place all decorators on the property itself. E.g.

asset Vehicle identified by vin {
    o VIN vin
   @Term("The colour of the vehicle")
   @Term_ Truck("The colour of the lorry")
   @Term_ Motorcycle("The colour of the motocycle")
    o Color color
}

In most cases we could use short names (the derived type and the base type are in the same namespace) but if the derived type is in a separate namespace we would have to use mangled fully-qualified names.

asset Vehicle identified by vin {
    o VIN vin
   @Term("The colour of the vehicle")
   @Term_ org_acme_watercraft_Boat("The colour of the boat")
    o Color color
}
mttrbrts commented 2 months ago

I see a small chance of collisions with other terms on the Concept, for example, if I have a property on the Concept called description and a description Term for the Concept.

How about we reserve a special term for overridden terms, and push the property name into an argument? That would also help us to avoid messy escaping for fully-qualified names too.

asset Vehicle identified by vin {
    o VIN vin
   @Term("The colour of the vehicle")
    o Color color
}

@Term_ override("color","The colour of the lorry")
asset Truck extends Vehicle {
    o Double weight
}

@Term_override("color", "The colour of the motorcycle")
asset Motorcycle extends Vehicle {
}
dselman commented 1 month ago

If we put the overridden terms on the concept, then we don't have to worry about escaping for fully-qualified names.

My hesitancy with this one is whether we need to support this at the API level, or whether users can deal with this as a custom term for the concept itself, using our existing YAML and APIs. If we push this into "user land" then users can invent their own prefix to prevent conflicts, if necessary.

imakhan80 commented 1 month ago

The snippet defines a schema for vehicles in YAML format. It includes a Vehicle entity with properties like vin and color, while Truck and Motorcycle inherit from it with their specific attributes, such as weight for trucks and distinct color_term for each type. The namespace defines the organizational scope and versioning. "locale: en namespace: org.acme@1.0.0 declarations: