gristlabs_grist-core/app/common/DocLimits.ts
Dmitry S 51ff72c15e (core) Faster builds all around.
Summary:
Building:
- Builds no longer wait for tsc for either client, server, or test targets. All use esbuild which is very fast.
- Build still runs tsc, but only to report errors. This may be turned off with `SKIP_TSC=1` env var.
- Grist-core continues to build using tsc.
- Esbuild requires ES6 module semantics. Typescript's esModuleInterop is turned
  on, so that tsc accepts and enforces correct usage.
- Client-side code is watched and bundled by webpack as before (using esbuild-loader)

Code changes:
- Imports must now follow ES6 semantics: `import * as X from ...` produces a
  module object; to import functions or class instances, use `import X from ...`.
- Everything is now built with isolatedModules flag. Some exports were updated for it.

Packages:
- Upgraded browserify dependency, and related packages (used for the distribution-building step).
- Building the distribution now uses esbuild's minification. babel-minify is no longer used.

Test Plan: Should have no behavior changes, existing tests should pass, and docker image should build too.

Reviewers: georgegevoian

Reviewed By: georgegevoian

Subscribers: alexmojaki

Differential Revision: https://phab.getgrist.com/D3506
2022-07-04 10:42:40 -04:00

75 lines
2.4 KiB
TypeScript

import {ApiError} from 'app/common/ApiError';
import {APPROACHING_LIMIT_RATIO, DataLimitStatus, DocumentUsage, getUsageRatio} from 'app/common/DocUsage';
import {Features} from 'app/common/Features';
import moment from 'moment-timezone';
/**
* Error class indicating failure due to limits being exceeded.
*/
export class LimitExceededError extends ApiError {
constructor(message: string) {
super(message, 413);
}
}
export interface GetDataLimitStatusParams {
docUsage: DocumentUsage | null;
productFeatures: Features | undefined;
gracePeriodStart: Date | null;
}
/**
* Given a set of params that includes document usage, current product features, and
* a grace-period start (if any), returns the data limit status of a document.
*/
export function getDataLimitStatus(params: GetDataLimitStatusParams): DataLimitStatus {
const {docUsage, productFeatures, gracePeriodStart} = params;
const ratio = getDataLimitRatio(docUsage, productFeatures);
if (ratio > 1) {
const start = gracePeriodStart;
const days = productFeatures?.gracePeriodDays;
if (start && days && moment().diff(moment(start), 'days') >= days) {
return 'deleteOnly';
} else {
return 'gracePeriod';
}
} else if (ratio > APPROACHING_LIMIT_RATIO) {
return 'approachingLimit';
} else {
return null;
}
}
/**
* Given `docUsage` and `productFeatures`, returns the highest usage ratio
* across all data-related limits (currently only row count and data size).
*/
export function getDataLimitRatio(
docUsage: DocumentUsage | null,
productFeatures: Features | undefined
): number {
if (!docUsage) { return 0; }
const {rowCount, dataSizeBytes} = docUsage;
const maxRows = productFeatures?.baseMaxRowsPerDocument;
const maxDataSize = productFeatures?.baseMaxDataSizePerDocument;
const rowRatio = getUsageRatio(rowCount, maxRows);
const dataSizeRatio = getUsageRatio(dataSizeBytes, maxDataSize);
return Math.max(rowRatio, dataSizeRatio);
}
/**
* Maps `dataLimitStatus` status to an integer and returns it; larger integer
* values indicate a more "severe" status.
*
* Useful for relatively comparing the severity of two DataLimitStatus values.
*/
export function getSeverity(dataLimitStatus: DataLimitStatus): number {
switch (dataLimitStatus) {
case null: { return 0; }
case 'approachingLimit': { return 1; }
case 'gracePeriod': { return 2; }
case 'deleteOnly': { return 3; }
}
}