Making sure the source ID is always set when creating a table - the frontend expects this to be set for every table so making the type represent this correctly.

This commit is contained in:
mike12345567 2023-10-25 19:00:25 +01:00
parent 6c3b535863
commit 455b26bac9
32 changed files with 185 additions and 109 deletions

View File

@ -12,7 +12,6 @@ import {
CreateDatasourceResponse, CreateDatasourceResponse,
Datasource, Datasource,
DatasourcePlus, DatasourcePlus,
ExternalTable,
FetchDatasourceInfoRequest, FetchDatasourceInfoRequest,
FetchDatasourceInfoResponse, FetchDatasourceInfoResponse,
IntegrationBase, IntegrationBase,
@ -59,7 +58,7 @@ async function buildSchemaHelper(datasource: Datasource): Promise<Schema> {
const connector = (await getConnector(datasource)) as DatasourcePlus const connector = (await getConnector(datasource)) as DatasourcePlus
return await connector.buildSchema( return await connector.buildSchema(
datasource._id!, datasource._id!,
datasource.entities! as Record<string, ExternalTable> datasource.entities! as Record<string, Table>
) )
} }

View File

@ -24,7 +24,6 @@ import sdk from "../../../sdk"
import { jsonFromCsvString } from "../../../utilities/csv" import { jsonFromCsvString } from "../../../utilities/csv"
import { builderSocket } from "../../../websockets" import { builderSocket } from "../../../websockets"
import { cloneDeep, isEqual } from "lodash" import { cloneDeep, isEqual } from "lodash"
import { processInternalTable } from "../../../sdk/app/tables/getters"
function pickApi({ tableId, table }: { tableId?: string; table?: Table }) { function pickApi({ tableId, table }: { tableId?: string; table?: Table }) {
if (table && !tableId) { if (table && !tableId) {
@ -50,7 +49,7 @@ export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
return Object.values(entities).map<Table>((entity: Table) => ({ return Object.values(entities).map<Table>((entity: Table) => ({
...entity, ...entity,
type: "external", type: "external",
sourceId: datasource._id, sourceId: datasource._id!,
sql: isSQL(datasource), sql: isSQL(datasource),
})) }))
} else { } else {

View File

@ -21,6 +21,7 @@ import {
SortType, SortType,
StaticQuotaName, StaticQuotaName,
Table, Table,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
import { import {
expectAnyExternalColsAttributes, expectAnyExternalColsAttributes,
@ -65,6 +66,7 @@ describe.each([
type: "table", type: "table",
primary: ["id"], primary: ["id"],
primaryDisplay: "name", primaryDisplay: "name",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
id: { id: {
type: FieldType.AUTO, type: FieldType.AUTO,
@ -880,6 +882,7 @@ describe.each([
async function userTable(): Promise<Table> { async function userTable(): Promise<Table> {
return { return {
name: `users_${generator.word()}`, name: `users_${generator.word()}`,
sourceId: INTERNAL_TABLE_SOURCE_ID,
type: "table", type: "table",
primary: ["id"], primary: ["id"],
schema: { schema: {
@ -1062,6 +1065,7 @@ describe.each([
async function userTable(): Promise<Table> { async function userTable(): Promise<Table> {
return { return {
name: `users_${generator.word()}`, name: `users_${generator.word()}`,
sourceId: INTERNAL_TABLE_SOURCE_ID,
type: "table", type: "table",
primary: ["id"], primary: ["id"],
schema: { schema: {
@ -1597,7 +1601,7 @@ describe.each([
const tableConfig = generateTableConfig() const tableConfig = generateTableConfig()
if (config.datasource) { if (config.datasource) {
tableConfig.sourceId = config.datasource._id tableConfig.sourceId = config.datasource._id!
if (config.datasource.plus) { if (config.datasource.plus) {
tableConfig.type = "external" tableConfig.type = "external"
} }

View File

@ -9,6 +9,7 @@ import {
InternalTable, InternalTable,
FieldSubtype, FieldSubtype,
Row, Row,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
import { checkBuilderEndpoint } from "./utilities/TestFunctions" import { checkBuilderEndpoint } from "./utilities/TestFunctions"
import * as setup from "./utilities" import * as setup from "./utilities"
@ -432,6 +433,7 @@ describe("/tables", () => {
const table = await config.api.table.create({ const table = await config.api.table.create({
name: "table", name: "table",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
"user relationship": { "user relationship": {
type: FieldType.LINK, type: FieldType.LINK,
@ -491,6 +493,7 @@ describe("/tables", () => {
const table = await config.api.table.create({ const table = await config.api.table.create({
name: "table", name: "table",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
"user relationship": { "user relationship": {
type: FieldType.LINK, type: FieldType.LINK,
@ -552,6 +555,7 @@ describe("/tables", () => {
const table = await config.api.table.create({ const table = await config.api.table.create({
name: "table", name: "table",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
"user relationship": { "user relationship": {
type: FieldType.LINK, type: FieldType.LINK,

View File

@ -10,6 +10,7 @@ import {
UIFieldMetadata, UIFieldMetadata,
UpdateViewRequest, UpdateViewRequest,
ViewV2, ViewV2,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
import { generator } from "@budibase/backend-core/tests" import { generator } from "@budibase/backend-core/tests"
import { generateDatasourceID } from "../../../db/utils" import { generateDatasourceID } from "../../../db/utils"
@ -18,6 +19,7 @@ function priceTable(): Table {
return { return {
name: "table", name: "table",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
Price: { Price: {
type: FieldType.NUMBER, type: FieldType.NUMBER,

View File

@ -1,5 +1,9 @@
import { objectStore, roles, constants } from "@budibase/backend-core" import { objectStore, roles, constants } from "@budibase/backend-core"
import { FieldType as FieldTypes } from "@budibase/types" import {
FieldType as FieldTypes,
Table,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types"
export { export {
FieldType as FieldTypes, FieldType as FieldTypes,
RelationshipType, RelationshipType,
@ -70,9 +74,10 @@ export enum SortDirection {
DESCENDING = "DESCENDING", DESCENDING = "DESCENDING",
} }
export const USERS_TABLE_SCHEMA = { export const USERS_TABLE_SCHEMA: Table = {
_id: "ta_users", _id: "ta_users",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
views: {}, views: {},
name: "Users", name: "Users",
// TODO: ADMIN PANEL - when implemented this doesn't need to be carried out // TODO: ADMIN PANEL - when implemented this doesn't need to be carried out
@ -87,12 +92,10 @@ export const USERS_TABLE_SCHEMA = {
}, },
presence: true, presence: true,
}, },
fieldName: "email",
name: "email", name: "email",
}, },
firstName: { firstName: {
name: "firstName", name: "firstName",
fieldName: "firstName",
type: FieldTypes.STRING, type: FieldTypes.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldTypes.STRING,
@ -101,7 +104,6 @@ export const USERS_TABLE_SCHEMA = {
}, },
lastName: { lastName: {
name: "lastName", name: "lastName",
fieldName: "lastName",
type: FieldTypes.STRING, type: FieldTypes.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldTypes.STRING,
@ -109,7 +111,6 @@ export const USERS_TABLE_SCHEMA = {
}, },
}, },
roleId: { roleId: {
fieldName: "roleId",
name: "roleId", name: "roleId",
type: FieldTypes.OPTIONS, type: FieldTypes.OPTIONS,
constraints: { constraints: {
@ -119,7 +120,6 @@ export const USERS_TABLE_SCHEMA = {
}, },
}, },
status: { status: {
fieldName: "status",
name: "status", name: "status",
type: FieldTypes.OPTIONS, type: FieldTypes.OPTIONS,
constraints: { constraints: {

View File

@ -5,6 +5,7 @@ import {
FieldSchema, FieldSchema,
RelationshipFieldMetadata, RelationshipFieldMetadata,
VirtualDocumentType, VirtualDocumentType,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
import { FieldTypes } from "../constants" import { FieldTypes } from "../constants"
export { DocumentType, VirtualDocumentType } from "@budibase/types" export { DocumentType, VirtualDocumentType } from "@budibase/types"
@ -18,7 +19,7 @@ export const enum AppStatus {
} }
export const BudibaseInternalDB = { export const BudibaseInternalDB = {
_id: "bb_internal", _id: INTERNAL_TABLE_SOURCE_ID,
type: dbCore.BUDIBASE_DATASOURCE_TYPE, type: dbCore.BUDIBASE_DATASOURCE_TYPE,
name: "Budibase DB", name: "Budibase DB",
source: "BUDIBASE", source: "BUDIBASE",

View File

@ -12,7 +12,7 @@ import {
Row, Row,
SearchFilters, SearchFilters,
SortJson, SortJson,
ExternalTable, Table,
TableRequest, TableRequest,
Schema, Schema,
} from "@budibase/types" } from "@budibase/types"
@ -262,7 +262,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
id?: string id?: string
) { ) {
// base table // base table
const table: ExternalTable = { const table: Table = {
name: title, name: title,
primary: [GOOGLE_SHEETS_PRIMARY_KEY], primary: [GOOGLE_SHEETS_PRIMARY_KEY],
schema: {}, schema: {},
@ -283,7 +283,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
async buildSchema( async buildSchema(
datasourceId: string, datasourceId: string,
entities: Record<string, ExternalTable> entities: Record<string, Table>
): Promise<Schema> { ): Promise<Schema> {
// not fully configured yet // not fully configured yet
if (!this.config.auth) { if (!this.config.auth) {
@ -291,7 +291,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
} }
await this.connect() await this.connect()
const sheets = this.client.sheetsByIndex const sheets = this.client.sheetsByIndex
const tables: Record<string, ExternalTable> = {} const tables: Record<string, Table> = {}
let errors: Record<string, string> = {} let errors: Record<string, string> = {}
await utils.parallelForeach( await utils.parallelForeach(
sheets, sheets,

View File

@ -2,7 +2,7 @@ import {
DatasourceFieldType, DatasourceFieldType,
Integration, Integration,
Operation, Operation,
ExternalTable, Table,
TableSchema, TableSchema,
QueryJson, QueryJson,
QueryType, QueryType,
@ -380,7 +380,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
*/ */
async buildSchema( async buildSchema(
datasourceId: string, datasourceId: string,
entities: Record<string, ExternalTable> entities: Record<string, Table>
): Promise<Schema> { ): Promise<Schema> {
await this.connect() await this.connect()
let tableInfo: MSSQLTablesResponse[] = await this.runSQL(this.TABLES_SQL) let tableInfo: MSSQLTablesResponse[] = await this.runSQL(this.TABLES_SQL)
@ -394,7 +394,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
.map((record: any) => record.TABLE_NAME) .map((record: any) => record.TABLE_NAME)
.filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1) .filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1)
const tables: Record<string, ExternalTable> = {} const tables: Record<string, Table> = {}
for (let tableName of tableNames) { for (let tableName of tableNames) {
// get the column definition (type) // get the column definition (type)
const definition = await this.runSQL( const definition = await this.runSQL(

View File

@ -4,7 +4,7 @@ import {
QueryType, QueryType,
QueryJson, QueryJson,
SqlQuery, SqlQuery,
ExternalTable, Table,
TableSchema, TableSchema,
DatasourcePlus, DatasourcePlus,
DatasourceFeature, DatasourceFeature,
@ -278,9 +278,9 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
async buildSchema( async buildSchema(
datasourceId: string, datasourceId: string,
entities: Record<string, ExternalTable> entities: Record<string, Table>
): Promise<Schema> { ): Promise<Schema> {
const tables: { [key: string]: ExternalTable } = {} const tables: { [key: string]: Table } = {}
await this.connect() await this.connect()
try { try {

View File

@ -5,7 +5,7 @@ import {
QueryJson, QueryJson,
QueryType, QueryType,
SqlQuery, SqlQuery,
ExternalTable, Table,
DatasourcePlus, DatasourcePlus,
DatasourceFeature, DatasourceFeature,
ConnectionInfo, ConnectionInfo,
@ -263,14 +263,14 @@ class OracleIntegration extends Sql implements DatasourcePlus {
*/ */
async buildSchema( async buildSchema(
datasourceId: string, datasourceId: string,
entities: Record<string, ExternalTable> entities: Record<string, Table>
): Promise<Schema> { ): Promise<Schema> {
const columnsResponse = await this.internalQuery<OracleColumnsResponse>({ const columnsResponse = await this.internalQuery<OracleColumnsResponse>({
sql: this.COLUMNS_SQL, sql: this.COLUMNS_SQL,
}) })
const oracleTables = this.mapColumns(columnsResponse) const oracleTables = this.mapColumns(columnsResponse)
const tables: { [key: string]: ExternalTable } = {} const tables: { [key: string]: Table } = {}
// iterate each table // iterate each table
Object.values(oracleTables).forEach(oracleTable => { Object.values(oracleTables).forEach(oracleTable => {

View File

@ -5,7 +5,7 @@ import {
QueryType, QueryType,
QueryJson, QueryJson,
SqlQuery, SqlQuery,
ExternalTable, Table,
DatasourcePlus, DatasourcePlus,
DatasourceFeature, DatasourceFeature,
ConnectionInfo, ConnectionInfo,
@ -273,7 +273,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
*/ */
async buildSchema( async buildSchema(
datasourceId: string, datasourceId: string,
entities: Record<string, ExternalTable> entities: Record<string, Table>
): Promise<Schema> { ): Promise<Schema> {
let tableKeys: { [key: string]: string[] } = {} let tableKeys: { [key: string]: string[] } = {}
await this.openConnection() await this.openConnection()
@ -300,7 +300,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
const columnsResponse: { rows: PostgresColumn[] } = const columnsResponse: { rows: PostgresColumn[] } =
await this.client.query(this.COLUMNS_SQL) await this.client.query(this.COLUMNS_SQL)
const tables: { [key: string]: ExternalTable } = {} const tables: { [key: string]: Table } = {}
for (let column of columnsResponse.rows) { for (let column of columnsResponse.rows) {
const tableName: string = column.table_name const tableName: string = column.table_name

View File

@ -31,6 +31,7 @@ import { structures } from "@budibase/backend-core/tests"
import TestConfiguration from "../../tests/utilities/TestConfiguration" import TestConfiguration from "../../tests/utilities/TestConfiguration"
import GoogleSheetsIntegration from "../googlesheets" import GoogleSheetsIntegration from "../googlesheets"
import { FieldType, Table, TableSchema } from "@budibase/types" import { FieldType, Table, TableSchema } from "@budibase/types"
import { generateDatasourceID } from "../../db/utils"
describe("Google Sheets Integration", () => { describe("Google Sheets Integration", () => {
let integration: any, let integration: any,
@ -61,6 +62,7 @@ describe("Google Sheets Integration", () => {
function createBasicTable(name: string, columns: string[]): Table { function createBasicTable(name: string, columns: string[]): Table {
return { return {
name, name,
sourceId: generateDatasourceID(),
schema: { schema: {
...columns.reduce((p, c) => { ...columns.reduce((p, c) => {
p[c] = { p[c] = {

View File

@ -4,7 +4,6 @@ import {
SearchFilters, SearchFilters,
Datasource, Datasource,
FieldType, FieldType,
ExternalTable,
} from "@budibase/types" } from "@budibase/types"
import { DocumentType, SEPARATOR } from "../db/utils" import { DocumentType, SEPARATOR } from "../db/utils"
import { InvalidColumns, NoEmptyFilterStrings } from "../constants" import { InvalidColumns, NoEmptyFilterStrings } from "../constants"
@ -301,9 +300,9 @@ function copyExistingPropsOver(
* @param entities The old list of tables, if there was any to look for definitions in. * @param entities The old list of tables, if there was any to look for definitions in.
*/ */
export function finaliseExternalTables( export function finaliseExternalTables(
tables: Record<string, ExternalTable>, tables: Record<string, Table>,
entities: Record<string, ExternalTable> entities: Record<string, Table>
): Record<string, ExternalTable> { ): Record<string, Table> {
let finalTables: Record<string, Table> = {} let finalTables: Record<string, Table> = {}
const tableIds = Object.values(tables).map(table => table._id!) const tableIds = Object.values(tables).map(table => table._id!)
for (let [name, table] of Object.entries(tables)) { for (let [name, table] of Object.entries(tables)) {
@ -316,7 +315,7 @@ export function finaliseExternalTables(
} }
export function checkExternalTables( export function checkExternalTables(
tables: Record<string, ExternalTable> tables: Record<string, Table>
): Record<string, string> { ): Record<string, string> {
const invalidColumns = Object.values(InvalidColumns) as string[] const invalidColumns = Object.values(InvalidColumns) as string[]
const errors: Record<string, string> = {} const errors: Record<string, string> = {}

View File

@ -1,5 +1,11 @@
import { generator } from "@budibase/backend-core/tests" import { generator } from "@budibase/backend-core/tests"
import { BBRequest, FieldType, Row, Table } from "@budibase/types" import {
BBRequest,
FieldType,
Row,
Table,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types"
import * as utils from "../../db/utils" import * as utils from "../../db/utils"
import trimViewRowInfoMiddleware from "../trimViewRowInfo" import trimViewRowInfoMiddleware from "../trimViewRowInfo"
@ -73,6 +79,7 @@ describe("trimViewRowInfo middleware", () => {
const table: Table = { const table: Table = {
_id: tableId, _id: tableId,
name: generator.word(), name: generator.word(),
sourceId: INTERNAL_TABLE_SOURCE_ID,
type: "table", type: "table",
schema: { schema: {
name: { name: {

View File

@ -197,11 +197,7 @@ export async function fetchView(
try { try {
table = await sdk.tables.getTable(viewInfo.meta.tableId) table = await sdk.tables.getTable(viewInfo.meta.tableId)
} catch (err) { } catch (err) {
/* istanbul ignore next */ throw new Error("Unable to retrieve view table.")
table = {
name: "",
schema: {},
}
} }
rows = await outputProcessing(table, response.rows) rows = await outputProcessing(table, response.rows)
} }

View File

@ -15,6 +15,7 @@ import {
expectAnyExternalColsAttributes, expectAnyExternalColsAttributes,
generator, generator,
} from "@budibase/backend-core/tests" } from "@budibase/backend-core/tests"
import datasource from "../../../../../api/routes/datasource"
jest.unmock("mysql2/promise") jest.unmock("mysql2/promise")
@ -23,36 +24,7 @@ jest.setTimeout(30000)
describe.skip("external", () => { describe.skip("external", () => {
const config = new TestConfiguration() const config = new TestConfiguration()
let externalDatasource: Datasource let externalDatasource: Datasource, tableData: Table
const tableData: Table = {
name: generator.word(),
type: "external",
primary: ["id"],
schema: {
id: {
name: "id",
type: FieldType.AUTO,
autocolumn: true,
},
name: {
name: "name",
type: FieldType.STRING,
},
surname: {
name: "surname",
type: FieldType.STRING,
},
age: {
name: "age",
type: FieldType.NUMBER,
},
address: {
name: "address",
type: FieldType.STRING,
},
},
}
beforeAll(async () => { beforeAll(async () => {
const container = await new GenericContainer("mysql") const container = await new GenericContainer("mysql")
@ -84,6 +56,36 @@ describe.skip("external", () => {
}, },
}, },
}) })
tableData = {
name: generator.word(),
type: "external",
primary: ["id"],
sourceId: externalDatasource._id!,
schema: {
id: {
name: "id",
type: FieldType.AUTO,
autocolumn: true,
},
name: {
name: "name",
type: FieldType.STRING,
},
surname: {
name: "surname",
type: FieldType.STRING,
},
age: {
name: "age",
type: FieldType.NUMBER,
},
address: {
name: "address",
type: FieldType.STRING,
},
},
}
}) })
describe("search", () => { describe("search", () => {

View File

@ -1,4 +1,10 @@
import { FieldType, Row, Table, SearchParams } from "@budibase/types" import {
FieldType,
Row,
Table,
SearchParams,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types"
import TestConfiguration from "../../../../../tests/utilities/TestConfiguration" import TestConfiguration from "../../../../../tests/utilities/TestConfiguration"
import { search } from "../internal" import { search } from "../internal"
import { import {
@ -12,6 +18,7 @@ describe("internal", () => {
const tableData: Table = { const tableData: Table = {
name: generator.word(), name: generator.word(),
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
name: "name", name: "name",

View File

@ -5,12 +5,14 @@ import {
FieldTypeSubtypes, FieldTypeSubtypes,
Table, Table,
SearchParams, SearchParams,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
const tableId = "ta_a" const tableId = "ta_a"
const tableWithUserCol: Table = { const tableWithUserCol: Table = {
_id: tableId, _id: tableId,
name: "table", name: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
user: { user: {
name: "user", name: "user",
@ -23,6 +25,7 @@ const tableWithUserCol: Table = {
const tableWithUsersCol: Table = { const tableWithUsersCol: Table = {
_id: tableId, _id: tableId,
name: "table", name: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
user: { user: {
name: "user", name: "user",

View File

@ -35,10 +35,10 @@ export async function save(
opts?: { tableId?: string; renaming?: RenameColumn } opts?: { tableId?: string; renaming?: RenameColumn }
) { ) {
let tableToSave: TableRequest = { let tableToSave: TableRequest = {
...update,
type: "table", type: "table",
_id: buildExternalTableId(datasourceId, update.name), _id: buildExternalTableId(datasourceId, update.name),
sourceId: datasourceId, sourceId: datasourceId,
...update,
} }
const tableId = opts?.tableId || update._id const tableId = opts?.tableId || update._id

View File

@ -76,12 +76,14 @@ export function generateManyLinkSchema(
const primary = table.name + table.primary[0] const primary = table.name + table.primary[0]
const relatedPrimary = relatedTable.name + relatedTable.primary[0] const relatedPrimary = relatedTable.name + relatedTable.primary[0]
const jcTblName = generateJunctionTableName(column, table, relatedTable) const jcTblName = generateJunctionTableName(column, table, relatedTable)
const datasourceId = datasource._id!
// first create the new table // first create the new table
const junctionTable = { const junctionTable = {
_id: buildExternalTableId(datasource._id!, jcTblName), _id: buildExternalTableId(datasourceId, jcTblName),
name: jcTblName, name: jcTblName,
primary: [primary, relatedPrimary], primary: [primary, relatedPrimary],
constrained: [primary, relatedPrimary], constrained: [primary, relatedPrimary],
sourceId: datasourceId,
schema: { schema: {
[primary]: foreignKeyStructure(primary, { [primary]: foreignKeyStructure(primary, {
toTable: table.name, toTable: table.name,

View File

@ -1,20 +1,16 @@
import { context } from "@budibase/backend-core" import { context } from "@budibase/backend-core"
import { import { getMultiIDParams, getTableParams } from "../../../db/utils"
BudibaseInternalDB,
getMultiIDParams,
getTableParams,
} from "../../../db/utils"
import { import {
breakExternalTableId, breakExternalTableId,
isExternalTable, isExternalTable,
isSQL, isSQL,
} from "../../../integrations/utils" } from "../../../integrations/utils"
import { import {
AllDocsResponse,
Database, Database,
Table, Table,
TableResponse, TableResponse,
TableViewsResponse, TableViewsResponse,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
import datasources from "../datasources" import datasources from "../datasources"
import sdk from "../../../sdk" import sdk from "../../../sdk"
@ -27,7 +23,7 @@ export function processInternalTable(table: Table): Table {
return { return {
...table, ...table,
type: "internal", type: "internal",
sourceId: table.sourceId || BudibaseInternalDB._id, sourceId: table.sourceId || INTERNAL_TABLE_SOURCE_ID,
} }
} }

View File

@ -1,4 +1,9 @@
import { FieldType, Table, ViewV2 } from "@budibase/types" import {
FieldType,
INTERNAL_TABLE_SOURCE_ID,
Table,
ViewV2,
} from "@budibase/types"
import { generator } from "@budibase/backend-core/tests" import { generator } from "@budibase/backend-core/tests"
import sdk from "../../.." import sdk from "../../.."
@ -13,6 +18,7 @@ describe("table sdk", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,

View File

@ -1,36 +1,50 @@
import { populateExternalTableSchemas } from "../validation" import { populateExternalTableSchemas } from "../validation"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { AutoReason, Datasource, Table } from "@budibase/types" import {
AutoReason,
Datasource,
FieldType,
RelationshipType,
SourceName,
Table,
} from "@budibase/types"
import { isEqual } from "lodash" import { isEqual } from "lodash"
import { generateDatasourceID } from "../../../../db/utils"
const SCHEMA = { const datasourceId = generateDatasourceID()
const SCHEMA: Datasource = {
source: SourceName.POSTGRES,
type: "datasource",
_id: datasourceId,
entities: { entities: {
client: { client: {
_id: "tableA", _id: "tableA",
name: "client", name: "client",
primary: ["idC"], primary: ["idC"],
primaryDisplay: "Name", primaryDisplay: "Name",
sourceId: datasourceId,
schema: { schema: {
idC: { idC: {
autocolumn: true, autocolumn: true,
externalType: "int unsigned", externalType: "int unsigned",
name: "idC", name: "idC",
type: "number", type: FieldType.NUMBER,
}, },
Name: { Name: {
autocolumn: false, autocolumn: false,
externalType: "varchar(255)", externalType: "varchar(255)",
name: "Name", name: "Name",
type: "string", type: FieldType.STRING,
}, },
project: { project: {
fieldName: "idC", fieldName: "idC",
foreignKey: "idC", foreignKey: "idC",
main: true, main: true,
name: "project", name: "project",
relationshipType: "many-to-one", relationshipType: RelationshipType.MANY_TO_ONE,
tableId: "tableB", tableId: "tableB",
type: "link", type: FieldType.LINK,
}, },
}, },
}, },
@ -39,31 +53,32 @@ const SCHEMA = {
name: "project", name: "project",
primary: ["idP"], primary: ["idP"],
primaryDisplay: "Name", primaryDisplay: "Name",
sourceId: datasourceId,
schema: { schema: {
idC: { idC: {
externalType: "int unsigned", externalType: "int unsigned",
name: "idC", name: "idC",
type: "number", type: FieldType.NUMBER,
}, },
idP: { idP: {
autocolumn: true, autocolumn: true,
externalType: "int unsigned", externalType: "int unsigned",
name: "idProject", name: "idProject",
type: "number", type: FieldType.NUMBER,
}, },
Name: { Name: {
autocolumn: false, autocolumn: false,
externalType: "varchar(255)", externalType: "varchar(255)",
name: "Name", name: "Name",
type: "string", type: FieldType.STRING,
}, },
client: { client: {
fieldName: "idC", fieldName: "idC",
foreignKey: "idC", foreignKey: "idC",
name: "client", name: "client",
relationshipType: "one-to-many", relationshipType: RelationshipType.ONE_TO_MANY,
tableId: "tableA", tableId: "tableA",
type: "link", type: FieldType.LINK,
}, },
}, },
sql: true, sql: true,
@ -95,12 +110,12 @@ describe("validation and update of external table schemas", () => {
function noOtherTableChanges(response: any) { function noOtherTableChanges(response: any) {
checkOtherColumns( checkOtherColumns(
response.entities!.client!, response.entities!.client!,
SCHEMA.entities.client as Table, SCHEMA.entities!.client,
OTHER_CLIENT_COLS OTHER_CLIENT_COLS
) )
checkOtherColumns( checkOtherColumns(
response.entities!.project!, response.entities!.project!,
SCHEMA.entities.project as Table, SCHEMA.entities!.project,
OTHER_PROJECT_COLS OTHER_PROJECT_COLS
) )
} }

View File

@ -2,6 +2,7 @@ import _ from "lodash"
import { import {
FieldSchema, FieldSchema,
FieldType, FieldType,
INTERNAL_TABLE_SOURCE_ID,
Table, Table,
TableSchema, TableSchema,
ViewV2, ViewV2,
@ -14,6 +15,7 @@ describe("table sdk", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,

View File

@ -56,6 +56,7 @@ import {
CreateViewRequest, CreateViewRequest,
RelationshipFieldMetadata, RelationshipFieldMetadata,
User, User,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
import API from "./api" import API from "./api"
@ -68,6 +69,10 @@ type DefaultUserValues = {
csrfToken: string csrfToken: string
} }
interface TableToBuild extends Omit<Table, "sourceId"> {
sourceId?: string
}
class TestConfiguration { class TestConfiguration {
server: any server: any
request: supertest.SuperTest<supertest.Test> | undefined request: supertest.SuperTest<supertest.Test> | undefined
@ -538,10 +543,13 @@ class TestConfiguration {
// TABLE // TABLE
async updateTable( async updateTable(
config?: Table, config?: TableToBuild,
{ skipReassigning } = { skipReassigning: false } { skipReassigning } = { skipReassigning: false }
): Promise<Table> { ): Promise<Table> {
config = config || basicTable() config = config || basicTable()
if (!config.sourceId) {
config.sourceId = INTERNAL_TABLE_SOURCE_ID
}
const response = await this._req(config, null, controllers.table.save) const response = await this._req(config, null, controllers.table.save)
if (!skipReassigning) { if (!skipReassigning) {
this.table = response this.table = response
@ -549,13 +557,19 @@ class TestConfiguration {
return response return response
} }
async createTable(config?: Table, options = { skipReassigning: false }) { async createTable(
config?: TableToBuild,
options = { skipReassigning: false }
) {
if (config != null && config._id) { if (config != null && config._id) {
delete config._id delete config._id
} }
config = config || basicTable() config = config || basicTable()
if (!config.sourceId) {
config.sourceId = INTERNAL_TABLE_SOURCE_ID
}
if (this.datasource && !config.sourceId) { if (this.datasource && !config.sourceId) {
config.sourceId = this.datasource._id config.sourceId = this.datasource._id || INTERNAL_TABLE_SOURCE_ID
if (this.datasource.plus) { if (this.datasource.plus) {
config.type = "external" config.type = "external"
} }
@ -572,12 +586,15 @@ class TestConfiguration {
async createLinkedTable( async createLinkedTable(
relationshipType = RelationshipType.ONE_TO_MANY, relationshipType = RelationshipType.ONE_TO_MANY,
links: any = ["link"], links: any = ["link"],
config?: Table config?: TableToBuild
) { ) {
if (!this.table) { if (!this.table) {
throw "Must have created a table first." throw "Must have created a table first."
} }
const tableConfig = config || basicTable() const tableConfig = config || basicTable()
if (!tableConfig.sourceId) {
tableConfig.sourceId = INTERNAL_TABLE_SOURCE_ID
}
tableConfig.primaryDisplay = "name" tableConfig.primaryDisplay = "name"
for (let link of links) { for (let link of links) {
tableConfig.schema[link] = { tableConfig.schema[link] = {
@ -590,7 +607,7 @@ class TestConfiguration {
} }
if (this.datasource && !tableConfig.sourceId) { if (this.datasource && !tableConfig.sourceId) {
tableConfig.sourceId = this.datasource._id tableConfig.sourceId = this.datasource._id || INTERNAL_TABLE_SOURCE_ID
if (this.datasource.plus) { if (this.datasource.plus) {
tableConfig.type = "external" tableConfig.type = "external"
} }

View File

@ -19,12 +19,14 @@ import {
FieldType, FieldType,
SourceName, SourceName,
Table, Table,
INTERNAL_TABLE_SOURCE_ID,
} from "@budibase/types" } from "@budibase/types"
export function basicTable(): Table { export function basicTable(): Table {
return { return {
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,

View File

@ -1,6 +1,11 @@
import { inputProcessing } from ".." import { inputProcessing } from ".."
import { generator, structures } from "@budibase/backend-core/tests" import { generator, structures } from "@budibase/backend-core/tests"
import { FieldType, FieldTypeSubtypes, Table } from "@budibase/types" import {
FieldType,
FieldTypeSubtypes,
INTERNAL_TABLE_SOURCE_ID,
Table,
} from "@budibase/types"
import * as bbReferenceProcessor from "../bbReferenceProcessor" import * as bbReferenceProcessor from "../bbReferenceProcessor"
jest.mock("../bbReferenceProcessor", (): typeof bbReferenceProcessor => ({ jest.mock("../bbReferenceProcessor", (): typeof bbReferenceProcessor => ({
@ -20,6 +25,7 @@ describe("rowProcessor - inputProcessing", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,
@ -70,6 +76,7 @@ describe("rowProcessor - inputProcessing", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,
@ -110,6 +117,7 @@ describe("rowProcessor - inputProcessing", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,
@ -150,6 +158,7 @@ describe("rowProcessor - inputProcessing", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,

View File

@ -2,6 +2,7 @@ import {
FieldSubtype, FieldSubtype,
FieldType, FieldType,
FieldTypeSubtypes, FieldTypeSubtypes,
INTERNAL_TABLE_SOURCE_ID,
Table, Table,
} from "@budibase/types" } from "@budibase/types"
import { outputProcessing } from ".." import { outputProcessing } from ".."
@ -26,6 +27,7 @@ describe("rowProcessor - outputProcessing", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,
@ -71,6 +73,7 @@ describe("rowProcessor - outputProcessing", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,
@ -108,6 +111,7 @@ describe("rowProcessor - outputProcessing", () => {
_id: generator.guid(), _id: generator.guid(),
name: "TestTable", name: "TestTable",
type: "table", type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
schema: { schema: {
name: { name: {
type: FieldType.STRING, type: FieldType.STRING,

View File

@ -17,7 +17,7 @@ import { clearLock, updateLock } from "../utilities/redis"
import { Socket } from "socket.io" import { Socket } from "socket.io"
import { BuilderSocketEvent } from "@budibase/shared-core" import { BuilderSocketEvent } from "@budibase/shared-core"
import { processInternalTable } from "../sdk/app/tables/getters" import { processInternalTable } from "../sdk/app/tables/getters"
import { isExternalTable, isInternalTable } from "../integrations/utils" import { isInternalTable } from "../integrations/utils"
export default class BuilderSocket extends BaseSocket { export default class BuilderSocket extends BaseSocket {
constructor(app: Koa, server: http.Server) { constructor(app: Koa, server: http.Server) {

View File

@ -3,14 +3,16 @@ import { View, ViewV2 } from "../view"
import { RenameColumn } from "../../../sdk" import { RenameColumn } from "../../../sdk"
import { TableSchema } from "./schema" import { TableSchema } from "./schema"
export const INTERNAL_TABLE_SOURCE_ID = "bb_internal"
export interface Table extends Document { export interface Table extends Document {
type?: string type?: string
views?: { [key: string]: View | ViewV2 } views?: { [key: string]: View | ViewV2 }
name: string name: string
sourceId: string
primary?: string[] primary?: string[]
schema: TableSchema schema: TableSchema
primaryDisplay?: string primaryDisplay?: string
sourceId?: string
relatedFormula?: string[] relatedFormula?: string[]
constrained?: string[] constrained?: string[]
sql?: boolean sql?: boolean
@ -19,10 +21,6 @@ export interface Table extends Document {
rowHeight?: number rowHeight?: number
} }
export interface ExternalTable extends Table {
sourceId: string
}
export interface TableRequest extends Table { export interface TableRequest extends Table {
_rename?: RenameColumn _rename?: RenameColumn
created?: boolean created?: boolean

View File

@ -1,4 +1,4 @@
import { ExternalTable, Table } from "../documents" import { Table } from "../documents"
export const PASSWORD_REPLACEMENT = "--secret-value--" export const PASSWORD_REPLACEMENT = "--secret-value--"
@ -176,7 +176,7 @@ export interface IntegrationBase {
} }
export interface Schema { export interface Schema {
tables: Record<string, ExternalTable> tables: Record<string, Table>
errors: Record<string, string> errors: Record<string, string>
} }
@ -187,7 +187,7 @@ export interface DatasourcePlus extends IntegrationBase {
getStringConcat(parts: string[]): string getStringConcat(parts: string[]): string
buildSchema( buildSchema(
datasourceId: string, datasourceId: string,
entities: Record<string, ExternalTable> entities: Record<string, Table>
): Promise<Schema> ): Promise<Schema>
getTableNames(): Promise<string[]> getTableNames(): Promise<string[]>
} }