Skip to content

goodm 0.7.1

Choose a tag to compare

@dwoolworth dwoolworth released this 25 Oct 00:25
· 7 commits to main since this release
bb3cdc2

goodm 0.7.1 is a patch release. It fixes a lost-update bug in Update's WithRetry merge that dates from 0.5.0, the items the adversarial reviews of 0.7.0 flagged as pre-existing, and the housekeeping left after 0.7.0. One behavior change is called out below. Full detail is in the CHANGELOG.

Tested against

MongoDB Go
6.0.28, 7.0.45, 8.0.34 as single-node replica sets 1.21, 1.22, 1.23 in CI; 1.26 locally

The full suite runs with the race detector on every combination. The change went through seven adversarial review rounds plus a confirmation pass; the last full round also ran a 160-case WithRetry matrix and a six-writer stress run on all three servers with no lost updates.

Fixed

  • Update with WithRetry lost the caller's changes. The 3-way merge base was the model at the moment Update was called, which already held the caller's edits, so the diff found nothing to apply: on a version conflict the retry wrote the database copy back and returned nil, and a same-field conflict never produced a MergeConflictError. goodm.Model now remembers the document as last loaded or saved through goodm (FindOne, FindByID, Find, FindOneAndUpdate, FindOneAndReplace, Create, Update, UpdateFields, SaveMany) and the merge diffs against that. The base is normalized through the model type, advances after each merge round, is used only when it describes the same document at the model's current version, and is not recorded for writes inside a transaction. The merged document is applied without resurrecting map keys or omitempty values another writer removed, while bson:"-" and unexported fields keep their values. UnsetFields counts as the caller's removals. A model without a base (built by hand, loaded through FindCursor, or without an embedded goodm.Model) gets ErrVersionConflict instead of a merge.
  • enum on a slice or array field rejected every non-empty value. Each element is now checked and reported as field[i], including UpdateFields element paths; nil pointer elements are skipped.
  • UpdatedAt not restored on failed Update and SaveMany items.
  • goodm discover typed date fields as interface{}; they are time.Time.
  • GenerateModel with EmbedModel: false omitted the goodm import its init() needs.
  • Several UpdateOptions values passed to one call are combined, so UnsetFields(...) and WithRetry(n) work together. After an Unset save the fields are zeroed on the model.

Changed

  • ErrVersionConflict no longer refreshes the model's version. The refresh added in 0.5.0 let the next plain Update match the version filter and overwrite the other writer's changes. A conflicting model now keeps its stale version, in Update and SaveMany, until it is reloaded or saved with WithRetry. Models loaded or saved inside a transaction that later aborted must be reloaded before they are saved again.
  • The 0.7.0 changelog entry names the tested servers and Go versions.

Docs

Snapshot sessions in WithTransaction; enum semantics on slices; the WithRetry base and conflict rules; models after an aborted transaction.

Pull request: #11.