diff --git a/packages/server/src/api/routes/tests/queries/mongodb.spec.ts b/packages/server/src/api/routes/tests/queries/mongodb.spec.ts index 4822729478..44c4fb7c65 100644 --- a/packages/server/src/api/routes/tests/queries/mongodb.spec.ts +++ b/packages/server/src/api/routes/tests/queries/mongodb.spec.ts @@ -1,8 +1,7 @@ import { Datasource, Query } from "@budibase/types" -import * as setup from "../utilities" import { DatabaseName, - getDatasource, + datasourceDescribe, } from "../../../../integrations/tests/utils" import { MongoClient, type Collection, BSON, Db } from "mongodb" import { generator } from "@budibase/backend-core/tests" @@ -10,468 +9,695 @@ import { generator } from "@budibase/backend-core/tests" const expectValidId = expect.stringMatching(/^\w{24}$/) const expectValidBsonObjectId = expect.any(BSON.ObjectId) -describe("/queries", () => { - let collection: string - let config = setup.getConfig() - let datasource: Datasource +datasourceDescribe( + { name: "/queries", only: [DatabaseName.MONGODB] }, + ({ config, dsProvider }) => { + let collection: string + let datasource: Datasource - async function createQuery(query: Partial): Promise { - const defaultQuery: Query = { - datasourceId: datasource._id!, - name: "New Query", - parameters: [], - fields: {}, - schema: {}, - queryVerb: "read", - transformer: "return data", - readable: true, - } - const combinedQuery = { ...defaultQuery, ...query } - if ( - combinedQuery.fields && - combinedQuery.fields.extra && - !combinedQuery.fields.extra.collection - ) { - combinedQuery.fields.extra.collection = collection - } - return await config.api.query.save(combinedQuery) - } - - async function withClient( - callback: (client: MongoClient) => Promise - ): Promise { - const client = new MongoClient(datasource.config!.connectionString) - await client.connect() - try { - return await callback(client) - } finally { - await client.close() - } - } - - async function withDb(callback: (db: Db) => Promise): Promise { - return await withClient(async client => { - return await callback(client.db(datasource.config!.db)) - }) - } - - async function withCollection( - callback: (collection: Collection) => Promise - ): Promise { - return await withDb(async db => { - return await callback(db.collection(collection)) - }) - } - - afterAll(async () => { - setup.afterAll() - }) - - beforeAll(async () => { - await config.init() - datasource = await config.api.datasource.create( - await getDatasource(DatabaseName.MONGODB) - ) - }) - - beforeEach(async () => { - collection = generator.guid() - await withCollection(async collection => { - await collection.insertMany([ - { name: "one" }, - { name: "two" }, - { name: "three" }, - { name: "four" }, - { name: "five" }, - ]) - }) - }) - - afterEach(async () => { - await withCollection(collection => collection.drop()) - }) - - describe("preview", () => { - it("should generate a nested schema with an empty array", async () => { - const name = generator.guid() - await withCollection( - async collection => await collection.insertOne({ name, nested: [] }) - ) - - const preview = await config.api.query.preview({ + async function createQuery(query: Partial): Promise { + const defaultQuery: Query = { + datasourceId: datasource._id!, name: "New Query", - datasourceId: datasource._id!, - fields: { - json: { - name: { $eq: name }, - }, - extra: { - collection, - actionType: "findOne", - }, - }, + parameters: [], + fields: {}, schema: {}, queryVerb: "read", - parameters: [], transformer: "return data", readable: true, - }) - - expect(preview).toEqual({ - nestedSchemaFields: {}, - rows: [{ _id: expect.any(String), name, nested: [] }], - schema: { - _id: { - type: "string", - name: "_id", - }, - name: { - type: "string", - name: "name", - }, - nested: { - type: "array", - name: "nested", - }, - }, - }) - }) - - it("should update schema when structure changes from object to array", async () => { - const name = generator.guid() - - await withCollection(async collection => { - await collection.insertOne({ name, field: { subfield: "value" } }) - }) - - const firstPreview = await config.api.query.preview({ - name: "Test Query", - datasourceId: datasource._id!, - fields: { - json: { name: { $eq: name } }, - extra: { - collection, - actionType: "findOne", - }, - }, - schema: {}, - queryVerb: "read", - parameters: [], - transformer: "return data", - readable: true, - }) - - expect(firstPreview.schema).toEqual( - expect.objectContaining({ - field: { type: "json", name: "field" }, - }) - ) - - await withCollection(async collection => { - await collection.updateOne( - { name }, - { $set: { field: ["value1", "value2"] } } - ) - }) - - const secondPreview = await config.api.query.preview({ - name: "Test Query", - datasourceId: datasource._id!, - fields: { - json: { name: { $eq: name } }, - extra: { - collection, - actionType: "findOne", - }, - }, - schema: firstPreview.schema, - queryVerb: "read", - parameters: [], - transformer: "return data", - readable: true, - }) - - expect(secondPreview.schema).toEqual( - expect.objectContaining({ - field: { type: "array", name: "field" }, - }) - ) - }) - - it("should generate a nested schema based on all of the nested items", async () => { - const name = generator.guid() - const item = { - name, - contacts: [ - { - address: "123 Lane", - }, - { - address: "456 Drive", - }, - { - postcode: "BT1 12N", - lat: 54.59, - long: -5.92, - }, - { - city: "Belfast", - }, - { - address: "789 Avenue", - phoneNumber: "0800-999-5555", - }, - { - name: "Name", - isActive: false, - }, - ], } + const combinedQuery = { ...defaultQuery, ...query } + if ( + combinedQuery.fields && + combinedQuery.fields.extra && + !combinedQuery.fields.extra.collection + ) { + combinedQuery.fields.extra.collection = collection + } + return await config.api.query.save(combinedQuery) + } - await withCollection(collection => collection.insertOne(item)) + async function withClient( + callback: (client: MongoClient) => Promise + ): Promise { + const client = new MongoClient(datasource.config!.connectionString) + await client.connect() + try { + return await callback(client) + } finally { + await client.close() + } + } - const preview = await config.api.query.preview({ - name: "New Query", - datasourceId: datasource._id!, - fields: { - json: { - name: { $eq: name }, - }, - extra: { - collection, - actionType: "findOne", - }, - }, - schema: {}, - queryVerb: "read", - parameters: [], - transformer: "return data", - readable: true, + async function withDb(callback: (db: Db) => Promise): Promise { + return await withClient(async client => { + return await callback(client.db(datasource.config!.db)) }) + } - expect(preview).toEqual({ - nestedSchemaFields: { - contacts: { - address: { + async function withCollection( + callback: (collection: Collection) => Promise + ): Promise { + return await withDb(async db => { + return await callback(db.collection(collection)) + }) + } + + beforeAll(async () => { + const ds = await dsProvider + datasource = ds.datasource! + }) + + beforeEach(async () => { + collection = generator.guid() + await withCollection(async collection => { + await collection.insertMany([ + { name: "one" }, + { name: "two" }, + { name: "three" }, + { name: "four" }, + { name: "five" }, + ]) + }) + }) + + afterEach(async () => { + await withCollection(collection => collection.drop()) + }) + + describe("preview", () => { + it("should generate a nested schema with an empty array", async () => { + const name = generator.guid() + await withCollection( + async collection => await collection.insertOne({ name, nested: [] }) + ) + + const preview = await config.api.query.preview({ + name: "New Query", + datasourceId: datasource._id!, + fields: { + json: { + name: { $eq: name }, + }, + extra: { + collection, + actionType: "findOne", + }, + }, + schema: {}, + queryVerb: "read", + parameters: [], + transformer: "return data", + readable: true, + }) + + expect(preview).toEqual({ + nestedSchemaFields: {}, + rows: [{ _id: expect.any(String), name, nested: [] }], + schema: { + _id: { type: "string", - name: "address", - }, - postcode: { - type: "string", - name: "postcode", - }, - lat: { - type: "number", - name: "lat", - }, - long: { - type: "number", - name: "long", - }, - city: { - type: "string", - name: "city", - }, - phoneNumber: { - type: "string", - name: "phoneNumber", + name: "_id", }, name: { type: "string", name: "name", }, - isActive: { - type: "boolean", - name: "isActive", + nested: { + type: "array", + name: "nested", }, }, - }, - rows: [{ ...item, _id: expect.any(String) }], - schema: { - _id: { type: "string", name: "_id" }, - name: { type: "string", name: "name" }, - contacts: { type: "json", name: "contacts", subtype: "array" }, - }, - }) - }) - }) - - describe("execute", () => { - it("a count query", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "count", - }, - }, + }) }) - const result = await config.api.query.execute(query._id!) + it("should update schema when structure changes from object to array", async () => { + const name = generator.guid() - expect(result.data).toEqual([{ value: 5 }]) - }) + await withCollection(async collection => { + await collection.insertOne({ name, field: { subfield: "value" } }) + }) - it("should be able to updateOne by ObjectId", async () => { - const insertResult = await withCollection(c => - c.insertOne({ name: "one" }) - ) - const query = await createQuery({ - fields: { - json: { - filter: { _id: { $eq: `ObjectId("${insertResult.insertedId}")` } }, - update: { $set: { name: "newName" } }, + const firstPreview = await config.api.query.preview({ + name: "Test Query", + datasourceId: datasource._id!, + fields: { + json: { name: { $eq: name } }, + extra: { + collection, + actionType: "findOne", + }, }, - extra: { - actionType: "updateOne", + schema: {}, + queryVerb: "read", + parameters: [], + transformer: "return data", + readable: true, + }) + + expect(firstPreview.schema).toEqual( + expect.objectContaining({ + field: { type: "json", name: "field" }, + }) + ) + + await withCollection(async collection => { + await collection.updateOne( + { name }, + { $set: { field: ["value1", "value2"] } } + ) + }) + + const secondPreview = await config.api.query.preview({ + name: "Test Query", + datasourceId: datasource._id!, + fields: { + json: { name: { $eq: name } }, + extra: { + collection, + actionType: "findOne", + }, }, - }, - queryVerb: "update", + schema: firstPreview.schema, + queryVerb: "read", + parameters: [], + transformer: "return data", + readable: true, + }) + + expect(secondPreview.schema).toEqual( + expect.objectContaining({ + field: { type: "array", name: "field" }, + }) + ) }) - const result = await config.api.query.execute(query._id!) + it("should generate a nested schema based on all of the nested items", async () => { + const name = generator.guid() + const item = { + name, + contacts: [ + { + address: "123 Lane", + }, + { + address: "456 Drive", + }, + { + postcode: "BT1 12N", + lat: 54.59, + long: -5.92, + }, + { + city: "Belfast", + }, + { + address: "789 Avenue", + phoneNumber: "0800-999-5555", + }, + { + name: "Name", + isActive: false, + }, + ], + } - expect(result.data).toEqual([ - { - acknowledged: true, - matchedCount: 1, - modifiedCount: 1, - upsertedCount: 0, - upsertedId: null, - }, - ]) + await withCollection(collection => collection.insertOne(item)) - await withCollection(async collection => { - const doc = await collection.findOne({ name: { $eq: "newName" } }) - expect(doc).toEqual({ - _id: insertResult.insertedId, - name: "newName", + const preview = await config.api.query.preview({ + name: "New Query", + datasourceId: datasource._id!, + fields: { + json: { + name: { $eq: name }, + }, + extra: { + collection, + actionType: "findOne", + }, + }, + schema: {}, + queryVerb: "read", + parameters: [], + transformer: "return data", + readable: true, + }) + + expect(preview).toEqual({ + nestedSchemaFields: { + contacts: { + address: { + type: "string", + name: "address", + }, + postcode: { + type: "string", + name: "postcode", + }, + lat: { + type: "number", + name: "lat", + }, + long: { + type: "number", + name: "long", + }, + city: { + type: "string", + name: "city", + }, + phoneNumber: { + type: "string", + name: "phoneNumber", + }, + name: { + type: "string", + name: "name", + }, + isActive: { + type: "boolean", + name: "isActive", + }, + }, + }, + rows: [{ ...item, _id: expect.any(String) }], + schema: { + _id: { type: "string", name: "_id" }, + name: { type: "string", name: "name" }, + contacts: { type: "json", name: "contacts", subtype: "array" }, + }, }) }) }) - it("a count query with a transformer", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "count", + describe("execute", () => { + it("a count query", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "count", + }, }, - }, - transformer: "return data + 1", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([{ value: 5 }]) }) - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([{ value: 6 }]) - }) - - it("a find query", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "find", + it("should be able to updateOne by ObjectId", async () => { + const insertResult = await withCollection(c => + c.insertOne({ name: "one" }) + ) + const query = await createQuery({ + fields: { + json: { + filter: { + _id: { $eq: `ObjectId("${insertResult.insertedId}")` }, + }, + update: { $set: { name: "newName" } }, + }, + extra: { + actionType: "updateOne", + }, }, - }, + queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + acknowledged: true, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0, + upsertedId: null, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ name: { $eq: "newName" } }) + expect(doc).toEqual({ + _id: insertResult.insertedId, + name: "newName", + }) + }) }) - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { _id: expectValidId, name: "one" }, - { _id: expectValidId, name: "two" }, - { _id: expectValidId, name: "three" }, - { _id: expectValidId, name: "four" }, - { _id: expectValidId, name: "five" }, - ]) - }) - - it("a findOne query", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "findOne", + it("a count query with a transformer", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "count", + }, }, - }, + transformer: "return data + 1", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([{ value: 6 }]) }) - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([{ _id: expectValidId, name: "one" }]) - }) - - it("a findOneAndUpdate query", async () => { - const query = await createQuery({ - fields: { - json: { - filter: { name: { $eq: "one" } }, - update: { $set: { name: "newName" } }, + it("a find query", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "find", + }, }, - extra: { - actionType: "findOneAndUpdate", - }, - }, + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { _id: expectValidId, name: "one" }, + { _id: expectValidId, name: "two" }, + { _id: expectValidId, name: "three" }, + { _id: expectValidId, name: "four" }, + { _id: expectValidId, name: "five" }, + ]) }) - const result = await config.api.query.execute(query._id!) + it("a findOne query", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "findOne", + }, + }, + }) - expect(result.data).toEqual([ - { - lastErrorObject: { n: 1, updatedExisting: true }, - ok: 1, - value: { _id: expectValidId, name: "one" }, - }, - ]) + const result = await config.api.query.execute(query._id!) - await withCollection(async collection => { - expect(await collection.countDocuments()).toBe(5) + expect(result.data).toEqual([{ _id: expectValidId, name: "one" }]) + }) - const doc = await collection.findOne({ name: { $eq: "newName" } }) - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - name: "newName", + it("a findOneAndUpdate query", async () => { + const query = await createQuery({ + fields: { + json: { + filter: { name: { $eq: "one" } }, + update: { $set: { name: "newName" } }, + }, + extra: { + actionType: "findOneAndUpdate", + }, + }, + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + lastErrorObject: { n: 1, updatedExisting: true }, + ok: 1, + value: { _id: expectValidId, name: "one" }, + }, + ]) + + await withCollection(async collection => { + expect(await collection.countDocuments()).toBe(5) + + const doc = await collection.findOne({ name: { $eq: "newName" } }) + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + name: "newName", + }) + }) + }) + + it("a distinct query", async () => { + const query = await createQuery({ + fields: { + json: "name", + extra: { + actionType: "distinct", + }, + }, + }) + + const result = await config.api.query.execute(query._id!) + const values = result.data.map(o => o.value).sort() + expect(values).toEqual(["five", "four", "one", "three", "two"]) + }) + + it("a create query with parameters", async () => { + const query = await createQuery({ + fields: { + json: { foo: "{{ foo }}" }, + extra: { + actionType: "insertOne", + }, + }, + queryVerb: "create", + parameters: [ + { + name: "foo", + default: "default", + }, + ], + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { foo: "bar" }, + }) + + expect(result.data).toEqual([ + { + acknowledged: true, + insertedId: expectValidId, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ foo: { $eq: "bar" } }) + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + foo: "bar", + }) + }) + }) + + it("a delete query with parameters", async () => { + const query = await createQuery({ + fields: { + json: { name: { $eq: "{{ name }}" } }, + extra: { + actionType: "deleteOne", + }, + }, + queryVerb: "delete", + parameters: [ + { + name: "name", + default: "", + }, + ], + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { name: "one" }, + }) + + expect(result.data).toEqual([ + { + acknowledged: true, + deletedCount: 1, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ name: { $eq: "one" } }) + expect(doc).toBeNull() + }) + }) + + it("an update query with parameters", async () => { + const query = await createQuery({ + fields: { + json: { + filter: { name: { $eq: "{{ name }}" } }, + update: { $set: { name: "{{ newName }}" } }, + }, + extra: { + actionType: "updateOne", + }, + }, + queryVerb: "update", + parameters: [ + { + name: "name", + default: "", + }, + { + name: "newName", + default: "", + }, + ], + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { name: "one", newName: "newOne" }, + }) + + expect(result.data).toEqual([ + { + acknowledged: true, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0, + upsertedId: null, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ name: { $eq: "newOne" } }) + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + name: "newOne", + }) + + const oldDoc = await collection.findOne({ name: { $eq: "one" } }) + expect(oldDoc).toBeNull() + }) + }) + + it("should be able to delete all records", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "deleteMany", + }, + }, + queryVerb: "delete", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + acknowledged: true, + deletedCount: 5, + }, + ]) + + await withCollection(async collection => { + const docs = await collection.find().toArray() + expect(docs).toHaveLength(0) + }) + }) + + it("should be able to update all documents", async () => { + const query = await createQuery({ + fields: { + json: { + filter: {}, + update: { $set: { name: "newName" } }, + }, + extra: { + actionType: "updateMany", + }, + }, + queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + acknowledged: true, + matchedCount: 5, + modifiedCount: 5, + upsertedCount: 0, + upsertedId: null, + }, + ]) + + await withCollection(async collection => { + const docs = await collection.find().toArray() + expect(docs).toHaveLength(5) + for (const doc of docs) { + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + name: "newName", + }) + } }) }) }) - it("a distinct query", async () => { - const query = await createQuery({ - fields: { - json: "name", - extra: { - actionType: "distinct", - }, - }, - }) - - const result = await config.api.query.execute(query._id!) - const values = result.data.map(o => o.value).sort() - expect(values).toEqual(["five", "four", "one", "three", "two"]) + it("should throw an error if the incorrect actionType is specified", async () => { + const verbs = ["read", "create", "update", "delete"] + for (const verb of verbs) { + const query = await createQuery({ + fields: { json: {}, extra: { actionType: "invalid" } }, + queryVerb: verb, + }) + await config.api.query.execute(query._id!, undefined, { status: 400 }) + } }) - it("a create query with parameters", async () => { + it("should ignore extra brackets in query", async () => { const query = await createQuery({ fields: { - json: { foo: "{{ foo }}" }, + json: { foo: "te}st" }, extra: { actionType: "insertOne", }, }, queryVerb: "create", - parameters: [ + }) + + const result = await config.api.query.execute(query._id!) + expect(result.data).toEqual([ + { + acknowledged: true, + insertedId: expectValidId, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ foo: { $eq: "te}st" } }) + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + foo: "te}st", + }) + }) + }) + + it("should be able to save deeply nested data", async () => { + const data = { + foo: "bar", + data: [ + { cid: 1 }, + { cid: 2 }, { - name: "foo", - default: "default", + nested: { + name: "test", + ary: [1, 2, 3], + aryOfObjects: [{ a: 1 }, { b: 2 }], + }, }, ], + } + const query = await createQuery({ + fields: { + json: data, + extra: { + actionType: "insertOne", + }, + }, + queryVerb: "create", }) - const result = await config.api.query.execute(query._id!, { - parameters: { foo: "bar" }, - }) - + const result = await config.api.query.execute(query._id!) expect(result.data).toEqual([ { acknowledged: true, @@ -483,238 +709,9 @@ describe("/queries", () => { const doc = await collection.findOne({ foo: { $eq: "bar" } }) expect(doc).toEqual({ _id: expectValidBsonObjectId, - foo: "bar", + ...data, }) }) }) - - it("a delete query with parameters", async () => { - const query = await createQuery({ - fields: { - json: { name: { $eq: "{{ name }}" } }, - extra: { - actionType: "deleteOne", - }, - }, - queryVerb: "delete", - parameters: [ - { - name: "name", - default: "", - }, - ], - }) - - const result = await config.api.query.execute(query._id!, { - parameters: { name: "one" }, - }) - - expect(result.data).toEqual([ - { - acknowledged: true, - deletedCount: 1, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ name: { $eq: "one" } }) - expect(doc).toBeNull() - }) - }) - - it("an update query with parameters", async () => { - const query = await createQuery({ - fields: { - json: { - filter: { name: { $eq: "{{ name }}" } }, - update: { $set: { name: "{{ newName }}" } }, - }, - extra: { - actionType: "updateOne", - }, - }, - queryVerb: "update", - parameters: [ - { - name: "name", - default: "", - }, - { - name: "newName", - default: "", - }, - ], - }) - - const result = await config.api.query.execute(query._id!, { - parameters: { name: "one", newName: "newOne" }, - }) - - expect(result.data).toEqual([ - { - acknowledged: true, - matchedCount: 1, - modifiedCount: 1, - upsertedCount: 0, - upsertedId: null, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ name: { $eq: "newOne" } }) - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - name: "newOne", - }) - - const oldDoc = await collection.findOne({ name: { $eq: "one" } }) - expect(oldDoc).toBeNull() - }) - }) - - it("should be able to delete all records", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "deleteMany", - }, - }, - queryVerb: "delete", - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - acknowledged: true, - deletedCount: 5, - }, - ]) - - await withCollection(async collection => { - const docs = await collection.find().toArray() - expect(docs).toHaveLength(0) - }) - }) - - it("should be able to update all documents", async () => { - const query = await createQuery({ - fields: { - json: { - filter: {}, - update: { $set: { name: "newName" } }, - }, - extra: { - actionType: "updateMany", - }, - }, - queryVerb: "update", - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - acknowledged: true, - matchedCount: 5, - modifiedCount: 5, - upsertedCount: 0, - upsertedId: null, - }, - ]) - - await withCollection(async collection => { - const docs = await collection.find().toArray() - expect(docs).toHaveLength(5) - for (const doc of docs) { - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - name: "newName", - }) - } - }) - }) - }) - - it("should throw an error if the incorrect actionType is specified", async () => { - const verbs = ["read", "create", "update", "delete"] - for (const verb of verbs) { - const query = await createQuery({ - fields: { json: {}, extra: { actionType: "invalid" } }, - queryVerb: verb, - }) - await config.api.query.execute(query._id!, undefined, { status: 400 }) - } - }) - - it("should ignore extra brackets in query", async () => { - const query = await createQuery({ - fields: { - json: { foo: "te}st" }, - extra: { - actionType: "insertOne", - }, - }, - queryVerb: "create", - }) - - const result = await config.api.query.execute(query._id!) - expect(result.data).toEqual([ - { - acknowledged: true, - insertedId: expectValidId, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ foo: { $eq: "te}st" } }) - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - foo: "te}st", - }) - }) - }) - - it("should be able to save deeply nested data", async () => { - const data = { - foo: "bar", - data: [ - { cid: 1 }, - { cid: 2 }, - { - nested: { - name: "test", - ary: [1, 2, 3], - aryOfObjects: [{ a: 1 }, { b: 2 }], - }, - }, - ], - } - const query = await createQuery({ - fields: { - json: data, - extra: { - actionType: "insertOne", - }, - }, - queryVerb: "create", - }) - - const result = await config.api.query.execute(query._id!) - expect(result.data).toEqual([ - { - acknowledged: true, - insertedId: expectValidId, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ foo: { $eq: "bar" } }) - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - ...data, - }) - }) - }) -}) + } +)