Skip to content

Add aliasing for table of placeholder contribution details, to make resilient to PG schema changes

About

In #443554 (closed) we are adding a table to save details of placeholder contributions. Its design involves saving model and column (name) data.

Problem

This is brittle as we persist names PostgreSQL schema that are changeable. A model or column name change could lead to us failing to assign user contributions.

Proposal

Treat the model and column values we save into the database as aliases to the real things, so if the real thing changes, we continue to save with the same model or column values, but update what the alias points to and then our old data remains valid.

YAML file

We would define a YAML file:

---
<model>:
  model: <actual model>
  columns:
   <column>: <actual column>

Example of a definition within the YAML:

---
MyModel:
  model: MyModel
  columns:
    user_id: user_id

Over time, if the model name changes, or column names change, the keys would remain unchanged, but the values would be updated:

---
MyModel:
  model: Imports::MyModel
  columns:
    user_id: author_id

Use the aliases in the model

We will update the model added in !156241 (merged) to refer to the aliases when looking up:

  • model example: (aliases.dig(model, :model))
  • column example (aliases.dig(model, :columns, column)
  • column names in composite_key (using the same method as with column)

Tolerant of unknown model, or combinations of <model> and <column>

We should not block the ability for something we don't know about yet to JustWork and still be saved and used successfully without us officially knowing about it.

!156672 (merged) will need to use the aliased values instead of the real values here. If that MR has not merged by the time this issue would otherwise be completed, we could create a follow-up issue to adjust it to use the aliased values.

When those lines read an unrecognised <model> or combination of <model> and <column>, in prod we should return the value and track a helpful exception (not raise one), and in dev and test we would raise the helpful exception.

If it gets to prod, we would eventually spot the exceptions we tracked (they don't contribute to our error budget) and could add it to the YAML later.

We could do this, for example like:

# within Import::SourceUserPlaceholderReference
def aliased_model
  aliases.dig(model, :model) || <track exception and return model>
end

and then update the lines to use aliased_x methods instead of accessing the properties directly.

Or alternatively, maybe make #model return the aliased model value and #raw_model return the database value.

Validation through a spec

We will also add a kind of static validation within a spec scenario. We will fail when the model name we expect no longer exists, or when a column name we expect doesn't exist for the model. The spec failure would alert a developer to update what our aliases map to. This would be similar to one to detect changes relevant to DesignManagement::CopyDesignCollection::CopyService which has successfully alerted people as what to do as the blame shows. We have a similar concept of keeping import_export.yml up to date).

We would need to ensure this spec runs after any change to app/models and ee/app/models and db/migrate in our partial merged pipeline results logic, which likely requires updating tests.yml (see !153092 (merged)).

Edited by Luke Duncalfe