Repository: jeremydaly/dynamodb-toolbox
Pull request #88 (2020-09-30 23:50:17)

Getkey handling falsy keys
When I was experimenting with the toolbox my data model used the sk for widget versions where version 0 was the master version. getKey complained that sk was required, even though number 0 is allowed for sort keys. The problem in the getKey function was that it was expecting non falsy keys. So I wrote some specs and fixed the getKey function.


Patch:
diff --git a/.eslintrc.json b/.eslintrc.json
index a95c8402..f55dc0a1 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,7 +1,8 @@
 {
   "env": {
       "es6": true,
-      "node": true
+      "node": true,
+      "jest": true
   },
   "extends": "eslint:recommended",
   "parserOptions": {
@@ -9,10 +10,6 @@
       "sourceType": "module"
   },
   "rules": {
-      "indent": [
-          "error",
-          2
-      ],
       "linebreak-style": [
           "error",
           "unix"
diff --git a/lib/getKey.js b/lib/getKey.js
index 89eb4f3c..fc17d13e 100644
--- a/lib/getKey.js
+++ b/lib/getKey.js
@@ -19,11 +19,15 @@ module.exports = (DocumentClient) => (data,schema,partitionKey,sortKey) => {
   // Intialize validate type
   let validateType = validateTypes(DocumentClient)
 
-  let pk = data[partitionKey] ||
-      error(`'${partitionKey}'${schema[partitionKey].alias ? ` or '${schema[partitionKey].alias}'` : ''} is required`)
-
-  let sk = sortKey === null || data[sortKey] ||
-      error(`'${sortKey}'${schema[sortKey].alias ? ` or '${schema[sortKey].alias}'` : ''} is required`)
+  let pk = data[partitionKey]
+  if (pk === undefined || pk === null || pk === '') {
+    error(`'${partitionKey}'${schema[partitionKey].alias ? ` or '${schema[partitionKey].alias}'` : ''} is required`)
+  }
+
+  const sk = data[sortKey]
+  if (sortKey && (sk === undefined || sk === null || sk === '')) {
+    error(`'${sortKey}'${schema[sortKey].alias ? ` or '${schema[sortKey].alias}'` : ''} is required`)
+  }
 
   return Object.assign(
     { [partitionKey]: transformAttr(schema[partitionKey],validateType(schema[partitionKey],partitionKey,pk,data),data) },


Test patch:
diff --git a/__tests__/lib/getKey.unit.test.js b/__tests__/lib/getKey.unit.test.js
new file mode 100644
index 00000000..944ec889
--- /dev/null
+++ b/__tests__/lib/getKey.unit.test.js
@@ -0,0 +1,177 @@
+const getKey = require('../../lib/getKey')
+
+describe('getKey', () => {
+  describe('pk', () => {
+    describe('is a string', () => {
+      it('returns the pk data in an object', () => {
+        const data = { pk: 'id1' }
+        const schema = {
+          pk: { partitionKey: true, type: 'string', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk')
+  
+        expect(result).toEqual({ pk: 'id1' })
+      })
+
+      it('can not be empty, its an AWS Dynamodb thing', () => {
+        const data = { pk: '' }
+        const schema = {
+          pk: { partitionKey: true, type: 'string', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        expect(() => getKey(dummyDocumentClient)(data, schema, 'pk')).toThrow(new Error('\'pk\' is required'))
+      })
+    })
+
+    describe('can be a number', () => {
+      it('returns the pk data', () => {
+        const data = { pk: 123 }
+        const schema = {
+          pk: { partitionKey: true, type: 'number', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk')
+  
+        expect(result).toEqual({ pk: 123 })
+      })
+
+      it('can be 0', () => {
+        const data = { pk: 0 }
+        const schema = {
+          pk: { partitionKey: true, type: 'number', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk')
+  
+        expect(result).toEqual({ pk: 0 })
+      })
+
+      it('can coerce from string', () => {
+        const data = { pk: '123' }
+        const schema = {
+          pk: { partitionKey: true, type: 'number', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk')
+  
+        expect(result).toEqual({ pk: 123 })
+      })
+    })
+
+    it('if no partitionKey in data will error', () => {
+      const data = {}
+      const schema = {
+        pk: { partitionKey: true, type: 'string', coerce: true },
+      }
+      const dummyDocumentClient = {}
+
+      expect(() => getKey(dummyDocumentClient)(data, schema, 'pk', 'sk')).toThrow(new Error('\'pk\' is required'))
+    })
+  })
+
+  describe('sk', () => {
+    it('returned object does not contain sort key if not required', () => {
+      const data = { pk: 'id1' }
+      const schema = {
+        pk: { partitionKey: true, type: 'string', coerce: true },
+      }
+      const dummyDocumentClient = {}
+
+      const result = getKey(dummyDocumentClient)(data, schema, 'pk')
+
+      expect(result).toEqual({
+        pk: 'id1'
+      })
+    })
+
+    describe('can be a string', () => {
+      it('returns the sk data', () => {
+        const data = { pk: 'id1', sk: 'sk1' }
+        const schema = {
+          pk: { partitionKey: true, type: 'string', coerce: true },
+          sk: { sortKey: true, type: 'string', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk', 'sk')
+  
+        expect(result).toEqual({ pk: 'id1', sk: 'sk1' })
+      })
+
+      it('can not be empty, its an AWS Dynamodb thing', () => {
+        const data = { pk: 'id1', sk: '' }
+        const schema = {
+          pk: { partitionKey: true, type: 'string', coerce: true },
+          sk: { sortKey: true, type: 'string', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        expect(() => getKey(dummyDocumentClient)(data, schema, 'pk', 'sk')).toThrow(new Error('\'sk\' is required'))
+      })
+    })
+
+    describe('can be a number', () => {
+      it('returns the sk data', () => {
+        const data = { pk: 'id1', sk: 5 }
+        const schema = {
+          pk: { partitionKey: true, type: 'string', coerce: true },
+          sk: { sortKey: true, type: 'number', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk', 'sk')
+  
+        expect(result).toEqual({ pk: 'id1', sk: 5 })
+      })
+  
+      it('can coerce sortKey string to number', () => {
+        const data = { pk: 'id1', sk: '5' }
+        const schema = {
+          pk: { partitionKey: true, type: 'string', coerce: true },
+          sk: { sortKey: true, type: 'number', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk', 'sk')
+  
+        expect(result).toEqual({
+          pk: 'id1',
+          sk: 5
+        })
+      })
+  
+      it('can be 0', () => {
+        const data = { pk: 'id1', sk: 0 }
+        const schema = {
+          pk: { partitionKey: true, type: 'string', coerce: true },
+          sk: { sortKey: true, type: 'number', coerce: true },
+        }
+        const dummyDocumentClient = {}
+  
+        const result = getKey(dummyDocumentClient)(data, schema, 'pk', 'sk')
+  
+        expect(result).toEqual({
+          pk: 'id1',
+          sk: 0
+        })
+      })
+    })
+
+    it('if no sortKey in data will error', () => {
+      const data = { pk: 'id1' }
+      const schema = {
+        pk: { partitionKey: true, type: 'string', coerce: true },
+        sk: { sortKey: true, type: 'number', coerce: true },
+      }
+      const dummyDocumentClient = {}
+
+      expect(() => getKey(dummyDocumentClient)(data, schema, 'pk', 'sk')).toThrow(new Error('\'sk\' is required'))
+    })
+  })
+})