PromucFlow_constructor/app/client/src/WidgetQueryGenerators/MongoDB/index.ts
balajisoundar 4c938676bd
chore: Miscellaneous one click binding updates (#24957)
## Description
- Remove the primary column from the insert and update queries.
- Save/Discard button isSaveDisabled and isDiscardDisabled properties
should be in js mode.
- Don't create insert and update query if datasource is read only

#### PR fixes following issue(s)
Fixes https://github.com/appsmithorg/appsmith/issues/24858

#### Type of change

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
>
>
>
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [x] Manual
- [ ] Jest
- [x] 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
- [x] 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
- [x] 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/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#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-07-20 11:52:20 +05:30

242 lines
6.5 KiB
TypeScript

import { isEmpty, merge } from "lodash";
import { BaseQueryGenerator } from "WidgetQueryGenerators/BaseQueryGenerator";
import { QUERY_TYPE } from "WidgetQueryGenerators/types";
import type {
WidgetQueryGenerationConfig,
WidgetQueryGenerationFormConfig,
ActionConfigurationMongoDB,
MongoDBFormData,
} from "WidgetQueryGenerators/types";
import { removeSpecialChars } from "utils/helpers";
import { DatasourceConnectionMode } from "entities/Datasource";
enum COMMAND_TYPES {
"FIND" = "FIND",
"INSERT" = "INSERT",
"UPDATE" = "UPDATE",
"COUNT" = "COUNT",
}
const ALLOWED_INITAL_VALUE_KEYS = ["aggregate", "smartSubstitution"];
export default abstract class MongoDB extends BaseQueryGenerator {
private static buildBasicConfig(command: COMMAND_TYPES, tableName: string) {
return { command: { data: command }, collection: { data: tableName } };
}
private static buildFind(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
) {
const { select } = widgetConfig;
if (select) {
return {
type: QUERY_TYPE.SELECT,
name: `Find_${removeSpecialChars(formConfig.tableName)}`,
formData: {
find: {
skip: { data: `{{${select["offset"]}}}` },
query: {
data: formConfig.searchableColumn
? `{{{ ${formConfig.searchableColumn}: {$regex: ${select["where"]}} }}}`
: "",
},
sort: {
data: `{{ ${select["orderBy"]} ? { [${select["orderBy"]}]: ${select["sortOrder"]} ? 1 : -1 } : {}}}`,
},
limit: { data: `{{${select["limit"]}}}` },
},
...this.buildBasicConfig(COMMAND_TYPES.FIND, formConfig.tableName),
},
dynamicBindingPathList: [
{
key: "formData.find.skip.data",
},
{
key: "formData.find.query.data",
},
{
key: "formData.find.sort.data",
},
{
key: "formData.find.limit.data",
},
],
};
}
}
private static buildTotalRecord(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
) {
const { select } = widgetConfig;
if (select) {
return {
type: QUERY_TYPE.TOTAL_RECORD,
name: `Total_record_${removeSpecialChars(formConfig.tableName)}`,
formData: {
count: {
query: {
data: formConfig.searchableColumn
? `{{{ ${formConfig.searchableColumn}: {$regex: ${select["where"]}} }}}`
: "",
},
},
...this.buildBasicConfig(COMMAND_TYPES.COUNT, formConfig.tableName),
},
dynamicBindingPathList: [
{
key: "formData.count.query.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_${removeSpecialChars(formConfig.tableName)}`,
formData: {
updateMany: {
query: { data: `{_id: ObjectId('{{${update.where}._id}}')}` },
update: { data: `{{{$set: _.omit(${update.value}, "_id")}}}` },
},
...this.buildBasicConfig(COMMAND_TYPES.UPDATE, formConfig.tableName),
},
dynamicBindingPathList: [
{
key: "formData.updateMany.query.data",
},
{
key: "formData.updateMany.update.data",
},
],
};
}
}
private static buildInsert(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
) {
const { create } = widgetConfig;
if (create) {
return {
type: QUERY_TYPE.CREATE,
name: `Insert_${removeSpecialChars(formConfig.tableName)}`,
formData: {
insert: {
documents: { data: `{{${create.value}}}` },
},
...this.buildBasicConfig(COMMAND_TYPES.INSERT, formConfig.tableName),
},
dynamicBindingPathList: [
{
key: "formData.insert.documents.data",
},
],
};
}
}
private static createPayload(
initialValues: MongoDBFormData,
commandKey: string,
builtValues: Record<string, object | string> | undefined,
) {
if (!builtValues || isEmpty(builtValues)) {
return;
}
if (!initialValues || isEmpty(initialValues)) {
return builtValues;
}
const scrubedOutInitalValues = [...ALLOWED_INITAL_VALUE_KEYS, commandKey]
.filter((key) => initialValues[key as keyof MongoDBFormData])
.reduce((acc, key) => {
acc[key] = initialValues[key as keyof MongoDBFormData];
return acc;
}, {} as Record<string, object>);
const { formData, ...rest } = builtValues;
return {
payload: {
formData: merge({}, scrubedOutInitalValues, formData),
},
...rest,
};
}
static build(
widgetConfig: WidgetQueryGenerationConfig,
formConfig: WidgetQueryGenerationFormConfig,
pluginInitalValues: { actionConfiguration: ActionConfigurationMongoDB },
) {
const configs = [];
const initialValues = pluginInitalValues?.actionConfiguration?.formData;
if (widgetConfig.select) {
configs.push(
this.createPayload(
initialValues,
"find",
this.buildFind(widgetConfig, formConfig),
),
);
}
if (
widgetConfig.update &&
formConfig.connectionMode === DatasourceConnectionMode.READ_WRITE
) {
configs.push(
this.createPayload(
initialValues,
"updateMany",
this.buildUpdate(widgetConfig, formConfig),
),
);
}
if (
widgetConfig.create &&
formConfig.connectionMode === DatasourceConnectionMode.READ_WRITE
) {
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}.n`;
}
}