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