Merge pull request #12177 from Budibase/feature/make-table-source-id-required
Make sourceId property of table required (for all table types)
This commit is contained in:
commit
2bfdd9769e
|
@ -5,4 +5,4 @@ package-lock.json
|
|||
release/
|
||||
dist/
|
||||
routify
|
||||
.routify/
|
||||
.routify/
|
||||
|
|
|
@ -580,7 +580,7 @@ export const getFrontendStore = () => {
|
|||
let table = validTables.find(table => {
|
||||
return (
|
||||
table.sourceId !== BUDIBASE_INTERNAL_DB_ID &&
|
||||
table.type === DB_TYPE_INTERNAL
|
||||
table.sourceType === DB_TYPE_INTERNAL
|
||||
)
|
||||
})
|
||||
if (table) {
|
||||
|
@ -591,7 +591,7 @@ export const getFrontendStore = () => {
|
|||
table = validTables.find(table => {
|
||||
return (
|
||||
table.sourceId === BUDIBASE_INTERNAL_DB_ID &&
|
||||
table.type === DB_TYPE_INTERNAL
|
||||
table.sourceType === DB_TYPE_INTERNAL
|
||||
)
|
||||
})
|
||||
if (table) {
|
||||
|
@ -599,7 +599,7 @@ export const getFrontendStore = () => {
|
|||
}
|
||||
|
||||
// Finally try an external table
|
||||
return validTables.find(table => table.type === DB_TYPE_EXTERNAL)
|
||||
return validTables.find(table => table.sourceType === DB_TYPE_EXTERNAL)
|
||||
},
|
||||
enrichEmptySettings: (component, opts) => {
|
||||
if (!component?._component) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
$: linkedTable = $tables.list.find(table => table._id === linkedTableId)
|
||||
$: schema = linkedTable?.schema
|
||||
$: table = $tables.list.find(table => table._id === tableId)
|
||||
$: type = table?.type
|
||||
$: fetchData(tableId, rowId)
|
||||
$: {
|
||||
let rowLabel = row?.[table?.primaryDisplay]
|
||||
|
@ -41,5 +40,5 @@
|
|||
</script>
|
||||
|
||||
{#if row && row._id === rowId}
|
||||
<Table {title} {schema} {data} {type} />
|
||||
<Table {title} {schema} {data} />
|
||||
{/if}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import GridRelationshipButton from "components/backend/DataTable/buttons/grid/GridRelationshipButton.svelte"
|
||||
import GridEditColumnModal from "components/backend/DataTable/modals/grid/GridEditColumnModal.svelte"
|
||||
import GridUsersTableButton from "components/backend/DataTable/modals/grid/GridUsersTableButton.svelte"
|
||||
import { DB_TYPE_EXTERNAL } from "constants/backend"
|
||||
|
||||
const userSchemaOverrides = {
|
||||
firstName: { displayName: "First name", disabled: true },
|
||||
|
@ -27,7 +28,7 @@
|
|||
|
||||
$: id = $tables.selected?._id
|
||||
$: isUsersTable = id === TableNames.USERS
|
||||
$: isInternal = $tables.selected?.type !== "external"
|
||||
$: isInternal = $tables.selected?.sourceType !== DB_TYPE_EXTERNAL
|
||||
$: gridDatasource = {
|
||||
type: "table",
|
||||
tableId: id,
|
||||
|
@ -46,10 +47,7 @@
|
|||
tables.replaceTable(id, e.detail)
|
||||
|
||||
// We need to refresh datasources when an external table changes.
|
||||
// Type "external" may exist - sometimes type is "table" and sometimes it
|
||||
// is "external" - it has different meanings in different endpoints.
|
||||
// If we check both these then we hopefully catch all external tables.
|
||||
if (e.detail?.type === "external" || e.detail?.sql) {
|
||||
if (e.detail?.sourceType === DB_TYPE_EXTERNAL) {
|
||||
await datasources.fetch()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
let hideAutocolumns = true
|
||||
let data = []
|
||||
let loading = false
|
||||
let type = "internal"
|
||||
|
||||
$: name = view.name
|
||||
$: calculation = view.calculation
|
||||
|
@ -65,7 +64,6 @@
|
|||
tableId={view.tableId}
|
||||
{data}
|
||||
{loading}
|
||||
{type}
|
||||
rowCount={10}
|
||||
allowEditing={false}
|
||||
bind:hideAutocolumns
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
<ImportButton
|
||||
{disabled}
|
||||
tableId={$datasource?.tableId}
|
||||
tableType={$definition?.type}
|
||||
tableType={$definition?.sourceType}
|
||||
on:importrows={rows.actions.refreshData}
|
||||
/>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
ALLOWABLE_NUMBER_TYPES,
|
||||
SWITCHABLE_TYPES,
|
||||
PrettyRelationshipDefinitions,
|
||||
DB_TYPE_EXTERNAL,
|
||||
} from "constants/backend"
|
||||
import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
|
@ -254,10 +255,11 @@
|
|||
!uneditable &&
|
||||
editableColumn?.type !== AUTO_TYPE &&
|
||||
!editableColumn.autocolumn
|
||||
$: external = table.type === "external"
|
||||
$: externalTable = table.sourceType === DB_TYPE_EXTERNAL
|
||||
// in the case of internal tables the sourceId will just be undefined
|
||||
$: tableOptions = $tables.list.filter(
|
||||
opt => opt.type === table.type && table.sourceId === opt.sourceId
|
||||
opt =>
|
||||
opt.sourceType === table.sourceType && table.sourceId === opt.sourceId
|
||||
)
|
||||
$: typeEnabled =
|
||||
!originalName ||
|
||||
|
@ -409,7 +411,7 @@
|
|||
editableColumn.type === FieldType.BB_REFERENCE &&
|
||||
editableColumn.subtype === FieldSubtype.USERS
|
||||
|
||||
if (!external) {
|
||||
if (!externalTable) {
|
||||
return [
|
||||
FIELDS.STRING,
|
||||
FIELDS.BARCODEQR,
|
||||
|
@ -441,7 +443,7 @@
|
|||
isUsers ? FIELDS.USERS : FIELDS.USER,
|
||||
]
|
||||
// no-sql or a spreadsheet
|
||||
if (!external || table.sql) {
|
||||
if (!externalTable || table.sql) {
|
||||
fields = [...fields, FIELDS.LINK, FIELDS.ARRAY]
|
||||
}
|
||||
return fields
|
||||
|
@ -486,7 +488,7 @@
|
|||
})
|
||||
}
|
||||
const newError = {}
|
||||
if (!external && fieldInfo.name?.startsWith("_")) {
|
||||
if (!externalTable && fieldInfo.name?.startsWith("_")) {
|
||||
newError.name = `Column name cannot start with an underscore.`
|
||||
} else if (fieldInfo.name && !fieldInfo.name.match(ValidColumnNameRegex)) {
|
||||
newError.name = `Illegal character; must be alpha-numeric.`
|
||||
|
@ -498,7 +500,7 @@
|
|||
newError.name = `Column name already in use.`
|
||||
}
|
||||
|
||||
if (fieldInfo.type == "auto" && !fieldInfo.subtype) {
|
||||
if (fieldInfo.type === "auto" && !fieldInfo.subtype) {
|
||||
newError.subtype = `Auto Column requires a type`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { Select, Toggle, Multiselect } from "@budibase/bbui"
|
||||
import { FIELDS } from "constants/backend"
|
||||
import { DB_TYPE_INTERNAL, FIELDS } from "constants/backend"
|
||||
import { API } from "api"
|
||||
import { parseFile } from "./utils"
|
||||
|
||||
|
@ -169,7 +169,7 @@
|
|||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if tableType === "internal"}
|
||||
{#if tableType === DB_TYPE_INTERNAL}
|
||||
<br />
|
||||
<Toggle
|
||||
bind:value={updateExistingRows}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import {
|
||||
BUDIBASE_INTERNAL_DB_ID,
|
||||
BUDIBASE_DATASOURCE_TYPE,
|
||||
DB_TYPE_INTERNAL,
|
||||
} from "constants/backend"
|
||||
|
||||
$: tableNames = $tables.list.map(table => table.name)
|
||||
|
@ -55,8 +56,9 @@
|
|||
name,
|
||||
schema: { ...schema },
|
||||
rows,
|
||||
type: "internal",
|
||||
type: "table",
|
||||
sourceId: targetDatasourceId,
|
||||
sourceType: DB_TYPE_INTERNAL,
|
||||
}
|
||||
|
||||
// Only set primary display if defined
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import { DB_TYPE_EXTERNAL } from "constants/backend"
|
||||
|
||||
export let table
|
||||
|
||||
|
@ -27,8 +28,8 @@
|
|||
let willBeDeleted
|
||||
let deleteTableName
|
||||
|
||||
$: external = table?.type === "external"
|
||||
$: allowDeletion = !external || table?.created
|
||||
$: externalTable = table?.sourceType === DB_TYPE_EXTERNAL
|
||||
$: allowDeletion = !externalTable || table?.created
|
||||
|
||||
function showDeleteModal() {
|
||||
templateScreens = $store.screens.filter(
|
||||
|
@ -48,7 +49,7 @@
|
|||
for (let screen of templateScreens) {
|
||||
await store.actions.screens.delete(screen)
|
||||
}
|
||||
if (table.type === "external") {
|
||||
if (table.sourceType === DB_TYPE_EXTERNAL) {
|
||||
await datasources.fetch()
|
||||
}
|
||||
notifications.success("Table deleted")
|
||||
|
@ -91,7 +92,7 @@
|
|||
<div slot="control" class="icon">
|
||||
<Icon s hoverable name="MoreSmallList" />
|
||||
</div>
|
||||
{#if !external}
|
||||
{#if !externalTable}
|
||||
<MenuItem icon="Edit" on:click={editorModal.show}>Edit</MenuItem>
|
||||
{/if}
|
||||
<MenuItem icon="Delete" on:click={showDeleteModal}>Delete</MenuItem>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</script>
|
||||
|
||||
<div class="table">
|
||||
<Table {schema} data={rowsCopy} type="external" allowEditing={false} />
|
||||
<Table {schema} data={rowsCopy} allowEditing={false} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { ModalContent, Body, Input, notifications } from "@budibase/bbui"
|
||||
import { tables, datasources } from "stores/backend"
|
||||
import { goto } from "@roxi/routify"
|
||||
import { DB_TYPE_EXTERNAL } from "constants/backend"
|
||||
|
||||
export let datasource
|
||||
|
||||
|
@ -16,9 +17,10 @@
|
|||
function buildDefaultTable(tableName, datasourceId) {
|
||||
return {
|
||||
name: tableName,
|
||||
type: "external",
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
sourceId: datasourceId,
|
||||
sourceType: DB_TYPE_EXTERNAL,
|
||||
schema: {
|
||||
id: {
|
||||
autocolumn: true,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import { tables, datasources } from "stores/backend"
|
||||
import { goto } from "@roxi/routify"
|
||||
import { onMount } from "svelte"
|
||||
import { BUDIBASE_INTERNAL_DB_ID } from "constants/backend"
|
||||
import { BUDIBASE_INTERNAL_DB_ID, DB_TYPE_EXTERNAL } from "constants/backend"
|
||||
import { TableNames } from "constants"
|
||||
import { store } from "builderStore"
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
$: store.actions.websocket.selectResource(BUDIBASE_INTERNAL_DB_ID)
|
||||
$: internalTablesBySourceId = $tables.list.filter(
|
||||
table =>
|
||||
table.type !== "external" &&
|
||||
table.sourceType !== DB_TYPE_EXTERNAL &&
|
||||
table.sourceId === BUDIBASE_INTERNAL_DB_ID &&
|
||||
table._id !== TableNames.USERS
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import ICONS from "components/backend/DatasourceNavigator/icons"
|
||||
import { tables, datasources } from "stores/backend"
|
||||
import { goto } from "@roxi/routify"
|
||||
import { DEFAULT_BB_DATASOURCE_ID } from "constants/backend"
|
||||
import { DEFAULT_BB_DATASOURCE_ID, DB_TYPE_EXTERNAL } from "constants/backend"
|
||||
import { onMount } from "svelte"
|
||||
import { store } from "builderStore"
|
||||
|
||||
|
@ -13,7 +13,8 @@
|
|||
$: store.actions.websocket.selectResource(DEFAULT_BB_DATASOURCE_ID)
|
||||
$: internalTablesBySourceId = $tables.list.filter(
|
||||
table =>
|
||||
table.type !== "external" && table.sourceId === DEFAULT_BB_DATASOURCE_ID
|
||||
table.sourceType !== DB_TYPE_EXTERNAL &&
|
||||
table.sourceId === DEFAULT_BB_DATASOURCE_ID
|
||||
)
|
||||
|
||||
onMount(() => {
|
||||
|
|
|
@ -2,7 +2,7 @@ version: "3.8"
|
|||
services:
|
||||
db:
|
||||
container_name: postgres
|
||||
image: postgres:15
|
||||
image: postgres:15-bullseye
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
CreateDatasourceResponse,
|
||||
Datasource,
|
||||
DatasourcePlus,
|
||||
ExternalTable,
|
||||
FetchDatasourceInfoRequest,
|
||||
FetchDatasourceInfoResponse,
|
||||
IntegrationBase,
|
||||
|
@ -59,7 +58,7 @@ async function buildSchemaHelper(datasource: Datasource): Promise<Schema> {
|
|||
const connector = (await getConnector(datasource)) as DatasourcePlus
|
||||
return await connector.buildSchema(
|
||||
datasource._id!,
|
||||
datasource.entities! as Record<string, ExternalTable>
|
||||
datasource.entities! as Record<string, Table>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { context } from "@budibase/backend-core"
|
||||
import { isExternalTable } from "../../../integrations/utils"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
import { APP_PREFIX, DocumentType } from "../../../db/utils"
|
||||
|
||||
export async function addRev(
|
||||
body: { _id?: string; _rev?: string },
|
||||
tableId?: string
|
||||
) {
|
||||
if (!body._id || (tableId && isExternalTable(tableId))) {
|
||||
if (!body._id || (tableId && isExternalTableID(tableId))) {
|
||||
return body
|
||||
}
|
||||
let id = body._id
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { quotas } from "@budibase/pro"
|
||||
import * as internal from "./internal"
|
||||
import * as external from "./external"
|
||||
import { isExternalTable } from "../../../integrations/utils"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
import {
|
||||
Ctx,
|
||||
UserCtx,
|
||||
|
@ -30,7 +30,7 @@ import { Format } from "../view/exporters"
|
|||
export * as views from "./views"
|
||||
|
||||
function pickApi(tableId: any) {
|
||||
if (isExternalTable(tableId)) {
|
||||
if (isExternalTableID(tableId)) {
|
||||
return external
|
||||
}
|
||||
return internal
|
||||
|
@ -227,7 +227,7 @@ export async function search(ctx: Ctx<SearchRowRequest, SearchRowResponse>) {
|
|||
export async function validate(ctx: Ctx<Row, ValidateResponse>) {
|
||||
const tableId = utils.getTableId(ctx)
|
||||
// external tables are hard to validate currently
|
||||
if (isExternalTable(tableId)) {
|
||||
if (isExternalTableID(tableId)) {
|
||||
ctx.body = { valid: true, errors: {} }
|
||||
} else {
|
||||
ctx.body = await sdk.rows.utils.validate({
|
||||
|
|
|
@ -5,34 +5,38 @@ import {
|
|||
isSchema,
|
||||
validate as validateSchema,
|
||||
} from "../../../utilities/schema"
|
||||
import { isExternalTable, isSQL } from "../../../integrations/utils"
|
||||
import {
|
||||
isExternalTable,
|
||||
isExternalTableID,
|
||||
isSQL,
|
||||
} from "../../../integrations/utils"
|
||||
import { events } from "@budibase/backend-core"
|
||||
import {
|
||||
BulkImportRequest,
|
||||
BulkImportResponse,
|
||||
DocumentType,
|
||||
FetchTablesResponse,
|
||||
MigrateRequest,
|
||||
MigrateResponse,
|
||||
Row,
|
||||
SaveTableRequest,
|
||||
SaveTableResponse,
|
||||
Table,
|
||||
TableResponse,
|
||||
TableSourceType,
|
||||
UserCtx,
|
||||
Row,
|
||||
SEPARATOR,
|
||||
} from "@budibase/types"
|
||||
import sdk from "../../../sdk"
|
||||
import { jsonFromCsvString } from "../../../utilities/csv"
|
||||
import { builderSocket } from "../../../websockets"
|
||||
import { cloneDeep, isEqual } from "lodash"
|
||||
import { processInternalTable } from "../../../sdk/app/tables/getters"
|
||||
|
||||
function pickApi({ tableId, table }: { tableId?: string; table?: Table }) {
|
||||
if (table && !tableId) {
|
||||
tableId = table._id
|
||||
}
|
||||
if (table && table.type === "external") {
|
||||
if (table && isExternalTable(table)) {
|
||||
return external
|
||||
} else if (tableId && isExternalTable(tableId)) {
|
||||
}
|
||||
if (tableId && isExternalTableID(tableId)) {
|
||||
return external
|
||||
}
|
||||
return internal
|
||||
|
@ -49,8 +53,8 @@ export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
|
|||
if (entities) {
|
||||
return Object.values(entities).map<Table>((entity: Table) => ({
|
||||
...entity,
|
||||
type: "external",
|
||||
sourceId: datasource._id,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
sourceId: datasource._id!,
|
||||
sql: isSQL(datasource),
|
||||
}))
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
SaveTableRequest,
|
||||
SaveTableResponse,
|
||||
Table,
|
||||
TableSourceType,
|
||||
UserCtx,
|
||||
} from "@budibase/types"
|
||||
import sdk from "../../../sdk"
|
||||
|
@ -16,10 +17,11 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
|
|||
let tableToSave: Table & {
|
||||
_rename?: RenameColumn
|
||||
} = {
|
||||
type: "table",
|
||||
_id: generateTableID(),
|
||||
views: {},
|
||||
...rest,
|
||||
type: "table",
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
views: {},
|
||||
}
|
||||
const renaming = tableToSave._rename
|
||||
delete tableToSave._rename
|
||||
|
|
|
@ -7,7 +7,7 @@ exports[`/datasources fetch returns all the datasources from the server 1`] = `
|
|||
"entities": [
|
||||
{
|
||||
"_id": "ta_users",
|
||||
"_rev": "1-2375e1bc58aeec664dc1b1f04ad43e44",
|
||||
"_rev": "1-73b7912e6cbdd3d696febc60f3715844",
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"name": "Users",
|
||||
"primaryDisplay": "email",
|
||||
|
@ -21,7 +21,6 @@ exports[`/datasources fetch returns all the datasources from the server 1`] = `
|
|||
"presence": true,
|
||||
"type": "string",
|
||||
},
|
||||
"fieldName": "email",
|
||||
"name": "email",
|
||||
"type": "string",
|
||||
},
|
||||
|
@ -30,7 +29,6 @@ exports[`/datasources fetch returns all the datasources from the server 1`] = `
|
|||
"presence": false,
|
||||
"type": "string",
|
||||
},
|
||||
"fieldName": "firstName",
|
||||
"name": "firstName",
|
||||
"type": "string",
|
||||
},
|
||||
|
@ -39,7 +37,6 @@ exports[`/datasources fetch returns all the datasources from the server 1`] = `
|
|||
"presence": false,
|
||||
"type": "string",
|
||||
},
|
||||
"fieldName": "lastName",
|
||||
"name": "lastName",
|
||||
"type": "string",
|
||||
},
|
||||
|
@ -54,7 +51,6 @@ exports[`/datasources fetch returns all the datasources from the server 1`] = `
|
|||
"presence": false,
|
||||
"type": "string",
|
||||
},
|
||||
"fieldName": "roleId",
|
||||
"name": "roleId",
|
||||
"type": "options",
|
||||
},
|
||||
|
@ -67,11 +63,12 @@ exports[`/datasources fetch returns all the datasources from the server 1`] = `
|
|||
"presence": false,
|
||||
"type": "string",
|
||||
},
|
||||
"fieldName": "status",
|
||||
"name": "status",
|
||||
"type": "options",
|
||||
},
|
||||
},
|
||||
"sourceId": "bb_internal",
|
||||
"sourceType": "internal",
|
||||
"type": "table",
|
||||
"updatedAt": "2020-01-01T00:00:00.000Z",
|
||||
"views": {},
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
FieldSchema,
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
MonthlyQuotaName,
|
||||
PermissionLevel,
|
||||
QuotaUsageType,
|
||||
|
@ -21,6 +22,7 @@ import {
|
|||
SortType,
|
||||
StaticQuotaName,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import {
|
||||
expectAnyExternalColsAttributes,
|
||||
|
@ -65,6 +67,8 @@ describe.each([
|
|||
type: "table",
|
||||
primary: ["id"],
|
||||
primaryDisplay: "name",
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
schema: {
|
||||
id: {
|
||||
type: FieldType.AUTO,
|
||||
|
@ -134,9 +138,22 @@ describe.each([
|
|||
}
|
||||
: undefined
|
||||
|
||||
async function createTable(
|
||||
cfg: Omit<SaveTableRequest, "sourceId" | "sourceType">,
|
||||
opts?: { skipReassigning: boolean }
|
||||
) {
|
||||
let table
|
||||
if (dsProvider) {
|
||||
table = await config.createExternalTable(cfg, opts)
|
||||
} else {
|
||||
table = await config.createTable(cfg, opts)
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
const table = await config.createTable(tableConfig)
|
||||
let table = await createTable(tableConfig)
|
||||
tableId = table._id!
|
||||
})
|
||||
|
||||
|
@ -165,7 +182,7 @@ describe.each([
|
|||
const queryUsage = await getQueryUsage()
|
||||
|
||||
const tableConfig = generateTableConfig()
|
||||
const newTable = await config.createTable(
|
||||
const newTable = await createTable(
|
||||
{
|
||||
...tableConfig,
|
||||
name: "TestTableAuto",
|
||||
|
@ -242,7 +259,7 @@ describe.each([
|
|||
})
|
||||
|
||||
it("should list all rows for given tableId", async () => {
|
||||
const table = await config.createTable(generateTableConfig(), {
|
||||
const table = await createTable(generateTableConfig(), {
|
||||
skipReassigning: true,
|
||||
})
|
||||
const tableId = table._id!
|
||||
|
@ -323,7 +340,7 @@ describe.each([
|
|||
inclusion: ["Alpha", "Beta", "Gamma"],
|
||||
},
|
||||
}
|
||||
const table = await config.createTable({
|
||||
const table = await createTable({
|
||||
name: "TestTable2",
|
||||
type: "table",
|
||||
schema: {
|
||||
|
@ -438,7 +455,8 @@ describe.each([
|
|||
|
||||
describe("view save", () => {
|
||||
it("views have extra data trimmed", async () => {
|
||||
const table = await config.createTable({
|
||||
const table = await createTable({
|
||||
type: "table",
|
||||
name: "orders",
|
||||
primary: ["OrderID"],
|
||||
schema: {
|
||||
|
@ -494,7 +512,7 @@ describe.each([
|
|||
describe("patch", () => {
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should update only the fields that are supplied", async () => {
|
||||
|
@ -548,7 +566,7 @@ describe.each([
|
|||
describe("destroy", () => {
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should be able to delete a row", async () => {
|
||||
|
@ -566,7 +584,7 @@ describe.each([
|
|||
describe("validate", () => {
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should return no errors on valid row", async () => {
|
||||
|
@ -603,7 +621,7 @@ describe.each([
|
|||
describe("bulkDelete", () => {
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should be able to delete a bulk set of rows", async () => {
|
||||
|
@ -687,7 +705,7 @@ describe.each([
|
|||
describe("fetchView", () => {
|
||||
beforeEach(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should be able to fetch tables contents via 'view'", async () => {
|
||||
|
@ -735,7 +753,7 @@ describe.each([
|
|||
describe("fetchEnrichedRows", () => {
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should allow enriching some linked rows", async () => {
|
||||
|
@ -808,7 +826,7 @@ describe.each([
|
|||
describe("attachments", () => {
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should allow enriching attachment rows", async () => {
|
||||
|
@ -839,7 +857,7 @@ describe.each([
|
|||
describe("exportData", () => {
|
||||
beforeAll(async () => {
|
||||
const tableConfig = generateTableConfig()
|
||||
table = await config.createTable(tableConfig)
|
||||
table = await createTable(tableConfig)
|
||||
})
|
||||
|
||||
it("should allow exporting all columns", async () => {
|
||||
|
@ -880,6 +898,8 @@ describe.each([
|
|||
async function userTable(): Promise<Table> {
|
||||
return {
|
||||
name: `users_${generator.word()}`,
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
schema: {
|
||||
|
@ -925,7 +945,7 @@ describe.each([
|
|||
|
||||
describe("create", () => {
|
||||
it("should persist a new row with only the provided view fields", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
const view = await config.createView({
|
||||
schema: {
|
||||
name: { visible: true },
|
||||
|
@ -960,7 +980,7 @@ describe.each([
|
|||
|
||||
describe("patch", () => {
|
||||
it("should update only the view fields for a row", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
const tableId = table._id!
|
||||
const view = await config.createView({
|
||||
schema: {
|
||||
|
@ -1001,7 +1021,7 @@ describe.each([
|
|||
|
||||
describe("destroy", () => {
|
||||
it("should be able to delete a row", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
const tableId = table._id!
|
||||
const view = await config.createView({
|
||||
schema: {
|
||||
|
@ -1025,7 +1045,7 @@ describe.each([
|
|||
})
|
||||
|
||||
it("should be able to delete multiple rows", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
const tableId = table._id!
|
||||
const view = await config.createView({
|
||||
schema: {
|
||||
|
@ -1062,6 +1082,8 @@ describe.each([
|
|||
async function userTable(): Promise<Table> {
|
||||
return {
|
||||
name: `users_${generator.word()}`,
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
schema: {
|
||||
|
@ -1088,7 +1110,7 @@ describe.each([
|
|||
}
|
||||
|
||||
it("returns empty rows from view when no schema is passed", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
const rows = await Promise.all(
|
||||
Array.from({ length: 10 }, () =>
|
||||
config.api.row.save(table._id!, { tableId: table._id })
|
||||
|
@ -1119,7 +1141,7 @@ describe.each([
|
|||
})
|
||||
|
||||
it("searching respects the view filters", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
|
||||
await Promise.all(
|
||||
Array.from({ length: 10 }, () =>
|
||||
|
@ -1243,7 +1265,7 @@ describe.each([
|
|||
|
||||
describe("sorting", () => {
|
||||
beforeAll(async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
const users = [
|
||||
{ name: "Alice", age: 25 },
|
||||
{ name: "Bob", age: 30 },
|
||||
|
@ -1310,7 +1332,7 @@ describe.each([
|
|||
})
|
||||
|
||||
it("when schema is defined, defined columns and row attributes are returned", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
const rows = await Promise.all(
|
||||
Array.from({ length: 10 }, () =>
|
||||
config.api.row.save(table._id!, {
|
||||
|
@ -1341,7 +1363,7 @@ describe.each([
|
|||
})
|
||||
|
||||
it("views without data can be returned", async () => {
|
||||
const table = await config.createTable(await userTable())
|
||||
const table = await createTable(await userTable())
|
||||
|
||||
const createViewResponse = await config.createView()
|
||||
const response = await config.api.viewV2.search(createViewResponse.id)
|
||||
|
@ -1350,7 +1372,7 @@ describe.each([
|
|||
})
|
||||
|
||||
it("respects the limit parameter", async () => {
|
||||
await config.createTable(await userTable())
|
||||
await createTable(await userTable())
|
||||
await Promise.all(Array.from({ length: 10 }, () => config.createRow()))
|
||||
|
||||
const limit = generator.integer({ min: 1, max: 8 })
|
||||
|
@ -1365,7 +1387,7 @@ describe.each([
|
|||
})
|
||||
|
||||
it("can handle pagination", async () => {
|
||||
await config.createTable(await userTable())
|
||||
await createTable(await userTable())
|
||||
await Promise.all(Array.from({ length: 10 }, () => config.createRow()))
|
||||
|
||||
const createViewResponse = await config.createView()
|
||||
|
@ -1443,7 +1465,7 @@ describe.each([
|
|||
let tableId: string
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.createTable(await userTable())
|
||||
await createTable(await userTable())
|
||||
await Promise.all(
|
||||
Array.from({ length: 10 }, () => config.createRow())
|
||||
)
|
||||
|
@ -1521,13 +1543,13 @@ describe.each([
|
|||
let o2mTable: Table
|
||||
let m2mTable: Table
|
||||
beforeAll(async () => {
|
||||
o2mTable = await config.createTable(
|
||||
o2mTable = await createTable(
|
||||
{ ...generateTableConfig(), name: "o2m" },
|
||||
{
|
||||
skipReassigning: true,
|
||||
}
|
||||
)
|
||||
m2mTable = await config.createTable(
|
||||
m2mTable = await createTable(
|
||||
{ ...generateTableConfig(), name: "m2m" },
|
||||
{
|
||||
skipReassigning: true,
|
||||
|
@ -1597,9 +1619,9 @@ describe.each([
|
|||
const tableConfig = generateTableConfig()
|
||||
|
||||
if (config.datasource) {
|
||||
tableConfig.sourceId = config.datasource._id
|
||||
tableConfig.sourceId = config.datasource._id!
|
||||
if (config.datasource.plus) {
|
||||
tableConfig.type = "external"
|
||||
tableConfig.sourceType = TableSourceType.EXTERNAL
|
||||
}
|
||||
}
|
||||
const table = await config.api.table.create({
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import { events, context } from "@budibase/backend-core"
|
||||
import { context, events } from "@budibase/backend-core"
|
||||
import {
|
||||
FieldType,
|
||||
SaveTableRequest,
|
||||
RelationshipType,
|
||||
Table,
|
||||
ViewCalculation,
|
||||
AutoFieldSubTypes,
|
||||
InternalTable,
|
||||
FieldSubtype,
|
||||
FieldType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
InternalTable,
|
||||
RelationshipType,
|
||||
Row,
|
||||
SaveTableRequest,
|
||||
Table,
|
||||
TableSourceType,
|
||||
ViewCalculation,
|
||||
} from "@budibase/types"
|
||||
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
||||
import * as setup from "./utilities"
|
||||
const { basicTable } = setup.structures
|
||||
import sdk from "../../../sdk"
|
||||
|
||||
const { basicTable } = setup.structures
|
||||
|
||||
describe("/tables", () => {
|
||||
let request = setup.getRequest()
|
||||
let config = setup.getConfig()
|
||||
|
@ -242,7 +245,8 @@ describe("/tables", () => {
|
|||
.expect(200)
|
||||
const fetchedTable = res.body[0]
|
||||
expect(fetchedTable.name).toEqual(testTable.name)
|
||||
expect(fetchedTable.type).toEqual("internal")
|
||||
expect(fetchedTable.type).toEqual("table")
|
||||
expect(fetchedTable.sourceType).toEqual("internal")
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
|
@ -432,6 +436,8 @@ describe("/tables", () => {
|
|||
const table = await config.api.table.create({
|
||||
name: "table",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
"user relationship": {
|
||||
type: FieldType.LINK,
|
||||
|
@ -491,6 +497,8 @@ describe("/tables", () => {
|
|||
const table = await config.api.table.create({
|
||||
name: "table",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
"user relationship": {
|
||||
type: FieldType.LINK,
|
||||
|
@ -552,6 +560,8 @@ describe("/tables", () => {
|
|||
const table = await config.api.table.create({
|
||||
name: "table",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
"user relationship": {
|
||||
type: FieldType.LINK,
|
||||
|
|
|
@ -3,10 +3,12 @@ import {
|
|||
CreateViewRequest,
|
||||
FieldSchema,
|
||||
FieldType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
SearchQueryOperators,
|
||||
SortOrder,
|
||||
SortType,
|
||||
Table,
|
||||
TableSourceType,
|
||||
UIFieldMetadata,
|
||||
UpdateViewRequest,
|
||||
ViewV2,
|
||||
|
@ -18,6 +20,8 @@ function priceTable(): Table {
|
|||
return {
|
||||
name: "table",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
Price: {
|
||||
type: FieldType.NUMBER,
|
||||
|
@ -54,10 +58,10 @@ describe.each([
|
|||
},
|
||||
})
|
||||
|
||||
return config.createTable({
|
||||
return config.createExternalTable({
|
||||
...priceTable(),
|
||||
sourceId: datasource._id,
|
||||
type: "external",
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
})
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import { objectStore, roles, constants } from "@budibase/backend-core"
|
||||
import { FieldType as FieldTypes } from "@budibase/types"
|
||||
import { constants, objectStore, roles } from "@budibase/backend-core"
|
||||
import {
|
||||
FieldType as FieldTypes,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
|
||||
export {
|
||||
FieldType as FieldTypes,
|
||||
RelationshipType,
|
||||
|
@ -70,9 +76,11 @@ export enum SortDirection {
|
|||
DESCENDING = "DESCENDING",
|
||||
}
|
||||
|
||||
export const USERS_TABLE_SCHEMA = {
|
||||
export const USERS_TABLE_SCHEMA: Table = {
|
||||
_id: "ta_users",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
views: {},
|
||||
name: "Users",
|
||||
// TODO: ADMIN PANEL - when implemented this doesn't need to be carried out
|
||||
|
@ -87,12 +95,10 @@ export const USERS_TABLE_SCHEMA = {
|
|||
},
|
||||
presence: true,
|
||||
},
|
||||
fieldName: "email",
|
||||
name: "email",
|
||||
},
|
||||
firstName: {
|
||||
name: "firstName",
|
||||
fieldName: "firstName",
|
||||
type: FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: FieldTypes.STRING,
|
||||
|
@ -101,7 +107,6 @@ export const USERS_TABLE_SCHEMA = {
|
|||
},
|
||||
lastName: {
|
||||
name: "lastName",
|
||||
fieldName: "lastName",
|
||||
type: FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: FieldTypes.STRING,
|
||||
|
@ -109,7 +114,6 @@ export const USERS_TABLE_SCHEMA = {
|
|||
},
|
||||
},
|
||||
roleId: {
|
||||
fieldName: "roleId",
|
||||
name: "roleId",
|
||||
type: FieldTypes.OPTIONS,
|
||||
constraints: {
|
||||
|
@ -119,7 +123,6 @@ export const USERS_TABLE_SCHEMA = {
|
|||
},
|
||||
},
|
||||
status: {
|
||||
fieldName: "status",
|
||||
name: "status",
|
||||
type: FieldTypes.OPTIONS,
|
||||
constraints: {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { FieldTypes, AutoFieldSubTypes } from "../../constants"
|
||||
import { AutoFieldSubTypes, FieldTypes } from "../../constants"
|
||||
import { importToRows } from "../../api/controllers/table/utils"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import LinkDocument from "../linkedRows/LinkDocument"
|
||||
|
@ -8,11 +8,12 @@ import { jobsImport } from "./jobsImport"
|
|||
import { expensesImport } from "./expensesImport"
|
||||
import { db as dbCore } from "@budibase/backend-core"
|
||||
import {
|
||||
Table,
|
||||
Row,
|
||||
RelationshipType,
|
||||
FieldType,
|
||||
RelationshipType,
|
||||
Row,
|
||||
Table,
|
||||
TableSchema,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
|
||||
export const DEFAULT_JOBS_TABLE_ID = "ta_bb_jobs"
|
||||
|
@ -89,9 +90,10 @@ const AUTO_COLUMNS: TableSchema = {
|
|||
|
||||
export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
|
||||
_id: DEFAULT_INVENTORY_TABLE_ID,
|
||||
type: "internal",
|
||||
type: "table",
|
||||
views: {},
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
primaryDisplay: "Item Name",
|
||||
name: "Inventory",
|
||||
schema: {
|
||||
|
@ -198,10 +200,11 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
|
|||
|
||||
export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
|
||||
_id: DEFAULT_EMPLOYEE_TABLE_ID,
|
||||
type: "internal",
|
||||
type: "table",
|
||||
views: {},
|
||||
name: "Employees",
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
primaryDisplay: "First Name",
|
||||
schema: {
|
||||
"First Name": {
|
||||
|
@ -346,9 +349,10 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
|
|||
|
||||
export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
|
||||
_id: DEFAULT_JOBS_TABLE_ID,
|
||||
type: "internal",
|
||||
type: "table",
|
||||
name: "Jobs",
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
primaryDisplay: "Job ID",
|
||||
schema: {
|
||||
"Job ID": {
|
||||
|
@ -503,10 +507,11 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
|
|||
|
||||
export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
|
||||
_id: DEFAULT_EXPENSES_TABLE_ID,
|
||||
type: "internal",
|
||||
type: "table",
|
||||
views: {},
|
||||
name: "Expenses",
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
primaryDisplay: "Expense ID",
|
||||
schema: {
|
||||
"Expense ID": {
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
FieldSchema,
|
||||
RelationshipFieldMetadata,
|
||||
VirtualDocumentType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
} from "@budibase/types"
|
||||
import { FieldTypes } from "../constants"
|
||||
export { DocumentType, VirtualDocumentType } from "@budibase/types"
|
||||
|
@ -18,7 +19,7 @@ export const enum AppStatus {
|
|||
}
|
||||
|
||||
export const BudibaseInternalDB = {
|
||||
_id: "bb_internal",
|
||||
_id: INTERNAL_TABLE_SOURCE_ID,
|
||||
type: dbCore.BUDIBASE_DATASOURCE_TYPE,
|
||||
name: "Budibase DB",
|
||||
source: "BUDIBASE",
|
||||
|
|
|
@ -75,7 +75,6 @@ const environment = {
|
|||
},
|
||||
isTest: coreEnv.isTest,
|
||||
isJest: coreEnv.isJest,
|
||||
|
||||
isDev: coreEnv.isDev,
|
||||
isProd: () => {
|
||||
return !coreEnv.isDev()
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import fetch from "node-fetch"
|
||||
// @ts-ignore
|
||||
fetch.mockSearch()
|
||||
import {
|
||||
generateMakeRequest,
|
||||
MakeRequestResponse,
|
||||
|
@ -13,12 +11,15 @@ import {
|
|||
RelationshipType,
|
||||
Row,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import _ from "lodash"
|
||||
import { generator } from "@budibase/backend-core/tests"
|
||||
import { utils } from "@budibase/backend-core"
|
||||
import { databaseTestProviders } from "../integrations/tests/utils"
|
||||
import { Client } from "pg"
|
||||
// @ts-ignore
|
||||
fetch.mockSearch()
|
||||
|
||||
const config = setup.getConfig()!
|
||||
|
||||
|
@ -52,7 +53,7 @@ describe("postgres integrations", () => {
|
|||
async function createAuxTable(prefix: string) {
|
||||
return await config.createTable({
|
||||
name: `${prefix}_${generator.word({ length: 6 })}`,
|
||||
type: "external",
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
primaryDisplay: "title",
|
||||
schema: {
|
||||
|
@ -67,6 +68,7 @@ describe("postgres integrations", () => {
|
|||
},
|
||||
},
|
||||
sourceId: postgresDatasource._id,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -88,7 +90,7 @@ describe("postgres integrations", () => {
|
|||
|
||||
primaryPostgresTable = await config.createTable({
|
||||
name: `p_${generator.word({ length: 6 })}`,
|
||||
type: "external",
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
schema: {
|
||||
id: {
|
||||
|
@ -143,6 +145,7 @@ describe("postgres integrations", () => {
|
|||
},
|
||||
},
|
||||
sourceId: postgresDatasource._id,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -249,7 +252,7 @@ describe("postgres integrations", () => {
|
|||
async function createDefaultPgTable() {
|
||||
return await config.createTable({
|
||||
name: generator.word({ length: 10 }),
|
||||
type: "external",
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
schema: {
|
||||
id: {
|
||||
|
@ -259,6 +262,7 @@ describe("postgres integrations", () => {
|
|||
},
|
||||
},
|
||||
sourceId: postgresDatasource._id,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@ import {
|
|||
QueryJson,
|
||||
QueryType,
|
||||
Row,
|
||||
Schema,
|
||||
SearchFilters,
|
||||
SortJson,
|
||||
ExternalTable,
|
||||
Table,
|
||||
TableRequest,
|
||||
Schema,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import { OAuth2Client } from "google-auth-library"
|
||||
import {
|
||||
|
@ -262,11 +263,13 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|||
id?: string
|
||||
) {
|
||||
// base table
|
||||
const table: ExternalTable = {
|
||||
const table: Table = {
|
||||
type: "table",
|
||||
name: title,
|
||||
primary: [GOOGLE_SHEETS_PRIMARY_KEY],
|
||||
schema: {},
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
}
|
||||
if (id) {
|
||||
table._id = id
|
||||
|
@ -283,7 +286,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|||
|
||||
async buildSchema(
|
||||
datasourceId: string,
|
||||
entities: Record<string, ExternalTable>
|
||||
entities: Record<string, Table>
|
||||
): Promise<Schema> {
|
||||
// not fully configured yet
|
||||
if (!this.config.auth) {
|
||||
|
@ -291,7 +294,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|||
}
|
||||
await this.connect()
|
||||
const sheets = this.client.sheetsByIndex
|
||||
const tables: Record<string, ExternalTable> = {}
|
||||
const tables: Record<string, Table> = {}
|
||||
let errors: Record<string, string> = {}
|
||||
await utils.parallelForeach(
|
||||
sheets,
|
||||
|
|
|
@ -2,7 +2,7 @@ import {
|
|||
DatasourceFieldType,
|
||||
Integration,
|
||||
Operation,
|
||||
ExternalTable,
|
||||
Table,
|
||||
TableSchema,
|
||||
QueryJson,
|
||||
QueryType,
|
||||
|
@ -12,6 +12,7 @@ import {
|
|||
ConnectionInfo,
|
||||
SourceName,
|
||||
Schema,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import {
|
||||
getSqlQuery,
|
||||
|
@ -380,7 +381,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
|
|||
*/
|
||||
async buildSchema(
|
||||
datasourceId: string,
|
||||
entities: Record<string, ExternalTable>
|
||||
entities: Record<string, Table>
|
||||
): Promise<Schema> {
|
||||
await this.connect()
|
||||
let tableInfo: MSSQLTablesResponse[] = await this.runSQL(this.TABLES_SQL)
|
||||
|
@ -394,7 +395,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
|
|||
.map((record: any) => record.TABLE_NAME)
|
||||
.filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1)
|
||||
|
||||
const tables: Record<string, ExternalTable> = {}
|
||||
const tables: Record<string, Table> = {}
|
||||
for (let tableName of tableNames) {
|
||||
// get the column definition (type)
|
||||
const definition = await this.runSQL(
|
||||
|
@ -439,7 +440,9 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
|
|||
}
|
||||
tables[tableName] = {
|
||||
_id: buildExternalTableId(datasourceId, tableName),
|
||||
type: "table",
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
primary: primaryKeys,
|
||||
name: tableName,
|
||||
schema,
|
||||
|
|
|
@ -4,13 +4,14 @@ import {
|
|||
QueryType,
|
||||
QueryJson,
|
||||
SqlQuery,
|
||||
ExternalTable,
|
||||
Table,
|
||||
TableSchema,
|
||||
DatasourcePlus,
|
||||
DatasourceFeature,
|
||||
ConnectionInfo,
|
||||
SourceName,
|
||||
Schema,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import {
|
||||
getSqlQuery,
|
||||
|
@ -278,9 +279,9 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
|
|||
|
||||
async buildSchema(
|
||||
datasourceId: string,
|
||||
entities: Record<string, ExternalTable>
|
||||
entities: Record<string, Table>
|
||||
): Promise<Schema> {
|
||||
const tables: { [key: string]: ExternalTable } = {}
|
||||
const tables: { [key: string]: Table } = {}
|
||||
await this.connect()
|
||||
|
||||
try {
|
||||
|
@ -317,8 +318,10 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
|
|||
}
|
||||
if (!tables[tableName]) {
|
||||
tables[tableName] = {
|
||||
type: "table",
|
||||
_id: buildExternalTableId(datasourceId, tableName),
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
primary: primaryKeys,
|
||||
name: tableName,
|
||||
schema,
|
||||
|
|
|
@ -5,11 +5,12 @@ import {
|
|||
QueryJson,
|
||||
QueryType,
|
||||
SqlQuery,
|
||||
ExternalTable,
|
||||
Table,
|
||||
DatasourcePlus,
|
||||
DatasourceFeature,
|
||||
ConnectionInfo,
|
||||
Schema,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import {
|
||||
buildExternalTableId,
|
||||
|
@ -263,25 +264,27 @@ class OracleIntegration extends Sql implements DatasourcePlus {
|
|||
*/
|
||||
async buildSchema(
|
||||
datasourceId: string,
|
||||
entities: Record<string, ExternalTable>
|
||||
entities: Record<string, Table>
|
||||
): Promise<Schema> {
|
||||
const columnsResponse = await this.internalQuery<OracleColumnsResponse>({
|
||||
sql: this.COLUMNS_SQL,
|
||||
})
|
||||
const oracleTables = this.mapColumns(columnsResponse)
|
||||
|
||||
const tables: { [key: string]: ExternalTable } = {}
|
||||
const tables: { [key: string]: Table } = {}
|
||||
|
||||
// iterate each table
|
||||
Object.values(oracleTables).forEach(oracleTable => {
|
||||
let table = tables[oracleTable.name]
|
||||
if (!table) {
|
||||
table = {
|
||||
type: "table",
|
||||
_id: buildExternalTableId(datasourceId, oracleTable.name),
|
||||
primary: [],
|
||||
name: oracleTable.name,
|
||||
schema: {},
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
}
|
||||
tables[oracleTable.name] = table
|
||||
}
|
||||
|
|
|
@ -5,12 +5,13 @@ import {
|
|||
QueryType,
|
||||
QueryJson,
|
||||
SqlQuery,
|
||||
ExternalTable,
|
||||
Table,
|
||||
DatasourcePlus,
|
||||
DatasourceFeature,
|
||||
ConnectionInfo,
|
||||
SourceName,
|
||||
Schema,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import {
|
||||
getSqlQuery,
|
||||
|
@ -273,7 +274,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
|
|||
*/
|
||||
async buildSchema(
|
||||
datasourceId: string,
|
||||
entities: Record<string, ExternalTable>
|
||||
entities: Record<string, Table>
|
||||
): Promise<Schema> {
|
||||
let tableKeys: { [key: string]: string[] } = {}
|
||||
await this.openConnection()
|
||||
|
@ -300,7 +301,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
|
|||
const columnsResponse: { rows: PostgresColumn[] } =
|
||||
await this.client.query(this.COLUMNS_SQL)
|
||||
|
||||
const tables: { [key: string]: ExternalTable } = {}
|
||||
const tables: { [key: string]: Table } = {}
|
||||
|
||||
for (let column of columnsResponse.rows) {
|
||||
const tableName: string = column.table_name
|
||||
|
@ -309,11 +310,13 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
|
|||
// table key doesn't exist yet
|
||||
if (!tables[tableName] || !tables[tableName].schema) {
|
||||
tables[tableName] = {
|
||||
type: "table",
|
||||
_id: buildExternalTableId(datasourceId, tableName),
|
||||
primary: tableKeys[tableName] || [],
|
||||
name: tableName,
|
||||
schema: {},
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ GoogleSpreadsheet.mockImplementation(() => mockGoogleIntegration)
|
|||
import { structures } from "@budibase/backend-core/tests"
|
||||
import TestConfiguration from "../../tests/utilities/TestConfiguration"
|
||||
import GoogleSheetsIntegration from "../googlesheets"
|
||||
import { FieldType, Table, TableSchema } from "@budibase/types"
|
||||
import { FieldType, Table, TableSchema, TableSourceType } from "@budibase/types"
|
||||
import { generateDatasourceID } from "../../db/utils"
|
||||
|
||||
describe("Google Sheets Integration", () => {
|
||||
let integration: any,
|
||||
|
@ -60,7 +61,10 @@ describe("Google Sheets Integration", () => {
|
|||
|
||||
function createBasicTable(name: string, columns: string[]): Table {
|
||||
return {
|
||||
type: "table",
|
||||
name,
|
||||
sourceId: generateDatasourceID(),
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
schema: {
|
||||
...columns.reduce((p, c) => {
|
||||
p[c] = {
|
||||
|
|
|
@ -1,39 +1,47 @@
|
|||
import { Datasource, SourceName } from "@budibase/types"
|
||||
import { GenericContainer, Wait, StartedTestContainer } from "testcontainers"
|
||||
import env from "../../../environment"
|
||||
|
||||
let container: StartedTestContainer | undefined
|
||||
|
||||
const isMac = process.platform === "darwin"
|
||||
|
||||
export async function getDsConfig(): Promise<Datasource> {
|
||||
if (!container) {
|
||||
container = await new GenericContainer("postgres")
|
||||
.withExposedPorts(5432)
|
||||
.withEnv("POSTGRES_PASSWORD", "password")
|
||||
.withWaitStrategy(
|
||||
Wait.forLogMessage(
|
||||
"PostgreSQL init process complete; ready for start up."
|
||||
try {
|
||||
if (!container) {
|
||||
// postgres 15-bullseye safer bet on Linux
|
||||
const version = isMac ? undefined : "15-bullseye"
|
||||
container = await new GenericContainer("postgres", version)
|
||||
.withExposedPorts(5432)
|
||||
.withEnv("POSTGRES_PASSWORD", "password")
|
||||
.withWaitStrategy(
|
||||
Wait.forLogMessage(
|
||||
"PostgreSQL init process complete; ready for start up."
|
||||
)
|
||||
)
|
||||
)
|
||||
.start()
|
||||
}
|
||||
.start()
|
||||
}
|
||||
const host = container.getContainerIpAddress()
|
||||
const port = container.getMappedPort(5432)
|
||||
|
||||
const host = container.getContainerIpAddress()
|
||||
const port = container.getMappedPort(5432)
|
||||
|
||||
return {
|
||||
type: "datasource_plus",
|
||||
source: SourceName.POSTGRES,
|
||||
plus: true,
|
||||
config: {
|
||||
host,
|
||||
port,
|
||||
database: "postgres",
|
||||
user: "postgres",
|
||||
password: "password",
|
||||
schema: "public",
|
||||
ssl: false,
|
||||
rejectUnauthorized: false,
|
||||
ca: false,
|
||||
},
|
||||
return {
|
||||
type: "datasource_plus",
|
||||
source: SourceName.POSTGRES,
|
||||
plus: true,
|
||||
config: {
|
||||
host,
|
||||
port,
|
||||
database: "postgres",
|
||||
user: "postgres",
|
||||
password: "password",
|
||||
schema: "public",
|
||||
ssl: false,
|
||||
rejectUnauthorized: false,
|
||||
ca: false,
|
||||
},
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error("**UNABLE TO CREATE TO POSTGRES CONTAINER**")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,13 @@ import {
|
|||
SearchFilters,
|
||||
Datasource,
|
||||
FieldType,
|
||||
ExternalTable,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import { DocumentType, SEPARATOR } from "../db/utils"
|
||||
import { InvalidColumns, NoEmptyFilterStrings } from "../constants"
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
import * as external from "../api/controllers/table/external"
|
||||
import * as internal from "../api/controllers/table/internal"
|
||||
|
||||
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
||||
const ROW_ID_REGEX = /^\[.*]$/g
|
||||
|
@ -83,12 +85,26 @@ export enum SqlClient {
|
|||
ORACLE = "oracledb",
|
||||
}
|
||||
|
||||
export function isExternalTable(tableId: string) {
|
||||
export function isExternalTableID(tableId: string) {
|
||||
return tableId.includes(DocumentType.DATASOURCE)
|
||||
}
|
||||
|
||||
export function isInternalTable(tableId: string) {
|
||||
return !isExternalTable(tableId)
|
||||
export function isInternalTableID(tableId: string) {
|
||||
return !isExternalTableID(tableId)
|
||||
}
|
||||
|
||||
export function isExternalTable(table: Table) {
|
||||
if (
|
||||
table?.sourceId &&
|
||||
table.sourceId.includes(DocumentType.DATASOURCE + SEPARATOR)
|
||||
) {
|
||||
return true
|
||||
} else if (table?.sourceType === TableSourceType.EXTERNAL) {
|
||||
return true
|
||||
} else if (table?._id && isExternalTableID(table._id)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function buildExternalTableId(datasourceId: string, tableName: string) {
|
||||
|
@ -301,9 +317,9 @@ function copyExistingPropsOver(
|
|||
* @param entities The old list of tables, if there was any to look for definitions in.
|
||||
*/
|
||||
export function finaliseExternalTables(
|
||||
tables: Record<string, ExternalTable>,
|
||||
entities: Record<string, ExternalTable>
|
||||
): Record<string, ExternalTable> {
|
||||
tables: Record<string, Table>,
|
||||
entities: Record<string, Table>
|
||||
): Record<string, Table> {
|
||||
let finalTables: Record<string, Table> = {}
|
||||
const tableIds = Object.values(tables).map(table => table._id!)
|
||||
for (let [name, table] of Object.entries(tables)) {
|
||||
|
@ -316,7 +332,7 @@ export function finaliseExternalTables(
|
|||
}
|
||||
|
||||
export function checkExternalTables(
|
||||
tables: Record<string, ExternalTable>
|
||||
tables: Record<string, Table>
|
||||
): Record<string, string> {
|
||||
const invalidColumns = Object.values(InvalidColumns) as string[]
|
||||
const errors: Record<string, string> = {}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { generator } from "@budibase/backend-core/tests"
|
||||
import { BBRequest, FieldType, Row, Table } from "@budibase/types"
|
||||
import {
|
||||
BBRequest,
|
||||
FieldType,
|
||||
Row,
|
||||
Table,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import * as utils from "../../db/utils"
|
||||
import trimViewRowInfoMiddleware from "../trimViewRowInfo"
|
||||
|
||||
|
@ -73,6 +80,8 @@ describe("trimViewRowInfo middleware", () => {
|
|||
const table: Table = {
|
||||
_id: tableId,
|
||||
name: generator.word(),
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
type: "table",
|
||||
schema: {
|
||||
name: {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Ctx, Row } from "@budibase/types"
|
||||
import * as utils from "../db/utils"
|
||||
import sdk from "../sdk"
|
||||
import { db } from "@budibase/backend-core"
|
||||
import { Next } from "koa"
|
||||
import { getTableId } from "../api/controllers/row/utils"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Row, SearchFilters, SearchParams } from "@budibase/types"
|
||||
import { isExternalTable } from "../../../integrations/utils"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
import * as internal from "./search/internal"
|
||||
import * as external from "./search/external"
|
||||
import { Format } from "../../../api/controllers/view/exporters"
|
||||
|
@ -12,7 +12,7 @@ export interface ViewParams {
|
|||
}
|
||||
|
||||
function pickApi(tableId: any) {
|
||||
if (isExternalTable(tableId)) {
|
||||
if (isExternalTableID(tableId)) {
|
||||
return external
|
||||
}
|
||||
return internal
|
||||
|
|
|
@ -197,11 +197,7 @@ export async function fetchView(
|
|||
try {
|
||||
table = await sdk.tables.getTable(viewInfo.meta.tableId)
|
||||
} catch (err) {
|
||||
/* istanbul ignore next */
|
||||
table = {
|
||||
name: "",
|
||||
schema: {},
|
||||
}
|
||||
throw new Error("Unable to retrieve view table.")
|
||||
}
|
||||
rows = await outputProcessing(table, response.rows)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
SourceName,
|
||||
Table,
|
||||
SearchParams,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
|
||||
import TestConfiguration from "../../../../../tests/utilities/TestConfiguration"
|
||||
|
@ -15,6 +16,7 @@ import {
|
|||
expectAnyExternalColsAttributes,
|
||||
generator,
|
||||
} from "@budibase/backend-core/tests"
|
||||
import datasource from "../../../../../api/routes/datasource"
|
||||
|
||||
jest.unmock("mysql2/promise")
|
||||
|
||||
|
@ -23,36 +25,7 @@ jest.setTimeout(30000)
|
|||
describe.skip("external", () => {
|
||||
const config = new TestConfiguration()
|
||||
|
||||
let externalDatasource: Datasource
|
||||
|
||||
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,
|
||||
},
|
||||
},
|
||||
}
|
||||
let externalDatasource: Datasource, tableData: Table
|
||||
|
||||
beforeAll(async () => {
|
||||
const container = await new GenericContainer("mysql")
|
||||
|
@ -84,12 +57,43 @@ describe.skip("external", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
|
||||
tableData = {
|
||||
name: generator.word(),
|
||||
type: "table",
|
||||
primary: ["id"],
|
||||
sourceId: externalDatasource._id!,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
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", () => {
|
||||
const rows: Row[] = []
|
||||
beforeAll(async () => {
|
||||
const table = await config.createTable({
|
||||
const table = await config.createExternalTable({
|
||||
...tableData,
|
||||
sourceId: externalDatasource._id,
|
||||
})
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
import { FieldType, Row, Table, SearchParams } from "@budibase/types"
|
||||
import {
|
||||
FieldType,
|
||||
Row,
|
||||
Table,
|
||||
SearchParams,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import TestConfiguration from "../../../../../tests/utilities/TestConfiguration"
|
||||
import { search } from "../internal"
|
||||
import {
|
||||
|
@ -12,6 +19,8 @@ describe("internal", () => {
|
|||
const tableData: Table = {
|
||||
name: generator.word(),
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
name: "name",
|
||||
|
|
|
@ -3,14 +3,19 @@ import { db as dbCore } from "@budibase/backend-core"
|
|||
import {
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
Table,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
SearchParams,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
|
||||
const tableId = "ta_a"
|
||||
const tableWithUserCol: Table = {
|
||||
type: "table",
|
||||
_id: tableId,
|
||||
name: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
user: {
|
||||
name: "user",
|
||||
|
@ -21,8 +26,11 @@ const tableWithUserCol: Table = {
|
|||
}
|
||||
|
||||
const tableWithUsersCol: Table = {
|
||||
type: "table",
|
||||
_id: tableId,
|
||||
name: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
user: {
|
||||
name: "user",
|
||||
|
|
|
@ -35,10 +35,10 @@ export async function save(
|
|||
opts?: { tableId?: string; renaming?: RenameColumn }
|
||||
) {
|
||||
let tableToSave: TableRequest = {
|
||||
...update,
|
||||
type: "table",
|
||||
_id: buildExternalTableId(datasourceId, update.name),
|
||||
sourceId: datasourceId,
|
||||
...update,
|
||||
}
|
||||
|
||||
const tableId = opts?.tableId || update._id
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
RelationshipFieldMetadata,
|
||||
RelationshipType,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import { FieldTypes } from "../../../../constants"
|
||||
import {
|
||||
|
@ -76,12 +77,16 @@ export function generateManyLinkSchema(
|
|||
const primary = table.name + table.primary[0]
|
||||
const relatedPrimary = relatedTable.name + relatedTable.primary[0]
|
||||
const jcTblName = generateJunctionTableName(column, table, relatedTable)
|
||||
const datasourceId = datasource._id!
|
||||
// first create the new table
|
||||
const junctionTable = {
|
||||
_id: buildExternalTableId(datasource._id!, jcTblName),
|
||||
const junctionTable: Table = {
|
||||
type: "table",
|
||||
_id: buildExternalTableId(datasourceId, jcTblName),
|
||||
name: jcTblName,
|
||||
primary: [primary, relatedPrimary],
|
||||
constrained: [primary, relatedPrimary],
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
schema: {
|
||||
[primary]: foreignKeyStructure(primary, {
|
||||
toTable: table.name,
|
||||
|
|
|
@ -1,34 +1,47 @@
|
|||
import { context } from "@budibase/backend-core"
|
||||
import {
|
||||
BudibaseInternalDB,
|
||||
getMultiIDParams,
|
||||
getTableParams,
|
||||
} from "../../../db/utils"
|
||||
import { getMultiIDParams, getTableParams } from "../../../db/utils"
|
||||
import {
|
||||
breakExternalTableId,
|
||||
isExternalTable,
|
||||
isExternalTableID,
|
||||
isSQL,
|
||||
} from "../../../integrations/utils"
|
||||
import {
|
||||
AllDocsResponse,
|
||||
Database,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
Table,
|
||||
TableResponse,
|
||||
TableSourceType,
|
||||
TableViewsResponse,
|
||||
} from "@budibase/types"
|
||||
import datasources from "../datasources"
|
||||
import sdk from "../../../sdk"
|
||||
|
||||
function processInternalTables(tables: Table[]): Table[] {
|
||||
return tables.map(processInternalTable)
|
||||
export function processTable(table: Table): Table {
|
||||
if (table._id && isExternalTableID(table._id)) {
|
||||
return {
|
||||
...table,
|
||||
type: "table",
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
...table,
|
||||
type: "table",
|
||||
sourceId: table.sourceId || INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function processInternalTable(table: Table): Table {
|
||||
return {
|
||||
...table,
|
||||
type: "internal",
|
||||
sourceId: table.sourceId || BudibaseInternalDB._id,
|
||||
export function processTables(tables: Table[]): Table[] {
|
||||
return tables.map(table => processTable(table))
|
||||
}
|
||||
|
||||
function processEntities(tables: Record<string, Table>) {
|
||||
for (let key of Object.keys(tables)) {
|
||||
tables[key] = processTable(tables[key])
|
||||
}
|
||||
return tables
|
||||
}
|
||||
|
||||
export async function getAllInternalTables(db?: Database): Promise<Table[]> {
|
||||
|
@ -40,7 +53,7 @@ export async function getAllInternalTables(db?: Database): Promise<Table[]> {
|
|||
include_docs: true,
|
||||
})
|
||||
)
|
||||
return processInternalTables(internalTables.rows.map(row => row.doc!))
|
||||
return processTables(internalTables.rows.map(row => row.doc!))
|
||||
}
|
||||
|
||||
async function getAllExternalTables(): Promise<Table[]> {
|
||||
|
@ -52,7 +65,7 @@ async function getAllExternalTables(): Promise<Table[]> {
|
|||
final = final.concat(Object.values(entities))
|
||||
}
|
||||
}
|
||||
return final
|
||||
return processTables(final)
|
||||
}
|
||||
|
||||
export async function getExternalTable(
|
||||
|
@ -60,19 +73,21 @@ export async function getExternalTable(
|
|||
tableName: string
|
||||
): Promise<Table> {
|
||||
const entities = await getExternalTablesInDatasource(datasourceId)
|
||||
return entities[tableName]
|
||||
return processTable(entities[tableName])
|
||||
}
|
||||
|
||||
export async function getTable(tableId: string): Promise<Table> {
|
||||
const db = context.getAppDB()
|
||||
if (isExternalTable(tableId)) {
|
||||
let output: Table
|
||||
if (isExternalTableID(tableId)) {
|
||||
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||
const datasource = await datasources.get(datasourceId!)
|
||||
const table = await getExternalTable(datasourceId!, tableName!)
|
||||
return { ...table, sql: isSQL(datasource) }
|
||||
output = { ...table, sql: isSQL(datasource) }
|
||||
} else {
|
||||
return db.get(tableId)
|
||||
output = await db.get<Table>(tableId)
|
||||
}
|
||||
return processTable(output)
|
||||
}
|
||||
|
||||
export async function getAllTables() {
|
||||
|
@ -80,7 +95,7 @@ export async function getAllTables() {
|
|||
getAllInternalTables(),
|
||||
getAllExternalTables(),
|
||||
])
|
||||
return [...internal, ...external]
|
||||
return processTables([...internal, ...external])
|
||||
}
|
||||
|
||||
export async function getExternalTablesInDatasource(
|
||||
|
@ -90,12 +105,14 @@ export async function getExternalTablesInDatasource(
|
|||
if (!datasource || !datasource.entities) {
|
||||
throw new Error("Datasource is not configured fully.")
|
||||
}
|
||||
return datasource.entities
|
||||
return processEntities(datasource.entities)
|
||||
}
|
||||
|
||||
export async function getTables(tableIds: string[]): Promise<Table[]> {
|
||||
const externalTableIds = tableIds.filter(tableId => isExternalTable(tableId)),
|
||||
internalTableIds = tableIds.filter(tableId => !isExternalTable(tableId))
|
||||
const externalTableIds = tableIds.filter(tableId =>
|
||||
isExternalTableID(tableId)
|
||||
),
|
||||
internalTableIds = tableIds.filter(tableId => !isExternalTableID(tableId))
|
||||
let tables: Table[] = []
|
||||
if (externalTableIds.length) {
|
||||
const externalTables = await getAllExternalTables()
|
||||
|
@ -110,11 +127,9 @@ export async function getTables(tableIds: string[]): Promise<Table[]> {
|
|||
const internalTableDocs = await db.allDocs<Table[]>(
|
||||
getMultiIDParams(internalTableIds)
|
||||
)
|
||||
tables = tables.concat(
|
||||
processInternalTables(internalTableDocs.rows.map(row => row.doc!))
|
||||
)
|
||||
tables = tables.concat(internalTableDocs.rows.map(row => row.doc!))
|
||||
}
|
||||
return tables
|
||||
return processTables(tables)
|
||||
}
|
||||
|
||||
export function enrichViewSchemas(table: Table): TableResponse {
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
Table,
|
||||
} from "@budibase/types"
|
||||
import sdk from "../../../sdk"
|
||||
import { isExternalTable } from "../../../integrations/utils"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
import { EventType, updateLinks } from "../../../db/linkedRows"
|
||||
import { cloneDeep } from "lodash"
|
||||
|
||||
|
@ -58,7 +58,7 @@ function getColumnMigrator(
|
|||
// columns in internal tables. In the future, we may want to support other
|
||||
// migrations but for now return an error if we aren't migrating a user
|
||||
// relationship.
|
||||
if (isExternalTable(table._id!)) {
|
||||
if (isExternalTableID(table._id!)) {
|
||||
throw new BadRequestError("External tables cannot be migrated")
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { FieldType, Table, ViewV2 } from "@budibase/types"
|
||||
import {
|
||||
FieldType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
Table,
|
||||
TableSourceType,
|
||||
ViewV2,
|
||||
} from "@budibase/types"
|
||||
import { generator } from "@budibase/backend-core/tests"
|
||||
import sdk from "../../.."
|
||||
|
||||
|
@ -13,6 +19,8 @@ describe("table sdk", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
|
|
@ -1,73 +1,92 @@
|
|||
import { populateExternalTableSchemas } from "../validation"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { AutoReason, Datasource, Table } from "@budibase/types"
|
||||
import {
|
||||
AutoReason,
|
||||
Datasource,
|
||||
FieldType,
|
||||
RelationshipType,
|
||||
SourceName,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
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: {
|
||||
client: {
|
||||
type: "table",
|
||||
_id: "tableA",
|
||||
name: "client",
|
||||
primary: ["idC"],
|
||||
primaryDisplay: "Name",
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
schema: {
|
||||
idC: {
|
||||
autocolumn: true,
|
||||
externalType: "int unsigned",
|
||||
name: "idC",
|
||||
type: "number",
|
||||
type: FieldType.NUMBER,
|
||||
},
|
||||
Name: {
|
||||
autocolumn: false,
|
||||
externalType: "varchar(255)",
|
||||
name: "Name",
|
||||
type: "string",
|
||||
type: FieldType.STRING,
|
||||
},
|
||||
project: {
|
||||
fieldName: "idC",
|
||||
foreignKey: "idC",
|
||||
main: true,
|
||||
name: "project",
|
||||
relationshipType: "many-to-one",
|
||||
relationshipType: RelationshipType.MANY_TO_ONE,
|
||||
tableId: "tableB",
|
||||
type: "link",
|
||||
type: FieldType.LINK,
|
||||
},
|
||||
},
|
||||
},
|
||||
project: {
|
||||
type: "table",
|
||||
_id: "tableB",
|
||||
name: "project",
|
||||
primary: ["idP"],
|
||||
primaryDisplay: "Name",
|
||||
sourceId: datasourceId,
|
||||
sourceType: TableSourceType.EXTERNAL,
|
||||
schema: {
|
||||
idC: {
|
||||
externalType: "int unsigned",
|
||||
name: "idC",
|
||||
type: "number",
|
||||
type: FieldType.NUMBER,
|
||||
},
|
||||
idP: {
|
||||
autocolumn: true,
|
||||
externalType: "int unsigned",
|
||||
name: "idProject",
|
||||
type: "number",
|
||||
type: FieldType.NUMBER,
|
||||
},
|
||||
Name: {
|
||||
autocolumn: false,
|
||||
externalType: "varchar(255)",
|
||||
name: "Name",
|
||||
type: "string",
|
||||
type: FieldType.STRING,
|
||||
},
|
||||
client: {
|
||||
fieldName: "idC",
|
||||
foreignKey: "idC",
|
||||
name: "client",
|
||||
relationshipType: "one-to-many",
|
||||
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||
tableId: "tableA",
|
||||
type: "link",
|
||||
type: FieldType.LINK,
|
||||
},
|
||||
},
|
||||
sql: true,
|
||||
type: "table",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -95,12 +114,12 @@ describe("validation and update of external table schemas", () => {
|
|||
function noOtherTableChanges(response: any) {
|
||||
checkOtherColumns(
|
||||
response.entities!.client!,
|
||||
SCHEMA.entities.client as Table,
|
||||
SCHEMA.entities!.client,
|
||||
OTHER_CLIENT_COLS
|
||||
)
|
||||
checkOtherColumns(
|
||||
response.entities!.project!,
|
||||
SCHEMA.entities.project as Table,
|
||||
SCHEMA.entities!.project,
|
||||
OTHER_PROJECT_COLS
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Table, RenameColumn } from "@budibase/types"
|
||||
import { isExternalTable } from "../../../integrations/utils"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
import sdk from "../../index"
|
||||
import { context } from "@budibase/backend-core"
|
||||
import { isExternal } from "./utils"
|
||||
|
@ -14,7 +14,7 @@ export * as internal from "./internal"
|
|||
export async function saveTable(table: Table): Promise<Table> {
|
||||
const db = context.getAppDB()
|
||||
let resp: DocumentInsertResponse
|
||||
if (isExternalTable(table._id!)) {
|
||||
if (isExternalTableID(table._id!)) {
|
||||
const datasource = await sdk.datasources.get(table.sourceId!)
|
||||
datasource.entities![table.name] = table
|
||||
resp = await db.put(datasource)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Table } from "@budibase/types"
|
||||
import { isExternalTable } from "../../../integrations/utils"
|
||||
import { Table, TableSourceType } from "@budibase/types"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
|
||||
export function isExternal(opts: { table?: Table; tableId?: string }): boolean {
|
||||
if (opts.table && opts.table.type === "external") {
|
||||
if (opts.table && opts.table.sourceType === TableSourceType.EXTERNAL) {
|
||||
return true
|
||||
} else if (opts.tableId && isExternalTable(opts.tableId)) {
|
||||
} else if (opts.tableId && isExternalTableID(opts.tableId)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -4,13 +4,13 @@ import { cloneDeep } from "lodash"
|
|||
|
||||
import sdk from "../../../sdk"
|
||||
import * as utils from "../../../db/utils"
|
||||
import { isExternalTable } from "../../../integrations/utils"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
|
||||
import * as internal from "./internal"
|
||||
import * as external from "./external"
|
||||
|
||||
function pickApi(tableId: any) {
|
||||
if (isExternalTable(tableId)) {
|
||||
if (isExternalTableID(tableId)) {
|
||||
return external
|
||||
}
|
||||
return internal
|
||||
|
|
|
@ -2,8 +2,10 @@ import _ from "lodash"
|
|||
import {
|
||||
FieldSchema,
|
||||
FieldType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
Table,
|
||||
TableSchema,
|
||||
TableSourceType,
|
||||
ViewV2,
|
||||
} from "@budibase/types"
|
||||
import { generator } from "@budibase/backend-core/tests"
|
||||
|
@ -14,6 +16,8 @@ describe("table sdk", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
|
|
@ -2,37 +2,31 @@ import { generator, mocks, structures } from "@budibase/backend-core/tests"
|
|||
|
||||
// init the licensing mock
|
||||
import * as pro from "@budibase/pro"
|
||||
mocks.licenses.init(pro)
|
||||
|
||||
// use unlimited license by default
|
||||
mocks.licenses.useUnlimited()
|
||||
|
||||
import { init as dbInit } from "../../db"
|
||||
dbInit()
|
||||
import env from "../../environment"
|
||||
import {
|
||||
basicTable,
|
||||
basicRow,
|
||||
basicRole,
|
||||
basicAutomation,
|
||||
basicDatasource,
|
||||
basicQuery,
|
||||
basicScreen,
|
||||
basicLayout,
|
||||
basicWebhook,
|
||||
basicAutomationResults,
|
||||
basicDatasource,
|
||||
basicLayout,
|
||||
basicQuery,
|
||||
basicRole,
|
||||
basicRow,
|
||||
basicScreen,
|
||||
basicTable,
|
||||
basicWebhook,
|
||||
} from "./structures"
|
||||
import {
|
||||
constants,
|
||||
tenancy,
|
||||
sessions,
|
||||
auth,
|
||||
cache,
|
||||
constants,
|
||||
context,
|
||||
db as dbCore,
|
||||
encryption,
|
||||
auth,
|
||||
roles,
|
||||
env as coreEnv,
|
||||
roles,
|
||||
sessions,
|
||||
tenancy,
|
||||
} from "@budibase/backend-core"
|
||||
import * as controllers from "./controllers"
|
||||
import { cleanup } from "../../utilities/fileSystem"
|
||||
|
@ -43,23 +37,32 @@ import supertest from "supertest"
|
|||
import {
|
||||
App,
|
||||
AuthToken,
|
||||
Automation,
|
||||
CreateViewRequest,
|
||||
Datasource,
|
||||
FieldType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
RelationshipFieldMetadata,
|
||||
RelationshipType,
|
||||
Row,
|
||||
SearchFilters,
|
||||
SourceName,
|
||||
Table,
|
||||
SearchFilters,
|
||||
UserRoles,
|
||||
Automation,
|
||||
View,
|
||||
FieldType,
|
||||
RelationshipType,
|
||||
CreateViewRequest,
|
||||
RelationshipFieldMetadata,
|
||||
TableSourceType,
|
||||
User,
|
||||
UserRoles,
|
||||
View,
|
||||
} from "@budibase/types"
|
||||
|
||||
import API from "./api"
|
||||
|
||||
mocks.licenses.init(pro)
|
||||
|
||||
// use unlimited license by default
|
||||
mocks.licenses.useUnlimited()
|
||||
|
||||
dbInit()
|
||||
|
||||
type DefaultUserValues = {
|
||||
globalUserId: string
|
||||
email: string
|
||||
|
@ -68,6 +71,11 @@ type DefaultUserValues = {
|
|||
csrfToken: string
|
||||
}
|
||||
|
||||
interface TableToBuild extends Omit<Table, "sourceId" | "sourceType"> {
|
||||
sourceId?: string
|
||||
sourceType?: TableSourceType
|
||||
}
|
||||
|
||||
class TestConfiguration {
|
||||
server: any
|
||||
request: supertest.SuperTest<supertest.Test> | undefined
|
||||
|
@ -538,10 +546,12 @@ class TestConfiguration {
|
|||
// TABLE
|
||||
|
||||
async updateTable(
|
||||
config?: Table,
|
||||
config?: TableToBuild,
|
||||
{ skipReassigning } = { skipReassigning: false }
|
||||
): Promise<Table> {
|
||||
config = config || basicTable()
|
||||
config.sourceType = config.sourceType || TableSourceType.INTERNAL
|
||||
config.sourceId = config.sourceId || INTERNAL_TABLE_SOURCE_ID
|
||||
const response = await this._req(config, null, controllers.table.save)
|
||||
if (!skipReassigning) {
|
||||
this.table = response
|
||||
|
@ -549,18 +559,32 @@ class TestConfiguration {
|
|||
return response
|
||||
}
|
||||
|
||||
async createTable(config?: Table, options = { skipReassigning: false }) {
|
||||
async createTable(
|
||||
config?: TableToBuild,
|
||||
options = { skipReassigning: false }
|
||||
) {
|
||||
if (config != null && config._id) {
|
||||
delete config._id
|
||||
}
|
||||
config = config || basicTable()
|
||||
if (this.datasource && !config.sourceId) {
|
||||
config.sourceId = this.datasource._id
|
||||
if (this.datasource.plus) {
|
||||
config.type = "external"
|
||||
}
|
||||
if (!config.sourceId) {
|
||||
config.sourceId = INTERNAL_TABLE_SOURCE_ID
|
||||
}
|
||||
return this.updateTable(config, options)
|
||||
}
|
||||
|
||||
async createExternalTable(
|
||||
config?: TableToBuild,
|
||||
options = { skipReassigning: false }
|
||||
) {
|
||||
if (config != null && config._id) {
|
||||
delete config._id
|
||||
}
|
||||
config = config || basicTable()
|
||||
if (this.datasource?._id) {
|
||||
config.sourceId = this.datasource._id
|
||||
config.sourceType = TableSourceType.EXTERNAL
|
||||
}
|
||||
return this.updateTable(config, options)
|
||||
}
|
||||
|
||||
|
@ -572,12 +596,15 @@ class TestConfiguration {
|
|||
async createLinkedTable(
|
||||
relationshipType = RelationshipType.ONE_TO_MANY,
|
||||
links: any = ["link"],
|
||||
config?: Table
|
||||
config?: TableToBuild
|
||||
) {
|
||||
if (!this.table) {
|
||||
throw "Must have created a table first."
|
||||
}
|
||||
const tableConfig = config || basicTable()
|
||||
if (!tableConfig.sourceId) {
|
||||
tableConfig.sourceId = INTERNAL_TABLE_SOURCE_ID
|
||||
}
|
||||
tableConfig.primaryDisplay = "name"
|
||||
for (let link of links) {
|
||||
tableConfig.schema[link] = {
|
||||
|
@ -589,15 +616,12 @@ class TestConfiguration {
|
|||
} as RelationshipFieldMetadata
|
||||
}
|
||||
|
||||
if (this.datasource && !tableConfig.sourceId) {
|
||||
if (this.datasource?._id) {
|
||||
tableConfig.sourceId = this.datasource._id
|
||||
if (this.datasource.plus) {
|
||||
tableConfig.type = "external"
|
||||
}
|
||||
tableConfig.sourceType = TableSourceType.EXTERNAL
|
||||
}
|
||||
|
||||
const linkedTable = await this.createTable(tableConfig)
|
||||
return linkedTable
|
||||
return await this.createTable(tableConfig)
|
||||
}
|
||||
|
||||
async createAttachmentTable() {
|
||||
|
|
|
@ -19,12 +19,16 @@ import {
|
|||
FieldType,
|
||||
SourceName,
|
||||
Table,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
|
||||
export function basicTable(): Table {
|
||||
return {
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
processInputBBReferences,
|
||||
processOutputBBReferences,
|
||||
} from "./bbReferenceProcessor"
|
||||
import { isExternalTable } from "../../integrations/utils"
|
||||
import { isExternalTableID } from "../../integrations/utils"
|
||||
export * from "./utils"
|
||||
|
||||
type AutoColumnProcessingOpts = {
|
||||
|
@ -51,7 +51,7 @@ function getRemovedAttachmentKeys(
|
|||
/**
|
||||
* This will update any auto columns that are found on the row/table with the correct information based on
|
||||
* time now and the current logged in user making the request.
|
||||
* @param user The user to be used for an appId as well as the createdBy and createdAt fields.
|
||||
* @param userId The user to be used for an appId as well as the createdBy and createdAt fields.
|
||||
* @param table The table which is to be used for the schema, as well as handling auto IDs incrementing.
|
||||
* @param row The row which is to be updated with information for the auto columns.
|
||||
* @param opts specific options for function to carry out optional features.
|
||||
|
@ -267,7 +267,7 @@ export async function outputProcessing<T extends Row[] | Row>(
|
|||
)) as Row[]
|
||||
}
|
||||
// remove null properties to match internal API
|
||||
if (isExternalTable(table._id!)) {
|
||||
if (isExternalTableID(table._id!)) {
|
||||
for (let row of enriched) {
|
||||
for (let key of Object.keys(row)) {
|
||||
if (row[key] === null) {
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { inputProcessing } from ".."
|
||||
import { generator, structures } from "@budibase/backend-core/tests"
|
||||
import { FieldType, FieldTypeSubtypes, Table } from "@budibase/types"
|
||||
import {
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import * as bbReferenceProcessor from "../bbReferenceProcessor"
|
||||
|
||||
jest.mock("../bbReferenceProcessor", (): typeof bbReferenceProcessor => ({
|
||||
|
@ -20,6 +26,8 @@ describe("rowProcessor - inputProcessing", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
@ -70,6 +78,8 @@ describe("rowProcessor - inputProcessing", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
@ -110,6 +120,8 @@ describe("rowProcessor - inputProcessing", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
@ -150,6 +162,8 @@ describe("rowProcessor - inputProcessing", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
|
|
@ -2,7 +2,9 @@ import {
|
|||
FieldSubtype,
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
import { outputProcessing } from ".."
|
||||
import { generator, structures } from "@budibase/backend-core/tests"
|
||||
|
@ -26,6 +28,8 @@ describe("rowProcessor - outputProcessing", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
@ -71,6 +75,8 @@ describe("rowProcessor - outputProcessing", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
@ -108,6 +114,8 @@ describe("rowProcessor - outputProcessing", () => {
|
|||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
|
|
|
@ -16,8 +16,7 @@ import { gridSocket } from "./index"
|
|||
import { clearLock, updateLock } from "../utilities/redis"
|
||||
import { Socket } from "socket.io"
|
||||
import { BuilderSocketEvent } from "@budibase/shared-core"
|
||||
import { processInternalTable } from "../sdk/app/tables/getters"
|
||||
import { isExternalTable, isInternalTable } from "../integrations/utils"
|
||||
import { processTable } from "../sdk/app/tables/getters"
|
||||
|
||||
export default class BuilderSocket extends BaseSocket {
|
||||
constructor(app: Koa, server: http.Server) {
|
||||
|
@ -106,9 +105,7 @@ export default class BuilderSocket extends BaseSocket {
|
|||
// This was added to make sure that sourceId is always present when
|
||||
// sending this message to clients. Without this, tables without a
|
||||
// sourceId (e.g. ta_users) won't get correctly updated client-side.
|
||||
if (isInternalTable(table._id!)) {
|
||||
table = processInternalTable(table)
|
||||
}
|
||||
table = processTable(table)
|
||||
|
||||
this.emitToRoom(
|
||||
ctx,
|
||||
|
|
|
@ -3,14 +3,22 @@ import { View, ViewV2 } from "../view"
|
|||
import { RenameColumn } from "../../../sdk"
|
||||
import { TableSchema } from "./schema"
|
||||
|
||||
export const INTERNAL_TABLE_SOURCE_ID = "bb_internal"
|
||||
|
||||
export enum TableSourceType {
|
||||
EXTERNAL = "external",
|
||||
INTERNAL = "internal",
|
||||
}
|
||||
|
||||
export interface Table extends Document {
|
||||
type?: string
|
||||
type: "table"
|
||||
sourceType: TableSourceType
|
||||
views?: { [key: string]: View | ViewV2 }
|
||||
name: string
|
||||
sourceId: string
|
||||
primary?: string[]
|
||||
schema: TableSchema
|
||||
primaryDisplay?: string
|
||||
sourceId?: string
|
||||
relatedFormula?: string[]
|
||||
constrained?: string[]
|
||||
sql?: boolean
|
||||
|
@ -19,10 +27,6 @@ export interface Table extends Document {
|
|||
rowHeight?: number
|
||||
}
|
||||
|
||||
export interface ExternalTable extends Table {
|
||||
sourceId: string
|
||||
}
|
||||
|
||||
export interface TableRequest extends Table {
|
||||
_rename?: RenameColumn
|
||||
created?: boolean
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ExternalTable, Table } from "../documents"
|
||||
import { Table } from "../documents"
|
||||
|
||||
export const PASSWORD_REPLACEMENT = "--secret-value--"
|
||||
|
||||
|
@ -176,7 +176,7 @@ export interface IntegrationBase {
|
|||
}
|
||||
|
||||
export interface Schema {
|
||||
tables: Record<string, ExternalTable>
|
||||
tables: Record<string, Table>
|
||||
errors: Record<string, string>
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ export interface DatasourcePlus extends IntegrationBase {
|
|||
getStringConcat(parts: string[]): string
|
||||
buildSchema(
|
||||
datasourceId: string,
|
||||
entities: Record<string, ExternalTable>
|
||||
entities: Record<string, Table>
|
||||
): Promise<Schema>
|
||||
getTableNames(): Promise<string[]>
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue