diff --git a/lib/connect-dynamodb.js b/lib/connect-dynamodb.js index 82f3694..cc29a1a 100644 --- a/lib/connect-dynamodb.js +++ b/lib/connect-dynamodb.js @@ -94,7 +94,7 @@ module.exports = function (connect) { this.initialized = true; }) .catch((err) => { - if (err.name == 'ResourceNotFoundException') { + if (err.name == "ResourceNotFoundException") { return this.createSessionsTable().then(() => { this.initialized = true; }); @@ -226,10 +226,11 @@ module.exports = function (connect) { const missingKeys = []; this.specialKeys.forEach((key) => { - if (typeof sess[key.name] !== "undefined") { + const value = getNestedValue(sess, key.name); + if (value != undefined) { const item = {}; - item[key.type] = sess[key.name]; - params.Item[key.name] = item; + item[key.type] = value; + params.Item[toCamelCase(key.name)] = item; } else { missingKeys.push(key.name); } @@ -250,6 +251,24 @@ module.exports = function (connect) { }); }; + function toCamelCase(name) { + const parts = name.split("."); + return parts + .map((part, idx) => { + if (idx === 0) { + return part; + } + return part.charAt(0).toUpperCase() + part.slice(1); + }) + .join(""); + } + + function getNestedValue(sess, path) { + return path.split(".").reduce((current, key) => { + return current && current[key] !== undefined ? current[key] : undefined; + }, sess); + } + /** * Cleans up expired sessions * @@ -346,7 +365,7 @@ module.exports = function (connect) { const now = Math.floor(Date.now() / 1000); const expires = typeof sess.cookie.maxAge === "number" - ? now + (sess.cookie.maxAge / 1000) + ? now + sess.cookie.maxAge / 1000 : now + oneDayInSeconds; return expires; }; diff --git a/test/test.js b/test/test.js index 66b23f7..4395d7c 100644 --- a/test/test.js +++ b/test/test.js @@ -6,6 +6,7 @@ const { CreateTableCommand, DeleteTableCommand, ScalarAttributeType, + GetItemCommand, } = require("@aws-sdk/client-dynamodb"); const ConnectDynamoDB = require(__dirname + "/../lib/connect-dynamodb.js"); @@ -41,6 +42,17 @@ describe("DynamoDBStore", () => { const store = new DynamoDBStore({ client: client, table: tableName, + specialKeys: [ + { + name: "flat", + type: "S", + }, + { + name: "nested.value", + type: "S", + }, + ], + skipThrowMissingSpecialKeys: true, }); const sessionId = Math.random().toString(); @@ -328,6 +340,56 @@ describe("DynamoDBStore", () => { }).timeout(5000); }); + describe("SpecialKeys", () => { + const name = Math.random().toString(); + + before((done) => { + store.set( + sessionId, + { + cookie: { + maxAge: 2000, + }, + name, + flat: "flatValue", + nested: { + value: "nestedValue", + }, + }, + done + ); + }); + + it("should get data correctly", async () => { + return new Promise((resolve, reject) => { + const input = { + TableName: tableName, + Key: { + ["id"]: { + S: "sess:" + sessionId, + }, + }, + ConsistntRead: true, + }; + const command = new GetItemCommand(input); + client + .send(command) + .then((response) => { + response["Item"]["nestedValue"].should.eql({ S: "nestedValue" }); + response["Item"]["flat"].should.eql({ S: "flatValue" }); + + resolve(); + }) + .catch((err) => reject(err)); + }); + }); + + it("does not crash on invalid session object", async () => { + const session = store.getParsedSession({ Item: {} }); + should.not.exist(session); + }).timeout(4000); + }); + after(async () => { // await client.send(new DeleteTableCommand({ TableName: tableName })); });