updateOrganizationRelations
Reparents an organization โ sets (or replaces) its parent and keeps the parent's children back-reference in sync. Roles allowed: Manager, Admin, OrgHead. This is a pure relation act: no pure fields are touched.
Import alias
The code below imports the framework as lesan โ that's the path alias this repo's app uses (see Project Layout). In your own project, import from @hemedani/lesan (npm/Bun) or jsr:@hemedani/lesan (Deno) instead.
Registration (mod.ts)โ
import { grantAccess, setTokens, setUser } from "@lib";
import { coreApp } from "../../../mod.ts";
import { updateOrganizationRelationsFn } from "./updateOrganizationRelations.fn.ts";
import { updateOrganizationRelationsValidator } from "./updateOrganizationRelations.val.ts";
export const updateOrganizationRelationsSetup = () =>
coreApp.acts.setAct({
schema: "organization",
actName: "updateOrganizationRelations",
preAct: [setTokens, setUser, grantAccess([{ roles: ["Manager", "Admin", "OrgHead"] }])],
validator: updateOrganizationRelationsValidator(),
fn: updateOrganizationRelationsFn,
});
The validator (updateOrganizationRelations.val.ts)โ
import { object, objectIdValidation, optional } from "lesan";
import { selectStruct } from "../../../mod.ts";
import { activeRoleMixin } from "@lib";
export const updateOrganizationRelationsValidator = () => {
return object({
set: object({
...activeRoleMixin,
_id: objectIdValidation,
parent: optional(objectIdValidation),
}),
get: selectStruct("organization", 2),
});
};
_id(required) is the organization being reparented.parent(optional) is the new parent id. If omitted, nothing happens.getis depth 2, so you can confirm the newparentsnapshot in the response.
The implementation (updateOrganizationRelations.fn.ts)โ
import { type ActFn, ObjectId } from "lesan";
import { organization } from "../../../mod.ts";
export const updateOrganizationRelationsFn: ActFn = async (body) => {
const {
set: { _id, parent },
get,
} = body.details;
const modelId = new ObjectId(_id as string);
if (parent) {
await organization.addRelation({
filters: { _id: modelId },
relations: {
parent: {
_ids: new ObjectId(parent as string),
relatedRelations: {
children: true,
},
},
},
projection: get,
replace: true,
});
}
return await organization.findOne({
filters: { _id: modelId },
projection: get,
});
};
modelIdis the organization being updated.- If
parentis provided,organization.addRelationsets theparentsingle relation. TherelatedRelations: { children: true }tells the ODM to also update the back-reference: the new parent'schildrenarray gets this organization's snapshot (and the old parent'schildrenloses it). replace: trueis key โ for asinglerelation it means "set, don't append". Noreplace: truewould try to add to the relation; for a single relation you always want replace.- Finally
organization.findOnereturns the fresh document so the client sees the new state.
Note this act has no throwError: if _id doesn't exist, addRelation throws can not find this document, and if you only get (no parent), findOne returns null with success: true.
In the workflowโ
Organizations rarely move in the tree, but when they do (mergers, reorganizations), this keeps the children snapshots honest. OrgHead is allowed here because a hospital head may restructure its own subtree.
- organization model
- Sibling acts: addOrganization, getOrganizations
Run itโ
curl http://localhost:1380/lesan \
-H "Content-Type: application/json" \
-H "token: <jwt>" \
-d '{
"model": "organization",
"act": "updateOrganizationRelations",
"details": {
"set": { "activeRoleId": "ghost-role", "_id": "<orgId>", "parent": "<parentOrgId>" },
"get": { "_id": 1, "name": 1, "parent": { "_id": 1, "name": 1 } }
}
}'
Errors & fixesโ
| Error | Meaning | Fix |
|---|---|---|
can not find this document | The _id (or the new parent id) doesn't match an existing organization. | Verify both ids via getOrganizations. |
activeRoleId is required | No activeRoleId in set. | Add it (ghost: any string, e.g. "ghost-role"). |
Active role not found | activeRoleId isn't one of the user's roles. | Pass a real roleId. |
You cant do this | Active role isn't Manager/Admin/OrgHead (or ghost). | Use an allowed role or the ghost. |
| superstruct "expected ObjectId-like string" | _id or parent isn't a valid ObjectId. | Send 24-hex id strings. |