overture-stack / lectern

Data Schema / Dictionary management system
GNU Affero General Public License v3.0
0 stars 1 forks source link

Feature Request: Foreign Key restriction for a schema #177

Closed joneubank closed 12 months ago

joneubank commented 1 year ago

Add a schema restriction that requires a value in records of this schema to have a matching value in a record on another schema.

Detailed Description

Each schema can be given a restriction that maps fields in this schema to fields in another schema (or other schemas). Every record validated by this schema will need to be validated against a data set for the other mapped schemas, the value in the specified field(s) in the record need to be found in a record on the other schema's data-set. If multiple foreign keys map to the same schema, then the values must be found in the same record.

As an example, a Specimen schema may add a foreignKey constraint mapping specimen.donor_id to the Donor schema field donor.id. Every record in specimen would have to find at least one record in the donor schema data-set that has a field id with a value matching the specimen's donor_id.

A foreign key restriction can include multiple fields and relations to multiple other schemas. This could be multiple fields to one schema, the same field mapped to multiple schema, or any such combination.

A note on uniqueness

Lectern clients only need to validate that a single record exists in the mapped schema that matches the foreign key restriction - there is no restriction on this mapping being unique. If you require the values to be be unique in either schema then make use of the schema uniqueKey restriction https://github.com/overture-stack/lectern/issues/176 or restrict the individual fields to be unique https://github.com/overture-stack/lectern/issues/175.

Possible Implementation

Add a restrictions object to the meta-schema for schemas, same one as described in https://github.com/overture-stack/lectern/issues/176 .

Add to the restrictions object an optional property called foreignKeys. The value will be an array of foreign-schema mappings.

Each of these mapping objects should include property schema with the string value of the name of the other schema, and a property mappings that will have a list of field mapping objects.

The field mapping objects will have two properties, local with a string value that is the name of the local field that we are mapping from, and foreign which will have a string value that is the name of the field in the foreign schema that it will be matched to.

{
  "restrictions": { 
    "foreignKeys":[
      {
        "schema": "donor", // <===== foreign schema name
        "mappings": [ // <===== can have multiple fields have foreign key mappings
          {
            "local": "donor_id", 
            "foreign": "id"
          }
        ]
      }
    ]
  }
}

Some code validations will be necessary in addition to the meta-data structure validation:

Handling Missing Values

If the local field is not required, then the foreign key mapping will not be applied when that field value is missing in a record. There is no changed behaviour when the foreign schema's field is not required. The rule still requires a record is found in the foreign schema's data set that will match the local record's value.