2020-05-25 21:30:55 -05:00
import * as AutoPilotUtils from "../Utils/AutoPilotUtils" ;
import * as Constants from "../Shared/Constants" ;
2020-12-18 16:15:55 -08:00
interface ComputeRUUsagePriceHourlyArgs {
serverId : string ;
requestUnits : number ;
numberOfRegions : number ;
multimasterEnabled : boolean ;
isAutoscale : boolean ;
}
export const estimatedCostDisclaimer =
"*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account" ;
2020-05-25 21:30:55 -05:00
/ * *
* Anything that is not a number should return 0
* Otherwise , return numberOfRegions
* @param number
* /
2020-08-06 10:56:40 -07:00
export function normalizeNumber ( number : null | undefined | string | number ) : number {
if ( ! number ) {
return 0 ;
}
return Math . floor ( Number ( number ) ) ;
2020-05-25 21:30:55 -05:00
}
2020-10-29 11:26:37 -05:00
export function getRuToolTipText ( ) : string {
2020-05-25 21:30:55 -05:00
return ` Set the throughput — Request Units per second (RU/s) — required for the workload. A read of a 1 KB document uses 1 RU. Select manual if you plan to scale RU/s yourself. Select autoscale to allow the system to scale RU/s based on usage. ` ;
}
/ * *
* For anything other than a numbers or numbers <= 0 , should return 0
* Otherwise , return numberOfRegions
* @param numberOfRegions
* /
export function getRegionMultiplier ( numberOfRegions : number , multimasterEnabled : boolean ) : number {
const normalizedNumberOfRegions : number = normalizeNumber ( numberOfRegions ) ;
if ( normalizedNumberOfRegions <= 0 ) {
return 0 ;
}
if ( numberOfRegions === 1 ) {
return numberOfRegions ;
}
if ( multimasterEnabled ) {
return numberOfRegions + 1 ;
}
return numberOfRegions ;
}
export function getMultimasterMultiplier ( numberOfRegions : number , multimasterEnabled : boolean ) : number {
const regionMultiplier : number = getRegionMultiplier ( numberOfRegions , multimasterEnabled ) ;
const multimasterMultiplier : number = ! multimasterEnabled ? 1 : regionMultiplier > 1 ? 2 : 1 ;
return multimasterMultiplier ;
}
2020-12-18 16:15:55 -08:00
export function computeRUUsagePriceHourly ( {
serverId ,
requestUnits ,
numberOfRegions ,
multimasterEnabled ,
isAutoscale
} : ComputeRUUsagePriceHourlyArgs ) : number {
2020-05-25 21:30:55 -05:00
const regionMultiplier : number = getRegionMultiplier ( numberOfRegions , multimasterEnabled ) ;
const multimasterMultiplier : number = getMultimasterMultiplier ( numberOfRegions , multimasterEnabled ) ;
2020-12-18 16:15:55 -08:00
const pricePerRu = isAutoscale ? getAutoscalePricePerRu ( serverId , multimasterMultiplier ) : getPricePerRu ( serverId ) ;
2020-05-25 21:30:55 -05:00
const ruCharge = requestUnits * pricePerRu * multimasterMultiplier * regionMultiplier ;
2020-11-30 23:06:38 -08:00
return Number ( ruCharge . toFixed ( 5 ) ) ;
2020-05-25 21:30:55 -05:00
}
export function getPriceCurrency ( serverId : string ) : string {
if ( serverId === "mooncake" ) {
return Constants . OfferPricing . HourlyPricing . mooncake . Currency ;
}
return Constants . OfferPricing . HourlyPricing . default . Currency ;
}
export function computeStorageUsagePrice ( serverId : string , storageUsedRoundUpToGB : number ) : string {
if ( serverId === "mooncake" ) {
2020-08-06 10:56:40 -07:00
const storageCharge = storageUsedRoundUpToGB * Constants . OfferPricing . HourlyPricing . mooncake . Standard . PricePerGB ;
2020-05-25 21:30:55 -05:00
return calculateEstimateNumber ( storageCharge ) + " " + Constants . OfferPricing . HourlyPricing . mooncake . Currency ;
}
2020-08-06 10:56:40 -07:00
const storageCharge = storageUsedRoundUpToGB * Constants . OfferPricing . HourlyPricing . default . Standard . PricePerGB ;
2020-05-25 21:30:55 -05:00
return calculateEstimateNumber ( storageCharge ) + " " + Constants . OfferPricing . HourlyPricing . default . Currency ;
}
export function computeDisplayUsageString ( usageInKB : number ) : string {
2020-08-06 10:56:40 -07:00
const usageInMB = usageInKB / 1024 ,
2020-05-25 21:30:55 -05:00
usageInGB = usageInMB / 1024 ,
displayUsageString =
usageInGB > 0.1
? usageInGB . toFixed ( 2 ) + " GB"
: usageInMB > 0.1
? usageInMB . toFixed ( 2 ) + " MB"
: usageInKB . toFixed ( 2 ) + " KB" ;
return displayUsageString ;
}
export function usageInGB ( usageInKB : number ) : number {
2020-08-06 10:56:40 -07:00
const usageInMB = usageInKB / 1024 ,
2020-05-25 21:30:55 -05:00
usageInGB = usageInMB / 1024 ;
return Math . ceil ( usageInGB ) ;
}
export function calculateEstimateNumber ( n : number ) : string {
return n >= 1 ? n . toFixed ( 2 ) : n . toPrecision ( 2 ) ;
}
2020-08-06 10:56:40 -07:00
export function numberWithCommasFormatter ( n : number ) : string {
2020-05-25 21:30:55 -05:00
return n . toString ( ) . replace ( /\B(?=(\d{3})+(?!\d))/g , "," ) ;
}
export function isLargerThanDefaultMinRU ( ru : number ) : boolean {
if ( typeof ru === "number" && ru > Constants . CollectionCreation . DefaultCollectionRUs400 ) {
return true ;
}
return false ;
}
export function getCurrencySign ( serverId : string ) : string {
if ( serverId === "mooncake" ) {
return Constants . OfferPricing . HourlyPricing . mooncake . CurrencySign ;
}
return Constants . OfferPricing . HourlyPricing . default . CurrencySign ;
}
export function getAutoscalePricePerRu ( serverId : string , mmMultiplier : number ) : number {
if ( serverId === "mooncake" ) {
if ( mmMultiplier > 1 ) {
return Constants . AutoscalePricing . HourlyPricing . mooncake . multiMaster . Standard . PricePerRU ;
} else {
return Constants . AutoscalePricing . HourlyPricing . mooncake . singleMaster . Standard . PricePerRU ;
}
}
if ( mmMultiplier > 1 ) {
return Constants . AutoscalePricing . HourlyPricing . default . multiMaster . Standard . PricePerRU ;
} else {
return Constants . AutoscalePricing . HourlyPricing . default . singleMaster . Standard . PricePerRU ;
}
}
export function getPricePerRu ( serverId : string ) : number {
if ( serverId === "mooncake" ) {
return Constants . OfferPricing . HourlyPricing . mooncake . Standard . PricePerRU ;
}
return Constants . OfferPricing . HourlyPricing . default . Standard . PricePerRU ;
}
export function getAutoPilotV3SpendHtml ( maxAutoPilotThroughputSet : number , isDatabaseThroughput : boolean ) : string {
if ( ! maxAutoPilotThroughputSet ) {
return "" ;
}
const resource : string = isDatabaseThroughput ? "database" : "container" ;
return ` Your ${ resource } throughput will automatically scale from <b> ${ AutoPilotUtils . getMinRUsBasedOnUserInput (
maxAutoPilotThroughputSet
) } RU / s ( 10 % of max RU / s ) - $ { maxAutoPilotThroughputSet } RU / s < / b > based on usage . < br / > < br / > After the first $ { AutoPilotUtils . getStorageBasedOnUserInput (
maxAutoPilotThroughputSet
) } GB of data stored , the max RU / s will be automatically upgraded based on the new storage value . < a href = ' $ {
Constants . AutopilotDocumentation . Url
2020-09-08 11:03:48 -07:00
} ' target=' _blank ' aria-label=' Learn more about autoscale throughput ' > Learn more < / a > . ` ;
2020-05-25 21:30:55 -05:00
}
export function getEstimatedAutoscaleSpendHtml (
throughput : number ,
serverId : string ,
regions : number ,
multimaster : boolean
) : string {
2020-12-18 16:15:55 -08:00
const hourlyPrice : number = computeRUUsagePriceHourly ( {
serverId : serverId ,
requestUnits : throughput ,
numberOfRegions : regions ,
multimasterEnabled : multimaster ,
isAutoscale : true
} ) ;
2020-05-25 21:30:55 -05:00
const monthlyPrice : number = hourlyPrice * Constants . hoursInAMonth ;
const currency : string = getPriceCurrency ( serverId ) ;
const currencySign : string = getCurrencySign ( serverId ) ;
const pricePerRu =
getAutoscalePricePerRu ( serverId , getMultimasterMultiplier ( regions , multimaster ) ) *
getMultimasterMultiplier ( regions , multimaster ) ;
return (
` Estimated monthly cost ( ${ currency } ): <b> ` +
` ${ currencySign } ${ calculateEstimateNumber ( monthlyPrice / 10 ) } - ` +
` ${ currencySign } ${ calculateEstimateNumber ( monthlyPrice ) } </b> ` +
` ( ${ regions } ${ regions === 1 ? "region" : "regions" } , ${ throughput /
10 } - $ { throughput } RU / s , $ { currencySign } $ { pricePerRu } / RU ) `
) ;
}
export function getEstimatedSpendHtml (
throughput : number ,
serverId : string ,
regions : number ,
2020-11-30 23:06:38 -08:00
multimaster : boolean
2020-05-25 21:30:55 -05:00
) : string {
2020-12-18 16:15:55 -08:00
const hourlyPrice : number = computeRUUsagePriceHourly ( {
serverId : serverId ,
requestUnits : throughput ,
numberOfRegions : regions ,
multimasterEnabled : multimaster ,
isAutoscale : false
} ) ;
2020-05-25 21:30:55 -05:00
const dailyPrice : number = hourlyPrice * 24 ;
const monthlyPrice : number = hourlyPrice * Constants . hoursInAMonth ;
const currency : string = getPriceCurrency ( serverId ) ;
const currencySign : string = getCurrencySign ( serverId ) ;
const pricePerRu = getPricePerRu ( serverId ) * getMultimasterMultiplier ( regions , multimaster ) ;
return (
2020-12-11 10:06:43 -08:00
` Cost ( ${ currency } ): <b> ` +
2020-05-25 21:30:55 -05:00
` ${ currencySign } ${ calculateEstimateNumber ( hourlyPrice ) } hourly / ` +
` ${ currencySign } ${ calculateEstimateNumber ( dailyPrice ) } daily / ` +
` ${ currencySign } ${ calculateEstimateNumber ( monthlyPrice ) } monthly </b> ` +
2020-12-11 10:06:43 -08:00
` ( ${ regions } ${ regions === 1 ? "region" : "regions" } , ${ throughput } RU/s, ${ currencySign } ${ pricePerRu } /RU) ` +
` <p style='padding: 10px 0px 0px 0px;'> ` +
2020-12-18 16:15:55 -08:00
` <em> ${ estimatedCostDisclaimer } </em></p> `
2020-05-25 21:30:55 -05:00
) ;
}
export function getEstimatedSpendAcknowledgeString (
throughput : number ,
serverId : string ,
regions : number ,
multimaster : boolean ,
isAutoscale : boolean
) : string {
2020-12-18 16:15:55 -08:00
const hourlyPrice : number = computeRUUsagePriceHourly ( {
serverId : serverId ,
requestUnits : throughput ,
numberOfRegions : regions ,
multimasterEnabled : multimaster ,
isAutoscale : isAutoscale
} ) ;
2020-05-25 21:30:55 -05:00
const dailyPrice : number = hourlyPrice * 24 ;
const monthlyPrice : number = hourlyPrice * Constants . hoursInAMonth ;
const currencySign : string = getCurrencySign ( serverId ) ;
return ! isAutoscale
? ` I acknowledge the estimated ${ currencySign } ${ calculateEstimateNumber (
dailyPrice
) } daily cost for the throughput above . `
: ` I acknowledge the estimated ${ currencySign } ${ calculateEstimateNumber (
monthlyPrice / 10
) } - $ { currencySign } $ { calculateEstimateNumber ( monthlyPrice ) } monthly cost for the throughput above . ` ;
}
2020-08-06 10:56:40 -07:00
export function getUpsellMessage ( serverId = "default" , isFreeTier = false ) : string {
2020-07-08 10:02:47 -07:00
if ( isFreeTier ) {
2020-08-06 10:56:40 -07:00
return "With free tier discount, you'll get the first 400 RU/s and 5 GB of storage in this account for free. Charges will apply if your resource throughput exceeds 400 RU/s." ;
2020-07-08 10:02:47 -07:00
} else {
let price : number = Constants . OfferPricing . MonthlyPricing . default . Standard . StartingPrice ;
2020-05-25 21:30:55 -05:00
2020-07-08 10:02:47 -07:00
if ( serverId === "mooncake" ) {
price = Constants . OfferPricing . MonthlyPricing . mooncake . Standard . StartingPrice ;
}
2020-05-25 21:30:55 -05:00
2020-07-08 10:02:47 -07:00
return ` Start at ${ getCurrencySign ( serverId ) } ${ price } /mo per database, multiple containers included ` ;
}
2020-05-25 21:30:55 -05:00
}