Merge branch 'master' into BUDI-8270/validation-for-search-api
This commit is contained in:
commit
47898d315d
|
@ -281,6 +281,7 @@ jobs:
|
|||
|
||||
check-lockfile:
|
||||
runs-on: ubuntu-latest
|
||||
if: inputs.run_as_oss != true && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase')
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
|
|
@ -6,6 +6,26 @@ import {
|
|||
import { ContainerInfo } from "dockerode"
|
||||
import path from "path"
|
||||
import lockfile from "proper-lockfile"
|
||||
import { execSync } from "child_process"
|
||||
|
||||
interface DockerContext {
|
||||
Name: string
|
||||
Description: string
|
||||
DockerEndpoint: string
|
||||
ContextType: string
|
||||
Error: string
|
||||
}
|
||||
|
||||
function getCurrentDockerContext(): DockerContext {
|
||||
const out = execSync("docker context ls --format json")
|
||||
for (const line of out.toString().split("\n")) {
|
||||
const parsed = JSON.parse(line)
|
||||
if (parsed.Current) {
|
||||
return parsed as DockerContext
|
||||
}
|
||||
}
|
||||
throw new Error("No current Docker context")
|
||||
}
|
||||
|
||||
async function getBudibaseContainers() {
|
||||
const client = await getContainerRuntimeClient()
|
||||
|
@ -27,6 +47,14 @@ async function killContainers(containers: ContainerInfo[]) {
|
|||
}
|
||||
|
||||
export default async function setup() {
|
||||
// For whatever reason, testcontainers doesn't always use the correct current
|
||||
// docker context. This bit of code forces the issue by finding the current
|
||||
// context and setting it as the DOCKER_HOST environment
|
||||
if (!process.env.DOCKER_HOST) {
|
||||
const dockerContext = getCurrentDockerContext()
|
||||
process.env.DOCKER_HOST = dockerContext.DockerEndpoint
|
||||
}
|
||||
|
||||
const lockPath = path.resolve(__dirname, "globalSetup.ts")
|
||||
// If you run multiple tests at the same time, it's possible for the CouchDB
|
||||
// shared container to get started multiple times despite having an
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||
"version": "3.2.14",
|
||||
"version": "3.2.16",
|
||||
"npmClient": "yarn",
|
||||
"concurrency": 20,
|
||||
"command": {
|
||||
|
|
|
@ -76,7 +76,6 @@
|
|||
"build:docker:dependencies": "docker build -f hosting/dependencies/Dockerfile -t budibase/dependencies:latest ./hosting",
|
||||
"publish:docker:couch": "docker buildx build --platform linux/arm64,linux/amd64 -f hosting/couchdb/Dockerfile -t budibase/couchdb:latest -t budibase/couchdb:v3.3.3 -t budibase/couchdb:v3.3.3-sqs-v2.1.1 --push ./hosting/couchdb",
|
||||
"publish:docker:dependencies": "docker buildx build --platform linux/arm64,linux/amd64 -f hosting/dependencies/Dockerfile -t budibase/dependencies:latest -t budibase/dependencies:v3.2.1 --push ./hosting",
|
||||
"release:helm": "node scripts/releaseHelmChart",
|
||||
"env:multi:enable": "lerna run --stream env:multi:enable",
|
||||
"env:multi:disable": "lerna run --stream env:multi:disable",
|
||||
"env:selfhost:enable": "lerna run --stream env:selfhost:enable",
|
||||
|
|
|
@ -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<SearchFilterKey, boolean> = {
|
|||
|
||||
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 { table, resource } = this.query
|
||||
|
||||
if (!resource || !resource.fields || resource.fields.length === 0) {
|
||||
return "*"
|
||||
}
|
||||
|
||||
const alias = this.getTableName(endpoint.entityId)
|
||||
const schema = meta.table.schema
|
||||
const alias = this.getTableName(table)
|
||||
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, schema, tableAliases: aliases, table } = this.query
|
||||
const fromAlias = aliases?.[table.name] || table.name
|
||||
const matches = (value: string) =>
|
||||
filterKey.match(new RegExp(`^${value}\\.`))
|
||||
if (!relationships) {
|
||||
|
@ -539,7 +537,7 @@ class InternalBuilder {
|
|||
aliases?.[manyToMany.through] || relationship.through
|
||||
let throughTable = this.tableNameWithSchema(manyToMany.through, {
|
||||
alias: throughAlias,
|
||||
schema: endpoint.schema,
|
||||
schema,
|
||||
})
|
||||
subQuery = subQuery
|
||||
// add a join through the junction table
|
||||
|
@ -1012,28 +1010,10 @@ class InternalBuilder {
|
|||
return isSqs(this.table)
|
||||
}
|
||||
|
||||
getTableName(tableOrName?: Table | string): string {
|
||||
let table: Table
|
||||
if (typeof tableOrName === "string") {
|
||||
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]) {
|
||||
// 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]
|
||||
}
|
||||
} else if (tableOrName) {
|
||||
table = tableOrName
|
||||
} else {
|
||||
getTableName(table?: Table): string {
|
||||
if (!table) {
|
||||
table = this.table
|
||||
}
|
||||
|
||||
let name = table.name
|
||||
if (isSqs(table) && table._id) {
|
||||
// SQS uses the table ID rather than the table name
|
||||
|
@ -1191,8 +1171,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 +1186,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 +1224,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, schema, tables } = this.query
|
||||
const fields = resource?.fields || []
|
||||
for (let relationship of relationships) {
|
||||
const {
|
||||
|
@ -1249,13 +1239,16 @@ 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
|
||||
let toTableWithSchema = this.tableNameWithSchema(toTable, {
|
||||
alias: toAlias,
|
||||
schema: endpoint.schema,
|
||||
schema,
|
||||
})
|
||||
const requiredFields = [
|
||||
...(relatedTable?.primary || []),
|
||||
|
@ -1271,8 +1264,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
|
||||
|
@ -1293,7 +1292,7 @@ class InternalBuilder {
|
|||
if (isManyToMany) {
|
||||
let throughTableWithSchema = this.tableNameWithSchema(throughTable, {
|
||||
alias: throughAlias,
|
||||
schema: endpoint.schema,
|
||||
schema,
|
||||
})
|
||||
subQuery = subQuery.join(throughTableWithSchema, function () {
|
||||
this.on(`${toAlias}.${toPrimary}`, "=", `${throughAlias}.${toKey}`)
|
||||
|
@ -1320,35 +1319,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()),
|
||||
})
|
||||
|
||||
|
@ -1377,8 +1383,7 @@ class InternalBuilder {
|
|||
toPrimary?: string
|
||||
}[]
|
||||
): Knex.QueryBuilder {
|
||||
const { tableAliases: aliases, endpoint } = this.query
|
||||
const schema = endpoint.schema
|
||||
const { tableAliases: aliases, schema } = this.query
|
||||
const toTable = tables.to,
|
||||
fromTable = tables.from,
|
||||
throughTable = tables.through
|
||||
|
@ -1429,16 +1434,16 @@ 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,
|
||||
schema: this.query.schema,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -1455,9 +1460,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 +1537,9 @@ class InternalBuilder {
|
|||
limits?: { base: number; query: number }
|
||||
} = {}
|
||||
): Knex.QueryBuilder {
|
||||
let { endpoint, filters, paginate, relationships } = this.query
|
||||
let { operation, 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
|
||||
|
@ -1557,7 +1558,7 @@ class InternalBuilder {
|
|||
foundLimit = paginate.limit
|
||||
}
|
||||
// counting should not sort, limit or offset
|
||||
if (!counting) {
|
||||
if (operation !== Operation.COUNT) {
|
||||
// add the found limit if supplied
|
||||
if (foundLimit != null) {
|
||||
query = query.limit(foundLimit)
|
||||
|
@ -1569,7 +1570,7 @@ class InternalBuilder {
|
|||
}
|
||||
|
||||
const aggregations = this.query.resource?.aggregations || []
|
||||
if (counting) {
|
||||
if (operation === Operation.COUNT) {
|
||||
query = this.addDistinctCount(query)
|
||||
} else if (aggregations.length > 0) {
|
||||
query = this.addAggregations(query, aggregations)
|
||||
|
@ -1578,7 +1579,7 @@ class InternalBuilder {
|
|||
}
|
||||
|
||||
// have to add after as well (this breaks MS-SQL)
|
||||
if (!counting) {
|
||||
if (operation !== Operation.COUNT) {
|
||||
query = this.addSorting(query)
|
||||
}
|
||||
|
||||
|
@ -1586,9 +1587,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 +1597,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 +1660,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 +1713,30 @@ 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({
|
||||
endpoint: {
|
||||
...json.endpoint,
|
||||
operation: Operation.READ,
|
||||
},
|
||||
resource: {
|
||||
fields: [],
|
||||
},
|
||||
operation: Operation.READ,
|
||||
datasource: json.datasource,
|
||||
schema: json.schema,
|
||||
table: json.table,
|
||||
tables: json.tables,
|
||||
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 +1749,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
|
||||
) {
|
||||
|
|
|
@ -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<string, Table>,
|
||||
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<string, Table>,
|
||||
oldTable: Table,
|
||||
renamed: RenameColumn
|
||||
oldTable?: Table,
|
||||
renamed?: RenameColumn
|
||||
): SchemaBuilder {
|
||||
return knex.alterTable(table.name, schema => {
|
||||
generateSchema(schema, table, tables, oldTable, renamed)
|
||||
|
@ -238,19 +238,18 @@ 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 {
|
||||
return json.endpoint.operation
|
||||
_operation(json: EnrichedQueryJson): Operation {
|
||||
return json.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) {
|
||||
client = client.withSchema(schemaName)
|
||||
if (json?.schema) {
|
||||
client = client.withSchema(json.schema)
|
||||
}
|
||||
|
||||
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,17 +258,17 @@ 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}\``
|
||||
const tableName = json?.schema
|
||||
? `\`${json.schema}\`.\`${json.table.name}\``
|
||||
: `\`${json.table.name}\``
|
||||
return {
|
||||
sql: `alter table ${tableName} rename column \`${json.meta.renamed.old}\` to \`${updatedColumn}\`;`,
|
||||
|
@ -280,18 +279,18 @@ 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
|
||||
? `${schemaName}.${json.table.name}`
|
||||
const tableName = json?.schema
|
||||
? `${json.schema}.${json.table.name}`
|
||||
: `${json.table.name}`
|
||||
const sql = getNativeSql(query)
|
||||
if (Array.isArray(sql)) {
|
||||
|
|
|
@ -25,7 +25,7 @@ function getTestcontainers(): ContainerInfo[] {
|
|||
// We use --format json to make sure the output is nice and machine-readable,
|
||||
// and we use --no-trunc so that the command returns full container IDs so we
|
||||
// can filter on them correctly.
|
||||
return execSync("docker ps --format json --no-trunc")
|
||||
return execSync("docker ps --all --format json --no-trunc")
|
||||
.toString()
|
||||
.split("\n")
|
||||
.filter(x => x.length > 0)
|
||||
|
@ -37,6 +37,10 @@ function getTestcontainers(): ContainerInfo[] {
|
|||
)
|
||||
}
|
||||
|
||||
function removeContainer(container: ContainerInfo) {
|
||||
execSync(`docker rm ${container.ID}`)
|
||||
}
|
||||
|
||||
export function getContainerByImage(image: string) {
|
||||
const containers = getTestcontainers().filter(x => x.Image.startsWith(image))
|
||||
if (containers.length > 1) {
|
||||
|
@ -49,6 +53,10 @@ export function getContainerByImage(image: string) {
|
|||
return containers[0]
|
||||
}
|
||||
|
||||
function getContainerByName(name: string) {
|
||||
return getTestcontainers().find(x => x.Names === name)
|
||||
}
|
||||
|
||||
export function getContainerById(id: string) {
|
||||
return getTestcontainers().find(x => x.ID === id)
|
||||
}
|
||||
|
@ -70,7 +78,34 @@ export function getExposedV4Port(container: ContainerInfo, port: number) {
|
|||
return getExposedV4Ports(container).find(x => x.container === port)?.host
|
||||
}
|
||||
|
||||
interface DockerContext {
|
||||
Name: string
|
||||
Description: string
|
||||
DockerEndpoint: string
|
||||
ContextType: string
|
||||
Error: string
|
||||
}
|
||||
|
||||
function getCurrentDockerContext(): DockerContext {
|
||||
const out = execSync("docker context ls --format json")
|
||||
for (const line of out.toString().split("\n")) {
|
||||
const parsed = JSON.parse(line)
|
||||
if (parsed.Current) {
|
||||
return parsed as DockerContext
|
||||
}
|
||||
}
|
||||
throw new Error("No current Docker context")
|
||||
}
|
||||
|
||||
export function setupEnv(...envs: any[]) {
|
||||
// For whatever reason, testcontainers doesn't always use the correct current
|
||||
// docker context. This bit of code forces the issue by finding the current
|
||||
// context and setting it as the DOCKER_HOST environment
|
||||
if (!process.env.DOCKER_HOST) {
|
||||
const dockerContext = getCurrentDockerContext()
|
||||
process.env.DOCKER_HOST = dockerContext.DockerEndpoint
|
||||
}
|
||||
|
||||
// We start couchdb in globalSetup.ts, in the root of the monorepo, so it
|
||||
// should be relatively safe to look for it by its image name.
|
||||
const couch = getContainerByImage("budibase/couchdb")
|
||||
|
@ -116,6 +151,16 @@ export async function startContainer(container: GenericContainer) {
|
|||
key = imageName.split("@")[0]
|
||||
}
|
||||
key = key.replace(/\//g, "-").replace(/:/g, "-")
|
||||
const name = `${key}_testcontainer`
|
||||
|
||||
// If a container has died it hangs around and future attempts to start a
|
||||
// container with the same name will fail. What we do here is if we find a
|
||||
// matching container and it has exited, we remove it before carrying on. This
|
||||
// removes the need to do this removal manually.
|
||||
const existingContainer = getContainerByName(name)
|
||||
if (existingContainer?.State === "exited") {
|
||||
removeContainer(existingContainer)
|
||||
}
|
||||
|
||||
container = container
|
||||
.withReuse()
|
||||
|
|
|
@ -4,27 +4,21 @@
|
|||
"version": "0.0.0",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
"module": "dist/bbui.mjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/bbui.es.js"
|
||||
"import": "./dist/bbui.mjs"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
"./spectrum-icons-rollup.js": "./src/spectrum-icons-rollup.js",
|
||||
"./spectrum-icons-vite.js": "./src/spectrum-icons-vite.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c"
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^16.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"postcss": "^8.2.9",
|
||||
"rollup": "^2.45.2",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-plugin-svelte": "^7.1.0",
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
"@sveltejs/vite-plugin-svelte": "1.4.0",
|
||||
"vite-plugin-css-injected-by-js": "3.5.2"
|
||||
},
|
||||
"keywords": [
|
||||
"svelte"
|
||||
|
@ -96,8 +90,7 @@
|
|||
"dependsOn": [
|
||||
{
|
||||
"projects": [
|
||||
"@budibase/string-templates",
|
||||
"@budibase/shared-core"
|
||||
"@budibase/string-templates"
|
||||
],
|
||||
"target": "build"
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import svelte from "rollup-plugin-svelte"
|
||||
import resolve from "@rollup/plugin-node-resolve"
|
||||
import commonjs from "@rollup/plugin-commonjs"
|
||||
import json from "@rollup/plugin-json"
|
||||
import { terser } from "rollup-plugin-terser"
|
||||
import postcss from "rollup-plugin-postcss"
|
||||
|
||||
export default {
|
||||
input: "src/index.js",
|
||||
output: {
|
||||
sourcemap: true,
|
||||
format: "esm",
|
||||
file: "dist/bbui.es.js",
|
||||
},
|
||||
onwarn(warning, warn) {
|
||||
// suppress eval warnings
|
||||
if (warning.code === "EVAL") {
|
||||
return
|
||||
}
|
||||
warn(warning)
|
||||
},
|
||||
plugins: [
|
||||
resolve(),
|
||||
commonjs(),
|
||||
svelte({
|
||||
emitCss: true,
|
||||
}),
|
||||
postcss(),
|
||||
terser(),
|
||||
json(),
|
||||
],
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import { defineConfig } from "vite"
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte"
|
||||
import path from "path"
|
||||
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const isProduction = mode === "production"
|
||||
return {
|
||||
build: {
|
||||
sourcemap: !isProduction,
|
||||
lib: {
|
||||
entry: "src/index.js",
|
||||
formats: ["es"],
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
svelte({
|
||||
emitCss: true,
|
||||
}),
|
||||
cssInjectedByJsPlugin(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@budibase/shared-core": path.resolve(__dirname, "../shared-core/src"),
|
||||
"@budibase/types": path.resolve(__dirname, "../types/src"),
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1 +1 @@
|
|||
Subproject commit e8ef2205de8bca5adcf18d07573096086aa9a606
|
||||
Subproject commit d9245f3d6d0b41ec2e6b3406b791f9e7448882cb
|
|
@ -296,16 +296,6 @@ export async function find(ctx: UserCtx) {
|
|||
ctx.body = await sdk.datasources.removeSecretSingle(datasource)
|
||||
}
|
||||
|
||||
// dynamic query functionality
|
||||
export async function query(ctx: UserCtx) {
|
||||
const queryJson = ctx.request.body
|
||||
try {
|
||||
ctx.body = await sdk.rows.utils.getDatasourceAndQuery(queryJson)
|
||||
} catch (err: any) {
|
||||
ctx.throw(400, err)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getExternalSchema(ctx: UserCtx) {
|
||||
const datasource = await sdk.datasources.get(ctx.params.datasourceId)
|
||||
const enrichedDatasource = await sdk.datasources.getAndMergeDatasource(
|
||||
|
|
|
@ -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<T extends Operation> {
|
|||
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<T extends Operation> {
|
|||
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<T extends Operation> {
|
|||
}
|
||||
|
||||
async getRow(table: Table, rowId: string): Promise<Row> {
|
||||
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<T extends Operation> {
|
|||
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<T extends Operation> {
|
|||
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<T extends Operation> {
|
|||
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<T extends Operation> {
|
|||
|
||||
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<T extends Operation> {
|
|||
table
|
||||
),
|
||||
},
|
||||
meta: {
|
||||
table,
|
||||
tables: this.tables,
|
||||
},
|
||||
}
|
||||
|
||||
// remove any relationships that could block deletion
|
||||
|
@ -773,8 +752,11 @@ export class ExternalRequest<T extends Operation> {
|
|||
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
|
||||
|
|
|
@ -11,27 +11,24 @@ export async function makeTableRequest(
|
|||
datasource: Datasource,
|
||||
operation: Operation,
|
||||
table: Table,
|
||||
tables: Record<string, Table>,
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@ import Router from "@koa/router"
|
|||
import * as datasourceController from "../controllers/datasource"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
import {
|
||||
datasourceValidator,
|
||||
datasourceQueryValidator,
|
||||
} from "./utils/validators"
|
||||
import { datasourceValidator } from "./utils/validators"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
|
@ -41,15 +38,6 @@ router
|
|||
),
|
||||
datasourceController.update
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/query",
|
||||
authorized(
|
||||
permissions.PermissionType.TABLE,
|
||||
permissions.PermissionLevel.READ
|
||||
),
|
||||
datasourceQueryValidator(),
|
||||
datasourceController.query
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/:datasourceId/schema",
|
||||
authorized(permissions.BUILDER),
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
Datasource,
|
||||
Operation,
|
||||
Query,
|
||||
QueryPreview,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import { Datasource, Query, QueryPreview } from "@budibase/types"
|
||||
import {
|
||||
DatabaseName,
|
||||
datasourceDescribe,
|
||||
|
@ -817,49 +811,6 @@ if (descriptions.length) {
|
|||
})
|
||||
|
||||
describe("query through datasource", () => {
|
||||
it("should be able to query the datasource", async () => {
|
||||
const datasource = await config.api.datasource.create(rawDatasource)
|
||||
|
||||
const entityId = tableName
|
||||
await config.api.datasource.update({
|
||||
...datasource,
|
||||
entities: {
|
||||
[entityId]: {
|
||||
name: entityId,
|
||||
schema: {},
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
sourceId: datasource._id!,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const res = await config.api.datasource.query({
|
||||
endpoint: {
|
||||
datasourceId: datasource._id!,
|
||||
operation: Operation.READ,
|
||||
entityId,
|
||||
},
|
||||
resource: {
|
||||
fields: ["id", "name"],
|
||||
},
|
||||
filters: {
|
||||
string: {
|
||||
name: "two",
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(res).toHaveLength(1)
|
||||
expect(res[0]).toEqual({
|
||||
id: 2,
|
||||
name: "two",
|
||||
// the use of table.* introduces the possibility of nulls being returned
|
||||
birthday: null,
|
||||
number: null,
|
||||
})
|
||||
})
|
||||
|
||||
// this parameter really only impacts SQL queries
|
||||
describe("confirm nullDefaultSupport", () => {
|
||||
let queryParams: Partial<Query>
|
||||
|
|
|
@ -3268,7 +3268,7 @@ if (descriptions.length) {
|
|||
formula: {
|
||||
name: "formula",
|
||||
type: FieldType.FORMULA,
|
||||
formula: formula,
|
||||
formula,
|
||||
responseType: opts?.responseType,
|
||||
formulaType: opts?.formulaType || FormulaType.DYNAMIC,
|
||||
},
|
||||
|
@ -3495,6 +3495,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")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { auth, permissions } from "@budibase/backend-core"
|
||||
import { DataSourceOperation } from "../../../constants"
|
||||
import {
|
||||
AutomationActionStepId,
|
||||
AutomationStep,
|
||||
|
@ -231,30 +230,6 @@ export function externalSearchValidator() {
|
|||
)
|
||||
}
|
||||
|
||||
export function datasourceQueryValidator() {
|
||||
return auth.joiValidator.body(
|
||||
Joi.object({
|
||||
endpoint: Joi.object({
|
||||
datasourceId: Joi.string().required(),
|
||||
operation: Joi.string()
|
||||
.required()
|
||||
.valid(...Object.values(DataSourceOperation)),
|
||||
entityId: Joi.string().required(),
|
||||
}).required(),
|
||||
resource: Joi.object({
|
||||
fields: Joi.array().items(Joi.string()).optional(),
|
||||
}).optional(),
|
||||
body: Joi.object().optional(),
|
||||
sort: Joi.object().optional(),
|
||||
filters: filterObject().optional(),
|
||||
paginate: Joi.object({
|
||||
page: Joi.string().alphanum().optional(),
|
||||
limit: Joi.number().optional(),
|
||||
}).optional(),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export function webhookValidator() {
|
||||
return auth.joiValidator.body(
|
||||
Joi.object({
|
||||
|
|
|
@ -45,17 +45,6 @@ export enum AuthTypes {
|
|||
EXTERNAL = "external",
|
||||
}
|
||||
|
||||
export enum DataSourceOperation {
|
||||
CREATE = "CREATE",
|
||||
READ = "READ",
|
||||
UPDATE = "UPDATE",
|
||||
DELETE = "DELETE",
|
||||
BULK_CREATE = "BULK_CREATE",
|
||||
CREATE_TABLE = "CREATE_TABLE",
|
||||
UPDATE_TABLE = "UPDATE_TABLE",
|
||||
DELETE_TABLE = "DELETE_TABLE",
|
||||
}
|
||||
|
||||
export enum DatasourceAuthTypes {
|
||||
GOOGLE = "google",
|
||||
}
|
||||
|
|
|
@ -1,37 +1,39 @@
|
|||
import {
|
||||
QueryJson,
|
||||
Datasource,
|
||||
DatasourcePlusQueryResponse,
|
||||
RowOperations,
|
||||
EnrichedQueryJson,
|
||||
QueryJson,
|
||||
} from "@budibase/types"
|
||||
import { getIntegration } from "../index"
|
||||
import sdk from "../../sdk"
|
||||
import { enrichQueryJson } from "../../sdk/app/rows/utils"
|
||||
|
||||
function isEnriched(
|
||||
json: QueryJson | EnrichedQueryJson
|
||||
): json is EnrichedQueryJson {
|
||||
return "datasource" in json
|
||||
}
|
||||
|
||||
export async function makeExternalQuery(
|
||||
datasource: Datasource,
|
||||
json: QueryJson
|
||||
json: QueryJson | EnrichedQueryJson
|
||||
): Promise<DatasourcePlusQueryResponse> {
|
||||
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 (!isEnriched(json)) {
|
||||
json = await enrichQueryJson(json)
|
||||
if (json.datasource) {
|
||||
json.datasource = await sdk.datasources.enrich(json.datasource)
|
||||
}
|
||||
}
|
||||
if (!datasource) {
|
||||
|
||||
if (!json.datasource) {
|
||||
throw new Error("No datasource provided for external query")
|
||||
}
|
||||
datasource = await sdk.datasources.enrich(datasource)
|
||||
const Integration = await getIntegration(datasource.source)
|
||||
|
||||
const Integration = await getIntegration(json.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(json.datasource.config)
|
||||
return integration.query(json)
|
||||
}
|
||||
|
|
|
@ -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,9 +381,9 @@ export class GoogleSheetsIntegration implements DatasourcePlus {
|
|||
return { tables: externalTables, errors }
|
||||
}
|
||||
|
||||
async query(json: QueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||
const sheet = json.endpoint.entityId
|
||||
switch (json.endpoint.operation) {
|
||||
async query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||
const sheet = json.table.name
|
||||
switch (json.operation) {
|
||||
case Operation.CREATE:
|
||||
return this.create({ sheet, row: json.body as Row })
|
||||
case Operation.BULK_CREATE:
|
||||
|
@ -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({
|
||||
|
@ -426,7 +426,7 @@ export class GoogleSheetsIntegration implements DatasourcePlus {
|
|||
return this.deleteTable(json?.table?.name)
|
||||
default:
|
||||
throw new Error(
|
||||
`GSheets integration does not support "${json.endpoint.operation}".`
|
||||
`GSheets integration does not support "${json.operation}".`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,23 +506,21 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
|
|||
return response.recordset || [{ deleted: true }]
|
||||
}
|
||||
|
||||
async query(json: QueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||
async query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||
const schema = this.config.schema
|
||||
await this.connect()
|
||||
if (schema && schema !== DEFAULT_SCHEMA && json?.endpoint) {
|
||||
json.endpoint.schema = schema
|
||||
if (schema && schema !== DEFAULT_SCHEMA) {
|
||||
json.schema = schema
|
||||
}
|
||||
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 }]
|
||||
}
|
||||
|
|
|
@ -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<DatasourcePlusQueryResponse> {
|
||||
async query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||
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
|
||||
)
|
||||
|
|
|
@ -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<DatasourcePlusQueryResponse> {
|
||||
async query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||
const operation = this._operation(json)
|
||||
const input = this._query(json, { disableReturning: true }) as SqlQuery
|
||||
if (Array.isArray(input)) {
|
||||
|
@ -572,13 +572,9 @@ class OracleIntegration extends Sql implements DatasourcePlus {
|
|||
return response.rows as Row[]
|
||||
} else {
|
||||
// get the last row that was updated
|
||||
if (
|
||||
response.lastRowid &&
|
||||
json.endpoint?.entityId &&
|
||||
operation !== Operation.DELETE
|
||||
) {
|
||||
if (response.lastRowid && 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 {
|
||||
|
|
|
@ -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<DatasourcePlusQueryResponse> {
|
||||
async query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||
const operation = this._operation(json).toLowerCase()
|
||||
const input = this._query(json) as SqlQuery
|
||||
if (Array.isArray(input)) {
|
||||
|
|
|
@ -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<Table> = {
|
||||
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<Table>
|
||||
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`,
|
||||
})
|
||||
})
|
||||
})
|
|
@ -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<string, Table> = { [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 },
|
||||
operation: op,
|
||||
resource: {
|
||||
fields,
|
||||
},
|
||||
meta: {
|
||||
table: TABLE,
|
||||
},
|
||||
table: TABLE,
|
||||
tables: { [TABLE.name]: TABLE },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
|
||||
"entityId": "persons",
|
||||
"operation": "READ"
|
||||
},
|
||||
"operation": "READ",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.year",
|
||||
|
@ -61,113 +57,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",
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_0ed5835e5552496285df546030f7c4ae",
|
||||
"entityId": "people",
|
||||
"operation": "CREATE"
|
||||
},
|
||||
"operation": "CREATE",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.name",
|
||||
"a.age"
|
||||
]
|
||||
"fields": ["a.name", "a.age"]
|
||||
},
|
||||
"filters": {},
|
||||
"relationships": [],
|
||||
|
@ -24,41 +17,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
|
||||
"entityId": "persons",
|
||||
"operation": "CREATE"
|
||||
},
|
||||
"operation": "CREATE",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.year",
|
||||
|
@ -51,123 +47,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
|
||||
"entityId": "compositetable",
|
||||
"operation": "DELETE"
|
||||
},
|
||||
"operation": "DELETE",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.keyparttwo",
|
||||
"a.keypartone",
|
||||
"a.name"
|
||||
]
|
||||
"fields": ["a.keyparttwo", "a.keypartone", "a.name"]
|
||||
},
|
||||
"filters": {
|
||||
"equal": {
|
||||
|
@ -26,50 +18,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81",
|
||||
"entityId": "tasks",
|
||||
"operation": "READ"
|
||||
},
|
||||
"operation": "READ",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.executorid",
|
||||
|
@ -17,10 +13,7 @@
|
|||
},
|
||||
"filters": {
|
||||
"oneOf": {
|
||||
"taskid": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
"taskid": [1, 2]
|
||||
}
|
||||
},
|
||||
"relationships": [
|
||||
|
@ -42,82 +35,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81",
|
||||
"entityId": "products",
|
||||
"operation": "READ"
|
||||
},
|
||||
"operation": "READ",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.productname",
|
||||
|
@ -56,48 +52,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",
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
|
||||
"entityId": "products",
|
||||
"operation": "READ"
|
||||
},
|
||||
"operation": "READ",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.productname",
|
||||
|
@ -46,47 +42,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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_44a967caf37a435f84fe01cd6dfe8f81",
|
||||
"entityId": "tasks",
|
||||
"operation": "READ"
|
||||
},
|
||||
"operation": "READ",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.executorid",
|
||||
|
@ -102,94 +98,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",
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
|
||||
"entityId": "persons",
|
||||
"operation": "UPDATE"
|
||||
},
|
||||
"operation": "UPDATE",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.year",
|
||||
|
@ -59,123 +55,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"endpoint": {
|
||||
"datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
|
||||
"entityId": "persons",
|
||||
"operation": "UPDATE"
|
||||
},
|
||||
"operation": "UPDATE",
|
||||
"resource": {
|
||||
"fields": [
|
||||
"a.year",
|
||||
|
@ -59,123 +55,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<string, Table> = {}
|
||||
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<Row[]>
|
||||
function runSqlQuery(
|
||||
json: QueryJson,
|
||||
json: EnrichedQueryJson,
|
||||
tables: Table[],
|
||||
relationships: RelationshipsJson[],
|
||||
opts: { countTotalRows: true }
|
||||
): Promise<number>
|
||||
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
|
||||
json.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<string, Table>)
|
||||
|
||||
// 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),
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
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<DatasourcePlusQueryResponse>
|
||||
|
||||
const WRITE_OPERATIONS: Operation[] = [
|
||||
|
@ -71,13 +68,12 @@ export default class AliasTables {
|
|||
this.charSeq = new CharSequence()
|
||||
}
|
||||
|
||||
isAliasingEnabled(json: QueryJson, datasource?: Datasource) {
|
||||
const operation = json.endpoint.operation
|
||||
isAliasingEnabled(json: EnrichedQueryJson, datasource?: Datasource) {
|
||||
const fieldLength = json.resource?.fields?.length
|
||||
if (
|
||||
!fieldLength ||
|
||||
fieldLength <= 0 ||
|
||||
DISABLED_OPERATIONS.includes(operation)
|
||||
DISABLED_OPERATIONS.includes(json.operation)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
@ -87,7 +83,7 @@ export default class AliasTables {
|
|||
}
|
||||
try {
|
||||
const sqlClient = getSQLClient(datasource)
|
||||
const isWrite = WRITE_OPERATIONS.includes(operation)
|
||||
const isWrite = WRITE_OPERATIONS.includes(json.operation)
|
||||
const isDisabledClient = DISABLED_WRITE_CLIENTS.includes(sqlClient)
|
||||
if (isWrite && isDisabledClient) {
|
||||
return false
|
||||
|
@ -99,7 +95,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 +177,15 @@ export default class AliasTables {
|
|||
}
|
||||
|
||||
async queryWithAliasing(
|
||||
json: QueryJson,
|
||||
json: EnrichedQueryJson,
|
||||
queryFn: PerformQueryFunction
|
||||
): Promise<DatasourcePlusQueryResponse> {
|
||||
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 +213,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<string, string> = {}
|
||||
for (let [key, value] of Object.entries(this.tableAliases)) {
|
||||
|
@ -241,7 +238,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 {
|
||||
|
|
|
@ -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,58 @@ export function processRowCountResponse(
|
|||
}
|
||||
}
|
||||
|
||||
export async function getDatasourceAndQuery(
|
||||
json: QueryJson
|
||||
): Promise<DatasourcePlusQueryResponse> {
|
||||
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<string, Table> = {}
|
||||
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<EnrichedQueryJson> {
|
||||
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<string, Table>
|
||||
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 {
|
||||
operation: json.endpoint.operation,
|
||||
table,
|
||||
tables,
|
||||
datasource,
|
||||
schema: json.endpoint.schema,
|
||||
...json,
|
||||
}
|
||||
return makeExternalQuery(datasource, json)
|
||||
}
|
||||
|
||||
export function cleanExportRows(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -46,6 +46,7 @@ export async function processTable(table: Table): Promise<Table> {
|
|||
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,
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import {
|
||||
Datasource,
|
||||
VerifyDatasourceRequest,
|
||||
CreateDatasourceResponse,
|
||||
UpdateDatasourceResponse,
|
||||
UpdateDatasourceRequest,
|
||||
QueryJson,
|
||||
BuildSchemaFromSourceResponse,
|
||||
CreateDatasourceResponse,
|
||||
Datasource,
|
||||
FetchDatasourceInfoResponse,
|
||||
FieldType,
|
||||
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,16 +68,6 @@ export class DatasourceAPI extends TestAPI {
|
|||
return await this._get<Datasource[]>(`/api/datasources`, { expectations })
|
||||
}
|
||||
|
||||
query = async (
|
||||
query: Omit<QueryJson, "meta"> & Partial<Pick<QueryJson, "meta">>,
|
||||
expectations?: Expectations
|
||||
) => {
|
||||
return await this._post<any>(`/api/datasources/query`, {
|
||||
body: query,
|
||||
expectations,
|
||||
})
|
||||
}
|
||||
|
||||
fetchSchema = async (
|
||||
{
|
||||
datasourceId,
|
||||
|
@ -103,4 +95,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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<DatasourcePlusQueryResponse>
|
||||
query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse>
|
||||
buildSchema(
|
||||
datasourceId: string,
|
||||
entities: Record<string, Table>
|
||||
|
|
|
@ -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<string, Table>
|
||||
meta?: {
|
||||
renamed?: RenameColumn
|
||||
oldTable?: Table
|
||||
// can specify something that columns could be prefixed with
|
||||
columnPrefix?: string
|
||||
}
|
||||
|
@ -186,6 +184,14 @@ export interface QueryJson {
|
|||
tableAliases?: Record<string, string>
|
||||
}
|
||||
|
||||
export interface EnrichedQueryJson extends Omit<QueryJson, "endpoint"> {
|
||||
operation: Operation
|
||||
table: Table
|
||||
tables: Record<string, Table>
|
||||
datasource?: Datasource
|
||||
schema?: string
|
||||
}
|
||||
|
||||
export interface QueryOptions {
|
||||
disableReturning?: boolean
|
||||
disableBindings?: boolean
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
sudo apt-get install -y qemu qemu-user-static
|
||||
docker buildx create --name budibase
|
||||
docker buildx use budibase
|
|
@ -1,46 +0,0 @@
|
|||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
|
||||
const MONOREPO_ROOT = "packages"
|
||||
|
||||
const packages = getPackages()
|
||||
|
||||
function getPackages() {
|
||||
if (fs.existsSync(MONOREPO_ROOT)) {
|
||||
return fs.readdirSync(MONOREPO_ROOT).map(pkg => path.join(MONOREPO_ROOT, pkg))
|
||||
} else {
|
||||
return ["./"]
|
||||
}
|
||||
}
|
||||
|
||||
function pinDeps(dependencies) {
|
||||
for (let dependency in dependencies) {
|
||||
if (dependency.startsWith("@budibase")) {
|
||||
dependencies[dependency] = dependencies[dependency].replace("^", "")
|
||||
}
|
||||
}
|
||||
return dependencies
|
||||
}
|
||||
|
||||
// iterate over the monorepo packages
|
||||
for (let pkgPath of packages) {
|
||||
// only directories
|
||||
if (fs.statSync(pkgPath).isDirectory()) {
|
||||
// get the package JSON file
|
||||
const pkgJsonPath = path.join(pkgPath, "package.json")
|
||||
if (!fs.existsSync(pkgJsonPath)) {
|
||||
continue
|
||||
}
|
||||
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath))
|
||||
|
||||
|
||||
// find any budibase dependencies, and pin them
|
||||
pkgJson.dependencies = pinDeps(pkgJson.dependencies)
|
||||
pkgJson.devDependencies = pinDeps(pkgJson.devDependencies)
|
||||
|
||||
// update the package JSON files
|
||||
fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2))
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Pinned dev versions for budibase packages successfully.")
|
|
@ -1,28 +0,0 @@
|
|||
const yaml = require("js-yaml")
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
|
||||
const CHART_PATH = path.join(__dirname, "../", "charts", "budibase", "Chart.yaml")
|
||||
const UPGRADE_VERSION = process.env.BUDIBASE_RELEASE_VERSION
|
||||
|
||||
if (!UPGRADE_VERSION) {
|
||||
throw new Error("BUDIBASE_RELEASE_VERSION env var must be set.")
|
||||
}
|
||||
|
||||
try {
|
||||
const chartFile = fs.readFileSync(CHART_PATH, "utf-8")
|
||||
const chart = yaml.load(chartFile)
|
||||
|
||||
// Upgrade app version in chart to match budibase release version
|
||||
chart.appVersion = UPGRADE_VERSION
|
||||
|
||||
// semantically version the chart
|
||||
const [major, minor, patch] = chart.version.split(".")
|
||||
const newPatch = parseInt(patch) + 1
|
||||
chart.version = [major, minor, newPatch].join(".")
|
||||
const updatedChartYaml = yaml.dump(chart)
|
||||
fs.writeFileSync(CHART_PATH, updatedChartYaml)
|
||||
} catch (err) {
|
||||
console.error("Error releasing helm chart")
|
||||
throw err
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
echo "Resetting package versions"
|
||||
yarn lerna exec "yarn version --no-git-tag-version --new-version=0.0.0"
|
||||
echo "Updating dependencies"
|
||||
node scripts/syncLocalDependencies.js "0.0.0"
|
||||
git checkout package.json
|
||||
echo "Package versions reset!"
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/bash
|
||||
version=$(./scripts/getCurrentVersion.sh)
|
||||
echo "Setting version $version"
|
||||
yarn lerna exec "yarn version --no-git-tag-version --new-version=$version"
|
||||
echo "Updating dependencies"
|
||||
node scripts/syncLocalDependencies.js $version
|
||||
echo "Syncing yarn workspace"
|
||||
yarn
|
588
yarn.lock
588
yarn.lock
|
@ -4025,19 +4025,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.4.tgz#af85eb080f6934580e4d3b58046026b6c2b18717"
|
||||
integrity sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==
|
||||
|
||||
"@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==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
commondir "^1.0.1"
|
||||
estree-walker "^2.0.1"
|
||||
glob "^7.1.6"
|
||||
is-reference "^1.2.1"
|
||||
magic-string "^0.25.7"
|
||||
resolve "^1.17.0"
|
||||
|
||||
"@rollup/plugin-commonjs@^17.1.0":
|
||||
version "17.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz#757ec88737dffa8aa913eb392fade2e45aef2a2d"
|
||||
|
@ -4079,18 +4066,6 @@
|
|||
dependencies:
|
||||
"@rollup/pluginutils" "^3.0.8"
|
||||
|
||||
"@rollup/plugin-node-resolve@^11.2.1":
|
||||
version "11.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60"
|
||||
integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
"@types/resolve" "1.17.1"
|
||||
builtin-modules "^3.1.0"
|
||||
deepmerge "^4.2.2"
|
||||
is-module "^1.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
"@rollup/plugin-node-resolve@^15.2.3":
|
||||
version "15.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz#e5e0b059bd85ca57489492f295ce88c2d4b0daf9"
|
||||
|
@ -4103,7 +4078,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==
|
||||
|
@ -4137,14 +4112,6 @@
|
|||
estree-walker "^1.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@rollup/pluginutils@^4.1.0":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
||||
integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
|
||||
dependencies:
|
||||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@rollup/pluginutils@^5.0.1":
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
|
||||
|
@ -5302,11 +5269,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||
|
||||
"@trysound/sax@0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
||||
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||
|
@ -6065,13 +6027,6 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/resolve@1.17.1":
|
||||
version "1.17.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
|
||||
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/resolve@1.20.2":
|
||||
version "1.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
|
||||
|
@ -7609,11 +7564,6 @@ bn.js@^5.0.0, bn.js@^5.2.1:
|
|||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
|
||||
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
|
||||
|
||||
boolbase@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
|
||||
|
||||
boolean@^3.0.1:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b"
|
||||
|
@ -7739,7 +7689,7 @@ browserify-sign@^4.0.0:
|
|||
readable-stream "^2.3.8"
|
||||
safe-buffer "^5.2.1"
|
||||
|
||||
browserslist@^4.0.0, browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5:
|
||||
browserslist@^4.21.3, browserslist@^4.21.5:
|
||||
version "4.21.5"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
|
||||
integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
|
||||
|
@ -8042,17 +7992,7 @@ camelcase@^6.2.0, camelcase@^6.3.0:
|
|||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
|
||||
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
|
||||
|
||||
caniuse-api@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
|
||||
integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
|
||||
dependencies:
|
||||
browserslist "^4.0.0"
|
||||
caniuse-lite "^1.0.0"
|
||||
lodash.memoize "^4.1.2"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449:
|
||||
caniuse-lite@^1.0.30001449:
|
||||
version "1.0.30001460"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz#31d2e26f0a2309860ed3eff154e03890d9d851a7"
|
||||
integrity sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==
|
||||
|
@ -8415,11 +8355,6 @@ color@^3.1.3:
|
|||
color-convert "^1.9.3"
|
||||
color-string "^1.6.0"
|
||||
|
||||
colord@^2.9.1:
|
||||
version "2.9.3"
|
||||
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
|
||||
integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
|
||||
|
||||
colorette@2.0.19, colorette@^2.0.7:
|
||||
version "2.0.19"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
|
||||
|
@ -8574,13 +8509,6 @@ concat-stream@^2.0.0:
|
|||
readable-stream "^3.0.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concat-with-sourcemaps@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e"
|
||||
integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==
|
||||
dependencies:
|
||||
source-map "^0.6.1"
|
||||
|
||||
condense-newlines@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f"
|
||||
|
@ -8972,30 +8900,6 @@ crypto-randomuuid@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/crypto-randomuuid/-/crypto-randomuuid-1.0.0.tgz#acf583e5e085e867ae23e107ff70279024f9e9e7"
|
||||
integrity sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==
|
||||
|
||||
css-declaration-sorter@^6.3.1:
|
||||
version "6.3.1"
|
||||
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec"
|
||||
integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==
|
||||
|
||||
css-select@^4.1.3:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
|
||||
integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
|
||||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
css-what "^6.0.1"
|
||||
domhandler "^4.3.1"
|
||||
domutils "^2.8.0"
|
||||
nth-check "^2.0.1"
|
||||
|
||||
css-tree@^1.1.2, css-tree@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
|
||||
integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
|
||||
dependencies:
|
||||
mdn-data "2.0.14"
|
||||
source-map "^0.6.1"
|
||||
|
||||
css-tree@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20"
|
||||
|
@ -9004,11 +8908,6 @@ css-tree@^2.3.1:
|
|||
mdn-data "2.0.30"
|
||||
source-map-js "^1.0.1"
|
||||
|
||||
css-what@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
|
||||
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
|
||||
|
||||
css.escape@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
|
||||
|
@ -9019,62 +8918,6 @@ cssesc@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||
|
||||
cssnano-preset-default@^5.2.14:
|
||||
version "5.2.14"
|
||||
resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8"
|
||||
integrity sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==
|
||||
dependencies:
|
||||
css-declaration-sorter "^6.3.1"
|
||||
cssnano-utils "^3.1.0"
|
||||
postcss-calc "^8.2.3"
|
||||
postcss-colormin "^5.3.1"
|
||||
postcss-convert-values "^5.1.3"
|
||||
postcss-discard-comments "^5.1.2"
|
||||
postcss-discard-duplicates "^5.1.0"
|
||||
postcss-discard-empty "^5.1.1"
|
||||
postcss-discard-overridden "^5.1.0"
|
||||
postcss-merge-longhand "^5.1.7"
|
||||
postcss-merge-rules "^5.1.4"
|
||||
postcss-minify-font-values "^5.1.0"
|
||||
postcss-minify-gradients "^5.1.1"
|
||||
postcss-minify-params "^5.1.4"
|
||||
postcss-minify-selectors "^5.2.1"
|
||||
postcss-normalize-charset "^5.1.0"
|
||||
postcss-normalize-display-values "^5.1.0"
|
||||
postcss-normalize-positions "^5.1.1"
|
||||
postcss-normalize-repeat-style "^5.1.1"
|
||||
postcss-normalize-string "^5.1.0"
|
||||
postcss-normalize-timing-functions "^5.1.0"
|
||||
postcss-normalize-unicode "^5.1.1"
|
||||
postcss-normalize-url "^5.1.0"
|
||||
postcss-normalize-whitespace "^5.1.1"
|
||||
postcss-ordered-values "^5.1.3"
|
||||
postcss-reduce-initial "^5.1.2"
|
||||
postcss-reduce-transforms "^5.1.0"
|
||||
postcss-svgo "^5.1.0"
|
||||
postcss-unique-selectors "^5.1.1"
|
||||
|
||||
cssnano-utils@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861"
|
||||
integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==
|
||||
|
||||
cssnano@^5.0.1:
|
||||
version "5.1.15"
|
||||
resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.15.tgz#ded66b5480d5127fcb44dac12ea5a983755136bf"
|
||||
integrity sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==
|
||||
dependencies:
|
||||
cssnano-preset-default "^5.2.14"
|
||||
lilconfig "^2.0.3"
|
||||
yaml "^1.10.2"
|
||||
|
||||
csso@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
|
||||
integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
|
||||
dependencies:
|
||||
css-tree "^1.1.2"
|
||||
|
||||
cssom@^0.4.4:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
|
||||
|
@ -9914,15 +9757,6 @@ dom-accessibility-api@^0.6.3:
|
|||
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz#993e925cc1d73f2c662e7d75dd5a5445259a8fd8"
|
||||
integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==
|
||||
|
||||
dom-serializer@^1.0.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
|
||||
integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
|
||||
dependencies:
|
||||
domelementtype "^2.0.1"
|
||||
domhandler "^4.2.0"
|
||||
entities "^2.0.0"
|
||||
|
||||
dom-serializer@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
|
||||
|
@ -9937,7 +9771,7 @@ dom-walk@^0.1.0:
|
|||
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
|
||||
integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==
|
||||
|
||||
domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0:
|
||||
domelementtype@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
|
||||
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
|
||||
|
@ -9956,13 +9790,6 @@ domexception@^4.0.0:
|
|||
dependencies:
|
||||
webidl-conversions "^7.0.0"
|
||||
|
||||
domhandler@^4.2.0, domhandler@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
|
||||
integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
|
||||
dependencies:
|
||||
domelementtype "^2.2.0"
|
||||
|
||||
domhandler@^5.0.1, domhandler@^5.0.2:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
|
||||
|
@ -9970,15 +9797,6 @@ domhandler@^5.0.1, domhandler@^5.0.2:
|
|||
dependencies:
|
||||
domelementtype "^2.3.0"
|
||||
|
||||
domutils@^2.8.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
|
||||
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
|
||||
dependencies:
|
||||
dom-serializer "^1.0.1"
|
||||
domelementtype "^2.2.0"
|
||||
domhandler "^4.2.0"
|
||||
|
||||
domutils@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c"
|
||||
|
@ -10266,11 +10084,6 @@ enquirer@~2.3.6:
|
|||
dependencies:
|
||||
ansi-colors "^4.1.1"
|
||||
|
||||
entities@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
||||
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
||||
|
||||
entities@^4.2.0, entities@^4.3.0, entities@^4.4.0, entities@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||
|
@ -11554,13 +11367,6 @@ generate-function@^2.3.1:
|
|||
dependencies:
|
||||
is-property "^1.0.2"
|
||||
|
||||
generic-names@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-4.0.0.tgz#0bd8a2fd23fe8ea16cbd0a279acd69c06933d9a3"
|
||||
integrity sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==
|
||||
dependencies:
|
||||
loader-utils "^3.2.0"
|
||||
|
||||
generic-pool@3.9.0, generic-pool@^3.8.2:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4"
|
||||
|
@ -12525,16 +12331,6 @@ iconv-lite@0.6.3, iconv-lite@^0.6.2, iconv-lite@^0.6.3:
|
|||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
icss-replace-symbols@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
|
||||
integrity sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==
|
||||
|
||||
icss-utils@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
|
||||
integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
|
||||
|
||||
idb-wrapper@^1.5.0:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/idb-wrapper/-/idb-wrapper-1.7.2.tgz#8251afd5e77fe95568b1c16152eb44b396767ea2"
|
||||
|
@ -12598,13 +12394,6 @@ immediate@~3.0.5:
|
|||
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
|
||||
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
|
||||
|
||||
import-cwd@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92"
|
||||
integrity sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==
|
||||
dependencies:
|
||||
import-from "^3.0.0"
|
||||
|
||||
import-fresh@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
|
@ -12613,13 +12402,6 @@ import-fresh@^3.2.1:
|
|||
parent-module "^1.0.0"
|
||||
resolve-from "^4.0.0"
|
||||
|
||||
import-from@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966"
|
||||
integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==
|
||||
dependencies:
|
||||
resolve-from "^5.0.0"
|
||||
|
||||
import-in-the-middle@1.11.2:
|
||||
version "1.11.2"
|
||||
resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.11.2.tgz#dd848e72b63ca6cd7c34df8b8d97fc9baee6174f"
|
||||
|
@ -14803,7 +14585,7 @@ lie@3.1.1:
|
|||
dependencies:
|
||||
immediate "~3.0.5"
|
||||
|
||||
lilconfig@^2.0.3, lilconfig@^2.0.5:
|
||||
lilconfig@^2.0.5:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
|
||||
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
|
||||
|
@ -14843,11 +14625,6 @@ load-json-file@^4.0.0:
|
|||
pify "^3.0.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
loader-utils@^3.2.0:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.1.tgz#4fb104b599daafd82ef3e1a41fb9265f87e1f576"
|
||||
integrity sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==
|
||||
|
||||
local-pkg@^0.4.2:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963"
|
||||
|
@ -14978,7 +14755,7 @@ lodash.keys@^4.2.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205"
|
||||
integrity sha512-J79MkJcp7Df5mizHiVNpjoHXLi4HLjh9VLS/M7lQSGoQ+0oQ+lWEigREkqKyizPB1IawvQLLKY8mzEcm1tkyxQ==
|
||||
|
||||
lodash.memoize@4.x, lodash.memoize@^4.1.2:
|
||||
lodash.memoize@4.x:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
|
||||
|
@ -15013,11 +14790,6 @@ lodash.union@^4.6.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
|
||||
integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==
|
||||
|
||||
lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
|
||||
|
||||
lodash.without@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
|
||||
|
@ -15328,11 +15100,6 @@ md5.js@^1.3.4:
|
|||
inherits "^2.0.1"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
mdn-data@2.0.14:
|
||||
version "2.0.14"
|
||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
|
||||
integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
|
||||
|
||||
mdn-data@2.0.30:
|
||||
version "2.0.30"
|
||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc"
|
||||
|
@ -16151,11 +15918,6 @@ normalize-url@^4.1.0:
|
|||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
|
||||
integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
|
||||
|
||||
normalize-url@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
|
||||
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
|
||||
|
||||
notepack.io@~3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/notepack.io/-/notepack.io-3.0.1.tgz#2c2c9de1bd4e64a79d34e33c413081302a0d4019"
|
||||
|
@ -16278,13 +16040,6 @@ npmlog@^6.0.0, npmlog@^6.0.2:
|
|||
gauge "^4.0.3"
|
||||
set-blocking "^2.0.0"
|
||||
|
||||
nth-check@^2.0.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
|
||||
integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
|
||||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
|
||||
nunjucks@^3.2.3:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/nunjucks/-/nunjucks-3.2.4.tgz#f0878eef528ce7b0aa35d67cc6898635fd74649e"
|
||||
|
@ -16779,7 +16534,7 @@ p-pipe@3.1.0:
|
|||
resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e"
|
||||
integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==
|
||||
|
||||
p-queue@6.6.2, p-queue@^6.6.2:
|
||||
p-queue@6.6.2:
|
||||
version "6.6.2"
|
||||
resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426"
|
||||
integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==
|
||||
|
@ -17230,7 +16985,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatc
|
|||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
pify@5.0.0, pify@^5.0.0:
|
||||
pify@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f"
|
||||
integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==
|
||||
|
@ -17422,53 +17177,7 @@ possible-typed-array-names@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
|
||||
integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
|
||||
|
||||
postcss-calc@^8.2.3:
|
||||
version "8.2.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5"
|
||||
integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.0.9"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-colormin@^5.3.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz#86c27c26ed6ba00d96c79e08f3ffb418d1d1988f"
|
||||
integrity sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
caniuse-api "^3.0.0"
|
||||
colord "^2.9.1"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-convert-values@^5.1.3:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393"
|
||||
integrity sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-discard-comments@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz#8df5e81d2925af2780075840c1526f0660e53696"
|
||||
integrity sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==
|
||||
|
||||
postcss-discard-duplicates@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848"
|
||||
integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==
|
||||
|
||||
postcss-discard-empty@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c"
|
||||
integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==
|
||||
|
||||
postcss-discard-overridden@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e"
|
||||
integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==
|
||||
|
||||
postcss-load-config@^3.0.0, postcss-load-config@^3.1.4:
|
||||
postcss-load-config@^3.1.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
|
||||
integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
|
||||
|
@ -17476,184 +17185,6 @@ postcss-load-config@^3.0.0, postcss-load-config@^3.1.4:
|
|||
lilconfig "^2.0.5"
|
||||
yaml "^1.10.2"
|
||||
|
||||
postcss-merge-longhand@^5.1.7:
|
||||
version "5.1.7"
|
||||
resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16"
|
||||
integrity sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
stylehacks "^5.1.1"
|
||||
|
||||
postcss-merge-rules@^5.1.4:
|
||||
version "5.1.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz#2f26fa5cacb75b1402e213789f6766ae5e40313c"
|
||||
integrity sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
caniuse-api "^3.0.0"
|
||||
cssnano-utils "^3.1.0"
|
||||
postcss-selector-parser "^6.0.5"
|
||||
|
||||
postcss-minify-font-values@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b"
|
||||
integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-minify-gradients@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c"
|
||||
integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==
|
||||
dependencies:
|
||||
colord "^2.9.1"
|
||||
cssnano-utils "^3.1.0"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-minify-params@^5.1.4:
|
||||
version "5.1.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352"
|
||||
integrity sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
cssnano-utils "^3.1.0"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-minify-selectors@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz#d4e7e6b46147b8117ea9325a915a801d5fe656c6"
|
||||
integrity sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.0.5"
|
||||
|
||||
postcss-modules-extract-imports@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
|
||||
integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
|
||||
|
||||
postcss-modules-local-by-default@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c"
|
||||
integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==
|
||||
dependencies:
|
||||
icss-utils "^5.0.0"
|
||||
postcss-selector-parser "^6.0.2"
|
||||
postcss-value-parser "^4.1.0"
|
||||
|
||||
postcss-modules-scope@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
|
||||
integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.0.4"
|
||||
|
||||
postcss-modules-values@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
|
||||
integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
|
||||
dependencies:
|
||||
icss-utils "^5.0.0"
|
||||
|
||||
postcss-modules@^4.0.0:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-4.3.1.tgz#517c06c09eab07d133ae0effca2c510abba18048"
|
||||
integrity sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==
|
||||
dependencies:
|
||||
generic-names "^4.0.0"
|
||||
icss-replace-symbols "^1.1.0"
|
||||
lodash.camelcase "^4.3.0"
|
||||
postcss-modules-extract-imports "^3.0.0"
|
||||
postcss-modules-local-by-default "^4.0.0"
|
||||
postcss-modules-scope "^3.0.0"
|
||||
postcss-modules-values "^4.0.0"
|
||||
string-hash "^1.1.1"
|
||||
|
||||
postcss-normalize-charset@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed"
|
||||
integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==
|
||||
|
||||
postcss-normalize-display-values@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8"
|
||||
integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-normalize-positions@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz#ef97279d894087b59325b45c47f1e863daefbb92"
|
||||
integrity sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-normalize-repeat-style@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz#e9eb96805204f4766df66fd09ed2e13545420fb2"
|
||||
integrity sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-normalize-string@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228"
|
||||
integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-normalize-timing-functions@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb"
|
||||
integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-normalize-unicode@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030"
|
||||
integrity sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-normalize-url@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc"
|
||||
integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==
|
||||
dependencies:
|
||||
normalize-url "^6.0.1"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-normalize-whitespace@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa"
|
||||
integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-ordered-values@^5.1.3:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz#b6fd2bd10f937b23d86bc829c69e7732ce76ea38"
|
||||
integrity sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==
|
||||
dependencies:
|
||||
cssnano-utils "^3.1.0"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-reduce-initial@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz#798cd77b3e033eae7105c18c9d371d989e1382d6"
|
||||
integrity sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
caniuse-api "^3.0.0"
|
||||
|
||||
postcss-reduce-transforms@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9"
|
||||
integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
postcss-safe-parser@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1"
|
||||
|
@ -17664,7 +17195,7 @@ postcss-scss@^4.0.8:
|
|||
resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.9.tgz#a03c773cd4c9623cb04ce142a52afcec74806685"
|
||||
integrity sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==
|
||||
|
||||
postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
|
||||
postcss-selector-parser@^6.0.11:
|
||||
version "6.0.13"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b"
|
||||
integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==
|
||||
|
@ -17672,26 +17203,6 @@ postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selecto
|
|||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-svgo@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d"
|
||||
integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.2.0"
|
||||
svgo "^2.7.0"
|
||||
|
||||
postcss-unique-selectors@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6"
|
||||
integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.0.5"
|
||||
|
||||
postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss-values-parser@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f"
|
||||
|
@ -17710,7 +17221,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.5:
|
||||
postcss@^8.1.7, 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==
|
||||
|
@ -18196,11 +17707,6 @@ promise-retry@^2.0.1:
|
|||
err-code "^2.0.2"
|
||||
retry "^0.12.0"
|
||||
|
||||
promise.series@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd"
|
||||
integrity sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ==
|
||||
|
||||
prompts@^2.0.1:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
|
||||
|
@ -18937,7 +18443,7 @@ resolve.exports@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.0.tgz#c1a0028c2d166ec2fbf7d0644584927e76e7400e"
|
||||
integrity sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==
|
||||
|
||||
resolve@^1.10.0, resolve@^1.11.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.21.0, resolve@^1.22.1, resolve@^1.22.3, resolve@^1.22.4:
|
||||
resolve@^1.10.0, resolve@^1.11.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.21.0, resolve@^1.22.1, resolve@^1.22.3, resolve@^1.22.4:
|
||||
version "1.22.8"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
|
||||
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
|
||||
|
@ -19071,33 +18577,6 @@ rollup-plugin-polyfill-node@^0.13.0:
|
|||
dependencies:
|
||||
"@rollup/plugin-inject" "^5.0.4"
|
||||
|
||||
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==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
concat-with-sourcemaps "^1.1.0"
|
||||
cssnano "^5.0.1"
|
||||
import-cwd "^3.0.0"
|
||||
p-queue "^6.6.2"
|
||||
pify "^5.0.0"
|
||||
postcss-load-config "^3.0.0"
|
||||
postcss-modules "^4.0.0"
|
||||
promise.series "^0.2.0"
|
||||
resolve "^1.19.0"
|
||||
rollup-pluginutils "^2.8.2"
|
||||
safe-identifier "^0.4.2"
|
||||
style-inject "^0.3.0"
|
||||
|
||||
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==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^4.1.0"
|
||||
resolve.exports "^2.0.0"
|
||||
|
||||
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"
|
||||
|
@ -19120,7 +18599,7 @@ rollup-pluginutils@^2.3.1, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2:
|
|||
dependencies:
|
||||
estree-walker "^0.6.1"
|
||||
|
||||
rollup@^2.36.2, rollup@^2.45.2:
|
||||
rollup@^2.36.2:
|
||||
version "2.79.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
|
||||
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
|
||||
|
@ -19227,11 +18706,6 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
|||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-identifier@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-identifier/-/safe-identifier-0.4.2.tgz#cf6bfca31c2897c588092d1750d30ef501d59fcb"
|
||||
integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==
|
||||
|
||||
safe-regex-test@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377"
|
||||
|
@ -19904,11 +19378,6 @@ ssri@^9.0.0, ssri@^9.0.1:
|
|||
dependencies:
|
||||
minipass "^3.1.1"
|
||||
|
||||
stable@^0.1.8:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
|
||||
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
|
||||
|
||||
stack-trace@0.0.x:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
|
||||
|
@ -20007,11 +19476,6 @@ strict-uri-encode@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
|
||||
|
||||
string-hash@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
|
||||
integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
|
||||
|
||||
string-length@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
|
||||
|
@ -20246,24 +19710,11 @@ stubs@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b"
|
||||
integrity "sha1-6NK6H6nJBXAwPAMLaQD31fiavls= sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw=="
|
||||
|
||||
style-inject@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/style-inject/-/style-inject-0.3.0.tgz#d21c477affec91811cc82355832a700d22bf8dd3"
|
||||
integrity sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==
|
||||
|
||||
style-mod@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.3.tgz#136c4abc905f82a866a18b39df4dc08ec762b1ad"
|
||||
integrity sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==
|
||||
|
||||
stylehacks@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9"
|
||||
integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
postcss-selector-parser "^6.0.4"
|
||||
|
||||
stylus-lookup@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/stylus-lookup/-/stylus-lookup-3.0.2.tgz#c9eca3ff799691020f30b382260a67355fefdddd"
|
||||
|
@ -20496,19 +19947,6 @@ svg.select.js@^3.0.1:
|
|||
dependencies:
|
||||
svg.js "^2.6.5"
|
||||
|
||||
svgo@^2.7.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
|
||||
integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
|
||||
dependencies:
|
||||
"@trysound/sax" "0.2.0"
|
||||
commander "^7.2.0"
|
||||
css-select "^4.1.3"
|
||||
css-tree "^1.1.3"
|
||||
csso "^4.2.0"
|
||||
picocolors "^1.0.0"
|
||||
stable "^0.1.8"
|
||||
|
||||
swagger-jsdoc@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/swagger-jsdoc/-/swagger-jsdoc-6.1.0.tgz#c2b86321f2c4dde8947b418fe8a4bc94431d5522"
|
||||
|
|
Loading…
Reference in New Issue