const {
InvalidFieldError,
InvalidOptionsError,
InvalidParameterError
} = require('./errors')
function validateValue (fieldName, opts, val) {
const schema = opts.schema
const valueType = SCHEMA_TYPE_TO_JS_TYPE_MAP[schema.type]
// handle omitted value
if (val === undefined) {
if (opts.optional) {
return valueType
} else {
throw new InvalidFieldError(fieldName, 'missing required value')
}
}
// validate the value against the provided schema
opts.assertValid(val)
return valueType
}
const SCHEMA_TYPE_TO_JS_TYPE_MAP = {
array: Array,
boolean: Boolean,
integer: Number,
number: Number,
float: Number,
object: Object,
string: String
}
/**
* Returns a string which uniquely identifies an item.
* @param {Model} modelCls the Model for the item
* @param {string} _id the item's partition key
* @param {string} [_sk] the item's sort key
*/
function makeItemString (modelCls, _id, _sk) {
const arr = [modelCls.tableName, _id]
if (_sk !== undefined) {
arr.push(_sk)
}
return JSON.stringify(arr)
}
async function sleep (millis) {
return new Promise((resolve, reject) => {
setTimeout(resolve, millis)
})
}
function checkUnexpectedOptions (options, defaults) {
if (typeof options !== 'object') {
throw new InvalidParameterError('options', 'must be an object')
}
Object.keys(options).forEach(opt => {
if (!Object.prototype.hasOwnProperty.call(defaults, opt)) {
throw new InvalidOptionsError(opt, 'Unexpected option. ' +
`Valid options are ${Object.keys(defaults)}`)
}
const optionVal = options[opt]
const defaultVal = defaults[opt]
if (optionVal !== undefined &&
defaultVal !== undefined &&
typeof optionVal !== typeof defaultVal) {
throw new InvalidOptionsError(opt, 'Unexpected option. ' +
`Invalid type for option ${opt}. Expected ${typeof defaultVal}`)
}
})
}
function loadOptionDefaults (options, defaults) {
// istanbul ignore next
options = options || {}
checkUnexpectedOptions(options, defaults)
const retOptions = Object.assign({}, defaults)
return Object.assign(retOptions, options)
}
// sentinel values for different item creation methods
const ITEM_SOURCE = {
CREATE_OR_PUT: { isCreateOrPut: true, canBeCached: false },
CREATE: { isCreate: true, canBeCached: true },
DELETE: { isDelete: true, canBeCached: false }, // Delete by key creates a local model
GET: { isGet: true, canBeCached: true },
QUERY: { isQuery: true, canBeCached: true },
SCAN: { isScan: true, canBeCached: true },
UPDATE: { isUpdate: true, canBeCached: false }
}
const ITEM_SOURCES = new Set(Object.values(ITEM_SOURCE))
module.exports = {
checkUnexpectedOptions,
ITEM_SOURCE,
ITEM_SOURCES,
loadOptionDefaults,
makeItemString,
SCHEMA_TYPE_TO_JS_TYPE_MAP,
sleep,
validateValue
}