mirror of
https://github.com/morluto/rea.git
synced 2026-11-06 06:46:10 +00:00
fix(environment): answer bulk updates without fields only later reads show
A bulk update's answer renders each entity with the same allowance a single update's answer has: a field only reads after the type's first write showed, which no initial entity holds, is left out for an entity without it, so a bulk update of a seeded task is no longer refused for lacking it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4515a000a6
commit
d1bb6477f6
6 files changed
+66
-5
No files matched your search
@@ -24,8 +24,8 @@ each write back:
|
||||
membership and for a list query's `limit` role.
|
||||
- **Fields only later reads show.** An item view also shows the members that reads after its type's first write show
|
||||
of the entities they name, when no initial entity holds them. They are never required. An update or delete that
|
||||
answers with the entity leaves such a field out when the entity does not hold it, and the field no longer makes the
|
||||
write `incomplete-entities`. A field some initial entity holds keeps the existing rule: an answer showing it is
|
||||
answers with the entity, a bulk update's answer included, leaves such a field out when the entity does not hold it,
|
||||
and the field no longer makes the write `incomplete-entities`. A field some initial entity holds keeps the existing rule: an answer showing it is
|
||||
refused for an entity without it.
|
||||
- **Skill.** Updates change the fields a person would change (a name, an email address, a status, a due date) rather
|
||||
than only a description, since a served update accepts only the members a recorded update stored, and a deleted
|
||||
|
||||
@@ -21,8 +21,8 @@ Ubuntu 24.04 VMs for the task runs.
|
||||
the list; only a `true` `deleted`, `isDeleted` or `is_deleted` marks an object deleted; a delete is confirmed by a
|
||||
list read paged with `maxSize`; a field only created tasks show joins the task item view without being required; a
|
||||
task update whose answers show it is served.
|
||||
- Serving: a deleted contact leaves the served list; an update of a seeded task answers without the field only created
|
||||
tasks show.
|
||||
- Serving: a deleted contact leaves the served list; an update of a seeded task, single or bulk, answers without the
|
||||
field only created tasks show (the bulk case fails on `4515a000`, before the review fix).
|
||||
- The six behaviour tests fail on `053264bd`.
|
||||
- The existing serving test that refuses to give chapter rows to a book the state holds without them still passes. A
|
||||
first version of the answer rule left out every field the item view does not require, which served that update; the
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
} from "../../domain/analysisView/environmentStateWriteAddress.js";
|
||||
import {
|
||||
bodyProblem,
|
||||
laterItemFields,
|
||||
optionalFields,
|
||||
updatedEntity,
|
||||
updatedFields,
|
||||
writtenBulkResponse,
|
||||
@@ -180,6 +182,12 @@ export const answerBulk = (
|
||||
...entity,
|
||||
sent: Object.keys(targets.value[index]!.body ?? {}),
|
||||
})),
|
||||
optionalFields(plan),
|
||||
laterItemFields(
|
||||
serving.store.state.views.values(),
|
||||
serving.store.state.entities,
|
||||
plan.target,
|
||||
),
|
||||
),
|
||||
{
|
||||
source: "state",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
LATER_BULK_ROWS,
|
||||
LATER_FIELD_ROWS,
|
||||
SOFT_DELETED_ROWS,
|
||||
} from "../../../tests/fixtures/environmentStateLaterReads.js";
|
||||
@@ -37,4 +38,12 @@ describe("served writes modelled on later reads", () => {
|
||||
}).body;
|
||||
expect(body).toEqual({ id: 1, title: "Trim the wicks", done: true });
|
||||
});
|
||||
|
||||
it("answers a bulk update of an initial entity without the field only created entities show", () => {
|
||||
const tasks = servedFrom(LATER_BULK_ROWS);
|
||||
const body = tasks.answer("patch_tasks", {
|
||||
body: [{ id: 1, done: true }],
|
||||
}).body;
|
||||
expect(body).toEqual([{ id: 1, title: "Trim the wicks", done: true }]);
|
||||
});
|
||||
});
|
||||
@@ -616,7 +616,7 @@ export const writtenResponse = (
|
||||
);
|
||||
};
|
||||
|
||||
/** The shared bulk renderer: fixed acknowledgements, or one first-template element per written entity. */
|
||||
/** The shared bulk renderer: fixed acknowledgements, or one first-template element per written entity, each with the single answer's optional and later fields. */
|
||||
export const writtenBulkResponse = (
|
||||
response: WriteResponse,
|
||||
recorded: JsonValue | undefined,
|
||||
@@ -625,6 +625,8 @@ export const writtenBulkResponse = (
|
||||
readonly id: string;
|
||||
readonly sent?: readonly string[];
|
||||
}[],
|
||||
optional: readonly string[] = [],
|
||||
later: ReadonlySet<string> = new Set(),
|
||||
): Applied<JsonValue | undefined> => {
|
||||
if (response.shape === "empty") return ok(undefined);
|
||||
if (response.shape === "recorded") return ok(recorded);
|
||||
@@ -637,6 +639,8 @@ export const writtenBulkResponse = (
|
||||
{ ...response, pointer: "" },
|
||||
template,
|
||||
entity,
|
||||
optional,
|
||||
later,
|
||||
);
|
||||
if (!element.ok) return element;
|
||||
elements.push(element.value ?? null);
|
||||
|
||||
+40
@@ -86,3 +86,43 @@ export const LATER_FIELD_ROWS: readonly TimedCaptureRow[] = (() => {
|
||||
],
|
||||
];
|
||||
})();
|
||||
|
||||
/** The same seeded and created tasks, then one bulk update marking both created tasks done, whose answer shows their subscriptions. */
|
||||
export const LATER_BULK_ROWS: readonly TimedCaptureRow[] = (() => {
|
||||
const seed = task(1, "Trim the wicks");
|
||||
const [first, second] = [
|
||||
task(2, "Order lamp oil"),
|
||||
task(3, "Paint the rail"),
|
||||
];
|
||||
const created = (entity: Entity) => ({
|
||||
...entity,
|
||||
...subscribed(Number(entity["id"])),
|
||||
});
|
||||
const done = (entity: Entity) => ({ ...created(entity), done: true });
|
||||
return [
|
||||
["GET", "/api/tasks", [seed]],
|
||||
["GET", "/api/tasks/1", seed],
|
||||
["POST", "/api/tasks", first, 201, { title: "Order lamp oil" }],
|
||||
["GET", "/api/tasks/2", created(first)],
|
||||
["POST", "/api/tasks", second, 201, { title: "Paint the rail" }],
|
||||
["GET", "/api/tasks/3", created(second)],
|
||||
["GET", "/api/tasks", [seed, first, second]],
|
||||
[
|
||||
"PATCH",
|
||||
"/api/tasks",
|
||||
[done(first), done(second)],
|
||||
200,
|
||||
[
|
||||
{ id: 2, done: true },
|
||||
{ id: 3, done: true },
|
||||
],
|
||||
],
|
||||
["GET", "/api/tasks/2", done(first)],
|
||||
["GET", "/api/tasks/3", done(second)],
|
||||
[
|
||||
"GET",
|
||||
"/api/tasks",
|
||||
[seed, { ...first, done: true }, { ...second, done: true }],
|
||||
],
|
||||
];
|
||||
})();
|
||||
Reference in new issue
Block a user