Repository navigation
goodm 0.7.1
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
UpdatewithWithRetrylost the caller's changes. The 3-way merge base was the model at the momentUpdatewas 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 aMergeConflictError.goodm.Modelnow 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 oromitemptyvalues another writer removed, whilebson:"-"and unexported fields keep their values.UnsetFieldscounts as the caller's removals. A model without a base (built by hand, loaded throughFindCursor, or without an embeddedgoodm.Model) getsErrVersionConflictinstead of a merge.enumon a slice or array field rejected every non-empty value. Each element is now checked and reported asfield[i], includingUpdateFieldselement paths; nil pointer elements are skipped.UpdatedAtnot restored on failedUpdateandSaveManyitems.goodm discovertyped date fields asinterface{}; they aretime.Time.GenerateModelwithEmbedModel: falseomitted the goodm import itsinit()needs.- Several
UpdateOptionsvalues passed to one call are combined, soUnsetFields(...)andWithRetry(n)work together. After an Unset save the fields are zeroed on the model.
Changed
ErrVersionConflictno longer refreshes the model's version. The refresh added in 0.5.0 let the next plainUpdatematch the version filter and overwrite the other writer's changes. A conflicting model now keeps its stale version, inUpdateandSaveMany, until it is reloaded or saved withWithRetry. 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.