"use strict"; const isDecimalStringNumber = require("./value-checks/string-number/is-decimal"); const isNegative = require("./value-checks/is-negative"); const fromDate = require("./type-adapters/from-date"); const fromTemporal = require("./type-adapters/from-temporal"); const getValueType = require("./get-value-type"); const coders = require("./coders"); // const forbiddenTypes = new Set([ // "function", "symbol" // ]); const allowedValueTypes = { bytes: { bytes: true }, string: { string: true }, boolean: { boolean: true }, decimal: { string: true }, date: { date: (value) => fromDate(value), temporalTime: (value) => fromTemporal(value) }, duration: { temporalDuration: true // TODO: Convert to internal data structure }, integer: { integer: (value) => BigInt(value), bigint: true, // TODO: Allow string inputs here, eventually? }, float: { float: true }, json: { array: true, object: true, string: true, integer: true, float: true } }; // FIXME: Deal with index key length restrictions, as well as value blob length restrictions? module.exports = function encodeField(options) { let { name, value, fieldType, required, signed, ... coderOptions } = options; let typeConverters = allowedValueTypes[fieldType]; let valueType = getValueType(value); let isNumericType = (fieldType === "integer" || fieldType === "float" || fieldType === "decimal"); // FIXME: Error types if (fieldType === "json" || fieldType === "float") { throw new Error(`Property '${name}' is of the '${fieldType}' type, but support for this is not yet implemented`); } else if (required === true && valueType === "null") { throw new Error(`Property '${name}' is required`); } else if (typeConverters[valueType] == null) { let typeString = Object.keys(typeConverters).map((type) => `'${type}'`).join(", "); throw new Error(`Value for property '${name}' should be one of types [${typeString}], but encountered '${valueType}' instead`); } else { let valueHandler = typeConverters[valueType]; let normalizedValue = (valueHandler === true) ? value : valueHandler(value); if (fieldType === "decimal" && !isDecimalStringNumber(normalizedValue)) { throw new Error(`Value for property '${name}' must be a string decimal`); } else if (typeof normalizedValue === "number" && Number.isNaN(normalizedValue)) { throw new Error(`NaN is not an allowed value for property '${name}'`); } else if (isNumericType && !signed && isNegative(normalizedValue)) { // FIXME: Check number range as well? throw new Error(`Value for property '${name}' is negative, but this is not allowed`); } else { return coders.encode(fieldType, normalizedValue, coderOptions); } } };