@blueleader07/typeorm
Version:
Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.
288 lines (286 loc) • 12.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DynamoEntityManager = void 0;
/**
* Entity manager supposed to work with any entity, automatically find its repository and call its methods,
* whatever entity type are you passing.
*
* This implementation is used for DynamoDB driver which has some specifics in its EntityManager.
*/
const EntityManager_1 = require("./EntityManager");
const FindOptionsUtils_1 = require("../find-options/FindOptionsUtils");
const DynamoParamHelper_1 = require("../driver/dynamo/helpers/DynamoParamHelper");
const DynamoGlobalSecondaryIndexHelper_1 = require("../driver/dynamo/helpers/DynamoGlobalSecondaryIndexHelper");
const DynamoFindOptions_1 = require("../driver/dynamo/models/DynamoFindOptions");
const DynamoBatchHelper_1 = require("../driver/dynamo/helpers/DynamoBatchHelper");
const DynamoObjectHelper_1 = require("../driver/dynamo/helpers/DynamoObjectHelper");
const DynamoClient_1 = require("../driver/dynamo/DynamoClient");
// todo: we should look at the @PrimaryKey on the entity
const DEFAULT_KEY_MAPPER = (item) => {
return {
id: item.id,
};
};
class DynamoEntityManager extends EntityManager_1.EntityManager {
get dynamodbQueryRunner() {
return this.connection.driver
.queryRunner;
}
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection) {
super(connection);
}
// -------------------------------------------------------------------------
// Overridden Methods
// -------------------------------------------------------------------------
createDefaultKeyMapper(target) {
const metadata = this.connection.getMetadata(target);
return (entity) => {
const keys = {};
for (let i = 0; i < metadata.primaryColumns.length; i++) {
const primaryColumn = metadata.primaryColumns[i];
const propertyName = primaryColumn.propertyName;
keys[propertyName] = entity[propertyName];
}
return keys;
};
}
async update(entityClassOrName, options) {
const metadata = this.connection.getMetadata(entityClassOrName);
const changedValues = (0, DynamoObjectHelper_1.mixin)(options.setValues || {}, options.where);
(0, DynamoGlobalSecondaryIndexHelper_1.indexedColumns)(metadata, changedValues);
(0, DynamoObjectHelper_1.mixin)(options.setValues, changedValues);
delete options.setValues.id;
const params = DynamoParamHelper_1.dynamoParamHelper.update(metadata.tablePath, options);
return (0, DynamoClient_1.getDocumentClient)().update(params).promise();
}
/**
* Finds entities that match given find options or conditions.
*/
async find(entityClassOrName, options) {
if (options) {
const dbClient = (0, DynamoClient_1.getDocumentClient)();
const metadata = this.connection.getMetadata(entityClassOrName);
const params = DynamoParamHelper_1.dynamoParamHelper.find(metadata.tablePath, options, metadata.indices);
const results = (0, DynamoObjectHelper_1.isEmpty)(options.where)
? await dbClient.scan(params).promise()
: await dbClient.query(params).promise();
const items = results.Items || [];
items.lastEvaluatedKey = results.LastEvaluatedKey;
return items;
}
return [];
}
/**
* Finds entities that match given find options or conditions.
*/
async findAll(entityClassOrName, options) {
delete options.limit;
const dbClient = (0, DynamoClient_1.getDocumentClient)();
const metadata = this.connection.getMetadata(entityClassOrName);
const params = DynamoParamHelper_1.dynamoParamHelper.find(metadata.tablePath, options, metadata.indices);
let items = [];
let results = await dbClient.query(params).promise();
items = items.concat(results.Items || []);
while (results.LastEvaluatedKey) {
params.ExclusiveStartKey = results.LastEvaluatedKey;
results = await dbClient.query(params).promise();
items = items.concat(results.Items || []);
}
return items;
}
async scan(entityClassOrName, options) {
const dbClient = (0, DynamoClient_1.getDocumentClient)();
const metadata = this.connection.getMetadata(entityClassOrName);
const params = {
TableName: metadata.tablePath,
// IndexName: findOptions.index,
// KeyConditionExpression: FindOptions.toKeyConditionExpression(findOptions.where),
// ExpressionAttributeValues: FindOptions.toExpressionAttributeValues(findOptions.where)
};
if (options.limit) {
params.Limit = options.limit;
}
if (options.exclusiveStartKey) {
params.ExclusiveStartKey = options.exclusiveStartKey;
}
const results = await dbClient.scan(params).promise();
const items = results.Items || [];
items.LastEvaluatedKey = results.LastEvaluatedKey;
return items;
}
/**
* Finds first entity that matches given conditions and/or find options.
*/
async findOne(entityClass, options) {
const dbClient = (0, DynamoClient_1.getDocumentClient)();
const metadata = this.connection.getMetadata(entityClass);
const id = typeof options === "string" ? options : undefined;
const findOneOptionsOrConditions = options;
let findOptions;
if (FindOptionsUtils_1.FindOptionsUtils.isFindOneOptions(findOneOptionsOrConditions)) {
findOptions = new DynamoFindOptions_1.DynamoFindOptions();
findOptions.where = findOneOptionsOrConditions.where;
findOptions.limit = 1;
}
else {
findOptions = new DynamoFindOptions_1.DynamoFindOptions();
findOptions.where = { id };
findOptions.limit = 1;
}
const params = DynamoParamHelper_1.dynamoParamHelper.find(metadata.tablePath, findOptions, metadata.indices);
const results = await dbClient.query(params).promise();
const items = results.Items || [];
return items.length > 0 ? items[0] : undefined;
}
/**
* Finds first entity that matches given conditions and/or find options.
*/
async findOneBy(entityClass, options) {
const dbClient = (0, DynamoClient_1.getDocumentClient)();
const metadata = this.connection.getMetadata(entityClass);
const findOptions = new DynamoFindOptions_1.DynamoFindOptions();
findOptions.where = options;
findOptions.limit = 1;
const params = DynamoParamHelper_1.dynamoParamHelper.find(metadata.tablePath, findOptions, metadata.indices);
const results = await dbClient.query(params).promise();
const items = results.Items || [];
return items.length > 0 ? items[0] : undefined;
}
/**
* Put a given entity into the database.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Executes fast and efficient INSERT query.
* Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
* You can execute bulk inserts using this method.
*/
async put(target, entity) {
if (Array.isArray(entity)) {
return this.putMany(target, entity);
}
else {
return this.putOne(target, entity);
}
}
async delete(targetOrEntity, criteria) {
if (Array.isArray(criteria)) {
await this.deleteMany(targetOrEntity, criteria);
}
else {
await this.deleteOne(targetOrEntity, criteria);
}
return {
raw: {},
};
}
async deleteAll(target, options, keyMapper) {
let items = await this.scan(target, { limit: 500 });
while (items.length > 0) {
const itemIds = items.map(keyMapper || this.createDefaultKeyMapper(target));
await this.deleteMany(target, itemIds);
await this.deleteAll(target, keyMapper);
items = await this.scan(target, { limit: 500 });
}
}
deleteAllBy(target, options, keyMapper) {
options.limit = options.limit || 500;
return this.deleteQueryBatch(target, options, keyMapper);
}
async deleteQueryBatch(target, options, keyMapper) {
const items = await this.find(target, options);
if (items.length > 0) {
const metadata = this.connection.getMetadata(target);
keyMapper = keyMapper || DEFAULT_KEY_MAPPER;
const keys = items.map(keyMapper);
await this.deleteMany(metadata.tablePath, keys);
await this.deleteQueryBatch(target, options, keyMapper);
}
}
/**
* Delete multiple documents on DynamoDB.
*/
deleteMany(entityClassOrName, keys) {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.dynamodbQueryRunner.deleteMany(metadata.tablePath, keys);
}
/**
* Delete a document on DynamoDB.
*/
deleteOne(entityClassOrName, key) {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.dynamodbQueryRunner.deleteOne(metadata.tablePath, key);
}
/**
* Put an array of documents into DynamoDB.
*/
putMany(entityClassOrName, docs) {
const metadata = this.connection.getMetadata(entityClassOrName);
docs.forEach((doc) => {
(0, DynamoGlobalSecondaryIndexHelper_1.indexedColumns)(metadata, doc);
});
return this.dynamodbQueryRunner.putMany(metadata.tablePath, docs);
}
/**
* Put a single document into DynamoDB.
*/
putOne(entityClassOrName, doc) {
const metadata = this.connection.getMetadata(entityClassOrName);
(0, DynamoGlobalSecondaryIndexHelper_1.indexedColumns)(metadata, doc);
(0, DynamoGlobalSecondaryIndexHelper_1.populateGeneratedColumns)(metadata, doc);
return this.dynamodbQueryRunner.putOne(metadata.tablePath, doc);
}
/**
* Read from DynamoDB in batches.
*/
async batchRead(entityClassOrName, keys) {
const dbClient = (0, DynamoClient_1.getDocumentClient)();
const metadata = this.connection.getMetadata(entityClassOrName);
const batches = DynamoBatchHelper_1.dynamoBatchHelper.batch(keys, 100);
let items = [];
for (let i = 0; i < batches.length; i++) {
const batch = batches[i];
const requestItems = {};
requestItems[metadata.tablePath] = {
Keys: batch,
};
const response = await dbClient
.batchGet({
RequestItems: requestItems,
})
.promise();
if (response.Responses !== undefined) {
items = items.concat(response.Responses[metadata.tablePath]);
}
}
return items;
}
/**
* Put an array of documents into DynamoDB in batches.
*/
// TODO: ... how do we update the indexColumn values here ... ?
async batchWrite(entityClassOrName, writes) {
const dbClient = (0, DynamoClient_1.getDocumentClient)();
const metadata = this.connection.getMetadata(entityClassOrName);
const batches = DynamoBatchHelper_1.dynamoBatchHelper.batch(writes, 25);
for (let i = 0; i < batches.length; i++) {
const batch = batches[i];
const requestItems = {};
requestItems[metadata.tablePath] = batch.map((write) => {
const request = {};
request[write.type] = {
Item: write.item,
};
return request;
});
await dbClient
.batchWrite({
RequestItems: requestItems,
})
.promise();
}
}
}
exports.DynamoEntityManager = DynamoEntityManager;
//# sourceMappingURL=DynamoEntityManager.js.map