mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat(MongoDB Node): Add search index CRUD API to MongoDB CRUD Node (#16490)
This commit is contained in:
@@ -16,6 +16,7 @@ import type {
|
|||||||
INodeType,
|
INodeType,
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
JsonObject,
|
JsonObject,
|
||||||
|
IPairedItemData,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -101,324 +102,445 @@ export class MongoDb implements INodeType {
|
|||||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||||
const credentials = await this.getCredentials('mongoDb');
|
const credentials = await this.getCredentials('mongoDb');
|
||||||
const { database, connectionString } = validateAndResolveMongoCredentials(this, credentials);
|
const { database, connectionString } = validateAndResolveMongoCredentials(this, credentials);
|
||||||
|
|
||||||
const client = await connectMongoClient(connectionString, credentials);
|
const client = await connectMongoClient(connectionString, credentials);
|
||||||
|
|
||||||
const mdb = client.db(database);
|
|
||||||
|
|
||||||
let returnData: INodeExecutionData[] = [];
|
let returnData: INodeExecutionData[] = [];
|
||||||
|
|
||||||
const items = this.getInputData();
|
try {
|
||||||
const operation = this.getNodeParameter('operation', 0);
|
const mdb = client.db(database);
|
||||||
const nodeVersion = this.getNode().typeVersion;
|
|
||||||
|
|
||||||
let itemsLength = items.length ? 1 : 0;
|
const items = this.getInputData();
|
||||||
let fallbackPairedItems;
|
const operation = this.getNodeParameter('operation', 0);
|
||||||
|
const nodeVersion = this.getNode().typeVersion;
|
||||||
|
|
||||||
if (nodeVersion >= 1.1) {
|
let itemsLength = items.length ? 1 : 0;
|
||||||
itemsLength = items.length;
|
let fallbackPairedItems: IPairedItemData[] | null = null;
|
||||||
} else {
|
|
||||||
fallbackPairedItems = generatePairedItemData(items.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation === 'aggregate') {
|
if (nodeVersion >= 1.1) {
|
||||||
for (let i = 0; i < itemsLength; i++) {
|
itemsLength = items.length;
|
||||||
try {
|
} else {
|
||||||
const queryParameter = JSON.parse(
|
fallbackPairedItems = generatePairedItemData(items.length);
|
||||||
this.getNodeParameter('query', i) as string,
|
}
|
||||||
) as IDataObject;
|
|
||||||
|
|
||||||
if (queryParameter._id && typeof queryParameter._id === 'string') {
|
if (operation === 'aggregate') {
|
||||||
queryParameter._id = new ObjectId(queryParameter._id);
|
for (let i = 0; i < itemsLength; i++) {
|
||||||
|
try {
|
||||||
|
const queryParameter = JSON.parse(
|
||||||
|
this.getNodeParameter('query', i) as string,
|
||||||
|
) as IDataObject;
|
||||||
|
|
||||||
|
if (queryParameter._id && typeof queryParameter._id === 'string') {
|
||||||
|
queryParameter._id = new ObjectId(queryParameter._id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = mdb
|
||||||
|
.collection(this.getNodeParameter('collection', i) as string)
|
||||||
|
.aggregate(queryParameter as unknown as Document[]);
|
||||||
|
|
||||||
|
for (const entry of await query.toArray()) {
|
||||||
|
returnData.push({ json: entry, pairedItem: fallbackPairedItems ?? [{ item: i }] });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: { error: (error as JsonObject).message },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const query = mdb
|
if (operation === 'delete') {
|
||||||
.collection(this.getNodeParameter('collection', i) as string)
|
for (let i = 0; i < itemsLength; i++) {
|
||||||
.aggregate(queryParameter as unknown as Document[]);
|
try {
|
||||||
|
const { deletedCount } = await mdb
|
||||||
|
.collection(this.getNodeParameter('collection', i) as string)
|
||||||
|
.deleteMany(JSON.parse(this.getNodeParameter('query', i) as string) as Document);
|
||||||
|
|
||||||
for (const entry of await query.toArray()) {
|
|
||||||
returnData.push({ json: entry, pairedItem: fallbackPairedItems ?? [{ item: i }] });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (this.continueOnFail()) {
|
|
||||||
returnData.push({
|
returnData.push({
|
||||||
json: { error: (error as JsonObject).message },
|
json: { deletedCount },
|
||||||
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
});
|
});
|
||||||
continue;
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: { error: (error as JsonObject).message },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation === 'delete') {
|
|
||||||
for (let i = 0; i < itemsLength; i++) {
|
|
||||||
try {
|
|
||||||
const { deletedCount } = await mdb
|
|
||||||
.collection(this.getNodeParameter('collection', i) as string)
|
|
||||||
.deleteMany(JSON.parse(this.getNodeParameter('query', i) as string) as Document);
|
|
||||||
|
|
||||||
returnData.push({
|
|
||||||
json: { deletedCount },
|
|
||||||
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
if (this.continueOnFail()) {
|
|
||||||
returnData.push({
|
|
||||||
json: { error: (error as JsonObject).message },
|
|
||||||
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation === 'find') {
|
|
||||||
for (let i = 0; i < itemsLength; i++) {
|
|
||||||
try {
|
|
||||||
const queryParameter = JSON.parse(
|
|
||||||
this.getNodeParameter('query', i) as string,
|
|
||||||
) as IDataObject;
|
|
||||||
|
|
||||||
if (queryParameter._id && typeof queryParameter._id === 'string') {
|
|
||||||
queryParameter._id = new ObjectId(queryParameter._id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let query = mdb
|
|
||||||
.collection(this.getNodeParameter('collection', i) as string)
|
|
||||||
.find(queryParameter as unknown as Document);
|
|
||||||
|
|
||||||
const options = this.getNodeParameter('options', i);
|
|
||||||
const limit = options.limit as number;
|
|
||||||
const skip = options.skip as number;
|
|
||||||
const projection =
|
|
||||||
options.projection && (JSON.parse(options.projection as string) as Document);
|
|
||||||
const sort = options.sort && (JSON.parse(options.sort as string) as Sort);
|
|
||||||
|
|
||||||
if (skip > 0) {
|
|
||||||
query = query.skip(skip);
|
|
||||||
}
|
|
||||||
if (limit > 0) {
|
|
||||||
query = query.limit(limit);
|
|
||||||
}
|
|
||||||
if (sort && Object.keys(sort).length !== 0 && sort.constructor === Object) {
|
|
||||||
query = query.sort(sort);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
projection &&
|
|
||||||
Object.keys(projection).length !== 0 &&
|
|
||||||
projection.constructor === Object
|
|
||||||
) {
|
|
||||||
query = query.project(projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryResult = await query.toArray();
|
|
||||||
|
|
||||||
for (const entry of queryResult) {
|
|
||||||
returnData.push({ json: entry, pairedItem: fallbackPairedItems ?? [{ item: i }] });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (this.continueOnFail()) {
|
|
||||||
returnData.push({
|
|
||||||
json: { error: (error as JsonObject).message },
|
|
||||||
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation === 'findOneAndReplace') {
|
|
||||||
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
|
||||||
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
|
||||||
const useDotNotation = this.getNodeParameter('options.useDotNotation', 0, false) as boolean;
|
|
||||||
const dateFields = prepareFields(
|
|
||||||
this.getNodeParameter('options.dateFields', 0, '') as string,
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateKey = ((this.getNodeParameter('updateKey', 0) as string) || '').trim();
|
|
||||||
|
|
||||||
const updateOptions = (this.getNodeParameter('upsert', 0) as boolean)
|
|
||||||
? { upsert: true }
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const updateItems = prepareItems({ items, fields, updateKey, useDotNotation, dateFields });
|
|
||||||
|
|
||||||
for (const item of updateItems) {
|
|
||||||
try {
|
|
||||||
const filter = { [updateKey]: item[updateKey] };
|
|
||||||
if (updateKey === '_id') {
|
|
||||||
filter[updateKey] = new ObjectId(item[updateKey] as string);
|
|
||||||
delete item._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
await mdb
|
|
||||||
.collection(this.getNodeParameter('collection', 0) as string)
|
|
||||||
.findOneAndReplace(filter, item, updateOptions as FindOneAndReplaceOptions);
|
|
||||||
} catch (error) {
|
|
||||||
if (this.continueOnFail()) {
|
|
||||||
item.json = { error: (error as JsonObject).message };
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData = this.helpers.constructExecutionMetaData(
|
if (operation === 'find') {
|
||||||
this.helpers.returnJsonArray(updateItems),
|
for (let i = 0; i < itemsLength; i++) {
|
||||||
{ itemData: fallbackPairedItems },
|
try {
|
||||||
);
|
const queryParameter = JSON.parse(
|
||||||
}
|
this.getNodeParameter('query', i) as string,
|
||||||
|
) as IDataObject;
|
||||||
|
|
||||||
if (operation === 'findOneAndUpdate') {
|
if (queryParameter._id && typeof queryParameter._id === 'string') {
|
||||||
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
queryParameter._id = new ObjectId(queryParameter._id);
|
||||||
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
}
|
||||||
const useDotNotation = this.getNodeParameter('options.useDotNotation', 0, false) as boolean;
|
|
||||||
const dateFields = prepareFields(
|
|
||||||
this.getNodeParameter('options.dateFields', 0, '') as string,
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateKey = ((this.getNodeParameter('updateKey', 0) as string) || '').trim();
|
let query = mdb
|
||||||
|
.collection(this.getNodeParameter('collection', i) as string)
|
||||||
|
.find(queryParameter as unknown as Document);
|
||||||
|
|
||||||
const updateOptions = (this.getNodeParameter('upsert', 0) as boolean)
|
const options = this.getNodeParameter('options', i);
|
||||||
? { upsert: true }
|
const limit = options.limit as number;
|
||||||
: undefined;
|
const skip = options.skip as number;
|
||||||
|
const projection =
|
||||||
|
options.projection && (JSON.parse(options.projection as string) as Document);
|
||||||
|
const sort = options.sort && (JSON.parse(options.sort as string) as Sort);
|
||||||
|
|
||||||
const updateItems = prepareItems({
|
if (skip > 0) {
|
||||||
items,
|
query = query.skip(skip);
|
||||||
fields,
|
}
|
||||||
updateKey,
|
if (limit > 0) {
|
||||||
useDotNotation,
|
query = query.limit(limit);
|
||||||
dateFields,
|
}
|
||||||
isUpdate: nodeVersion >= 1.2,
|
if (sort && Object.keys(sort).length !== 0 && sort.constructor === Object) {
|
||||||
});
|
query = query.sort(sort);
|
||||||
|
}
|
||||||
|
|
||||||
for (const item of updateItems) {
|
if (
|
||||||
try {
|
projection &&
|
||||||
const filter = { [updateKey]: item[updateKey] };
|
Object.keys(projection).length !== 0 &&
|
||||||
if (updateKey === '_id') {
|
projection.constructor === Object
|
||||||
filter[updateKey] = new ObjectId(item[updateKey] as string);
|
) {
|
||||||
delete item._id;
|
query = query.project(projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryResult = await query.toArray();
|
||||||
|
|
||||||
|
for (const entry of queryResult) {
|
||||||
|
returnData.push({ json: entry, pairedItem: fallbackPairedItems ?? [{ item: i }] });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: { error: (error as JsonObject).message },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
await mdb
|
|
||||||
.collection(this.getNodeParameter('collection', 0) as string)
|
|
||||||
.findOneAndUpdate(filter, { $set: item }, updateOptions as FindOneAndUpdateOptions);
|
|
||||||
} catch (error) {
|
|
||||||
if (this.continueOnFail()) {
|
|
||||||
item.json = { error: (error as JsonObject).message };
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData = this.helpers.constructExecutionMetaData(
|
if (operation === 'findOneAndReplace') {
|
||||||
this.helpers.returnJsonArray(updateItems),
|
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
||||||
{ itemData: fallbackPairedItems },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation === 'insert') {
|
|
||||||
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
|
||||||
let responseData: IDataObject[] = [];
|
|
||||||
try {
|
|
||||||
// Prepare the data to insert and copy it to be returned
|
|
||||||
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
||||||
const useDotNotation = this.getNodeParameter('options.useDotNotation', 0, false) as boolean;
|
const useDotNotation = this.getNodeParameter('options.useDotNotation', 0, false) as boolean;
|
||||||
const dateFields = prepareFields(
|
const dateFields = prepareFields(
|
||||||
this.getNodeParameter('options.dateFields', 0, '') as string,
|
this.getNodeParameter('options.dateFields', 0, '') as string,
|
||||||
);
|
);
|
||||||
|
|
||||||
const insertItems = prepareItems({
|
const updateKey = ((this.getNodeParameter('updateKey', 0) as string) || '').trim();
|
||||||
|
|
||||||
|
const updateOptions = (this.getNodeParameter('upsert', 0) as boolean)
|
||||||
|
? { upsert: true }
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const updateItems = prepareItems({ items, fields, updateKey, useDotNotation, dateFields });
|
||||||
|
|
||||||
|
for (const item of updateItems) {
|
||||||
|
try {
|
||||||
|
const filter = { [updateKey]: item[updateKey] };
|
||||||
|
if (updateKey === '_id') {
|
||||||
|
filter[updateKey] = new ObjectId(item[updateKey] as string);
|
||||||
|
delete item._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
await mdb
|
||||||
|
.collection(this.getNodeParameter('collection', 0) as string)
|
||||||
|
.findOneAndReplace(filter, item, updateOptions as FindOneAndReplaceOptions);
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
item.json = { error: (error as JsonObject).message };
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
returnData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray(updateItems),
|
||||||
|
{ itemData: fallbackPairedItems },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation === 'findOneAndUpdate') {
|
||||||
|
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
||||||
|
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
||||||
|
const useDotNotation = this.getNodeParameter('options.useDotNotation', 0, false) as boolean;
|
||||||
|
const dateFields = prepareFields(
|
||||||
|
this.getNodeParameter('options.dateFields', 0, '') as string,
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateKey = ((this.getNodeParameter('updateKey', 0) as string) || '').trim();
|
||||||
|
|
||||||
|
const updateOptions = (this.getNodeParameter('upsert', 0) as boolean)
|
||||||
|
? { upsert: true }
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const updateItems = prepareItems({
|
||||||
items,
|
items,
|
||||||
fields,
|
fields,
|
||||||
updateKey: '',
|
updateKey,
|
||||||
useDotNotation,
|
useDotNotation,
|
||||||
dateFields,
|
dateFields,
|
||||||
|
isUpdate: nodeVersion >= 1.2,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { insertedIds } = await mdb
|
for (const item of updateItems) {
|
||||||
.collection(this.getNodeParameter('collection', 0) as string)
|
try {
|
||||||
.insertMany(insertItems);
|
const filter = { [updateKey]: item[updateKey] };
|
||||||
|
if (updateKey === '_id') {
|
||||||
|
filter[updateKey] = new ObjectId(item[updateKey] as string);
|
||||||
|
delete item._id;
|
||||||
|
}
|
||||||
|
|
||||||
// Add the id to the data
|
await mdb
|
||||||
for (const i of Object.keys(insertedIds)) {
|
.collection(this.getNodeParameter('collection', 0) as string)
|
||||||
responseData.push({
|
.findOneAndUpdate(filter, { $set: item }, updateOptions as FindOneAndUpdateOptions);
|
||||||
...insertItems[parseInt(i, 10)],
|
} catch (error) {
|
||||||
id: insertedIds[parseInt(i, 10)] as unknown as string,
|
if (this.continueOnFail()) {
|
||||||
});
|
item.json = { error: (error as JsonObject).message };
|
||||||
}
|
continue;
|
||||||
} catch (error) {
|
}
|
||||||
if (this.continueOnFail()) {
|
throw error;
|
||||||
responseData = [{ error: (error as JsonObject).message }];
|
}
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
returnData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray(updateItems),
|
||||||
|
{ itemData: fallbackPairedItems },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData = this.helpers.constructExecutionMetaData(
|
if (operation === 'insert') {
|
||||||
this.helpers.returnJsonArray(responseData),
|
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
||||||
{ itemData: fallbackPairedItems },
|
let responseData: IDataObject[] = [];
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation === 'update') {
|
|
||||||
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
|
||||||
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
|
||||||
const useDotNotation = this.getNodeParameter('options.useDotNotation', 0, false) as boolean;
|
|
||||||
const dateFields = prepareFields(
|
|
||||||
this.getNodeParameter('options.dateFields', 0, '') as string,
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateKey = ((this.getNodeParameter('updateKey', 0) as string) || '').trim();
|
|
||||||
|
|
||||||
const updateOptions = (this.getNodeParameter('upsert', 0) as boolean)
|
|
||||||
? { upsert: true }
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const updateItems = prepareItems({
|
|
||||||
items,
|
|
||||||
fields,
|
|
||||||
updateKey,
|
|
||||||
useDotNotation,
|
|
||||||
dateFields,
|
|
||||||
isUpdate: nodeVersion >= 1.2,
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const item of updateItems) {
|
|
||||||
try {
|
try {
|
||||||
const filter = { [updateKey]: item[updateKey] };
|
// Prepare the data to insert and copy it to be returned
|
||||||
if (updateKey === '_id') {
|
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
||||||
filter[updateKey] = new ObjectId(item[updateKey] as string);
|
const useDotNotation = this.getNodeParameter(
|
||||||
delete item._id;
|
'options.useDotNotation',
|
||||||
}
|
0,
|
||||||
|
false,
|
||||||
|
) as boolean;
|
||||||
|
const dateFields = prepareFields(
|
||||||
|
this.getNodeParameter('options.dateFields', 0, '') as string,
|
||||||
|
);
|
||||||
|
|
||||||
await mdb
|
const insertItems = prepareItems({
|
||||||
|
items,
|
||||||
|
fields,
|
||||||
|
updateKey: '',
|
||||||
|
useDotNotation,
|
||||||
|
dateFields,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { insertedIds } = await mdb
|
||||||
.collection(this.getNodeParameter('collection', 0) as string)
|
.collection(this.getNodeParameter('collection', 0) as string)
|
||||||
.updateOne(filter, { $set: item }, updateOptions as UpdateOptions);
|
.insertMany(insertItems);
|
||||||
|
|
||||||
|
// Add the id to the data
|
||||||
|
for (const i of Object.keys(insertedIds)) {
|
||||||
|
responseData.push({
|
||||||
|
...insertItems[parseInt(i, 10)],
|
||||||
|
id: insertedIds[parseInt(i, 10)] as unknown as string,
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.continueOnFail()) {
|
if (this.continueOnFail()) {
|
||||||
item.json = { error: (error as JsonObject).message };
|
responseData = [{ error: (error as JsonObject).message }];
|
||||||
continue;
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
returnData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray(responseData),
|
||||||
|
{ itemData: fallbackPairedItems },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation === 'update') {
|
||||||
|
fallbackPairedItems = fallbackPairedItems ?? generatePairedItemData(items.length);
|
||||||
|
const fields = prepareFields(this.getNodeParameter('fields', 0) as string);
|
||||||
|
const useDotNotation = this.getNodeParameter('options.useDotNotation', 0, false) as boolean;
|
||||||
|
const dateFields = prepareFields(
|
||||||
|
this.getNodeParameter('options.dateFields', 0, '') as string,
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateKey = ((this.getNodeParameter('updateKey', 0) as string) || '').trim();
|
||||||
|
|
||||||
|
const updateOptions = (this.getNodeParameter('upsert', 0) as boolean)
|
||||||
|
? { upsert: true }
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const updateItems = prepareItems({
|
||||||
|
items,
|
||||||
|
fields,
|
||||||
|
updateKey,
|
||||||
|
useDotNotation,
|
||||||
|
dateFields,
|
||||||
|
isUpdate: nodeVersion >= 1.2,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const item of updateItems) {
|
||||||
|
try {
|
||||||
|
const filter = { [updateKey]: item[updateKey] };
|
||||||
|
if (updateKey === '_id') {
|
||||||
|
filter[updateKey] = new ObjectId(item[updateKey] as string);
|
||||||
|
delete item._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
await mdb
|
||||||
|
.collection(this.getNodeParameter('collection', 0) as string)
|
||||||
|
.updateOne(filter, { $set: item }, updateOptions as UpdateOptions);
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
item.json = { error: (error as JsonObject).message };
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
returnData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray(updateItems),
|
||||||
|
{ itemData: fallbackPairedItems },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation === 'listSearchIndexes') {
|
||||||
|
for (let i = 0; i < itemsLength; i++) {
|
||||||
|
try {
|
||||||
|
const collection = this.getNodeParameter('collection', i) as string;
|
||||||
|
const indexName = (() => {
|
||||||
|
const name = this.getNodeParameter('indexName', i) as string;
|
||||||
|
return name.length === 0 ? undefined : name;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const cursor = indexName
|
||||||
|
? mdb.collection(collection).listSearchIndexes(indexName)
|
||||||
|
: mdb.collection(collection).listSearchIndexes();
|
||||||
|
|
||||||
|
const query = await cursor.toArray();
|
||||||
|
const result = query.map((json) => ({
|
||||||
|
json,
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
}));
|
||||||
|
returnData.push(...result);
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: { error: (error as JsonObject).message },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData = this.helpers.constructExecutionMetaData(
|
if (operation === 'dropSearchIndex') {
|
||||||
this.helpers.returnJsonArray(updateItems),
|
for (let i = 0; i < itemsLength; i++) {
|
||||||
{ itemData: fallbackPairedItems },
|
try {
|
||||||
);
|
const collection = this.getNodeParameter('collection', i) as string;
|
||||||
}
|
const indexName = this.getNodeParameter('indexNameRequired', i) as string;
|
||||||
|
|
||||||
await client.close();
|
await mdb.collection(collection).dropSearchIndex(indexName);
|
||||||
|
returnData.push({
|
||||||
|
json: {
|
||||||
|
[indexName]: true,
|
||||||
|
},
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: { error: (error as JsonObject).message },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation === 'createSearchIndex') {
|
||||||
|
for (let i = 0; i < itemsLength; i++) {
|
||||||
|
try {
|
||||||
|
const collection = this.getNodeParameter('collection', i) as string;
|
||||||
|
const indexName = this.getNodeParameter('indexNameRequired', i) as string;
|
||||||
|
const definition = JSON.parse(
|
||||||
|
this.getNodeParameter('indexDefinition', i) as string,
|
||||||
|
) as Record<string, unknown>;
|
||||||
|
|
||||||
|
await mdb.collection(collection).createSearchIndex({
|
||||||
|
name: indexName,
|
||||||
|
definition,
|
||||||
|
});
|
||||||
|
|
||||||
|
returnData.push({
|
||||||
|
json: { indexName },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: { error: (error as JsonObject).message },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation === 'updateSearchIndex') {
|
||||||
|
for (let i = 0; i < itemsLength; i++) {
|
||||||
|
try {
|
||||||
|
const collection = this.getNodeParameter('collection', i) as string;
|
||||||
|
const indexName = this.getNodeParameter('indexNameRequired', i) as string;
|
||||||
|
const definition = JSON.parse(
|
||||||
|
this.getNodeParameter('indexDefinition', i) as string,
|
||||||
|
) as Record<string, unknown>;
|
||||||
|
|
||||||
|
await mdb.collection(collection).updateSearchIndex(indexName, definition);
|
||||||
|
|
||||||
|
returnData.push({
|
||||||
|
json: { [indexName]: true },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
returnData.push({
|
||||||
|
json: { error: (error as JsonObject).message },
|
||||||
|
pairedItem: fallbackPairedItems ?? [{ item: i }],
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await client.close().catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
return [stringifyObjectIDs(returnData)];
|
return [stringifyObjectIDs(returnData)];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,33 @@
|
|||||||
import type { INodeProperties } from 'n8n-workflow';
|
import type { INodeProperties } from 'n8n-workflow';
|
||||||
|
|
||||||
export const nodeProperties: INodeProperties[] = [
|
export const nodeProperties: INodeProperties[] = [
|
||||||
|
{
|
||||||
|
displayName: 'Resource',
|
||||||
|
name: 'resource',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Search Index',
|
||||||
|
value: 'searchIndexes',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Document',
|
||||||
|
value: 'document',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'document',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Operation',
|
displayName: 'Operation',
|
||||||
name: 'operation',
|
name: 'operation',
|
||||||
type: 'options',
|
type: 'options',
|
||||||
noDataExpression: true,
|
noDataExpression: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['document'],
|
||||||
|
},
|
||||||
|
},
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: 'Aggregate',
|
name: 'Aggregate',
|
||||||
@@ -52,7 +74,40 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
],
|
],
|
||||||
default: 'find',
|
default: 'find',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['searchIndexes'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Create',
|
||||||
|
value: 'createSearchIndex',
|
||||||
|
action: 'Create Search Index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Drop',
|
||||||
|
value: 'dropSearchIndex',
|
||||||
|
action: 'Drop Search Index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'List',
|
||||||
|
value: 'listSearchIndexes',
|
||||||
|
action: 'List Search Indexes',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Update',
|
||||||
|
value: 'updateSearchIndex',
|
||||||
|
action: 'Update Search Index',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'createSearchIndex',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Collection',
|
displayName: 'Collection',
|
||||||
name: 'collection',
|
name: 'collection',
|
||||||
@@ -75,6 +130,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['aggregate'],
|
operation: ['aggregate'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: '',
|
default: '',
|
||||||
@@ -97,6 +153,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['delete'],
|
operation: ['delete'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: '{}',
|
default: '{}',
|
||||||
@@ -115,6 +172,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['find'],
|
operation: ['find'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: {},
|
default: {},
|
||||||
@@ -175,6 +233,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['find'],
|
operation: ['find'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: '{}',
|
default: '{}',
|
||||||
@@ -193,6 +252,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['insert'],
|
operation: ['insert'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: '',
|
default: '',
|
||||||
@@ -210,6 +270,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['update', 'findOneAndReplace', 'findOneAndUpdate'],
|
operation: ['update', 'findOneAndReplace', 'findOneAndUpdate'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: 'id',
|
default: 'id',
|
||||||
@@ -225,6 +286,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['update', 'findOneAndReplace', 'findOneAndUpdate'],
|
operation: ['update', 'findOneAndReplace', 'findOneAndUpdate'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: '',
|
default: '',
|
||||||
@@ -238,6 +300,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['update', 'findOneAndReplace', 'findOneAndUpdate'],
|
operation: ['update', 'findOneAndReplace', 'findOneAndUpdate'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
default: false,
|
default: false,
|
||||||
@@ -250,6 +313,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: ['update', 'insert', 'findOneAndReplace', 'findOneAndUpdate'],
|
operation: ['update', 'insert', 'findOneAndReplace', 'findOneAndUpdate'],
|
||||||
|
resource: ['document'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
placeholder: 'Add option',
|
placeholder: 'Add option',
|
||||||
@@ -271,4 +335,74 @@ export const nodeProperties: INodeProperties[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Index Name',
|
||||||
|
name: 'indexName',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['listSearchIndexes'],
|
||||||
|
resource: ['searchIndexes'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'If provided, only lists indexes with the specified name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Index Name',
|
||||||
|
name: 'indexNameRequired',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['createSearchIndex', 'dropSearchIndex', 'updateSearchIndex'],
|
||||||
|
resource: ['searchIndexes'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
description: 'The name of the search index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Index Definition',
|
||||||
|
name: 'indexDefinition',
|
||||||
|
type: 'json',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['createSearchIndex', 'updateSearchIndex'],
|
||||||
|
resource: ['searchIndexes'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typeOptions: {
|
||||||
|
alwaysOpenEditWindow: true,
|
||||||
|
},
|
||||||
|
placeholder: '{ "type": "vectorSearch", "definition": {} }',
|
||||||
|
hint: 'Learn more about search index definitions <a href="https://www.mongodb.com/docs/atlas/atlas-search/index-definitions/">here</a>',
|
||||||
|
default: '{}',
|
||||||
|
required: true,
|
||||||
|
description: 'The search index definition',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Index Type',
|
||||||
|
name: 'indexType',
|
||||||
|
type: 'options',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['createSearchIndex'],
|
||||||
|
resource: ['searchIndexes'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: 'vectorSearch',
|
||||||
|
name: 'Vector Search',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Search',
|
||||||
|
value: 'search',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'vectorSearch',
|
||||||
|
required: true,
|
||||||
|
description: 'The search index index type',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
242
packages/nodes-base/nodes/MongoDb/test/MongoDB.test.ts
Normal file
242
packages/nodes-base/nodes/MongoDb/test/MongoDB.test.ts
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||||
|
import { Collection, MongoClient } from 'mongodb';
|
||||||
|
import type { INodeParameters, WorkflowTestData } from 'n8n-workflow';
|
||||||
|
|
||||||
|
MongoClient.connect = async function () {
|
||||||
|
const client = new MongoClient('mongodb://localhost:27017');
|
||||||
|
return client;
|
||||||
|
};
|
||||||
|
|
||||||
|
function buildWorkflow({
|
||||||
|
parameters,
|
||||||
|
expectedResult,
|
||||||
|
}: { parameters: INodeParameters; expectedResult: unknown[] }) {
|
||||||
|
const test: WorkflowTestData = {
|
||||||
|
description: 'should pass test',
|
||||||
|
input: {
|
||||||
|
workflowData: {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
parameters: {},
|
||||||
|
id: '8b7bb389-e4ef-424a-bca1-e7ead60e43eb',
|
||||||
|
name: 'When clicking "Execute Workflow"',
|
||||||
|
type: 'n8n-nodes-base.manualTrigger',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [740, 380],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameters,
|
||||||
|
id: '8b7bb389-e4ef-424a-bca1-e7ead60e43ec',
|
||||||
|
name: 'mongoDb',
|
||||||
|
type: 'n8n-nodes-base.mongoDb',
|
||||||
|
typeVersion: 1.2,
|
||||||
|
position: [1260, 360],
|
||||||
|
credentials: {
|
||||||
|
mongoDb: {
|
||||||
|
id: 'mongodb://localhost:27017',
|
||||||
|
name: 'Connection String',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {
|
||||||
|
'When clicking "Execute Workflow"': {
|
||||||
|
main: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
node: 'mongoDb',
|
||||||
|
type: 'main',
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
assertBinaryData: true,
|
||||||
|
nodeData: {
|
||||||
|
mongoDb: [expectedResult],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('MongoDB CRUD Node', () => {
|
||||||
|
const testHarness = new NodeTestHarness();
|
||||||
|
|
||||||
|
describe('createSearchIndex operation', () => {
|
||||||
|
const spy: jest.SpyInstance = jest.spyOn(Collection.prototype, 'createSearchIndex');
|
||||||
|
afterAll(() => jest.restoreAllMocks());
|
||||||
|
beforeAll(() => {
|
||||||
|
spy.mockResolvedValueOnce('my-index');
|
||||||
|
});
|
||||||
|
|
||||||
|
testHarness.setupTest(
|
||||||
|
buildWorkflow({
|
||||||
|
parameters: {
|
||||||
|
operation: 'createSearchIndex',
|
||||||
|
resource: 'searchIndexes',
|
||||||
|
collection: 'foo',
|
||||||
|
indexType: 'vectorSearch',
|
||||||
|
indexDefinition: JSON.stringify({ mappings: {} }),
|
||||||
|
indexNameRequired: 'my-index',
|
||||||
|
},
|
||||||
|
expectedResult: [{ json: { indexName: 'my-index' } }],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
it('calls the spy with the expected arguments', function () {
|
||||||
|
expect(spy).toBeCalledWith({ name: 'my-index', definition: { mappings: {} } });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('listSearchIndexes operation', () => {
|
||||||
|
describe('no index name provided', function () {
|
||||||
|
let spy: jest.SpyInstance;
|
||||||
|
beforeAll(() => {
|
||||||
|
spy = jest.spyOn(Collection.prototype, 'listSearchIndexes');
|
||||||
|
const mockCursor = {
|
||||||
|
toArray: async () => [],
|
||||||
|
};
|
||||||
|
spy.mockReturnValue(mockCursor);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => jest.restoreAllMocks());
|
||||||
|
|
||||||
|
testHarness.setupTest(
|
||||||
|
buildWorkflow({
|
||||||
|
parameters: {
|
||||||
|
resource: 'searchIndexes',
|
||||||
|
operation: 'listSearchIndexes',
|
||||||
|
collection: 'foo',
|
||||||
|
},
|
||||||
|
expectedResult: [],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
it('calls the spy with the expected arguments', function () {
|
||||||
|
expect(spy).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('index name provided', function () {
|
||||||
|
let spy: jest.SpyInstance;
|
||||||
|
beforeAll(() => {
|
||||||
|
spy = jest.spyOn(Collection.prototype, 'listSearchIndexes');
|
||||||
|
const mockCursor = {
|
||||||
|
toArray: async () => [],
|
||||||
|
};
|
||||||
|
spy.mockReturnValue(mockCursor);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => jest.restoreAllMocks());
|
||||||
|
|
||||||
|
testHarness.setupTest(
|
||||||
|
buildWorkflow({
|
||||||
|
parameters: {
|
||||||
|
resource: 'searchIndexes',
|
||||||
|
operation: 'listSearchIndexes',
|
||||||
|
collection: 'foo',
|
||||||
|
indexName: 'my-index',
|
||||||
|
},
|
||||||
|
expectedResult: [],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
it('calls the spy with the expected arguments', function () {
|
||||||
|
expect(spy).toHaveBeenCalledWith('my-index');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('return values are transformed into the expected return type', function () {
|
||||||
|
let spy: jest.SpyInstance;
|
||||||
|
beforeAll(() => {
|
||||||
|
spy = jest.spyOn(Collection.prototype, 'listSearchIndexes');
|
||||||
|
const mockCursor = {
|
||||||
|
toArray: async () => [{ name: 'my-index' }, { name: 'my-index-2' }],
|
||||||
|
};
|
||||||
|
spy.mockReturnValue(mockCursor);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => jest.restoreAllMocks());
|
||||||
|
|
||||||
|
testHarness.setupTest(
|
||||||
|
buildWorkflow({
|
||||||
|
parameters: {
|
||||||
|
operation: 'listSearchIndexes',
|
||||||
|
resource: 'searchIndexes',
|
||||||
|
collection: 'foo',
|
||||||
|
indexName: 'my-index',
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
{
|
||||||
|
json: { name: 'my-index' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
json: { name: 'my-index-2' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('dropSearchIndex operation', () => {
|
||||||
|
let spy: jest.SpyInstance;
|
||||||
|
afterAll(() => jest.restoreAllMocks());
|
||||||
|
beforeAll(() => {
|
||||||
|
spy = jest.spyOn(Collection.prototype, 'dropSearchIndex');
|
||||||
|
spy.mockResolvedValueOnce(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
testHarness.setupTest(
|
||||||
|
buildWorkflow({
|
||||||
|
parameters: {
|
||||||
|
operation: 'dropSearchIndex',
|
||||||
|
resource: 'searchIndexes',
|
||||||
|
collection: 'foo',
|
||||||
|
indexNameRequired: 'my-index',
|
||||||
|
},
|
||||||
|
expectedResult: [{ json: { 'my-index': true } }],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
it('calls the spy with the expected arguments', function () {
|
||||||
|
expect(spy).toBeCalledWith('my-index');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateSearchIndex operation', () => {
|
||||||
|
let spy: jest.SpyInstance;
|
||||||
|
afterAll(() => jest.restoreAllMocks());
|
||||||
|
beforeAll(() => {
|
||||||
|
spy = jest.spyOn(Collection.prototype, 'updateSearchIndex');
|
||||||
|
spy.mockResolvedValueOnce(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
testHarness.setupTest(
|
||||||
|
buildWorkflow({
|
||||||
|
parameters: {
|
||||||
|
operation: 'updateSearchIndex',
|
||||||
|
resource: 'searchIndexes',
|
||||||
|
collection: 'foo',
|
||||||
|
indexNameRequired: 'my-index',
|
||||||
|
indexDefinition: JSON.stringify({
|
||||||
|
mappings: {
|
||||||
|
dynamic: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
expectedResult: [{ json: { 'my-index': true } }],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
it('calls the spy with the expected arguments', function () {
|
||||||
|
expect(spy).toBeCalledWith('my-index', { mappings: { dynamic: true } });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user