@cheetah.js/orm
Version:
A simple ORM for Cheetah.js
142 lines (141 loc) • 5.34 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModelTransformer = void 0;
const value_object_1 = require("../common/value-object");
const utils_1 = require("../utils");
class ModelTransformer {
constructor(entityStorage) {
this.entityStorage = entityStorage;
}
transform(model, statement, data) {
const instanceMap = this.createInstances(model, statement);
const optionsMap = this.buildOptionsMap(instanceMap);
this.populateProperties(data, instanceMap, optionsMap);
this.linkJoinedEntities(statement, instanceMap, optionsMap);
this.resetChangedValues(instanceMap);
return instanceMap[statement.alias];
}
createInstances(model, statement) {
const instance = this.createInstance(model);
const instanceMap = {
[statement.alias]: instance,
};
if (statement.join) {
this.addJoinedInstances(statement, instanceMap);
}
return instanceMap;
}
createInstance(model) {
const instance = new model();
instance.$_isPersisted = true;
return instance;
}
addJoinedInstances(statement, instanceMap) {
statement.join.forEach(join => {
const joinInstance = this.createInstance(join.joinEntity);
instanceMap[join.joinAlias] = joinInstance;
});
}
buildOptionsMap(instanceMap) {
const optionsMap = new Map();
for (const [alias, instance] of Object.entries(instanceMap)) {
const options = this.entityStorage.get(instance.constructor);
if (options) {
optionsMap.set(alias, options);
}
}
return optionsMap;
}
populateProperties(data, instanceMap, optionsMap) {
Object.entries(data).forEach(([key, value]) => {
const { alias, propertyName } = this.parseColumnKey(key);
const entity = instanceMap[alias];
if (!entity) {
return;
}
this.setPropertyValue(entity, propertyName, value, optionsMap.get(alias));
});
}
parseColumnKey(key) {
const index = key.indexOf('_');
return {
alias: key.substring(0, index),
propertyName: key.substring(index + 1),
};
}
setPropertyValue(entity, columnName, value, options) {
const propertyInfo = this.findPropertyByColumnName(columnName, options);
if (!propertyInfo) {
return;
}
const { key, property } = propertyInfo;
if (this.isValueObjectType(property.type)) {
entity[key] = new property.type(value);
return;
}
entity[key] = value;
}
findPropertyByColumnName(columnName, options) {
// First, try to find in regular properties
const entry = Object.entries(options.properties).find(([_, prop]) => prop.options.columnName === columnName);
if (entry) {
return { key: entry[0], property: entry[1] };
}
// If not found, try to find in relations (many-to-one)
const relation = options.relations?.find((rel) => rel.columnName === columnName && rel.relation === 'many-to-one');
if (relation) {
return { key: relation.propertyKey, property: relation };
}
return null;
}
isValueObjectType(type) {
return (0, utils_1.extendsFrom)(value_object_1.ValueObject, type?.prototype);
}
linkJoinedEntities(statement, instanceMap, optionsMap) {
if (!statement.join) {
return;
}
statement.join.forEach(join => {
this.linkSingleJoin(join, instanceMap, optionsMap);
});
}
linkSingleJoin(join, instanceMap, optionsMap) {
const { joinAlias, originAlias, propertyKey } = join;
const originEntity = instanceMap[originAlias];
const joinEntity = instanceMap[joinAlias];
if (!originEntity || !joinEntity) {
return;
}
const property = this.findRelationProperty(originAlias, propertyKey, optionsMap);
if (property) {
this.attachJoinedEntity(originEntity, joinEntity, propertyKey, property);
}
}
findRelationProperty(alias, propertyKey, optionsMap) {
return optionsMap.get(alias)?.relations.find(rel => rel.propertyKey === propertyKey);
}
attachJoinedEntity(originEntity, joinEntity, propertyKey, property) {
if (property.type === Array) {
originEntity[propertyKey] = this.appendToArray(originEntity[propertyKey], joinEntity);
}
else {
originEntity[propertyKey] = joinEntity;
}
}
appendToArray(existingArray, newItem) {
return existingArray ? [...existingArray, newItem] : [newItem];
}
resetChangedValues(instanceMap) {
Object.values(instanceMap).forEach(instance => {
const currentValues = {};
for (const key in instance) {
if (!key.startsWith('_') && !key.startsWith('$')) {
currentValues[key] = instance[key];
}
}
instance._oldValues = currentValues;
instance._changedValues = {};
});
}
}
exports.ModelTransformer = ModelTransformer;