@compas/code-gen
Version:
Generate various boring parts of your server
243 lines (208 loc) • 6.87 kB
JavaScript
import { lowerCaseFirst, upperCaseFirst } from "../../utils.js";
import { modelKeyGetPrimary } from "./model-keys.js";
/**
* @typedef {object} CrudInformation
* @property {import("../generated/common/types").ExperimentalObjectDefinition} model
* @property {import("../generated/common/types").ExperimentalCrudDefinition} [parent]
* @property {import("../generated/common/types").
* ExperimentalRelationDefinition} [relation]
* @property {{ group: string, name: string }} readableType
* @property {{ group: string, name: string }} writableType
* @property {boolean} hasCustomReadableType
*/
/**
* Cache various items around CRUD objects
*
* @type {WeakMap<object, CrudInformation>}
*/
const crudCache = new WeakMap();
/**
* Get the resolved name of the provided crud route
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @param {string} suffix
* @returns {string}
*/
export function crudInformationGetName(crud, suffix) {
let result = lowerCaseFirst(suffix);
if (crud.fromParent) {
result =
(crud.fromParent?.options?.name ?? crud.fromParent.field) +
upperCaseFirst(result);
return crudInformationGetName(crudInformationGetParent(crud), result);
}
return result;
}
/**
* Get the resolved path of the provided crud route
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @param {string} suffix
* @returns {string}
*/
export function crudInformationGetPath(crud, suffix) {
if (!suffix.startsWith("/")) {
suffix = `/${suffix}`;
}
const path = crud.basePath + suffix;
if (crud.fromParent) {
const parent = crudInformationGetParent(crud);
const relation = crudInformationGetRelation(crud);
if (
relation.subType === "oneToOneReverse" ||
relation.subType === "oneToOne"
) {
return crudInformationGetPath(parent, path);
}
return crudInformationGetPath(
parent,
`/:${crudInformationGetParamName(parent)}${path}`,
);
}
return path;
}
/**
* Get the param name for the provided crud object
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
*/
export function crudInformationGetParamName(crud) {
const model = crudInformationGetModel(crud);
const { primaryKeyName } = modelKeyGetPrimary(model);
return `${crud.fromParent?.options?.name ?? model.name}${upperCaseFirst(
primaryKeyName,
)}`;
}
/**
* Save the used model, so we don't have to resolve that each and every time.
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @param {import("../generated/common/types").ExperimentalObjectDefinition} model
*/
export function crudInformationSetModel(crud, model) {
const obj = crudCache.get(crud) ?? {};
// @ts-expect-error
obj.model = model;
// @ts-expect-error
crudCache.set(crud, obj);
}
/**
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @returns {import("../generated/common/types").ExperimentalObjectDefinition}
*/
export function crudInformationGetModel(crud) {
// @ts-expect-error
return crudCache.get(crud).model;
}
/**
* Save the used relation and parent
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @param {import("../generated/common/types").ExperimentalCrudDefinition} parent
* @param {import("../generated/common/types").
* ExperimentalRelationDefinition} relation
*/
export function crudInformationSetRelationAndParent(crud, parent, relation) {
const obj = crudCache.get(crud) ?? {};
// @ts-expect-error
obj.parent = parent;
// @ts-expect-error
obj.relation = relation;
// @ts-expect-error
crudCache.set(crud, obj);
}
/**
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @returns {import("../generated/common/types").ExperimentalRelationDefinition}
*/
export function crudInformationGetRelation(crud) {
// @ts-expect-error
return crudCache.get(crud).relation;
}
/**
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @returns {import("../generated/common/types").ExperimentalCrudDefinition}
*/
export function crudInformationGetParent(crud) {
// @ts-expect-error
return crudCache.get(crud).parent;
}
/**
* Save the created readable type, so it is easily resolvable later on.
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @param {{ group: string, name: string }} readable
*/
export function crudInformationSetReadableType(crud, readable) {
const obj = crudCache.get(crud) ?? {};
// @ts-expect-error
obj.readableType = readable;
// @ts-expect-error
crudCache.set(crud, obj);
}
/**
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @returns {{ group: string, name: string }}
*/
export function crudInformationGetReadableType(crud) {
// @ts-expect-error
return crudCache.get(crud).readableType;
}
/**
* Save the created writable type, so it is easily resolvable later on.
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @param {{ group: string, name: string }} writable
*/
export function crudInformationSetWritableType(crud, writable) {
const obj = crudCache.get(crud) ?? {};
// @ts-expect-error
obj.writableType = writable;
// @ts-expect-error
crudCache.set(crud, obj);
}
/**
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @returns {{ group: string, name: string }}
*/
export function crudInformationGetWritableType(crud) {
// @ts-expect-error
return crudCache.get(crud).writableType;
}
/**
* Cache when the provided CRUD has a custom readable type.
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @param {boolean} hasCustomReadableType
*/
export function crudInformationSetHasCustomReadableType(
crud,
hasCustomReadableType,
) {
const obj = crudCache.get(crud) ?? {};
// @ts-expect-error
obj.hasCustomReadableType = hasCustomReadableType;
// @ts-expect-error
crudCache.set(crud, obj);
}
/**
* Check if the crud or parent has a custom readable type
*
* @param {import("../generated/common/types").ExperimentalCrudDefinition} crud
* @returns {boolean}
*/
export function crudInformationGetHasCustomReadableType(crud) {
const information = crudCache.get(crud) ?? {};
// @ts-expect-error
if (information.hasCustomReadableType) {
return true;
}
// @ts-expect-error
if (information.parent && information.parent.inlineRelations.includes(crud)) {
// Nested relations can define for themselves if they have a custom readable type, so
// we only traverse upwards when we are in an inline relation.
// @ts-expect-error
return crudInformationGetHasCustomReadableType(information.parent);
}
return false;
}