ionic-orm-3
Version:
Data-mapper ORM for Ionic WebSQL and SQLite
231 lines • 15.2 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { OperateEntity } from "./operation/PersistOperation";
import { QueryBuilder } from "../query-builder/QueryBuilder";
import { PlainObjectToDatabaseEntityTransformer } from "../query-builder/transformer/PlainObjectToDatabaseEntityTransformer";
import { EntityPersistOperationBuilder } from "./EntityPersistOperationsBuilder";
import { PersistOperationExecutor } from "./PersistOperationExecutor";
/**
* Manages entity persistence - insert, update and remove of entity.
*/
var EntityPersister = (function () {
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
function EntityPersister(connection, metadata, queryRunner) {
this.connection = connection;
this.metadata = metadata;
this.queryRunner = queryRunner;
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Persists given entity in the database.
*/
EntityPersister.prototype.persist = function (entity) {
return __awaiter(this, void 0, void 0, function () {
var allNewEntities, persistedEntity, dbEntity, allDbInNewEntities, queryBuilder, plainObjectToDatabaseEntityTransformer, loadedDbEntity, allDbEntities, entityPersistOperationBuilder, persistOperation, persistOperationExecutor;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flattenEntityRelationTree(entity, this.metadata)];
case 1:
allNewEntities = _a.sent();
persistedEntity = allNewEntities.find(function (operatedEntity) { return operatedEntity.entity === entity; });
if (!persistedEntity)
throw new Error("Internal error. Persisted entity was not found in the list of prepared operated entities");
allDbInNewEntities = [];
if (!this.hasId(entity)) return [3 /*break*/, 4];
queryBuilder = new QueryBuilder(this.connection, this.queryRunner)
.select(this.metadata.table.name)
.from(this.metadata.target, this.metadata.table.name);
plainObjectToDatabaseEntityTransformer = new PlainObjectToDatabaseEntityTransformer();
return [4 /*yield*/, plainObjectToDatabaseEntityTransformer.transform(entity, this.metadata, queryBuilder)];
case 2:
loadedDbEntity = _a.sent();
if (!loadedDbEntity) return [3 /*break*/, 4];
dbEntity = new OperateEntity(this.metadata, loadedDbEntity);
return [4 /*yield*/, this.flattenEntityRelationTree(loadedDbEntity, this.metadata)];
case 3:
allDbInNewEntities = _a.sent();
_a.label = 4;
case 4: return [4 /*yield*/, this.findNotLoadedIds(allNewEntities, allDbInNewEntities)];
case 5:
allDbEntities = _a.sent();
entityPersistOperationBuilder = new EntityPersistOperationBuilder(this.connection.entityMetadatas);
persistOperation = entityPersistOperationBuilder.buildFullPersistment(dbEntity, persistedEntity, allDbEntities, allNewEntities);
persistOperationExecutor = new PersistOperationExecutor(this.connection.driver, this.connection.entityMetadatas, this.connection.broadcaster, this.queryRunner);
return [4 /*yield*/, persistOperationExecutor.executePersistOperation(persistOperation)];
case 6:
_a.sent();
return [2 /*return*/, entity];
}
});
});
};
/**
* Removes given entity from the database.
*/
EntityPersister.prototype.remove = function (entity) {
return __awaiter(this, void 0, void 0, function () {
var queryBuilder, plainObjectToDatabaseEntityTransformer, dbEntity, dbEntities, allPersistedEntities, entityWithId, dbEntityWithId, entityPersistOperationBuilder, persistOperation, persistOperationExecutor;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
queryBuilder = new QueryBuilder(this.connection, this.queryRunner)
.select(this.metadata.table.name)
.from(this.metadata.target, this.metadata.table.name);
plainObjectToDatabaseEntityTransformer = new PlainObjectToDatabaseEntityTransformer();
return [4 /*yield*/, plainObjectToDatabaseEntityTransformer.transform(entity, this.metadata, queryBuilder)];
case 1:
dbEntity = _a.sent();
this.metadata.primaryColumnsWithParentPrimaryColumns.forEach(function (primaryColumn) { return entity[primaryColumn.propertyName] = undefined; });
dbEntities = this.flattenEntityRelationTree(dbEntity, this.metadata);
allPersistedEntities = this.flattenEntityRelationTree(entity, this.metadata);
entityWithId = new OperateEntity(this.metadata, entity);
dbEntityWithId = new OperateEntity(this.metadata, dbEntity);
entityPersistOperationBuilder = new EntityPersistOperationBuilder(this.connection.entityMetadatas);
persistOperation = entityPersistOperationBuilder.buildOnlyRemovement(this.metadata, dbEntityWithId, entityWithId, dbEntities, allPersistedEntities);
persistOperationExecutor = new PersistOperationExecutor(this.connection.driver, this.connection.entityMetadatas, this.connection.broadcaster, this.queryRunner);
return [4 /*yield*/, persistOperationExecutor.executePersistOperation(persistOperation)];
case 2:
_a.sent();
return [2 /*return*/, entity];
}
});
});
};
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
/**
* todo: multiple implementations of hasId: here, in repository, in entity metadata
*/
EntityPersister.prototype.hasId = function (entity) {
return this.metadata.primaryColumns.every(function (primaryColumn) {
var columnName = primaryColumn.propertyName;
return !!entity &&
entity.hasOwnProperty(columnName) &&
entity[columnName] !== null &&
entity[columnName] !== undefined &&
entity[columnName] !== "";
});
};
/**
* When ORM loads dbEntity it uses joins to load all entity dependencies. However when dbEntity is newly persisted
* to the db, but uses already exist in the db relational entities, those entities cannot be loaded, and will
* absent in dbEntities. To fix it, we need to go throw all persistedEntities we have, find out those which have
* ids, check if we did not load them yet and try to load them. This algorithm will make sure that all dbEntities
* are loaded. Further it will help insert operations to work correctly.
*/
EntityPersister.prototype.findNotLoadedIds = function (persistedEntities, dbEntities) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
var newDbEntities, missingDbEntitiesLoad;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
newDbEntities = dbEntities ? dbEntities.map(function (dbEntity) { return dbEntity; }) : [];
missingDbEntitiesLoad = persistedEntities.map(function (entityWithId) { return __awaiter(_this, void 0, void 0, function () {
var alias, parameters, condition, metadata, loadedEntity;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (entityWithId.id === null ||
entityWithId.id === undefined ||
newDbEntities.find(function (dbEntity) { return dbEntity.entityTarget === entityWithId.entityTarget && dbEntity.compareId(entityWithId.id); }))
return [2 /*return*/];
alias = entityWithId.entityTarget.name;
parameters = {};
condition = "";
metadata = this.connection.entityMetadatas.findByTarget(entityWithId.entityTarget);
if (metadata.hasParentIdColumn) {
condition = metadata.parentIdColumns.map(function (parentIdColumn) {
parameters[parentIdColumn.propertyName] = entityWithId.id[parentIdColumn.propertyName];
return alias + "." + parentIdColumn.propertyName + "=:" + parentIdColumn.propertyName;
}).join(" AND ");
}
else {
condition = metadata.primaryColumns.map(function (primaryColumn) {
parameters[primaryColumn.propertyName] = entityWithId.id[primaryColumn.propertyName];
return alias + "." + primaryColumn.propertyName + "=:" + primaryColumn.propertyName;
}).join(" AND ");
}
return [4 /*yield*/, new QueryBuilder(this.connection, this.queryRunner)
.select(alias)
.from(entityWithId.entityTarget, alias)
.where(condition, parameters)
.getSingleResult()];
case 1:
loadedEntity = _a.sent();
if (loadedEntity)
newDbEntities.push(new OperateEntity(metadata, loadedEntity));
return [2 /*return*/];
}
});
}); });
return [4 /*yield*/, Promise.all(missingDbEntitiesLoad)];
case 1:
_a.sent();
return [2 /*return*/, newDbEntities];
}
});
});
};
/**
* Extracts unique entities from given entity and all its downside relations.
*/
EntityPersister.prototype.flattenEntityRelationTree = function (entity, metadata) {
var operateEntities = [];
var recursive = function (entity, metadata) {
operateEntities.push(new OperateEntity(metadata, entity));
metadata.extractRelationValuesFromEntity(entity, metadata.relations)
.filter(function (_a) {
var relation = _a[0], value = _a[1];
return !operateEntities.find(function (operateEntity) { return operateEntity.entity === value; });
}) // exclude duplicate entities and avoid recursion
.forEach(function (_a) {
var relation = _a[0], value = _a[1];
return recursive(value, relation.inverseEntityMetadata);
});
};
recursive(entity, metadata);
return operateEntities;
};
return EntityPersister;
}());
export { EntityPersister };
//# sourceMappingURL=EntityPersister.js.map