1
0
Fork 0
mirror of synced 2024-10-03 02:27:06 +13:00

Merge branch 'master' into limit-js-execution-per-request

This commit is contained in:
Adria Navarro 2023-12-19 12:44:37 +01:00 committed by GitHub
commit dbc45da7f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 191 additions and 15 deletions

View file

@ -32,6 +32,7 @@
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"bull": "4.10.1", "bull": "4.10.1",
"correlation-id": "4.0.0", "correlation-id": "4.0.0",
"dd-trace": "4.20.0",
"dotenv": "16.0.1", "dotenv": "16.0.1",
"ioredis": "5.3.2", "ioredis": "5.3.2",
"joi": "17.6.0", "joi": "17.6.0",

View file

@ -17,6 +17,7 @@ import { directCouchUrlCall } from "./utils"
import { getPouchDB } from "./pouchDB" import { getPouchDB } from "./pouchDB"
import { WriteStream, ReadStream } from "fs" import { WriteStream, ReadStream } from "fs"
import { newid } from "../../docIds/newid" import { newid } from "../../docIds/newid"
import { DDInstrumentedDatabase } from "../instrumentation"
function buildNano(couchInfo: { url: string; cookie: string }) { function buildNano(couchInfo: { url: string; cookie: string }) {
return Nano({ return Nano({
@ -35,10 +36,8 @@ export function DatabaseWithConnection(
connection: string, connection: string,
opts?: DatabaseOpts opts?: DatabaseOpts
) { ) {
if (!connection) { const db = new DatabaseImpl(dbName, opts, connection)
throw new Error("Must provide connection details") return new DDInstrumentedDatabase(db, "couchdb")
}
return new DatabaseImpl(dbName, opts, connection)
} }
export class DatabaseImpl implements Database { export class DatabaseImpl implements Database {

View file

@ -1,8 +1,9 @@
import { directCouchQuery, DatabaseImpl } from "./couch" import { directCouchQuery, DatabaseImpl } from "./couch"
import { CouchFindOptions, Database, DatabaseOpts } from "@budibase/types" import { CouchFindOptions, Database, DatabaseOpts } from "@budibase/types"
import { DDInstrumentedDatabase } from "./instrumentation"
export function getDB(dbName: string, opts?: DatabaseOpts): Database { export function getDB(dbName: string, opts?: DatabaseOpts): Database {
return new DatabaseImpl(dbName, opts) return new DDInstrumentedDatabase(new DatabaseImpl(dbName, opts), "couchdb")
} }
// we have to use a callback for this so that we can close // we have to use a callback for this so that we can close

View file

@ -0,0 +1,159 @@
import {
DocumentScope,
DocumentDestroyResponse,
DocumentInsertResponse,
DocumentBulkResponse,
OkResponse,
} from "@budibase/nano"
import {
AllDocsResponse,
AnyDocument,
Database,
DatabaseDumpOpts,
DatabasePutOpts,
DatabaseQueryOpts,
Document,
} from "@budibase/types"
import tracer from "dd-trace"
import { Writable } from "stream"
export class DDInstrumentedDatabase implements Database {
constructor(
private readonly db: Database,
private readonly resource: string
) {}
get name(): string {
return this.db.name
}
exists(): Promise<boolean> {
return tracer.trace("exists", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.exists()
})
}
checkSetup(): Promise<DocumentScope<any>> {
return tracer.trace("checkSetup", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.checkSetup()
})
}
get<T extends Document>(id?: string | undefined): Promise<T> {
return tracer.trace("get", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name, doc_id: id })
return this.db.get(id)
})
}
getMultiple<T extends Document>(
ids: string[],
opts?: { allowMissing?: boolean | undefined } | undefined
): Promise<T[]> {
return tracer.trace("getMultiple", { resource: this.resource }, span => {
span?.addTags({
db_name: this.name,
num_docs: ids.length,
allow_missing: opts?.allowMissing,
})
return this.db.getMultiple(ids, opts)
})
}
remove(
id: string | Document,
rev?: string | undefined
): Promise<DocumentDestroyResponse> {
return tracer.trace("remove", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name, doc_id: id })
return this.db.remove(id, rev)
})
}
put(
document: AnyDocument,
opts?: DatabasePutOpts | undefined
): Promise<DocumentInsertResponse> {
return tracer.trace("put", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name, doc_id: document._id })
return this.db.put(document, opts)
})
}
bulkDocs(documents: AnyDocument[]): Promise<DocumentBulkResponse[]> {
return tracer.trace("bulkDocs", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name, num_docs: documents.length })
return this.db.bulkDocs(documents)
})
}
allDocs<T extends Document>(
params: DatabaseQueryOpts
): Promise<AllDocsResponse<T>> {
return tracer.trace("allDocs", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.allDocs(params)
})
}
query<T extends Document>(
viewName: string,
params: DatabaseQueryOpts
): Promise<AllDocsResponse<T>> {
return tracer.trace("query", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name, view_name: viewName })
return this.db.query(viewName, params)
})
}
destroy(): Promise<void | OkResponse> {
return tracer.trace("destroy", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.destroy()
})
}
compact(): Promise<void | OkResponse> {
return tracer.trace("compact", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.compact()
})
}
dump(stream: Writable, opts?: DatabaseDumpOpts | undefined): Promise<any> {
return tracer.trace("dump", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.dump(stream, opts)
})
}
load(...args: any[]): Promise<any> {
return tracer.trace("load", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.load(...args)
})
}
createIndex(...args: any[]): Promise<any> {
return tracer.trace("createIndex", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.createIndex(...args)
})
}
deleteIndex(...args: any[]): Promise<any> {
return tracer.trace("deleteIndex", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.deleteIndex(...args)
})
}
getIndexes(...args: any[]): Promise<any> {
return tracer.trace("getIndexes", { resource: this.resource }, span => {
span?.addTags({ db_name: this.name })
return this.db.getIndexes(...args)
})
}
}

View file

@ -69,7 +69,15 @@
on:change={e => onChange(e, field)} on:change={e => onChange(e, field)}
useLabel={false} useLabel={false}
/> />
{:else if schema.type === "string" || schema.type === "number"} {:else if schema.type === "bb_reference"}
<LinkedRowSelector
linkedRows={value[field]}
{schema}
linkedTableId={"ta_users"}
on:change={e => onChange(e, field)}
useLabel={false}
/>
{:else if ["string", "number", "bigint", "barcodeqr"].includes(schema.type)}
<svelte:component <svelte:component
this={isTestModal ? ModalBindableInput : DrawerBindableInput} this={isTestModal ? ModalBindableInput : DrawerBindableInput}
panel={AutomationBindingPanel} panel={AutomationBindingPanel}

View file

@ -8,6 +8,8 @@
export let schema export let schema
export let linkedRows = [] export let linkedRows = []
export let useLabel = true export let useLabel = true
export let linkedTableId
export let label
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let rows = [] let rows = []
@ -16,8 +18,8 @@
$: linkedIds = (Array.isArray(linkedRows) ? linkedRows : [])?.map( $: linkedIds = (Array.isArray(linkedRows) ? linkedRows : [])?.map(
row => row?._id || row row => row?._id || row
) )
$: label = capitalise(schema.name) $: label = label || capitalise(schema.name)
$: linkedTableId = schema.tableId $: linkedTableId = linkedTableId || schema.tableId
$: linkedTable = $tables.list.find(table => table._id === linkedTableId) $: linkedTable = $tables.list.find(table => table._id === linkedTableId)
$: fetchRows(linkedTableId) $: fetchRows(linkedTableId)
@ -57,7 +59,7 @@
{:else} {:else}
<Multiselect <Multiselect
value={linkedIds} value={linkedIds}
{label} label={useLabel ? label : null}
options={rows} options={rows}
getOptionLabel={getPrettyName} getOptionLabel={getPrettyName}
getOptionValue={row => row._id} getOptionValue={row => row._id}

View file

@ -113,7 +113,7 @@
if (type === "json" && !isJSBinding(value)) { if (type === "json" && !isJSBinding(value)) {
return "json-slot-icon" return "json-slot-icon"
} }
if (type !== "string" && type !== "number") { if (!["string", "number", "bigint", "barcodeqr"].includes(type)) {
return "slot-icon" return "slot-icon"
} }
return "" return ""

View file

@ -164,7 +164,8 @@
// Required constraint // Required constraint
if ( if (
field === dataSourceSchema?.table?.primaryDisplay || field === dataSourceSchema?.table?.primaryDisplay ||
constraints.presence?.allowEmpty === false constraints.presence?.allowEmpty === false ||
constraints.presence === true
) { ) {
rules.push({ rules.push({
constraint: "required", constraint: "required",

View file

@ -23,7 +23,8 @@ export const createValidatorFromConstraints = (
// Required constraint // Required constraint
if ( if (
field === table?.primaryDisplay || field === table?.primaryDisplay ||
schemaConstraints.presence?.allowEmpty === false schemaConstraints.presence?.allowEmpty === false ||
schemaConstraints.presence === true
) { ) {
rules.push({ rules.push({
type: schemaConstraints.type == "array" ? "array" : "string", type: schemaConstraints.type == "array" ? "array" : "string",

View file

@ -84,9 +84,11 @@ export async function run({ inputs, appId, emitter }: AutomationStepInput) {
// clear any undefined, null or empty string properties so that they aren't updated // clear any undefined, null or empty string properties so that they aren't updated
for (let propKey of Object.keys(inputs.row)) { for (let propKey of Object.keys(inputs.row)) {
const clearRelationships =
inputs.meta?.fields?.[propKey]?.clearRelationships
if ( if (
(inputs.row[propKey] == null || inputs.row[propKey] === "") && (inputs.row[propKey] == null || inputs.row[propKey]?.length === 0) &&
!inputs.meta?.fields?.[propKey]?.clearRelationships !clearRelationships
) { ) {
delete inputs.row[propKey] delete inputs.row[propKey]
} }

View file

@ -1,5 +1,6 @@
import { import {
ConnectionInfo, ConnectionInfo,
Database,
DatasourceFeature, DatasourceFeature,
DatasourceFieldType, DatasourceFieldType,
Document, Document,
@ -66,7 +67,7 @@ const SCHEMA: Integration = {
} }
class CouchDBIntegration implements IntegrationBase { class CouchDBIntegration implements IntegrationBase {
private readonly client: dbCore.DatabaseImpl private readonly client: Database
constructor(config: CouchDBConfig) { constructor(config: CouchDBConfig) {
this.client = dbCore.DatabaseWithConnection(config.database, config.url) this.client = dbCore.DatabaseWithConnection(config.database, config.url)

View file

@ -59,6 +59,7 @@ function runBuild(entry, outfile) {
"pouchdb", "pouchdb",
"bcrypt", "bcrypt",
"bcryptjs", "bcryptjs",
"graphql/*",
], ],
} }