From 478e297e9e3c2944fb20b750463db89f2dea1b72 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 24 Nov 2023 18:11:53 +0000 Subject: [PATCH 01/76] Initial work towards aliasing queries for SQL. --- .../server/src/api/controllers/row/alias.ts | 101 ++++++++++++++++++ packages/server/src/integrations/base/sql.ts | 1 + 2 files changed, 102 insertions(+) create mode 100644 packages/server/src/api/controllers/row/alias.ts diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts new file mode 100644 index 0000000000..8111396ea9 --- /dev/null +++ b/packages/server/src/api/controllers/row/alias.ts @@ -0,0 +1,101 @@ +import { QueryJson, SearchFilters, Table, Row } from "@budibase/types" +import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils" +import { cloneDeep } from "lodash" + +class AliasTables { + character: string + aliases: Record + tableAliases: Record + + constructor() { + this.character = "a" + this.aliases = {} + this.tableAliases = {} + } + + getAlias(tableName: string) { + if (this.aliases[tableName]) { + return this.aliases[tableName] + } + this.character = String.fromCharCode(this.character.charCodeAt(0) + 1) + this.aliases[tableName] = this.character + this.tableAliases[this.character] = tableName + return this.character + } + + aliasField(tableNames: string[], field: string) { + if (field.includes(".")) { + const [tableName, column] = field.split(".") + if (tableNames.includes(tableName)) { + return `${this.getAlias(tableName)}.${column}` + } + } + return field + } + + reverse(tableNames: string[], rows: T): T { + const process = (row: Row) => { + const final: Row = {} + for (let [key, value] of Object.entries(row)) { + if (!key.includes(".")) { + final[key] = value + } else { + const [alias, column] = key.split(".") + const tableName = this.tableAliases[alias] || alias + final[`${tableName}.${column}`] = value + } + } + return final + } + if (Array.isArray(rows)) { + return rows.map(row => process(row)) as T + } else { + return process(rows) as T + } + } + + async queryWithAliasing(tableNames: string[], json: QueryJson) { + json = cloneDeep(json) + const aliasField = (field: string) => this.aliasField(tableNames, field) + const aliasTable = (table: Table) => ({ + ...table, + name: this.getAlias(table.name), + }) + // run through the query json to update anywhere a table may be used + if (json.resource?.fields) { + json.resource.fields = json.resource.fields.map(field => + aliasField(field) + ) + } + if (json.filters) { + for (let [filterKey, filter] of Object.entries(json.filters)) { + if (typeof filter !== "object") { + continue + } + const aliasedFilters: typeof filter = {} + for (let key of Object.keys(filter)) { + aliasedFilters[aliasField(key)] = filter + } + json.filters[filterKey as keyof SearchFilters] = aliasedFilters + } + } + if (json.relationships) { + json.relationships = json.relationships.map(relationship => ({ + ...relationship, + tableName: this.getAlias(relationship.tableName), + })) + } + if (json.meta?.table) { + json.meta.table = aliasTable(json.meta.table) + } + if (json.meta?.tables) { + const aliasedTables: Record = {} + for (let [tableName, table] of Object.entries(json.meta.tables)) { + aliasedTables[this.getAlias(tableName)] = aliasTable(table) + } + json.meta.tables = aliasedTables + } + const response = await getDatasourceAndQuery(json) + return this.reverse(tableNames, response) + } +} diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 29c8416b34..630c962a15 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -437,6 +437,7 @@ class InternalBuilder { read(knex: Knex, json: QueryJson, limit: number): KnexQuery { let { endpoint, resource, filters, paginate, relationships } = json + const tableName = endpoint.entityId // select all if not specified if (!resource) { From c16ad8614240cbb70f21179aeb2e6239916fcce2 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 24 Nov 2023 18:12:35 +0000 Subject: [PATCH 02/76] Updating reverse function. --- packages/server/src/api/controllers/row/alias.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index 8111396ea9..d4937186d9 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -33,7 +33,7 @@ class AliasTables { return field } - reverse(tableNames: string[], rows: T): T { + reverse(rows: T): T { const process = (row: Row) => { const final: Row = {} for (let [key, value] of Object.entries(row)) { @@ -96,6 +96,6 @@ class AliasTables { json.meta.tables = aliasedTables } const response = await getDatasourceAndQuery(json) - return this.reverse(tableNames, response) + return this.reverse(response) } } From cb7c1898f2d29ac52f6b943dc04dd716b9ba128e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 27 Nov 2023 19:02:06 +0000 Subject: [PATCH 03/76] Getting basic aliasing working after some testing. --- .../api/controllers/row/ExternalRequest.ts | 19 +++++++------- .../server/src/api/controllers/row/alias.ts | 25 +++++++++++-------- packages/server/src/integrations/base/sql.ts | 11 +++++--- packages/server/src/sdk/app/rows/utils.ts | 4 +-- packages/types/src/sdk/search.ts | 2 ++ 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 7c98fecb9b..29851e457f 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -32,6 +32,7 @@ import { processObjectSync } from "@budibase/string-templates" import { cloneDeep } from "lodash/fp" import { processDates, processFormulas } from "../../../utilities/rowProcessor" import { db as dbCore } from "@budibase/backend-core" +import AliasTables from "./alias" import sdk from "../../../sdk" export interface ManyRelationship { @@ -178,13 +179,13 @@ function generateIdForRow( function getEndpoint(tableId: string | undefined, operation: string) { if (!tableId) { - return {} + throw new Error("Cannot get endpoint information - no table ID specified") } const { datasourceId, tableName } = breakExternalTableId(tableId) return { - datasourceId, - entityId: tableName, - operation, + datasourceId: datasourceId!, + entityId: tableName!, + operation: operation as Operation, } } @@ -704,7 +705,7 @@ export class ExternalRequest { // safety check, if there are no filters on deletion bad things happen if (Object.keys(filters).length !== 0) { const op = isMany ? Operation.DELETE : Operation.UPDATE - const body = isMany ? null : { [colName]: null } + const body = isMany ? undefined : { [colName]: null } promises.push( getDatasourceAndQuery({ endpoint: getEndpoint(tableId, op), @@ -807,7 +808,7 @@ export class ExternalRequest { } let json = { endpoint: { - datasourceId, + datasourceId: datasourceId!, entityId: tableName, operation, }, @@ -829,9 +830,9 @@ export class ExternalRequest { }, } - // can't really use response right now - const response = await getDatasourceAndQuery(json) - // handle many to many relationships now if we know the ID (could be auto increment) + const aliasing = new AliasTables(Object.keys(this.tables)) + const response = await aliasing.queryWithAliasing(json) + // handle many-to-many relationships now if we know the ID (could be auto increment) if (operation !== Operation.READ) { await this.handleManyRelationships( table._id || "", diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index d4937186d9..19be8db654 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -2,12 +2,14 @@ import { QueryJson, SearchFilters, Table, Row } from "@budibase/types" import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils" import { cloneDeep } from "lodash" -class AliasTables { +export default class AliasTables { character: string aliases: Record tableAliases: Record + tableNames: string[] - constructor() { + constructor(tableNames: string[]) { + this.tableNames = tableNames this.character = "a" this.aliases = {} this.tableAliases = {} @@ -17,13 +19,15 @@ class AliasTables { if (this.aliases[tableName]) { return this.aliases[tableName] } - this.character = String.fromCharCode(this.character.charCodeAt(0) + 1) - this.aliases[tableName] = this.character - this.tableAliases[this.character] = tableName - return this.character + const char = this.character + this.aliases[tableName] = char + this.tableAliases[char] = tableName + this.character = String.fromCharCode(char.charCodeAt(0) + 1) + return char } - aliasField(tableNames: string[], field: string) { + aliasField(field: string) { + const tableNames = this.tableNames if (field.includes(".")) { const [tableName, column] = field.split(".") if (tableNames.includes(tableName)) { @@ -54,9 +58,9 @@ class AliasTables { } } - async queryWithAliasing(tableNames: string[], json: QueryJson) { + async queryWithAliasing(json: QueryJson) { json = cloneDeep(json) - const aliasField = (field: string) => this.aliasField(tableNames, field) + const aliasField = (field: string) => this.aliasField(field) const aliasTable = (table: Table) => ({ ...table, name: this.getAlias(table.name), @@ -82,7 +86,7 @@ class AliasTables { if (json.relationships) { json.relationships = json.relationships.map(relationship => ({ ...relationship, - tableName: this.getAlias(relationship.tableName), + alias: this.getAlias(relationship.tableName), })) } if (json.meta?.table) { @@ -95,6 +99,7 @@ class AliasTables { } json.meta.tables = aliasedTables } + json.endpoint.alias = this.getAlias(json.endpoint.entityId) const response = await getDatasourceAndQuery(json) return this.reverse(response) } diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 630c962a15..3147e8c670 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -439,6 +439,9 @@ class InternalBuilder { let { endpoint, resource, filters, paginate, relationships } = json const tableName = endpoint.entityId + const alias = endpoint.alias + const aliased = alias ? alias : tableName + const tableAliased = alias ? `${tableName} as ${alias}` : tableName // select all if not specified if (!resource) { resource = { fields: [] } @@ -463,20 +466,20 @@ class InternalBuilder { foundLimit = paginate.limit } // start building the query - let query: KnexQuery = knex(tableName).limit(foundLimit) + let query: KnexQuery = knex(tableAliased).limit(foundLimit) if (endpoint.schema) { query = query.withSchema(endpoint.schema) } if (foundOffset) { query = query.offset(foundOffset) } - query = this.addFilters(query, filters, { tableName }) + query = this.addFilters(query, filters, { tableName: aliased }) // add sorting to pre-query query = this.addSorting(query, json) // @ts-ignore let preQuery: KnexQuery = knex({ // @ts-ignore - [tableName]: query, + [aliased]: query, }).select(selectStatement) // have to add after as well (this breaks MS-SQL) if (this.client !== SqlClient.MS_SQL) { @@ -485,7 +488,7 @@ class InternalBuilder { // handle joins query = this.addRelationships( preQuery, - tableName, + aliased, relationships, endpoint.schema ) diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index d0227c7c6b..c160aaba3f 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -1,13 +1,13 @@ import cloneDeep from "lodash/cloneDeep" import validateJs from "validate.js" -import { Row, Table, TableSchema } from "@budibase/types" +import { QueryJson, Row, Table, TableSchema } from "@budibase/types" import { FieldTypes } from "../../../constants" import { makeExternalQuery } from "../../../integrations/base/query" import { Format } from "../../../api/controllers/view/exporters" import sdk from "../.." import { isRelationshipColumn } from "../../../db/utils" -export async function getDatasourceAndQuery(json: any) { +export async function getDatasourceAndQuery(json: QueryJson) { const datasourceId = json.endpoint.datasourceId const datasource = await sdk.datasources.get(datasourceId) return makeExternalQuery(datasource, json) diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts index 35fd148c05..1f9aa6c375 100644 --- a/packages/types/src/sdk/search.ts +++ b/packages/types/src/sdk/search.ts @@ -67,6 +67,7 @@ export interface RelationshipsJson { fromPrimary?: string toPrimary?: string tableName: string + alias?: string column: string } @@ -74,6 +75,7 @@ export interface QueryJson { endpoint: { datasourceId: string entityId: string + alias?: string operation: Operation schema?: string } From 65cddae9dac4f511c70634e4885987b672989c13 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 28 Nov 2023 18:43:38 +0000 Subject: [PATCH 04/76] Getting relationship aliasing working. --- .../server/src/api/controllers/row/alias.ts | 16 +++++++- packages/server/src/integrations/base/sql.ts | 39 ++++++++++++++----- packages/types/src/sdk/search.ts | 2 +- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index 19be8db654..0c7a4bb8a0 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -58,6 +58,16 @@ export default class AliasTables { } } + aliasMap(tableNames: (string | undefined)[]) { + const map: Record = {} + for (let tableName of tableNames) { + if (tableName) { + map[tableName] = this.getAlias(tableName) + } + } + return map + } + async queryWithAliasing(json: QueryJson) { json = cloneDeep(json) const aliasField = (field: string) => this.aliasField(field) @@ -86,7 +96,11 @@ export default class AliasTables { if (json.relationships) { json.relationships = json.relationships.map(relationship => ({ ...relationship, - alias: this.getAlias(relationship.tableName), + aliases: this.aliasMap([ + relationship.through, + relationship.tableName, + json.endpoint.entityId, + ]), })) } if (json.meta?.table) { diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 3147e8c670..f3f574b1af 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -330,6 +330,17 @@ class InternalBuilder { return query } + tableNameWithSchema( + tableName: string, + opts?: { alias?: string; schema?: string } + ) { + let withSchema = opts?.schema ? `${opts.schema}.${tableName}` : tableName + if (opts?.alias) { + withSchema += ` as ${opts.alias}` + } + return withSchema + } + addRelationships( query: KnexQuery, fromTable: string, @@ -339,9 +350,12 @@ class InternalBuilder { if (!relationships) { return query } - const tableSets: Record = {} + const tableSets: Record = {} + // add up all aliases + let aliases: Record = {} // aggregate into table sets (all the same to tables) for (let relationship of relationships) { + aliases = { ...aliases, ...relationship.aliases } const keyObj: { toTable: string; throughTable: string | undefined } = { toTable: relationship.tableName, throughTable: undefined, @@ -358,10 +372,17 @@ class InternalBuilder { } for (let [key, relationships] of Object.entries(tableSets)) { const { toTable, throughTable } = JSON.parse(key) - const toTableWithSchema = schema ? `${schema}.${toTable}` : toTable - const throughTableWithSchema = schema - ? `${schema}.${throughTable}` - : throughTable + const toAlias = aliases[toTable], + throughAlias = aliases[throughTable], + fromAlias = aliases[fromTable] + let toTableWithSchema = this.tableNameWithSchema(toTable, { + alias: toAlias, + schema, + }) + let throughTableWithSchema = this.tableNameWithSchema(throughTable, { + alias: throughAlias, + schema, + }) if (!throughTable) { // @ts-ignore query = query.leftJoin(toTableWithSchema, function () { @@ -369,7 +390,7 @@ class InternalBuilder { const from = relationship.from, to = relationship.to // @ts-ignore - this.orOn(`${fromTable}.${from}`, "=", `${toTable}.${to}`) + this.orOn(`${fromTable}.${from}`, "=", `${toAlias}.${to}`) } }) } else { @@ -381,9 +402,9 @@ class InternalBuilder { const from = relationship.from // @ts-ignore this.orOn( - `${fromTable}.${fromPrimary}`, + `${fromAlias}.${fromPrimary}`, "=", - `${throughTable}.${from}` + `${throughAlias}.${from}` ) } }) @@ -392,7 +413,7 @@ class InternalBuilder { const toPrimary = relationship.toPrimary const to = relationship.to // @ts-ignore - this.orOn(`${toTable}.${toPrimary}`, `${throughTable}.${to}`) + this.orOn(`${toAlias}.${toPrimary}`, `${throughAlias}.${to}`) } }) } diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts index 1f9aa6c375..a4045c2558 100644 --- a/packages/types/src/sdk/search.ts +++ b/packages/types/src/sdk/search.ts @@ -67,7 +67,7 @@ export interface RelationshipsJson { fromPrimary?: string toPrimary?: string tableName: string - alias?: string + aliases?: Record column: string } From 649025ca124a4b9b7f0714d9621edcb3c4ae3424 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 28 Nov 2023 18:45:05 +0000 Subject: [PATCH 05/76] Fixing missed from. --- packages/server/src/integrations/base/sql.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index f3f574b1af..c419edc805 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -390,7 +390,7 @@ class InternalBuilder { const from = relationship.from, to = relationship.to // @ts-ignore - this.orOn(`${fromTable}.${from}`, "=", `${toAlias}.${to}`) + this.orOn(`${fromAlias}.${from}`, "=", `${toAlias}.${to}`) } }) } else { From 5c4dc0dc8351310f6ab9c022594386a4543c47f6 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 1 Dec 2023 14:14:44 +0000 Subject: [PATCH 06/76] Fixing issue with aliasing. --- packages/server/src/integrations/base/sql.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index c419edc805..57af95eabb 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -372,9 +372,9 @@ class InternalBuilder { } for (let [key, relationships] of Object.entries(tableSets)) { const { toTable, throughTable } = JSON.parse(key) - const toAlias = aliases[toTable], - throughAlias = aliases[throughTable], - fromAlias = aliases[fromTable] + const toAlias = aliases[toTable] || toTable, + throughAlias = aliases[throughTable] || throughTable, + fromAlias = aliases[fromTable] || fromTable let toTableWithSchema = this.tableNameWithSchema(toTable, { alias: toAlias, schema, From 7eccbb851dac11b36e936ae52a67500f99cc7a52 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 1 Dec 2023 15:27:49 +0000 Subject: [PATCH 07/76] Fixing issues with other SQL functions than just reading. --- .../server/src/api/controllers/row/alias.ts | 2 +- packages/server/src/integrations/base/sql.ts | 46 +++++++++---------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index 0c7a4bb8a0..fc00b505c4 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -88,7 +88,7 @@ export default class AliasTables { } const aliasedFilters: typeof filter = {} for (let key of Object.keys(filter)) { - aliasedFilters[aliasField(key)] = filter + aliasedFilters[aliasField(key)] = filter[key] } json.filters[filterKey as keyof SearchFilters] = aliasedFilters } diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 57af95eabb..14bcb532cc 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -421,12 +421,24 @@ class InternalBuilder { return query.limit(BASE_LIMIT) } - create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { - const { endpoint, body } = json - let query: KnexQuery = knex(endpoint.entityId) + knexWithAlias( + knex: Knex, + endpoint: { entityId: string; alias?: string; schema?: string } + ): { query: KnexQuery; name: string } { + const tableName = endpoint.entityId + const alias = endpoint.alias + const aliased = alias ? alias : tableName + const tableAliased = alias ? `${tableName} as ${alias}` : tableName + let query = knex(tableAliased) if (endpoint.schema) { query = query.withSchema(endpoint.schema) } + return { query, name: aliased } + } + + create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { + const { endpoint, body } = json + let { query } = this.knexWithAlias(knex, endpoint) const parsedBody = parseBody(body) // make sure no null values in body for creation for (let [key, value] of Object.entries(parsedBody)) { @@ -445,10 +457,7 @@ class InternalBuilder { bulkCreate(knex: Knex, json: QueryJson): KnexQuery { const { endpoint, body } = json - let query: KnexQuery = knex(endpoint.entityId) - if (endpoint.schema) { - query = query.withSchema(endpoint.schema) - } + let { query } = this.knexWithAlias(knex, endpoint) if (!Array.isArray(body)) { return query } @@ -459,10 +468,6 @@ class InternalBuilder { read(knex: Knex, json: QueryJson, limit: number): KnexQuery { let { endpoint, resource, filters, paginate, relationships } = json - const tableName = endpoint.entityId - const alias = endpoint.alias - const aliased = alias ? alias : tableName - const tableAliased = alias ? `${tableName} as ${alias}` : tableName // select all if not specified if (!resource) { resource = { fields: [] } @@ -487,10 +492,9 @@ class InternalBuilder { foundLimit = paginate.limit } // start building the query - let query: KnexQuery = knex(tableAliased).limit(foundLimit) - if (endpoint.schema) { - query = query.withSchema(endpoint.schema) - } + + let { query, name: aliased } = this.knexWithAlias(knex, endpoint) + query = query.limit(foundLimit) if (foundOffset) { query = query.offset(foundOffset) } @@ -518,10 +522,7 @@ class InternalBuilder { update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { const { endpoint, body, filters } = json - let query: KnexQuery = knex(endpoint.entityId) - if (endpoint.schema) { - query = query.withSchema(endpoint.schema) - } + let { query } = this.knexWithAlias(knex, endpoint) const parsedBody = parseBody(body) query = this.addFilters(query, filters, { tableName: endpoint.entityId }) // mysql can't use returning @@ -534,11 +535,8 @@ class InternalBuilder { delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { const { endpoint, filters } = json - let query: KnexQuery = knex(endpoint.entityId) - if (endpoint.schema) { - query = query.withSchema(endpoint.schema) - } - query = this.addFilters(query, filters, { tableName: endpoint.entityId }) + let { query, name: aliased } = this.knexWithAlias(knex, endpoint) + query = this.addFilters(query, filters, { tableName: aliased }) // mysql can't use returning if (opts.disableReturning) { return query.delete() From 3ce00c42a2e9751bcfb17d906b8b8a8c85f04752 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 18 Jan 2024 18:13:11 +0000 Subject: [PATCH 08/76] Adding SQL logging capabilities. --- packages/server/src/environment.ts | 1 + packages/server/src/integrations/base/sql.ts | 12 + .../src/integrations/microsoftSqlServer.ts | 1 + packages/server/src/integrations/mysql.ts | 1 + packages/server/src/integrations/oracle.ts | 1 + packages/server/src/integrations/postgres.ts | 4 +- yarn.lock | 660 +----------------- 7 files changed, 55 insertions(+), 625 deletions(-) diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index f692a8b6cf..f46abe5b16 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -67,6 +67,7 @@ const environment = { DISABLE_RATE_LIMITING: process.env.DISABLE_RATE_LIMITING, MULTI_TENANCY: process.env.MULTI_TENANCY, ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS, + ENABLE_SQL_LOGGING: process.env.ENABLE_SQL_LOGGING, SELF_HOSTED: process.env.SELF_HOSTED, HTTP_MB_LIMIT: process.env.HTTP_MB_LIMIT, FORKED_PROCESS_NAME: process.env.FORKED_PROCESS_NAME || "main", diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 14bcb532cc..3375e175e6 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -671,6 +671,18 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { } return results.length ? results : [{ [operation.toLowerCase()]: true }] } + + log(query: string, values?: any[]) { + if (!environment.ENABLE_SQL_LOGGING) { + return + } + const sqlClient = this.getSqlClient() + let string = `[SQL] [${sqlClient.toUpperCase()}] query="${query}"` + if (values) { + string += ` values="${values.join(", ")}"` + } + console.log(string) + } } export default SqlQueryBuilder diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index d0a06d4476..e063933503 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -329,6 +329,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { operation === Operation.CREATE ? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;` : query.sql + this.log(sql, query.bindings) return await request.query(sql) } catch (err: any) { let readableMessage = getReadableErrorMessage( diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts index 8ec73307f4..6eebda8df5 100644 --- a/packages/server/src/integrations/mysql.ts +++ b/packages/server/src/integrations/mysql.ts @@ -261,6 +261,7 @@ class MySQLIntegration extends Sql implements DatasourcePlus { const bindings = opts?.disableCoercion ? baseBindings : bindingTypeCoerce(baseBindings) + this.log(query.sql, bindings) // Node MySQL is callback based, so we must wrap our call in a promise const response = await this.client!.query(query.sql, bindings) return response[0] diff --git a/packages/server/src/integrations/oracle.ts b/packages/server/src/integrations/oracle.ts index e9a2dc7998..1a1e440410 100644 --- a/packages/server/src/integrations/oracle.ts +++ b/packages/server/src/integrations/oracle.ts @@ -368,6 +368,7 @@ class OracleIntegration extends Sql implements DatasourcePlus { const options: ExecuteOptions = { autoCommit: true } const bindings: BindParameters = query.bindings || [] + this.log(query.sql, bindings) return await connection.execute(query.sql, bindings, options) } finally { if (connection) { diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts index 78955c06dc..f8cd2b62fc 100644 --- a/packages/server/src/integrations/postgres.ts +++ b/packages/server/src/integrations/postgres.ts @@ -262,7 +262,9 @@ class PostgresIntegration extends Sql implements DatasourcePlus { } } try { - return await client.query(query.sql, query.bindings || []) + const bindings = query.bindings || [] + this.log(query.sql, bindings) + return await client.query(query.sql, bindings) } catch (err: any) { await this.closeConnection() let readableMessage = getReadableErrorMessage( diff --git a/yarn.lock b/yarn.lock index 91697cd151..fa746b9d72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -625,13 +625,6 @@ dependencies: tslib "^2.5.0" -"@aws/dynamodb-auto-marshaller@^0.7.1": - version "0.7.1" - resolved "https://registry.yarnpkg.com/@aws/dynamodb-auto-marshaller/-/dynamodb-auto-marshaller-0.7.1.tgz#70676c056e4ecb798c08ec2e398a3d93e703858d" - integrity sha512-LeURlf6/avrfFo9+4Yht9J3CUTJ72yoBpm1FOUmlexuHNW4Ka61tG30w3ZDCXXXmCO2rG0k3ywAgNJEo3WPbyw== - dependencies: - tslib "^1.8.1" - "@azure/abort-controller@^1.0.0", "@azure/abort-controller@^1.0.4": version "1.1.0" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249" @@ -1980,7 +1973,7 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.23.8" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650" integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw== @@ -2638,14 +2631,6 @@ teeny-request "^8.0.0" uuid "^8.0.0" -"@grpc/grpc-js@1.9.7": - version "1.9.7" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.7.tgz#7d0e29bc162287bee2523901c9bc9320d8402397" - integrity sha512-yMaA/cIsRhGzW3ymCNpdlPcInXcovztlgu/rirThj2b87u3RzWUszliOqZ/pldy7yhmJPS8uwog+kZSTa4A0PQ== - dependencies: - "@grpc/proto-loader" "^0.7.8" - "@types/node" ">=12.12.47" - "@grpc/grpc-js@~1.8.0": version "1.8.21" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.21.tgz#d282b122c71227859bf6c5866f4c40f4a2696513" @@ -2654,7 +2639,7 @@ "@grpc/proto-loader" "^0.7.0" "@types/node" ">=12.12.47" -"@grpc/proto-loader@0.7.10", "@grpc/proto-loader@^0.7.0", "@grpc/proto-loader@^0.7.8": +"@grpc/proto-loader@^0.7.0": version "0.7.10" resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.10.tgz#6bf26742b1b54d0a473067743da5d3189d06d720" integrity sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ== @@ -2676,20 +2661,6 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@hubspot/api-client@7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@hubspot/api-client/-/api-client-7.1.2.tgz#a405b0a18b8caa27f129fd510b2555e5a5cc2708" - integrity sha512-JVQqh0fdHf97ePk0Hg/7BJsiXNlS9HQRPiM/CLgvVWt5CIviSLQ/kHLZXREmZqTWu7BisjCgHxnSx/d7gRdr2g== - dependencies: - bluebird "^3.7.2" - bottleneck "^2.19.5" - btoa "^1.2.1" - es6-promise "^4.2.4" - form-data "^2.5.0" - lodash "^4.17.21" - node-fetch "^2.6.0" - url-parse "^1.4.3" - "@humanwhocodes/config-array@^0.11.13": version "0.11.13" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" @@ -3341,13 +3312,6 @@ dependencies: lodash "^4.17.21" -"@koa/cors@^3.1.0": - version "3.4.3" - resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.4.3.tgz#d669ee6e8d6e4f0ec4a7a7b0a17e7a3ed3752ebb" - integrity sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw== - dependencies: - vary "^1.1.2" - "@koa/router@8.0.8": version "8.0.8" resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236" @@ -3956,14 +3920,6 @@ is-module "^1.0.0" resolve "^1.19.0" -"@rollup/plugin-replace@^2.4.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a" - integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - magic-string "^0.25.7" - "@rollup/plugin-replace@^5.0.2", "@rollup/plugin-replace@^5.0.3": version "5.0.5" resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz#33d5653dce6d03cb24ef98bef7f6d25b57faefdf" @@ -4006,23 +3962,6 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@roxi/routify@2.18.0": - version "2.18.0" - resolved "https://registry.yarnpkg.com/@roxi/routify/-/routify-2.18.0.tgz#8f88bedd936312d0dbe44cbc11ab179b1f938ec2" - integrity sha512-MVB50HN+VQWLzfjLplcBjsSBvwOiExKOmht2DuWR3WQ60JxQi9pSejkB06tFVkFKNXz2X5iYtKDqKBTdae/gRg== - dependencies: - "@roxi/ssr" "^0.2.1" - "@types/node" ">=4.2.0 < 13" - chalk "^4.0.0" - cheap-watch "^1.0.2" - commander "^7.1.0" - configent "^2.1.4" - esm "^3.2.25" - fs-extra "^9.0.1" - log-symbols "^3.0.0" - picomatch "^2.2.2" - rollup-pluginutils "^2.8.2" - "@roxi/routify@2.18.12": version "2.18.12" resolved "https://registry.yarnpkg.com/@roxi/routify/-/routify-2.18.12.tgz#901ca95b96f274ddddaefbf18424557ee1ae3fae" @@ -4104,11 +4043,6 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@sindresorhus/is@^4.0.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" - integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== - "@sinonjs/commons@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" @@ -4932,13 +4866,6 @@ dependencies: defer-to-connect "^1.0.1" -"@szmarczak/http-timer@^4.0.5": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" - integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== - dependencies: - defer-to-connect "^2.0.0" - "@techpass/passport-openidconnect@0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.2.tgz#f8fd5d97256286665dbf26dac92431f977ab1e63" @@ -4950,17 +4877,6 @@ request "^2.88.0" webfinger "^0.4.2" -"@techpass/passport-openidconnect@^0.3.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.3.tgz#6c01c78bd8da0ca8917378dfbe18024702620352" - integrity sha512-i2X/CofjnGBqpTmw6b+Ex3Co/NrR2xjnIHvnOJk62XIlJJHNSTwmhJ1PkXoA5RGKlxZWchADFGjLTJnebvRj7A== - dependencies: - base64url "^3.0.1" - oauth "^0.9.15" - passport-strategy "^1.0.0" - request "^2.88.0" - webfinger "^0.4.2" - "@techteamer/ocsp@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@techteamer/ocsp/-/ocsp-1.0.0.tgz#7b82b02093fbe351e915bb37685ac1ac5a1233d3" @@ -5133,16 +5049,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/cacheable-request@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" - integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== - dependencies: - "@types/http-cache-semantics" "*" - "@types/keyv" "^3.1.4" - "@types/node" "*" - "@types/responselike" "^1.0.0" - "@types/caseless@*": version "0.12.2" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" @@ -5307,11 +5213,6 @@ resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.3.tgz#ef8e3d1a8d46c387f04ab0f2e8ab8cb0c5078661" integrity sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA== -"@types/http-cache-semantics@*": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" - integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== - "@types/http-errors@*": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" @@ -5373,13 +5274,6 @@ resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== -"@types/keyv@^3.1.4": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" - integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== - dependencies: - "@types/node" "*" - "@types/koa-compose@*": version "3.2.5" resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.5.tgz#85eb2e80ac50be95f37ccf8c407c09bbe3468e9d" @@ -5387,29 +5281,13 @@ dependencies: "@types/koa" "*" -"@types/koa-passport@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/koa-passport/-/koa-passport-4.0.3.tgz#063ec6310edee76cf854aadaa717b97f04b104fb" - integrity sha512-tNMYd/bcv0Zw7fc0CzEBYM9uUzVtn4XWzdUYfkTgSkEljP6nap7eI4E5x43ukrUQvztgXSYFkz3Uk+ujFeUzTg== - dependencies: - "@types/koa" "*" - "@types/passport" "*" - -"@types/koa-send@*", "@types/koa-send@^4.1.6": +"@types/koa-send@^4.1.6": version "4.1.6" resolved "https://registry.yarnpkg.com/@types/koa-send/-/koa-send-4.1.6.tgz#15d90e95e3ccce669a15b6a3c56c3a650a167cea" integrity sha512-vgnNGoOJkx7FrF0Jl6rbK1f8bBecqAchKpXtKuXzqIEdXTDO6dsSTjr+eZ5m7ltSjH4K/E7auNJEQCAd0McUPA== dependencies: "@types/koa" "*" -"@types/koa-static@^4.0.2": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/koa-static/-/koa-static-4.0.4.tgz#ce6f2a5d14cc7ef19f9bf6ee8e4f3eadfcc77323" - integrity sha512-j1AUzzl7eJYEk9g01hNTlhmipFh8RFbOQmaMNLvLcNNAkPw0bdTs3XTa3V045XFlrWN0QYnblbDJv2RzawTn6A== - dependencies: - "@types/koa" "*" - "@types/koa-send" "*" - "@types/koa@*": version "2.13.5" resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.5.tgz#64b3ca4d54e08c0062e89ec666c9f45443b21a61" @@ -5438,13 +5316,6 @@ "@types/koa-compose" "*" "@types/node" "*" -"@types/koa__cors@^3.1.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.3.1.tgz#0ec7543c4c620fd23451bfdd3e21b9a6aadedccd" - integrity sha512-aFGYhTFW7651KhmZZ05VG0QZJre7QxBxDj2LF1lf6GA/wSXEfKVAJxiQQWzRV4ZoMzQIO8vJBXKsUcRuvYK9qw== - dependencies: - "@types/koa" "*" - "@types/koa__router@8.0.8": version "8.0.8" resolved "https://registry.yarnpkg.com/@types/koa__router/-/koa__router-8.0.8.tgz#b1e0e9a512498777d3366bbdf0e853df27ec831c" @@ -5546,42 +5417,21 @@ dependencies: undici-types "~5.26.4" -"@types/node@>=4.2.0 < 13", "@types/node@^12.20.52": - version "12.20.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" - integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== - "@types/node@>=8.0.0 <15": version "14.18.37" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.37.tgz#0bfcd173e8e1e328337473a8317e37b3b14fd30d" integrity sha512-7GgtHCs/QZrBrDzgIJnQtuSvhFSwhyYSI2uafSwZoNt1iOGhEN5fwNrQMjtONyHm9+/LoA4453jH0CMYcr06Pg== -"@types/node@>=8.1.0": - version "20.11.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.2.tgz#39cea3fe02fbbc2f80ed283e94e1d24f2d3856fb" - integrity sha512-cZShBaVa+UO1LjWWBPmWRR4+/eY/JR/UIEcDlVsw3okjWEu+rB7/mH6X3B/L+qJVHDLjk9QW/y2upp9wp1yDXA== - dependencies: - undici-types "~5.26.4" - -"@types/nodemailer@^6.4.4": - version "6.4.14" - resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.14.tgz#5c81a5e856db7f8ede80013e6dbad7c5fb2283e2" - integrity sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA== - dependencies: - "@types/node" "*" +"@types/node@^12.20.52": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== -"@types/oauth@*": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@types/oauth/-/oauth-0.9.4.tgz#dcbab5efa2f34f312b915f80685760ccc8111e0a" - integrity sha512-qk9orhti499fq5XxKCCEbd0OzdPZuancneyse3KtR+vgMiHRbh+mn8M4G6t64ob/Fg+GZGpa565MF/2dKWY32A== - dependencies: - "@types/node" "*" - "@types/oracledb@5.2.2": version "5.2.2" resolved "https://registry.yarnpkg.com/@types/oracledb/-/oracledb-5.2.2.tgz#ae7ba795969e3bbd8d57ab141873a1aa012b86cd" @@ -5590,37 +5440,6 @@ "@types/node" "*" dotenv "^8.2.0" -"@types/passport-google-oauth@^1.0.42": - version "1.0.45" - resolved "https://registry.yarnpkg.com/@types/passport-google-oauth/-/passport-google-oauth-1.0.45.tgz#c986c787ec9706b4a596d2bae43342b50b54973d" - integrity sha512-O3Y3DDKnf9lR8+DSaUOCEGF6aFjVYdI8TLhQYtySZ3Sq75c5tGYJ0KJRDZw0GsyLD/Que0nqFkP/GnDVwZZL9w== - dependencies: - "@types/express" "*" - "@types/passport" "*" - -"@types/passport-microsoft@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/passport-microsoft/-/passport-microsoft-1.0.0.tgz#a2ddc2200843570d38c35c53f6388e33df915b58" - integrity sha512-vD9ajSUc9Sz/8gdCj0ODUbPYQDxcI/imIDdgMPh//c5yMK/PgV6SNUXFLBzJo89Y30LU6bYAfXKn40WJqtMBiA== - dependencies: - "@types/passport-oauth2" "*" - -"@types/passport-oauth2@*": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@types/passport-oauth2/-/passport-oauth2-1.4.15.tgz#34f2684f53aad36e664cd01ca9879224229f47e7" - integrity sha512-9cUTP/HStNSZmhxXGuRrBJfEWzIEJRub2eyJu3CvkA+8HAMc9W3aKdFhVq+Qz1hi42qn+GvSAnz3zwacDSYWpw== - dependencies: - "@types/express" "*" - "@types/oauth" "*" - "@types/passport" "*" - -"@types/passport@*": - version "1.0.16" - resolved "https://registry.yarnpkg.com/@types/passport/-/passport-1.0.16.tgz#5a2918b180a16924c4d75c31254c31cdca5ce6cf" - integrity sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A== - dependencies: - "@types/express" "*" - "@types/pg@8.6.6": version "8.6.6" resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.6.tgz#21cdf873a3e345a6e78f394677e3b3b1b543cb80" @@ -5825,13 +5644,6 @@ dependencies: "@types/node" "*" -"@types/responselike@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" - integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== - dependencies: - "@types/node" "*" - "@types/rimraf@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.2.tgz#a63d175b331748e5220ad48c901d7bbf1f44eef8" @@ -5860,13 +5672,6 @@ dependencies: "@types/node" "*" -"@types/server-destroy@^1.0.1": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/server-destroy/-/server-destroy-1.0.3.tgz#2460932ea3a02a70ec99669c8f40ff089a5b8a2b" - integrity sha512-Qq0fn70C7TLDG1W9FCblKufNWW1OckQ41dVKV2Dku5KdZF7bexezG4e2WBaBKhdwL3HZ+cYCEIKwg2BRgzrWmA== - dependencies: - "@types/node" "*" - "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -5948,7 +5753,7 @@ dependencies: "@types/node" "*" -"@types/uuid@8.3.4", "@types/uuid@^8.3.4": +"@types/uuid@8.3.4": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== @@ -6290,6 +6095,11 @@ js-yaml "^3.10.0" tslib "^2.4.0" +"@zerodevx/svelte-json-view@^1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@zerodevx/svelte-json-view/-/svelte-json-view-1.0.7.tgz#abf3efa71dedcb3e9d16bc9cc61d5ea98c8d00b1" + integrity sha512-yW0MV+9BCKOwzt3h86y3xDqYdI5st+Rxk+L5pa0Utq7nlPD+VvxyhL7R1gJoLxQvWwjyAvY/fyUCFTdwDyI14w== + "@zkochan/js-yaml@0.0.6": version "0.0.6" resolved "https://registry.yarnpkg.com/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz#975f0b306e705e28b8068a07737fa46d3fc04826" @@ -6332,7 +6142,7 @@ abortcontroller-polyfill@^1.4.0: resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== -abstract-leveldown@^6.2.1, abstract-leveldown@^6.3.0: +abstract-leveldown@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== @@ -6854,13 +6664,6 @@ async-retry@^1.3.3: dependencies: retry "0.13.1" -async@^2.6.3: - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" - async@^3.2.1, async@^3.2.3: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" @@ -7234,11 +7037,6 @@ bootstrap@3.4.1: resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.4.1.tgz#c3a347d419e289ad11f4033e3c4132b87c081d72" integrity sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA== -bottleneck@^2.19.5: - version "2.19.5" - resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" - integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== - bowser@^2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" @@ -7387,11 +7185,6 @@ bson@^5.4.0: resolved "https://registry.yarnpkg.com/bson/-/bson-5.4.0.tgz#0eea77276d490953ad8616b483298dbff07384c6" integrity sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA== -btoa@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" - integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== - buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -7405,7 +7198,7 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" -buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: +buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== @@ -7590,11 +7383,6 @@ cache-content-type@^1.0.0: mime-types "^2.1.18" ylru "^1.2.0" -cacheable-lookup@^5.0.3: - version "5.0.4" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" - integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== - cacheable-request@^2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" @@ -7621,19 +7409,6 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" - integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^4.0.0" - lowercase-keys "^2.0.0" - normalize-url "^6.0.1" - responselike "^2.0.0" - call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" @@ -7672,52 +7447,6 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -camunda-8-credentials-from-env@^1.1.1, camunda-8-credentials-from-env@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/camunda-8-credentials-from-env/-/camunda-8-credentials-from-env-1.2.2.tgz#abe5d216e7e4cfc970e0463e9aa5e802487b1062" - integrity sha512-uj2PY5/IoAgu0cHmeEUp+qmSXCtpQafStzGJ8ORYvyupBN/gVpdP9X+A+UlQRCGmApcaIuPUw8/9FsXig5NWXg== - dependencies: - neon-env "^0.1.1" - -camunda-8-sdk@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/camunda-8-sdk/-/camunda-8-sdk-0.15.0.tgz#13754dca499d16802675b6f2790e2d06bd8034d6" - integrity sha512-felyQU+rD8uupPjBArmyy0E/k9mrmeZvfFliF3y/pxYkGBoaC5kjDHDsx+hNpbnIwShET0RLjklit7f+98yIBw== - dependencies: - camunda-console-client "^0.9.1" - camunda-tasklist-client "0.9.5" - operate-api-client "1.2.3" - optimize-api-client "^1.0.3" - zeebe-node "^8.2.5" - -camunda-console-client@^0.9.1: - version "0.9.2" - resolved "https://registry.yarnpkg.com/camunda-console-client/-/camunda-console-client-0.9.2.tgz#137dbd2e61bb5bbfff38aebe5d53e775653aabb8" - integrity sha512-ni+7lSc5oG0FevCagrBV6juZzwcQ4ciATBZxyOMFQK0yVTmZxOUz5efN9XWP4E36PGpuqALQXsViUDlGZcfZBA== - dependencies: - camunda-8-credentials-from-env "^1.2.2" - camunda-saas-oauth "^1.2.4" - debug "^4.3.4" - dotenv "^16.3.1" - got "^11.8.6" - -camunda-saas-oauth@^1.2.0, camunda-saas-oauth@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/camunda-saas-oauth/-/camunda-saas-oauth-1.2.4.tgz#348a8422f266dafed98cf2a73046aa62c89d03f2" - integrity sha512-AO/kcnZXcsodwM3qgMZj/5wn8SBoKmSDpuFYUpPS+HqQhG9GvWY8noBx/4pvX3gYPKiPTYi9/e9ApAe02NARzA== - dependencies: - camunda-8-credentials-from-env "^1.2.2" - got "^11.8.5" - -camunda-tasklist-client@0.9.5: - version "0.9.5" - resolved "https://registry.yarnpkg.com/camunda-tasklist-client/-/camunda-tasklist-client-0.9.5.tgz#c0f2685ef7fb7fdb198a37e5b35a911e3b233b28" - integrity sha512-gipH8ON/ttTgLfleWecQith1g9SpC5Q8CoLXFq2yw3cVJ1JVrcn0ArtgCxA1QCgtZBlV7EuGt9QWGc9UCfbbGw== - dependencies: - camunda-8-credentials-from-env "^1.1.1" - camunda-saas-oauth "^1.2.0" - gotql "^2.1.0-alpha1" - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -7811,7 +7540,7 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -cheap-watch@^1.0.2, cheap-watch@^1.0.4: +cheap-watch@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/cheap-watch/-/cheap-watch-1.0.4.tgz#0bcb4a3a8fbd9d5327936493f6b56baa668d8fef" integrity sha512-QR/9FrtRL5fjfUJBhAKCdi0lSRQ3rVRRum3GF9wDKp2TJbEIMGhUEr2yU8lORzm9Isdjx7/k9S0DFDx+z5VGtw== @@ -8138,7 +7867,7 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@^7.0.0, commander@^7.1.0, commander@^7.2.0: +commander@^7.0.0, commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== @@ -8247,7 +7976,7 @@ config-chain@^1.1.13: ini "^1.3.4" proto-list "~1.2.1" -configent@^2.1.4, configent@^2.2.0: +configent@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/configent/-/configent-2.2.0.tgz#2de230fc43f22c47cfd99016aa6962d6f9546994" integrity sha512-yIN6zfOWk2nycNJ2JFNiWEai0oiqAhISIht8+pbEBP8bdcpwoQ74AhCZPbUv9aRVJwo7wh1MbCBDUV44UJa7Kw== @@ -8271,14 +8000,6 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -console-stamp@^3.0.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/console-stamp/-/console-stamp-3.1.2.tgz#35dac393e16069a4d9d37b71ca6d5d13d7f3f8fd" - integrity sha512-ab66x3NxOTxPuq71dI6gXEiw2X6ql4Le5gZz0bm7FW3FSCB00eztra/oQUuCoCGlsyKOxtULnHwphzMrRtzMBg== - dependencies: - chalk "^4.1.2" - dateformat "^4.6.3" - consolidate@^0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.16.0.tgz#a11864768930f2f19431660a65906668f5fbdc16" @@ -8771,7 +8492,7 @@ dateformat@^4.6.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== -dayjs@^1.10.8, dayjs@^1.8.15: +dayjs@^1.10.8: version "1.11.10" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== @@ -8821,7 +8542,7 @@ dd-trace@5.0.0: semver "^7.5.4" tlhunter-sorted-set "^0.1.0" -debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -8870,13 +8591,6 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -decompress-response@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" - integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== - dependencies: - mimic-response "^3.1.0" - decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" @@ -9002,11 +8716,6 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== -defer-to-connect@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" - integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== - deferred-leveldown@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-0.2.0.tgz#2cef1f111e1c57870d8bbb8af2650e587cd2f5b4" @@ -9050,11 +8759,6 @@ defined@^1.0.0: resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== -defined@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e" - integrity sha512-zpqiCT8bODLu3QSmLLic8xJnYWBFjOSu/fBCm189oAiTtPq/PSanNACKZDS7kgSyCJY7P+IcODzlIogBK/9RBg== - delay@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" @@ -9350,7 +9054,7 @@ docker-compose@0.24.0: dependencies: yaml "^1.10.2" -docker-compose@^0.23.5, docker-compose@^0.23.6: +docker-compose@^0.23.5: version "0.23.19" resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.23.19.tgz#9947726e2fe67bdfa9e8efe1ff15aa0de2e10eb8" integrity sha512-v5vNLIdUqwj4my80wxFDkNH+4S85zsRuH29SO7dCWVWPCMt/ohZBsGN6g6KXWifT0pzQ7uOxqEKCYCDPJ8Vz4g== @@ -9491,11 +9195,6 @@ dotenv@8.6.0, dotenv@^8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== -dotenv@^16.3.1: - version "16.3.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" - integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== - dotenv@~10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" @@ -9548,24 +9247,6 @@ duplexify@^4.0.0, duplexify@^4.1.2: readable-stream "^3.1.1" stream-shift "^1.0.0" -dynalite@^3.2.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/dynalite/-/dynalite-3.2.2.tgz#34b4f4dd69638f17c0f7551a867959972c892441" - integrity sha512-sx9ZjTgMs/D4gHnba4rnBkw29648dHwHmywJet132KAbiq1ZyWx9W1fMd/eP9cPwTKDXyCBuTYOChE0qMDjaXQ== - dependencies: - async "^2.6.3" - big.js "^5.2.2" - buffer-crc32 "^0.2.13" - lazy "^1.0.11" - levelup "^4.4.0" - lock "^1.1.0" - memdown "^5.1.0" - minimist "^1.2.5" - once "^1.4.0" - subleveldown "^5.0.1" - optionalDependencies: - leveldown "^5.6.0" - eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -9672,7 +9353,7 @@ encodeurl@^1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -encoding-down@^6.2.0, encoding-down@^6.3.0: +encoding-down@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== @@ -9780,11 +9461,6 @@ envinfo@7.8.1, envinfo@^7.7.3: resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== -err-code@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" - integrity sha512-CJAN+O0/yA1CKfRn9SXOGctSpEM7DCon/r/5r2eXFMY2zCCJBasFhcM5I+1kh3Ap11FsQCX+vGHceNPvpWKhoA== - err-code@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" @@ -9922,11 +9598,6 @@ es6-error@^4.0.1, es6-error@^4.1.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -es6-promise@^4.2.4: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - esbuild-loader@^2.16.0: version "2.21.0" resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.21.0.tgz#2698a3e565b0db2bb19a3dd91c2b6c9aad526c80" @@ -10525,13 +10196,6 @@ fast-xml-parser@4.2.5: dependencies: strnum "^1.0.5" -fast-xml-parser@^4.1.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.3.3.tgz#aeaf5778392329f17168c40c51bcbfec8ff965be" - integrity sha512-coV/D1MhrShMvU6D0I+VAK3umz6hUaxxhL0yp/9RjfiYUfAv14rDhGQL+PLForhMdr0wq3PiV07WtkkNjJjNHg== - dependencies: - strnum "^1.0.5" - fast-xml-parser@^4.2.2, fast-xml-parser@^4.2.5: version "4.3.2" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz#761e641260706d6e13251c4ef8e3f5694d4b0d79" @@ -10872,11 +10536,6 @@ formidable@^2.1.2: once "^1.4.0" qs "^6.11.0" -fp-ts@^2.5.1: - version "2.16.2" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.16.2.tgz#7faa90f6fc2e8cf84c711d2c4e606afe2be9e342" - integrity sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng== - fresh@^0.5.2, fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -10918,7 +10577,7 @@ fs-extra@^11.1.0, fs-extra@^11.1.1: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: +fs-extra@^9.0.0, fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== @@ -10967,7 +10626,7 @@ function.prototype.name@^1.1.6: es-abstract "^1.22.1" functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1: +functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= @@ -11561,23 +11220,6 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -got@^11.5.1, got@^11.8.5, got@^11.8.6: - version "11.8.6" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" - integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== - dependencies: - "@sindresorhus/is" "^4.0.0" - "@szmarczak/http-timer" "^4.0.5" - "@types/cacheable-request" "^6.0.1" - "@types/responselike" "^1.0.0" - cacheable-lookup "^5.0.3" - cacheable-request "^7.0.2" - decompress-response "^6.0.0" - http2-wrapper "^1.0.0-beta.5.2" - lowercase-keys "^2.0.0" - p-cancelable "^2.0.0" - responselike "^2.0.0" - got@^8.3.1: version "8.3.2" resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" @@ -11618,15 +11260,6 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -gotql@^2.1.0-alpha1: - version "2.1.0-alpha1" - resolved "https://registry.yarnpkg.com/gotql/-/gotql-2.1.0-alpha1.tgz#b04e9adb0d1751a0c2de05bd4399f5c57aec79ba" - integrity sha512-4xG1AczSpK+tdKUDM4kB1ah/2LoNlmFU5IhGNktuYNBLgyWB5iDs4OE36NE7k59iTKYi2B7vudQz2Itw1ZXrRg== - dependencies: - debug "^4.1.1" - got "^11.5.1" - prepend-http "^3.0.1" - graceful-fs@4.2.11, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -11991,14 +11624,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -http2-wrapper@^1.0.0-beta.5.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" - integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.0.0" - https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -12118,11 +11743,6 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== -immediate@~3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" - integrity sha512-RrGCXRm/fRVqMIhqXrGEX9rRADavPiDFSoMb/k64i9XMk8uH4r/Omi5Ctierj6XzNecwDbO4WuFbDD1zmpl3Tg== - import-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92" @@ -13048,15 +12668,6 @@ jest-docblock@^29.7.0: dependencies: detect-newline "^3.0.0" -jest-dynalite@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/jest-dynalite/-/jest-dynalite-3.6.1.tgz#8bae305a3c33d9a8036f563827b173b54a323ca5" - integrity sha512-MERtTt8Pj39vFmbItMC3YuIaqLf1kh/pJIE0DRcjeP/2Fa8Nni9IxwN6XWIMgXNbFKtlOM6ppH+Bsy0rWIdPiw== - dependencies: - "@aws/dynamodb-auto-marshaller" "^0.7.1" - dynalite "^3.2.1" - setimmediate "^1.0.5" - jest-each@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" @@ -13576,11 +13187,6 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -13749,13 +13355,6 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -keyv@^4.0.0: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - kill-port@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/kill-port/-/kill-port-1.6.1.tgz#560fe79484583bdf3a5e908557dae614447618aa" @@ -13871,7 +13470,7 @@ koa-mount@^4.0.0: debug "^4.0.1" koa-compose "^4.1.0" -koa-passport@4.1.4, koa-passport@^4.1.4: +koa-passport@4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa" integrity sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg== @@ -13905,7 +13504,7 @@ koa-send@5.0.1, koa-send@^5.0.0: http-errors "^1.7.3" resolve-path "^1.4.0" -koa-session@5.13.1, koa-session@^5.12.0: +koa-session@5.13.1: version "5.13.1" resolved "https://registry.yarnpkg.com/koa-session/-/koa-session-5.13.1.tgz#a47e39015a4b464e21e3e1e2deeca48eb83916ee" integrity sha512-TfYiun6xiFosyfIJKnEw0aoG5XmLIwM+K3OVWfkz84qY0NP2gbk0F/olRn0/Hrxq0f14s8amHVXeWyKYH3Cx3Q== @@ -13923,7 +13522,7 @@ koa-static@5.0.0, koa-static@^5.0.0: debug "^3.1.0" koa-send "^5.0.0" -koa-useragent@4.1.0, koa-useragent@^4.1.0: +koa-useragent@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/koa-useragent/-/koa-useragent-4.1.0.tgz#d3f128b552c6da3e5e9e9e9c887b2922b16e4468" integrity sha512-x/HUDZ1zAmNNh5hA9hHbPm9p3UVg2prlpHzxCXQCzbibrNS0kmj7MkCResCbAbG7ZT6FVxNSMjR94ZGamdMwxA== @@ -14023,11 +13622,6 @@ latest-version@^5.1.0: dependencies: package-json "^6.3.0" -lazy@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" - integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== - lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" @@ -14213,13 +13807,6 @@ level-js@^5.0.0: inherits "^2.0.3" ltgt "^2.1.2" -level-option-wrap@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/level-option-wrap/-/level-option-wrap-1.1.0.tgz#ad20e68d9f3c22c8897531cc6aa7af596b1ed129" - integrity sha512-gQouC22iCqHuBLNl4BHxEZUxLvUKALAtT/Q0c6ziOxZQ8c02G/gyxHWNbLbxUzRNfMrRnbt6TZT3gNe8VBqQeg== - dependencies: - defined "~0.0.0" - level-packager@^5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" @@ -14268,7 +13855,7 @@ level@6.0.1: level-packager "^5.1.0" leveldown "^5.4.0" -leveldown@5.6.0, leveldown@^5.4.0, leveldown@^5.6.0: +leveldown@5.6.0, leveldown@^5.4.0: version "5.6.0" resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98" integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== @@ -14277,7 +13864,7 @@ leveldown@5.6.0, leveldown@^5.4.0, leveldown@^5.6.0: napi-macros "~2.0.0" node-gyp-build "~4.1.0" -levelup@4.4.0, levelup@^4.3.2, levelup@^4.4.0: +levelup@4.4.0, levelup@^4.3.2: version "4.4.0" resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== @@ -14466,11 +14053,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lock@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/lock/-/lock-1.1.0.tgz#53157499d1653b136ca66451071fca615703fa55" - integrity sha512-NZQIJJL5Rb9lMJ0Yl1JoVr9GSdo4HTPsUEWsSFzB8dE8DSoiLCVavWZPi7Rnlv/o73u6I24S/XYc/NmG4l8EKA== - lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" @@ -14611,7 +14193,7 @@ lodash.xor@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6" integrity sha512-sVN2zimthq7aZ5sPGXnSz32rZPuqcparVW50chJQe+mzTYV+IsxSsl/2gnkWWE2Of7K3myBQBqtLKOUEHJKRsQ== -lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.7.0: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -14965,18 +14547,6 @@ memdown@1.4.1: ltgt "~2.2.0" safe-buffer "~5.1.1" -memdown@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb" - integrity sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw== - dependencies: - abstract-leveldown "~6.2.1" - functional-red-black-tree "~1.0.1" - immediate "~3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.2.0" - memory-pager@^1.0.2: version "1.5.0" resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" @@ -15085,11 +14655,6 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mimic-response@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" - integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== - min-document@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" @@ -15533,11 +15098,6 @@ neo-async@^2.6.0, neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -neon-env@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/neon-env/-/neon-env-0.1.3.tgz#071e86fde3c698e9314f057d209e0b79ddab16e9" - integrity sha512-Zo+L6Nm19gJrjyfhxn/ZDm8eIIDzr75o64ZhijBau4LNuhLzjEAteRg3gchIvgaN8XTo5BxN6iTNP5clZQ0agA== - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -16255,23 +15815,6 @@ opentracing@>=0.12.1: resolved "https://registry.yarnpkg.com/opentracing/-/opentracing-0.14.7.tgz#25d472bd0296dc0b64d7b94cbc995219031428f5" integrity sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q== -operate-api-client@1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/operate-api-client/-/operate-api-client-1.2.3.tgz#c884ab09fe07360ac5ce5b58ae470ba1e91db879" - integrity sha512-8FWfDsHVxgYIBe4p4fB6e7SSiYdW/PPTCCLFcGnbqdUxlhcUq9ncYu6ZMMm6E3A3WKxagdInYQbxOhtTeVGhVQ== - dependencies: - camunda-saas-oauth "^1.2.0" - got "^11.8.5" - -optimize-api-client@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/optimize-api-client/-/optimize-api-client-1.0.4.tgz#a2e653780fd1e9e54a38912418b0ea27bd0484ef" - integrity sha512-2XBW+sv6eENOCHMc5v0XmH2DaaSETAb/qH5BsfpTDD8Pmeu10ZR61W7Pc/rBqauy96vPP/MfgmMphx5CjHb2xg== - dependencies: - camunda-8-credentials-from-env "^1.1.1" - camunda-saas-oauth "^1.2.4" - got "^11.8.5" - optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -16345,11 +15888,6 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== -p-cancelable@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" - integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== - p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -16662,7 +16200,7 @@ passport-google-oauth20@2.x.x: dependencies: passport-oauth2 "1.x.x" -passport-google-oauth@2.0.0, passport-google-oauth@^2.0.0: +passport-google-oauth@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz#f6eb4bc96dd6c16ec0ecfdf4e05ec48ca54d4dae" integrity sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA== @@ -16677,14 +16215,6 @@ passport-local@1.0.0: dependencies: passport-strategy "1.x.x" -passport-microsoft@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/passport-microsoft/-/passport-microsoft-1.0.0.tgz#78954cf3201fdce61beeb6587a3b158f8e9db86c" - integrity sha512-L1JHeCbSObSZZXiG7jU2KoKie6nzZLwGt38HXz1GasKrsCQdOnf5kH8ltV4BWNUfBL2Pt1csWn1iuBSerprrcg== - dependencies: - passport-oauth2 "1.6.1" - pkginfo "0.4.x" - passport-oauth1@1.x.x: version "1.3.0" resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.3.0.tgz#5d57f1415c8e28e46b461a12ec1b492934f7c354" @@ -16699,17 +16229,6 @@ passport-oauth2-refresh@^2.1.0: resolved "https://registry.yarnpkg.com/passport-oauth2-refresh/-/passport-oauth2-refresh-2.1.0.tgz#c31cd133826383f5539d16ad8ab4f35ca73ce4a4" integrity sha512-4ML7ooCESCqiTgdDBzNUFTBcPR8zQq9iM6eppEUGMMvLdsjqRL93jKwWm4Az3OJcI+Q2eIVyI8sVRcPFvxcF/A== -passport-oauth2@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.1.tgz#c5aee8f849ce8bd436c7f81d904a3cd1666f181b" - integrity sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ== - dependencies: - base64url "3.x.x" - oauth "0.9.x" - passport-strategy "1.x.x" - uid2 "0.0.x" - utils-merge "1.x.x" - passport-oauth2@1.x.x: version "1.7.0" resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.7.0.tgz#5c4766c8531ac45ffe9ec2c09de9809e2c841fc4" @@ -17086,11 +16605,6 @@ pkg-types@^1.0.3: mlly "^1.2.0" pathe "^1.1.0" -pkginfo@0.4.x: - version "0.4.1" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" - integrity sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ== - pluralize@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" @@ -17420,13 +16934,6 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" -posthog-js@^1.13.4: - version "1.100.0" - resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.100.0.tgz#687b9a6e4ed226aa6572f4040b418ea0c8b3d353" - integrity sha512-r2XZEiHQ9mBK7D1G9k57I8uYZ2kZTAJ0OCX6K/OOdCWN8jKPhw3h5F9No5weilP6eVAn+hrsy7NvPV7SCX7gMg== - dependencies: - fflate "^0.4.1" - posthog-js@^1.36.0: version "1.96.1" resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.96.1.tgz#4f9719a24e4e14037b0e72d430194d7cdb576447" @@ -17723,11 +17230,6 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== -prepend-http@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-3.0.1.tgz#3e724d58fd5867465b300bb9615009fa2f8ee3b6" - integrity sha512-BLxfZh+m6UiAiCPZFJ4+vYoL7NrRs5XgCTRrjseATAggXhdZKKxn+JUNmuVYWY23bDHgaEHodxw8mnmtVEDtHw== - prettier-plugin-svelte@^2.3.0: version "2.6.0" resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.6.0.tgz#0e845b560b55cd1d951d6c50431b4949f8591746" @@ -17827,14 +17329,6 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== -promise-retry@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" - integrity sha512-StEy2osPr28o17bIW776GtwO6+Q+M9zPiZkYfosciUUMYqjhU/ffwRAH0zN2+uvGyUsn8/YICIHRzLbPacpZGw== - dependencies: - err-code "^1.0.0" - retry "^0.10.0" - promise-retry@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" @@ -18026,7 +17520,7 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@^6.10.3, qs@^6.11.0, qs@^6.4.0: +qs@^6.11.0, qs@^6.4.0: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== @@ -18082,11 +17576,6 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - quote-unquote@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/quote-unquote/-/quote-unquote-1.0.0.tgz#67a9a77148effeaf81a4d428404a710baaac8a0b" @@ -18139,11 +17628,6 @@ rc@1.2.8, rc@^1.2.7, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -reachdown@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/reachdown/-/reachdown-1.1.0.tgz#c3b85b459dbd0fe2c79782233a0a38e66a9b5454" - integrity sha512-6LsdRe4cZyOjw4NnvbhUd/rGG7WQ9HMopPr+kyL018Uci4kijtxcGR5kVb5Ln13k4PEE+fEFQbjfOvNw7cnXmA== - react-is@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" @@ -18541,11 +18025,6 @@ requizzle@^0.2.3: dependencies: lodash "^4.17.21" -resolve-alpn@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" - integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -18605,13 +18084,6 @@ responselike@1.0.2, responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -responselike@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" - integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== - dependencies: - lowercase-keys "^2.0.0" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -18633,11 +18105,6 @@ retry@0.13.1, retry@^0.13.1: resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" integrity "sha1-GFsVh6z2eRnWOzVzSeA1N7JIRlg= sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" -retry@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - integrity sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ== - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -19094,7 +18561,7 @@ serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" -server-destroy@1.0.1, server-destroy@^1.0.1: +server-destroy@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" integrity sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ== @@ -19123,11 +18590,6 @@ set-function-name@^2.0.0, set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -19603,7 +19065,7 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-trace@0.0.10, stack-trace@0.0.x: +stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== @@ -19885,14 +19347,6 @@ strip-outer@^1.0.0: dependencies: escape-string-regexp "^1.0.2" -stripe@9.16.0: - version "9.16.0" - resolved "https://registry.yarnpkg.com/stripe/-/stripe-9.16.0.tgz#94c24549c91fced457b9e3259e8a1a1bdb6dbd0e" - integrity sha512-Dn8K+jSoQcXjxCobRI4HXUdHjOXsiF/KszK49fJnkbeCFjZ3EZxLG2JiM/CX+Hcq27NBDtv/Sxhvy+HhTmvyaQ== - dependencies: - "@types/node" ">=8.1.0" - qs "^6.10.3" - striptags@^3.1.1: version "3.2.0" resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" @@ -19966,18 +19420,6 @@ sublevel-pouchdb@7.2.2: ltgt "2.2.1" readable-stream "1.1.14" -subleveldown@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/subleveldown/-/subleveldown-5.0.1.tgz#aa2b4e4698a48d9a86856b2c4df1b6bce2d2ce53" - integrity sha512-cVqd/URpp7si1HWu5YqQ3vqQkjuolAwHypY1B4itPlS71/lsf6TQPZ2Y0ijT22EYVkvH5ove9JFJf4u7VGPuZw== - dependencies: - abstract-leveldown "^6.3.0" - encoding-down "^6.2.0" - inherits "^2.0.3" - level-option-wrap "^1.1.0" - levelup "^4.4.0" - reachdown "^1.1.0" - superagent@^8.0.5: version "8.1.2" resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.1.2.tgz#03cb7da3ec8b32472c9d20f6c2a57c7f3765f30b" @@ -20844,11 +20286,6 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typed-duration@^1.0.12: - version "1.0.13" - resolved "https://registry.yarnpkg.com/typed-duration/-/typed-duration-1.0.13.tgz#a40f9ba563b6e20674cac491e15ecbf6811d85a7" - integrity sha512-HLwA+hNq/2eXe03isJSfa7YJt6NikplBGdNKvlhyuR6WL5iZi2uXJIZv1SSOMEIukCZbeQ8QwIcQ801S0/Qulw== - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -21062,7 +20499,7 @@ update-browserslist-db@^1.0.10: escalade "^3.1.1" picocolors "^1.0.0" -update-dotenv@1.1.1, update-dotenv@^1.1.1: +update-dotenv@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/update-dotenv/-/update-dotenv-1.1.1.tgz#17146f302f216c3c92419d5a327a45be910050ca" integrity sha512-3cIC18In/t0X/yH793c00qqxcKD8jVCgNOPif/fGQkFpYMGecM9YAc+kaAKXuZsM2dE9I9wFI7KvAuNX22SGMQ== @@ -21106,7 +20543,7 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@^1.4.3, url-parse@^1.5.3: +url-parse@^1.5.3: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== @@ -21176,11 +20613,6 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - uuid@^9.0.0, uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" @@ -22079,23 +21511,3 @@ z-schema@^5.0.1: validator "^13.7.0" optionalDependencies: commander "^9.4.1" - -zeebe-node@^8.2.5: - version "8.3.1" - resolved "https://registry.yarnpkg.com/zeebe-node/-/zeebe-node-8.3.1.tgz#e100bf3708464e305305b4efa1ffde53f9786c45" - integrity sha512-68ascWO3g7g+9WwDzvfa3I9TkLKHku5auEgSINP+k5ktNfsfGW68ELDmEJA+XHZgzvGsdGILZqGRzVd5SC8aaQ== - dependencies: - "@grpc/grpc-js" "1.9.7" - "@grpc/proto-loader" "0.7.10" - chalk "^2.4.2" - console-stamp "^3.0.2" - dayjs "^1.8.15" - debug "^4.2.0" - fast-xml-parser "^4.1.3" - fp-ts "^2.5.1" - got "^11.8.5" - long "^4.0.0" - promise-retry "^1.1.1" - stack-trace "0.0.10" - typed-duration "^1.0.12" - uuid "^7.0.3" From 6964e2d146de1a51eb55ffbf8a40052bce090575 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 29 Jan 2024 13:43:51 +0000 Subject: [PATCH 09/76] Fixing update aliasing. --- .../server/scripts/integrations/postgres/reset.sh | 1 + packages/server/src/integrations/base/sql.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/server/scripts/integrations/postgres/reset.sh b/packages/server/scripts/integrations/postgres/reset.sh index 32778bd11f..29a5db0181 100755 --- a/packages/server/scripts/integrations/postgres/reset.sh +++ b/packages/server/scripts/integrations/postgres/reset.sh @@ -1,3 +1,4 @@ #!/bin/bash docker-compose down docker volume prune -f +docker volume rm postgres_pg_data diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 3375e175e6..d33c077ee5 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -424,7 +424,7 @@ class InternalBuilder { knexWithAlias( knex: Knex, endpoint: { entityId: string; alias?: string; schema?: string } - ): { query: KnexQuery; name: string } { + ): { query: KnexQuery; aliased: string } { const tableName = endpoint.entityId const alias = endpoint.alias const aliased = alias ? alias : tableName @@ -433,7 +433,7 @@ class InternalBuilder { if (endpoint.schema) { query = query.withSchema(endpoint.schema) } - return { query, name: aliased } + return { query, aliased } } create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { @@ -493,7 +493,7 @@ class InternalBuilder { } // start building the query - let { query, name: aliased } = this.knexWithAlias(knex, endpoint) + let { query, aliased } = this.knexWithAlias(knex, endpoint) query = query.limit(foundLimit) if (foundOffset) { query = query.offset(foundOffset) @@ -522,9 +522,9 @@ class InternalBuilder { update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { const { endpoint, body, filters } = json - let { query } = this.knexWithAlias(knex, endpoint) + let { query, aliased } = this.knexWithAlias(knex, endpoint) const parsedBody = parseBody(body) - query = this.addFilters(query, filters, { tableName: endpoint.entityId }) + query = this.addFilters(query, filters, { tableName: aliased }) // mysql can't use returning if (opts.disableReturning) { return query.update(parsedBody) @@ -535,7 +535,7 @@ class InternalBuilder { delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { const { endpoint, filters } = json - let { query, name: aliased } = this.knexWithAlias(knex, endpoint) + let { query, aliased } = this.knexWithAlias(knex, endpoint) query = this.addFilters(query, filters, { tableName: aliased }) // mysql can't use returning if (opts.disableReturning) { From 5d2ba68fae4b39086686c41999b903c05c352ba4 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 30 Jan 2024 13:35:45 +0000 Subject: [PATCH 10/76] Adding test case based on capture of real failing query. --- .../server/src/integrations/tests/sql.spec.ts | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index 5cc4849d03..580a8117cb 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -683,3 +683,110 @@ describe("SQL query builder", () => { }) }) }) + +describe("Captures of real examples", () => { + const limit = 5000 + + it("should handle filtering by relationship", () => { + const queryJson = { + endpoint: { + datasourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + entityId: "products", + operation: "READ", + alias: "a", + }, + resource: { + fields: [ + "a.productname", + "a.productid", + "b.executorid", + "b.taskname", + "b.taskid", + "b.completed", + "b.qaid", + ], + }, + filters: { + equal: { + "1:tasks.taskname": "assembling", + }, + onEmptyFilter: "all", + }, + sort: { + productname: { + direction: "ASCENDING", + }, + }, + paginate: { + limit: 100, + page: 1, + }, + relationships: [ + { + tableName: "tasks", + column: "tasks", + through: "products_tasks", + from: "productid", + to: "taskid", + fromPrimary: "productid", + toPrimary: "taskid", + aliases: { + products_tasks: "c", + tasks: "b", + products: "a", + }, + }, + ], + meta: { + table: { + type: "table", + _id: "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products", + primary: ["productid"], + name: "a", + schema: { + productname: { + type: "string", + externalType: "character varying", + autocolumn: false, + name: "productname", + constraints: { + presence: false, + }, + }, + productid: { + type: "number", + externalType: "integer", + autocolumn: true, + name: "productid", + constraints: { + presence: false, + }, + }, + tasks: { + tableId: + "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + name: "tasks", + relationshipType: "many-to-many", + fieldName: "taskid", + through: + "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products_tasks", + throughFrom: "taskid", + throughTo: "productid", + type: "link", + main: true, + _id: "ca6862d9ba09146dd8a68e3b5b7055a09", + }, + }, + sourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + sourceType: "external", + primaryDisplay: "productname", + }, + }, + } + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: [100, "assembling", limit], + sql: `select "a"."productname" as "a.productname", "a"."productid" as "a.productid", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid" from (select * from "products" as "a" order by "a"."productname" asc limit $1) as "a" left join "products_tasks" as "c" on "a"."productid" = "c"."productid" left join "tasks" as "b" on "b"."taskid" = "c"."taskid" where "b"."taskname" = $2 order by "a"."productname" asc limit $3`, + }) + }) +}) From 09a0d00aa7df535454cb3eafe49714dcd1adf3e9 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 30 Jan 2024 13:50:36 +0000 Subject: [PATCH 11/76] Fixing some test cases. --- packages/server/src/integrations/tests/sql.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index 580a8117cb..bca0cf5422 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -502,7 +502,7 @@ describe("SQL query builder", () => { const query = sql._query(generateRelationshipJson({ schema: "production" })) expect(query).toEqual({ bindings: [500, 5000], - sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "production"."brands" limit $1) as "brands" left join "production"."products" on "brands"."brand_id" = "products"."brand_id" limit $2`, + sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "production"."brands" limit $1) as "brands" left join "production"."products" as "products" on "brands"."brand_id" = "products"."brand_id" limit $2`, }) }) @@ -510,7 +510,7 @@ describe("SQL query builder", () => { const query = sql._query(generateRelationshipJson()) expect(query).toEqual({ bindings: [500, 5000], - sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "brands" limit $1) as "brands" left join "products" on "brands"."brand_id" = "products"."brand_id" limit $2`, + sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "brands" limit $1) as "brands" left join "products" as "products" on "brands"."brand_id" = "products"."brand_id" limit $2`, }) }) @@ -520,7 +520,7 @@ describe("SQL query builder", () => { ) expect(query).toEqual({ bindings: [500, 5000], - sql: `select "stores"."store_id" as "stores.store_id", "stores"."store_name" as "stores.store_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name" from (select * from "production"."stores" limit $1) as "stores" left join "production"."stocks" on "stores"."store_id" = "stocks"."store_id" left join "production"."products" on "products"."product_id" = "stocks"."product_id" limit $2`, + sql: `select "stores"."store_id" as "stores.store_id", "stores"."store_name" as "stores.store_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name" from (select * from "production"."stores" limit $1) as "stores" left join "production"."stocks" as "stocks" on "stores"."store_id" = "stocks"."store_id" left join "production"."products" as "products" on "products"."product_id" = "stocks"."product_id" limit $2`, }) }) From bb0b776684e29a529ac5198451472e8981cadd1f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 30 Jan 2024 17:57:10 +0000 Subject: [PATCH 12/76] Updating how aliasing is handled. --- .../server/src/api/controllers/row/alias.ts | 2 +- packages/server/src/integrations/base/sql.ts | 86 ++++++++------ .../server/src/integrations/tests/sql.spec.ts | 110 ++---------------- .../sqlQueryJson/filterByRelationship.json | 94 +++++++++++++++ packages/types/src/sdk/search.ts | 3 +- 5 files changed, 158 insertions(+), 137 deletions(-) create mode 100644 packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index fc00b505c4..589431cc1a 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -113,7 +113,7 @@ export default class AliasTables { } json.meta.tables = aliasedTables } - json.endpoint.alias = this.getAlias(json.endpoint.entityId) + json.tableAliases = this.tableAliases const response = await getDatasourceAndQuery(json) return this.reverse(response) } diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index d33c077ee5..c9be2e1ae6 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -129,8 +129,13 @@ class InternalBuilder { addFilters( query: KnexQuery, filters: SearchFilters | undefined, - opts: { relationship?: boolean; tableName?: string } + tableName: string, + opts: { aliases?: Record; relationship?: boolean } ): KnexQuery { + function getTableName(name: string) { + const alias = opts.aliases?.[name] + return alias || name + } function iterate( structure: { [key: string]: any }, fn: (key: string, value: any) => void @@ -139,10 +144,11 @@ class InternalBuilder { const updatedKey = dbCore.removeKeyNumbering(key) const isRelationshipField = updatedKey.includes(".") if (!opts.relationship && !isRelationshipField) { - fn(`${opts.tableName}.${updatedKey}`, value) + fn(`${getTableName(tableName)}.${updatedKey}`, value) } if (opts.relationship && isRelationshipField) { - fn(updatedKey, value) + const [filterTableName, property] = updatedKey.split(".") + fn(`${getTableName(filterTableName)}.${property}`, value) } } } @@ -345,17 +351,15 @@ class InternalBuilder { query: KnexQuery, fromTable: string, relationships: RelationshipsJson[] | undefined, - schema: string | undefined + schema: string | undefined, + aliases?: Record ): KnexQuery { if (!relationships) { return query } const tableSets: Record = {} - // add up all aliases - let aliases: Record = {} // aggregate into table sets (all the same to tables) for (let relationship of relationships) { - aliases = { ...aliases, ...relationship.aliases } const keyObj: { toTable: string; throughTable: string | undefined } = { toTable: relationship.tableName, throughTable: undefined, @@ -372,9 +376,9 @@ class InternalBuilder { } for (let [key, relationships] of Object.entries(tableSets)) { const { toTable, throughTable } = JSON.parse(key) - const toAlias = aliases[toTable] || toTable, - throughAlias = aliases[throughTable] || throughTable, - fromAlias = aliases[fromTable] || fromTable + const toAlias = aliases?.[toTable] || toTable, + throughAlias = aliases?.[throughTable] || throughTable, + fromAlias = aliases?.[fromTable] || fromTable let toTableWithSchema = this.tableNameWithSchema(toTable, { alias: toAlias, schema, @@ -423,22 +427,23 @@ class InternalBuilder { knexWithAlias( knex: Knex, - endpoint: { entityId: string; alias?: string; schema?: string } - ): { query: KnexQuery; aliased: string } { + endpoint: QueryJson["endpoint"], + aliases?: QueryJson["tableAliases"] + ): KnexQuery { const tableName = endpoint.entityId - const alias = endpoint.alias - const aliased = alias ? alias : tableName - const tableAliased = alias ? `${tableName} as ${alias}` : tableName + const tableAliased = aliases?.[tableName] + ? `${tableName} as ${aliases?.[tableName]}` + : tableName let query = knex(tableAliased) if (endpoint.schema) { query = query.withSchema(endpoint.schema) } - return { query, aliased } + return query } create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { const { endpoint, body } = json - let { query } = this.knexWithAlias(knex, endpoint) + let query = this.knexWithAlias(knex, endpoint) const parsedBody = parseBody(body) // make sure no null values in body for creation for (let [key, value] of Object.entries(parsedBody)) { @@ -457,7 +462,7 @@ class InternalBuilder { bulkCreate(knex: Knex, json: QueryJson): KnexQuery { const { endpoint, body } = json - let { query } = this.knexWithAlias(knex, endpoint) + let query = this.knexWithAlias(knex, endpoint) if (!Array.isArray(body)) { return query } @@ -466,8 +471,10 @@ class InternalBuilder { } read(knex: Knex, json: QueryJson, limit: number): KnexQuery { - let { endpoint, resource, filters, paginate, relationships } = json + let { endpoint, resource, filters, paginate, relationships, tableAliases } = + json + const tableName = endpoint.entityId // select all if not specified if (!resource) { resource = { fields: [] } @@ -493,19 +500,20 @@ class InternalBuilder { } // start building the query - let { query, aliased } = this.knexWithAlias(knex, endpoint) + let query = this.knexWithAlias(knex, endpoint, tableAliases) query = query.limit(foundLimit) if (foundOffset) { query = query.offset(foundOffset) } - query = this.addFilters(query, filters, { tableName: aliased }) + query = this.addFilters(query, filters, tableName, { + aliases: tableAliases, + }) // add sorting to pre-query query = this.addSorting(query, json) - // @ts-ignore - let preQuery: KnexQuery = knex({ - // @ts-ignore - [aliased]: query, - }).select(selectStatement) + const alias = tableAliases?.[tableName] || tableName + let preQuery = knex({ + [alias]: query, + } as any).select(selectStatement) as any // have to add after as well (this breaks MS-SQL) if (this.client !== SqlClient.MS_SQL) { preQuery = this.addSorting(preQuery, json) @@ -513,18 +521,24 @@ class InternalBuilder { // handle joins query = this.addRelationships( preQuery, - aliased, + tableName, relationships, - endpoint.schema + endpoint.schema, + tableAliases ) - return this.addFilters(query, filters, { relationship: true }) + return this.addFilters(query, filters, tableName, { + relationship: true, + aliases: tableAliases, + }) } update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { - const { endpoint, body, filters } = json - let { query, aliased } = this.knexWithAlias(knex, endpoint) + const { endpoint, body, filters, tableAliases } = json + let query = this.knexWithAlias(knex, endpoint, tableAliases) const parsedBody = parseBody(body) - query = this.addFilters(query, filters, { tableName: aliased }) + query = this.addFilters(query, filters, endpoint.entityId, { + aliases: tableAliases, + }) // mysql can't use returning if (opts.disableReturning) { return query.update(parsedBody) @@ -534,9 +548,11 @@ class InternalBuilder { } delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { - const { endpoint, filters } = json - let { query, aliased } = this.knexWithAlias(knex, endpoint) - query = this.addFilters(query, filters, { tableName: aliased }) + const { endpoint, filters, tableAliases } = json + let query = this.knexWithAlias(knex, endpoint, tableAliases) + query = this.addFilters(query, filters, endpoint.entityId, { + aliases: tableAliases, + }) // mysql can't use returning if (opts.disableReturning) { return query.delete() diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index bca0cf5422..0e7257242c 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -1,5 +1,7 @@ -const Sql = require("../base/sql").default -const { SqlClient } = require("../utils") +import { SqlClient } from "../utils" +import Sql from "../base/sql" +import { QueryJson } from "@budibase/types" +import { join } from "path" const TABLE_NAME = "test" @@ -17,7 +19,7 @@ function generateReadJson({ filters, sort, paginate, -}: any = {}) { +}: any = {}): QueryJson { return { endpoint: endpoint(table || TABLE_NAME, "READ"), resource: { @@ -30,7 +32,7 @@ function generateReadJson({ table: { name: table || TABLE_NAME, primary: ["id"], - }, + } as any, }, } } @@ -687,102 +689,12 @@ describe("SQL query builder", () => { describe("Captures of real examples", () => { const limit = 5000 + function getJson(name: string): QueryJson { + return require(join(__dirname, "sqlQueryJson", name)) as QueryJson + } + it("should handle filtering by relationship", () => { - const queryJson = { - endpoint: { - datasourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - entityId: "products", - operation: "READ", - alias: "a", - }, - resource: { - fields: [ - "a.productname", - "a.productid", - "b.executorid", - "b.taskname", - "b.taskid", - "b.completed", - "b.qaid", - ], - }, - filters: { - equal: { - "1:tasks.taskname": "assembling", - }, - onEmptyFilter: "all", - }, - sort: { - productname: { - direction: "ASCENDING", - }, - }, - paginate: { - limit: 100, - page: 1, - }, - relationships: [ - { - tableName: "tasks", - column: "tasks", - through: "products_tasks", - from: "productid", - to: "taskid", - fromPrimary: "productid", - toPrimary: "taskid", - aliases: { - products_tasks: "c", - tasks: "b", - products: "a", - }, - }, - ], - meta: { - table: { - type: "table", - _id: "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products", - primary: ["productid"], - name: "a", - schema: { - productname: { - type: "string", - externalType: "character varying", - autocolumn: false, - name: "productname", - constraints: { - presence: false, - }, - }, - productid: { - type: "number", - externalType: "integer", - autocolumn: true, - name: "productid", - constraints: { - presence: false, - }, - }, - tasks: { - tableId: - "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", - name: "tasks", - relationshipType: "many-to-many", - fieldName: "taskid", - through: - "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products_tasks", - throughFrom: "taskid", - throughTo: "productid", - type: "link", - main: true, - _id: "ca6862d9ba09146dd8a68e3b5b7055a09", - }, - }, - sourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - sourceType: "external", - primaryDisplay: "productname", - }, - }, - } + const queryJson = getJson(`filterByRelationship.json`) let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) expect(query).toEqual({ bindings: [100, "assembling", limit], diff --git a/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json b/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json new file mode 100644 index 0000000000..eb1025f382 --- /dev/null +++ b/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json @@ -0,0 +1,94 @@ +{ + "endpoint": { + "datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "entityId": "products", + "operation": "READ" + }, + "resource": { + "fields": [ + "a.productname", + "a.productid", + "b.executorid", + "b.taskname", + "b.taskid", + "b.completed", + "b.qaid" + ] + }, + "filters": { + "equal": { + "1:tasks.taskname": "assembling" + }, + "onEmptyFilter": "all" + }, + "sort": { + "productname": { + "direction": "ASCENDING" + } + }, + "paginate": { + "limit": 100, + "page": 1 + }, + "relationships": [ + { + "tableName": "tasks", + "column": "tasks", + "through": "products_tasks", + "from": "productid", + "to": "taskid", + "fromPrimary": "productid", + "toPrimary": "taskid" + } + ], + "tableAliases": { + "products_tasks": "c", + "tasks": "b", + "products": "a" + }, + "meta": { + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products", + "primary": [ + "productid" + ], + "name": "a", + "schema": { + "productname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "productname", + "constraints": { + "presence": false + } + }, + "productid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "productid", + "constraints": { + "presence": false + } + }, + "tasks": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "tasks", + "relationshipType": "many-to-many", + "fieldName": "taskid", + "through": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products_tasks", + "throughFrom": "taskid", + "throughTo": "productid", + "type": "link", + "main": true, + "_id": "ca6862d9ba09146dd8a68e3b5b7055a09" + } + }, + "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "sourceType": "external", + "primaryDisplay": "productname" + } + } +} \ No newline at end of file diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts index a4045c2558..67c344d845 100644 --- a/packages/types/src/sdk/search.ts +++ b/packages/types/src/sdk/search.ts @@ -67,7 +67,6 @@ export interface RelationshipsJson { fromPrimary?: string toPrimary?: string tableName: string - aliases?: Record column: string } @@ -75,7 +74,6 @@ export interface QueryJson { endpoint: { datasourceId: string entityId: string - alias?: string operation: Operation schema?: string } @@ -96,6 +94,7 @@ export interface QueryJson { idFilter?: SearchFilters } relationships?: RelationshipsJson[] + tableAliases?: Record } export interface SqlQuery { From c4f4a46d7002e3b4321bb6cd7c22b0a608d481bf Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 5 Feb 2024 12:45:19 +0000 Subject: [PATCH 13/76] Quick fix based on testing. --- .../server/src/api/controllers/row/alias.ts | 7 +++++- packages/server/src/integrations/base/sql.ts | 1 - .../server/src/integrations/tests/sql.spec.ts | 17 ------------- .../src/integrations/tests/sqlAlias.spec.ts | 25 +++++++++++++++++++ 4 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 packages/server/src/integrations/tests/sqlAlias.spec.ts diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index 589431cc1a..6533e51728 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -113,7 +113,12 @@ export default class AliasTables { } json.meta.tables = aliasedTables } - json.tableAliases = this.tableAliases + // invert and return + const invertedTableAliases: Record = {} + for (let [key, value] of Object.entries(this.tableAliases)) { + invertedTableAliases[value] = key + } + json.tableAliases = invertedTableAliases const response = await getDatasourceAndQuery(json) return this.reverse(response) } diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index c9be2e1ae6..cc2e1d94a8 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -499,7 +499,6 @@ class InternalBuilder { foundLimit = paginate.limit } // start building the query - let query = this.knexWithAlias(knex, endpoint, tableAliases) query = query.limit(foundLimit) if (foundOffset) { diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index 0e7257242c..cf22064cb7 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -685,20 +685,3 @@ describe("SQL query builder", () => { }) }) }) - -describe("Captures of real examples", () => { - const limit = 5000 - - function getJson(name: string): QueryJson { - return require(join(__dirname, "sqlQueryJson", name)) as QueryJson - } - - it("should handle filtering by relationship", () => { - const queryJson = getJson(`filterByRelationship.json`) - let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) - expect(query).toEqual({ - bindings: [100, "assembling", limit], - sql: `select "a"."productname" as "a.productname", "a"."productid" as "a.productid", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid" from (select * from "products" as "a" order by "a"."productname" asc limit $1) as "a" left join "products_tasks" as "c" on "a"."productid" = "c"."productid" left join "tasks" as "b" on "b"."taskid" = "c"."taskid" where "b"."taskname" = $2 order by "a"."productname" asc limit $3`, - }) - }) -}) diff --git a/packages/server/src/integrations/tests/sqlAlias.spec.ts b/packages/server/src/integrations/tests/sqlAlias.spec.ts new file mode 100644 index 0000000000..cfd82cfd01 --- /dev/null +++ b/packages/server/src/integrations/tests/sqlAlias.spec.ts @@ -0,0 +1,25 @@ +import { QueryJson } from "@budibase/types" +import { join } from "path" +import Sql from "../base/sql" +import { SqlClient } from "../utils" + +describe("Captures of real examples", () => { + const limit = 5000 + + function getJson(name: string): QueryJson { + return require(join(__dirname, "sqlQueryJson", name)) as QueryJson + } + + it("should handle basic retrieval", () => { + const queryJson = getJson("") + }) + + it("should handle filtering by relationship", () => { + const queryJson = getJson("filterByRelationship.json") + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: [100, "assembling", limit], + sql: `select "a"."productname" as "a.productname", "a"."productid" as "a.productid", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid" from (select * from "products" as "a" order by "a"."productname" asc limit $1) as "a" left join "products_tasks" as "c" on "a"."productid" = "c"."productid" left join "tasks" as "b" on "b"."taskid" = "c"."taskid" where "b"."taskname" = $2 order by "a"."productname" asc limit $3`, + }) + }) +}) From e8e7eea47a234241dd2c79196b7e101b183c56ca Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 5 Feb 2024 15:23:24 +0000 Subject: [PATCH 14/76] Adding some test cases for aliasing. --- .../src/integrations/tests/sqlAlias.spec.ts | 65 ++++++- .../basicFetchWithRelationships.json | 183 ++++++++++++++++++ .../sqlQueryJson/createWithRelationships.json | 173 +++++++++++++++++ .../tests/sqlQueryJson/deleteSimple.json | 75 +++++++ .../sqlQueryJson/updateRelationship.json | 181 +++++++++++++++++ .../tests/sqlQueryJson/updateSimple.json | 181 +++++++++++++++++ 6 files changed, 850 insertions(+), 8 deletions(-) create mode 100644 packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json create mode 100644 packages/server/src/integrations/tests/sqlQueryJson/createWithRelationships.json create mode 100644 packages/server/src/integrations/tests/sqlQueryJson/deleteSimple.json create mode 100644 packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json create mode 100644 packages/server/src/integrations/tests/sqlQueryJson/updateSimple.json diff --git a/packages/server/src/integrations/tests/sqlAlias.spec.ts b/packages/server/src/integrations/tests/sqlAlias.spec.ts index cfd82cfd01..c91d988849 100644 --- a/packages/server/src/integrations/tests/sqlAlias.spec.ts +++ b/packages/server/src/integrations/tests/sqlAlias.spec.ts @@ -10,16 +10,65 @@ describe("Captures of real examples", () => { return require(join(__dirname, "sqlQueryJson", name)) as QueryJson } - it("should handle basic retrieval", () => { - const queryJson = getJson("") + describe("create", () => { + it("should create a row with relationships", () => { + const queryJson = getJson("createWithRelationships.json") + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: ["A Street", 34, "London", "A", "B", "designer", 1990], + sql: `insert into "persons" ("address", "age", "city", "firstname", "lastname", "type", "year") values ($1, $2, $3, $4, $5, $6, $7) returning *`, + }) + }) }) - it("should handle filtering by relationship", () => { - const queryJson = getJson("filterByRelationship.json") - let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) - expect(query).toEqual({ - bindings: [100, "assembling", limit], - sql: `select "a"."productname" as "a.productname", "a"."productid" as "a.productid", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid" from (select * from "products" as "a" order by "a"."productname" asc limit $1) as "a" left join "products_tasks" as "c" on "a"."productid" = "c"."productid" left join "tasks" as "b" on "b"."taskid" = "c"."taskid" where "b"."taskname" = $2 order by "a"."productname" asc limit $3`, + describe("read", () => { + it("should handle basic retrieval with relationships", () => { + const queryJson = getJson("basicFetchWithRelationships.json") + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: [100, limit], + sql: `select "a"."year" as "a.year", "a"."firstname" as "a.firstname", "a"."personid" as "a.personid", "a"."address" as "a.address", "a"."age" as "a.age", "a"."type" as "a.type", "a"."city" as "a.city", "a"."lastname" as "a.lastname", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid" from (select * from "persons" as "a" order by "a"."firstname" asc limit $1) as "a" left join "tasks" as "b" on "a"."personid" = "b"."qaid" or "a"."personid" = "b"."executorid" order by "a"."firstname" asc limit $2`, + }) + }) + + it("should handle filtering by relationship", () => { + const queryJson = getJson("filterByRelationship.json") + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: [100, "assembling", limit], + sql: `select "a"."productname" as "a.productname", "a"."productid" as "a.productid", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid" from (select * from "products" as "a" order by "a"."productname" asc limit $1) as "a" left join "products_tasks" as "c" on "a"."productid" = "c"."productid" left join "tasks" as "b" on "b"."taskid" = "c"."taskid" where "b"."taskname" = $2 order by "a"."productname" asc limit $3`, + }) + }) + }) + + describe("update", () => { + it("should handle performing a simple update", () => { + const queryJson = getJson("updateSimple.json") + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: [1990, "C", "A Street", 34, "designer", "London", "B", 5], + sql: `update "persons" as "a" set "year" = $1, "firstname" = $2, "address" = $3, "age" = $4, "type" = $5, "city" = $6, "lastname" = $7 where "a"."personid" = $8 returning *`, + }) + }) + + it("should handle performing an update of relationships", () => { + const queryJson = getJson("updateRelationship.json") + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: [1990, "C", "A Street", 34, "designer", "London", "B", 5], + sql: `update "persons" as "a" set "year" = $1, "firstname" = $2, "address" = $3, "age" = $4, "type" = $5, "city" = $6, "lastname" = $7 where "a"."personid" = $8 returning *`, + }) + }) + }) + + describe("delete", () => { + it("should handle deleting with relationships", () => { + const queryJson = getJson("deleteSimple.json") + let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson) + expect(query).toEqual({ + bindings: ["ddd", ""], + sql: `delete from "compositetable" as "a" where "a"."keypartone" = $1 and "a"."keyparttwo" = $2 returning "a"."keyparttwo" as "a.keyparttwo", "a"."keypartone" as "a.keypartone", "a"."name" as "a.name"`, + }) }) }) }) diff --git a/packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json b/packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json new file mode 100644 index 0000000000..3445f5fe67 --- /dev/null +++ b/packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json @@ -0,0 +1,183 @@ +{ + "endpoint": { + "datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "entityId": "persons", + "operation": "READ" + }, + "resource": { + "fields": [ + "a.year", + "a.firstname", + "a.personid", + "a.address", + "a.age", + "a.type", + "a.city", + "a.lastname", + "b.executorid", + "b.taskname", + "b.taskid", + "b.completed", + "b.qaid", + "b.executorid", + "b.taskname", + "b.taskid", + "b.completed", + "b.qaid" + ] + }, + "filters": {}, + "sort": { + "firstname": { + "direction": "ASCENDING" + } + }, + "paginate": { + "limit": 100, + "page": 1 + }, + "relationships": [ + { + "tableName": "tasks", + "column": "QA", + "from": "personid", + "to": "qaid", + "aliases": { + "tasks": "b", + "persons": "a" + } + }, + { + "tableName": "tasks", + "column": "executor", + "from": "personid", + "to": "executorid", + "aliases": { + "tasks": "b", + "persons": "a" + } + } + ], + "extra": { + "idFilter": {} + }, + "meta": { + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": [ + "personid" + ], + "name": "a", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false + } + }, + "firstname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "firstname", + "constraints": { + "presence": false + } + }, + "personid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "personid", + "constraints": { + "presence": false + } + }, + "address": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "address", + "constraints": { + "presence": false + } + }, + "age": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "age", + "constraints": { + "presence": false + } + }, + "type": { + "type": "options", + "externalType": "USER-DEFINED", + "autocolumn": false, + "name": "type", + "constraints": { + "presence": false, + "inclusion": [ + "support", + "designer", + "programmer", + "qa" + ] + } + }, + "city": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "city", + "constraints": { + "presence": false + } + }, + "lastname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "lastname", + "constraints": { + "presence": false + } + }, + "QA": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "QA", + "relationshipType": "many-to-one", + "fieldName": "qaid", + "type": "link", + "main": true, + "_id": "ccb68481c80c34217a4540a2c6c27fe46", + "foreignKey": "personid" + }, + "executor": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "executor", + "relationshipType": "many-to-one", + "fieldName": "executorid", + "type": "link", + "main": true, + "_id": "c89530b9770d94bec851e062b5cff3001", + "foreignKey": "personid", + "tableName": "persons" + } + }, + "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "sourceType": "external", + "primaryDisplay": "firstname", + "views": {} + } + }, + "tableAliases": { + "persons": "a", + "tasks": "b" + } +} \ No newline at end of file diff --git a/packages/server/src/integrations/tests/sqlQueryJson/createWithRelationships.json b/packages/server/src/integrations/tests/sqlQueryJson/createWithRelationships.json new file mode 100644 index 0000000000..20331b949a --- /dev/null +++ b/packages/server/src/integrations/tests/sqlQueryJson/createWithRelationships.json @@ -0,0 +1,173 @@ +{ + "endpoint": { + "datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "entityId": "persons", + "operation": "CREATE" + }, + "resource": { + "fields": [ + "a.year", + "a.firstname", + "a.personid", + "a.address", + "a.age", + "a.type", + "a.city", + "a.lastname" + ] + }, + "filters": {}, + "relationships": [ + { + "tableName": "tasks", + "column": "QA", + "from": "personid", + "to": "qaid", + "aliases": { + "tasks": "b", + "persons": "a" + } + }, + { + "tableName": "tasks", + "column": "executor", + "from": "personid", + "to": "executorid", + "aliases": { + "tasks": "b", + "persons": "a" + } + } + ], + "body": { + "year": 1990, + "firstname": "A", + "address": "A Street", + "age": 34, + "type": "designer", + "city": "London", + "lastname": "B" + }, + "extra": { + "idFilter": {} + }, + "meta": { + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": [ + "personid" + ], + "name": "a", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false + } + }, + "firstname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "firstname", + "constraints": { + "presence": false + } + }, + "personid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "personid", + "constraints": { + "presence": false + } + }, + "address": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "address", + "constraints": { + "presence": false + } + }, + "age": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "age", + "constraints": { + "presence": false + } + }, + "type": { + "type": "options", + "externalType": "USER-DEFINED", + "autocolumn": false, + "name": "type", + "constraints": { + "presence": false, + "inclusion": [ + "support", + "designer", + "programmer", + "qa" + ] + } + }, + "city": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "city", + "constraints": { + "presence": false + } + }, + "lastname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "lastname", + "constraints": { + "presence": false + } + }, + "QA": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "QA", + "relationshipType": "many-to-one", + "fieldName": "qaid", + "type": "link", + "main": true, + "_id": "ccb68481c80c34217a4540a2c6c27fe46", + "foreignKey": "personid" + }, + "executor": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "executor", + "relationshipType": "many-to-one", + "fieldName": "executorid", + "type": "link", + "main": true, + "_id": "c89530b9770d94bec851e062b5cff3001", + "foreignKey": "personid", + "tableName": "persons" + } + }, + "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "sourceType": "external", + "primaryDisplay": "firstname", + "views": {} + } + }, + "tableAliases": { + "persons": "a", + "tasks": "b" + } +} \ No newline at end of file diff --git a/packages/server/src/integrations/tests/sqlQueryJson/deleteSimple.json b/packages/server/src/integrations/tests/sqlQueryJson/deleteSimple.json new file mode 100644 index 0000000000..2266b8c8be --- /dev/null +++ b/packages/server/src/integrations/tests/sqlQueryJson/deleteSimple.json @@ -0,0 +1,75 @@ +{ + "endpoint": { + "datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "entityId": "compositetable", + "operation": "DELETE" + }, + "resource": { + "fields": [ + "a.keyparttwo", + "a.keypartone", + "a.name" + ] + }, + "filters": { + "equal": { + "keypartone": "ddd", + "keyparttwo": "" + } + }, + "relationships": [], + "extra": { + "idFilter": { + "equal": { + "keypartone": "ddd", + "keyparttwo": "" + } + } + }, + "meta": { + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__compositetable", + "primary": [ + "keypartone", + "keyparttwo" + ], + "name": "a", + "schema": { + "keyparttwo": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "keyparttwo", + "constraints": { + "presence": true + } + }, + "keypartone": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "keypartone", + "constraints": { + "presence": true + } + }, + "name": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "name", + "constraints": { + "presence": false + } + } + }, + "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "sourceType": "external", + "primaryDisplay": "keypartone" + } + }, + "tableAliases": { + "compositetable": "a" + } +} \ No newline at end of file diff --git a/packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json b/packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json new file mode 100644 index 0000000000..01e795bd6c --- /dev/null +++ b/packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json @@ -0,0 +1,181 @@ +{ + "endpoint": { + "datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "entityId": "persons", + "operation": "UPDATE" + }, + "resource": { + "fields": [ + "a.year", + "a.firstname", + "a.personid", + "a.address", + "a.age", + "a.type", + "a.city", + "a.lastname" + ] + }, + "filters": { + "equal": { + "personid": 5 + } + }, + "relationships": [ + { + "tableName": "tasks", + "column": "QA", + "from": "personid", + "to": "qaid", + "aliases": { + "tasks": "b", + "persons": "a" + } + }, + { + "tableName": "tasks", + "column": "executor", + "from": "personid", + "to": "executorid", + "aliases": { + "tasks": "b", + "persons": "a" + } + } + ], + "body": { + "year": 1990, + "firstname": "C", + "address": "A Street", + "age": 34, + "type": "designer", + "city": "London", + "lastname": "B" + }, + "extra": { + "idFilter": { + "equal": { + "personid": 5 + } + } + }, + "meta": { + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": [ + "personid" + ], + "name": "a", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false + } + }, + "firstname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "firstname", + "constraints": { + "presence": false + } + }, + "personid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "personid", + "constraints": { + "presence": false + } + }, + "address": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "address", + "constraints": { + "presence": false + } + }, + "age": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "age", + "constraints": { + "presence": false + } + }, + "type": { + "type": "options", + "externalType": "USER-DEFINED", + "autocolumn": false, + "name": "type", + "constraints": { + "presence": false, + "inclusion": [ + "support", + "designer", + "programmer", + "qa" + ] + } + }, + "city": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "city", + "constraints": { + "presence": false + } + }, + "lastname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "lastname", + "constraints": { + "presence": false + } + }, + "QA": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "QA", + "relationshipType": "many-to-one", + "fieldName": "qaid", + "type": "link", + "main": true, + "_id": "ccb68481c80c34217a4540a2c6c27fe46", + "foreignKey": "personid" + }, + "executor": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "executor", + "relationshipType": "many-to-one", + "fieldName": "executorid", + "type": "link", + "main": true, + "_id": "c89530b9770d94bec851e062b5cff3001", + "foreignKey": "personid", + "tableName": "persons" + } + }, + "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "sourceType": "external", + "primaryDisplay": "firstname", + "views": {} + } + }, + "tableAliases": { + "persons": "a", + "tasks": "b" + } +} \ No newline at end of file diff --git a/packages/server/src/integrations/tests/sqlQueryJson/updateSimple.json b/packages/server/src/integrations/tests/sqlQueryJson/updateSimple.json new file mode 100644 index 0000000000..01e795bd6c --- /dev/null +++ b/packages/server/src/integrations/tests/sqlQueryJson/updateSimple.json @@ -0,0 +1,181 @@ +{ + "endpoint": { + "datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "entityId": "persons", + "operation": "UPDATE" + }, + "resource": { + "fields": [ + "a.year", + "a.firstname", + "a.personid", + "a.address", + "a.age", + "a.type", + "a.city", + "a.lastname" + ] + }, + "filters": { + "equal": { + "personid": 5 + } + }, + "relationships": [ + { + "tableName": "tasks", + "column": "QA", + "from": "personid", + "to": "qaid", + "aliases": { + "tasks": "b", + "persons": "a" + } + }, + { + "tableName": "tasks", + "column": "executor", + "from": "personid", + "to": "executorid", + "aliases": { + "tasks": "b", + "persons": "a" + } + } + ], + "body": { + "year": 1990, + "firstname": "C", + "address": "A Street", + "age": 34, + "type": "designer", + "city": "London", + "lastname": "B" + }, + "extra": { + "idFilter": { + "equal": { + "personid": 5 + } + } + }, + "meta": { + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": [ + "personid" + ], + "name": "a", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false + } + }, + "firstname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "firstname", + "constraints": { + "presence": false + } + }, + "personid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "personid", + "constraints": { + "presence": false + } + }, + "address": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "address", + "constraints": { + "presence": false + } + }, + "age": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "age", + "constraints": { + "presence": false + } + }, + "type": { + "type": "options", + "externalType": "USER-DEFINED", + "autocolumn": false, + "name": "type", + "constraints": { + "presence": false, + "inclusion": [ + "support", + "designer", + "programmer", + "qa" + ] + } + }, + "city": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "city", + "constraints": { + "presence": false + } + }, + "lastname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "lastname", + "constraints": { + "presence": false + } + }, + "QA": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "QA", + "relationshipType": "many-to-one", + "fieldName": "qaid", + "type": "link", + "main": true, + "_id": "ccb68481c80c34217a4540a2c6c27fe46", + "foreignKey": "personid" + }, + "executor": { + "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks", + "name": "executor", + "relationshipType": "many-to-one", + "fieldName": "executorid", + "type": "link", + "main": true, + "_id": "c89530b9770d94bec851e062b5cff3001", + "foreignKey": "personid", + "tableName": "persons" + } + }, + "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", + "sourceType": "external", + "primaryDisplay": "firstname", + "views": {} + } + }, + "tableAliases": { + "persons": "a", + "tasks": "b" + } +} \ No newline at end of file From 9a8c31a2a42bc616d096b2d76e0e015c3ac18983 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 5 Feb 2024 18:57:16 +0000 Subject: [PATCH 15/76] Handling deletion of rows that violate constraints, this has been an issue in Budibase for some time and causes some confusion, attempting to resolve this when deleting rows. --- .../api/controllers/row/ExternalRequest.ts | 91 ++++++++++++++++--- 1 file changed, 76 insertions(+), 15 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 2f3c1ad557..4f755845dc 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -7,6 +7,7 @@ import { FilterType, IncludeRelationship, ManyToManyRelationshipFieldMetadata, + ManyToOneRelationshipFieldMetadata, OneToManyRelationshipFieldMetadata, Operation, PaginationJson, @@ -102,6 +103,26 @@ function buildFilters( } } +function removeRelationships( + rowId: string, + table: Table, + isManyToMany: boolean, + colName?: string +) { + const tableId = table._id! + const filters = buildFilters(rowId, {}, table) + // safety check, if there are no filters on deletion bad things happen + if (Object.keys(filters).length !== 0) { + const op = isManyToMany ? Operation.DELETE : Operation.UPDATE + const body = colName && !isManyToMany ? { [colName]: null } : undefined + return getDatasourceAndQuery({ + endpoint: getEndpoint(tableId, op), + body, + filters, + }) + } +} + /** * This function checks the incoming parameters to make sure all the inputs are * valid based on on the table schema. The main thing this is looking for is when a @@ -305,6 +326,18 @@ export class ExternalRequest { } } + async getRow(table: Table, rowId: string): Promise { + const response = await getDatasourceAndQuery({ + endpoint: getEndpoint(table._id!, Operation.READ), + filters: buildFilters(rowId, {}, table), + }) + if (response.length > 0) { + return response[0] + } else { + throw new Error(`Cannot fetch row by ID "${rowId}"`) + } + } + inputProcessing(row: Row | undefined, table: Table) { if (!row) { return { row, manyRelationships: [] } @@ -572,7 +605,9 @@ export class ExternalRequest { * information. */ async lookupRelations(tableId: string, row: Row) { - const related: { [key: string]: any } = {} + const related: { + [key: string]: { rows: Row[]; isMany: boolean; tableId: string } + } = {} const { tableName } = breakExternalTableId(tableId) if (!tableName) { return related @@ -591,7 +626,7 @@ export class ExternalRequest { continue } const isMany = field.relationshipType === RelationshipType.MANY_TO_MANY - const tableId = isMany ? field.through : field.tableId + const tableId = isMany ? field.through! : field.tableId! const { tableName: relatedTableName } = breakExternalTableId(tableId) // @ts-ignore const linkPrimaryKey = this.tables[relatedTableName].primary[0] @@ -610,7 +645,7 @@ export class ExternalRequest { }, }) // this is the response from knex if no rows found - const rows = !response[0].read ? response : [] + const rows: Row[] = !response[0].read ? response : [] const storeTo = isMany ? field.throughFrom || linkPrimaryKey : fieldName related[storeTo] = { rows, isMany, tableId } } @@ -698,24 +733,46 @@ export class ExternalRequest { continue } for (let row of rows) { - const filters = buildFilters(generateIdForRow(row, table), {}, table) - // safety check, if there are no filters on deletion bad things happen - if (Object.keys(filters).length !== 0) { - const op = isMany ? Operation.DELETE : Operation.UPDATE - const body = isMany ? undefined : { [colName]: null } - promises.push( - getDatasourceAndQuery({ - endpoint: getEndpoint(tableId, op), - body, - filters, - }) - ) + const promise = removeRelationships( + generateIdForRow(row, table), + table, + isMany, + colName + ) + if (promise) { + promises.push(promise) } } } await Promise.all(promises) } + async removeRelationshipsToRow(table: Table, rowId: string) { + const row = await this.getRow(table, rowId) + const related = await this.lookupRelations(table._id!, row) + for (let column of Object.values(table.schema)) { + if ( + column.type !== FieldType.LINK || + column.relationshipType === RelationshipType.ONE_TO_MANY + ) { + continue + } + const relationshipColumn = column as ManyToOneRelationshipFieldMetadata + const { rows, isMany, tableId } = related[relationshipColumn.fieldName] + const table = this.getTable(tableId)! + await Promise.all( + rows.map(row => + removeRelationships( + generateIdForRow(row, table), + table, + isMany, + relationshipColumn.fieldName + ) + ) + ) + } + } + /** * This function is a bit crazy, but the exact purpose of it is to protect against the scenario in which * you have column overlap in relationships, e.g. we join a few different tables and they all have the @@ -828,6 +885,10 @@ export class ExternalRequest { } const aliasing = new AliasTables(Object.keys(this.tables)) + // remove any relationships that could block deletion + if (operation === Operation.DELETE && id) { + await this.removeRelationshipsToRow(table, generateRowIdField(id)) + } const response = await aliasing.queryWithAliasing(json) // handle many-to-many relationships now if we know the ID (could be auto increment) if (operation !== Operation.READ) { From b2c4f04aa60f3e19e70eb9eaf63b870f5843d961 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 21 Feb 2024 17:52:58 +0000 Subject: [PATCH 16/76] Typing and config.api'ing application.spec.ts, WIP --- .../server/src/api/controllers/application.ts | 25 +++--- .../src/api/routes/tests/application.spec.ts | 79 +++++++------------ .../src/tests/utilities/api/application.ts | 41 +++++++++- packages/types/src/documents/app/app.ts | 12 +++ packages/worker/scripts/test.sh | 8 +- qa-core/src/internal-api/api/apis/AppAPI.ts | 3 +- .../src/internal-api/fixtures/applications.ts | 2 +- .../internal-api/tests/tables/tables.spec.ts | 11 --- .../src/shared/BudibaseTestConfiguration.ts | 4 +- qa-core/src/types/app.ts | 10 --- qa-core/src/types/index.ts | 1 - 11 files changed, 105 insertions(+), 91 deletions(-) delete mode 100644 qa-core/src/types/app.ts diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 33582cf656..2d8b4b8686 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -47,6 +47,7 @@ import { PlanType, Screen, UserCtx, + CreateAppRequest, } from "@budibase/types" import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts" import sdk from "../../sdk" @@ -116,8 +117,8 @@ function checkAppName( } interface AppTemplate { - templateString: string - useTemplate: string + templateString?: string + useTemplate?: string file?: { type: string path: string @@ -231,17 +232,21 @@ export async function fetchAppPackage(ctx: UserCtx) { } } -async function performAppCreate(ctx: UserCtx) { +async function performAppCreate(ctx: UserCtx) { const apps = (await dbCore.getAllApps({ dev: true })) as App[] - const name = ctx.request.body.name, - possibleUrl = ctx.request.body.url, - encryptionPassword = ctx.request.body.encryptionPassword + const { + name, + url, + encryptionPassword, + useTemplate, + templateKey, + templateString, + } = ctx.request.body checkAppName(ctx, apps, name) - const url = sdk.applications.getAppUrl({ name, url: possibleUrl }) - checkAppUrl(ctx, apps, url) + const appUrl = sdk.applications.getAppUrl({ name, url }) + checkAppUrl(ctx, apps, appUrl) - const { useTemplate, templateKey, templateString } = ctx.request.body const instanceConfig: AppTemplate = { useTemplate, key: templateKey, @@ -268,7 +273,7 @@ async function performAppCreate(ctx: UserCtx) { version: envCore.VERSION, componentLibraries: ["@budibase/standard-components"], name: name, - url: url, + url: appUrl, template: templateKey, instance, tenantId: tenancy.getTenantId(), diff --git a/packages/server/src/api/routes/tests/application.spec.ts b/packages/server/src/api/routes/tests/application.spec.ts index fa5cb0a983..7340166e67 100644 --- a/packages/server/src/api/routes/tests/application.spec.ts +++ b/packages/server/src/api/routes/tests/application.spec.ts @@ -35,41 +35,30 @@ describe("/applications", () => { describe("create", () => { it("creates empty app", async () => { - const res = await request - .post("/api/applications") - .field("name", utils.newid()) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body._id).toBeDefined() + const app = await config.api.application.create({ name: utils.newid() }) + expect(app._id).toBeDefined() expect(events.app.created).toBeCalledTimes(1) }) it("creates app from template", async () => { - const res = await request - .post("/api/applications") - .field("name", utils.newid()) - .field("useTemplate", "true") - .field("templateKey", "test") - .field("templateString", "{}") // override the file download - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body._id).toBeDefined() + const app = await config.api.application.create({ + name: utils.newid(), + useTemplate: "true", + templateKey: "test", + templateString: "{}", + }) + expect(app._id).toBeDefined() expect(events.app.created).toBeCalledTimes(1) expect(events.app.templateImported).toBeCalledTimes(1) }) it("creates app from file", async () => { - const res = await request - .post("/api/applications") - .field("name", utils.newid()) - .field("useTemplate", "true") - .set(config.defaultHeaders()) - .attach("templateFile", "src/api/routes/tests/data/export.txt") - .expect("Content-Type", /json/) - .expect(200) - expect(res.body._id).toBeDefined() + const app = await config.api.application.create({ + name: utils.newid(), + useTemplate: "true", + templateFile: "src/api/routes/tests/data/export.txt", + }) + expect(app._id).toBeDefined() expect(events.app.created).toBeCalledTimes(1) expect(events.app.fileImported).toBeCalledTimes(1) }) @@ -84,24 +73,21 @@ describe("/applications", () => { }) it("migrates navigation settings from old apps", async () => { - const res = await request - .post("/api/applications") - .field("name", "Old App") - .field("useTemplate", "true") - .set(config.defaultHeaders()) - .attach("templateFile", "src/api/routes/tests/data/old-app.txt") - .expect("Content-Type", /json/) - .expect(200) - expect(res.body._id).toBeDefined() - expect(res.body.navigation).toBeDefined() - expect(res.body.navigation.hideLogo).toBe(true) - expect(res.body.navigation.title).toBe("Custom Title") - expect(res.body.navigation.hideLogo).toBe(true) - expect(res.body.navigation.navigation).toBe("Left") - expect(res.body.navigation.navBackground).toBe( + const app = await config.api.application.create({ + name: "Old App", + useTemplate: "true", + templateFile: "src/api/routes/tests/data/old-app.txt", + }) + expect(app._id).toBeDefined() + expect(app.navigation).toBeDefined() + expect(app.navigation!.hideLogo).toBe(true) + expect(app.navigation!.title).toBe("Custom Title") + expect(app.navigation!.hideLogo).toBe(true) + expect(app.navigation!.navigation).toBe("Left") + expect(app.navigation!.navBackground).toBe( "var(--spectrum-global-color-blue-600)" ) - expect(res.body.navigation.navTextColor).toBe( + expect(app.navigation!.navTextColor).toBe( "var(--spectrum-global-color-gray-50)" ) expect(events.app.created).toBeCalledTimes(1) @@ -118,15 +104,10 @@ describe("/applications", () => { it("lists all applications", async () => { await config.createApp("app1") await config.createApp("app2") - - const res = await request - .get(`/api/applications?status=${AppStatus.DEV}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const apps = await config.api.application.fetch({ status: AppStatus.DEV }) // two created apps + the inited app - expect(res.body.length).toBe(3) + expect(apps.length).toBe(3) }) }) diff --git a/packages/server/src/tests/utilities/api/application.ts b/packages/server/src/tests/utilities/api/application.ts index 9c784bade1..7cc88d9eea 100644 --- a/packages/server/src/tests/utilities/api/application.ts +++ b/packages/server/src/tests/utilities/api/application.ts @@ -1,13 +1,38 @@ import { Response } from "supertest" -import { App } from "@budibase/types" +import { App, type CreateAppRequest } from "@budibase/types" import TestConfiguration from "../TestConfiguration" import { TestAPI } from "./base" +import { AppStatus } from "../../../db/utils" +import { dbObjectAsPojo } from "oracledb" export class ApplicationAPI extends TestAPI { constructor(config: TestConfiguration) { super(config) } + create = async (app: CreateAppRequest): Promise => { + const request = this.request + .post("/api/applications") + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + + for (const key of Object.keys(app)) { + request.field(key, (app as any)[key]) + } + + if (app.templateFile) { + request.attach("templateFile", app.templateFile) + } + + const result = await request + + if (result.statusCode !== 200) { + fail(JSON.stringify(result.body)) + } + + return result.body as App + } + getRaw = async (appId: string): Promise => { const result = await this.request .get(`/api/applications/${appId}/appPackage`) @@ -21,4 +46,18 @@ export class ApplicationAPI extends TestAPI { const result = await this.getRaw(appId) return result.body.application as App } + + fetch = async ({ status }: { status?: AppStatus } = {}): Promise => { + let query = [] + if (status) { + query.push(`status=${status}`) + } + + const result = await this.request + .get(`/api/applications${query.length ? `?${query.join("&")}` : ""}`) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + return result.body as App[] + } } diff --git a/packages/types/src/documents/app/app.ts b/packages/types/src/documents/app/app.ts index 08aafc6527..8571895fcc 100644 --- a/packages/types/src/documents/app/app.ts +++ b/packages/types/src/documents/app/app.ts @@ -73,3 +73,15 @@ export interface AppFeatures { export interface AutomationSettings { chainAutomations?: boolean } + +export interface CreateAppRequest { + name: string + url?: string + useTemplate?: string + templateName?: string + templateKey?: string + templateFile?: string + includeSampleData?: boolean + encryptionPassword?: string + templateString?: string +} diff --git a/packages/worker/scripts/test.sh b/packages/worker/scripts/test.sh index eba95c4916..17b3ee17f4 100644 --- a/packages/worker/scripts/test.sh +++ b/packages/worker/scripts/test.sh @@ -4,10 +4,10 @@ set -e if [[ -n $CI ]] then # Running in ci, where resources are limited - echo "jest --coverage --maxWorkers=2 --forceExit --bail" - jest --coverage --maxWorkers=2 --forceExit --bail + echo "jest --coverage --maxWorkers=2 --forceExit --bail $@" + jest --coverage --maxWorkers=2 --forceExit --bail $@ else # --maxWorkers performs better in development - echo "jest --coverage --maxWorkers=2 --forceExit" - jest --coverage --maxWorkers=2 --forceExit + echo "jest --coverage --maxWorkers=2 --forceExit $@" + jest --coverage --maxWorkers=2 --forceExit $@ fi \ No newline at end of file diff --git a/qa-core/src/internal-api/api/apis/AppAPI.ts b/qa-core/src/internal-api/api/apis/AppAPI.ts index a9f9a6a841..8b291a628e 100644 --- a/qa-core/src/internal-api/api/apis/AppAPI.ts +++ b/qa-core/src/internal-api/api/apis/AppAPI.ts @@ -1,11 +1,10 @@ -import { App } from "@budibase/types" +import { App, CreateAppRequest } from "@budibase/types" import { Response } from "node-fetch" import { RouteConfig, AppPackageResponse, DeployConfig, MessageResponse, - CreateAppRequest, } from "../../../types" import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" import BaseAPI from "./BaseAPI" diff --git a/qa-core/src/internal-api/fixtures/applications.ts b/qa-core/src/internal-api/fixtures/applications.ts index 01dd18fc6a..59f73ba863 100644 --- a/qa-core/src/internal-api/fixtures/applications.ts +++ b/qa-core/src/internal-api/fixtures/applications.ts @@ -1,5 +1,5 @@ import { generator } from "../../shared" -import { CreateAppRequest } from "../../types" +import { CreateAppRequest } from "@budibase/types" function uniqueWord() { return generator.word() + generator.hash() diff --git a/qa-core/src/internal-api/tests/tables/tables.spec.ts b/qa-core/src/internal-api/tests/tables/tables.spec.ts index 09d8f68e86..a38b8e6059 100644 --- a/qa-core/src/internal-api/tests/tables/tables.spec.ts +++ b/qa-core/src/internal-api/tests/tables/tables.spec.ts @@ -13,17 +13,6 @@ describe("Internal API - Table Operations", () => { await config.afterAll() }) - async function createAppFromTemplate() { - return config.api.apps.create({ - name: generator.word(), - url: `/${generator.word()}`, - useTemplate: "true", - templateName: "Near Miss Register", - templateKey: "app/near-miss-register", - templateFile: undefined, - }) - } - it("Create and delete table, columns and rows", async () => { // create the app await config.createApp(fixtures.apps.appFromTemplate()) diff --git a/qa-core/src/shared/BudibaseTestConfiguration.ts b/qa-core/src/shared/BudibaseTestConfiguration.ts index 18b7c89ec8..9a12f3e65d 100644 --- a/qa-core/src/shared/BudibaseTestConfiguration.ts +++ b/qa-core/src/shared/BudibaseTestConfiguration.ts @@ -1,8 +1,8 @@ import { BudibaseInternalAPI } from "../internal-api" import { AccountInternalAPI } from "../account-api" -import { APIRequestOpts, CreateAppRequest, State } from "../types" +import { APIRequestOpts, State } from "../types" import * as fixtures from "../internal-api/fixtures" -import { CreateAccountRequest } from "@budibase/types" +import { CreateAccountRequest, CreateAppRequest } from "@budibase/types" export default class BudibaseTestConfiguration { // apis diff --git a/qa-core/src/types/app.ts b/qa-core/src/types/app.ts deleted file mode 100644 index 7159112024..0000000000 --- a/qa-core/src/types/app.ts +++ /dev/null @@ -1,10 +0,0 @@ -// TODO: Integrate with budibase -export interface CreateAppRequest { - name: string - url: string - useTemplate?: string - templateName?: string - templateKey?: string - templateFile?: string - includeSampleData?: boolean -} diff --git a/qa-core/src/types/index.ts b/qa-core/src/types/index.ts index 9bde46c66e..a44df4ef3c 100644 --- a/qa-core/src/types/index.ts +++ b/qa-core/src/types/index.ts @@ -1,6 +1,5 @@ export * from "./api" export * from "./apiKeyResponse" -export * from "./app" export * from "./appPackage" export * from "./deploy" export * from "./newAccount" From 9bafb66616624edbcb142a3ad40b01b75f142fe3 Mon Sep 17 00:00:00 2001 From: jvcalderon Date: Fri, 23 Feb 2024 16:25:04 +0100 Subject: [PATCH 17/76] Update account portal submodule --- packages/account-portal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account-portal b/packages/account-portal index 97329c0318..c50e137a93 160000 --- a/packages/account-portal +++ b/packages/account-portal @@ -1 +1 @@ -Subproject commit 97329c0318ef0f4bbbd2b9ce30d6976bc6505272 +Subproject commit c50e137a9369801997ff6a1da25fdd96b4a44456 From 55410dcfd46ba32b96fa8b23b7154f5986167ac4 Mon Sep 17 00:00:00 2001 From: jvcalderon Date: Fri, 23 Feb 2024 16:25:37 +0100 Subject: [PATCH 18/76] Update pro submodule --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 60e47a8249..183b35d3ac 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 60e47a8249fd6291a6bc20fe3fe6776b11938fa1 +Subproject commit 183b35d3acd42433dcb2d32bcd89a36abe13afec From 1ef5e54c29bad501558667ceadb24e247c8f2d52 Mon Sep 17 00:00:00 2001 From: jvcalderon Date: Fri, 23 Feb 2024 16:26:23 +0100 Subject: [PATCH 19/76] Add BPM_EVENTS to Redis DB list --- packages/backend-core/src/redis/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend-core/src/redis/utils.ts b/packages/backend-core/src/redis/utils.ts index 4d8b1bb9a4..7b93458b52 100644 --- a/packages/backend-core/src/redis/utils.ts +++ b/packages/backend-core/src/redis/utils.ts @@ -29,6 +29,7 @@ export enum Databases { WRITE_THROUGH = "writeThrough", LOCKS = "locks", SOCKET_IO = "socket_io", + BPM_EVENTS = "bpmEvents", } /** From 07b6947d03e3532307de5882febe02571d85f877 Mon Sep 17 00:00:00 2001 From: jvcalderon Date: Fri, 23 Feb 2024 16:48:40 +0100 Subject: [PATCH 20/76] Update account portal submodule --- packages/account-portal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account-portal b/packages/account-portal index c50e137a93..ab324e35d8 160000 --- a/packages/account-portal +++ b/packages/account-portal @@ -1 +1 @@ -Subproject commit c50e137a9369801997ff6a1da25fdd96b4a44456 +Subproject commit ab324e35d855012bd0f49caa53c6dd765223c6fa From 5f76f143bf1d8a561821317b3145256ac0a51fd3 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 23 Feb 2024 17:31:45 +0000 Subject: [PATCH 21/76] Adding the ability to disable SQL aliasing if necessary. --- .../src/api/controllers/row/ExternalRequest.ts | 13 +++++++++++-- packages/server/src/environment.ts | 6 ++++-- packages/server/src/integrations/base/sql.ts | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 4f755845dc..0070e0bf24 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -35,6 +35,7 @@ import { processDates, processFormulas } from "../../../utilities/rowProcessor" import { db as dbCore } from "@budibase/backend-core" import AliasTables from "./alias" import sdk from "../../../sdk" +import env from "../../../environment" export interface ManyRelationship { tableId?: string @@ -884,12 +885,20 @@ export class ExternalRequest { }, } - const aliasing = new AliasTables(Object.keys(this.tables)) // remove any relationships that could block deletion if (operation === Operation.DELETE && id) { await this.removeRelationshipsToRow(table, generateRowIdField(id)) } - const response = await aliasing.queryWithAliasing(json) + + // aliasing can be disabled fully if desired + let response + if (!env.SQL_ALIASING_DISABLE) { + const aliasing = new AliasTables(Object.keys(this.tables)) + response = await aliasing.queryWithAliasing(json) + } else { + response = await getDatasourceAndQuery(json) + } + // handle many-to-many relationships now if we know the ID (could be auto increment) if (operation !== Operation.READ) { await this.handleManyRelationships( diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index 1d07eff1ce..a7c6df29ea 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -76,13 +76,16 @@ const environment = { DEFAULTS.AUTOMATION_THREAD_TIMEOUT > QUERY_THREAD_TIMEOUT ? DEFAULTS.AUTOMATION_THREAD_TIMEOUT : QUERY_THREAD_TIMEOUT, - SQL_MAX_ROWS: process.env.SQL_MAX_ROWS, BB_ADMIN_USER_EMAIL: process.env.BB_ADMIN_USER_EMAIL, BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD, PLUGINS_DIR: process.env.PLUGINS_DIR || DEFAULTS.PLUGINS_DIR, OPENAI_API_KEY: process.env.OPENAI_API_KEY, MAX_IMPORT_SIZE_MB: process.env.MAX_IMPORT_SIZE_MB, SESSION_EXPIRY_SECONDS: process.env.SESSION_EXPIRY_SECONDS, + // SQL + SQL_MAX_ROWS: process.env.SQL_MAX_ROWS, + SQL_LOGGING_ENABLE: process.env.SQL_LOGGING_ENABLE, + SQL_ALIASING_DISABLE: process.env.SQL_ALIASING_DISABLE, // flags ALLOW_DEV_AUTOMATIONS: process.env.ALLOW_DEV_AUTOMATIONS, DISABLE_THREADING: process.env.DISABLE_THREADING, @@ -90,7 +93,6 @@ const environment = { DISABLE_RATE_LIMITING: process.env.DISABLE_RATE_LIMITING, MULTI_TENANCY: process.env.MULTI_TENANCY, ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS, - ENABLE_SQL_LOGGING: process.env.ENABLE_SQL_LOGGING, SELF_HOSTED: process.env.SELF_HOSTED, HTTP_MB_LIMIT: process.env.HTTP_MB_LIMIT, FORKED_PROCESS_NAME: diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index cc2e1d94a8..172a10ea7f 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -688,7 +688,7 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { } log(query: string, values?: any[]) { - if (!environment.ENABLE_SQL_LOGGING) { + if (!environment.SQL_LOGGING_ENABLE) { return } const sqlClient = this.getSqlClient() From c1f4cb685c8972ffe2c66bbe70e256f246b741f7 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Mon, 26 Feb 2024 09:07:47 +0000 Subject: [PATCH 22/76] update sdk packages (#13120) --- packages/sdk/package.json | 9 +++++---- yarn.lock | 15 +-------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 0fc14b03c4..ed625e10fa 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -11,9 +11,10 @@ "build:sdk": "yarn run generate && rollup -c" }, "devDependencies": { - "@rollup/plugin-commonjs": "^18.0.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "rollup": "^2.44.0", - "rollup-plugin-terser": "^7.0.2" + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "rollup": "^4.9.6", + "rollup-plugin-terser": "^7.0.2", + "rollup-plugin-polyfill-node": "^0.13.0" } } diff --git a/yarn.lock b/yarn.lock index 21d3c5a76b..2c367e469b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3902,19 +3902,6 @@ magic-string "^0.25.7" resolve "^1.17.0" -"@rollup/plugin-commonjs@^18.0.0": - version "18.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-18.1.0.tgz#5a760d757af168a50727c0ae080251fbfcc5eb02" - integrity sha512-h3e6T9rUxVMAQswpDIobfUHn/doMzM9sgkMrsMWCFLmB84PSoC8mV8tOloAJjSRwdqhXBqstlX2BwBpHJvbhxg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - commondir "^1.0.1" - estree-walker "^2.0.1" - glob "^7.1.6" - is-reference "^1.2.1" - magic-string "^0.25.7" - resolve "^1.17.0" - "@rollup/plugin-commonjs@^25.0.7": version "25.0.7" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz#145cec7589ad952171aeb6a585bbeabd0fd3b4cf" @@ -19257,7 +19244,7 @@ rollup@2.45.2: optionalDependencies: fsevents "~2.3.1" -rollup@^2.36.2, rollup@^2.44.0, rollup@^2.45.2: +rollup@^2.36.2, rollup@^2.45.2: version "2.79.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== From af7b6a46a9e4d4834ededef6d8b564ded32253bf Mon Sep 17 00:00:00 2001 From: Conor Webb <126772285+ConorWebb96@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:45:47 +0000 Subject: [PATCH 23/76] Help popout email support license validation check (#13133) * Added helper function to check user plan type. * Updated help menu email support license check. * Removed stray output check * Updated function name as per feedback. * Reworked code to use the licensing store over the auth store. * Removed unnecessary variable declaration and return instead. * Updated function name to maintain consistency. --- .../src/components/common/HelpMenu.svelte | 17 ++++++++++------- packages/builder/src/helpers/planTitle.js | 4 ++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/components/common/HelpMenu.svelte b/packages/builder/src/components/common/HelpMenu.svelte index f6e2f42c98..baff9a5a27 100644 --- a/packages/builder/src/components/common/HelpMenu.svelte +++ b/packages/builder/src/components/common/HelpMenu.svelte @@ -1,11 +1,11 @@ @@ -67,13 +95,29 @@ options={componentOptions} on:change={() => (parameters.columns = [])} /> + - { + const columns = e.detail + parameters.customHeaders = columns.reduce((headerMap, column) => { + return { + [column.name]: column.displayName, + ...headerMap, + } + }, {}) + }} /> @@ -97,8 +141,8 @@ .params { display: grid; column-gap: var(--spacing-xs); - row-gap: var(--spacing-s); - grid-template-columns: 90px 1fr; + row-gap: var(--spacing-m); + grid-template-columns: 90px 1fr 90px; align-items: center; } diff --git a/packages/builder/src/components/design/settings/controls/ColumnEditor/ColumnEditor.svelte b/packages/builder/src/components/design/settings/controls/ColumnEditor/ColumnEditor.svelte index 2b9fa573c2..742ab785a1 100644 --- a/packages/builder/src/components/design/settings/controls/ColumnEditor/ColumnEditor.svelte +++ b/packages/builder/src/components/design/settings/controls/ColumnEditor/ColumnEditor.svelte @@ -29,6 +29,12 @@ allowLinks: true, }) + $: { + value = (value || []).filter( + column => (schema || {})[column.name || column] !== undefined + ) + } + const getText = value => { if (!value?.length) { return "All columns" diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index b2068ad152..68478b76ac 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -341,7 +341,11 @@ const exportDataHandler = async action => { tableId: selection.tableId, rows: selection.selectedRows, format: action.parameters.type, - columns: action.parameters.columns, + columns: action.parameters.columns?.map( + column => column.name || column + ), + delimiter: action.parameters.delimiter, + customHeaders: action.parameters.customHeaders, }) download( new Blob([data], { type: "text/plain" }), diff --git a/packages/frontend-core/src/api/rows.js b/packages/frontend-core/src/api/rows.js index 79f837e864..0a0d48da43 100644 --- a/packages/frontend-core/src/api/rows.js +++ b/packages/frontend-core/src/api/rows.js @@ -89,13 +89,24 @@ export const buildRowEndpoints = API => ({ * @param rows the array of rows to export * @param format the format to export (csv or json) * @param columns which columns to export (all if undefined) + * @param delimiter how values should be separated in a CSV (default is comma) */ - exportRows: async ({ tableId, rows, format, columns, search }) => { + exportRows: async ({ + tableId, + rows, + format, + columns, + search, + delimiter, + customHeaders, + }) => { return await API.post({ url: `/api/${tableId}/rows/exportRows?format=${format}`, body: { rows, columns, + delimiter, + customHeaders, ...search, }, parseResponse: async response => { diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 1ad8a2a695..ec56919d12 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -223,7 +223,8 @@ export const exportRows = async ( const format = ctx.query.format - const { rows, columns, query, sort, sortOrder } = ctx.request.body + const { rows, columns, query, sort, sortOrder, delimiter, customHeaders } = + ctx.request.body if (typeof format !== "string" || !exporters.isFormat(format)) { ctx.throw( 400, @@ -241,6 +242,8 @@ export const exportRows = async ( query, sort, sortOrder, + delimiter, + customHeaders, }) ctx.attachment(fileName) ctx.body = apiFileReturn(content) diff --git a/packages/server/src/api/controllers/view/exporters.ts b/packages/server/src/api/controllers/view/exporters.ts index d6caff6035..3b5f951dca 100644 --- a/packages/server/src/api/controllers/view/exporters.ts +++ b/packages/server/src/api/controllers/view/exporters.ts @@ -1,7 +1,19 @@ import { Row, TableSchema } from "@budibase/types" -export function csv(headers: string[], rows: Row[]) { - let csv = headers.map(key => `"${key}"`).join(",") +function getHeaders( + headers: string[], + customHeaders: { [key: string]: string } +) { + return headers.map(header => `"${customHeaders[header] || header}"`) +} + +export function csv( + headers: string[], + rows: Row[], + delimiter: string = ",", + customHeaders: { [key: string]: string } = {} +) { + let csv = getHeaders(headers, customHeaders).join(delimiter) for (let row of rows) { csv = `${csv}\n${headers @@ -15,7 +27,7 @@ export function csv(headers: string[], rows: Row[]) { : "" return val.trim() }) - .join(",")}` + .join(delimiter)}` } return csv } diff --git a/packages/server/src/sdk/app/rows/search.ts b/packages/server/src/sdk/app/rows/search.ts index 4b71179839..8b24f9bc5f 100644 --- a/packages/server/src/sdk/app/rows/search.ts +++ b/packages/server/src/sdk/app/rows/search.ts @@ -36,11 +36,13 @@ export async function search(options: SearchParams): Promise<{ export interface ExportRowsParams { tableId: string format: Format + delimiter?: string rowIds?: string[] columns?: string[] query?: SearchFilters sort?: string sortOrder?: SortOrder + customHeaders?: { [key: string]: string } } export interface ExportRowsResult { diff --git a/packages/server/src/sdk/app/rows/search/external.ts b/packages/server/src/sdk/app/rows/search/external.ts index 8465f997e3..e2d1a1b32c 100644 --- a/packages/server/src/sdk/app/rows/search/external.ts +++ b/packages/server/src/sdk/app/rows/search/external.ts @@ -101,7 +101,17 @@ export async function search(options: SearchParams) { export async function exportRows( options: ExportRowsParams ): Promise { - const { tableId, format, columns, rowIds, query, sort, sortOrder } = options + const { + tableId, + format, + columns, + rowIds, + query, + sort, + sortOrder, + delimiter, + customHeaders, + } = options const { datasourceId, tableName } = breakExternalTableId(tableId) let requestQuery: SearchFilters = {} @@ -153,12 +163,17 @@ export async function exportRows( rows = result.rows } - let exportRows = cleanExportRows(rows, schema, format, columns) + let exportRows = cleanExportRows(rows, schema, format, columns, customHeaders) let content: string switch (format) { case exporters.Format.CSV: - content = exporters.csv(headers ?? Object.keys(schema), exportRows) + content = exporters.csv( + headers ?? Object.keys(schema), + exportRows, + delimiter, + customHeaders + ) break case exporters.Format.JSON: content = exporters.json(exportRows) diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 22cb3985b7..2d3c32e02e 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -84,7 +84,17 @@ export async function search(options: SearchParams) { export async function exportRows( options: ExportRowsParams ): Promise { - const { tableId, format, rowIds, columns, query, sort, sortOrder } = options + const { + tableId, + format, + rowIds, + columns, + query, + sort, + sortOrder, + delimiter, + customHeaders, + } = options const db = context.getAppDB() const table = await sdk.tables.getTable(tableId) @@ -124,11 +134,16 @@ export async function exportRows( rows = result } - let exportRows = cleanExportRows(rows, schema, format, columns) + let exportRows = cleanExportRows(rows, schema, format, columns, customHeaders) if (format === Format.CSV) { return { fileName: "export.csv", - content: csv(headers ?? Object.keys(rows[0]), exportRows), + content: csv( + headers ?? Object.keys(rows[0]), + exportRows, + delimiter, + customHeaders + ), } } else if (format === Format.JSON) { return { diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index 14868a4013..0ff85f40ac 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -16,7 +16,8 @@ export function cleanExportRows( rows: any[], schema: TableSchema, format: string, - columns?: string[] + columns?: string[], + customHeaders: { [key: string]: string } = {} ) { let cleanRows = [...rows] @@ -44,11 +45,27 @@ export function cleanExportRows( } } } + } else if (format === Format.JSON) { + // Replace row keys with custom headers + for (let row of cleanRows) { + renameKeys(customHeaders, row) + } } return cleanRows } +function renameKeys(keysMap: { [key: string]: any }, row: any) { + for (const key in keysMap) { + Object.defineProperty( + row, + keysMap[key], + Object.getOwnPropertyDescriptor(row, key) || {} + ) + delete row[key] + } +} + function isForeignKey(key: string, table: Table) { const relationships = Object.values(table.schema).filter(isRelationshipColumn) return relationships.some( diff --git a/packages/types/src/api/web/app/rows.ts b/packages/types/src/api/web/app/rows.ts index dad3286754..14e28e4a01 100644 --- a/packages/types/src/api/web/app/rows.ts +++ b/packages/types/src/api/web/app/rows.ts @@ -37,6 +37,8 @@ export interface ExportRowsRequest { query?: SearchFilters sort?: string sortOrder?: SortOrder + delimiter?: string + customHeaders?: { [key: string]: string } } export type ExportRowsResponse = ReadStream From b1dd8999cb9ff7d542277fe02d33586064abfdf1 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 27 Feb 2024 09:33:44 +0000 Subject: [PATCH 36/76] Bump version to 2.20.11 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 54e106cd5a..623fbf6d43 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.20.10", + "version": "2.20.11", "npmClient": "yarn", "packages": [ "packages/*", From c11527d5399fb63f62ed7f45869c42d37efbb856 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 27 Feb 2024 09:56:56 +0000 Subject: [PATCH 37/76] Adding in char sequence. --- .../server/src/api/controllers/row/alias.ts | 38 ++++++++++++++----- .../src/integrations/tests/sqlAlias.spec.ts | 2 +- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index 747166a7ba..280d50de9b 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -8,33 +8,51 @@ import { import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils" import { cloneDeep } from "lodash" +class CharSequence { + static alphabet = "abcdefghijklmnopqrstuvwxyz" + counters: number[] + + constructor() { + this.counters = [0] + } + + get character() { + return this.counters.map(i => CharSequence.alphabet[i]).join("") + } + + next() { + for (let i = this.counters.length - 1; i >= 0; i--) { + if (this.counters[i] < CharSequence.alphabet.length - 1) { + this.counters[i]++ + return + } + this.counters[i] = 0 + } + this.counters.unshift(0) + } +} + export default class AliasTables { - character: string aliases: Record tableAliases: Record tableNames: string[] + charSeq: CharSequence constructor(tableNames: string[]) { this.tableNames = tableNames - this.character = "a" this.aliases = {} this.tableAliases = {} + this.charSeq = new CharSequence() } getAlias(tableName: string) { if (this.aliases[tableName]) { return this.aliases[tableName] } - const char = this.character + const char = this.charSeq.character + this.charSeq.next() this.aliases[tableName] = char this.tableAliases[char] = tableName - this.character = - char.substring(0, char.length - 1) + - String.fromCharCode(char.charCodeAt(char.length - 1) + 1) - // reached end of characters, extend number of characters used - if (this.character.charAt(this.character.length - 1) === "z") { - this.character = new Array(this.character.length + 1).fill("a").join("") - } return char } diff --git a/packages/server/src/integrations/tests/sqlAlias.spec.ts b/packages/server/src/integrations/tests/sqlAlias.spec.ts index c35c2b45b6..6e8bd0ea72 100644 --- a/packages/server/src/integrations/tests/sqlAlias.spec.ts +++ b/packages/server/src/integrations/tests/sqlAlias.spec.ts @@ -171,7 +171,7 @@ describe("Captures of real examples", () => { for (let table of tableNames) { alias = aliasing.getAlias(table) } - expect(alias).toEqual("aaay") + expect(alias).toEqual("cu") }) }) }) From c0bb03e9382ac16c14c0fd29537d443e8126dd94 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 27 Feb 2024 09:58:06 +0000 Subject: [PATCH 38/76] Adding length check back for get row. --- packages/server/src/api/controllers/row/ExternalRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index dceadb3cd4..165a1847b5 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -346,7 +346,7 @@ export class ExternalRequest { endpoint: getEndpoint(table._id!, Operation.READ), filters: buildFilters(rowId, {}, table), }) - if (Array.isArray(response)) { + if (Array.isArray(response) && response.length > 0) { return response[0] } else { throw new Error(`Cannot fetch row by ID "${rowId}"`) From 3d48a8f7f3d463ae735bc177af700c879e34e554 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:26:45 +0000 Subject: [PATCH 39/76] Don't encode twice (#13138) --- packages/builder/src/helpers/data/utils.js | 6 +++++- packages/builder/src/helpers/tests/dataUtils.test.js | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/helpers/data/utils.js b/packages/builder/src/helpers/data/utils.js index a29ce8db6d..a592b57a26 100644 --- a/packages/builder/src/helpers/data/utils.js +++ b/packages/builder/src/helpers/data/utils.js @@ -17,6 +17,10 @@ export function breakQueryString(qs) { return paramObj } +function isEncoded(str) { + return typeof str == "string" && decodeURIComponent(str) !== str +} + export function buildQueryString(obj) { let str = "" if (obj) { @@ -35,7 +39,7 @@ export function buildQueryString(obj) { value = value.replace(binding, marker) bindingMarkers[marker] = binding }) - let encoded = encodeURIComponent(value || "") + let encoded = isEncoded(value) ? value : encodeURIComponent(value || "") Object.entries(bindingMarkers).forEach(([marker, binding]) => { encoded = encoded.replace(marker, binding) }) diff --git a/packages/builder/src/helpers/tests/dataUtils.test.js b/packages/builder/src/helpers/tests/dataUtils.test.js index 8fc2d706d7..bd207ea339 100644 --- a/packages/builder/src/helpers/tests/dataUtils.test.js +++ b/packages/builder/src/helpers/tests/dataUtils.test.js @@ -39,4 +39,11 @@ describe("check query string utils", () => { expect(broken.key1).toBe(obj2.key1) expect(broken.key2).toBe(obj2.key2) }) + + it("should not encode a URL more than once when building the query string", () => { + const queryString = buildQueryString({ + values: "a%2Cb%2Cc", + }) + expect(queryString).toBe("values=a%2Cb%2Cc") + }) }) From 4c203ea35d57ce9248ae31786a58356e3d2719b4 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:49:11 +0000 Subject: [PATCH 40/76] Budi 6149 export data make csv delimiter configurable (#13140) * Add delimiter option * Add custom delimiter * external export delimiter * Custom headers for row export * External export rows custom headers * Support custom JSON export labels * Handle export table source switch * update account portal * Add space as delimiter * Refactor * update account portal * Update columns from ColumnEditor * Revert "Update columns from ColumnEditor" This reverts commit d23293cd8b5d007b13a8825bc80e161d60f691c0. * Revert "Revert "Update columns from ColumnEditor"" This reverts commit 0f16bddff7a745f7593e331ceedcec5511bbe4ba. --- .../controls/ButtonActionEditor/actions/ExportData.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte index 5955cc762d..096341783d 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte @@ -106,11 +106,12 @@ /> { const columns = e.detail + parameters.columns = columns parameters.customHeaders = columns.reduce((headerMap, column) => { return { [column.name]: column.displayName, From 2a8bb872adc87d01827eabe6de0535859c5fe6da Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 27 Feb 2024 12:49:37 +0000 Subject: [PATCH 41/76] Bump version to 2.20.12 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 623fbf6d43..e1a469adf1 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.20.11", + "version": "2.20.12", "npmClient": "yarn", "packages": [ "packages/*", From fac9f18bc2214f6f62249a372c88803ea19a4a7e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 27 Feb 2024 13:40:31 +0000 Subject: [PATCH 42/76] PR comments. --- .../api/controllers/row/ExternalRequest.ts | 31 ++++++++++++++----- .../server/src/api/controllers/row/alias.ts | 13 +++----- .../src/integrations/tests/sqlAlias.spec.ts | 4 +-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 165a1847b5..685af4e98e 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -640,14 +640,26 @@ export class ExternalRequest { ) { continue } - const isMany = field.relationshipType === RelationshipType.MANY_TO_MANY - const tableId = isMany ? field.through! : field.tableId! + let tableId: string | undefined, + lookupField: string | undefined, + fieldName: string | undefined + if (isManyToMany(field)) { + tableId = field.through + lookupField = primaryKey + fieldName = field.throughTo || primaryKey + } else if (isManyToOne(field)) { + tableId = field.tableId + lookupField = field.foreignKey + fieldName = field.fieldName + } + if (!tableId || !lookupField || !fieldName) { + throw new Error( + "Unable to lookup relationships - undefined column properties." + ) + } const { tableName: relatedTableName } = breakExternalTableId(tableId) // @ts-ignore const linkPrimaryKey = this.tables[relatedTableName].primary[0] - - const lookupField = isMany ? primaryKey : field.foreignKey - const fieldName = isMany ? field.throughTo || primaryKey : field.fieldName if (!lookupField || !row[lookupField]) { continue } @@ -660,9 +672,12 @@ export class ExternalRequest { }, }) // this is the response from knex if no rows found - const rows: Row[] = response?.[0].read ? [] : (response as Row[]) - const storeTo = isMany ? field.throughFrom || linkPrimaryKey : fieldName - related[storeTo] = { rows, isMany, tableId } + const rows: Row[] = + !Array.isArray(response) || response?.[0].read ? [] : response + const storeTo = isManyToMany(field) + ? field.throughFrom || linkPrimaryKey + : fieldName + related[storeTo] = { rows, isMany: isManyToMany(field), tableId } } return related } diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts index 280d50de9b..9d54bbff8e 100644 --- a/packages/server/src/api/controllers/row/alias.ts +++ b/packages/server/src/api/controllers/row/alias.ts @@ -16,19 +16,17 @@ class CharSequence { this.counters = [0] } - get character() { - return this.counters.map(i => CharSequence.alphabet[i]).join("") - } - - next() { + getCharacter(): string { + const char = this.counters.map(i => CharSequence.alphabet[i]).join("") for (let i = this.counters.length - 1; i >= 0; i--) { if (this.counters[i] < CharSequence.alphabet.length - 1) { this.counters[i]++ - return + return char } this.counters[i] = 0 } this.counters.unshift(0) + return char } } @@ -49,8 +47,7 @@ export default class AliasTables { if (this.aliases[tableName]) { return this.aliases[tableName] } - const char = this.charSeq.character - this.charSeq.next() + const char = this.charSeq.getCharacter() this.aliases[tableName] = char this.tableAliases[char] = tableName return char diff --git a/packages/server/src/integrations/tests/sqlAlias.spec.ts b/packages/server/src/integrations/tests/sqlAlias.spec.ts index 6e8bd0ea72..61dbc11840 100644 --- a/packages/server/src/integrations/tests/sqlAlias.spec.ts +++ b/packages/server/src/integrations/tests/sqlAlias.spec.ts @@ -164,14 +164,14 @@ describe("Captures of real examples", () => { it("should handle over 'z' max character alias", () => { const tableNames = [] for (let i = 0; i < 100; i++) { - tableNames.push(generator.word()) + tableNames.push(generator.guid()) } const aliasing = new AliasTables(tableNames) let alias: string = "" for (let table of tableNames) { alias = aliasing.getAlias(table) } - expect(alias).toEqual("cu") + expect(alias).toEqual("cv") }) }) }) From 9a9b74579529cd061735c371b73ec862ea1856cc Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 27 Feb 2024 15:29:35 +0000 Subject: [PATCH 43/76] App Preview Skeleton (#12898) * wip * wip * wip * wip * wip * wip * builder design skeleton * pre doc loading skeleton for portal preview * feature complete? * wip * linting * linting * linting * fix ts error? * ts types fix * linting * remove unnecessary build stuff * include skeleton in server app directly * linting * linting * fix builder preview aspect ratio for skeleton * remove dev tools skeleton * linting --- .../[screenId]/_components/AppPreview.svelte | 43 ++- .../builder/portal/apps/[appId]/index.svelte | 51 +++- .../client/src/components/ClientApp.svelte | 258 ++++++++++-------- .../client/src/components/FreeFooter.svelte | 1 + .../src/components/ClientAppSkeleton.svelte | 244 +++++++++++++++++ .../frontend-core/src/components/index.js | 1 + .../frontend-core/src/themes/midnight.css | 3 + packages/frontend-core/src/themes/nord.css | 3 + packages/server/package.json | 1 + .../src/api/controllers/static/index.ts | 79 +++++- .../static/templates/BudibaseApp.svelte | 7 + .../api/controllers/static/templates/app.hbs | 8 +- packages/server/src/api/routes/static.ts | 2 +- scripts/build.js | 14 +- 14 files changed, 563 insertions(+), 152 deletions(-) create mode 100644 packages/frontend-core/src/components/ClientAppSkeleton.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index fa126bbc99..4bd62c0049 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -12,17 +12,11 @@ hoverStore, } from "stores/builder" import ConfirmDialog from "components/common/ConfirmDialog.svelte" - import { - ProgressCircle, - Layout, - Heading, - Body, - Icon, - notifications, - } from "@budibase/bbui" + import { Layout, Heading, Body, Icon, notifications } from "@budibase/bbui" import ErrorSVG from "@budibase/frontend-core/assets/error.svg?raw" import { findComponent, findComponentPath } from "helpers/components" import { isActive, goto } from "@roxi/routify" + import { ClientAppSkeleton } from "@budibase/frontend-core" let iframe let layout @@ -240,8 +234,16 @@
{#if loading} -
- +
+
{:else if error}
@@ -258,8 +260,6 @@ bind:this={iframe} src="/app/preview" class:hidden={loading || error} - class:tablet={$previewStore.previewDevice === "tablet"} - class:mobile={$previewStore.previewDevice === "mobile"} />
diff --git a/packages/frontend-core/src/components/index.js b/packages/frontend-core/src/components/index.js index f724e1e4d9..f71420b12b 100644 --- a/packages/frontend-core/src/components/index.js +++ b/packages/frontend-core/src/components/index.js @@ -5,3 +5,4 @@ export { default as UserAvatar } from "./UserAvatar.svelte" export { default as UserAvatars } from "./UserAvatars.svelte" export { default as Updating } from "./Updating.svelte" export { Grid } from "./grid" +export { default as ClientAppSkeleton } from "./ClientAppSkeleton.svelte" diff --git a/packages/frontend-core/src/themes/midnight.css b/packages/frontend-core/src/themes/midnight.css index e311452262..cf6a4fbd13 100644 --- a/packages/frontend-core/src/themes/midnight.css +++ b/packages/frontend-core/src/themes/midnight.css @@ -17,5 +17,8 @@ --modal-background: var(--spectrum-global-color-gray-50); --drop-shadow: rgba(0, 0, 0, 0.25) !important; --spectrum-global-color-blue-100: rgba(35, 40, 50) !important; + + --spectrum-alias-background-color-secondary: var(--spectrum-global-color-gray-75); + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-100); } diff --git a/packages/frontend-core/src/themes/nord.css b/packages/frontend-core/src/themes/nord.css index d47dbe8aa8..bc142db0fd 100644 --- a/packages/frontend-core/src/themes/nord.css +++ b/packages/frontend-core/src/themes/nord.css @@ -50,4 +50,7 @@ --modal-background: var(--spectrum-global-color-gray-50); --drop-shadow: rgba(0, 0, 0, 0.15) !important; --spectrum-global-color-blue-100: rgb(56, 65, 84) !important; + + --spectrum-alias-background-color-secondary: var(--spectrum-global-color-gray-75); + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-100); } diff --git a/packages/server/package.json b/packages/server/package.json index 45980a4be6..4f1a9fb3cc 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -52,6 +52,7 @@ "@budibase/pro": "0.0.0", "@budibase/shared-core": "0.0.0", "@budibase/string-templates": "0.0.0", + "@budibase/frontend-core": "0.0.0", "@budibase/types": "0.0.0", "@bull-board/api": "5.10.2", "@bull-board/koa": "5.10.2", diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 5a3803e6d5..367934445a 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -1,7 +1,5 @@ import { InvalidFileExtensions } from "@budibase/shared-core" - import AppComponent from "./templates/BudibaseApp.svelte" - import { join } from "../../../utilities/centralPath" import * as uuid from "uuid" import { ObjectStoreBuckets } from "../../../constants" @@ -24,7 +22,13 @@ import AWS from "aws-sdk" import fs from "fs" import sdk from "../../../sdk" import * as pro from "@budibase/pro" -import { App, Ctx, ProcessAttachmentResponse } from "@budibase/types" +import { + UserCtx, + App, + Ctx, + ProcessAttachmentResponse, + Feature, +} from "@budibase/types" import { getAppMigrationVersion, getLatestMigrationId, @@ -32,6 +36,61 @@ import { import send from "koa-send" +const getThemeVariables = (theme: string) => { + if (theme === "spectrum--lightest") { + return ` + --spectrum-global-color-gray-50: rgb(255, 255, 255); + --spectrum-global-color-gray-200: rgb(244, 244, 244); + --spectrum-global-color-gray-300: rgb(234, 234, 234); + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-50); + ` + } + if (theme === "spectrum--light") { + return ` + --spectrum-global-color-gray-50: rgb(255, 255, 255); + --spectrum-global-color-gray-200: rgb(234, 234, 234); + --spectrum-global-color-gray-300: rgb(225, 225, 225); + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-50); + + ` + } + if (theme === "spectrum--dark") { + return ` + --spectrum-global-color-gray-100: rgb(50, 50, 50); + --spectrum-global-color-gray-200: rgb(62, 62, 62); + --spectrum-global-color-gray-300: rgb(74, 74, 74); + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-100); + ` + } + if (theme === "spectrum--darkest") { + return ` + --spectrum-global-color-gray-100: rgb(30, 30, 30); + --spectrum-global-color-gray-200: rgb(44, 44, 44); + --spectrum-global-color-gray-300: rgb(57, 57, 57); + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-100); + ` + } + if (theme === "spectrum--nord") { + return ` + --spectrum-global-color-gray-100: #3b4252; + + --spectrum-global-color-gray-200: #424a5c; + --spectrum-global-color-gray-300: #4c566a; + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-100); + ` + } + if (theme === "spectrum--midnight") { + return ` + --hue: 220; + --sat: 10%; + --spectrum-global-color-gray-100: hsl(var(--hue), var(--sat), 17%); + --spectrum-global-color-gray-200: hsl(var(--hue), var(--sat), 20%); + --spectrum-global-color-gray-300: hsl(var(--hue), var(--sat), 24%); + --spectrum-alias-background-color-primary: var(--spectrum-global-color-gray-100); + ` + } +} + export const toggleBetaUiFeature = async function (ctx: Ctx) { const cookieName = `beta:${ctx.params.feature}` @@ -146,7 +205,7 @@ const requiresMigration = async (ctx: Ctx) => { return requiresMigrations } -export const serveApp = async function (ctx: Ctx) { +export const serveApp = async function (ctx: UserCtx) { const needMigrations = await requiresMigration(ctx) const bbHeaderEmbed = @@ -167,9 +226,19 @@ export const serveApp = async function (ctx: Ctx) { const appInfo = await db.get(DocumentType.APP_METADATA) let appId = context.getAppId() + const hideDevTools = !!ctx.params.appUrl + const sideNav = appInfo.navigation.navigation === "Left" + const hideFooter = + ctx?.user?.license?.features?.includes(Feature.BRANDING) || false + const themeVariables = getThemeVariables(appInfo?.theme) + if (!env.isJest()) { const plugins = objectStore.enrichPluginURLs(appInfo.usedPlugins) + const { head, html, css } = AppComponent.render({ + hideDevTools, + sideNav, + hideFooter, metaImage: branding?.metaImageUrl || "https://res.cloudinary.com/daog6scxm/image/upload/v1698759482/meta-images/plain-branded-meta-image-coral_ocxmgu.png", @@ -194,7 +263,7 @@ export const serveApp = async function (ctx: Ctx) { ctx.body = await processString(appHbs, { head, body: html, - style: css.code, + css: `:root{${themeVariables}} ${css.code}`, appId, embedded: bbHeaderEmbed, }) diff --git a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte index 7819368fc0..63b293b4ca 100644 --- a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte +++ b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte @@ -1,4 +1,6 @@ @@ -96,6 +102,7 @@ +
{#if clientLibPath}

There was an error loading your app

diff --git a/packages/server/src/api/controllers/static/templates/app.hbs b/packages/server/src/api/controllers/static/templates/app.hbs index 8c445158a0..b01b723c3e 100644 --- a/packages/server/src/api/controllers/static/templates/app.hbs +++ b/packages/server/src/api/controllers/static/templates/app.hbs @@ -1,8 +1,12 @@ - + {{{head}}} - +
@@ -98,17 +78,7 @@
{:else} -
-
- -
-
-