Merge branch 'master' into limit-js-execution-per-request
This commit is contained in:
commit
dbc45da7f5
|
@ -32,6 +32,7 @@
|
|||
"bcryptjs": "2.4.3",
|
||||
"bull": "4.10.1",
|
||||
"correlation-id": "4.0.0",
|
||||
"dd-trace": "4.20.0",
|
||||
"dotenv": "16.0.1",
|
||||
"ioredis": "5.3.2",
|
||||
"joi": "17.6.0",
|
||||
|
|
|
@ -17,6 +17,7 @@ import { directCouchUrlCall } from "./utils"
|
|||
import { getPouchDB } from "./pouchDB"
|
||||
import { WriteStream, ReadStream } from "fs"
|
||||
import { newid } from "../../docIds/newid"
|
||||
import { DDInstrumentedDatabase } from "../instrumentation"
|
||||
|
||||
function buildNano(couchInfo: { url: string; cookie: string }) {
|
||||
return Nano({
|
||||
|
@ -35,10 +36,8 @@ export function DatabaseWithConnection(
|
|||
connection: string,
|
||||
opts?: DatabaseOpts
|
||||
) {
|
||||
if (!connection) {
|
||||
throw new Error("Must provide connection details")
|
||||
}
|
||||
return new DatabaseImpl(dbName, opts, connection)
|
||||
const db = new DatabaseImpl(dbName, opts, connection)
|
||||
return new DDInstrumentedDatabase(db, "couchdb")
|
||||
}
|
||||
|
||||
export class DatabaseImpl implements Database {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { directCouchQuery, DatabaseImpl } from "./couch"
|
||||
import { CouchFindOptions, Database, DatabaseOpts } from "@budibase/types"
|
||||
import { DDInstrumentedDatabase } from "./instrumentation"
|
||||
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -69,7 +69,15 @@
|
|||
on:change={e => onChange(e, field)}
|
||||
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
|
||||
this={isTestModal ? ModalBindableInput : DrawerBindableInput}
|
||||
panel={AutomationBindingPanel}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
export let schema
|
||||
export let linkedRows = []
|
||||
export let useLabel = true
|
||||
export let linkedTableId
|
||||
export let label
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let rows = []
|
||||
|
@ -16,8 +18,8 @@
|
|||
$: linkedIds = (Array.isArray(linkedRows) ? linkedRows : [])?.map(
|
||||
row => row?._id || row
|
||||
)
|
||||
$: label = capitalise(schema.name)
|
||||
$: linkedTableId = schema.tableId
|
||||
$: label = label || capitalise(schema.name)
|
||||
$: linkedTableId = linkedTableId || schema.tableId
|
||||
$: linkedTable = $tables.list.find(table => table._id === linkedTableId)
|
||||
$: fetchRows(linkedTableId)
|
||||
|
||||
|
@ -57,7 +59,7 @@
|
|||
{:else}
|
||||
<Multiselect
|
||||
value={linkedIds}
|
||||
{label}
|
||||
label={useLabel ? label : null}
|
||||
options={rows}
|
||||
getOptionLabel={getPrettyName}
|
||||
getOptionValue={row => row._id}
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
if (type === "json" && !isJSBinding(value)) {
|
||||
return "json-slot-icon"
|
||||
}
|
||||
if (type !== "string" && type !== "number") {
|
||||
if (!["string", "number", "bigint", "barcodeqr"].includes(type)) {
|
||||
return "slot-icon"
|
||||
}
|
||||
return ""
|
||||
|
|
|
@ -164,7 +164,8 @@
|
|||
// Required constraint
|
||||
if (
|
||||
field === dataSourceSchema?.table?.primaryDisplay ||
|
||||
constraints.presence?.allowEmpty === false
|
||||
constraints.presence?.allowEmpty === false ||
|
||||
constraints.presence === true
|
||||
) {
|
||||
rules.push({
|
||||
constraint: "required",
|
||||
|
|
|
@ -23,7 +23,8 @@ export const createValidatorFromConstraints = (
|
|||
// Required constraint
|
||||
if (
|
||||
field === table?.primaryDisplay ||
|
||||
schemaConstraints.presence?.allowEmpty === false
|
||||
schemaConstraints.presence?.allowEmpty === false ||
|
||||
schemaConstraints.presence === true
|
||||
) {
|
||||
rules.push({
|
||||
type: schemaConstraints.type == "array" ? "array" : "string",
|
||||
|
|
|
@ -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
|
||||
for (let propKey of Object.keys(inputs.row)) {
|
||||
const clearRelationships =
|
||||
inputs.meta?.fields?.[propKey]?.clearRelationships
|
||||
if (
|
||||
(inputs.row[propKey] == null || inputs.row[propKey] === "") &&
|
||||
!inputs.meta?.fields?.[propKey]?.clearRelationships
|
||||
(inputs.row[propKey] == null || inputs.row[propKey]?.length === 0) &&
|
||||
!clearRelationships
|
||||
) {
|
||||
delete inputs.row[propKey]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
ConnectionInfo,
|
||||
Database,
|
||||
DatasourceFeature,
|
||||
DatasourceFieldType,
|
||||
Document,
|
||||
|
@ -66,7 +67,7 @@ const SCHEMA: Integration = {
|
|||
}
|
||||
|
||||
class CouchDBIntegration implements IntegrationBase {
|
||||
private readonly client: dbCore.DatabaseImpl
|
||||
private readonly client: Database
|
||||
|
||||
constructor(config: CouchDBConfig) {
|
||||
this.client = dbCore.DatabaseWithConnection(config.database, config.url)
|
||||
|
|
|
@ -59,6 +59,7 @@ function runBuild(entry, outfile) {
|
|||
"pouchdb",
|
||||
"bcrypt",
|
||||
"bcryptjs",
|
||||
"graphql/*",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue