Guide

Optimistic locking

One line on a model, and a stale save is refused instead of silently overwriting.

The problem

Two people open the same record, both save. The second write overwrites the first, and neither is told. Guarding against that in every endpoint means remembering to, every time, forever.

The whole feature

import {
  ParseClass, BaseModel, ParseVersionField, createVersionedMongoAdapter,
  VersionRegistry,
} from 'parse-server-kit';

@ParseClass('Job')
class Job extends BaseModel {
  @ParseVersionField()   // declares the Number field itself
  declare version: number;
}

That is all of it. No endpoint reads or writes the field:

An object built from a bare id is not protected Model.pointer(id) was never read, so it carries no version and has nothing to assert. That is by design — there is no safe value to guess — but it means a read-modify-write must actually read.

Requirements

Needs createVersionedMongoAdapter, the same adapter that powers transactions. It is MongoDB only; on Postgres the field is declared but nothing enforces it — and since 3.0 that says so at boot rather than passing unnoticed.

// In the boot output:
[Versioning] Optimistic locking active on: Job, Invoice

// Or, if the adapter was never wired in:
[Versioning] 2 class(es) declare @ParseVersionField … but
createVersionedMongoAdapter() was never called. Optimistic locking
is INACTIVE - stale saves will overwrite silently.

Recovering

try {
  await job.save(null, { useMasterKey: true });
} catch (error) {
  if (error instanceof Parse.Error && error.code === CONFLICT) {
    const fresh = await new Parse.Query(Job).get(job.id);
    // re-apply the change to `fresh` and save again
  }
  throw error;
}

VERSION_CONFLICT and CONFLICT are the same value deliberately, and CONFLICT_MESSAGE is already phrased for an end user.

Inspecting it

VersionRegistry.classNames();        // every versioned class
VersionRegistry.isVersioned('Job');   // true
VersionRegistry.adapterIsInstalled();