PromucFlow_constructor/app/client/src/WidgetQueryGenerators/GSheets/index.ts

292 lines
7.1 KiB
TypeScript
Raw Normal View History

chore: [one click binding] gsheets query adaptor (#23390) ## Description Developed Gsheets query generator for one click binding epic. #### PR fixes following issue(s) Fixes #23255 #### Type of change - New feature (non-breaking change which adds functionality) - Chore (housekeeping or task changes that don't impact user perception) ## Testing > #### How Has This Been Tested? - [x] Manual - [x] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Test-plan-implementation#speedbreaker-features-to-consider-for-every-change) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans/_edit#areas-of-interest) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
2023-06-12 08:42:59 +00:00
import { isEmpty, isNumber, merge } from "lodash";
import { BaseQueryGenerator } from "WidgetQueryGenerators/BaseQueryGenerator";
import { QUERY_TYPE } from "WidgetQueryGenerators/types";
import type {
WidgetQueryGenerationConfig,
WidgetQueryGenerationFormConfig,
GSheetsFormData,
ActionConfigurationGSheets,
} from "WidgetQueryGenerators/types";
enum COMMAND_TYPES {
"FIND" = "FETCH_MANY",
"INSERT" = "INSERT_ONE",
"UPDATE" = "UPDATE_ONE",
"COUNT" = "FETCH_MANY",
}
const COMMON_INITIAL_VALUE_KEYS = [
"smartSubstitution",
"entityType",
"queryFormat",
];
const SELECT_INITAL_VALUE_KEYS = [
"range",
"where",
"pagination",
"tableHeaderIndex",
"projection",
];
export default abstract class GSheets extends BaseQueryGenerator {
private static buildBasicConfig(
command: COMMAND_TYPES,
tableName: string,
sheetName?: string,
tableHeaderIndex?: number,
) {
return {
command: { data: command },
sheetUrl: { data: tableName },
sheetName: { data: sheetName },
tableHeaderIndex: {
data: isNumber(tableHeaderIndex)
? tableHeaderIndex.toString()
: undefined,
},
};
}
private static buildFind(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
) {
const { select } = widgetConfig;
if (select) {
return {
type: QUERY_TYPE.SELECT,
name: "Find_query",
formData: {
where: {
data: {
children: [
{
condition: "CONTAINS",
key: `{{${select["where"]} ? "${formConfig.searchableColumn}" : ""}}`,
value: `{{${select["where"]}}}`,
},
],
},
},
sortBy: {
data: [
{
column: `{{${select["orderBy"]}}}`,
order: select["sortOrder"],
},
],
},
pagination: {
data: {
limit: `{{${select["limit"]}}}`,
offset: `{{${select["offset"]}}}`,
},
},
...this.buildBasicConfig(
COMMAND_TYPES.FIND,
formConfig.tableName,
formConfig.sheetName,
formConfig.tableHeaderIndex,
),
},
dynamicBindingPathList: [
{
key: "formData.where.data",
},
{
key: "formData.sortBy.data",
},
{
key: "formData.pagination.data",
},
],
};
}
}
private static buildTotalRecord(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
) {
const { select } = widgetConfig;
if (select) {
return {
type: QUERY_TYPE.TOTAL_RECORD,
name: "Total_record_query",
formData: {
where: {
data: {
children: [
{
condition: "CONTAINS",
key: `{{${select["where"]} ? "${formConfig.searchableColumn}" : ""}}`,
value: `{{${select["where"]}}}`,
},
],
},
},
...this.buildBasicConfig(
COMMAND_TYPES.COUNT,
formConfig.tableName,
formConfig.sheetName,
formConfig.tableHeaderIndex,
),
},
dynamicBindingPathList: [
{
key: "formData.where.data",
},
],
};
}
}
private static buildUpdate(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
): Record<string, object | string> | undefined {
const { update } = widgetConfig;
if (update) {
return {
type: QUERY_TYPE.UPDATE,
name: "Update_query",
formData: {
rowObjects: {
data: `{{${update.value}}}`,
},
...this.buildBasicConfig(
COMMAND_TYPES.UPDATE,
formConfig.tableName,
formConfig.sheetName,
formConfig.tableHeaderIndex,
),
},
dynamicBindingPathList: [
{
key: "formData.rowObjects.data",
},
],
};
}
}
private static buildInsert(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
) {
const { create } = widgetConfig;
if (create) {
return {
type: QUERY_TYPE.CREATE,
name: "Insert_query",
formData: {
rowObjects: {
data: `{{${create.value}}}`,
},
...this.buildBasicConfig(
COMMAND_TYPES.INSERT,
formConfig.tableName,
formConfig.sheetName,
formConfig.tableHeaderIndex,
),
},
dynamicBindingPathList: [
{
key: "formData.rowObjects.data",
},
],
};
}
}
private static createPayload(
initialValues: GSheetsFormData,
commandKey: string,
builtValues: Record<string, object | string> | undefined,
) {
if (!builtValues || isEmpty(builtValues)) {
return;
}
if (!initialValues || isEmpty(initialValues)) {
return builtValues;
}
const allowedInitialValueKeys = [
...COMMON_INITIAL_VALUE_KEYS,
...(commandKey === "find" ? SELECT_INITAL_VALUE_KEYS : []),
];
const scrubedOutInitialValues = allowedInitialValueKeys
.filter((key) => initialValues[key as keyof GSheetsFormData])
.reduce((acc, key) => {
acc[key] = initialValues[key as keyof GSheetsFormData];
return acc;
}, {} as Record<string, object>);
const { formData, ...rest } = builtValues;
return {
payload: {
formData: merge({}, scrubedOutInitialValues, formData),
},
...rest,
};
}
static build(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
pluginInitalValues: { actionConfiguration: ActionConfigurationGSheets },
) {
const configs = [];
const initialValues = pluginInitalValues?.actionConfiguration?.formData;
if (widgetConfig.select) {
configs.push(
this.createPayload(
initialValues,
"find",
this.buildFind(widgetConfig, formConfig),
),
);
}
if (widgetConfig.update) {
configs.push(
this.createPayload(
initialValues,
"updateMany",
this.buildUpdate(widgetConfig, formConfig),
),
);
}
if (widgetConfig.create) {
configs.push(
this.createPayload(
initialValues,
"insert",
this.buildInsert(widgetConfig, formConfig),
),
);
}
if (widgetConfig.totalRecord) {
configs.push(
this.createPayload(
initialValues,
"count",
this.buildTotalRecord(widgetConfig, formConfig),
),
);
}
return configs.filter((val) => !!val);
}
static getTotalRecordExpression(binding: string) {
return `${binding}.length`;
}
}