## 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
242 lines
6.5 KiB
TypeScript
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`;
|
|
}
|
|
}
|