Files

64 lines
3.1 KiB
JavaScript

const checked = async (port, revision) => {
const snapshot = await port.collection();
if (snapshot.revision !== revision)
throw new Error("STALE_COLLECTION_REVISION");
return snapshot;
};
/** Helpers never retry a failed CAS or silently overwrite concurrent edits. */
export const relationshipMap = (port) => ({
read: () => port.collection(),
async get(key) {
const snapshot = await port.collection();
return { revision: snapshot.revision, value: snapshot.entries.find((entry) => entry.key === key)?.target };
},
async set(key, target, expectedRevision) {
const snapshot = await checked(port, expectedRevision);
const entries = snapshot.entries.filter((entry) => entry.key !== key);
const existing = snapshot.entries.find((entry) => entry.key === key && entry.target.equals(target));
entries.push(existing ?? { key, target });
return port.replace(entries, expectedRevision);
},
async delete(key, expectedRevision) {
const snapshot = await checked(port, expectedRevision);
return port.replace(snapshot.entries.filter((entry) => entry.key !== key), expectedRevision);
},
});
export const relationshipList = (port) => ({
read: () => port.collection(),
async insert(index, target, expectedRevision) {
const snapshot = await checked(port, expectedRevision);
if (!Number.isSafeInteger(index) || index < 0 || index > snapshot.entries.length)
throw new Error("List index out of bounds");
snapshot.entries.splice(index, 0, { target });
return port.replace(snapshot.entries, expectedRevision);
},
async move(edgeId, index, expectedRevision) {
const snapshot = await checked(port, expectedRevision);
const prior = snapshot.entries.findIndex((entry) => entry.edgeId === edgeId);
if (prior < 0 || !Number.isSafeInteger(index) || index < 0 || index >= snapshot.entries.length)
throw new Error("Unknown list entry or invalid index");
const [entry] = snapshot.entries.splice(prior, 1);
snapshot.entries.splice(index, 0, entry);
return port.replace(snapshot.entries, expectedRevision);
},
async delete(edgeId, expectedRevision) {
const snapshot = await checked(port, expectedRevision);
if (!snapshot.entries.some((entry) => entry.edgeId === edgeId))
throw new Error("Unknown list entry");
return port.replace(snapshot.entries.filter((entry) => entry.edgeId !== edgeId), expectedRevision);
},
});
export const relationshipSet = (port) => ({
read: () => port.collection(),
async add(target, expectedRevision) {
const snapshot = await checked(port, expectedRevision);
if (snapshot.entries.some((entry) => entry.target.equals(target)))
return snapshot;
return port.replace([...snapshot.entries, { target }], expectedRevision);
},
async delete(target, expectedRevision) {
const snapshot = await checked(port, expectedRevision);
return port.replace(snapshot.entries.filter((entry) => !entry.target.equals(target)), expectedRevision);
},
});