@commodo/fields-storage-dynamodb
Version:
We're working hard to get all the docs in order. New articles will be added daily.
246 lines (201 loc) • 7.06 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _dynamodb = require("aws-sdk/clients/dynamodb");
var _BatchProcess = _interopRequireDefault(require("./BatchProcess"));
var _QueryGenerator = _interopRequireDefault(require("./QueryGenerator"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
const propertyIsPartOfUniqueKey = (property, keys) => {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (!key.unique) {
continue;
}
let fields = keys[i].fields;
if (!Array.isArray(fields)) {
continue;
}
for (let j = 0; j < fields.length; j++) {
let field = fields[j];
if (field.name === property) {
return true;
}
}
}
return false;
};
class DynamoDbDriver {
constructor({
documentClient,
tableName
} = {}) {
this.batchProcesses = {};
this.documentClient = documentClient || new _dynamodb.DocumentClient();
this.tableName = tableName;
}
getClient() {
return this.documentClient;
}
async create({
name,
data,
batch
}) {
if (!batch) {
return await this.documentClient.put({
TableName: this.tableName || name,
Item: data
}).promise();
}
const batchProcess = this.getBatchProcess(batch);
batchProcess.addOperation("PutRequest", {
TableName: this.tableName || name,
Item: data
});
if (batchProcess.allOperationsAdded()) {
batchProcess.execute();
batchProcess.markAsReady();
} else {
await batchProcess.waitForOperationsAdded();
}
await batchProcess.waitForQueryExecution();
return true;
}
async update({
query,
data,
name,
batch,
instance,
keys
}) {
if (!batch) {
const update = {
UpdateExpression: "SET ",
ExpressionAttributeNames: {},
ExpressionAttributeValues: {}
};
const updateExpression = [];
for (const key in data) {
updateExpression.push(`#${key} = :${key}`);
update.ExpressionAttributeNames[`#${key}`] = key;
update.ExpressionAttributeValues[`:${key}`] = data[key];
}
update.UpdateExpression += updateExpression.join(", ");
return await this.documentClient.update(_objectSpread({
TableName: this.tableName || name,
Key: query
}, update)).promise();
}
const batchProcess = this.getBatchProcess(batch); // It would be nice if we could rely on the received data all the time, but that's not possible. Because
// "PutRequest" operations only insert or overwrite existing data (meaning => classic updates are NOT allowed),
// we must get complete model data, and use that in the operation. This is possible only if the update
// call is part of an model instance update (not part of SomeModel.save() call), where we can access the
// toStorage function. So, if that's the case, we'll call it with the skipDifferenceCheck flag enabled.
// Normally we wouldn't have to do all of this dancing, but it's how DynamoDB works, there's no way around it.
const storageData = instance ? await instance.toStorage({
skipDifferenceCheck: true
}) : data; // The only problem with the above approach is that it may insert null values into GSI columns,
// which immediately gets rejected by DynamoDB. Let's remove those here.
const Item = {};
for (let property in storageData) {
// Check if key is a part of a unique index. If so, and is null, remove it from data.
if (!propertyIsPartOfUniqueKey(property, keys)) {
Item[property] = storageData[property];
continue;
}
if (storageData[property] !== null) {
Item[property] = storageData[property];
}
}
batchProcess.addOperation("PutRequest", {
TableName: this.tableName || name,
Item
});
if (batchProcess.allOperationsAdded()) {
batchProcess.execute();
batchProcess.markAsReady();
} else {
await batchProcess.waitForOperationsAdded();
}
await batchProcess.waitForQueryExecution();
return true;
}
async delete({
query,
name,
batch
}) {
if (!batch) {
return await this.documentClient.delete({
TableName: this.tableName || name,
Key: query
}).promise();
}
const batchProcess = this.getBatchProcess(batch);
batchProcess.addOperation("DeleteRequest", {
TableName: this.tableName || name,
Key: query
});
if (batchProcess.allOperationsAdded()) {
batchProcess.execute();
batchProcess.markAsReady();
} else {
await batchProcess.waitForOperationsAdded();
}
await batchProcess.waitForQueryExecution();
return true;
}
async find({
name,
query,
sort,
limit,
batch,
keys
}) {
if (!batch) {
const queryGenerator = new _QueryGenerator.default();
const queryParams = queryGenerator.generate({
query,
keys,
sort,
limit,
table: this.tableName || name
});
const {
Items
} = await this.documentClient.query(queryParams).promise();
return [Items];
}
const batchProcess = this.getBatchProcess(batch);
batchProcess.addOperation("DeleteRequest", {
Key: query
});
if (batchProcess.allOperationsAdded()) {
batchProcess.execute();
batchProcess.markAsReady();
} else {
await batchProcess.waitForOperationsAdded();
}
await batchProcess.waitForQueryExecution();
return true;
}
async count() {
throw new Error(`Cannot run "count" operation - not supported.`);
}
getBatchProcess(batch) {
if (!this.batchProcesses[batch.id]) {
this.batchProcesses[batch.id] = new _BatchProcess.default(batch, this.documentClient);
}
return this.batchProcesses[batch.id];
}
}
var _default = DynamoDbDriver;
exports.default = _default;
//# sourceMappingURL=DynamoDbDriver.js.map