// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. import { RpcNullableBool, RpcNullableDouble, RpcNullableString, RpcNullableTimestamp } from '@azure/functions-core'; import { AzFuncSystemError } from '../errors'; import { isDefined } from '../utils/nonNull'; /** * Converts boolean input to an 'INullableBool' to be sent through the RPC layer. * Input that is not a boolean but is also not null or undefined logs a function app level warning. * @param nullable Input to be converted to an INullableBool if it is a valid boolean * @param propertyName The name of the property that the caller will assign the output to. Used for debugging. */ export function toNullableBool(nullable: boolean | undefined, propertyName: string): undefined | RpcNullableBool { if (typeof nullable === 'boolean') { return { value: nullable, }; } if (isDefined(nullable)) { throw new AzFuncSystemError( `A 'boolean' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } return undefined; } /** * Converts number or string that parses to a number to an 'INullableDouble' to be sent through the RPC layer. * Input that is not a valid number but is also not null or undefined logs a function app level warning. * @param nullable Input to be converted to an INullableDouble if it is a valid number * @param propertyName The name of the property that the caller will assign the output to. Used for debugging. */ export function toNullableDouble( nullable: number | string | undefined, propertyName: string ): undefined | RpcNullableDouble { if (typeof nullable === 'number') { return { value: nullable, }; } else if (typeof nullable === 'string') { if (!isNaN(Number(nullable))) { const parsedNumber = parseFloat(nullable); return { value: parsedNumber, }; } } if (isDefined(nullable)) { throw new AzFuncSystemError( `A 'number' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } return undefined; } /** * Converts string input to an 'INullableString' to be sent through the RPC layer. * Input that is not a string but is also not null or undefined logs a function app level warning. * @param nullable Input to be converted to an INullableString if it is a valid string * @param propertyName The name of the property that the caller will assign the output to. Used for debugging. */ export function toRpcString(nullable: string | undefined, propertyName: string): string { if (typeof nullable === 'string') { return nullable; } if (isDefined(nullable)) { throw new AzFuncSystemError( `A 'string' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } return ''; } /** * Converts string input to an 'INullableString' to be sent through the RPC layer. * Input that is not a string but is also not null or undefined logs a function app level warning. * @param nullable Input to be converted to an INullableString if it is a valid string * @param propertyName The name of the property that the caller will assign the output to. Used for debugging. */ export function toNullableString(nullable: string | undefined, propertyName: string): undefined | RpcNullableString { if (typeof nullable === 'string') { return { value: nullable, }; } if (isDefined(nullable)) { throw new AzFuncSystemError( `A 'string' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } return undefined; } /** * Converts Date or number input to an 'INullableTimestamp' to be sent through the RPC layer. * Input that is not a Date or number but is also not null or undefined logs a function app level warning. * @param nullable Input to be converted to an INullableTimestamp if it is valid input * @param propertyName The name of the property that the caller will assign the output to. Used for debugging. */ export function toNullableTimestamp( dateTime: Date | number | undefined, propertyName: string ): RpcNullableTimestamp | undefined { if (isDefined(dateTime)) { try { const timeInMilliseconds = typeof dateTime === 'number' ? dateTime : dateTime.getTime(); if (timeInMilliseconds && timeInMilliseconds >= 0) { return { value: { seconds: Math.round(timeInMilliseconds / 1000), }, }; } } catch { throw new AzFuncSystemError( `A 'number' or 'Date' input was expected instead of a '${typeof dateTime}'. Cannot parse value of '${propertyName}'.` ); } } return undefined; }