mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-17 12:56:05 +00:00
public commit
This commit is contained in:
121
app/src/data/relations/RelationMutator.ts
Normal file
121
app/src/data/relations/RelationMutator.ts
Normal 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."
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user