electrodb-temp
Version:
A library to more easily create and interact with multiple entities and heretical relationships in dynamodb
310 lines (283 loc) • 7.31 kB
JavaScript
const lib = require("@aws-sdk/lib-dynamodb");
const util = require("@aws-sdk/util-dynamodb");
const { isFunction } = require("./validations");
const { ElectroError, ErrorCodes } = require("./errors");
const DocumentClientVersions = {
v2: "v2",
v3: "v3",
electro: "electro",
};
const unmarshallItem = (value) => {
const unmarshall = util.unmarshall || ((val) => val);
try {
value.Item = unmarshall(value.Item);
} catch (err) {
console.error("Internal Error: Failed to unmarshal input", err);
}
return value;
};
const v3Methods = ["send"];
const v2Methods = [
"get",
"put",
"update",
"delete",
"batchWrite",
"batchGet",
"scan",
"query",
"createSet",
"transactWrite",
"transactGet",
];
const supportedClientVersions = {
[DocumentClientVersions.v2]: v2Methods,
[DocumentClientVersions.v3]: v3Methods,
};
class DocumentClientV2Wrapper {
static init(client) {
return new DocumentClientV2Wrapper(client, lib);
}
constructor(client, lib) {
this.client = client;
this.lib = lib;
this.__v = "v2";
}
get(params) {
return this.client.get(params);
}
put(params) {
return this.client.put(params);
}
update(params) {
return this.client.update(params);
}
delete(params) {
return this.client.delete(params);
}
batchWrite(params) {
return this.client.batchWrite(params);
}
batchGet(params) {
return this.client.batchGet(params);
}
scan(params) {
return this.client.scan(params);
}
query(params) {
return this.client.query(params);
}
_transact(transactionRequest) {
let cancellationReasons;
transactionRequest.on("extractError", (response) => {
try {
cancellationReasons = JSON.parse(
response.httpResponse.body.toString(),
).CancellationReasons;
} catch (err) {}
});
return {
async promise() {
return transactionRequest.promise().catch((err) => {
if (err) {
if (Array.isArray(cancellationReasons)) {
return {
canceled: cancellationReasons.map((reason) => {
if (reason.Item) {
return unmarshallItem(reason);
}
return reason;
}),
};
}
throw err;
}
});
},
};
}
transactWrite(params) {
const transactionRequest = this.client.transactWrite(params);
return this._transact(transactionRequest);
}
transactGet(params) {
const transactionRequest = this.client.transactGet(params);
return this._transact(transactionRequest);
}
createSet(value, ...rest) {
if (Array.isArray(value)) {
return this.client.createSet(value, ...rest);
} else {
return this.client.createSet([value], ...rest);
}
}
}
class DocumentClientV3Wrapper {
static init(client) {
return new DocumentClientV3Wrapper(client, lib);
}
constructor(client, lib) {
this.client = client;
this.lib = lib;
this.__v = "v3";
}
promiseWrap(fn) {
return {
promise: async () => {
return fn();
},
};
}
get(params) {
return this.promiseWrap(() => {
const command = new this.lib.GetCommand(params);
return this.client.send(command);
});
}
put(params) {
return this.promiseWrap(() => {
const command = new this.lib.PutCommand(params);
return this.client.send(command);
});
}
update(params) {
return this.promiseWrap(() => {
const command = new this.lib.UpdateCommand(params);
return this.client.send(command);
});
}
delete(params) {
return this.promiseWrap(async () => {
const command = new this.lib.DeleteCommand(params);
return this.client.send(command);
});
}
batchWrite(params) {
return this.promiseWrap(async () => {
const command = new this.lib.BatchWriteCommand(params);
return this.client.send(command);
});
}
batchGet(params) {
return this.promiseWrap(async () => {
const command = new this.lib.BatchGetCommand(params);
return this.client.send(command);
});
}
scan(params) {
return this.promiseWrap(async () => {
const command = new this.lib.ScanCommand(params);
return this.client.send(command);
});
}
query(params) {
return this.promiseWrap(async () => {
const command = new this.lib.QueryCommand(params);
return this.client.send(command);
});
}
transactWrite(params) {
return this.promiseWrap(async () => {
const command = new this.lib.TransactWriteCommand(params);
return this.client
.send(command)
.then((result) => {
return result;
})
.catch((err) => {
if (err.CancellationReasons) {
return {
canceled: err.CancellationReasons.map((reason) => {
if (reason.Item) {
return unmarshallItem(reason);
}
return reason;
}),
};
}
throw err;
});
});
}
transactGet(params) {
return this.promiseWrap(async () => {
const command = new this.lib.TransactGetCommand(params);
return this.client
.send(command)
.then((result) => {
return result;
})
.catch((err) => {
if (err.CancellationReasons) {
return {
canceled: err.CancellationReasons.map((reason) => {
if (reason.Item) {
return unmarshallItem(reason);
}
return reason;
}),
};
}
throw err;
});
});
}
createSet(value) {
if (Array.isArray(value)) {
return new Set(value);
} else {
return new Set([value]);
}
}
}
function identifyClientVersion(client = {}) {
if (
client instanceof DocumentClientV3Wrapper ||
client instanceof DocumentClientV2Wrapper
) {
return DocumentClientVersions.electro;
}
for (const [version, methods] of Object.entries(supportedClientVersions)) {
const hasMethods = methods.every((method) => {
return method in client && isFunction(client[method]);
});
if (hasMethods) {
return version;
}
}
}
function normalizeClient(client) {
if (client === undefined) return client;
const version = identifyClientVersion(client);
switch (version) {
case DocumentClientVersions.v3:
return DocumentClientV3Wrapper.init(client);
case DocumentClientVersions.v2:
return DocumentClientV2Wrapper.init(client);
case DocumentClientVersions.electro:
return client;
default:
throw new ElectroError(
ErrorCodes.InvalidClientProvided,
"Invalid DynamoDB Document Client provided. ElectroDB supports the v2 and v3 DynamoDB Document Clients from the aws-sdk",
);
}
}
function normalizeConfig(config = {}) {
return {
...config,
client: normalizeClient(config.client),
};
}
module.exports = {
util,
v2Methods,
v3Methods,
normalizeClient,
normalizeConfig,
identifyClientVersion,
DocumentClientVersions,
supportedClientVersions,
DocumentClientV3Wrapper,
DocumentClientV2Wrapper,
};