2023-07-08 14:07:26 +00:00
|
|
|
import {
|
|
|
|
|
getEntityNameAndPropertyPath,
|
|
|
|
|
isWidget,
|
|
|
|
|
overrideWidgetProperties,
|
|
|
|
|
} from "@appsmith/workers/Evaluation/evaluationUtils";
|
|
|
|
|
import type { EvalMetaUpdates } from "@appsmith/workers/common/DataTreeEvaluator/types";
|
|
|
|
|
import { evalTreeWithChanges } from "./evalTreeWithChanges";
|
|
|
|
|
import { dataTreeEvaluator } from "./handlers/evalTree";
|
|
|
|
|
import { get, set } from "lodash";
|
|
|
|
|
import { validate } from "./validations";
|
2023-10-16 09:23:47 +00:00
|
|
|
import type {
|
|
|
|
|
DataTreeEntityConfig,
|
|
|
|
|
WidgetEntity,
|
|
|
|
|
} from "@appsmith/entities/DataTree/types";
|
2023-07-08 14:07:26 +00:00
|
|
|
import type {
|
|
|
|
|
ConfigTree,
|
|
|
|
|
DataTree,
|
|
|
|
|
DataTreeEntity,
|
2023-10-10 12:32:17 +00:00
|
|
|
} from "entities/DataTree/dataTreeTypes";
|
2023-07-08 14:07:26 +00:00
|
|
|
import { getFnWithGuards, isAsyncGuard } from "./fns/utils/fnGuard";
|
|
|
|
|
import { shouldAddSetter } from "./evaluate";
|
|
|
|
|
|
|
|
|
|
class Setters {
|
2023-07-24 06:53:45 +00:00
|
|
|
/** stores the setter method accessor as key and true as value
|
2023-07-08 14:07:26 +00:00
|
|
|
*
|
|
|
|
|
* example - ```{ "Table1.setVisibility": true, "Table1.setData": true }```
|
|
|
|
|
*/
|
|
|
|
|
private setterMethodLookup: Record<string, true> = {};
|
2023-07-24 06:53:45 +00:00
|
|
|
/** stores the setter property accessor as key and setter method name as value
|
|
|
|
|
*
|
|
|
|
|
* example - ```{ "Table1.tableData": "Table1.setData" }```
|
|
|
|
|
*/
|
|
|
|
|
private setterAccessorMap: Record<string, string> = {};
|
2023-07-08 14:07:26 +00:00
|
|
|
|
2023-10-09 13:54:06 +00:00
|
|
|
private async applySetterMethod(
|
2023-07-08 14:07:26 +00:00
|
|
|
path: string,
|
|
|
|
|
value: unknown,
|
|
|
|
|
setterMethodName: string,
|
|
|
|
|
) {
|
|
|
|
|
const { entityName, propertyPath } = getEntityNameAndPropertyPath(path);
|
|
|
|
|
|
|
|
|
|
if (!dataTreeEvaluator) return;
|
|
|
|
|
|
|
|
|
|
const evalTree = dataTreeEvaluator.getEvalTree();
|
|
|
|
|
const configTree = dataTreeEvaluator.getConfigTree();
|
|
|
|
|
|
|
|
|
|
const entity = evalTree[entityName];
|
|
|
|
|
const entityConfig = configTree[entityName];
|
|
|
|
|
|
|
|
|
|
const updatedProperties: string[][] = [];
|
|
|
|
|
const overriddenProperties: string[] = [];
|
|
|
|
|
const evalMetaUpdates: EvalMetaUpdates = [];
|
|
|
|
|
|
|
|
|
|
let parsedValue = value;
|
|
|
|
|
|
|
|
|
|
if (value === undefined) {
|
|
|
|
|
const error = new Error(
|
|
|
|
|
`The value passed to ${entityName}.${setterMethodName}() evaluates to undefined.`,
|
|
|
|
|
);
|
|
|
|
|
error.name = entityName + "." + setterMethodName + " failed";
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { validationPaths } = entityConfig;
|
|
|
|
|
|
|
|
|
|
if (validationPaths) {
|
|
|
|
|
const validationConfig = validationPaths[propertyPath] || {};
|
|
|
|
|
|
|
|
|
|
const config = {
|
|
|
|
|
...validationConfig,
|
|
|
|
|
params: { ...(validationConfig.params || {}) },
|
|
|
|
|
};
|
|
|
|
|
config.params.strict = true;
|
|
|
|
|
|
|
|
|
|
const { isValid, messages, parsed } = validate(
|
|
|
|
|
config,
|
|
|
|
|
value,
|
|
|
|
|
entity as Record<string, unknown>,
|
|
|
|
|
propertyPath,
|
|
|
|
|
);
|
|
|
|
|
parsedValue = parsed;
|
|
|
|
|
|
|
|
|
|
if (!isValid) {
|
|
|
|
|
const message = messages && messages[0] ? messages[0].message : "";
|
|
|
|
|
const error = new Error(
|
|
|
|
|
`${entityName + "." + setterMethodName}: ${message}`,
|
|
|
|
|
);
|
|
|
|
|
error.name = entityName + "." + setterMethodName + " failed";
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isWidget(entity)) {
|
|
|
|
|
overrideWidgetProperties({
|
2023-10-16 09:23:47 +00:00
|
|
|
entity: entity as WidgetEntity,
|
2023-07-08 14:07:26 +00:00
|
|
|
propertyPath,
|
|
|
|
|
value: parsedValue,
|
|
|
|
|
currentTree: evalTree,
|
|
|
|
|
configTree,
|
|
|
|
|
evalMetaUpdates,
|
|
|
|
|
fullPropertyPath: path,
|
|
|
|
|
isNewWidget: false,
|
|
|
|
|
shouldUpdateGlobalContext: true,
|
|
|
|
|
overriddenProperties,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
overriddenProperties.forEach((propPath) => {
|
|
|
|
|
updatedProperties.push([entityName, propPath]);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set(evalTree, path, parsedValue);
|
|
|
|
|
set(self, path, parsedValue);
|
|
|
|
|
|
2023-08-08 14:12:07 +00:00
|
|
|
/**
|
|
|
|
|
* Making the update to dataTree async as there could be queue microtask updates that need to execute before this update.
|
|
|
|
|
* Issue:- https://github.com/appsmithorg/appsmith/issues/25364
|
|
|
|
|
*/
|
2023-07-08 14:07:26 +00:00
|
|
|
return new Promise((resolve) => {
|
2023-08-08 14:12:07 +00:00
|
|
|
resolve(parsedValue);
|
|
|
|
|
}).then((res) => {
|
2023-07-08 14:07:26 +00:00
|
|
|
updatedProperties.push([entityName, propertyPath]);
|
|
|
|
|
evalTreeWithChanges(updatedProperties, evalMetaUpdates);
|
2023-08-08 14:12:07 +00:00
|
|
|
return res;
|
2023-07-08 14:07:26 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/** Generates a new setter method */
|
2023-07-24 06:53:45 +00:00
|
|
|
private createSetter(
|
|
|
|
|
path: string,
|
|
|
|
|
setterMethodName: string,
|
|
|
|
|
entityName: string,
|
|
|
|
|
) {
|
2023-07-08 14:07:26 +00:00
|
|
|
/** register the setter method in the lookup */
|
|
|
|
|
set(this.setterMethodLookup, [entityName, setterMethodName], true);
|
|
|
|
|
|
|
|
|
|
const fn = async (value: unknown) => {
|
|
|
|
|
if (!dataTreeEvaluator) return;
|
|
|
|
|
return this.applySetterMethod(path, value, setterMethodName);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return getFnWithGuards(fn, setterMethodName, [isAsyncGuard]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clear() {
|
|
|
|
|
this.setterMethodLookup = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
has(entityName: string, propertyName: string) {
|
|
|
|
|
return get(this.setterMethodLookup, [entityName, propertyName], false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getMap() {
|
|
|
|
|
return this.setterMethodLookup;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 06:53:45 +00:00
|
|
|
getSetterAccessorMap() {
|
|
|
|
|
return this.setterAccessorMap;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-08 14:07:26 +00:00
|
|
|
getEntitySettersFromConfig(
|
|
|
|
|
entityConfig: DataTreeEntityConfig,
|
|
|
|
|
entityName: string,
|
|
|
|
|
entity: DataTreeEntity,
|
|
|
|
|
) {
|
|
|
|
|
const setterMethodMap: Record<string, any> = {};
|
|
|
|
|
if (!entityConfig) return setterMethodMap;
|
|
|
|
|
|
|
|
|
|
if (entityConfig.__setters) {
|
|
|
|
|
for (const setterMethodName of Object.keys(entityConfig.__setters)) {
|
2023-07-24 06:53:45 +00:00
|
|
|
const pathToSet = entityConfig.__setters[setterMethodName].path;
|
2023-07-08 14:07:26 +00:00
|
|
|
|
|
|
|
|
if (!shouldAddSetter(entityConfig.__setters[setterMethodName], entity))
|
|
|
|
|
continue;
|
|
|
|
|
|
2023-07-24 06:53:45 +00:00
|
|
|
this.setterAccessorMap[pathToSet] = `${entityName}.${setterMethodName}`;
|
|
|
|
|
|
|
|
|
|
setterMethodMap[setterMethodName] = this.createSetter(
|
|
|
|
|
pathToSet,
|
2023-07-08 14:07:26 +00:00
|
|
|
setterMethodName,
|
|
|
|
|
entityName,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return setterMethodMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init(configTree: ConfigTree, dataTree: DataTree) {
|
|
|
|
|
const configTreeEntries = Object.entries(configTree);
|
|
|
|
|
for (const [entityName, entityConfig] of configTreeEntries) {
|
|
|
|
|
const entity = dataTree[entityName];
|
|
|
|
|
|
|
|
|
|
this.getEntitySettersFromConfig(entityConfig, entityName, entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const setters = new Setters();
|
|
|
|
|
export default setters;
|