Skip to content
Sean DeNigris edited this page Aug 13, 2018 · 2 revisions

Motivation

Let's say you have a Person object with a Name. Maybe you are in the marketing domain, and info comes in through various lists (say csv or Excel files). Some of these may contain missing, incomplete, or incorrect information. When new info comes in referring to the same person, you'd like to take the most correct parts of both the existing and incoming data.

API

Main entry point

The well-known #patchRelativeToBase:, which we borrow from Monticello. newObject patchRelativeToBase: existingObject returns an MAPatchMacro which contains a MAPatchOperation for each description of interest. "Interesting" here means that the description:

  1. The field has not been excluded from merging
  2. The new value is interesting

Excluding a field from merging

Just do anElementDescription shouldMerge: false. Why would you want to do this? Continuing our Person example, let's say we have a virtual #fullName field which concatenates #firstName, #lastName, etc into a pretty printed string. The real data lies not in the generated string, but in the components and will be merged there. NB: maybe a simpler way would be to exclude #readonly fields?

Is a New Value "Interesting"

The default rules are:

  1. The value has changed - duh!
  2. The new value is not nil
  3. The new value is not the Magritte default value (This should be implemented. See Issue #19)

These can be changed by overriding #is:anInterestingReplacementFor:, currently on the domain object level e.g. Name. For example, aName might want to merge a new value which is a full first name like "James", when the previous value was an abbreviation e.g. "J.". Obviously, overriding once per domain object only works when its fields which are all similar. Probably in the future when the need arises, this should be moved to the element description.

Merging in Place

By default, field values are replaced with the new values. If instead you want to keep the existing field value object and recursively update its fields, in your field type (Name in our example), override as follows:

patchRelativeToBase: oldValue as: description of: receiver
	"Edit me in place instead of full replacement like a value object"
	^ self patchRelativeToBase: oldValue

This would allow us to consider each update to aPerson's name individually and not as an atomic operation. We may want to accept the new first name, but reject the new middle name.

UI

There is a very-barebones spike called MAPatchBrowser