diff --git a/lerna.json b/lerna.json index fdd10e4bf1..be6673e7ae 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.13", + "version": "3.2.14", "npmClient": "yarn", "concurrency": 20, "command": { diff --git a/packages/backend-core/src/sql/sql.ts b/packages/backend-core/src/sql/sql.ts index e4b2b843af..d251ff672d 100644 --- a/packages/backend-core/src/sql/sql.ts +++ b/packages/backend-core/src/sql/sql.ts @@ -18,6 +18,7 @@ import { BasicOperator, BBReferenceFieldMetadata, CalculationType, + EnrichedQueryJson, FieldSchema, FieldType, INTERNAL_TABLE_SOURCE_ID, @@ -27,7 +28,6 @@ import { LogicalOperator, Operation, prefixed, - QueryJson, QueryOptions, RangeOperator, RelationshipsJson, @@ -134,18 +134,18 @@ const allowEmptyRelationships: Record = { class InternalBuilder { private readonly client: SqlClient - private readonly query: QueryJson + private readonly query: EnrichedQueryJson private readonly splitter: dataFilters.ColumnSplitter private readonly knex: Knex - constructor(client: SqlClient, knex: Knex, query: QueryJson) { + constructor(client: SqlClient, knex: Knex, query: EnrichedQueryJson) { this.client = client this.query = query this.knex = knex this.splitter = new dataFilters.ColumnSplitter([this.table], { aliases: this.query.tableAliases, - columnPrefix: this.query.meta.columnPrefix, + columnPrefix: this.query.meta?.columnPrefix, }) } @@ -167,7 +167,7 @@ class InternalBuilder { } get table(): Table { - return this.query.meta.table + return this.query.table } get knexClient(): Knex.Client { @@ -273,8 +273,7 @@ class InternalBuilder { } private isFullSelectStatementRequired(): boolean { - const { meta } = this.query - for (let column of Object.values(meta.table.schema)) { + for (let column of Object.values(this.table.schema)) { if (this.SPECIAL_SELECT_CASES.POSTGRES_MONEY(column)) { return true } else if (this.SPECIAL_SELECT_CASES.MSSQL_DATES(column)) { @@ -285,14 +284,14 @@ class InternalBuilder { } private generateSelectStatement(): (string | Knex.Raw)[] | "*" { - const { meta, endpoint, resource } = this.query + const { endpoint, resource } = this.query if (!resource || !resource.fields || resource.fields.length === 0) { return "*" } const alias = this.getTableName(endpoint.entityId) - const schema = meta.table.schema + const schema = this.table.schema if (!this.isFullSelectStatementRequired()) { return [this.knex.raw("??", [`${alias}.*`])] } @@ -497,9 +496,8 @@ class InternalBuilder { filterKey: string, whereCb: (filterKey: string, query: Knex.QueryBuilder) => Knex.QueryBuilder ): Knex.QueryBuilder { - const { relationships, endpoint, tableAliases: aliases } = this.query - const tableName = endpoint.entityId - const fromAlias = aliases?.[tableName] || tableName + const { relationships, endpoint, tableAliases: aliases, table } = this.query + const fromAlias = aliases?.[table.name] || table.name const matches = (value: string) => filterKey.match(new RegExp(`^${value}\\.`)) if (!relationships) { @@ -1018,15 +1016,15 @@ class InternalBuilder { const name = tableOrName if (this.query.table?.name === name) { table = this.query.table - } else if (this.query.meta.table?.name === name) { - table = this.query.meta.table - } else if (!this.query.meta.tables?.[name]) { + } else if (this.query.table.name === name) { + table = this.query.table + } else if (!this.query.tables[name]) { // This can legitimately happen in custom queries, where the user is // querying against a table that may not have been imported into // Budibase. return name } else { - table = this.query.meta.tables[name] + table = this.query.tables[name] } } else if (tableOrName) { table = tableOrName @@ -1191,8 +1189,9 @@ class InternalBuilder { return withSchema } - private buildJsonField(field: string): string { + private buildJsonField(table: Table, field: string): [string, Knex.Raw] { const parts = field.split(".") + let baseName = parts[parts.length - 1] let unaliased: string let tableField: string @@ -1205,10 +1204,19 @@ class InternalBuilder { tableField = unaliased } - const separator = this.client === SqlClient.ORACLE ? " VALUE " : "," - return this.knex - .raw(`?${separator}??`, [unaliased, this.rawQuotedIdentifier(tableField)]) - .toString() + if (this.query.meta?.columnPrefix) { + baseName = baseName.replace(this.query.meta.columnPrefix, "") + } + + let identifier = this.rawQuotedIdentifier(tableField) + // Internal tables have special _id, _rev, createdAt, and updatedAt fields + // that do not appear in the schema, meaning schema could actually be + // undefined. + const schema: FieldSchema | undefined = table.schema[baseName] + if (schema && schema.type === FieldType.BIGINT) { + identifier = this.castIntToString(identifier) + } + return [unaliased, identifier] } maxFunctionParameters() { @@ -1234,7 +1242,7 @@ class InternalBuilder { ): Knex.QueryBuilder { const sqlClient = this.client const knex = this.knex - const { resource, tableAliases: aliases, endpoint, meta } = this.query + const { resource, tableAliases: aliases, endpoint, tables } = this.query const fields = resource?.fields || [] for (let relationship of relationships) { const { @@ -1249,7 +1257,10 @@ class InternalBuilder { if (!toTable || !fromTable) { continue } - const relatedTable = meta.tables?.[toTable] + const relatedTable = tables[toTable] + if (!relatedTable) { + throw new Error(`related table "${toTable}" not found in datasource`) + } const toAlias = aliases?.[toTable] || toTable, fromAlias = aliases?.[fromTable] || fromTable, throughAlias = (throughTable && aliases?.[throughTable]) || throughTable @@ -1271,8 +1282,14 @@ class InternalBuilder { 0, Math.floor(this.maxFunctionParameters() / 2) ) - const fieldList: string = relationshipFields - .map(field => this.buildJsonField(field)) + const fieldList = relationshipFields.map(field => + this.buildJsonField(relatedTable, field) + ) + const fieldListFormatted = fieldList + .map(f => { + const separator = this.client === SqlClient.ORACLE ? " VALUE " : "," + return this.knex.raw(`?${separator}??`, [f[0], f[1]]).toString() + }) .join(",") // SQL Server uses TOP - which performs a little differently to the normal LIMIT syntax // it reduces the result set rather than limiting how much data it filters over @@ -1320,35 +1337,42 @@ class InternalBuilder { // need to check the junction table document is to the right column, this is just for SQS subQuery = this.addJoinFieldCheck(subQuery, relationship) wrapperQuery = standardWrap( - this.knex.raw(`json_group_array(json_object(${fieldList}))`) + this.knex.raw( + `json_group_array(json_object(${fieldListFormatted}))` + ) ) break case SqlClient.POSTGRES: wrapperQuery = standardWrap( - this.knex.raw(`json_agg(json_build_object(${fieldList}))`) + this.knex.raw(`json_agg(json_build_object(${fieldListFormatted}))`) ) break case SqlClient.MARIADB: // can't use the standard wrap due to correlated sub-query limitations in MariaDB wrapperQuery = subQuery.select( knex.raw( - `json_arrayagg(json_object(${fieldList}) LIMIT ${getRelationshipLimit()})` + `json_arrayagg(json_object(${fieldListFormatted}) LIMIT ${getRelationshipLimit()})` ) ) break case SqlClient.MY_SQL: case SqlClient.ORACLE: wrapperQuery = standardWrap( - this.knex.raw(`json_arrayagg(json_object(${fieldList}))`) + this.knex.raw(`json_arrayagg(json_object(${fieldListFormatted}))`) ) break case SqlClient.MS_SQL: { const comparatorQuery = knex - .select(`${fromAlias}.*`) + .select(`*`) // @ts-ignore - from alias syntax not TS supported .from({ [fromAlias]: subQuery - .select(`${toAlias}.*`) + .select( + fieldList.map(f => { + // @ts-expect-error raw is fine here, knex types are wrong + return knex.ref(f[1]).as(f[0]) + }) + ) .limit(getRelationshipLimit()), }) @@ -1429,14 +1453,14 @@ class InternalBuilder { } qualifiedKnex(opts?: { alias?: string | boolean }): Knex.QueryBuilder { - let alias = this.query.tableAliases?.[this.query.endpoint.entityId] + let alias = this.query.tableAliases?.[this.query.table.name] if (opts?.alias === false) { alias = undefined } else if (typeof opts?.alias === "string") { alias = opts.alias } return this.knex( - this.tableNameWithSchema(this.query.endpoint.entityId, { + this.tableNameWithSchema(this.query.table.name, { alias, schema: this.query.endpoint.schema, }) @@ -1455,9 +1479,7 @@ class InternalBuilder { if (this.client === SqlClient.ORACLE) { // Oracle doesn't seem to automatically insert nulls // if we don't specify them, so we need to do that here - for (const [column, schema] of Object.entries( - this.query.meta.table.schema - )) { + for (const [column, schema] of Object.entries(this.query.table.schema)) { if ( schema.constraints?.presence === true || schema.type === FieldType.FORMULA || @@ -1534,11 +1556,10 @@ class InternalBuilder { limits?: { base: number; query: number } } = {} ): Knex.QueryBuilder { - let { endpoint, filters, paginate, relationships } = this.query + let { endpoint, filters, paginate, relationships, table } = this.query const { limits } = opts const counting = endpoint.operation === Operation.COUNT - const tableName = endpoint.entityId // start building the query let query = this.qualifiedKnex() // handle pagination @@ -1586,9 +1607,7 @@ class InternalBuilder { // handle relationships with a CTE for all others if (relationships?.length && aggregations.length === 0) { - const mainTable = - this.query.tableAliases?.[this.query.endpoint.entityId] || - this.query.endpoint.entityId + const mainTable = this.query.tableAliases?.[table.name] || table.name const cte = this.addSorting( this.knex .with("paginated", query) @@ -1598,7 +1617,7 @@ class InternalBuilder { }) ) // add JSON aggregations attached to the CTE - return this.addJsonRelationships(cte, tableName, relationships) + return this.addJsonRelationships(cte, table.name, relationships) } return query @@ -1661,7 +1680,10 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { * which for the sake of mySQL stops adding the returning statement to inserts, updates and deletes. * @return the query ready to be passed to the driver. */ - _query(json: QueryJson, opts: QueryOptions = {}): SqlQuery | SqlQuery[] { + _query( + json: EnrichedQueryJson, + opts: QueryOptions = {} + ): SqlQuery | SqlQuery[] { const sqlClient = this.getSqlClient() const config: Knex.Config = { client: this.getBaseSqlClient(), @@ -1711,34 +1733,32 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { return this.convertToNative(query, opts) } - async getReturningRow(queryFn: QueryFunction, json: QueryJson) { + async getReturningRow(queryFn: QueryFunction, json: EnrichedQueryJson) { if (!json.extra || !json.extra.idFilter) { return {} } const input = this._query({ + datasource: json.datasource, + table: json.table, + tables: json.tables, endpoint: { ...json.endpoint, operation: Operation.READ, }, - resource: { - fields: [], - }, + resource: { fields: [] }, filters: json.extra?.idFilter, - paginate: { - limit: 1, - }, - meta: json.meta, + paginate: { limit: 1 }, }) return queryFn(input, Operation.READ) } // when creating if an ID has been inserted need to make sure // the id filter is enriched with it before trying to retrieve the row - checkLookupKeys(id: any, json: QueryJson) { - if (!id || !json.meta.table || !json.meta.table.primary) { + checkLookupKeys(id: any, json: EnrichedQueryJson) { + if (!id || !json.table.primary) { return json } - const primaryKey = json.meta.table.primary?.[0] + const primaryKey = json.table.primary[0] json.extra = { idFilter: { equal: { @@ -1751,7 +1771,7 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { // this function recreates the returning functionality of postgres async queryWithReturning( - json: QueryJson, + json: EnrichedQueryJson, queryFn: QueryFunction, processFn: Function = (result: any) => result ) { diff --git a/packages/backend-core/src/sql/sqlTable.ts b/packages/backend-core/src/sql/sqlTable.ts index 84f4e290aa..5b76e155f9 100644 --- a/packages/backend-core/src/sql/sqlTable.ts +++ b/packages/backend-core/src/sql/sqlTable.ts @@ -3,13 +3,13 @@ import { FieldType, NumberFieldMetadata, Operation, - QueryJson, RelationshipType, RenameColumn, SqlQuery, Table, TableSourceType, SqlClient, + EnrichedQueryJson, } from "@budibase/types" import { breakExternalTableId, getNativeSql } from "./utils" import { helpers, utils } from "@budibase/shared-core" @@ -25,7 +25,7 @@ function generateSchema( schema: CreateTableBuilder, table: Table, tables: Record, - oldTable: null | Table = null, + oldTable?: Table, renamed?: RenameColumn ) { let primaryKeys = table && table.primary ? table.primary : [] @@ -55,7 +55,7 @@ function generateSchema( ) for (let [key, column] of Object.entries(table.schema)) { // skip things that are already correct - const oldColumn = oldTable ? oldTable.schema[key] : null + const oldColumn = oldTable?.schema[key] if ( (oldColumn && oldColumn.type) || columnTypeSet.includes(key) || @@ -199,8 +199,8 @@ function buildUpdateTable( knex: SchemaBuilder, table: Table, tables: Record, - oldTable: Table, - renamed: RenameColumn + oldTable?: Table, + renamed?: RenameColumn ): SchemaBuilder { return knex.alterTable(table.name, schema => { generateSchema(schema, table, tables, oldTable, renamed) @@ -238,11 +238,11 @@ class SqlTableQueryBuilder { * @param json the input JSON structure from which an SQL query will be built. * @return the operation that was found in the JSON. */ - _operation(json: QueryJson): Operation { + _operation(json: EnrichedQueryJson): Operation { return json.endpoint.operation } - _tableQuery(json: QueryJson): SqlQuery | SqlQuery[] { + _tableQuery(json: EnrichedQueryJson): SqlQuery | SqlQuery[] { let client = knex({ client: this.sqlClient }).schema let schemaName = json?.endpoint?.schema if (schemaName) { @@ -250,7 +250,7 @@ class SqlTableQueryBuilder { } let query: Knex.SchemaBuilder - if (!json.table || !json.meta || !json.meta.tables) { + if (!json.table || !json.tables) { throw new Error("Cannot execute without table being specified") } if (json.table.sourceType === TableSourceType.INTERNAL) { @@ -259,14 +259,14 @@ class SqlTableQueryBuilder { switch (this._operation(json)) { case Operation.CREATE_TABLE: - query = buildCreateTable(client, json.table, json.meta.tables) + query = buildCreateTable(client, json.table, json.tables) break case Operation.UPDATE_TABLE: - if (!json.meta || !json.meta.table) { + if (!json.table) { throw new Error("Must specify old table for update") } // renameColumn does not work for MySQL, so return a raw query - if (this.sqlClient === SqlClient.MY_SQL && json.meta.renamed) { + if (this.sqlClient === SqlClient.MY_SQL && json.meta?.renamed) { const updatedColumn = json.meta.renamed.updated const tableName = schemaName ? `\`${schemaName}\`.\`${json.table.name}\`` @@ -280,14 +280,14 @@ class SqlTableQueryBuilder { query = buildUpdateTable( client, json.table, - json.meta.tables, - json.meta.table, - json.meta.renamed! + json.tables, + json.meta?.oldTable, + json.meta?.renamed ) // renameColumn for SQL Server returns a parameterised `sp_rename` query, // which is not supported by SQL Server and gives a syntax error. - if (this.sqlClient === SqlClient.MS_SQL && json.meta.renamed) { + if (this.sqlClient === SqlClient.MS_SQL && json.meta?.renamed) { const oldColumn = json.meta.renamed.old const updatedColumn = json.meta.renamed.updated const tableName = schemaName diff --git a/packages/backend-core/tests/core/utilities/structures/licenses.ts b/packages/backend-core/tests/core/utilities/structures/licenses.ts index b4d209a7ee..77f6d57b09 100644 --- a/packages/backend-core/tests/core/utilities/structures/licenses.ts +++ b/packages/backend-core/tests/core/utilities/structures/licenses.ts @@ -22,7 +22,6 @@ export function price(): PurchasedPrice { currency: "usd", duration: PriceDuration.MONTHLY, priceId: "price_123", - dayPasses: undefined, isPerUser: true, } } @@ -50,11 +49,6 @@ export function quotas(): Quotas { value: 1, triggers: [], }, - dayPasses: { - name: "Queries", - value: 1, - triggers: [], - }, budibaseAICredits: { name: "Budibase AI Credits", value: 1, diff --git a/packages/backend-core/tests/core/utilities/structures/quotas.ts b/packages/backend-core/tests/core/utilities/structures/quotas.ts index 58817e4831..83c3a8a766 100644 --- a/packages/backend-core/tests/core/utilities/structures/quotas.ts +++ b/packages/backend-core/tests/core/utilities/structures/quotas.ts @@ -15,7 +15,6 @@ export const usage = (users: number = 0, creators: number = 0): QuotaUsage => { monthly: { "01-2023": { automations: 0, - dayPasses: 0, queries: 0, budibaseAICredits: 0, triggers: {}, @@ -45,14 +44,12 @@ export const usage = (users: number = 0, creators: number = 0): QuotaUsage => { }, "02-2023": { automations: 0, - dayPasses: 0, queries: 0, budibaseAICredits: 0, triggers: {}, }, current: { automations: 0, - dayPasses: 0, queries: 0, budibaseAICredits: 0, triggers: {}, diff --git a/packages/builder/src/components/portal/licensing/DayPassWarningModal.svelte b/packages/builder/src/components/portal/licensing/DayPassWarningModal.svelte deleted file mode 100644 index 341e427bf0..0000000000 --- a/packages/builder/src/components/portal/licensing/DayPassWarningModal.svelte +++ /dev/null @@ -1,81 +0,0 @@ - - - - {#if $auth.user.accountPortalAccess} - { - window.location.href = upgradeUrl - }} - > - - You have used {dayPassesUsed}% of - your plans Day Passes with {daysRemaining} day{daysRemaining == 1 - ? "" - : "s"} remaining. - - - - - {dayPassesBody} - - {:else} - - - You have used {dayPassesUsed}% of - your plans Day Passes with {daysRemaining} day{daysRemaining == 1 - ? "" - : "s"} remaining. - - - - - Please contact your account holder to upgrade. - - {/if} - - - diff --git a/packages/builder/src/components/portal/licensing/LicensingOverlays.svelte b/packages/builder/src/components/portal/licensing/LicensingOverlays.svelte index ab80418b6e..e2c52e3448 100644 --- a/packages/builder/src/components/portal/licensing/LicensingOverlays.svelte +++ b/packages/builder/src/components/portal/licensing/LicensingOverlays.svelte @@ -1,7 +1,6 @@ - { - const appAuth = get(auth) - const appLicensing = get(licensing) - if (get(licensing)?.usageMetrics["dayPasses"] >= 100) { - return { - key: "max_dayPasses", - type: BANNER_TYPES.NEGATIVE, - criteria: () => { - return true - }, - message: `Your apps are currently offline. You have exceeded your plans limit for Day Passes. ${ - appAuth.user.accountPortalAccess - ? "" - : "Please contact your account holder to upgrade." - }`, - ...upgradeAction(), - showCloseButton: false, - } - } - - return buildUsageInfoBanner( - "dayPasses", - "Day Passes", - ExpiringKeys.LICENSING_DAYPASS_WARNING_BANNER, - 90, - `You have used ${ - appLicensing?.usageMetrics["dayPasses"] - }% of your monthly usage of Day Passes with ${ - appLicensing?.quotaResetDaysRemaining - } day${ - get(licensing).quotaResetDaysRemaining == 1 ? "" : "s" - } remaining. All apps will be taken offline if this limit is reached. ${ - appAuth.user.accountPortalAccess - ? "" - : "Please contact your account holder to upgrade." - }` - ) -} - const buildPaymentFailedBanner = () => { return { key: "payment_Failed", @@ -166,7 +127,6 @@ const buildUsersAboveLimitBanner = EXPIRY_KEY => { export const getBanners = () => { return [ buildPaymentFailedBanner(), - buildDayPassBanner(ExpiringKeys.LICENSING_DAYPASS_WARNING_BANNER), buildUsageInfoBanner( "rows", "Rows", diff --git a/packages/builder/src/constants/index.js b/packages/builder/src/constants/index.js index 0d51f57c3e..3498183c8e 100644 --- a/packages/builder/src/constants/index.js +++ b/packages/builder/src/constants/index.js @@ -68,7 +68,6 @@ export const OnboardingType = { export const PlanModel = { PER_USER: "perUser", - DAY_PASS: "dayPass", } export const ChangelogURL = "https://docs.budibase.com/changelog" diff --git a/packages/builder/src/pages/builder/apps/index.svelte b/packages/builder/src/pages/builder/apps/index.svelte index 095bf2023b..632478748d 100644 --- a/packages/builder/src/pages/builder/apps/index.svelte +++ b/packages/builder/src/pages/builder/apps/index.svelte @@ -136,7 +136,7 @@ - {#if $licensing.usageMetrics?.dayPasses >= 100 || $licensing.errUserLimit} + {#if $licensing.errUserLimit}
spaceman diff --git a/packages/builder/src/pages/builder/portal/account/usage.svelte b/packages/builder/src/pages/builder/portal/account/usage.svelte index 7a1b1f8e14..cb0f5ea512 100644 --- a/packages/builder/src/pages/builder/portal/account/usage.svelte +++ b/packages/builder/src/pages/builder/portal/account/usage.svelte @@ -28,7 +28,7 @@ const upgradeUrl = `${$admin.accountPortalUrl}/portal/upgrade` const manageUrl = `${$admin.accountPortalUrl}/portal/billing` - const WARN_USAGE = ["Queries", "Automations", "Rows", "Day Passes", "Users"] + const WARN_USAGE = ["Queries", "Automations", "Rows", "Users"] const oneDayInSeconds = 86400 const EXCLUDE_QUOTAS = { @@ -36,9 +36,6 @@ Users: license => { return license.plan.model !== PlanModel.PER_USER }, - "Day Passes": license => { - return license.plan.model !== PlanModel.DAY_PASS - }, } function excludeQuota(name) { diff --git a/packages/client/package.json b/packages/client/package.json index fb9851e0a1..073869415d 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -15,8 +15,8 @@ "./manifest.json": "./manifest.json" }, "scripts": { - "build": "rollup -c", - "dev": "rollup -cw" + "build": "vite build", + "dev": "vite build --watch" }, "dependencies": { "@budibase/bbui": "0.0.0", @@ -36,19 +36,9 @@ "svelte-spa-router": "^4.0.1" }, "devDependencies": { - "@rollup/plugin-alias": "^5.1.0", - "@rollup/plugin-commonjs": "^25.0.7", - "@rollup/plugin-image": "^3.0.3", - "@rollup/plugin-node-resolve": "^15.2.3", - "postcss": "^8.4.35", - "rollup": "^4.9.6", - "rollup-plugin-json": "^4.0.0", - "rollup-plugin-polyfill-node": "^0.13.0", - "rollup-plugin-postcss": "^4.0.2", - "rollup-plugin-svelte": "^7.1.6", - "rollup-plugin-svg": "^2.0.0", - "rollup-plugin-terser": "^7.0.2", - "rollup-plugin-visualizer": "^5.12.0" + "@sveltejs/vite-plugin-svelte": "1.4.0", + "vite": "^4.5.0", + "vite-plugin-css-injected-by-js": "3.5.2" }, "resolutions": { "loader-utils": "1.4.1" diff --git a/packages/client/rollup.config.js b/packages/client/rollup.config.js deleted file mode 100644 index 9839414f7e..0000000000 --- a/packages/client/rollup.config.js +++ /dev/null @@ -1,117 +0,0 @@ -import commonjs from "@rollup/plugin-commonjs" -import resolve from "@rollup/plugin-node-resolve" -import alias from "@rollup/plugin-alias" -import svelte from "rollup-plugin-svelte" -import { terser } from "rollup-plugin-terser" -import postcss from "rollup-plugin-postcss" -import svg from "rollup-plugin-svg" -import image from "@rollup/plugin-image" -import json from "rollup-plugin-json" -import nodePolyfills from "rollup-plugin-polyfill-node" -import path from "path" -import { visualizer } from "rollup-plugin-visualizer" - -const production = !process.env.ROLLUP_WATCH -const ignoredWarnings = [ - "unused-export-let", - "css-unused-selector", - "module-script-reactive-declaration", - "a11y-no-onchange", - "a11y-click-events-have-key-events", -] - -const devPaths = production - ? [] - : [ - { - find: "@budibase/shared-core", - replacement: path.resolve("../shared-core/dist/index"), - }, - { - find: "@budibase/types", - replacement: path.resolve("../types/dist/index"), - }, - ] - -export default { - input: "src/index.js", - output: [ - { - sourcemap: false, - format: "iife", - file: `./dist/budibase-client.js`, - }, - ], - onwarn(warning, warn) { - if ( - warning.code === "THIS_IS_UNDEFINED" || - warning.code === "CIRCULAR_DEPENDENCY" || - warning.code === "EVAL" - ) { - return - } - warn(warning) - }, - plugins: [ - alias({ - entries: [ - { - find: "manifest.json", - replacement: path.resolve("./manifest.json"), - }, - { - find: "api", - replacement: path.resolve("./src/api"), - }, - { - find: "components", - replacement: path.resolve("./src/components"), - }, - { - find: "stores", - replacement: path.resolve("./src/stores"), - }, - { - find: "utils", - replacement: path.resolve("./src/utils"), - }, - { - find: "constants", - replacement: path.resolve("./src/constants"), - }, - { - find: "sdk", - replacement: path.resolve("./src/sdk"), - }, - ...devPaths, - ], - }), - svelte({ - emitCss: true, - onwarn: (warning, handler) => { - // Ignore some warnings - if (!ignoredWarnings.includes(warning.code)) { - handler(warning) - } - }, - }), - postcss(), - commonjs(), - nodePolyfills(), - resolve({ - preferBuiltins: true, - browser: true, - dedupe: ["svelte", "svelte/internal"], - }), - svg(), - image({ - exclude: "**/*.svg", - }), - json(), - production && terser(), - !production && visualizer(), - ], - watch: { - clearScreen: false, - }, -} diff --git a/packages/client/src/index.js b/packages/client/src/index.js index de6d1bdc12..9cef52bb1e 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -10,7 +10,7 @@ import { eventStore, hoverStore, } from "./stores" -import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-rollup.js" +import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-vite.js" import { get } from "svelte/store" import { initWebsocket } from "./websocket.js" diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index 81f1657f48..740b129738 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -3,6 +3,10 @@ "allowJs": true, "strict": true, "outDir": "dist", + "allowSyntheticDefaultImports": true, + "target": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, "paths": { "@budibase/*": [ "../*/src/index.ts", @@ -12,6 +16,5 @@ ], "*": ["./src/*"] } - }, - "include": ["src/**/*"] + } } diff --git a/packages/client/vite.config.mjs b/packages/client/vite.config.mjs new file mode 100644 index 0000000000..9c623b709f --- /dev/null +++ b/packages/client/vite.config.mjs @@ -0,0 +1,89 @@ +import { svelte } from "@sveltejs/vite-plugin-svelte" +import { defineConfig } from "vite" +import path from "path" +import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js" + +const ignoredWarnings = [ + "unused-export-let", + "css-unused-selector", + "module-script-reactive-declaration", + "a11y-no-onchange", + "a11y-click-events-have-key-events", +] + +export default defineConfig(({ mode }) => { + const isProduction = mode === "production" + + return { + server: { + open: false, + }, + build: { + lib: { + entry: "src/index.js", + formats: ["iife"], + outDir: "dist", + name: "budibase_client", + fileName: () => "budibase-client.js", + minify: isProduction, + }, + }, + plugins: [ + svelte({ + emitCss: true, + onwarn: (warning, handler) => { + // Ignore some warnings + if (!ignoredWarnings.includes(warning.code)) { + handler(warning) + } + }, + }), + cssInjectedByJsPlugin(), + ], + resolve: { + dedupe: ["svelte", "svelte/internal"], + alias: [ + { + find: "manifest.json", + replacement: path.resolve("./manifest.json"), + }, + { + find: "api", + replacement: path.resolve("./src/api"), + }, + { + find: "components", + replacement: path.resolve("./src/components"), + }, + { + find: "stores", + replacement: path.resolve("./src/stores"), + }, + { + find: "utils", + replacement: path.resolve("./src/utils"), + }, + { + find: "constants", + replacement: path.resolve("./src/constants"), + }, + { + find: "sdk", + replacement: path.resolve("./src/sdk"), + }, + { + find: "@budibase/types", + replacement: path.resolve("../types/src"), + }, + { + find: "@budibase/shared-core", + replacement: path.resolve("../shared-core/src"), + }, + { + find: "@budibase/bbui", + replacement: path.resolve("../bbui/src"), + }, + ], + }, + } +}) diff --git a/packages/pro b/packages/pro index 25dd40ee12..e2252498dd 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 25dd40ee12b048307b558ebcedb36548d6e042cd +Subproject commit e2252498ddfade3c2592b1ec78f7bee4e3cf0d2f diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index 794e2dfddd..82eadca312 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -23,11 +23,13 @@ import { Table, RowValue, DynamicVariable, + QueryJsonRequest, } from "@budibase/types" import sdk from "../../sdk" import { builderSocket } from "../../websockets" import { isEqual } from "lodash" import { processTable } from "../../sdk/app/tables/getters" +import { makeExternalQuery } from "../../integrations/base/query" export async function fetch(ctx: UserCtx) { ctx.body = await sdk.datasources.fetch() @@ -297,10 +299,10 @@ export async function find(ctx: UserCtx) { } // dynamic query functionality -export async function query(ctx: UserCtx) { +export async function query(ctx: UserCtx) { const queryJson = ctx.request.body try { - ctx.body = await sdk.rows.utils.getDatasourceAndQuery(queryJson) + ctx.body = await makeExternalQuery(queryJson) } catch (err: any) { ctx.throw(400, err) } diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 939ea399d9..5f01f323e6 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -42,7 +42,7 @@ import { sqlOutputProcessing, } from "./utils" import { - getDatasourceAndQuery, + enrichQueryJson, processRowCountResponse, } from "../../../sdk/app/rows/utils" import { processObjectSync } from "@budibase/string-templates" @@ -135,16 +135,9 @@ function cleanupConfig(config: RunConfig, table: Table): RunConfig { return config } -function getEndpoint(tableId: string | undefined, operation: string) { - if (!tableId) { - throw new Error("Cannot get endpoint information - no table ID specified") - } +function getEndpoint(tableId: string, operation: Operation) { const { datasourceId, tableName } = breakExternalTableId(tableId) - return { - datasourceId: datasourceId, - entityId: tableName, - operation: operation as Operation, - } + return { datasourceId, entityId: tableName, operation } } function isOneSide( @@ -268,12 +261,9 @@ export class ExternalRequest { const filters = this.prepareFilters(rowId, {}, table) // safety check, if there are no filters on deletion bad things happen if (Object.keys(filters).length !== 0) { - return getDatasourceAndQuery({ + return makeExternalQuery({ endpoint: getEndpoint(tableId, Operation.DELETE), filters, - meta: { - table, - }, }) } else { return [] @@ -289,13 +279,10 @@ export class ExternalRequest { const filters = this.prepareFilters(rowId, {}, table) // safety check, if there are no filters on deletion bad things happen if (Object.keys(filters).length !== 0) { - return getDatasourceAndQuery({ + return makeExternalQuery({ endpoint: getEndpoint(tableId, Operation.UPDATE), body: { [colName]: null }, filters, - meta: { - table, - }, }) } else { return [] @@ -311,12 +298,9 @@ export class ExternalRequest { } async getRow(table: Table, rowId: string): Promise { - const response = await getDatasourceAndQuery({ + const response = await makeExternalQuery({ endpoint: getEndpoint(table._id!, Operation.READ), filters: this.prepareFilters(rowId, {}, table), - meta: { - table, - }, }) if (Array.isArray(response) && response.length > 0) { return response[0] @@ -490,16 +474,13 @@ export class ExternalRequest { if (!relatedTable) { throw new Error("unable to find related table") } - const response = await getDatasourceAndQuery({ - endpoint: endpoint, + const response = await makeExternalQuery({ + endpoint, filters: { equal: { [fieldName]: row[lookupField], }, }, - meta: { - table: relatedTable, - }, }) // this is the response from knex if no rows found const rows: Row[] = @@ -537,6 +518,11 @@ export class ExternalRequest { for (let relationship of relationships) { const { key, tableId, isUpdate, id, relationshipType, ...rest } = relationship + + if (!tableId) { + throw new Error("Table ID is unknown, cannot find table") + } + const body: { [key: string]: any } = processObjectSync(rest, row, {}) const linkTable = this.getTable(tableId) const relationshipPrimary = linkTable?.primary || [] @@ -583,14 +569,11 @@ export class ExternalRequest { const operation = isUpdate ? Operation.UPDATE : Operation.CREATE if (!existingRelationship) { promises.push( - getDatasourceAndQuery({ + makeExternalQuery({ endpoint: getEndpoint(tableId, operation), // if we're doing many relationships then we're writing, only one response body, filters: this.prepareFilters(id, {}, linkTable), - meta: { - table: linkTable, - }, }) ) } else { @@ -723,8 +706,8 @@ export class ExternalRequest { let json: QueryJson = { endpoint: { - datasourceId: this.datasource._id!, - entityId: table.name, + datasourceId: this.datasource, + entityId: table, operation, }, resource: { @@ -749,10 +732,6 @@ export class ExternalRequest { table ), }, - meta: { - table, - tables: this.tables, - }, } // remove any relationships that could block deletion @@ -773,8 +752,11 @@ export class ExternalRequest { response = [unprocessedRow] } else { response = env.SQL_ALIASING_DISABLE - ? await getDatasourceAndQuery(json) - : await aliasing.queryWithAliasing(json, makeExternalQuery) + ? await makeExternalQuery(json) + : await aliasing.queryWithAliasing( + await enrichQueryJson(json), + makeExternalQuery + ) } // if it's a counting operation there will be no more processing, just return the number diff --git a/packages/server/src/api/controllers/table/ExternalRequest.ts b/packages/server/src/api/controllers/table/ExternalRequest.ts index 1e57ea3294..df5707b072 100644 --- a/packages/server/src/api/controllers/table/ExternalRequest.ts +++ b/packages/server/src/api/controllers/table/ExternalRequest.ts @@ -11,27 +11,24 @@ export async function makeTableRequest( datasource: Datasource, operation: Operation, table: Table, - tables: Record, oldTable?: Table, renamed?: RenameColumn ) { const json: QueryJson = { endpoint: { - datasourceId: datasource._id!, - entityId: table._id!, + datasourceId: datasource, + entityId: table, operation, }, - meta: { - table, - tables, - }, - table, + } + if (!json.meta) { + json.meta = {} } if (oldTable) { - json.meta!.table = oldTable + json.meta.oldTable = oldTable } if (renamed) { - json.meta!.renamed = renamed + json.meta.renamed = renamed } - return makeExternalQuery(datasource, json) + return makeExternalQuery(json) } diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 25c9b8abef..1f4c4bc7cb 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -3269,7 +3269,7 @@ if (descriptions.length) { formula: { name: "formula", type: FieldType.FORMULA, - formula: formula, + formula, responseType: opts?.responseType, formulaType: opts?.formulaType || FormulaType.DYNAMIC, }, @@ -3496,6 +3496,72 @@ if (descriptions.length) { ) }) }) + + if (!isInternal && !isOracle) { + describe("bigint ids", () => { + let table1: Table, table2: Table + let table1Name: string, table2Name: string + + beforeAll(async () => { + table1Name = `table1-${generator.guid().substring(0, 5)}` + await client!.schema.createTable(table1Name, table => { + table.bigInteger("table1Id").primary() + }) + + table2Name = `table2-${generator.guid().substring(0, 5)}` + await client!.schema.createTable(table2Name, table => { + table.bigInteger("table2Id").primary() + table + .bigInteger("table1Ref") + .references("table1Id") + .inTable(table1Name) + }) + + const resp = await config.api.datasource.fetchSchema({ + datasourceId: datasource!._id!, + }) + + const tables = Object.values(resp.datasource.entities || {}) + table1 = tables.find(t => t.name === table1Name)! + table2 = tables.find(t => t.name === table2Name)! + + await config.api.datasource.addExistingRelationship({ + one: { + tableId: table2._id!, + relationshipName: "one", + foreignKey: "table1Ref", + }, + many: { + tableId: table1._id!, + relationshipName: "many", + primaryKey: "table1Id", + }, + }) + }) + + it("should be able to fetch rows with related bigint ids", async () => { + const row = await config.api.row.save(table1._id!, { + table1Id: "1", + }) + await config.api.row.save(table2._id!, { + table2Id: "2", + table1Ref: row.table1Id, + }) + + let resp = await config.api.row.search(table1._id!) + expect(resp.rows).toHaveLength(1) + expect(resp.rows[0]._id).toBe("%5B'1'%5D") + expect(resp.rows[0].many).toHaveLength(1) + expect(resp.rows[0].many[0]._id).toBe("%5B'2'%5D") + + resp = await config.api.row.search(table2._id!) + expect(resp.rows).toHaveLength(1) + expect(resp.rows[0]._id).toBe("%5B'2'%5D") + expect(resp.rows[0].one).toHaveLength(1) + expect(resp.rows[0].one[0]._id).toBe("%5B'1'%5D") + }) + }) + } } ) } diff --git a/packages/server/src/integrations/base/query.ts b/packages/server/src/integrations/base/query.ts index 55886cd20f..6555a5de51 100644 --- a/packages/server/src/integrations/base/query.ts +++ b/packages/server/src/integrations/base/query.ts @@ -1,37 +1,27 @@ -import { - QueryJson, - Datasource, - DatasourcePlusQueryResponse, - RowOperations, -} from "@budibase/types" +import { DatasourcePlusQueryResponse, QueryJson } from "@budibase/types" import { getIntegration } from "../index" import sdk from "../../sdk" +import { enrichQueryJson } from "../../sdk/app/rows/utils" export async function makeExternalQuery( - datasource: Datasource, json: QueryJson ): Promise { - const entityId = json.endpoint.entityId, - tableName = json.meta.table.name, - tableId = json.meta.table._id - // case found during testing - make sure this doesn't happen again - if ( - RowOperations.includes(json.endpoint.operation) && - entityId !== tableId && - entityId !== tableName - ) { - throw new Error("Entity ID and table metadata do not align") - } - if (!datasource) { + const enrichedJson = await enrichQueryJson(json) + if (!enrichedJson.datasource) { throw new Error("No datasource provided for external query") } - datasource = await sdk.datasources.enrich(datasource) - const Integration = await getIntegration(datasource.source) + + enrichedJson.datasource = await sdk.datasources.enrich( + enrichedJson.datasource + ) + + const Integration = await getIntegration(enrichedJson.datasource.source) + // query is the opinionated function - if (Integration.prototype.query) { - const integration = new Integration(datasource.config) - return integration.query(json) - } else { + if (!Integration.prototype.query) { throw "Datasource does not support query." } + + const integration = new Integration(enrichedJson.datasource.config) + return integration.query(enrichedJson) } diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts index 5f61791683..6492a651e1 100644 --- a/packages/server/src/integrations/googlesheets.ts +++ b/packages/server/src/integrations/googlesheets.ts @@ -7,7 +7,6 @@ import { Integration, Operation, PaginationJson, - QueryJson, QueryType, Row, Schema, @@ -18,6 +17,7 @@ import { TableSourceType, DatasourcePlusQueryResponse, BBReferenceFieldSubType, + EnrichedQueryJson, } from "@budibase/types" import { OAuth2Client } from "google-auth-library" import { @@ -381,8 +381,8 @@ export class GoogleSheetsIntegration implements DatasourcePlus { return { tables: externalTables, errors } } - async query(json: QueryJson): Promise { - const sheet = json.endpoint.entityId + async query(json: EnrichedQueryJson): Promise { + const sheet = json.table.name switch (json.endpoint.operation) { case Operation.CREATE: return this.create({ sheet, row: json.body as Row }) @@ -400,7 +400,7 @@ export class GoogleSheetsIntegration implements DatasourcePlus { rowIndex: json.extra?.idFilter?.equal?.rowNumber, sheet, row: json.body, - table: json.meta.table, + table: json.table, }) case Operation.DELETE: return this.delete({ diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 1c74e6b1ff..a7a0b53312 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -4,9 +4,9 @@ import { DatasourceFieldType, DatasourcePlus, DatasourcePlusQueryResponse, + EnrichedQueryJson, Integration, Operation, - QueryJson, QueryType, Schema, SourceName, @@ -342,7 +342,8 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { ? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;` : query.sql this.log(sql, query.bindings) - return await request.query(sql) + const resp = await request.query(sql) + return resp } catch (err: any) { let readableMessage = getReadableErrorMessage( SourceName.SQL_SERVER, @@ -505,7 +506,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { return response.recordset || [{ deleted: true }] } - async query(json: QueryJson): Promise { + async query(json: EnrichedQueryJson): Promise { const schema = this.config.schema await this.connect() if (schema && schema !== DEFAULT_SCHEMA && json?.endpoint) { @@ -514,14 +515,12 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { const operation = this._operation(json) const queryFn = (query: any, op: string) => this.internalQuery(query, op) const processFn = (result: any) => { - if (json?.meta?.table && result.recordset) { + if (result.recordset) { return this.convertJsonStringColumns( - json.meta.table, + json.table, result.recordset, json.tableAliases ) - } else if (result.recordset) { - return result.recordset } return [{ [operation]: true }] } diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts index f78915fb49..9236409375 100644 --- a/packages/server/src/integrations/mysql.ts +++ b/packages/server/src/integrations/mysql.ts @@ -2,7 +2,6 @@ import { Integration, DatasourceFieldType, QueryType, - QueryJson, SqlQuery, Table, TableSchema, @@ -15,6 +14,7 @@ import { DatasourcePlusQueryResponse, SqlQueryBinding, SqlClient, + EnrichedQueryJson, } from "@budibase/types" import { getSqlQuery, @@ -390,15 +390,15 @@ class MySQLIntegration extends Sql implements DatasourcePlus { return results.length ? results : [{ deleted: true }] } - async query(json: QueryJson): Promise { + async query(json: EnrichedQueryJson): Promise { await this.connect() try { const queryFn = (query: any) => this.internalQuery(query, { connect: false, disableCoercion: true }) const processFn = (result: any) => { - if (json?.meta?.table && Array.isArray(result)) { + if (Array.isArray(result)) { return this.convertJsonStringColumns( - json.meta.table, + json.table, result, json.tableAliases ) diff --git a/packages/server/src/integrations/oracle.ts b/packages/server/src/integrations/oracle.ts index fcbc0731ea..ded21487f6 100644 --- a/packages/server/src/integrations/oracle.ts +++ b/packages/server/src/integrations/oracle.ts @@ -3,7 +3,6 @@ import { DatasourceFieldType, Integration, Operation, - QueryJson, QueryType, SqlQuery, Table, @@ -15,6 +14,7 @@ import { Row, DatasourcePlusQueryResponse, SqlClient, + EnrichedQueryJson, } from "@budibase/types" import { buildExternalTableId, @@ -545,7 +545,7 @@ class OracleIntegration extends Sql implements DatasourcePlus { : [{ deleted: true }] } - async query(json: QueryJson): Promise { + async query(json: EnrichedQueryJson): Promise { const operation = this._operation(json) const input = this._query(json, { disableReturning: true }) as SqlQuery if (Array.isArray(input)) { @@ -578,7 +578,7 @@ class OracleIntegration extends Sql implements DatasourcePlus { operation !== Operation.DELETE ) { const lastRow = await this.internalQuery({ - sql: `SELECT * FROM "${json.endpoint.entityId}" WHERE ROWID = '${response.lastRowid}'`, + sql: `SELECT * FROM "${json.table.name}" WHERE ROWID = '${response.lastRowid}'`, }) return lastRow.rows as Row[] } else { diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts index 28400f616f..164468b5ae 100644 --- a/packages/server/src/integrations/postgres.ts +++ b/packages/server/src/integrations/postgres.ts @@ -3,7 +3,6 @@ import { Integration, DatasourceFieldType, QueryType, - QueryJson, SqlQuery, Table, DatasourcePlus, @@ -14,6 +13,7 @@ import { TableSourceType, DatasourcePlusQueryResponse, SqlClient, + EnrichedQueryJson, } from "@budibase/types" import { getSqlQuery, @@ -419,7 +419,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus { return response.rows.length ? response.rows : [{ deleted: true }] } - async query(json: QueryJson): Promise { + async query(json: EnrichedQueryJson): Promise { const operation = this._operation(json).toLowerCase() const input = this._query(json) as SqlQuery if (Array.isArray(input)) { diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts deleted file mode 100644 index 2b3649161c..0000000000 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { - FieldType, - Operation, - PaginationJson, - QueryJson, - SearchFilters, - SortJson, - SqlClient, - Table, - TableSourceType, -} from "@budibase/types" -import { sql } from "@budibase/backend-core" -import { merge } from "lodash" - -const Sql = sql.Sql - -const TABLE_NAME = "test" -const TABLE: Table = { - type: "table", - sourceType: TableSourceType.EXTERNAL, - sourceId: "SOURCE_ID", - schema: { - id: { - name: "id", - type: FieldType.NUMBER, - }, - }, - name: TABLE_NAME, - primary: ["id"], -} - -const ORACLE_TABLE: Partial = { - schema: { - name: { - name: "name", - type: FieldType.STRING, - }, - }, -} - -function endpoint(table: string, operation: Operation) { - return { - datasourceId: "Postgres", - operation: operation, - entityId: table || TABLE_NAME, - } -} - -function generateReadJson({ - table, - fields, - filters, - sort, - paginate, -}: { - table?: Partial
- fields?: string[] - filters?: SearchFilters - sort?: SortJson - paginate?: PaginationJson -} = {}): QueryJson { - let tableObj: Table = { ...TABLE } - if (table) { - tableObj = merge(TABLE, table) - } - return { - endpoint: endpoint(tableObj.name || TABLE_NAME, Operation.READ), - resource: { - fields: fields || [], - }, - filters: filters || {}, - sort: sort || {}, - paginate: paginate || undefined, - meta: { - table: tableObj, - }, - } -} - -function generateRelationshipJson(config: { schema?: string } = {}): QueryJson { - return { - endpoint: { - datasourceId: "Postgres", - entityId: "brands", - operation: Operation.READ, - schema: config.schema, - }, - resource: { - fields: [ - "brands.brand_id", - "brands.brand_name", - "products.product_id", - "products.product_name", - "products.brand_id", - ], - }, - filters: {}, - sort: {}, - relationships: [ - { - from: "brand_id", - to: "brand_id", - tableName: "products", - column: "products", - }, - ], - extra: { idFilter: {} }, - meta: { - table: TABLE, - }, - } -} - -function generateManyRelationshipJson(config: { schema?: string } = {}) { - return { - endpoint: { - datasourceId: "Postgres", - entityId: "stores", - operation: "READ", - schema: config.schema, - }, - resource: { - fields: [ - "stores.store_id", - "stores.store_name", - "products.product_id", - "products.product_name", - ], - }, - filters: {}, - sort: {}, - paginate: {}, - relationships: [ - { - from: "store_id", - to: "product_id", - tableName: "products", - column: "products", - through: "stocks", - fromPrimary: "store_id", - toPrimary: "product_id", - }, - ], - extra: { idFilter: {} }, - meta: { - table: TABLE, - }, - } -} - -describe("SQL query builder", () => { - const relationshipLimit = 500 - const limit = 500 - const client = SqlClient.POSTGRES - let sql: any - - beforeEach(() => { - sql = new Sql(client, limit) - }) - - it("should add the schema to the LEFT JOIN", () => { - const query = sql._query(generateRelationshipJson({ schema: "production" })) - expect(query).toEqual({ - bindings: [limit, relationshipLimit], - sql: `with "paginated" as (select "brands".* from "production"."brands" order by "test"."id" asc limit $1) select "brands".*, (select json_agg(json_build_object('brand_id',"products"."brand_id",'product_id',"products"."product_id",'product_name',"products"."product_name")) from (select "products".* from "production"."products" as "products" where "products"."brand_id" = "brands"."brand_id" order by "products"."brand_id" asc limit $2) as "products") as "products" from "paginated" as "brands" order by "test"."id" asc`, - }) - }) - - it("should handle if the schema is not present when doing a LEFT JOIN", () => { - const query = sql._query(generateRelationshipJson()) - expect(query).toEqual({ - bindings: [limit, relationshipLimit], - sql: `with "paginated" as (select "brands".* from "brands" order by "test"."id" asc limit $1) select "brands".*, (select json_agg(json_build_object('brand_id',"products"."brand_id",'product_id',"products"."product_id",'product_name',"products"."product_name")) from (select "products".* from "products" as "products" where "products"."brand_id" = "brands"."brand_id" order by "products"."brand_id" asc limit $2) as "products") as "products" from "paginated" as "brands" order by "test"."id" asc`, - }) - }) - - it("should add the schema to both the toTable and throughTable in many-to-many join", () => { - const query = sql._query( - generateManyRelationshipJson({ schema: "production" }) - ) - expect(query).toEqual({ - bindings: [limit, relationshipLimit], - sql: `with "paginated" as (select "stores".* from "production"."stores" order by "test"."id" asc limit $1) select "stores".*, (select json_agg(json_build_object('product_id',"products"."product_id",'product_name',"products"."product_name")) from (select "products".* from "production"."products" as "products" inner join "production"."stocks" as "stocks" on "products"."product_id" = "stocks"."product_id" where "stocks"."store_id" = "stores"."store_id" order by "products"."product_id" asc limit $2) as "products") as "products" from "paginated" as "stores" order by "test"."id" asc`, - }) - }) - - it("should lowercase the values for Oracle LIKE statements", () => { - let query = new Sql(SqlClient.ORACLE, limit)._query( - generateReadJson({ - filters: { - string: { - name: "John", - }, - }, - }) - ) - expect(query).toEqual({ - bindings: ["john%", limit], - sql: `select * from (select * from "test" where LOWER("test"."name") LIKE :1 order by "test"."id" asc) where rownum <= :2`, - }) - - query = new Sql(SqlClient.ORACLE, limit)._query( - generateReadJson({ - filters: { - contains: { - age: [20, 25], - name: ["John", "Mary"], - }, - }, - }) - ) - const filterSet = [`%20%`, `%25%`, `%"john"%`, `%"mary"%`] - expect(query).toEqual({ - bindings: [...filterSet, limit], - sql: `select * from (select * from "test" where ((COALESCE(LOWER("test"."age"), '') like :1 and COALESCE(LOWER("test"."age"), '') like :2)) and ((COALESCE(LOWER("test"."name"), '') like :3 and COALESCE(LOWER("test"."name"), '') like :4)) order by "test"."id" asc) where rownum <= :5`, - }) - - query = new Sql(SqlClient.ORACLE, limit)._query( - generateReadJson({ - filters: { - fuzzy: { - name: "Jo", - }, - }, - }) - ) - expect(query).toEqual({ - bindings: [`%jo%`, limit], - sql: `select * from (select * from "test" where LOWER("test"."name") LIKE :1 order by "test"."id" asc) where rownum <= :2`, - }) - }) - - it("should use an oracle compatible coalesce query for oracle when using the equals filter", () => { - let query = new Sql(SqlClient.ORACLE, limit)._query( - generateReadJson({ - table: ORACLE_TABLE, - filters: { - equal: { - name: "John", - }, - }, - }) - ) - - expect(query).toEqual({ - bindings: ["John", limit], - sql: `select * from (select * from "test" where (to_char("test"."name") is not null and to_char("test"."name") = :1) order by "test"."id" asc) where rownum <= :2`, - }) - }) - - it("should use an oracle compatible coalesce query for oracle when using the not equals filter", () => { - let query = new Sql(SqlClient.ORACLE, limit)._query( - generateReadJson({ - table: ORACLE_TABLE, - filters: { - notEqual: { - name: "John", - }, - }, - }) - ) - - expect(query).toEqual({ - bindings: ["John", limit], - sql: `select * from (select * from "test" where (to_char("test"."name") is not null and to_char("test"."name") != :1) or to_char("test"."name") is null order by "test"."id" asc) where rownum <= :2`, - }) - }) -}) diff --git a/packages/server/src/integrations/tests/sqlAlias.spec.ts b/packages/server/src/integrations/tests/sqlAlias.spec.ts index 739d3a4aee..4de84f689e 100644 --- a/packages/server/src/integrations/tests/sqlAlias.spec.ts +++ b/packages/server/src/integrations/tests/sqlAlias.spec.ts @@ -1,12 +1,13 @@ import { Datasource, Operation, - QueryJson, SourceName, SqlQuery, + SqlClient, + EnrichedQueryJson, + TableSchema, Table, TableSourceType, - SqlClient, } from "@budibase/types" import { sql } from "@budibase/backend-core" import { join } from "path" @@ -16,17 +17,21 @@ import sdk from "../../sdk" const Sql = sql.Sql // this doesn't exist strictly -const TABLE: Table = { - type: "table", - sourceType: TableSourceType.EXTERNAL, - sourceId: "SOURCE_ID", - schema: {}, - name: "tableName", - primary: ["id"], -} +const TABLE = buildTable("tableName", {}) const AliasTables = sdk.rows.AliasTables +function buildTable(name: string, schema: TableSchema): Table { + return { + type: "table", + sourceType: TableSourceType.EXTERNAL, + sourceId: "SOURCE_ID", + schema: schema, + name: name, + primary: ["id"], + } +} + function multiline(sql: string) { return sql.replace(/\n/g, "").replace(/ +/g, " ") } @@ -35,8 +40,22 @@ describe("Captures of real examples", () => { const relationshipLimit = 500 const primaryLimit = 100 - function getJson(name: string): QueryJson { - return require(join(__dirname, "sqlQueryJson", name)) as QueryJson + function getJson(name: string): EnrichedQueryJson { + // tables aren't fully specified in the test JSON + const base = require(join(__dirname, "sqlQueryJson", name)) as Omit< + EnrichedQueryJson, + "tables" + > + const tables: Record = { [base.table.name]: base.table } + if (base.relationships) { + for (let { tableName } of base.relationships) { + tables[tableName] = buildTable(tableName, {}) + } + } + return { + ...base, + tables: tables, + } } describe("create", () => { @@ -63,7 +82,7 @@ describe("Captures of real examples", () => { bindings: [primaryLimit, relationshipLimit, relationshipLimit], sql: expect.stringContaining( multiline( - `select json_agg(json_build_object('completed',"b"."completed",'completed',"b"."completed",'executorid',"b"."executorid",'executorid',"b"."executorid",'qaid',"b"."qaid",'qaid',"b"."qaid",'taskid',"b"."taskid",'taskid',"b"."taskid",'taskname',"b"."taskname",'taskname',"b"."taskname")` + `select json_agg(json_build_object('executorid',"b"."executorid",'executorid',"b"."executorid",'qaid',"b"."qaid",'qaid',"b"."qaid",'taskid',"b"."taskid",'taskid',"b"."taskid",'completed',"b"."completed",'completed',"b"."completed",'taskname',"b"."taskname",'taskname',"b"."taskname"` ) ), }) @@ -94,7 +113,7 @@ describe("Captures of real examples", () => { sql: expect.stringContaining( multiline( `with "paginated" as (select "a".* from "products" as "a" order by "a"."productname" asc nulls first, "a"."productid" asc limit $1) - select "a".*, (select json_agg(json_build_object('completed',"b"."completed",'executorid',"b"."executorid",'qaid',"b"."qaid",'taskid',"b"."taskid",'taskname',"b"."taskname")) + select "a".*, (select json_agg(json_build_object('executorid',"b"."executorid",'qaid',"b"."qaid",'taskid',"b"."taskid",'completed',"b"."completed",'taskname',"b"."taskname")) from (select "b".* from "tasks" as "b" inner join "products_tasks" as "c" on "b"."taskid" = "c"."taskid" where "c"."productid" = "a"."productid" order by "b"."taskid" asc limit $2) as "b") as "tasks" from "paginated" as "a" order by "a"."productname" asc nulls first, "a"."productid" asc` ) @@ -212,8 +231,7 @@ describe("Captures of real examples", () => { }, queryJson) expect(returningQuery).toEqual({ sql: multiline( - `select top (@p0) * from [people] where CASE WHEN [people].[name] = @p1 THEN 1 ELSE 0 END = 1 - and CASE WHEN [people].[age] = @p2 THEN 1 ELSE 0 END = 1 order by [people].[name] asc` + `select top (@p0) * from [people] where CASE WHEN [people].[name] = @p1 THEN 1 ELSE 0 END = 1 and CASE WHEN [people].[age] = @p2 THEN 1 ELSE 0 END = 1 order by [people].[name] asc` ), bindings: [1, "Test", 22], }) @@ -246,15 +264,17 @@ describe("Captures of real examples", () => { } } - function getQuery(op: Operation, fields: string[] = ["a"]): QueryJson { + function getQuery( + op: Operation, + fields: string[] = ["a"] + ): EnrichedQueryJson { return { endpoint: { datasourceId: "", entityId: "", operation: op }, resource: { fields, }, - meta: { - table: TABLE, - }, + table: TABLE, + tables: { [TABLE.name]: TABLE }, } } diff --git a/packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json b/packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json index aa2cab3afd..27d6efec29 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/basicFetchWithRelationships.json @@ -61,113 +61,111 @@ "extra": { "idFilter": {} }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", - "primary": ["personid"], - "name": "persons", - "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" + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": ["personid"], + "name": "persons", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - "sourceType": "external", - "primaryDisplay": "firstname", - "views": {} - } + "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", diff --git a/packages/server/src/integrations/tests/sqlQueryJson/createSimple.json b/packages/server/src/integrations/tests/sqlQueryJson/createSimple.json index 33a88d30e1..474be32cf2 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/createSimple.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/createSimple.json @@ -5,10 +5,7 @@ "operation": "CREATE" }, "resource": { - "fields": [ - "a.name", - "a.age" - ] + "fields": ["a.name", "a.age"] }, "filters": {}, "relationships": [], @@ -24,41 +21,36 @@ } } }, - "meta": { - "table": { - "_id": "datasource_plus_0ed5835e5552496285df546030f7c4ae__people", - "type": "table", - "sourceId": "datasource_plus_0ed5835e5552496285df546030f7c4ae", - "sourceType": "external", - "primary": [ - "name", - "age" - ], - "name": "people", - "schema": { - "name": { - "type": "string", - "externalType": "varchar", - "autocolumn": false, - "name": "name", - "constraints": { - "presence": true - } - }, - "age": { - "type": "number", - "externalType": "int", - "autocolumn": false, - "name": "age", - "constraints": { - "presence": false - } + "table": { + "_id": "datasource_plus_0ed5835e5552496285df546030f7c4ae__people", + "type": "table", + "sourceId": "datasource_plus_0ed5835e5552496285df546030f7c4ae", + "sourceType": "external", + "primary": ["name", "age"], + "name": "people", + "schema": { + "name": { + "type": "string", + "externalType": "varchar", + "autocolumn": false, + "name": "name", + "constraints": { + "presence": true } }, - "primaryDisplay": "name" - } + "age": { + "type": "number", + "externalType": "int", + "autocolumn": false, + "name": "age", + "constraints": { + "presence": false + } + } + }, + "primaryDisplay": "name" }, "tableAliases": { "people": "a" } -} \ 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 index 82d85c417b..060197dd01 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/createWithRelationships.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/createWithRelationships.json @@ -51,123 +51,114 @@ "extra": { "idFilter": {} }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", - "primary": [ - "personid" - ], - "name": "persons", - "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" + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": ["personid"], + "name": "persons", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - "sourceType": "external", - "primaryDisplay": "firstname", - "views": {} - } + "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 index d6e099c4b6..d9fc34165f 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/deleteSimple.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/deleteSimple.json @@ -5,11 +5,7 @@ "operation": "DELETE" }, "resource": { - "fields": [ - "a.keyparttwo", - "a.keypartone", - "a.name" - ] + "fields": ["a.keyparttwo", "a.keypartone", "a.name"] }, "filters": { "equal": { @@ -26,50 +22,45 @@ } } }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__compositetable", - "primary": [ - "keypartone", - "keyparttwo" - ], - "name": "compositetable", - "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 - } + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__compositetable", + "primary": ["keypartone", "keyparttwo"], + "name": "compositetable", + "schema": { + "keyparttwo": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "keyparttwo", + "constraints": { + "presence": true } }, - "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - "sourceType": "external", - "primaryDisplay": "keypartone" - } + "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/enrichRelationship.json b/packages/server/src/integrations/tests/sqlQueryJson/enrichRelationship.json index d71f0552c6..f24b46859f 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/enrichRelationship.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/enrichRelationship.json @@ -17,10 +17,7 @@ }, "filters": { "oneOf": { - "taskid": [ - 1, - 2 - ] + "taskid": [1, 2] } }, "relationships": [ @@ -42,82 +39,78 @@ "extra": { "idFilter": {} }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__tasks", - "primary": [ - "taskid" - ], - "name": "tasks", - "schema": { - "executorid": { - "type": "number", - "externalType": "integer", - "autocolumn": false, - "name": "executorid", - "constraints": { - "presence": false - } - }, - "taskname": { - "type": "string", - "externalType": "character varying", - "autocolumn": false, - "name": "taskname", - "constraints": { - "presence": false - } - }, - "taskid": { - "type": "number", - "externalType": "integer", - "autocolumn": true, - "name": "taskid", - "constraints": { - "presence": false - } - }, - "completed": { - "type": "boolean", - "externalType": "boolean", - "autocolumn": false, - "name": "completed", - "constraints": { - "presence": false - } - }, - "qaid": { - "type": "number", - "externalType": "integer", - "autocolumn": false, - "name": "qaid", - "constraints": { - "presence": false - } - }, - "products": { - "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products", - "name": "products", - "relationshipType": "many-to-many", - "through": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products_tasks", - "type": "link", - "_id": "c3b91d00cd36c4cc1a347794725b9adbd", - "fieldName": "productid", - "throughFrom": "productid", - "throughTo": "taskid" + "table": { + "type": "table", + "_id": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__tasks", + "primary": ["taskid"], + "name": "tasks", + "schema": { + "executorid": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "executorid", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81", - "sourceType": "external", - "primaryDisplay": "taskname", - "sql": true, - "views": {} - } + "taskname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "taskname", + "constraints": { + "presence": false + } + }, + "taskid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "taskid", + "constraints": { + "presence": false + } + }, + "completed": { + "type": "boolean", + "externalType": "boolean", + "autocolumn": false, + "name": "completed", + "constraints": { + "presence": false + } + }, + "qaid": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "qaid", + "constraints": { + "presence": false + } + }, + "products": { + "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products", + "name": "products", + "relationshipType": "many-to-many", + "through": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products_tasks", + "type": "link", + "_id": "c3b91d00cd36c4cc1a347794725b9adbd", + "fieldName": "productid", + "throughFrom": "productid", + "throughTo": "taskid" + } + }, + "sourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81", + "sourceType": "external", + "primaryDisplay": "taskname", + "sql": true, + "views": {} }, "tableAliases": { "tasks": "a", "products": "b", "products_tasks": "c" } -} \ No newline at end of file +} diff --git a/packages/server/src/integrations/tests/sqlQueryJson/fetchManyToMany.json b/packages/server/src/integrations/tests/sqlQueryJson/fetchManyToMany.json index d81c8cf6d0..b746e05c5e 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/fetchManyToMany.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/fetchManyToMany.json @@ -56,48 +56,46 @@ "extra": { "idFilter": {} }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products", - "primary": ["productid"], - "name": "products", - "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_44a967caf37a435f84fe01cd6dfe8f81__tasks", - "name": "tasks", - "relationshipType": "many-to-many", - "fieldName": "taskid", - "through": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products_tasks", - "throughFrom": "taskid", - "throughTo": "productid", - "type": "link", - "main": true, - "_id": "c3b91d00cd36c4cc1a347794725b9adbd" + "table": { + "type": "table", + "_id": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products", + "primary": ["productid"], + "name": "products", + "schema": { + "productname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "productname", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81", - "sourceType": "external", - "primaryDisplay": "productname" - } + "productid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "productid", + "constraints": { + "presence": false + } + }, + "tasks": { + "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__tasks", + "name": "tasks", + "relationshipType": "many-to-many", + "fieldName": "taskid", + "through": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products_tasks", + "throughFrom": "taskid", + "throughTo": "productid", + "type": "link", + "main": true, + "_id": "c3b91d00cd36c4cc1a347794725b9adbd" + } + }, + "sourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81", + "sourceType": "external", + "primaryDisplay": "productname" }, "tableAliases": { "products": "a", diff --git a/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json b/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json index 36010bf61d..6a9717f5dd 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json @@ -46,47 +46,45 @@ "tasks": "b", "products": "a" }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products", - "primary": ["productid"], - "name": "products", - "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" + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products", + "primary": ["productid"], + "name": "products", + "schema": { + "productname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "productname", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - "sourceType": "external", - "primaryDisplay": "productname" - } + "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" } } diff --git a/packages/server/src/integrations/tests/sqlQueryJson/manyRelationshipFilters.json b/packages/server/src/integrations/tests/sqlQueryJson/manyRelationshipFilters.json index 01b85f433f..23f56796a9 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/manyRelationshipFilters.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/manyRelationshipFilters.json @@ -102,94 +102,92 @@ "extra": { "idFilter": {} }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__tasks", - "primary": ["taskid"], - "name": "tasks", - "schema": { - "executorid": { - "type": "number", - "externalType": "integer", - "name": "executorid", - "constraints": { - "presence": false - }, - "autocolumn": true, - "autoReason": "foreign_key" + "table": { + "type": "table", + "_id": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__tasks", + "primary": ["taskid"], + "name": "tasks", + "schema": { + "executorid": { + "type": "number", + "externalType": "integer", + "name": "executorid", + "constraints": { + "presence": false }, - "taskname": { - "type": "string", - "externalType": "character varying", - "autocolumn": false, - "name": "taskname", - "constraints": { - "presence": false - } - }, - "taskid": { - "type": "number", - "externalType": "integer", - "autocolumn": true, - "name": "taskid", - "constraints": { - "presence": false - } - }, - "completed": { - "type": "boolean", - "externalType": "boolean", - "autocolumn": false, - "name": "completed", - "constraints": { - "presence": false - } - }, - "qaid": { - "type": "number", - "externalType": "integer", - "name": "qaid", - "constraints": { - "presence": false - } - }, - "products": { - "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products", - "name": "products", - "relationshipType": "many-to-many", - "through": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products_tasks", - "type": "link", - "_id": "c3b91d00cd36c4cc1a347794725b9adbd", - "fieldName": "productid", - "throughFrom": "productid", - "throughTo": "taskid" - }, - "tasksToExecute": { - "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__persons", - "name": "tasksToExecute", - "relationshipType": "one-to-many", - "type": "link", - "_id": "c0f440590bda04f28846242156c1dd60b", - "foreignKey": "executorid", - "fieldName": "personid" - }, - "tasksToQA": { - "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__persons", - "name": "tasksToQA", - "relationshipType": "one-to-many", - "type": "link", - "_id": "c5fdf453a0ba743d58e29491d174c974b", - "foreignKey": "qaid", - "fieldName": "personid" + "autocolumn": true, + "autoReason": "foreign_key" + }, + "taskname": { + "type": "string", + "externalType": "character varying", + "autocolumn": false, + "name": "taskname", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81", - "sourceType": "external", - "primaryDisplay": "taskname", - "sql": true, - "views": {} - } + "taskid": { + "type": "number", + "externalType": "integer", + "autocolumn": true, + "name": "taskid", + "constraints": { + "presence": false + } + }, + "completed": { + "type": "boolean", + "externalType": "boolean", + "autocolumn": false, + "name": "completed", + "constraints": { + "presence": false + } + }, + "qaid": { + "type": "number", + "externalType": "integer", + "name": "qaid", + "constraints": { + "presence": false + } + }, + "products": { + "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products", + "name": "products", + "relationshipType": "many-to-many", + "through": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__products_tasks", + "type": "link", + "_id": "c3b91d00cd36c4cc1a347794725b9adbd", + "fieldName": "productid", + "throughFrom": "productid", + "throughTo": "taskid" + }, + "tasksToExecute": { + "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__persons", + "name": "tasksToExecute", + "relationshipType": "one-to-many", + "type": "link", + "_id": "c0f440590bda04f28846242156c1dd60b", + "foreignKey": "executorid", + "fieldName": "personid" + }, + "tasksToQA": { + "tableId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81__persons", + "name": "tasksToQA", + "relationshipType": "one-to-many", + "type": "link", + "_id": "c5fdf453a0ba743d58e29491d174c974b", + "foreignKey": "qaid", + "fieldName": "personid" + } + }, + "sourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81", + "sourceType": "external", + "primaryDisplay": "taskname", + "sql": true, + "views": {} }, "tableAliases": { "tasks": "a", diff --git a/packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json b/packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json index 42c2a44335..8171e22c64 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/updateRelationship.json @@ -59,123 +59,114 @@ } } }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", - "primary": [ - "personid" - ], - "name": "persons", - "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" + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": ["personid"], + "name": "persons", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - "sourceType": "external", - "primaryDisplay": "firstname", - "views": {} - } + "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 index 42c2a44335..8171e22c64 100644 --- a/packages/server/src/integrations/tests/sqlQueryJson/updateSimple.json +++ b/packages/server/src/integrations/tests/sqlQueryJson/updateSimple.json @@ -59,123 +59,114 @@ } } }, - "meta": { - "table": { - "type": "table", - "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", - "primary": [ - "personid" - ], - "name": "persons", - "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" + "table": { + "type": "table", + "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__persons", + "primary": ["personid"], + "name": "persons", + "schema": { + "year": { + "type": "number", + "externalType": "integer", + "autocolumn": false, + "name": "year", + "constraints": { + "presence": false } }, - "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7", - "sourceType": "external", - "primaryDisplay": "firstname", - "views": {} - } + "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/sdk/app/rows/search/internal/sqs.ts b/packages/server/src/sdk/app/rows/search/internal/sqs.ts index a160bfbb3e..9bfa0ecd27 100644 --- a/packages/server/src/sdk/app/rows/search/internal/sqs.ts +++ b/packages/server/src/sdk/app/rows/search/internal/sqs.ts @@ -1,8 +1,8 @@ import { Aggregation, CalculationType, - Datasource, DocumentType, + EnrichedQueryJson, FieldType, isLogicalSearchOperator, Operation, @@ -38,7 +38,7 @@ import { generateJunctionTableID } from "../../../../../db/utils" import AliasTables from "../../sqlAlias" import { outputProcessing } from "../../../../../utilities/rowProcessor" import pick from "lodash/pick" -import { processRowCountResponse } from "../../utils" +import { enrichQueryJson, processRowCountResponse } from "../../utils" import { dataFilters, helpers, @@ -180,19 +180,6 @@ function cleanupFilters(filters: SearchFilters, allTables: Table[]) { return filters } -function buildTableMap(tables: Table[]) { - const tableMap: Record = {} - for (let table of tables) { - // update the table name, should never query by name for SQLite - table.originalName = table.name - table.name = table._id! - // need a primary for sorting, lookups etc - table.primary = ["_id"] - tableMap[table._id!] = table - } - return tableMap -} - // table is only needed to handle relationships function reverseUserColumnMapping(rows: Row[], table?: Table) { const prefixLength = USER_COLUMN_PREFIX.length @@ -223,30 +210,30 @@ function reverseUserColumnMapping(rows: Row[], table?: Table) { } function runSqlQuery( - json: QueryJson, + json: EnrichedQueryJson, tables: Table[], relationships: RelationshipsJson[] ): Promise function runSqlQuery( - json: QueryJson, + json: EnrichedQueryJson, tables: Table[], relationships: RelationshipsJson[], opts: { countTotalRows: true } ): Promise async function runSqlQuery( - json: QueryJson, + json: EnrichedQueryJson, tables: Table[], relationships: RelationshipsJson[], opts?: { countTotalRows?: boolean } ) { const relationshipJunctionTableIds = relationships.map(rel => rel.through!) const alias = new AliasTables( - tables.map(table => table.name).concat(relationshipJunctionTableIds) + tables.map(table => table._id!).concat(relationshipJunctionTableIds) ) if (opts?.countTotalRows) { json.endpoint.operation = Operation.COUNT } - const processSQLQuery = async (_: Datasource, json: QueryJson) => { + const processSQLQuery = async (json: EnrichedQueryJson) => { const query = builder._query(json, { disableReturning: true, }) @@ -281,7 +268,7 @@ async function runSqlQuery( if (opts?.countTotalRows) { return processRowCountResponse(response) } else if (Array.isArray(response)) { - return reverseUserColumnMapping(response, json.meta.table) + return reverseUserColumnMapping(response, json.table) } return response } @@ -315,7 +302,11 @@ export async function search( } const allTables = await sdk.tables.getAllInternalTables() - const allTablesMap = buildTableMap(allTables) + const allTablesMap = allTables.reduce((acc, table) => { + acc[table._id!] = table + return acc + }, {} as Record) + // make sure we have the mapped/latest table if (table._id) { table = allTablesMap[table._id] @@ -372,10 +363,7 @@ export async function search( operation: Operation.READ, }, filters: searchFilters, - table, meta: { - table, - tables: allTablesMap, columnPrefix: USER_COLUMN_PREFIX, }, resource: { @@ -427,11 +415,13 @@ export async function search( } } + const enrichedRequest = await enrichQueryJson(request) + try { const [rows, totalRows] = await Promise.all([ - runSqlQuery(request, allTables, relationships), + runSqlQuery(enrichedRequest, allTables, relationships), options.countRows - ? runSqlQuery(request, allTables, relationships, { + ? runSqlQuery(enrichedRequest, allTables, relationships, { countTotalRows: true, }) : Promise.resolve(undefined), diff --git a/packages/server/src/sdk/app/rows/sqlAlias.ts b/packages/server/src/sdk/app/rows/sqlAlias.ts index 535709791d..62e0db9aad 100644 --- a/packages/server/src/sdk/app/rows/sqlAlias.ts +++ b/packages/server/src/sdk/app/rows/sqlAlias.ts @@ -1,22 +1,20 @@ import { Datasource, DatasourcePlusQueryResponse, + EnrichedQueryJson, Operation, QueryJson, Row, SearchFilters, SqlClient, + Table, } from "@budibase/types" -import { SQS_DATASOURCE_INTERNAL } from "@budibase/backend-core" import { getSQLClient } from "./utils" import { cloneDeep } from "lodash" -import datasources from "../datasources" -import { BudibaseInternalDB } from "../../../db/utils" import { dataFilters } from "@budibase/shared-core" type PerformQueryFunction = ( - datasource: Datasource, - json: QueryJson + json: EnrichedQueryJson ) => Promise const WRITE_OPERATIONS: Operation[] = [ @@ -99,7 +97,11 @@ export default class AliasTables { return true } - getAlias(tableName: string) { + getAlias(tableName: string | Table) { + if (typeof tableName === "object") { + tableName = tableName.name + } + if (this.aliases[tableName]) { return this.aliases[tableName] } @@ -177,17 +179,15 @@ export default class AliasTables { } async queryWithAliasing( - json: QueryJson, + json: EnrichedQueryJson, queryFn: PerformQueryFunction ): Promise { - const datasourceId = json.endpoint.datasourceId - const isSqs = datasourceId === SQS_DATASOURCE_INTERNAL - let aliasingEnabled: boolean, datasource: Datasource + const datasource = json.datasource + const isSqs = datasource === undefined + let aliasingEnabled: boolean if (isSqs) { aliasingEnabled = this.isAliasingEnabled(json) - datasource = BudibaseInternalDB } else { - datasource = await datasources.get(datasourceId) aliasingEnabled = this.isAliasingEnabled(json, datasource) } @@ -215,24 +215,23 @@ export default class AliasTables { } json.filters = aliasFilters(json.filters) } - if (json.meta?.table) { - this.getAlias(json.meta.table.name) - } - if (json.meta?.tables) { - Object.keys(json.meta.tables).forEach(tableName => - this.getAlias(tableName) - ) - } + if (json.relationships) { json.relationships = json.relationships.map(relationship => ({ ...relationship, aliases: this.aliasMap([ relationship.through, relationship.tableName, - json.endpoint.entityId, + json.table.name, ]), })) } + + this.getAlias(json.table) + for (const tableName of Object.keys(json.tables)) { + this.getAlias(tableName) + } + // invert and return const invertedTableAliases: Record = {} for (let [key, value] of Object.entries(this.tableAliases)) { @@ -241,7 +240,7 @@ export default class AliasTables { json.tableAliases = invertedTableAliases } - let response: DatasourcePlusQueryResponse = await queryFn(datasource, json) + let response = await queryFn(json) if (Array.isArray(response) && aliasingEnabled) { return this.reverse(response) } else { diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index bded6a7a18..977cdb9bd2 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -14,13 +14,13 @@ import { SqlClient, ArrayOperator, ViewV2, + EnrichedQueryJson, } from "@budibase/types" -import { makeExternalQuery } from "../../../integrations/base/query" import { Format } from "../../../api/controllers/view/exporters" import sdk from "../.." import { extractViewInfoFromID, isRelationshipColumn } from "../../../db/utils" import { isSQL } from "../../../integrations/utils" -import { docIds, sql } from "@budibase/backend-core" +import { docIds, sql, SQS_DATASOURCE_INTERNAL } from "@budibase/backend-core" import { getTableFromSource } from "../../../api/controllers/row/utils" import env from "../../../environment" @@ -73,18 +73,56 @@ export function processRowCountResponse( } } -export async function getDatasourceAndQuery( - json: QueryJson -): Promise { - const datasourceId = json.endpoint.datasourceId - const datasource = await sdk.datasources.get(datasourceId) - const table = datasource.entities?.[json.endpoint.entityId] - if (!json.meta && table) { - json.meta = { - table, - } +function processInternalTables(tables: Table[]) { + const tableMap: Record = {} + for (let table of tables) { + // update the table name, should never query by name for SQLite + table.originalName = table.name + table.name = table._id! + tableMap[table._id!] = table + } + return tableMap +} + +export async function enrichQueryJson( + json: QueryJson +): Promise { + let datasource: Datasource | undefined = undefined + + if (typeof json.endpoint.datasourceId === "string") { + if (json.endpoint.datasourceId !== SQS_DATASOURCE_INTERNAL) { + datasource = await sdk.datasources.get(json.endpoint.datasourceId, { + enriched: true, + }) + } + } else { + datasource = json.endpoint.datasourceId + } + + let tables: Record + if (datasource) { + tables = datasource.entities || {} + } else { + tables = processInternalTables(await sdk.tables.getAllInternalTables()) + } + + let table: Table + if (typeof json.endpoint.entityId === "string") { + let entityId = json.endpoint.entityId + if (docIds.isDatasourceId(entityId)) { + entityId = sql.utils.breakExternalTableId(entityId).tableName + } + table = tables[entityId] + } else { + table = json.endpoint.entityId + } + + return { + table, + tables, + datasource, + ...json, } - return makeExternalQuery(datasource, json) } export function cleanExportRows( diff --git a/packages/server/src/sdk/app/tables/external/index.ts b/packages/server/src/sdk/app/tables/external/index.ts index 941d193b94..3eaf146793 100644 --- a/packages/server/src/sdk/app/tables/external/index.ts +++ b/packages/server/src/sdk/app/tables/external/index.ts @@ -245,7 +245,6 @@ export async function save( datasource, operation, tableToSave, - tables, oldTable, opts?.renaming ) @@ -253,7 +252,7 @@ export async function save( for (let extraTable of extraTablesToUpdate) { const oldExtraTable = oldTables[extraTable.name] let op = oldExtraTable ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE - await makeTableRequest(datasource, op, extraTable, tables, oldExtraTable) + await makeTableRequest(datasource, op, extraTable, oldExtraTable) } // make sure the constrained list, all still exist @@ -292,7 +291,7 @@ export async function destroy(datasourceId: string, table: Table) { const operation = Operation.DELETE_TABLE if (tables) { - await makeTableRequest(datasource, operation, table, tables) + await makeTableRequest(datasource, operation, table) cleanupRelationships(table, tables, { deleting: true }) delete tables[table.name] datasource.entities = tables diff --git a/packages/server/src/sdk/app/tables/getters.ts b/packages/server/src/sdk/app/tables/getters.ts index 1ad82b8e42..79091ea660 100644 --- a/packages/server/src/sdk/app/tables/getters.ts +++ b/packages/server/src/sdk/app/tables/getters.ts @@ -46,6 +46,7 @@ export async function processTable(table: Table): Promise
{ const processed: Table = { ...table, type: "table", + primary: ["_id"], // internal tables must always use _id as primary key sourceId: table.sourceId || INTERNAL_TABLE_SOURCE_ID, sourceType: TableSourceType.INTERNAL, sql: true, diff --git a/packages/server/src/tests/utilities/api/datasource.ts b/packages/server/src/tests/utilities/api/datasource.ts index 67484a688a..f4adaefa24 100644 --- a/packages/server/src/tests/utilities/api/datasource.ts +++ b/packages/server/src/tests/utilities/api/datasource.ts @@ -1,14 +1,17 @@ import { - Datasource, - VerifyDatasourceRequest, - CreateDatasourceResponse, - UpdateDatasourceResponse, - UpdateDatasourceRequest, - QueryJson, BuildSchemaFromSourceResponse, + CreateDatasourceResponse, + Datasource, FetchDatasourceInfoResponse, + FieldType, + QueryJsonRequest, + RelationshipType, + UpdateDatasourceRequest, + UpdateDatasourceResponse, + VerifyDatasourceRequest, } from "@budibase/types" import { Expectations, TestAPI } from "./base" +import { sql } from "@budibase/backend-core" export class DatasourceAPI extends TestAPI { create = async ( @@ -66,10 +69,7 @@ export class DatasourceAPI extends TestAPI { return await this._get(`/api/datasources`, { expectations }) } - query = async ( - query: Omit & Partial>, - expectations?: Expectations - ) => { + query = async (query: QueryJsonRequest, expectations?: Expectations) => { return await this._post(`/api/datasources/query`, { body: query, expectations, @@ -103,4 +103,50 @@ export class DatasourceAPI extends TestAPI { } ) } + + addExistingRelationship = async ( + { + one, + many, + }: { + one: { tableId: string; relationshipName: string; foreignKey: string } + many: { tableId: string; relationshipName: string; primaryKey: string } + }, + expectations?: Expectations + ) => { + const oneTableInfo = sql.utils.breakExternalTableId(one.tableId), + manyTableInfo = sql.utils.breakExternalTableId(many.tableId) + if (oneTableInfo.datasourceId !== manyTableInfo.datasourceId) { + throw new Error( + "Tables are in different datasources, cannot create relationship." + ) + } + const datasource = await this.get(oneTableInfo.datasourceId) + const oneTable = datasource.entities?.[oneTableInfo.tableName], + manyTable = datasource.entities?.[manyTableInfo.tableName] + if (!oneTable || !manyTable) { + throw new Error( + "Both tables not found in datasource, cannot create relationship." + ) + } + + manyTable.schema[many.relationshipName] = { + type: FieldType.LINK, + name: many.relationshipName, + tableId: oneTable._id!, + relationshipType: RelationshipType.MANY_TO_ONE, + fieldName: one.foreignKey, + foreignKey: many.primaryKey, + main: true, + } + oneTable.schema[one.relationshipName] = { + type: FieldType.LINK, + name: one.relationshipName, + tableId: manyTable._id!, + relationshipType: RelationshipType.ONE_TO_MANY, + fieldName: many.primaryKey, + foreignKey: one.foreignKey, + } + return await this.update(datasource, expectations) + } } diff --git a/packages/types/src/documents/global/quotas.ts b/packages/types/src/documents/global/quotas.ts index 4726dabf0d..a24fc8f9b0 100644 --- a/packages/types/src/documents/global/quotas.ts +++ b/packages/types/src/documents/global/quotas.ts @@ -44,7 +44,6 @@ export interface StaticUsage { export interface MonthlyUsage { [MonthlyQuotaName.QUERIES]: number [MonthlyQuotaName.AUTOMATIONS]: number - [MonthlyQuotaName.DAY_PASSES]: number [MonthlyQuotaName.BUDIBASE_AI_CREDITS]: number triggers: { [key in MonthlyQuotaName]?: QuotaTriggers diff --git a/packages/types/src/documents/global/user.ts b/packages/types/src/documents/global/user.ts index 1b242886b5..529223e88d 100644 --- a/packages/types/src/documents/global/user.ts +++ b/packages/types/src/documents/global/user.ts @@ -62,7 +62,6 @@ export interface User extends Document { password?: string status?: UserStatus createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now() - dayPassRecordedAt?: string userGroups?: string[] onboardedAt?: string freeTrialConfirmedAt?: string diff --git a/packages/types/src/sdk/datasources.ts b/packages/types/src/sdk/datasources.ts index bdad9c4825..8b0574bd7c 100644 --- a/packages/types/src/sdk/datasources.ts +++ b/packages/types/src/sdk/datasources.ts @@ -1,5 +1,5 @@ import { Table, Row } from "../documents" -import { QueryJson } from "./search" +import { EnrichedQueryJson } from "./search" export const PASSWORD_REPLACEMENT = "--secret-value--" @@ -207,7 +207,7 @@ export interface DatasourcePlus extends IntegrationBase { // this returns the format of the identifier getBindingIdentifier(): string getStringConcat(parts: string[]): string - query(json: QueryJson): Promise + query(json: EnrichedQueryJson): Promise buildSchema( datasourceId: string, entities: Record diff --git a/packages/types/src/sdk/licensing/plan.ts b/packages/types/src/sdk/licensing/plan.ts index af682cbad1..8cdd72dd5d 100644 --- a/packages/types/src/sdk/licensing/plan.ts +++ b/packages/types/src/sdk/licensing/plan.ts @@ -38,7 +38,6 @@ export interface AvailablePrice { export enum PlanModel { PER_USER = "perUser", PER_CREATOR_PER_USER = "per_creator_per_user", - DAY_PASS = "dayPass", } export interface PurchasedPlan { @@ -49,7 +48,6 @@ export interface PurchasedPlan { } export interface PurchasedPrice extends AvailablePrice { - dayPasses: number | undefined /** @deprecated - now at the plan level via model */ isPerUser: boolean } diff --git a/packages/types/src/sdk/licensing/quota.ts b/packages/types/src/sdk/licensing/quota.ts index 75fc18e8e6..ed541d2974 100644 --- a/packages/types/src/sdk/licensing/quota.ts +++ b/packages/types/src/sdk/licensing/quota.ts @@ -23,7 +23,6 @@ export enum StaticQuotaName { export enum MonthlyQuotaName { QUERIES = "queries", AUTOMATIONS = "automations", - DAY_PASSES = "dayPasses", BUDIBASE_AI_CREDITS = "budibaseAICredits", } @@ -63,7 +62,6 @@ export type PlanQuotas = { [key in PlanType]: Quotas | undefined } export type MonthlyQuotas = { [MonthlyQuotaName.QUERIES]: Quota [MonthlyQuotaName.AUTOMATIONS]: Quota - [MonthlyQuotaName.DAY_PASSES]: Quota [MonthlyQuotaName.BUDIBASE_AI_CREDITS]: Quota } diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts index d6dcb0a2fa..e25390bdd0 100644 --- a/packages/types/src/sdk/search.ts +++ b/packages/types/src/sdk/search.ts @@ -1,5 +1,5 @@ import { Operation } from "./datasources" -import { Row, Table, DocumentType } from "../documents" +import { Row, DocumentType, Table, Datasource } from "../documents" import { SortOrder, SortType } from "../api" import { Knex } from "knex" import { Aggregation } from "./row" @@ -158,8 +158,8 @@ export interface ManyToManyRelationshipJson { export interface QueryJson { endpoint: { - datasourceId: string - entityId: string + datasourceId: string | Datasource + entityId: string | Table operation: Operation schema?: string } @@ -171,11 +171,9 @@ export interface QueryJson { sort?: SortJson paginate?: PaginationJson body?: Row | Row[] - table?: Table - meta: { - table: Table - tables?: Record + meta?: { renamed?: RenameColumn + oldTable?: Table // can specify something that columns could be prefixed with columnPrefix?: string } @@ -186,6 +184,16 @@ export interface QueryJson { tableAliases?: Record } +export interface EnrichedQueryJson extends QueryJson { + table: Table + tables: Record + datasource?: Datasource +} + +export interface QueryJsonRequest extends Omit { + endpoint: QueryJson["endpoint"] & { datasourceId: string; entityId: string } +} + export interface QueryOptions { disableReturning?: boolean disableBindings?: boolean diff --git a/packages/worker/src/api/routes/global/tests/self.spec.ts b/packages/worker/src/api/routes/global/tests/self.spec.ts index 277c11b081..bf34f14aa0 100644 --- a/packages/worker/src/api/routes/global/tests/self.spec.ts +++ b/packages/worker/src/api/routes/global/tests/self.spec.ts @@ -1,5 +1,5 @@ jest.mock("nodemailer") -import { TestConfiguration, mocks } from "../../../../tests" +import { TestConfiguration } from "../../../../tests" import { events } from "@budibase/backend-core" describe("/api/global/self", () => { @@ -39,7 +39,6 @@ describe("/api/global/self", () => { const dbUser = (await config.getUser(user.email))! user._rev = dbUser._rev - user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString() expect(res.body._id).toBe(user._id) expect(events.user.updated).toHaveBeenCalledTimes(1) expect(events.user.updated).toHaveBeenCalledWith(dbUser) @@ -62,7 +61,6 @@ describe("/api/global/self", () => { const dbUser = (await config.getUser(user.email))! user._rev = dbUser._rev - user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString() expect(dbUser.onboardedAt).toBe("2023-03-07T14:10:54.869Z") expect(dbUser.freeTrialConfirmedAt).toBe("2024-03-17T14:10:54.869Z") expect(res.body._id).toBe(user._id) diff --git a/yarn.lock b/yarn.lock index dd01832bba..f52cdc79a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2196,7 +2196,7 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@3.2.11": +"@budibase/backend-core@3.2.14": version "0.0.0" dependencies: "@budibase/nano" "10.1.5" @@ -2280,18 +2280,18 @@ through2 "^2.0.0" "@budibase/pro@npm:@budibase/pro@latest": - version "3.2.11" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.11.tgz#40d4929b3958dacca3f4c207718a4647c08a6100" - integrity sha512-xE1tx/C2cnbyR4s/6XkkweoQw6CW5fsQt++gzrrML8abgsODru+tA7M2NbWlKsEnVWHDQRvUVcXm4wqDeNNZ9g== + version "3.2.14" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.14.tgz#2ea1ef4372803304ac3a06ce77620ce54a09dd02" + integrity sha512-ski7NeXOdDIjC0vapo+hxr8/VnbDhmOLF5TdvoLBgviMk7ij2rNPI2dNs+6kQuVXAEVJPD6bJ4Ke0z2d5YcYrQ== dependencies: "@anthropic-ai/sdk" "^0.27.3" - "@budibase/backend-core" "3.2.11" - "@budibase/shared-core" "3.2.11" - "@budibase/string-templates" "3.2.11" - "@budibase/types" "3.2.11" + "@budibase/backend-core" "3.2.14" + "@budibase/shared-core" "3.2.14" + "@budibase/string-templates" "3.2.14" + "@budibase/types" "3.2.14" "@koa/router" "13.1.0" bull "4.10.1" - dd-trace "5.23.0" + dd-trace "5.26.0" joi "17.6.0" jsonwebtoken "9.0.2" lru-cache "^7.14.1" @@ -2301,13 +2301,13 @@ scim-patch "^0.8.1" scim2-parse-filter "^0.2.8" -"@budibase/shared-core@3.2.11": +"@budibase/shared-core@3.2.14": version "0.0.0" dependencies: "@budibase/types" "0.0.0" cron-validate "1.4.5" -"@budibase/string-templates@3.2.11": +"@budibase/string-templates@3.2.14": version "0.0.0" dependencies: "@budibase/handlebars-helpers" "^0.13.2" @@ -2315,7 +2315,7 @@ handlebars "^4.7.8" lodash.clonedeep "^4.5.0" -"@budibase/types@3.2.11": +"@budibase/types@3.2.14": version "0.0.0" dependencies: scim-patch "^0.8.1" @@ -2482,13 +2482,6 @@ resolved "https://registry.yarnpkg.com/@datadog/libdatadog/-/libdatadog-0.2.2.tgz#ac02c76ac9a38250dca740727c7cdf00244ce3d3" integrity sha512-rTWo96mEPTY5UbtGoFj8/wY0uKSViJhsPg/Z6aoFWBFXQ8b45Ix2e/yvf92AAwrhG+gPLTxEqTXh3kef2dP8Ow== -"@datadog/native-appsec@8.1.1": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.1.1.tgz#76aa34697e6ecbd3d9ef7e6938d3cdcfa689b1f3" - integrity sha512-mf+Ym/AzET4FeUTXOs8hz0uLOSsVIUnavZPUx8YoKWK5lKgR2L+CLfEzOpjBwgFpDgbV8I1/vyoGelgGpsMKHA== - dependencies: - node-gyp-build "^3.9.0" - "@datadog/native-appsec@8.3.0": version "8.3.0" resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.3.0.tgz#91afd89d18d386be4da8a1b0e04500f2f8b5eb66" @@ -2496,14 +2489,6 @@ dependencies: node-gyp-build "^3.9.0" -"@datadog/native-iast-rewriter@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@datadog/native-iast-rewriter/-/native-iast-rewriter-2.4.1.tgz#e8211f78c818906513fb96a549374da0382c7623" - integrity sha512-j3auTmyyn63e2y+SL28CGNy/l+jXQyh+pxqoGTacWaY5FW/dvo5nGQepAismgJ3qJ8VhQfVWRdxBSiT7wu9clw== - dependencies: - lru-cache "^7.14.0" - node-gyp-build "^4.5.0" - "@datadog/native-iast-rewriter@2.5.0": version "2.5.0" resolved "https://registry.yarnpkg.com/@datadog/native-iast-rewriter/-/native-iast-rewriter-2.5.0.tgz#b613defe86e78168f750d1f1662d4ffb3cf002e6" @@ -2512,13 +2497,6 @@ lru-cache "^7.14.0" node-gyp-build "^4.5.0" -"@datadog/native-iast-taint-tracking@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-3.1.0.tgz#7b2ed7f8fad212d65e5ab03bcdea8b42a3051b2e" - integrity sha512-rw6qSjmxmu1yFHVvZLXFt/rVq2tUZXocNogPLB8n7MPpA0jijNGb109WokWw5ITImiW91GcGDuBW6elJDVKouQ== - dependencies: - node-gyp-build "^3.9.0" - "@datadog/native-iast-taint-tracking@3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-3.2.0.tgz#9fb6823d82f934e12c06ea1baa7399ca80deb2ec" @@ -2526,14 +2504,6 @@ dependencies: node-gyp-build "^3.9.0" -"@datadog/native-metrics@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@datadog/native-metrics/-/native-metrics-2.0.0.tgz#65bf03313ee419956361e097551db36173e85712" - integrity sha512-YklGVwUtmKGYqFf1MNZuOHvTYdKuR4+Af1XkWcMD8BwOAjxmd9Z+97328rCOY8TFUJzlGUPaXzB8j2qgG/BMwA== - dependencies: - node-addon-api "^6.1.0" - node-gyp-build "^3.9.0" - "@datadog/native-metrics@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@datadog/native-metrics/-/native-metrics-3.0.1.tgz#dc276c93785c0377a048e316f23b7c8ff3acfa84" @@ -2542,17 +2512,6 @@ node-addon-api "^6.1.0" node-gyp-build "^3.9.0" -"@datadog/pprof@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219" - integrity sha512-53z2Q3K92T6Pf4vz4Ezh8kfkVEvLzbnVqacZGgcbkP//q0joFzO8q00Etw1S6NdnCX0XmX08ULaF4rUI5r14mw== - dependencies: - delay "^5.0.0" - node-gyp-build "<4.0" - p-limit "^3.1.0" - pprof-format "^2.1.0" - source-map "^0.7.4" - "@datadog/pprof@5.4.1": version "5.4.1" resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.4.1.tgz#08c9bcf5d8efb2eeafdfc9f5bb5402f79fb41266" @@ -3469,16 +3428,6 @@ resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== -"@jsep-plugin/assignment@^1.2.1": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@jsep-plugin/assignment/-/assignment-1.3.0.tgz#fcfc5417a04933f7ceee786e8ab498aa3ce2b242" - integrity sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ== - -"@jsep-plugin/regex@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@jsep-plugin/regex/-/regex-1.0.4.tgz#cb2fc423220fa71c609323b9ba7f7d344a755fcc" - integrity sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg== - "@koa/cors@5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-5.0.0.tgz#0029b5f057fa0d0ae0e37dd2c89ece315a0daffd" @@ -4075,14 +4024,7 @@ resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.4.tgz#af85eb080f6934580e4d3b58046026b6c2b18717" integrity sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng== -"@rollup/plugin-alias@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-alias/-/plugin-alias-5.1.0.tgz#99a94accc4ff9a3483be5baeedd5d7da3b597e93" - integrity sha512-lpA3RZ9PdIG7qqhEfv79tBffNaoDuukFDrmhLqg9ifv99u/ehn+lOg30x2zmhf8AQqQUZaMk/B9fZraQ6/acDQ== - dependencies: - slash "^4.0.0" - -"@rollup/plugin-commonjs@16.0.0", "@rollup/plugin-commonjs@^16.0.0": +"@rollup/plugin-commonjs@^16.0.0": version "16.0.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f" integrity sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw== @@ -4120,14 +4062,6 @@ is-reference "1.2.1" magic-string "^0.30.3" -"@rollup/plugin-image@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@rollup/plugin-image/-/plugin-image-3.0.3.tgz#025b557180bae20f2349ff5130ef2114169feaac" - integrity sha512-qXWQwsXpvD4trSb8PeFPFajp8JLpRtqqOeNYRUKnEQNHm7e5UP7fuSRcbjQAJ7wDZBbnJvSdY5ujNBQd9B1iFg== - dependencies: - "@rollup/pluginutils" "^5.0.1" - mini-svg-data-uri "^1.4.4" - "@rollup/plugin-inject@^5.0.4", "@rollup/plugin-inject@^5.0.5": version "5.0.5" resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz#616f3a73fe075765f91c5bec90176608bed277a3" @@ -4168,7 +4102,7 @@ is-module "^1.0.0" resolve "^1.22.1" -"@rollup/plugin-replace@^5.0.2", "@rollup/plugin-replace@^5.0.3": +"@rollup/plugin-replace@^5.0.3": version "5.0.7" resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz#150c9ee9db8031d9e4580a61a0edeaaed3d37687" integrity sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ== @@ -9336,43 +9270,6 @@ dc-polyfill@^0.1.4: resolved "https://registry.yarnpkg.com/dc-polyfill/-/dc-polyfill-0.1.6.tgz#c2940fa68ffb24a7bf127cc6cfdd15b39f0e7f02" integrity sha512-UV33cugmCC49a5uWAApM+6Ev9ZdvIUMTrtCO9fj96TPGOQiea54oeO3tiEVdVeo3J9N2UdJEmbS4zOkkEA35uQ== -dd-trace@5.23.0: - version "5.23.0" - resolved "https://registry.yarnpkg.com/dd-trace/-/dd-trace-5.23.0.tgz#a0c11863406de440a6675648caf06e1d07d67ba8" - integrity sha512-nLvwSGpTMIk6S3sMSge6yFqqgqI573VgZc8MF31vl6K0ouJoE7OkVx9cmSVjS4CbSi525tcKq9z7tApsNLpVLQ== - dependencies: - "@datadog/native-appsec" "8.1.1" - "@datadog/native-iast-rewriter" "2.4.1" - "@datadog/native-iast-taint-tracking" "3.1.0" - "@datadog/native-metrics" "^2.0.0" - "@datadog/pprof" "5.3.0" - "@datadog/sketches-js" "^2.1.0" - "@opentelemetry/api" ">=1.0.0 <1.9.0" - "@opentelemetry/core" "^1.14.0" - crypto-randomuuid "^1.0.0" - dc-polyfill "^0.1.4" - ignore "^5.2.4" - import-in-the-middle "1.11.2" - int64-buffer "^0.1.9" - istanbul-lib-coverage "3.2.0" - jest-docblock "^29.7.0" - jsonpath-plus "^9.0.0" - koalas "^1.0.2" - limiter "1.1.5" - lodash.sortby "^4.7.0" - lru-cache "^7.14.0" - module-details-from-path "^1.0.3" - msgpack-lite "^0.1.26" - opentracing ">=0.12.1" - path-to-regexp "^0.1.10" - pprof-format "^2.1.0" - protobufjs "^7.2.5" - retry "^0.13.1" - rfdc "^1.3.1" - semver "^7.5.4" - shell-quote "^1.8.1" - tlhunter-sorted-set "^0.1.0" - dd-trace@5.26.0: version "5.26.0" resolved "https://registry.yarnpkg.com/dd-trace/-/dd-trace-5.26.0.tgz#cc55061f66742bf01d0d7dc9f75c0e4937c82f40" @@ -10885,11 +10782,6 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.2.1.tgz#bdafe8095383d8414d5dc2ecf4c9173b6db9412e" - integrity sha512-6/I1dwNKk0N9iGOU3ydzAAurz4NPo/ttxZNCqgIVbWFvWyzWBSNonRrJ5CpjDuyBfmM7ENN7WCzUi9aT/UPXXQ== - estree-walker@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" @@ -14148,11 +14040,6 @@ jsdom@^21.1.1: ws "^8.13.0" xml-name-validator "^4.0.0" -jsep@^1.3.8: - version "1.4.0" - resolved "https://registry.yarnpkg.com/jsep/-/jsep-1.4.0.tgz#19feccbfa51d8a79f72480b4b8e40ce2e17152f0" - integrity sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -14256,15 +14143,6 @@ jsonparse@^1.2.0, jsonparse@^1.3.1: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -jsonpath-plus@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/jsonpath-plus/-/jsonpath-plus-9.0.0.tgz#bb8703ee481531142bca8dee9a42fe72b8358a7f" - integrity sha512-bqE77VIDStrOTV/czspZhTn+o27Xx9ZJRGVkdVShEtPoqsIx5yALv3lWVU6y+PqYvWPJNWE7ORCQheQkEe0DDA== - dependencies: - "@jsep-plugin/assignment" "^1.2.1" - "@jsep-plugin/regex" "^1.0.3" - jsep "^1.3.8" - jsonschema@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" @@ -15653,11 +15531,6 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -mini-svg-data-uri@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" - integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -15668,7 +15541,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +"minimatch@2 || 3", minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -17924,7 +17797,7 @@ postcss-values-parser@^6.0.2: is-url-superb "^4.0.0" quote-unquote "^1.0.0" -postcss@^8.1.7, postcss@^8.2.9, postcss@^8.3.11, postcss@^8.4.12, postcss@^8.4.27, postcss@^8.4.29, postcss@^8.4.35, postcss@^8.4.5: +postcss@^8.1.7, postcss@^8.2.9, postcss@^8.3.11, postcss@^8.4.12, postcss@^8.4.27, postcss@^8.4.29, postcss@^8.4.5: version "8.4.41" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== @@ -19245,13 +19118,6 @@ rollup-plugin-inject-process-env@^1.3.1: dependencies: magic-string "^0.25.7" -rollup-plugin-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz#a18da0a4b30bf5ca1ee76ddb1422afbb84ae2b9e" - integrity sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow== - dependencies: - rollup-pluginutils "^2.5.0" - rollup-plugin-node-builtins@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/rollup-plugin-node-builtins/-/rollup-plugin-node-builtins-2.1.2.tgz#24a1fed4a43257b6b64371d8abc6ce1ab14597e9" @@ -19292,7 +19158,7 @@ rollup-plugin-polyfill-node@^0.13.0: dependencies: "@rollup/plugin-inject" "^5.0.4" -rollup-plugin-postcss@^4.0.0, rollup-plugin-postcss@^4.0.2: +rollup-plugin-postcss@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/rollup-plugin-postcss/-/rollup-plugin-postcss-4.0.2.tgz#15e9462f39475059b368ce0e49c800fa4b1f7050" integrity sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w== @@ -19311,7 +19177,7 @@ rollup-plugin-postcss@^4.0.0, rollup-plugin-postcss@^4.0.2: safe-identifier "^0.4.2" style-inject "^0.3.0" -rollup-plugin-svelte@^7.1.0, rollup-plugin-svelte@^7.1.6: +rollup-plugin-svelte@^7.1.0: version "7.1.6" resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.6.tgz#44a4ea6c6e8ed976824d9fd40c78d048515e5838" integrity sha512-nVFRBpGWI2qUY1OcSiEEA/kjCY2+vAjO9BI8SzA7NRrh2GTunLd6w2EYmnMt/atgdg8GvcNjLsmZmbQs/u4SQA== @@ -19319,13 +19185,6 @@ rollup-plugin-svelte@^7.1.0, rollup-plugin-svelte@^7.1.6: "@rollup/pluginutils" "^4.1.0" resolve.exports "^2.0.0" -rollup-plugin-svg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-svg/-/rollup-plugin-svg-2.0.0.tgz#ce11b55e915d5b2190328c4e6632bd6b4fe12ee9" - integrity sha512-DmE7dSQHo1SC5L2uH2qul3Mjyd5oV6U1aVVkyvTLX/mUsRink7f1b1zaIm+32GEBA6EHu8H/JJi3DdWqM53ySQ== - dependencies: - rollup-pluginutils "^1.3.1" - rollup-plugin-terser@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" @@ -19336,30 +19195,12 @@ rollup-plugin-terser@^7.0.2: serialize-javascript "^4.0.0" terser "^5.0.0" -rollup-plugin-visualizer@^5.12.0: - version "5.12.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz#661542191ce78ee4f378995297260d0c1efb1302" - integrity sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ== - dependencies: - open "^8.4.0" - picomatch "^2.3.1" - source-map "^0.7.4" - yargs "^17.5.1" - rollup-plugin-web-worker-loader@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/rollup-plugin-web-worker-loader/-/rollup-plugin-web-worker-loader-1.6.1.tgz#9d7a27575b64b0780fe4e8b3bc87470d217e485f" integrity sha512-4QywQSz1NXFHKdyiou16mH3ijpcfLtLGOrAqvAqu1Gx+P8+zj+3gwC2BSL/VW1d+LW4nIHC8F7d7OXhs9UdR2A== -rollup-pluginutils@^1.3.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408" - integrity sha512-SjdWWWO/CUoMpDy8RUbZ/pSpG68YHmhk5ROKNIoi2En9bJ8bTt3IhYi254RWiTclQmL7Awmrq+rZFOhZkJAHmQ== - dependencies: - estree-walker "^0.2.1" - minimatch "^3.0.2" - -rollup-pluginutils@^2.3.1, rollup-pluginutils@^2.5.0, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: +rollup-pluginutils@^2.3.1, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== @@ -19817,11 +19658,6 @@ slash@3.0.0, slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== - slice-ansi@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" @@ -21897,6 +21733,11 @@ vite-node@0.29.8: picocolors "^1.0.0" vite "^3.0.0 || ^4.0.0" +vite-plugin-css-injected-by-js@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.2.tgz#1f75d16ad5c05b6b49bf18018099a189ec2e46ad" + integrity sha512-2MpU/Y+SCZyWUB6ua3HbJCrgnF0KACAsmzOQt1UvRVJCGF6S8xdA3ZUhWcWdM9ivG4I5az8PnQmwwrkC2CAQrQ== + vite-plugin-static-copy@^0.17.0: version "0.17.0" resolved "https://registry.yarnpkg.com/vite-plugin-static-copy/-/vite-plugin-static-copy-0.17.0.tgz#e45527da186c4a3818d09635797b6fc7cc9e035f" @@ -22534,7 +22375,7 @@ yargs@16.2.0, yargs@^16.1.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.3.1, yargs@^17.5.1, yargs@^17.6.2, yargs@^17.7.2: +yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==