You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
80 lines
2.7 KiB
JavaScript
80 lines
2.7 KiB
JavaScript
"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);
|
|
}
|
|
}
|
|
|
|
};
|