CheckProposedVersion - given DocID and a version in string form, check whether it can be added without conflict. proposedVersionStr is the string representation of the proposed version's CV. previousRev is the string representation of the CV of the last known parent of the proposed version. proposed
(ctx context.Context, docid, proposedVersionStr string, previousRev string, proposedHLVString string)
| 3696 | // previousRev is the string representation of the CV of the last known parent of the proposed version. |
| 3697 | // proposedHLVString is the string representation of the proposed version's full HLV. |
| 3698 | func (db *DatabaseCollectionWithUser) CheckProposedVersion(ctx context.Context, docid, proposedVersionStr string, previousRev string, proposedHLVString string) (status ProposedRevStatus, currentVersion string) { |
| 3699 | |
| 3700 | proposedVersion, err := ParseVersion(proposedVersionStr) |
| 3701 | if err != nil { |
| 3702 | base.WarnfCtx(ctx, "Couldn't parse proposed version for doc %q / %q: %v", base.UD(docid), proposedVersionStr, err) |
| 3703 | return ProposedRev_Error, "" |
| 3704 | } |
| 3705 | |
| 3706 | // previousRev may be revTreeID or version |
| 3707 | var previousVersion Version |
| 3708 | previousRevFormat := "version" |
| 3709 | // TODO: CBG-4812 Use base.IsRevTreeID |
| 3710 | if !strings.Contains(previousRev, "@") { |
| 3711 | previousRevFormat = "revTreeID" |
| 3712 | } |
| 3713 | if previousRev != "" && previousRevFormat == "version" { |
| 3714 | var err error |
| 3715 | previousVersion, err = ParseVersion(previousRev) |
| 3716 | if err != nil { |
| 3717 | base.WarnfCtx(ctx, "Couldn't parse previous version for doc %q / %q: %v", base.UD(docid), previousRev, err) |
| 3718 | return ProposedRev_Error, "" |
| 3719 | } |
| 3720 | } |
| 3721 | |
| 3722 | localDocCV := Version{} |
| 3723 | syncData, hlv, err := db.GetDocSyncDataNoImport(ctx, docid, DocUnmarshalNoHistory) |
| 3724 | if hlv != nil { |
| 3725 | localDocCV.SourceID, localDocCV.Value = hlv.GetCurrentVersion() |
| 3726 | } |
| 3727 | if err != nil { |
| 3728 | if !base.IsDocNotFoundError(err) && !errors.Is(err, base.ErrXattrNotFound) { |
| 3729 | base.WarnfCtx(ctx, "CheckProposedRev(%q) --> %T %v", base.UD(docid), err, err) |
| 3730 | return ProposedRev_Error, "" |
| 3731 | } |
| 3732 | // New document not found on server |
| 3733 | return ProposedRev_OK_IsNew, "" |
| 3734 | } else if previousRevFormat == "revTreeID" && syncData.GetRevTreeID() == previousRev { |
| 3735 | if proposedVersion.SourceID == encodedRevTreeSourceID { |
| 3736 | // If we have encoded CV proposed to us and local CV is not encoded, check if proposed encoded CV |
| 3737 | // is derived from the local current revID. If so we already have this rev. |
| 3738 | localEncodedCV, err := LegacyRevToRevTreeEncodedVersion(syncData.GetRevTreeID()) |
| 3739 | if err != nil { |
| 3740 | base.DebugfCtx(ctx, base.KeyCRUD, "Failed to parse local revID to encoded CV for doc %q / %q: %v", base.UD(docid), previousRev, err) |
| 3741 | return ProposedRev_Error, "" |
| 3742 | } |
| 3743 | if localEncodedCV.Equal(proposedVersion) { |
| 3744 | return ProposedRev_Exists, "" |
| 3745 | } |
| 3746 | } |
| 3747 | // Non-conflicting update, client's previous legacy revTreeID is server's currentRev |
| 3748 | return ProposedRev_OK, "" |
| 3749 | } else if hlv == nil { |
| 3750 | // no HLV on this doc in SGW so if previousRev didn't match current rev then it is a conflict |
| 3751 | return ProposedRev_Conflict, syncData.GetRevTreeID() |
| 3752 | } else if previousRevFormat == "version" && localDocCV == previousVersion { |
| 3753 | // Non-conflicting update, client's previous version is server's CV |
| 3754 | return ProposedRev_OK, "" |
| 3755 | } else if hlv.DominatesSource(proposedVersion) { |