diff --git a/lerna.json b/lerna.json
index 4b1c967e11..99915ab67b 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"npmClient": "yarn",
"packages": [
"packages/*"
diff --git a/package.json b/package.json
index fb6d9da990..84f1999ead 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,8 @@
"private": true,
"devDependencies": {
"@rollup/plugin-json": "^4.0.2",
+ "@types/mongodb": "3.6.3",
+ "@typescript-eslint/parser": "4.28.0",
"babel-eslint": "^10.0.3",
"eslint": "^7.28.0",
"eslint-plugin-cypress": "^2.11.3",
@@ -16,7 +18,6 @@
"rimraf": "^3.0.2",
"rollup-plugin-replace": "^2.2.0",
"svelte": "^3.38.2",
- "@typescript-eslint/parser": "4.28.0",
"typescript": "4.5.5"
},
"scripts": {
diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json
index 7464b90725..68df3f3f4c 100644
--- a/packages/backend-core/package.json
+++ b/packages/backend-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/backend-core",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"description": "Budibase backend core libraries used in server and worker",
"main": "src/index.js",
"author": "Budibase",
diff --git a/packages/backend-core/src/middleware/passport/datasource/google.js b/packages/backend-core/src/middleware/passport/datasource/google.js
index 96c7f99953..9b8019575c 100644
--- a/packages/backend-core/src/middleware/passport/datasource/google.js
+++ b/packages/backend-core/src/middleware/passport/datasource/google.js
@@ -1,7 +1,7 @@
const google = require("../google")
const { Cookies, Configs } = require("../../../constants")
const { clearCookie, getCookie } = require("../../../utils")
-const { getScopedConfig, getPlatformUrl } = require("../../../db/utils")
+const { getScopedConfig } = require("../../../db/utils")
const { doWithDB } = require("../../../db")
const environment = require("../../../environment")
const { getGlobalDB } = require("../../../tenancy")
@@ -21,20 +21,28 @@ async function fetchGoogleCreds() {
)
}
-async function platformUrl() {
+async function getPlatformUrl() {
+ let platformUrl = environment.PLATFORM_URL || "http://localhost:10000"
+
const db = getGlobalDB()
- const publicConfig = await getScopedConfig(db, {
+ const settings = await getScopedConfig(db, {
type: Configs.SETTINGS,
})
- return getPlatformUrl(publicConfig)
+
+ // self hosted - check for platform url override
+ if (settings && settings.platformUrl) {
+ platformUrl = settings.platformUrl
+ }
+
+ return platformUrl
}
async function preAuth(passport, ctx, next) {
// get the relevant config
const googleConfig = await fetchGoogleCreds()
- const platUrl = await platformUrl()
+ const platformUrl = await getPlatformUrl()
- let callbackUrl = `${platUrl}/api/global/auth/datasource/google/callback`
+ let callbackUrl = `${platformUrl}/api/global/auth/datasource/google/callback`
const strategy = await google.strategyFactory(googleConfig, callbackUrl)
if (!ctx.query.appId || !ctx.query.datasourceId) {
@@ -51,9 +59,9 @@ async function preAuth(passport, ctx, next) {
async function postAuth(passport, ctx, next) {
// get the relevant config
const config = await fetchGoogleCreds()
- const platUrl = await platformUrl()
+ const platformUrl = await getPlatformUrl()
- let callbackUrl = `${platUrl}/api/global/auth/datasource/google/callback`
+ let callbackUrl = `${platformUrl}/api/global/auth/datasource/google/callback`
const strategy = await google.strategyFactory(
config,
callbackUrl,
diff --git a/packages/backend-core/src/middleware/passport/tests/oidc.spec.js b/packages/backend-core/src/middleware/passport/tests/oidc.spec.js
index bfe9f97dc0..c5e9fe0034 100644
--- a/packages/backend-core/src/middleware/passport/tests/oidc.spec.js
+++ b/packages/backend-core/src/middleware/passport/tests/oidc.spec.js
@@ -71,7 +71,7 @@ describe("oidc", () => {
describe("authenticate", () => {
afterEach(() => {
- jest.clearAllMocks();
+ jest.clearAllMocks()
});
// mock third party common authentication
@@ -80,10 +80,10 @@ describe("oidc", () => {
// mock the passport callback
const mockDone = jest.fn()
+ const mockSaveUserFn = jest.fn()
async function doAuthenticate() {
const oidc = require("../oidc")
- const mockSaveUserFn = jest.fn()
const authenticate = await oidc.buildVerifyFn(mockSaveUserFn)
await authenticate(
@@ -105,11 +105,13 @@ describe("oidc", () => {
expect(authenticateThirdParty).toHaveBeenCalledWith(
user,
false,
- mockDone)
+ mockDone,
+ mockSaveUserFn,
+ )
}
it("delegates authentication to third party common", async () => {
- doTest()
+ await doTest()
})
it("uses JWT email to get email", async () => {
@@ -118,7 +120,7 @@ describe("oidc", () => {
email : "mock@budibase.com"
}
- doTest()
+ await doTest()
})
it("uses JWT username to get email", async () => {
@@ -127,7 +129,7 @@ describe("oidc", () => {
preferred_username : "mock@budibase.com"
}
- doTest()
+ await doTest()
})
it("uses JWT invalid username to get email", async () => {
diff --git a/packages/bbui/package.json b/packages/bbui/package.json
index b00d3fc993..3147880fcb 100644
--- a/packages/bbui/package.json
+++ b/packages/bbui/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"license": "MPL-2.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",
@@ -38,7 +38,7 @@
],
"dependencies": {
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
- "@budibase/string-templates": "^1.0.159-alpha.3",
+ "@budibase/string-templates": "^1.0.163",
"@spectrum-css/actionbutton": "^1.0.1",
"@spectrum-css/actiongroup": "^1.0.1",
"@spectrum-css/avatar": "^3.0.2",
diff --git a/packages/bbui/src/Form/Core/DatePicker.svelte b/packages/bbui/src/Form/Core/DatePicker.svelte
index 1d0d32b03c..73ba7bb642 100644
--- a/packages/bbui/src/Form/Core/DatePicker.svelte
+++ b/packages/bbui/src/Form/Core/DatePicker.svelte
@@ -58,6 +58,11 @@
if (timeOnly) {
newValue = `2000-01-01T${newValue.split("T")[1]}`
}
+ // date only, offset for timezone so always right date
+ else if (!enableTime) {
+ const offset = dates[0].getTimezoneOffset() * 60000
+ newValue = new Date(dates[0].getTime() - offset).toISOString()
+ }
dispatch("change", newValue)
}
diff --git a/packages/builder/package.json b/packages/builder/package.json
index b7db9f6375..95611c6713 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"license": "GPL-3.0",
"private": true,
"scripts": {
@@ -67,10 +67,10 @@
}
},
"dependencies": {
- "@budibase/bbui": "^1.0.159-alpha.3",
- "@budibase/client": "^1.0.159-alpha.3",
- "@budibase/frontend-core": "^1.0.159-alpha.3",
- "@budibase/string-templates": "^1.0.159-alpha.3",
+ "@budibase/bbui": "^1.0.163",
+ "@budibase/client": "^1.0.163",
+ "@budibase/frontend-core": "^1.0.163",
+ "@budibase/string-templates": "^1.0.163",
"@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1",
diff --git a/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte b/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte
index dcd96ce2b9..9ba4140b51 100644
--- a/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte
+++ b/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte
@@ -12,4 +12,4 @@
}
-
+
diff --git a/packages/builder/src/components/common/inputs/CopyInput.svelte b/packages/builder/src/components/common/inputs/CopyInput.svelte
index 102fd5682a..589623f542 100644
--- a/packages/builder/src/components/common/inputs/CopyInput.svelte
+++ b/packages/builder/src/components/common/inputs/CopyInput.svelte
@@ -3,7 +3,6 @@
export let label = null
export let value
- export let copyValue
export let dataCy = null
const copyToClipboard = val => {
@@ -19,7 +18,7 @@
-
copyToClipboard(value || copyValue)}>
+
copyToClipboard(value)}>
diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte
index 5a60bfdff8..a9399fcca7 100644
--- a/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte
+++ b/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte
@@ -14,7 +14,10 @@
let options = roles
.filter(role => role._id !== "PUBLIC")
.map(role => ({ value: role._id, label: role.name }))
- options.push({ value: NO_ACCESS, label: "No Access" })
+
+ if (!user?.builder?.global) {
+ options.push({ value: NO_ACCESS, label: "No Access" })
+ }
let selectedRole = user?.roles?.[app?._id]
async function updateUserRoles() {
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 31bdbc910c..340f51c434 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {
diff --git a/packages/client/package.json b/packages/client/package.json
index 80251bc351..64f8b2a32c 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/client",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@@ -19,9 +19,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
- "@budibase/bbui": "^1.0.159-alpha.3",
- "@budibase/frontend-core": "^1.0.159-alpha.3",
- "@budibase/string-templates": "^1.0.159-alpha.3",
+ "@budibase/bbui": "^1.0.163",
+ "@budibase/frontend-core": "^1.0.163",
+ "@budibase/string-templates": "^1.0.163",
"@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3",
diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json
index c6f0ff4bec..c10eedf983 100644
--- a/packages/frontend-core/package.json
+++ b/packages/frontend-core/package.json
@@ -1,12 +1,12 @@
{
"name": "@budibase/frontend-core",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase",
"license": "MPL-2.0",
"svelte": "src/index.js",
"dependencies": {
- "@budibase/bbui": "^1.0.159-alpha.3",
+ "@budibase/bbui": "^1.0.163",
"lodash": "^4.17.21",
"svelte": "^3.46.2"
}
diff --git a/packages/server/package.json b/packages/server/package.json
index 920bb66efb..ecc02aef4f 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"description": "Budibase Web Server",
"main": "src/index.ts",
"repository": {
@@ -69,10 +69,10 @@
"license": "GPL-3.0",
"dependencies": {
"@apidevtools/swagger-parser": "^10.0.3",
- "@budibase/backend-core": "^1.0.159-alpha.3",
- "@budibase/client": "^1.0.159-alpha.3",
- "@budibase/pro": "1.0.159-alpha.3",
- "@budibase/string-templates": "^1.0.159-alpha.3",
+ "@budibase/backend-core": "^1.0.163",
+ "@budibase/client": "^1.0.163",
+ "@budibase/pro": "1.0.163",
+ "@budibase/string-templates": "^1.0.163",
"@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0",
diff --git a/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap b/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap
index 27c8615a46..4572a8a24f 100644
--- a/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap
+++ b/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap
@@ -1,9 +1,66 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`viewBuilder Calculate and filter creates a view with the calculation statistics and filter schema 1`] = `
+Object {
+ "map": "function (doc) {
+ if ((doc.tableId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" && !(
+ doc[\\"myField\\"] === undefined ||
+ doc[\\"myField\\"] === null ||
+ doc[\\"myField\\"] === \\"\\" ||
+ (Array.isArray(doc[\\"myField\\"]) && doc[\\"myField\\"].length === 0)
+ )) && (doc[\\"age\\"] > 17)) {
+ emit(doc[\\"_id\\"], doc[\\"myField\\"]);
+ }
+ }",
+ "meta": Object {
+ "calculation": "stats",
+ "field": "myField",
+ "filters": Array [
+ Object {
+ "condition": "MT",
+ "key": "age",
+ "value": 17,
+ },
+ ],
+ "groupBy": undefined,
+ "schema": Object {
+ "avg": Object {
+ "type": "number",
+ },
+ "count": Object {
+ "type": "number",
+ },
+ "field": Object {
+ "type": "string",
+ },
+ "max": Object {
+ "type": "number",
+ },
+ "min": Object {
+ "type": "number",
+ },
+ "sum": Object {
+ "type": "number",
+ },
+ "sumsqr": Object {
+ "type": "number",
+ },
+ },
+ "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0",
+ },
+ "reduce": "_stats",
+}
+`;
+
exports[`viewBuilder Calculate creates a view with the calculation statistics schema 1`] = `
Object {
"map": "function (doc) {
- if (doc.tableId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" ) {
+ if ((doc.tableId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" && !(
+ doc[\\"myField\\"] === undefined ||
+ doc[\\"myField\\"] === null ||
+ doc[\\"myField\\"] === \\"\\" ||
+ (Array.isArray(doc[\\"myField\\"]) && doc[\\"myField\\"].length === 0)
+ )) ) {
emit(doc[\\"_id\\"], doc[\\"myField\\"]);
}
}",
diff --git a/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js b/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js
index d1674bca08..58fb68cfa7 100644
--- a/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js
+++ b/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js
@@ -44,4 +44,22 @@ describe("viewBuilder", () => {
})).toMatchSnapshot()
})
})
+
+ describe("Calculate and filter", () => {
+ it("creates a view with the calculation statistics and filter schema", () => {
+ expect(viewTemplate({
+ "name": "Calculate View",
+ "field": "myField",
+ "calculation": "stats",
+ "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0",
+ "filters": [
+ {
+ "value": 17,
+ "condition": "MT",
+ "key": "age",
+ }
+ ]
+ })).toMatchSnapshot()
+ })
+ })
});
\ No newline at end of file
diff --git a/packages/server/src/api/controllers/view/utils.js b/packages/server/src/api/controllers/view/utils.js
index 59d169ef7f..5bddbf345c 100644
--- a/packages/server/src/api/controllers/view/utils.js
+++ b/packages/server/src/api/controllers/view/utils.js
@@ -7,6 +7,7 @@ const {
} = require("../../../db/utils")
const env = require("../../../environment")
const { getAppDB } = require("@budibase/backend-core/context")
+const viewBuilder = require("./viewBuilder")
exports.getView = async viewName => {
const db = getAppDB()
@@ -114,7 +115,8 @@ exports.deleteView = async viewName => {
exports.migrateToInMemoryView = async (db, viewName) => {
// delete the view initially
const designDoc = await db.get("_design/database")
- const view = designDoc.views[viewName]
+ // run the view back through the view builder to update it
+ const view = viewBuilder(designDoc.views[viewName].meta)
delete designDoc.views[viewName]
await db.put(designDoc)
await exports.saveView(db, null, viewName, view)
@@ -123,7 +125,7 @@ exports.migrateToInMemoryView = async (db, viewName) => {
exports.migrateToDesignView = async (db, viewName) => {
let view = await db.get(generateMemoryViewID(viewName))
const designDoc = await db.get("_design/database")
- designDoc.views[viewName] = view.view
+ designDoc.views[viewName] = viewBuilder(view.view.meta)
await db.put(designDoc)
await db.remove(view._id, view._rev)
}
diff --git a/packages/server/src/api/controllers/view/viewBuilder.js b/packages/server/src/api/controllers/view/viewBuilder.js
index 6e2e5c8527..6596e0d9e7 100644
--- a/packages/server/src/api/controllers/view/viewBuilder.js
+++ b/packages/server/src/api/controllers/view/viewBuilder.js
@@ -10,6 +10,12 @@ const TOKEN_MAP = {
OR: "||",
}
+const CONDITIONS = {
+ EMPTY: "EMPTY",
+ NOT_EMPTY: "NOT_EMPTY",
+ CONTAINS: "CONTAINS",
+}
+
const isEmptyExpression = key => {
return `(
doc["${key}"] === undefined ||
@@ -77,13 +83,13 @@ function parseFilterExpression(filters) {
expression.push(TOKEN_MAP[filter.conjunction])
}
- if (filter.condition === "CONTAINS") {
+ if (filter.condition === CONDITIONS.CONTAINS) {
expression.push(
`doc["${filter.key}"].${TOKEN_MAP[filter.condition]}("${filter.value}")`
)
- } else if (filter.condition === "EMPTY") {
+ } else if (filter.condition === CONDITIONS.EMPTY) {
expression.push(isEmptyExpression(filter.key))
- } else if (filter.condition === "NOT_EMPTY") {
+ } else if (filter.condition === CONDITIONS.NOT_EMPTY) {
expression.push(`!${isEmptyExpression(filter.key)}`)
} else {
const value =
@@ -125,22 +131,37 @@ function viewTemplate({ field, tableId, groupBy, filters = [], calculation }) {
if (filters && filters.length > 0 && filters[0].conjunction) {
delete filters[0].conjunction
}
- const parsedFilters = parseFilterExpression(filters)
- const filterExpression = parsedFilters ? `&& (${parsedFilters})` : ""
- const emitExpression = parseEmitExpression(field, groupBy)
-
- const reduction = field && calculation ? { reduce: `_${calculation}` } : {}
-
- let schema = null
+ let schema = null,
+ statFilter = null
if (calculation) {
schema = {
...(groupBy ? GROUP_PROPERTY : FIELD_PROPERTY),
...SCHEMA_MAP[calculation],
}
+ if (
+ !filters.find(
+ filter =>
+ filter.key === field && filter.condition === CONDITIONS.NOT_EMPTY
+ )
+ ) {
+ statFilter = parseFilterExpression([
+ { key: field, condition: CONDITIONS.NOT_EMPTY },
+ ])
+ }
}
+ const parsedFilters = parseFilterExpression(filters)
+ const filterExpression = parsedFilters ? `&& (${parsedFilters})` : ""
+
+ const emitExpression = parseEmitExpression(field, groupBy)
+ const tableExpression = `doc.tableId === "${tableId}"`
+ const coreExpression = statFilter
+ ? `(${tableExpression} && ${statFilter})`
+ : tableExpression
+ const reduction = field && calculation ? { reduce: `_${calculation}` } : {}
+
return {
meta: {
field,
@@ -151,7 +172,7 @@ function viewTemplate({ field, tableId, groupBy, filters = [], calculation }) {
calculation,
},
map: `function (doc) {
- if (doc.tableId === "${tableId}" ${filterExpression}) {
+ if (${coreExpression} ${filterExpression}) {
${emitExpression}
}
}`,
diff --git a/packages/server/src/integrations/mongodb.ts b/packages/server/src/integrations/mongodb.ts
index c955b43a65..ae6754907b 100644
--- a/packages/server/src/integrations/mongodb.ts
+++ b/packages/server/src/integrations/mongodb.ts
@@ -4,10 +4,18 @@ import {
QueryTypes,
} from "../definitions/datasource"
import { IntegrationBase } from "./base/IntegrationBase"
+import {
+ MongoClient,
+ ObjectID,
+ FilterQuery,
+ UpdateQuery,
+ FindOneAndUpdateOption,
+ UpdateOneOptions,
+ UpdateManyOptions,
+ CommonOptions,
+} from "mongodb"
module MongoDBModule {
- const { MongoClient } = require("mongodb")
-
interface MongoDBConfig {
connectionString: string
db: string
@@ -76,20 +84,76 @@ module MongoDBModule {
return this.client.connect()
}
+ createObjectIds(json: any): object {
+ const self = this
+ function interpolateObjectIds(json: any) {
+ for (let field of Object.keys(json)) {
+ if (json[field] instanceof Object) {
+ json[field] = self.createObjectIds(json[field])
+ }
+ if (field === "_id" && typeof json[field] === "string") {
+ const id = json["_id"].match(
+ /(?<=objectid\(['"]).*(?=['"]\))/gi
+ )?.[0]
+ if (id) {
+ json["_id"] = ObjectID.createFromHexString(id)
+ }
+ }
+ }
+ return json
+ }
+
+ if (Array.isArray(json)) {
+ for (let i = 0; i < json.length; i++) {
+ json[i] = interpolateObjectIds(json[i])
+ }
+ return json
+ }
+ return interpolateObjectIds(json)
+ }
+
+ parseQueryParams(params: string, mode: string) {
+ let queryParams = params.split(/(?<=(},)).*{/g)
+ let group1 = queryParams[0]
+ let group2 = queryParams[2]
+ let group3 = queryParams[4]
+ if (group1) {
+ group1 = JSON.parse(group1.replace(/,+$/, ""))
+ }
+ if (group2) {
+ group2 = JSON.parse("{" + group2.replace(/,+$/, ""))
+ }
+ if (group3) {
+ group3 = JSON.parse("{" + group3.replace(/,+$/, ""))
+ }
+ if (mode === "update") {
+ return {
+ filter: group1,
+ update: group2,
+ options: group3 ?? {},
+ }
+ }
+ return {
+ filter: group1,
+ options: group2 ?? {},
+ }
+ }
+
async create(query: { json: object; extra: { [key: string]: string } }) {
try {
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(query.extra.collection)
+ let json = this.createObjectIds(query.json)
// For mongodb we add an extra actionType to specify
// which method we want to call on the collection
switch (query.extra.actionTypes) {
case "insertOne": {
- return await collection.insertOne(query.json)
+ return await collection.insertOne(json)
}
case "insertMany": {
- return await collection.insertOne(query.json).toArray()
+ return await collection.insertMany(json)
}
default: {
throw new Error(
@@ -110,22 +174,32 @@ module MongoDBModule {
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(query.extra.collection)
+ let json = this.createObjectIds(query.json)
switch (query.extra.actionTypes) {
case "find": {
- return await collection.find(query.json).toArray()
+ return await collection.find(json).toArray()
}
case "findOne": {
- return await collection.findOne(query.json)
+ return await collection.findOne(json)
}
case "findOneAndUpdate": {
- return await collection.findOneAndUpdate(query.json)
+ let findAndUpdateJson = json as {
+ filter: FilterQuery
+ update: UpdateQuery
+ options: FindOneAndUpdateOption
+ }
+ return await collection.findOneAndUpdate(
+ findAndUpdateJson.filter,
+ findAndUpdateJson.update,
+ findAndUpdateJson.options
+ )
}
case "count": {
- return await collection.countDocuments(query.json)
+ return await collection.countDocuments(json)
}
case "distinct": {
- return await collection.distinct(query.json)
+ return await collection.distinct(json)
}
default: {
throw new Error(
@@ -146,13 +220,30 @@ module MongoDBModule {
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(query.extra.collection)
+ let queryJson = query.json
+ if (typeof queryJson === "string") {
+ queryJson = this.parseQueryParams(queryJson, "update")
+ }
+ let json = this.createObjectIds(queryJson) as {
+ filter: FilterQuery
+ update: UpdateQuery
+ options: object
+ }
switch (query.extra.actionTypes) {
case "updateOne": {
- return await collection.updateOne(query.json)
+ return await collection.updateOne(
+ json.filter,
+ json.update,
+ json.options as UpdateOneOptions
+ )
}
case "updateMany": {
- return await collection.updateMany(query.json).toArray()
+ return await collection.updateMany(
+ json.filter,
+ json.update,
+ json.options as UpdateManyOptions
+ )
}
default: {
throw new Error(
@@ -173,13 +264,21 @@ module MongoDBModule {
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(query.extra.collection)
+ let queryJson = query.json
+ if (typeof queryJson === "string") {
+ queryJson = this.parseQueryParams(queryJson, "delete")
+ }
+ let json = this.createObjectIds(queryJson) as {
+ filter: FilterQuery
+ options: CommonOptions
+ }
switch (query.extra.actionTypes) {
case "deleteOne": {
- return await collection.deleteOne(query.json)
+ return await collection.deleteOne(json.filter, json.options)
}
case "deleteMany": {
- return await collection.deleteMany(query.json).toArray()
+ return await collection.deleteMany(json.filter, json.options)
}
default: {
throw new Error(
diff --git a/packages/server/src/integrations/tests/mongo.spec.js b/packages/server/src/integrations/tests/mongo.spec.js
index 430ccc1c3a..b0a49521ec 100644
--- a/packages/server/src/integrations/tests/mongo.spec.js
+++ b/packages/server/src/integrations/tests/mongo.spec.js
@@ -4,19 +4,19 @@ jest.mock("mongodb")
class TestConfiguration {
constructor(config = {}) {
- this.integration = new MongoDBIntegration.integration(config)
+ this.integration = new MongoDBIntegration.integration(config)
}
}
function disableConsole() {
- jest.spyOn(console, 'error');
- console.error.mockImplementation(() => {});
+ jest.spyOn(console, "error")
+ console.error.mockImplementation(() => {})
- return console.error.mockRestore;
+ return console.error.mockRestore
}
describe("MongoDB Integration", () => {
- let config
+ let config
let indexName = "Users"
beforeEach(() => {
@@ -25,12 +25,12 @@ describe("MongoDB Integration", () => {
it("calls the create method with the correct params", async () => {
const body = {
- name: "Hello"
+ name: "Hello",
}
await config.integration.create({
index: indexName,
json: body,
- extra: { collection: 'testCollection', actionTypes: 'insertOne'}
+ extra: { collection: "testCollection", actionTypes: "insertOne" },
})
expect(config.integration.client.insertOne).toHaveBeenCalledWith(body)
})
@@ -38,9 +38,9 @@ describe("MongoDB Integration", () => {
it("calls the read method with the correct params", async () => {
const query = {
json: {
- address: "test"
+ address: "test",
},
- extra: { collection: 'testCollection', actionTypes: 'find'}
+ extra: { collection: "testCollection", actionTypes: "find" },
}
const response = await config.integration.read(query)
expect(config.integration.client.find).toHaveBeenCalledWith(query.json)
@@ -50,30 +50,47 @@ describe("MongoDB Integration", () => {
it("calls the delete method with the correct params", async () => {
const query = {
json: {
- id: "test"
+ filter: {
+ id: "test",
+ },
+ options: {
+ opt: "option"
+ }
},
- extra: { collection: 'testCollection', actionTypes: 'deleteOne'}
+ extra: { collection: "testCollection", actionTypes: "deleteOne" },
}
await config.integration.delete(query)
- expect(config.integration.client.deleteOne).toHaveBeenCalledWith(query.json)
+ expect(config.integration.client.deleteOne).toHaveBeenCalledWith(query.json.filter, query.json.options)
})
it("calls the update method with the correct params", async () => {
const query = {
json: {
- id: "test"
+ filter: {
+ id: "test",
+ },
+ update: {
+ name: "TestName",
+ },
+ options: {
+ upsert: false,
+ },
},
- extra: { collection: 'testCollection', actionTypes: 'updateOne'}
+ extra: { collection: "testCollection", actionTypes: "updateOne" },
}
await config.integration.update(query)
- expect(config.integration.client.updateOne).toHaveBeenCalledWith(query.json)
+ expect(config.integration.client.updateOne).toHaveBeenCalledWith(
+ query.json.filter,
+ query.json.update,
+ query.json.options
+ )
})
it("throws an error when an invalid query.extra.actionType is passed for each method", async () => {
const restore = disableConsole()
const query = {
- extra: { collection: 'testCollection', actionTypes: 'deleteOne'}
+ extra: { collection: "testCollection", actionTypes: "deleteOne" },
}
let error = null
@@ -85,4 +102,4 @@ describe("MongoDB Integration", () => {
expect(error).toBeDefined()
restore()
})
-})
\ No newline at end of file
+})
diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock
index fd9eea9339..ef93d2c163 100644
--- a/packages/server/yarn.lock
+++ b/packages/server/yarn.lock
@@ -1014,10 +1014,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@budibase/backend-core@1.0.154":
- version "1.0.154"
- resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.154.tgz#c310834892e7621778b07579464955487c5c9830"
- integrity sha512-mcZxt8XhGgOB4XRHKkWTvBEI4HGp2bo8qyzOJRCvDqlg56S9zqGJDl75Z0N/Wc8N3I53QRcxISerj48odX172A==
+"@budibase/backend-core@1.0.160":
+ version "1.0.160"
+ resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.160.tgz#000e3b5a3ed91e73a542b4caa202a6f147d91294"
+ integrity sha512-XfAFU6sRPrCSEKlm58WeuPw8lUoJK+KwO0tcbT+bB2Nb7XCHplskryEgk/PM9ujRU6SMPDx11zKeqRebHlycbA==
dependencies:
"@techpass/passport-openidconnect" "^0.3.0"
aws-sdk "^2.901.0"
@@ -1091,12 +1091,12 @@
svelte-flatpickr "^3.2.3"
svelte-portal "^1.0.0"
-"@budibase/pro@1.0.154":
- version "1.0.154"
- resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.154.tgz#f4e31e30376b206159b711224038141d73a1118e"
- integrity sha512-+O6bemrcgyWG4a+D5dIOoZ+LGjW4aN7tRdFeZqoaIPCc1pA6zNtLUkM1nb+Laafuwq2Aht37vEuaRy7jfzVprA==
+"@budibase/pro@1.0.160":
+ version "1.0.160"
+ resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.160.tgz#921c4e3f65b866d84292644dfd8793c4d0b667c7"
+ integrity sha512-p+Jhnk1n98CWCJXydSQSO7a+HDpqGAHekGQbOR7aayuwuoYzyOXxTcHNLdBp+3lkXhLSZq9oIwfEGpgdrrhXPA==
dependencies:
- "@budibase/backend-core" "1.0.154"
+ "@budibase/backend-core" "1.0.160"
node-fetch "^2.6.1"
"@budibase/standard-components@^0.9.139":
diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json
index 7caa7a216e..b054ba9d65 100644
--- a/packages/string-templates/package.json
+++ b/packages/string-templates/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/string-templates",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs",
"module": "dist/bundle.mjs",
diff --git a/packages/worker/package.json b/packages/worker/package.json
index 3b1a63de84..987c54c5c0 100644
--- a/packages/worker/package.json
+++ b/packages/worker/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/worker",
"email": "hi@budibase.com",
- "version": "1.0.159-alpha.3",
+ "version": "1.0.163",
"description": "Budibase background service",
"main": "src/index.ts",
"repository": {
@@ -31,9 +31,9 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
- "@budibase/backend-core": "^1.0.159-alpha.3",
- "@budibase/pro": "1.0.159-alpha.3",
- "@budibase/string-templates": "^1.0.159-alpha.3",
+ "@budibase/backend-core": "^1.0.163",
+ "@budibase/pro": "1.0.163",
+ "@budibase/string-templates": "^1.0.163",
"@koa/router": "^8.0.0",
"@sentry/node": "6.17.7",
"@techpass/passport-openidconnect": "^0.3.0",
diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock
index a5e4c2d9e7..1b31c8ef50 100644
--- a/packages/worker/yarn.lock
+++ b/packages/worker/yarn.lock
@@ -293,10 +293,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@budibase/backend-core@1.0.154":
- version "1.0.154"
- resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.154.tgz#c310834892e7621778b07579464955487c5c9830"
- integrity sha512-mcZxt8XhGgOB4XRHKkWTvBEI4HGp2bo8qyzOJRCvDqlg56S9zqGJDl75Z0N/Wc8N3I53QRcxISerj48odX172A==
+"@budibase/backend-core@1.0.160":
+ version "1.0.160"
+ resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.160.tgz#000e3b5a3ed91e73a542b4caa202a6f147d91294"
+ integrity sha512-XfAFU6sRPrCSEKlm58WeuPw8lUoJK+KwO0tcbT+bB2Nb7XCHplskryEgk/PM9ujRU6SMPDx11zKeqRebHlycbA==
dependencies:
"@techpass/passport-openidconnect" "^0.3.0"
aws-sdk "^2.901.0"
@@ -321,12 +321,12 @@
uuid "^8.3.2"
zlib "^1.0.5"
-"@budibase/pro@1.0.154":
- version "1.0.154"
- resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.154.tgz#f4e31e30376b206159b711224038141d73a1118e"
- integrity sha512-+O6bemrcgyWG4a+D5dIOoZ+LGjW4aN7tRdFeZqoaIPCc1pA6zNtLUkM1nb+Laafuwq2Aht37vEuaRy7jfzVprA==
+"@budibase/pro@1.0.160":
+ version "1.0.160"
+ resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.160.tgz#921c4e3f65b866d84292644dfd8793c4d0b667c7"
+ integrity sha512-p+Jhnk1n98CWCJXydSQSO7a+HDpqGAHekGQbOR7aayuwuoYzyOXxTcHNLdBp+3lkXhLSZq9oIwfEGpgdrrhXPA==
dependencies:
- "@budibase/backend-core" "1.0.154"
+ "@budibase/backend-core" "1.0.160"
node-fetch "^2.6.1"
"@cspotcode/source-map-consumer@0.8.0":
diff --git a/yarn.lock b/yarn.lock
index 129b650c73..276dd62d08 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -972,6 +972,13 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
+"@types/bson@*":
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.2.0.tgz#a2f71e933ff54b2c3bf267b67fa221e295a33337"
+ integrity sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==
+ dependencies:
+ bson "*"
+
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
@@ -982,6 +989,19 @@
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
+"@types/mongodb@3.6.3":
+ version "3.6.3"
+ resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.6.3.tgz#5655af409d9e32d5d5ae9a653abf3e5f9c83eb7a"
+ integrity sha512-6YNqGP1hk5bjUFaim+QoFFuI61WjHiHE1BNeB41TA00Xd2K7zG4lcWyLLq/XtIp36uMavvS5hoAUJ+1u/GcX2Q==
+ dependencies:
+ "@types/bson" "*"
+ "@types/node" "*"
+
+"@types/node@*":
+ version "17.0.33"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.33.tgz#3c1879b276dc63e73030bb91165e62a4509cd506"
+ integrity sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==
+
"@types/node@>= 8":
version "17.0.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.18.tgz#3b4fed5cfb58010e3a2be4b6e74615e4847f1074"
@@ -1300,6 +1320,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
base@^0.11.1:
version "0.11.2"
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
@@ -1361,6 +1386,13 @@ braces@^3.0.2:
dependencies:
fill-range "^7.0.1"
+bson@*:
+ version "4.6.3"
+ resolved "https://registry.yarnpkg.com/bson/-/bson-4.6.3.tgz#d1a9a0b84b9e84b62390811fc5580f6a8b1d858c"
+ integrity sha512-rAqP5hcUVJhXP2MCSNVsf0oM2OGU1So6A9pVRDYayvJ5+hygXHQApf87wd5NlhPM1J9RJnbqxIG/f8QTzRoQ4A==
+ dependencies:
+ buffer "^5.6.0"
+
btoa-lite@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337"
@@ -1371,6 +1403,14 @@ buffer-from@^1.0.0:
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+buffer@^5.6.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
+
builtins@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
@@ -2969,6 +3009,11 @@ iconv-lite@^0.6.2:
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
+ieee754@^1.1.13:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
iferr@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
@@ -4663,12 +4708,7 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
-picomatch@^2.2.2:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
- integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-
-picomatch@^2.3.1:
+picomatch@^2.2.2, picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==