public commit

This commit is contained in:
dswbx
2024-11-16 12:01:47 +01:00
commit 90f80c4280
582 changed files with 49291 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
import type { PrimaryFieldType } from "core";
import type { Entity, EntityManager } from "../entities";
import {
type EntityRelation,
type MutationOperation,
MutationOperations,
RelationField
} from "../relations";
export type MutationInstructionResponse = [string, PrimaryFieldType | null];
export class RelationMutator {
constructor(
protected entity: Entity,
protected em: EntityManager<any>
) {}
/**
* Returns all keys that are somehow relational.
* Includes local fields (users_id) and references (users|author)
*
* @param em
* @param entity_name
*
* @returns string[]
*/
getRelationalKeys(): string[] {
const references: string[] = [];
this.em.relationsOf(this.entity.name).map((r) => {
const info = r.helper(this.entity.name).getMutationInfo();
references.push(info.reference);
info.local_field && references.push(info.local_field);
});
return references;
}
async persistRelationField(
field: RelationField,
key: string,
value: PrimaryFieldType
): Promise<MutationInstructionResponse> {
// allow empty if field is not required
if (value === null && !field.isRequired()) {
return [key, value];
}
// make sure it's a primitive value
// @todo: this is not a good way of checking primitives. Null is also an object
if (typeof value === "object") {
console.log("value", value);
throw new Error(`Invalid value for relation field "${key}" given, expected primitive.`);
}
const query = await this.em.repository(field.target()).exists({
[field.targetField()]: value
});
if (!query.exists) {
const idProp = field.targetField();
throw new Error(
`Cannot connect "${this.entity.name}.${key}" to ` +
`"${field.target()}.${idProp}" = "${value}": not found.`
);
}
return [key, value];
}
async persistReference(
relation: EntityRelation,
key: string,
value: unknown
): Promise<void | MutationInstructionResponse> {
if (typeof value !== "object" || value === null || typeof value === "undefined") {
throw new Error(
`Invalid value for relation "${key}" given, expected object to persist reference. Like '{$set: {id: 1}}'.`
);
}
const operation = Object.keys(value)[0] as MutationOperation;
if (!MutationOperations.includes(operation)) {
throw new Error(
`Invalid operation "${operation}" for relation "${key}". ` +
`Allowed: ${MutationOperations.join(", ")}`
);
}
// @ts-ignore
const payload = value[operation];
return await relation[operation](this.em, key, payload);
}
async persistRelation(key: string, value: unknown): Promise<void | MutationInstructionResponse> {
// if field (e.g. 'user_id')
// relation types: n:1, 1:1 (mapping entity)
const field = this.entity.getField(key);
if (field instanceof RelationField) {
return this.persistRelationField(field, key, value as PrimaryFieldType);
}
/**
* If reference given, value operations are given
*
* Could be:
* { $set: { id: 1 } }
* { $set: [{ id: 1 }, { id: 2 }] }
* { $create: { theme: "dark" } }
* { $attach: [{ id: 1 }, { id: 2 }] }
* { $detach: [{ id: 1 }, { id: 2 }] }
*/
const relation = this.em.relationOf(this.entity.name, key);
if (relation) {
return this.persistReference(relation, key, value);
}
throw new Error(
`Relation "${key}" failed to resolve on entity "${this.entity.name}": ` +
"Unable to resolve relation origin."
);
}
}