Skip to content

Commit

Permalink
refactor(data-validation): data validation validator (#4141)
Browse files Browse the repository at this point in the history
  • Loading branch information
weird94 authored Nov 26, 2024
1 parent ae027eb commit ace8f93
Show file tree
Hide file tree
Showing 28 changed files with 204 additions and 479 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export * from './types/interfaces';
export * from './types/interfaces';
export type { ICellCustomRender, ICellRenderContext } from './types/interfaces/i-cell-custom-render';
export type { IDataValidationRule, IDataValidationRuleBase, IDataValidationRuleInfo, IDataValidationRuleOptions, ISheetDataValidationRule } from './types/interfaces/i-data-validation';
export { type IRTreeItem, RTree } from './shared/r-tree';
export { type BBox, type IRTreeItem, RBush, RTree } from './shared/r-tree';

export { type IUniverConfig, Univer } from './univer';
export { isNodeEnv } from './shared/tools';
2 changes: 2 additions & 0 deletions packages/core/src/shared/r-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,5 @@ export class RTree {
}
}
}

export { type BBox, RBush };
10 changes: 5 additions & 5 deletions packages/core/src/types/interfaces/i-data-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@
* limitations under the License.
*/

import type { DataValidationOperator } from '../enum/data-validation-operator';
import type { DataValidationType } from '../enum/data-validation-type';
import type { DataValidationImeMode } from '../enum/data-validation-ime-mode';
import type { IRange } from '../../sheets/typedef';
import type { DataValidationErrorStyle } from '../enum/data-validation-error-style';
import type { DataValidationImeMode } from '../enum/data-validation-ime-mode';
import type { DataValidationOperator } from '../enum/data-validation-operator';
import type { DataValidationRenderMode } from '../enum/data-validation-render-mode';
import type { IRange } from '../../sheets/typedef';
import type { DataValidationType } from '../enum/data-validation-type';

// TODO@weird94: should be moved outside of the or package

export interface IDataValidationRuleBase {
/**
* data validation type
*/
type: DataValidationType;
type: DataValidationType | string;
allowBlank?: boolean;
/**
* data validation creteria
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class DataValidatorRegistryService {
}
}

register(validator: BaseDataValidator<any>) {
register(validator: BaseDataValidator) {
this._validatorMap.set(validator.id, validator);

if (Array.isArray(validator.scopes)) {
Expand Down
99 changes: 71 additions & 28 deletions packages/data-validation/src/validators/base-data-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ export interface IFormulaValidResult {
formula2?: string;
}

export abstract class BaseDataValidator<DataType = CellValue> {
export abstract class BaseDataValidator {
abstract id: string;
abstract title: string;
abstract operators: DataValidationOperator[];
abstract scopes: string[] | string;

offsetFormulaByRange = true;

// #region UI related

formulaInput: string | undefined = undefined;
Expand Down Expand Up @@ -127,7 +129,7 @@ export abstract class BaseDataValidator<DataType = CellValue> {
return false;
}

abstract parseFormula(rule: IDataValidationRule, unitId: string, subUnitId: string, row: number, column: number): Promise<IFormulaResult>;
abstract parseFormula(rule: IDataValidationRule, unitId: string, subUnitId: string, row: number, column: number): Promise<IFormulaResult<number | undefined>>;

abstract validatorFormula(rule: IDataValidationRule, unitId: string, subUnitId: string): IFormulaValidResult;

Expand All @@ -142,41 +144,82 @@ export abstract class BaseDataValidator<DataType = CellValue> {
return true;
};

transform(cellInfo: IValidatorCellInfo, formula: IFormulaResult, rule: IDataValidationRule): IValidatorCellInfo<DataType> {
return cellInfo as IValidatorCellInfo<DataType>;
transform(cellInfo: IValidatorCellInfo, formula: IFormulaResult, rule: IDataValidationRule): IValidatorCellInfo<number> {
return cellInfo as IValidatorCellInfo<number>;
};

async validatorIsEqual(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
async validatorIsEqual(cellInfo: IValidatorCellInfo<CellValue>, formula: IFormulaResult, rule: IDataValidationRule) {
const { formula1 } = formula;
const { value: cellValue } = cellInfo;
if (Number.isNaN(formula1)) {
return true;
}

async validatorIsNotEqual(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
return cellValue === formula1;
}

async validatorIsBetween(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
async validatorIsNotEqual(cellInfo: IValidatorCellInfo<number>, formula: IFormulaResult, _rule: IDataValidationRule) {
const { formula1 } = formula;
if (Number.isNaN(formula1)) {
return true;
}

async validatorIsNotBetween(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
return cellInfo.value !== formula1;
}

async validatorIsGreaterThan(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
async validatorIsBetween(cellInfo: IValidatorCellInfo<number>, formula: IFormulaResult, _rule: IDataValidationRule) {
const { formula1, formula2 } = formula;
if (Number.isNaN(formula1) || Number.isNaN(formula2)) {
return true;
}

async validatorIsGreaterThanOrEqual(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
const start = Math.min(formula1, formula2);
const end = Math.max(formula1, formula2);
return cellInfo.value >= start && cellInfo.value <= end;
}

async validatorIsLessThan(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
async validatorIsNotBetween(cellInfo: IValidatorCellInfo<number>, formula: IFormulaResult, _rule: IDataValidationRule) {
const { formula1, formula2 } = formula;
if (Number.isNaN(formula1) || Number.isNaN(formula2)) {
return true;
}
const start = Math.min(formula1, formula2);
const end = Math.max(formula1, formula2);
return cellInfo.value < start || cellInfo.value > end;
}

async validatorIsLessThanOrEqual(cellInfo: IValidatorCellInfo<DataType>, formula: IFormulaResult, rule: IDataValidationRule): Promise<boolean> {
return true;
};
async validatorIsGreaterThan(cellInfo: IValidatorCellInfo<number>, formula: IFormulaResult, _rule: IDataValidationRule) {
const { formula1 } = formula;
if (Number.isNaN(formula1)) {
return true;
}
return cellInfo.value > formula1;
}

async validatorIsGreaterThanOrEqual(cellInfo: IValidatorCellInfo<number>, formula: IFormulaResult, _rule: IDataValidationRule) {
const { formula1 } = formula;
if (Number.isNaN(formula1)) {
return true;
}
return cellInfo.value >= formula1;
}

async validatorIsLessThan(cellInfo: IValidatorCellInfo<number>, formula: IFormulaResult, _rule: IDataValidationRule) {
const { formula1 } = formula;
if (Number.isNaN(formula1)) {
return true;
}
return cellInfo.value < formula1;
}

async validatorIsLessThanOrEqual(cellInfo: IValidatorCellInfo<number>, formula: IFormulaResult, _rule: IDataValidationRule) {
const { formula1 } = formula;
if (Number.isNaN(formula1)) {
return true;
}

return cellInfo.value <= formula1;
}

async validator(cellInfo: IValidatorCellInfo, rule: IDataValidationRule): Promise<boolean> {
const { value: cellValue, unitId, subUnitId } = cellInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,14 @@ export class DataValidationAutoFillController extends Disposable {
redos: redoMutations,
};
};
const disabledDataVallation = [
DataValidationType.CHECKBOX,
];
const hook: ISheetAutoFillHook = {
id: DATA_VALIDATION_PLUGIN_NAME,
onBeforeFillData: (location) => {
const { source: sourceRange, unitId, subUnitId } = location;
for (const row of sourceRange.rows) {
for (const col of sourceRange.cols) {
const dv = this._sheetDataValidationModel.getRuleByLocation(unitId, subUnitId, row, col);
if (dv && disabledDataVallation.indexOf(dv.type) > -1) {
if (dv && dv.type === DataValidationType.CHECKBOX) {
this._autoFillService.setDisableApplyType(APPLY_TYPE.SERIES, true);
return;
}
Expand Down
1 change: 0 additions & 1 deletion packages/sheets-data-validation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
"rxjs": ">=7.0.0"
},
"dependencies": {
"@flatten-js/interval-tree": "^1.1.3",
"@univerjs/core": "workspace:*",
"@univerjs/data-validation": "workspace:*",
"@univerjs/engine-formula": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { AddDataValidationMutation, DataValidatorRegistryService, getRuleOptions
import { LexerTreeBuilder } from '@univerjs/engine-formula';
import { getSheetCommandTarget, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets';
import { SheetDataValidationModel } from '../../models/sheet-data-validation-model';
import { isCustomFormulaType } from '../../utils/formula';
import { shouldOffsetFormulaByRange } from '../../utils/formula';
import { getStringCellValue } from '../../utils/get-cell-data-origin';
import { CHECKBOX_FORMULA_1, CHECKBOX_FORMULA_2, type CheckboxValidator } from '../../validators';

Expand Down Expand Up @@ -57,6 +57,7 @@ export function getDataValidationDiffMutations(
fillDefaultValue = true
) {
const lexerTreeBuilder = accessor.get(LexerTreeBuilder);
const validatorRegistryService = accessor.get(DataValidatorRegistryService);
const redoMutations: IMutationInfo[] = [];
const undoMutations: IMutationInfo[] = [];
const sheetDataValidationModel = accessor.get(SheetDataValidationModel);
Expand Down Expand Up @@ -115,7 +116,7 @@ export function getDataValidationDiffMutations(
});
break;
case 'update': {
if (isCustomFormulaType(diff.rule.type)) {
if (shouldOffsetFormulaByRange(diff.rule.type, validatorRegistryService)) {
const originRow = diff.oldRanges[0].startRow;
const originColumn = diff.oldRanges[0].startColumn;
const newRow = diff.newRanges[0].startRow;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
import type { IDisposable, IMutationInfo, ISheetDataValidationRule } from '@univerjs/core';
import type { IUpdateDataValidationMutationParams } from '@univerjs/data-validation';
import { Disposable, generateRandomId, Inject, toDisposable } from '@univerjs/core';
import { AddDataValidationMutation, RemoveDataValidationMutation, UpdateDataValidationMutation, UpdateRuleType } from '@univerjs/data-validation';
import { AddDataValidationMutation, DataValidatorRegistryService, RemoveDataValidationMutation, UpdateDataValidationMutation, UpdateRuleType } from '@univerjs/data-validation';
import { FormulaRefRangeService } from '@univerjs/sheets-formula';
import { SheetDataValidationModel } from '../models/sheet-data-validation-model';
import { isCustomFormulaType } from '../utils/formula';
import { shouldOffsetFormulaByRange } from '../utils/formula';

export class DataValidationFormulaRefRangeController extends Disposable {
private _disposableMap: Map<string, IDisposable> = new Map();

constructor(
@Inject(SheetDataValidationModel) private _dataValidationModel: SheetDataValidationModel,
@Inject(FormulaRefRangeService) private _formulaRefRangeService: FormulaRefRangeService
@Inject(FormulaRefRangeService) private _formulaRefRangeService: FormulaRefRangeService,
@Inject(DataValidatorRegistryService) private _validatorRegistryService: DataValidatorRegistryService
) {
super();
this._initRefRange();
Expand All @@ -38,7 +39,7 @@ export class DataValidationFormulaRefRangeController extends Disposable {
}

registerRule = (unitId: string, subUnitId: string, rule: ISheetDataValidationRule) => {
if (!isCustomFormulaType(rule.type)) {
if (!shouldOffsetFormulaByRange(rule.type, this._validatorRegistryService)) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ import type { ISheetDataValidationRule } from '@univerjs/core';
import type { IRemoveDataValidationMutationParams, IUpdateDataValidationMutationParams } from '@univerjs/data-validation';
import type { EffectRefRangeParams } from '@univerjs/sheets';
import { Disposable, Inject, Injector, isRangesEqual, toDisposable } from '@univerjs/core';
import { RemoveDataValidationMutation, UpdateDataValidationMutation, UpdateRuleType } from '@univerjs/data-validation';
import { DataValidatorRegistryService, RemoveDataValidationMutation, UpdateDataValidationMutation, UpdateRuleType } from '@univerjs/data-validation';
import { handleCommonDefaultRangeChangeWithEffectRefCommands, RefRangeService } from '@univerjs/sheets';
import { FormulaRefRangeService } from '@univerjs/sheets-formula';
import { removeDataValidationUndoFactory } from '../commands/commands/data-validation.command';
import { SheetDataValidationModel } from '../models/sheet-data-validation-model';
import { DataValidationCustomFormulaService } from '../services/dv-custom-formula.service';
import { DataValidationFormulaService } from '../services/dv-formula.service';
import { isCustomFormulaType } from '../utils/formula';
import { shouldOffsetFormulaByRange } from '../utils/formula';

export class DataValidationRefRangeController extends Disposable {
private _disposableMap: Map<string, Set<() => void>> = new Map();
Expand All @@ -34,9 +33,9 @@ export class DataValidationRefRangeController extends Disposable {
@Inject(SheetDataValidationModel) private _dataValidationModel: SheetDataValidationModel,
@Inject(Injector) private _injector: Injector,
@Inject(RefRangeService) private _refRangeService: RefRangeService,
@Inject(DataValidationCustomFormulaService) private _dataValidationCustomFormulaService: DataValidationCustomFormulaService,
@Inject(DataValidationFormulaService) private _dataValidationFormulaService: DataValidationFormulaService,
@Inject(FormulaRefRangeService) private _formulaRefRangeService: FormulaRefRangeService
@Inject(FormulaRefRangeService) private _formulaRefRangeService: FormulaRefRangeService,
@Inject(DataValidatorRegistryService) private _validatorRegistryService: DataValidatorRegistryService
) {
super();
this._initRefRange();
Expand All @@ -47,7 +46,7 @@ export class DataValidationRefRangeController extends Disposable {
}

registerRule = (unitId: string, subUnitId: string, rule: ISheetDataValidationRule) => {
if (isCustomFormulaType(rule.type)) {
if (shouldOffsetFormulaByRange(rule.type, this._validatorRegistryService)) {
return;
}
this.register(unitId, subUnitId, rule);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class FDataValidationBuilder {
*
* @returns {DataValidationType} The data validation type
*/
getCriteriaType(): DataValidationType {
getCriteriaType(): DataValidationType | string {
return this._rule.type;
}

Expand Down Expand Up @@ -438,7 +438,7 @@ export class FDataValidationBuilder {
* operator is a DataValidationOperator enum value, formula1 is the first formula, and formula2 is the second formula.
* @return The current instance of the FDataValidationBuilder class, allowing for method chaining.
*/
withCriteriaValues(type: DataValidationType, values: [DataValidationOperator, string, string]): this {
withCriteriaValues(type: DataValidationType | string, values: [DataValidationOperator, string, string]): this {
this._rule.type = type;
this._rule.operator = values[0];
this._rule.formula1 = values[1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class FDataValidation {
*
* @returns The data validation type
*/
getCriteriaType(): DataValidationType {
getCriteriaType(): DataValidationType | string {
return this.rule.type;
};

Expand Down
Loading

0 comments on commit ace8f93

Please sign in to comment.