1
0
Fork 0
mirror of synced 2024-09-02 18:51:36 +12:00

Merge pull request #12862 from Budibase/refactor/remove-field-types

Refactor - fully replace FieldTypes with newer FieldType
This commit is contained in:
Michael Drury 2024-01-26 13:49:45 +00:00 committed by GitHub
commit 94ec160ba3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 426 additions and 355 deletions

View file

@ -13,7 +13,7 @@
import { getColumnIcon } from "../lib/utils" import { getColumnIcon } from "../lib/utils"
import MigrationModal from "../controls/MigrationModal.svelte" import MigrationModal from "../controls/MigrationModal.svelte"
import { debounce } from "../../../utils/utils" import { debounce } from "../../../utils/utils"
import { FieldType, FormulaTypes } from "@budibase/types" import { FieldType, FormulaType } from "@budibase/types"
import { TableNames } from "../../../constants" import { TableNames } from "../../../constants"
export let column export let column
@ -96,7 +96,7 @@
const { type, formulaType } = col.schema const { type, formulaType } = col.schema
return ( return (
searchableTypes.includes(type) || searchableTypes.includes(type) ||
(type === FieldType.FORMULA && formulaType === FormulaTypes.STATIC) (type === FieldType.FORMULA && formulaType === FormulaType.STATIC)
) )
} }

View file

@ -1,4 +1,4 @@
import { FieldTypes, RelationshipType, FormulaTypes } from "../../src/constants" import { FieldType, FormulaType, RelationshipType } from "@budibase/types"
import { object } from "./utils" import { object } from "./utils"
import Resource from "./utils/Resource" import Resource from "./utils/Resource"
@ -27,7 +27,7 @@ const table = {
const baseColumnDef = { const baseColumnDef = {
type: { type: {
type: "string", type: "string",
enum: Object.values(FieldTypes), enum: Object.values(FieldType),
description: description:
"Defines the type of the column, most explain themselves, a link column is a relationship.", "Defines the type of the column, most explain themselves, a link column is a relationship.",
}, },
@ -81,7 +81,7 @@ const tableSchema = {
...baseColumnDef, ...baseColumnDef,
type: { type: {
type: "string", type: "string",
enum: [FieldTypes.LINK], enum: [FieldType.LINK],
description: "A relationship column.", description: "A relationship column.",
}, },
fieldName: { fieldName: {
@ -128,7 +128,7 @@ const tableSchema = {
...baseColumnDef, ...baseColumnDef,
type: { type: {
type: "string", type: "string",
enum: [FieldTypes.FORMULA], enum: [FieldType.FORMULA],
description: "A formula column.", description: "A formula column.",
}, },
formula: { formula: {
@ -138,7 +138,7 @@ const tableSchema = {
}, },
formulaType: { formulaType: {
type: "string", type: "string",
enum: Object.values(FormulaTypes), enum: Object.values(FormulaType),
description: description:
"Defines whether this is a static or dynamic formula.", "Defines whether this is a static or dynamic formula.",
}, },

View file

@ -1,4 +1,5 @@
import { import {
AutoFieldSubType,
AutoReason, AutoReason,
Datasource, Datasource,
FieldSchema, FieldSchema,
@ -27,7 +28,6 @@ import {
isSQL, isSQL,
} from "../../../integrations/utils" } from "../../../integrations/utils"
import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils" import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils"
import { AutoFieldSubTypes, FieldTypes } from "../../../constants"
import { processObjectSync } from "@budibase/string-templates" import { processObjectSync } from "@budibase/string-templates"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { processDates, processFormulas } from "../../../utilities/rowProcessor" import { processDates, processFormulas } from "../../../utilities/rowProcessor"
@ -111,10 +111,10 @@ function buildFilters(
*/ */
function cleanupConfig(config: RunConfig, table: Table): RunConfig { function cleanupConfig(config: RunConfig, table: Table): RunConfig {
const primaryOptions = [ const primaryOptions = [
FieldTypes.STRING, FieldType.STRING,
FieldTypes.LONGFORM, FieldType.LONGFORM,
FieldTypes.OPTIONS, FieldType.OPTIONS,
FieldTypes.NUMBER, FieldType.NUMBER,
] ]
// filter out fields which cannot be keys // filter out fields which cannot be keys
const fieldNames = Object.entries(table.schema) const fieldNames = Object.entries(table.schema)
@ -241,10 +241,7 @@ function basicProcessing({
function fixArrayTypes(row: Row, table: Table) { function fixArrayTypes(row: Row, table: Table) {
for (let [fieldName, schema] of Object.entries(table.schema)) { for (let [fieldName, schema] of Object.entries(table.schema)) {
if ( if (schema.type === FieldType.ARRAY && typeof row[fieldName] === "string") {
schema.type === FieldTypes.ARRAY &&
typeof row[fieldName] === "string"
) {
try { try {
row[fieldName] = JSON.parse(row[fieldName]) row[fieldName] = JSON.parse(row[fieldName])
} catch (err) { } catch (err) {
@ -274,8 +271,8 @@ function isEditableColumn(column: FieldSchema) {
const isExternalAutoColumn = const isExternalAutoColumn =
column.autocolumn && column.autocolumn &&
column.autoReason !== AutoReason.FOREIGN_KEY && column.autoReason !== AutoReason.FOREIGN_KEY &&
column.subtype !== AutoFieldSubTypes.AUTO_ID column.subtype !== AutoFieldSubType.AUTO_ID
const isFormula = column.type === FieldTypes.FORMULA const isFormula = column.type === FieldType.FORMULA
return !(isExternalAutoColumn || isFormula) return !(isExternalAutoColumn || isFormula)
} }
@ -322,11 +319,11 @@ export class ExternalRequest<T extends Operation> {
continue continue
} }
// parse floats/numbers // parse floats/numbers
if (field.type === FieldTypes.NUMBER && !isNaN(parseFloat(row[key]))) { if (field.type === FieldType.NUMBER && !isNaN(parseFloat(row[key]))) {
newRow[key] = parseFloat(row[key]) newRow[key] = parseFloat(row[key])
} }
// if its not a link then just copy it over // if its not a link then just copy it over
if (field.type !== FieldTypes.LINK) { if (field.type !== FieldType.LINK) {
newRow[key] = row[key] newRow[key] = row[key]
continue continue
} }
@ -532,7 +529,7 @@ export class ExternalRequest<T extends Operation> {
buildRelationships(table: Table): RelationshipsJson[] { buildRelationships(table: Table): RelationshipsJson[] {
const relationships = [] const relationships = []
for (let [fieldName, field] of Object.entries(table.schema)) { for (let [fieldName, field] of Object.entries(table.schema)) {
if (field.type !== FieldTypes.LINK) { if (field.type !== FieldType.LINK) {
continue continue
} }
const { tableName: linkTableName } = breakExternalTableId(field.tableId) const { tableName: linkTableName } = breakExternalTableId(field.tableId)
@ -586,7 +583,7 @@ export class ExternalRequest<T extends Operation> {
// we need this to work out if any relationships need removed // we need this to work out if any relationships need removed
for (const field of Object.values(table.schema)) { for (const field of Object.values(table.schema)) {
if ( if (
field.type !== FieldTypes.LINK || field.type !== FieldType.LINK ||
!field.fieldName || !field.fieldName ||
isOneSide(field) isOneSide(field)
) { ) {
@ -730,15 +727,15 @@ export class ExternalRequest<T extends Operation> {
return Object.entries(table.schema) return Object.entries(table.schema)
.filter( .filter(
column => column =>
column[1].type !== FieldTypes.LINK && column[1].type !== FieldType.LINK &&
column[1].type !== FieldTypes.FORMULA && column[1].type !== FieldType.FORMULA &&
!existing.find((field: string) => field === column[0]) !existing.find((field: string) => field === column[0])
) )
.map(column => `${table.name}.${column[0]}`) .map(column => `${table.name}.${column[0]}`)
} }
let fields = extractRealFields(table) let fields = extractRealFields(table)
for (let field of Object.values(table.schema)) { for (let field of Object.values(table.schema)) {
if (field.type !== FieldTypes.LINK || !includeRelations) { if (field.type !== FieldType.LINK || !includeRelations) {
continue continue
} }
const { tableName: linkTableName } = breakExternalTableId(field.tableId) const { tableName: linkTableName } = breakExternalTableId(field.tableId)

View file

@ -1,4 +1,3 @@
import { FieldTypes } from "../../../constants"
import { import {
breakExternalTableId, breakExternalTableId,
breakRowIdField, breakRowIdField,
@ -9,6 +8,7 @@ import {
RunConfig, RunConfig,
} from "./ExternalRequest" } from "./ExternalRequest"
import { import {
FieldType,
Datasource, Datasource,
IncludeRelationship, IncludeRelationship,
Operation, Operation,
@ -154,7 +154,7 @@ export async function fetchEnrichedRow(ctx: UserCtx) {
// for a single row, there is probably a better way to do this with some smart multi-layer joins // for a single row, there is probably a better way to do this with some smart multi-layer joins
for (let [fieldName, field] of Object.entries(table.schema)) { for (let [fieldName, field] of Object.entries(table.schema)) {
if ( if (
field.type !== FieldTypes.LINK || field.type !== FieldType.LINK ||
!row[fieldName] || !row[fieldName] ||
row[fieldName].length === 0 row[fieldName].length === 0
) { ) {

View file

@ -6,12 +6,12 @@ import {
inputProcessing, inputProcessing,
outputProcessing, outputProcessing,
} from "../../../utilities/rowProcessor" } from "../../../utilities/rowProcessor"
import { FieldTypes } from "../../../constants"
import * as utils from "./utils" import * as utils from "./utils"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { context } from "@budibase/backend-core" import { context } from "@budibase/backend-core"
import { finaliseRow, updateRelatedFormula } from "./staticFormula" import { finaliseRow, updateRelatedFormula } from "./staticFormula"
import { import {
FieldType,
LinkDocumentValue, LinkDocumentValue,
PatchRowRequest, PatchRowRequest,
PatchRowResponse, PatchRowResponse,
@ -225,7 +225,7 @@ export async function fetchEnrichedRow(ctx: UserCtx) {
// insert the link rows in the correct place throughout the main row // insert the link rows in the correct place throughout the main row
for (let fieldName of Object.keys(table.schema)) { for (let fieldName of Object.keys(table.schema)) {
let field = table.schema[fieldName] let field = table.schema[fieldName]
if (field.type === FieldTypes.LINK) { if (field.type === FieldType.LINK) {
// find the links that pertain to this field // find the links that pertain to this field
const links = linkVals.filter(link => link.fieldName === fieldName) const links = linkVals.filter(link => link.fieldName === fieldName)
// find the rows that the links state are linked to this field // find the rows that the links state are linked to this field

View file

@ -4,9 +4,15 @@ import {
processAutoColumn, processAutoColumn,
processFormulas, processFormulas,
} from "../../../utilities/rowProcessor" } from "../../../utilities/rowProcessor"
import { FieldTypes, FormulaTypes } from "../../../constants"
import { context, locks } from "@budibase/backend-core" import { context, locks } from "@budibase/backend-core"
import { Table, Row, LockType, LockName } from "@budibase/types" import {
Table,
Row,
LockType,
LockName,
FormulaType,
FieldType,
} from "@budibase/types"
import * as linkRows from "../../../db/linkedRows" import * as linkRows from "../../../db/linkedRows"
import sdk from "../../../sdk" import sdk from "../../../sdk"
import isEqual from "lodash/isEqual" import isEqual from "lodash/isEqual"
@ -35,7 +41,7 @@ export async function updateRelatedFormula(
let relatedRows: Record<string, Row[]> = {} let relatedRows: Record<string, Row[]> = {}
for (let [key, field] of Object.entries(enrichedRow)) { for (let [key, field] of Object.entries(enrichedRow)) {
const columnDefinition = table.schema[key] const columnDefinition = table.schema[key]
if (columnDefinition && columnDefinition.type === FieldTypes.LINK) { if (columnDefinition && columnDefinition.type === FieldType.LINK) {
const relatedTableId = columnDefinition.tableId! const relatedTableId = columnDefinition.tableId!
if (!relatedRows[relatedTableId]) { if (!relatedRows[relatedTableId]) {
relatedRows[relatedTableId] = [] relatedRows[relatedTableId] = []
@ -63,8 +69,8 @@ export async function updateRelatedFormula(
for (let column of Object.values(relatedTable!.schema)) { for (let column of Object.values(relatedTable!.schema)) {
// needs updated in related rows // needs updated in related rows
if ( if (
column.type === FieldTypes.FORMULA && column.type === FieldType.FORMULA &&
column.formulaType === FormulaTypes.STATIC column.formulaType === FormulaType.STATIC
) { ) {
// re-enrich rows for all the related, don't update the related formula for them // re-enrich rows for all the related, don't update the related formula for them
promises = promises.concat( promises = promises.concat(

View file

@ -1,4 +1,3 @@
import { FormulaTypes } from "../../../constants"
import { clearColumns } from "./utils" import { clearColumns } from "./utils"
import { doesContainStrings } from "@budibase/string-templates" import { doesContainStrings } from "@budibase/string-templates"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
@ -7,6 +6,7 @@ import uniq from "lodash/uniq"
import { updateAllFormulasInTable } from "../row/staticFormula" import { updateAllFormulasInTable } from "../row/staticFormula"
import { context } from "@budibase/backend-core" import { context } from "@budibase/backend-core"
import { import {
FormulaType,
FieldSchema, FieldSchema,
FieldType, FieldType,
FormulaFieldMetadata, FormulaFieldMetadata,
@ -17,10 +17,10 @@ import { isRelationshipColumn } from "../../../db/utils"
function isStaticFormula( function isStaticFormula(
column: FieldSchema column: FieldSchema
): column is FormulaFieldMetadata & { formulaType: FormulaTypes.STATIC } { ): column is FormulaFieldMetadata & { formulaType: FormulaType.STATIC } {
return ( return (
column.type === FieldType.FORMULA && column.type === FieldType.FORMULA &&
column.formulaType === FormulaTypes.STATIC column.formulaType === FormulaType.STATIC
) )
} }

View file

@ -1,5 +1,4 @@
import { FieldType } from "@budibase/types" import { AutoFieldSubType, FieldType } from "@budibase/types"
import { AutoFieldSubTypes } from "../../../../constants"
import TestConfiguration from "../../../../tests/utilities/TestConfiguration" import TestConfiguration from "../../../../tests/utilities/TestConfiguration"
import { importToRows } from "../utils" import { importToRows } from "../utils"
@ -22,7 +21,7 @@ describe("utils", () => {
autoId: { autoId: {
name: "autoId", name: "autoId",
type: FieldType.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldType.NUMBER, type: FieldType.NUMBER,
@ -69,7 +68,7 @@ describe("utils", () => {
autoId: { autoId: {
name: "autoId", name: "autoId",
type: FieldType.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldType.NUMBER, type: FieldType.NUMBER,

View file

@ -2,8 +2,6 @@ import { parse, isSchema, isRows } from "../../../utilities/schema"
import { getRowParams, generateRowID, InternalTables } from "../../../db/utils" import { getRowParams, generateRowID, InternalTables } from "../../../db/utils"
import isEqual from "lodash/isEqual" import isEqual from "lodash/isEqual"
import { import {
AutoFieldSubTypes,
FieldTypes,
GOOGLE_SHEETS_PRIMARY_KEY, GOOGLE_SHEETS_PRIMARY_KEY,
USERS_TABLE_SCHEMA, USERS_TABLE_SCHEMA,
SwitchableTypes, SwitchableTypes,
@ -19,6 +17,7 @@ import { cloneDeep } from "lodash/fp"
import { quotas } from "@budibase/pro" import { quotas } from "@budibase/pro"
import { events, context } from "@budibase/backend-core" import { events, context } from "@budibase/backend-core"
import { import {
AutoFieldSubType,
ContextUser, ContextUser,
Datasource, Datasource,
Row, Row,
@ -106,7 +105,7 @@ export function makeSureTableUpToDate(table: Table, tableToSave: Table) {
for ([field, column] of Object.entries(table.schema)) { for ([field, column] of Object.entries(table.schema)) {
if ( if (
column.autocolumn && column.autocolumn &&
column.subtype === AutoFieldSubTypes.AUTO_ID && column.subtype === AutoFieldSubType.AUTO_ID &&
tableToSave.schema[field] tableToSave.schema[field]
) { ) {
const tableCol = tableToSave.schema[field] as NumberFieldMetadata const tableCol = tableToSave.schema[field] as NumberFieldMetadata
@ -144,8 +143,8 @@ export async function importToRows(
? row[fieldName] ? row[fieldName]
: [row[fieldName]] : [row[fieldName]]
if ( if (
(schema.type === FieldTypes.OPTIONS || (schema.type === FieldType.OPTIONS ||
schema.type === FieldTypes.ARRAY) && schema.type === FieldType.ARRAY) &&
row[fieldName] row[fieldName]
) { ) {
let merged = [...schema.constraints!.inclusion!, ...rowVal] let merged = [...schema.constraints!.inclusion!, ...rowVal]
@ -403,7 +402,7 @@ export async function checkForViewUpdates(
) )
const newViewTemplate = viewTemplate( const newViewTemplate = viewTemplate(
viewMetadata, viewMetadata,
groupByField?.type === FieldTypes.ARRAY groupByField?.type === FieldType.ARRAY
) )
const viewName = view.name! const viewName = view.name!
await saveView(null, viewName, newViewTemplate) await saveView(null, viewName, newViewTemplate)
@ -434,7 +433,7 @@ export function generateJunctionTableName(
export function foreignKeyStructure(keyName: string, meta?: any) { export function foreignKeyStructure(keyName: string, meta?: any) {
const structure: any = { const structure: any = {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
constraints: {}, constraints: {},
name: keyName, name: keyName,
} }

View file

@ -6,8 +6,8 @@ import { fetchView } from "../row"
import { context, events } from "@budibase/backend-core" import { context, events } from "@budibase/backend-core"
import { DocumentType } from "../../../db/utils" import { DocumentType } from "../../../db/utils"
import sdk from "../../../sdk" import sdk from "../../../sdk"
import { FieldTypes } from "../../../constants"
import { import {
FieldType,
Ctx, Ctx,
Row, Row,
Table, Table,
@ -37,7 +37,7 @@ export async function save(ctx: Ctx) {
(field: any) => field.name == viewToSave.groupBy (field: any) => field.name == viewToSave.groupBy
) )
const view = viewTemplate(viewToSave, groupByField?.type === FieldTypes.ARRAY) const view = viewTemplate(viewToSave, groupByField?.type === FieldType.ARRAY)
const viewName = viewToSave.name const viewName = viewToSave.name
if (!viewName) { if (!viewName) {

View file

@ -6,11 +6,11 @@ import * as setup from "./utilities"
import { context, InternalTable, roles, tenancy } from "@budibase/backend-core" import { context, InternalTable, roles, tenancy } from "@budibase/backend-core"
import { quotas } from "@budibase/pro" import { quotas } from "@budibase/pro"
import { import {
AutoFieldSubTypes, AutoFieldSubType,
FieldSchema, FieldSchema,
FieldType, FieldType,
FieldTypeSubtypes, FieldTypeSubtypes,
FormulaTypes, FormulaType,
INTERNAL_TABLE_SOURCE_ID, INTERNAL_TABLE_SOURCE_ID,
MonthlyQuotaName, MonthlyQuotaName,
PermissionLevel, PermissionLevel,
@ -192,7 +192,7 @@ describe.each([
"Row ID": { "Row ID": {
name: "Row ID", name: "Row ID",
type: FieldType.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
icon: "ri-magic-line", icon: "ri-magic-line",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
@ -2032,7 +2032,7 @@ describe.each([
name: "formula", name: "formula",
type: FieldType.FORMULA, type: FieldType.FORMULA,
formula: "{{ links.0.name }}", formula: "{{ links.0.name }}",
formulaType: FormulaTypes.DYNAMIC, formulaType: FormulaType.DYNAMIC,
}, },
}, },
} }
@ -2086,7 +2086,7 @@ describe.each([
name: "formula", name: "formula",
type: FieldType.FORMULA, type: FieldType.FORMULA,
formula: `{{ js "${js}"}}`, formula: `{{ js "${js}"}}`,
formulaType: FormulaTypes.DYNAMIC, formulaType: FormulaType.DYNAMIC,
}, },
}, },
}) })
@ -2129,7 +2129,7 @@ describe.each([
name: "formula", name: "formula",
type: FieldType.FORMULA, type: FieldType.FORMULA,
formula: `{{ js "${js}"}}`, formula: `{{ js "${js}"}}`,
formulaType: FormulaTypes.DYNAMIC, formulaType: FormulaType.DYNAMIC,
}, },
}, },
}) })

View file

@ -1,6 +1,6 @@
import { context, events } from "@budibase/backend-core" import { context, events } from "@budibase/backend-core"
import { import {
AutoFieldSubTypes, AutoFieldSubType,
FieldSubtype, FieldSubtype,
FieldType, FieldType,
INTERNAL_TABLE_SOURCE_ID, INTERNAL_TABLE_SOURCE_ID,
@ -205,7 +205,7 @@ describe("/tables", () => {
autoId: { autoId: {
name: "id", name: "id",
type: FieldType.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: "number", type: "number",

View file

@ -1,9 +1,9 @@
import * as rowController from "../../api/controllers/row" import * as rowController from "../../api/controllers/row"
import * as tableController from "../../api/controllers/table" import * as tableController from "../../api/controllers/table"
import { FieldTypes } from "../../constants"
import { buildCtx } from "./utils" import { buildCtx } from "./utils"
import * as automationUtils from "../automationUtils" import * as automationUtils from "../automationUtils"
import { import {
FieldType,
AutomationActionStepId, AutomationActionStepId,
AutomationCustomIOType, AutomationCustomIOType,
AutomationFeature, AutomationFeature,
@ -115,7 +115,7 @@ function typeCoercion(filters: SearchFilters, table: Table) {
if (!column || typeof value !== "string") { if (!column || typeof value !== "string") {
continue continue
} }
if (column.type === FieldTypes.NUMBER) { if (column.type === FieldType.NUMBER) {
if (key === "oneOf") { if (key === "oneOf") {
searchParam[property] = value searchParam[property] = value
.split(",") .split(",")
@ -148,11 +148,11 @@ export async function run({ inputs, appId }: AutomationStepInput) {
} }
} }
const table = await getTable(appId, tableId) const table = await getTable(appId, tableId)
let sortType = FieldTypes.STRING let sortType = FieldType.STRING
if (table && table.schema && table.schema[sortColumn] && sortColumn) { if (table && table.schema && table.schema[sortColumn] && sortColumn) {
const fieldType = table.schema[sortColumn].type const fieldType = table.schema[sortColumn].type
sortType = sortType =
fieldType === FieldTypes.NUMBER ? FieldTypes.NUMBER : FieldTypes.STRING fieldType === FieldType.NUMBER ? FieldType.NUMBER : FieldType.STRING
} }
const ctx: any = buildCtx(appId, null, { const ctx: any = buildCtx(appId, null, {
params: { params: {

View file

@ -1,18 +1,11 @@
import { constants, objectStore, roles } from "@budibase/backend-core" import { constants, objectStore, roles } from "@budibase/backend-core"
import { import {
FieldType as FieldTypes, FieldType,
INTERNAL_TABLE_SOURCE_ID, INTERNAL_TABLE_SOURCE_ID,
Table, Table,
TableSourceType, TableSourceType,
} from "@budibase/types" } from "@budibase/types"
export {
FieldType as FieldTypes,
RelationshipType,
AutoFieldSubTypes,
FormulaTypes,
} from "@budibase/types"
export enum FilterTypes { export enum FilterTypes {
STRING = "string", STRING = "string",
FUZZY = "fuzzy", FUZZY = "fuzzy",
@ -36,14 +29,14 @@ export const NoEmptyFilterStrings = [
] ]
export const CanSwitchTypes = [ export const CanSwitchTypes = [
[FieldTypes.JSON, FieldTypes.ARRAY], [FieldType.JSON, FieldType.ARRAY],
[ [
FieldTypes.STRING, FieldType.STRING,
FieldTypes.OPTIONS, FieldType.OPTIONS,
FieldTypes.LONGFORM, FieldType.LONGFORM,
FieldTypes.BARCODEQR, FieldType.BARCODEQR,
], ],
[FieldTypes.BOOLEAN, FieldTypes.NUMBER], [FieldType.BOOLEAN, FieldType.NUMBER],
] ]
export const SwitchableTypes = CanSwitchTypes.reduce((prev, current) => export const SwitchableTypes = CanSwitchTypes.reduce((prev, current) =>
@ -86,9 +79,9 @@ export const USERS_TABLE_SCHEMA: Table = {
// 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
schema: { schema: {
email: { email: {
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
email: true, email: true,
length: { length: {
maximum: "", maximum: "",
@ -99,34 +92,34 @@ export const USERS_TABLE_SCHEMA: Table = {
}, },
firstName: { firstName: {
name: "firstName", name: "firstName",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
presence: false, presence: false,
}, },
}, },
lastName: { lastName: {
name: "lastName", name: "lastName",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
presence: false, presence: false,
}, },
}, },
roleId: { roleId: {
name: "roleId", name: "roleId",
type: FieldTypes.OPTIONS, type: FieldType.OPTIONS,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
presence: false, presence: false,
inclusion: Object.values(roles.BUILTIN_ROLE_IDS), inclusion: Object.values(roles.BUILTIN_ROLE_IDS),
}, },
}, },
status: { status: {
name: "status", name: "status",
type: FieldTypes.OPTIONS, type: FieldType.OPTIONS,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
presence: false, presence: false,
inclusion: Object.values(constants.UserStatus), inclusion: Object.values(constants.UserStatus),
}, },

View file

@ -1,6 +1,4 @@
import { import {
AutoFieldSubTypes,
FieldTypes,
DEFAULT_BB_DATASOURCE_ID, DEFAULT_BB_DATASOURCE_ID,
DEFAULT_INVENTORY_TABLE_ID, DEFAULT_INVENTORY_TABLE_ID,
DEFAULT_EMPLOYEE_TABLE_ID, DEFAULT_EMPLOYEE_TABLE_ID,
@ -16,6 +14,7 @@ import { jobsImport } from "./jobsImport"
import { expensesImport } from "./expensesImport" import { expensesImport } from "./expensesImport"
import { db as dbCore } from "@budibase/backend-core" import { db as dbCore } from "@budibase/backend-core"
import { import {
AutoFieldSubType,
FieldType, FieldType,
RelationshipType, RelationshipType,
Row, Row,
@ -40,7 +39,7 @@ function syncLastIds(table: Table, rowCount: number) {
if ( if (
entry.autocolumn && entry.autocolumn &&
entry.type === FieldType.NUMBER && entry.type === FieldType.NUMBER &&
entry.subtype == AutoFieldSubTypes.AUTO_ID entry.subtype == AutoFieldSubType.AUTO_ID
) { ) {
entry.lastID = rowCount entry.lastID = rowCount
} }
@ -58,12 +57,12 @@ async function tableImport(table: Table, data: Row[]) {
const AUTO_COLUMNS: TableSchema = { const AUTO_COLUMNS: TableSchema = {
"Created At": { "Created At": {
name: "Created At", name: "Created At",
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
subtype: AutoFieldSubTypes.CREATED_AT, subtype: AutoFieldSubType.CREATED_AT,
icon: "ri-magic-line", icon: "ri-magic-line",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -74,12 +73,12 @@ const AUTO_COLUMNS: TableSchema = {
}, },
"Updated At": { "Updated At": {
name: "Updated At", name: "Updated At",
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
subtype: AutoFieldSubTypes.UPDATED_AT, subtype: AutoFieldSubType.UPDATED_AT,
icon: "ri-magic-line", icon: "ri-magic-line",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -101,12 +100,12 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
schema: { schema: {
"Item ID": { "Item ID": {
name: "Item ID", name: "Item ID",
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
icon: "ri-magic-line", icon: "ri-magic-line",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
presence: false, presence: false,
numericality: { numericality: {
greaterThanOrEqualTo: "", greaterThanOrEqualTo: "",
@ -115,9 +114,9 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
}, },
}, },
"Item Name": { "Item Name": {
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: { length: {
maximum: null, maximum: null,
}, },
@ -128,9 +127,9 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
name: "Item Name", name: "Item Name",
}, },
"Item Tags": { "Item Tags": {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },
@ -140,9 +139,9 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
sortable: false, sortable: false,
}, },
Notes: { Notes: {
type: FieldTypes.LONGFORM, type: FieldType.LONGFORM,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
@ -150,9 +149,9 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
useRichText: null, useRichText: null,
}, },
Status: { Status: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },
@ -162,18 +161,18 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
sortable: false, sortable: false,
}, },
SKU: { SKU: {
type: FieldTypes.BARCODEQR, type: FieldType.BARCODEQR,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
name: "SKU", name: "SKU",
}, },
"Purchase Date": { "Purchase Date": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -185,9 +184,9 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
ignoreTimezones: true, ignoreTimezones: true,
}, },
"Purchase Price": { "Purchase Price": {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
constraints: { constraints: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
presence: false, presence: false,
numericality: { numericality: {
greaterThanOrEqualTo: null, greaterThanOrEqualTo: null,
@ -211,75 +210,75 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
schema: { schema: {
"First Name": { "First Name": {
name: "First Name", name: "First Name",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
}, },
"Last Name": { "Last Name": {
name: "Last Name", name: "Last Name",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
}, },
Email: { Email: {
name: "Email", name: "Email",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
}, },
Address: { Address: {
name: "Address", name: "Address",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
}, },
City: { City: {
name: "City", name: "City",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
}, },
Postcode: { Postcode: {
name: "Postcode", name: "Postcode",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
}, },
Phone: { Phone: {
name: "Phone", name: "Phone",
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
}, },
"EMPLOYEE ID": { "EMPLOYEE ID": {
name: "EMPLOYEE ID", name: "EMPLOYEE ID",
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
icon: "ri-magic-line", icon: "ri-magic-line",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
presence: false, presence: false,
numericality: { numericality: {
greaterThanOrEqualTo: "", greaterThanOrEqualTo: "",
@ -288,9 +287,9 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
}, },
}, },
"Employee Level": { "Employee Level": {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
presence: false, presence: false,
inclusion: ["Manager", "Junior", "Senior", "Apprentice", "Contractor"], inclusion: ["Manager", "Junior", "Senior", "Apprentice", "Contractor"],
}, },
@ -298,18 +297,18 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
sortable: false, sortable: false,
}, },
"Badge Photo": { "Badge Photo": {
type: FieldTypes.ATTACHMENT, type: FieldType.ATTACHMENT,
constraints: { constraints: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
presence: false, presence: false,
}, },
name: "Badge Photo", name: "Badge Photo",
sortable: false, sortable: false,
}, },
Jobs: { Jobs: {
type: FieldTypes.LINK, type: FieldType.LINK,
constraints: { constraints: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
presence: false, presence: false,
}, },
fieldName: "Assigned", fieldName: "Assigned",
@ -318,9 +317,9 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
tableId: DEFAULT_JOBS_TABLE_ID, tableId: DEFAULT_JOBS_TABLE_ID,
}, },
"Start Date": { "Start Date": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -332,9 +331,9 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
ignoreTimezones: true, ignoreTimezones: true,
}, },
"End Date": { "End Date": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -359,12 +358,12 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
schema: { schema: {
"Job ID": { "Job ID": {
name: "Job ID", name: "Job ID",
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
icon: "ri-magic-line", icon: "ri-magic-line",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
presence: false, presence: false,
numericality: { numericality: {
greaterThanOrEqualTo: "", greaterThanOrEqualTo: "",
@ -373,9 +372,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
}, },
}, },
"Quote Date": { "Quote Date": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: { presence: {
allowEmpty: false, allowEmpty: false,
@ -389,9 +388,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
ignoreTimezones: true, ignoreTimezones: true,
}, },
"Quote Price": { "Quote Price": {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
constraints: { constraints: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },
@ -403,9 +402,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
name: "Quote Price", name: "Quote Price",
}, },
"Works Start": { "Works Start": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -417,9 +416,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
ignoreTimezones: true, ignoreTimezones: true,
}, },
Address: { Address: {
type: FieldTypes.LONGFORM, type: FieldType.LONGFORM,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
@ -427,9 +426,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
useRichText: null, useRichText: null,
}, },
"Customer Name": { "Customer Name": {
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: { length: {
maximum: null, maximum: null,
}, },
@ -438,9 +437,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
name: "Customer Name", name: "Customer Name",
}, },
Notes: { Notes: {
type: FieldTypes.LONGFORM, type: FieldType.LONGFORM,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
@ -448,9 +447,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
useRichText: null, useRichText: null,
}, },
"Customer Phone": { "Customer Phone": {
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: { length: {
maximum: null, maximum: null,
}, },
@ -459,9 +458,9 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
name: "Customer Phone", name: "Customer Phone",
}, },
"Customer Email": { "Customer Email": {
type: FieldTypes.STRING, type: FieldType.STRING,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: { length: {
maximum: null, maximum: null,
}, },
@ -471,14 +470,14 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
}, },
Assigned: { Assigned: {
name: "Assigned", name: "Assigned",
type: FieldTypes.LINK, type: FieldType.LINK,
tableId: DEFAULT_EMPLOYEE_TABLE_ID, tableId: DEFAULT_EMPLOYEE_TABLE_ID,
fieldName: "Jobs", fieldName: "Jobs",
relationshipType: RelationshipType.MANY_TO_MANY, relationshipType: RelationshipType.MANY_TO_MANY,
// sortable: true, // sortable: true,
}, },
"Works End": { "Works End": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: "string", type: "string",
length: {}, length: {},
@ -492,7 +491,7 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
ignoreTimezones: true, ignoreTimezones: true,
}, },
"Updated Price": { "Updated Price": {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
constraints: { constraints: {
type: "number", type: "number",
presence: false, presence: false,
@ -518,12 +517,12 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
schema: { schema: {
"Expense ID": { "Expense ID": {
name: "Expense ID", name: "Expense ID",
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
icon: "ri-magic-line", icon: "ri-magic-line",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
presence: false, presence: false,
numericality: { numericality: {
greaterThanOrEqualTo: "", greaterThanOrEqualTo: "",
@ -532,9 +531,9 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
}, },
}, },
"Expense Tags": { "Expense Tags": {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },
@ -554,9 +553,9 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
sortable: false, sortable: false,
}, },
Cost: { Cost: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
constraints: { constraints: {
type: FieldTypes.NUMBER, type: FieldType.NUMBER,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },
@ -568,9 +567,9 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
name: "Cost", name: "Cost",
}, },
Notes: { Notes: {
type: FieldTypes.LONGFORM, type: FieldType.LONGFORM,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
}, },
@ -578,9 +577,9 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
useRichText: null, useRichText: null,
}, },
"Payment Due": { "Payment Due": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -592,9 +591,9 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
ignoreTimezones: true, ignoreTimezones: true,
}, },
"Date Paid": { "Date Paid": {
type: FieldTypes.DATETIME, type: FieldType.DATETIME,
constraints: { constraints: {
type: FieldTypes.STRING, type: FieldType.STRING,
length: {}, length: {},
presence: false, presence: false,
datetime: { datetime: {
@ -606,9 +605,9 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
ignoreTimezones: true, ignoreTimezones: true,
}, },
Attachment: { Attachment: {
type: FieldTypes.ATTACHMENT, type: FieldType.ATTACHMENT,
constraints: { constraints: {
type: FieldTypes.ARRAY, type: FieldType.ARRAY,
presence: false, presence: false,
}, },
name: "Attachment", name: "Attachment",

View file

@ -1,6 +1,5 @@
import { IncludeDocs, getLinkDocuments } from "./linkUtils" import { IncludeDocs, getLinkDocuments } from "./linkUtils"
import { InternalTables, getUserMetadataParams } from "../utils" import { InternalTables, getUserMetadataParams } from "../utils"
import { FieldTypes } from "../../constants"
import { context, logging } from "@budibase/backend-core" import { context, logging } from "@budibase/backend-core"
import LinkDocument from "./LinkDocument" import LinkDocument from "./LinkDocument"
import { import {
@ -62,7 +61,7 @@ class LinkController {
} }
for (let fieldName of Object.keys(table.schema)) { for (let fieldName of Object.keys(table.schema)) {
const { type } = table.schema[fieldName] const { type } = table.schema[fieldName]
if (type === FieldTypes.LINK) { if (type === FieldType.LINK) {
return true return true
} }
} }
@ -96,7 +95,7 @@ class LinkController {
validateTable(table: Table) { validateTable(table: Table) {
const usedAlready = [] const usedAlready = []
for (let schema of Object.values(table.schema)) { for (let schema of Object.values(table.schema)) {
if (schema.type !== FieldTypes.LINK) { if (schema.type !== FieldType.LINK) {
continue continue
} }
const unique = schema.tableId! + schema?.fieldName const unique = schema.tableId! + schema?.fieldName
@ -172,7 +171,7 @@ class LinkController {
// get the links this row wants to make // get the links this row wants to make
const rowField = row[fieldName] const rowField = row[fieldName]
const field = table.schema[fieldName] const field = table.schema[fieldName]
if (field.type === FieldTypes.LINK && rowField != null) { if (field.type === FieldType.LINK && rowField != null) {
// check which links actual pertain to the update in this row // check which links actual pertain to the update in this row
const thisFieldLinkDocs = linkDocs.filter( const thisFieldLinkDocs = linkDocs.filter(
linkDoc => linkDoc =>
@ -353,7 +352,7 @@ class LinkController {
const schema = table.schema const schema = table.schema
for (let fieldName of Object.keys(schema)) { for (let fieldName of Object.keys(schema)) {
const field = schema[fieldName] const field = schema[fieldName]
if (field.type === FieldTypes.LINK && field.fieldName) { if (field.type === FieldType.LINK && field.fieldName) {
// handle this in a separate try catch, want // handle this in a separate try catch, want
// the put to bubble up as an error, if can't update // the put to bubble up as an error, if can't update
// table for some reason // table for some reason
@ -366,7 +365,7 @@ class LinkController {
} }
const fields = this.handleRelationshipType(field, { const fields = this.handleRelationshipType(field, {
name: field.fieldName, name: field.fieldName,
type: FieldTypes.LINK, type: FieldType.LINK,
// these are the props of the table that initiated the link // these are the props of the table that initiated the link
tableId: table._id!, tableId: table._id!,
fieldName: fieldName, fieldName: fieldName,
@ -413,10 +412,7 @@ class LinkController {
for (let fieldName of Object.keys(oldTable?.schema || {})) { for (let fieldName of Object.keys(oldTable?.schema || {})) {
const field = oldTable?.schema[fieldName] as FieldSchema const field = oldTable?.schema[fieldName] as FieldSchema
// this field has been removed from the table schema // this field has been removed from the table schema
if ( if (field.type === FieldType.LINK && newTable.schema[fieldName] == null) {
field.type === FieldTypes.LINK &&
newTable.schema[fieldName] == null
) {
await this.removeFieldFromTable(fieldName) await this.removeFieldFromTable(fieldName)
} }
} }
@ -437,7 +433,7 @@ class LinkController {
for (let fieldName of Object.keys(schema)) { for (let fieldName of Object.keys(schema)) {
const field = schema[fieldName] const field = schema[fieldName]
try { try {
if (field.type === FieldTypes.LINK && field.fieldName) { if (field.type === FieldType.LINK && field.fieldName) {
const linkedTable = await this._db.get<Table>(field.tableId) const linkedTable = await this._db.get<Table>(field.tableId)
delete linkedTable.schema[field.fieldName] delete linkedTable.schema[field.fieldName]
field.tableRev = (await this._db.put(linkedTable)).rev field.tableRev = (await this._db.put(linkedTable)).rev

View file

@ -1,6 +1,5 @@
import { generateLinkID } from "../utils" import { generateLinkID } from "../utils"
import { FieldTypes } from "../../constants" import { FieldType, LinkDocument } from "@budibase/types"
import { LinkDocument } from "@budibase/types"
/** /**
* Creates a new link document structure which can be put to the database. It is important to * Creates a new link document structure which can be put to the database. It is important to
@ -43,7 +42,7 @@ class LinkDocumentImpl implements LinkDocument {
fieldName1, fieldName1,
fieldName2 fieldName2
) )
this.type = FieldTypes.LINK this.type = FieldType.LINK
this.doc1 = { this.doc1 = {
tableId: tableId1, tableId: tableId1,
fieldName: fieldName1, fieldName: fieldName1,

View file

@ -1,8 +1,8 @@
import { ViewName, getQueryIndex, isRelationshipColumn } from "../utils" import { ViewName, getQueryIndex, isRelationshipColumn } from "../utils"
import { FieldTypes } from "../../constants"
import { createLinkView } from "../views/staticViews" import { createLinkView } from "../views/staticViews"
import { context, logging } from "@budibase/backend-core" import { context, logging } from "@budibase/backend-core"
import { import {
FieldType,
DatabaseQueryOpts, DatabaseQueryOpts,
LinkDocument, LinkDocument,
LinkDocumentValue, LinkDocumentValue,
@ -131,11 +131,11 @@ export async function getLinkedTable(id: string, tables: Table[]) {
export function getRelatedTableForField(table: Table, fieldName: string) { export function getRelatedTableForField(table: Table, fieldName: string) {
// look to see if its on the table, straight in the schema // look to see if its on the table, straight in the schema
const field = table.schema[fieldName] const field = table.schema[fieldName]
if (field?.type === FieldTypes.LINK) { if (field?.type === FieldType.LINK) {
return field.tableId return field.tableId
} }
for (let column of Object.values(table.schema)) { for (let column of Object.values(table.schema)) {
if (column.type === FieldTypes.LINK && column.fieldName === fieldName) { if (column.type === FieldType.LINK && column.fieldName === fieldName) {
return column.tableId return column.tableId
} }
} }

View file

@ -1,17 +1,57 @@
const TestConfig = require("../../tests/utilities/TestConfiguration") import TestConfig from "../../tests/utilities/TestConfiguration"
const { import {
basicRow,
basicLinkedRow, basicLinkedRow,
basicRow,
basicTable, basicTable,
} = require("../../tests/utilities/structures") } from "../../tests/utilities/structures"
const LinkController = require("../linkedRows/LinkController").default import LinkController from "../linkedRows/LinkController"
const { context } = require("@budibase/backend-core") import { context } from "@budibase/backend-core"
const { RelationshipType } = require("../../constants") import {
const { cloneDeep } = require("lodash/fp") FieldType,
ManyToManyRelationshipFieldMetadata,
ManyToOneRelationshipFieldMetadata,
OneToManyRelationshipFieldMetadata,
RelationshipFieldMetadata,
RelationshipType,
Row,
Table,
} from "@budibase/types"
import { cloneDeep } from "lodash"
const baseColumn = {
type: FieldType.LINK,
fieldName: "",
tableId: "",
name: "",
}
function mockManyToManyColumn(): ManyToManyRelationshipFieldMetadata {
return <ManyToManyRelationshipFieldMetadata>{
...baseColumn,
through: "",
throughFrom: "",
throughTo: "",
relationshipType: RelationshipType.MANY_TO_MANY,
}
}
function mockManyToOneColumn(): ManyToOneRelationshipFieldMetadata {
return <ManyToOneRelationshipFieldMetadata>{
...baseColumn,
relationshipType: RelationshipType.MANY_TO_ONE,
}
}
function mockOneToManyColumn(): OneToManyRelationshipFieldMetadata {
return <OneToManyRelationshipFieldMetadata>{
...baseColumn,
relationshipType: RelationshipType.ONE_TO_MANY,
}
}
describe("test the link controller", () => { describe("test the link controller", () => {
let config = new TestConfig() let config = new TestConfig()
let table1, table2, appId let table1: Table, table2: Table, appId: string
beforeAll(async () => { beforeAll(async () => {
const app = await config.init() const app = await config.init()
@ -30,9 +70,18 @@ describe("test the link controller", () => {
afterAll(config.end) afterAll(config.end)
async function createLinkController(table, row = null, oldTable = null) { async function createLinkController(
table: Table,
row?: Row,
oldTable?: Table
) {
return context.doInAppContext(appId, () => { return context.doInAppContext(appId, () => {
const linkConfig = { const linkConfig: {
tableId?: string
table: Table
row?: Row
oldTable?: Table
} = {
tableId: table._id, tableId: table._id,
table, table,
} }
@ -47,11 +96,11 @@ describe("test the link controller", () => {
} }
async function createLinkedRow(linkField = "link", t1 = table1, t2 = table2) { async function createLinkedRow(linkField = "link", t1 = table1, t2 = table2) {
const row = await config.createRow(basicRow(t2._id)) const row = await config.createRow(basicRow(t2._id!))
const { _id } = await config.createRow( const { _id } = await config.createRow(
basicLinkedRow(t1._id, row._id, linkField) basicLinkedRow(t1._id!, row._id!, linkField)
) )
return config.getRow(t1._id, _id) return config.getRow(t1._id!, _id!)
} }
it("should be able to confirm if two table schemas are equal", async () => { it("should be able to confirm if two table schemas are equal", async () => {
@ -71,6 +120,7 @@ describe("test the link controller", () => {
it("should be able to check the relationship types across two fields", async () => { it("should be able to check the relationship types across two fields", async () => {
const controller = await createLinkController(table1) const controller = await createLinkController(table1)
// empty case // empty case
//@ts-ignore
let output = controller.handleRelationshipType({}, {}) let output = controller.handleRelationshipType({}, {})
expect(output.linkedField.relationshipType).toEqual( expect(output.linkedField.relationshipType).toEqual(
RelationshipType.MANY_TO_MANY RelationshipType.MANY_TO_MANY
@ -79,8 +129,8 @@ describe("test the link controller", () => {
RelationshipType.MANY_TO_MANY RelationshipType.MANY_TO_MANY
) )
output = controller.handleRelationshipType( output = controller.handleRelationshipType(
{ relationshipType: RelationshipType.MANY_TO_MANY }, mockManyToManyColumn(),
{} {} as any
) )
expect(output.linkedField.relationshipType).toEqual( expect(output.linkedField.relationshipType).toEqual(
RelationshipType.MANY_TO_MANY RelationshipType.MANY_TO_MANY
@ -88,20 +138,14 @@ describe("test the link controller", () => {
expect(output.linkerField.relationshipType).toEqual( expect(output.linkerField.relationshipType).toEqual(
RelationshipType.MANY_TO_MANY RelationshipType.MANY_TO_MANY
) )
output = controller.handleRelationshipType( output = controller.handleRelationshipType(mockManyToOneColumn(), {} as any)
{ relationshipType: RelationshipType.MANY_TO_ONE },
{}
)
expect(output.linkedField.relationshipType).toEqual( expect(output.linkedField.relationshipType).toEqual(
RelationshipType.ONE_TO_MANY RelationshipType.ONE_TO_MANY
) )
expect(output.linkerField.relationshipType).toEqual( expect(output.linkerField.relationshipType).toEqual(
RelationshipType.MANY_TO_ONE RelationshipType.MANY_TO_ONE
) )
output = controller.handleRelationshipType( output = controller.handleRelationshipType(mockOneToManyColumn(), {} as any)
{ relationshipType: RelationshipType.ONE_TO_MANY },
{}
)
expect(output.linkedField.relationshipType).toEqual( expect(output.linkedField.relationshipType).toEqual(
RelationshipType.MANY_TO_ONE RelationshipType.MANY_TO_ONE
) )
@ -115,16 +159,16 @@ describe("test the link controller", () => {
const controller = await createLinkController(table1, row) const controller = await createLinkController(table1, row)
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
// get initial count // get initial count
const beforeLinks = await controller.getRowLinkDocs(row._id) const beforeLinks = await controller.getRowLinkDocs(row._id!)
await controller.rowDeleted() await controller.rowDeleted()
let afterLinks = await controller.getRowLinkDocs(row._id) let afterLinks = await controller.getRowLinkDocs(row._id!)
expect(beforeLinks.length).toEqual(1) expect(beforeLinks.length).toEqual(1)
expect(afterLinks.length).toEqual(0) expect(afterLinks.length).toEqual(0)
}) })
}) })
it("shouldn't throw an error when deleting a row with no links", async () => { it("shouldn't throw an error when deleting a row with no links", async () => {
const row = await config.createRow(basicRow(table1._id)) const row = await config.createRow(basicRow(table1._id!))
const controller = await createLinkController(table1, row) const controller = await createLinkController(table1, row)
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
let error let error
@ -142,12 +186,13 @@ describe("test the link controller", () => {
const copyTable = { const copyTable = {
...table1, ...table1,
} }
//@ts-ignore
copyTable.schema.otherTableLink = { copyTable.schema.otherTableLink = {
type: "link", type: FieldType.LINK,
fieldName: "link", fieldName: "link",
tableId: table2._id, tableId: table2._id!,
} }
let error let error: any
try { try {
controller.validateTable(copyTable) controller.validateTable(copyTable)
} catch (err) { } catch (err) {
@ -166,7 +211,7 @@ describe("test the link controller", () => {
const controller = await createLinkController(table1, row) const controller = await createLinkController(table1, row)
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
await controller.rowSaved() await controller.rowSaved()
let links = await controller.getRowLinkDocs(row._id) let links = await controller.getRowLinkDocs(row._id!)
expect(links.length).toEqual(0) expect(links.length).toEqual(0)
}) })
}) })
@ -186,7 +231,7 @@ describe("test the link controller", () => {
it("should be able to remove a linked field from a table", async () => { it("should be able to remove a linked field from a table", async () => {
await createLinkedRow() await createLinkedRow()
await createLinkedRow("link2") await createLinkedRow("link2")
const controller = await createLinkController(table1, null, table1) const controller = await createLinkController(table1, undefined, table1)
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
let before = await controller.getTableLinkDocs() let before = await controller.getTableLinkDocs()
await controller.removeFieldFromTable("link") await controller.removeFieldFromTable("link")
@ -199,7 +244,8 @@ describe("test the link controller", () => {
it("should throw an error when overwriting a link column", async () => { it("should throw an error when overwriting a link column", async () => {
const update = cloneDeep(table1) const update = cloneDeep(table1)
update.schema.link.relationshipType = RelationshipType.MANY_TO_ONE const linkSchema = update.schema.link as ManyToOneRelationshipFieldMetadata
linkSchema.relationshipType = RelationshipType.MANY_TO_ONE
let error let error
try { try {
const controller = await createLinkController(update) const controller = await createLinkController(update)
@ -215,7 +261,7 @@ describe("test the link controller", () => {
await createLinkedRow() await createLinkedRow()
const newTable = cloneDeep(table1) const newTable = cloneDeep(table1)
delete newTable.schema.link delete newTable.schema.link
const controller = await createLinkController(newTable, null, table1) const controller = await createLinkController(newTable, undefined, table1)
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
await controller.tableUpdated() await controller.tableUpdated()
const links = await controller.getTableLinkDocs() const links = await controller.getTableLinkDocs()
@ -235,7 +281,7 @@ describe("test the link controller", () => {
let error let error
try { try {
// create another row to initiate the error // create another row to initiate the error
await config.createRow(basicLinkedRow(row.tableId, row.link[0])) await config.createRow(basicLinkedRow(row.tableId!, row.link[0]))
} catch (err) { } catch (err) {
error = err error = err
} }
@ -245,7 +291,7 @@ describe("test the link controller", () => {
it("should not error if a link being created doesn't exist", async () => { it("should not error if a link being created doesn't exist", async () => {
let error let error
try { try {
await config.createRow(basicLinkedRow(table1._id, "invalid")) await config.createRow(basicLinkedRow(table1._id!, "invalid"))
} catch (err) { } catch (err) {
error = err error = err
} }
@ -255,10 +301,11 @@ describe("test the link controller", () => {
it("make sure auto column goes onto other row too", async () => { it("make sure auto column goes onto other row too", async () => {
const table = await config.createTable() const table = await config.createTable()
const tableCfg = basicTable() const tableCfg = basicTable()
//@ts-ignore
tableCfg.schema.link = { tableCfg.schema.link = {
type: "link", type: FieldType.LINK,
fieldName: "link", fieldName: "link",
tableId: table._id, tableId: table._id!,
name: "link", name: "link",
autocolumn: true, autocolumn: true,
} }
@ -269,10 +316,11 @@ describe("test the link controller", () => {
it("should be able to link to self", async () => { it("should be able to link to self", async () => {
const table = await config.createTable() const table = await config.createTable()
//@ts-ignore
table.schema.link = { table.schema.link = {
type: "link", type: FieldType.LINK,
fieldName: "link", fieldName: "link",
tableId: table._id, tableId: table._id!,
name: "link", name: "link",
autocolumn: true, autocolumn: true,
} }
@ -282,8 +330,9 @@ describe("test the link controller", () => {
it("should be able to remove a linked field from a table, even if the linked table does not exist", async () => { it("should be able to remove a linked field from a table, even if the linked table does not exist", async () => {
await createLinkedRow() await createLinkedRow()
await createLinkedRow("link2") await createLinkedRow("link2")
table1.schema["link"].tableId = "not_found" const linkSchema = table1.schema["link"] as RelationshipFieldMetadata
const controller = await createLinkController(table1, null, table1) linkSchema.tableId = "not_found"
const controller = await createLinkController(table1, undefined, table1)
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
let before = await controller.getTableLinkDocs() let before = await controller.getTableLinkDocs()
await controller.removeFieldFromTable("link") await controller.removeFieldFromTable("link")

View file

@ -1,14 +1,15 @@
const TestConfig = require("../../tests/utilities/TestConfiguration") import TestConfig from "../../tests/utilities/TestConfiguration"
const { basicTable } = require("../../tests/utilities/structures") import { basicTable } from "../../tests/utilities/structures"
const linkUtils = require("../linkedRows/linkUtils") import * as linkUtils from "../linkedRows/linkUtils"
const { context } = require("@budibase/backend-core") import { context } from "@budibase/backend-core"
import { FieldType, RelationshipType, Table } from "@budibase/types"
describe("test link functionality", () => { describe("test link functionality", () => {
const config = new TestConfig() const config = new TestConfig()
let appId let appId: string
describe("getLinkedTable", () => { describe("getLinkedTable", () => {
let table let table: Table
beforeAll(async () => { beforeAll(async () => {
const app = await config.init() const app = await config.init()
appId = app.appId appId = app.appId
@ -17,15 +18,15 @@ describe("test link functionality", () => {
it("should be able to retrieve a linked table from a list", async () => { it("should be able to retrieve a linked table from a list", async () => {
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
const retrieved = await linkUtils.getLinkedTable(table._id, [table]) const retrieved = await linkUtils.getLinkedTable(table._id!, [table])
expect(retrieved._id).toBe(table._id) expect(retrieved._id).toBe(table._id)
}) })
}) })
it("should be able to retrieve a table from DB and update list", async () => { it("should be able to retrieve a table from DB and update list", async () => {
const tables = [] const tables: Table[] = []
await context.doInAppContext(appId, async () => { await context.doInAppContext(appId, async () => {
const retrieved = await linkUtils.getLinkedTable(table._id, tables) const retrieved = await linkUtils.getLinkedTable(table._id!, tables)
expect(retrieved._id).toBe(table._id) expect(retrieved._id).toBe(table._id)
expect(tables[0]).toBeDefined() expect(tables[0]).toBeDefined()
}) })
@ -35,9 +36,11 @@ describe("test link functionality", () => {
describe("getRelatedTableForField", () => { describe("getRelatedTableForField", () => {
let link = basicTable() let link = basicTable()
link.schema.link = { link.schema.link = {
name: "link",
relationshipType: RelationshipType.ONE_TO_MANY,
fieldName: "otherLink", fieldName: "otherLink",
tableId: "tableID", tableId: "tableID",
type: "link", type: FieldType.LINK,
} }
it("should get the field from the table directly", () => { it("should get the field from the table directly", () => {

View file

@ -1,6 +1,7 @@
import newid from "./newid" import newid from "./newid"
import { db as dbCore } from "@budibase/backend-core" import { db as dbCore } from "@budibase/backend-core"
import { import {
FieldType,
DocumentType, DocumentType,
FieldSchema, FieldSchema,
RelationshipFieldMetadata, RelationshipFieldMetadata,
@ -8,7 +9,6 @@ import {
INTERNAL_TABLE_SOURCE_ID, INTERNAL_TABLE_SOURCE_ID,
DatabaseQueryOpts, DatabaseQueryOpts,
} from "@budibase/types" } from "@budibase/types"
import { FieldTypes } from "../constants"
export { DocumentType, VirtualDocumentType } from "@budibase/types" export { DocumentType, VirtualDocumentType } from "@budibase/types"
@ -315,5 +315,5 @@ export function extractViewInfoFromID(viewId: string) {
export function isRelationshipColumn( export function isRelationshipColumn(
column: FieldSchema column: FieldSchema
): column is RelationshipFieldMetadata { ): column is RelationshipFieldMetadata {
return column.type === FieldTypes.LINK return column.type === FieldType.LINK
} }

View file

@ -1,5 +1,6 @@
import { Knex, knex } from "knex" import { Knex, knex } from "knex"
import { import {
RelationshipType,
FieldSubtype, FieldSubtype,
NumberFieldMetadata, NumberFieldMetadata,
Operation, Operation,
@ -11,7 +12,6 @@ import {
import { breakExternalTableId } from "../utils" import { breakExternalTableId } from "../utils"
import SchemaBuilder = Knex.SchemaBuilder import SchemaBuilder = Knex.SchemaBuilder
import CreateTableBuilder = Knex.CreateTableBuilder import CreateTableBuilder = Knex.CreateTableBuilder
import { RelationshipType } from "../../constants"
import { utils } from "@budibase/shared-core" import { utils } from "@budibase/shared-core"
function isIgnoredType(type: FieldType) { function isIgnoredType(type: FieldType) {

View file

@ -1,4 +1,5 @@
import { import {
FieldType,
DatasourceFieldType, DatasourceFieldType,
Integration, Integration,
Operation, Operation,
@ -21,7 +22,6 @@ import {
SqlClient, SqlClient,
} from "./utils" } from "./utils"
import Sql from "./base/sql" import Sql from "./base/sql"
import { FieldTypes } from "../constants"
import { import {
BindParameters, BindParameters,
Connection, Connection,
@ -302,7 +302,7 @@ class OracleIntegration extends Sql implements DatasourcePlus {
}) })
if (this.isBooleanType(oracleColumn)) { if (this.isBooleanType(oracleColumn)) {
fieldSchema.type = FieldTypes.BOOLEAN fieldSchema.type = FieldType.BOOLEAN
} }
table.schema[columnName] = fieldSchema table.schema[columnName] = fieldSchema

View file

@ -1,7 +1,6 @@
import { CouchFindOptions, Table, Row } from "@budibase/types" import { FieldType, CouchFindOptions, Table, Row } from "@budibase/types"
import { db as dbCore } from "@budibase/backend-core" import { db as dbCore } from "@budibase/backend-core"
import { DocumentType, SEPARATOR } from "../../../db/utils" import { DocumentType, SEPARATOR } from "../../../db/utils"
import { FieldTypes } from "../../../constants"
// default limit - seems to work well for performance // default limit - seems to work well for performance
export const FIND_LIMIT = 25 export const FIND_LIMIT = 25
@ -31,7 +30,7 @@ export async function getRowsWithAttachments(appId: string, table: Table) {
const db = dbCore.getDB(appId) const db = dbCore.getDB(appId)
const attachmentCols: string[] = [] const attachmentCols: string[] = []
for (let [key, column] of Object.entries(table.schema)) { for (let [key, column] of Object.entries(table.schema)) {
if (column.type === FieldTypes.ATTACHMENT) { if (column.type === FieldType.ATTACHMENT) {
attachmentCols.push(key) attachmentCols.push(key)
} }
} }

View file

@ -7,7 +7,7 @@ import {
TableSourceType, TableSourceType,
FieldType, FieldType,
Table, Table,
AutoFieldSubTypes, AutoFieldSubType,
} from "@budibase/types" } from "@budibase/types"
import TestConfiguration from "../../../../tests/utilities/TestConfiguration" import TestConfiguration from "../../../../tests/utilities/TestConfiguration"
@ -117,7 +117,7 @@ describe("sdk >> rows >> internal", () => {
id: { id: {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.AUTO,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
autocolumn: true, autocolumn: true,
lastID: 0, lastID: 0,
}, },
@ -181,7 +181,7 @@ describe("sdk >> rows >> internal", () => {
id: { id: {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.AUTO,
subtype: AutoFieldSubTypes.AUTO_ID, subtype: AutoFieldSubType.AUTO_ID,
autocolumn: true, autocolumn: true,
lastID: 0, lastID: 0,
}, },

View file

@ -1,7 +1,6 @@
import cloneDeep from "lodash/cloneDeep" import cloneDeep from "lodash/cloneDeep"
import validateJs from "validate.js" import validateJs from "validate.js"
import { Row, Table, TableSchema } from "@budibase/types" import { FieldType, Row, Table, TableSchema } from "@budibase/types"
import { FieldTypes } from "../../../constants"
import { makeExternalQuery } from "../../../integrations/base/query" import { makeExternalQuery } from "../../../integrations/base/query"
import { Format } from "../../../api/controllers/view/exporters" import { Format } from "../../../api/controllers/view/exporters"
import sdk from "../.." import sdk from "../.."
@ -22,7 +21,7 @@ export function cleanExportRows(
let cleanRows = [...rows] let cleanRows = [...rows]
const relationships = Object.entries(schema) const relationships = Object.entries(schema)
.filter((entry: any[]) => entry[1].type === FieldTypes.LINK) .filter((entry: any[]) => entry[1].type === FieldType.LINK)
.map(entry => entry[0]) .map(entry => entry[0])
relationships.forEach(column => { relationships.forEach(column => {
@ -88,17 +87,17 @@ export async function validate({
continue continue
} }
// formulas shouldn't validated, data will be deleted anyway // formulas shouldn't validated, data will be deleted anyway
if (type === FieldTypes.FORMULA || column.autocolumn) { if (type === FieldType.FORMULA || column.autocolumn) {
continue continue
} }
// special case for options, need to always allow unselected (empty) // special case for options, need to always allow unselected (empty)
if (type === FieldTypes.OPTIONS && constraints?.inclusion) { if (type === FieldType.OPTIONS && constraints?.inclusion) {
constraints.inclusion.push(null as any, "") constraints.inclusion.push(null as any, "")
} }
let res let res
// Validate.js doesn't seem to handle array // Validate.js doesn't seem to handle array
if (type === FieldTypes.ARRAY && row[fieldName]) { if (type === FieldType.ARRAY && row[fieldName]) {
if (row[fieldName].length) { if (row[fieldName].length) {
if (!Array.isArray(row[fieldName])) { if (!Array.isArray(row[fieldName])) {
row[fieldName] = row[fieldName].split(",") row[fieldName] = row[fieldName].split(",")
@ -116,13 +115,13 @@ export async function validate({
errors[fieldName] = [`${fieldName} is required`] errors[fieldName] = [`${fieldName} is required`]
} }
} else if ( } else if (
(type === FieldTypes.ATTACHMENT || type === FieldTypes.JSON) && (type === FieldType.ATTACHMENT || type === FieldType.JSON) &&
typeof row[fieldName] === "string" typeof row[fieldName] === "string"
) { ) {
// this should only happen if there is an error // this should only happen if there is an error
try { try {
const json = JSON.parse(row[fieldName]) const json = JSON.parse(row[fieldName])
if (type === FieldTypes.ATTACHMENT) { if (type === FieldType.ATTACHMENT) {
if (Array.isArray(json)) { if (Array.isArray(json)) {
row[fieldName] = json row[fieldName] = json
} else { } else {

View file

@ -1,4 +1,5 @@
import { import {
FieldType,
Operation, Operation,
RelationshipType, RelationshipType,
RenameColumn, RenameColumn,
@ -14,7 +15,6 @@ import {
setStaticSchemas, setStaticSchemas,
} from "../../../../api/controllers/table/utils" } from "../../../../api/controllers/table/utils"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { FieldTypes } from "../../../../constants"
import { makeTableRequest } from "../../../../api/controllers/table/ExternalRequest" import { makeTableRequest } from "../../../../api/controllers/table/ExternalRequest"
import { import {
isRelationshipSetup, isRelationshipSetup,
@ -78,7 +78,7 @@ export async function save(
// check if relations need setup // check if relations need setup
for (let schema of Object.values(tableToSave.schema)) { for (let schema of Object.values(tableToSave.schema)) {
if (schema.type !== FieldTypes.LINK || isRelationshipSetup(schema)) { if (schema.type !== FieldType.LINK || isRelationshipSetup(schema)) {
continue continue
} }
const schemaTableId = schema.tableId const schemaTableId = schema.tableId

View file

@ -9,7 +9,6 @@ import {
Table, Table,
TableSourceType, TableSourceType,
} from "@budibase/types" } from "@budibase/types"
import { FieldTypes } from "../../../../constants"
import { import {
foreignKeyStructure, foreignKeyStructure,
generateForeignKey, generateForeignKey,
@ -27,7 +26,7 @@ export function cleanupRelationships(
// clean up relationships in couch table schemas // clean up relationships in couch table schemas
for (let [key, schema] of Object.entries(tableToIterate.schema)) { for (let [key, schema] of Object.entries(tableToIterate.schema)) {
if ( if (
schema.type === FieldTypes.LINK && schema.type === FieldType.LINK &&
(!oldTable || table.schema[key] == null) (!oldTable || table.schema[key] == null)
) { ) {
const schemaTableId = schema.tableId const schemaTableId = schema.tableId

View file

@ -1,4 +1,5 @@
import { import {
FieldType,
RenameColumn, RenameColumn,
Table, Table,
ViewStatisticsSchema, ViewStatisticsSchema,
@ -10,7 +11,6 @@ import {
hasTypeChanged, hasTypeChanged,
TableSaveFunctions, TableSaveFunctions,
} from "../../../../api/controllers/table/utils" } from "../../../../api/controllers/table/utils"
import { FieldTypes } from "../../../../constants"
import { EventType, updateLinks } from "../../../../db/linkedRows" import { EventType, updateLinks } from "../../../../db/linkedRows"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import isEqual from "lodash/isEqual" import isEqual from "lodash/isEqual"
@ -63,7 +63,7 @@ export async function save(
} }
// rename row fields when table column is renamed // rename row fields when table column is renamed
if (renaming && table.schema[renaming.updated].type === FieldTypes.LINK) { if (renaming && table.schema[renaming.updated].type === FieldType.LINK) {
throw new Error("Cannot rename a linked column.") throw new Error("Cannot rename a linked column.")
} }

View file

@ -1,6 +1,12 @@
import { FieldTypes, ObjectStoreBuckets } from "../../constants" import { ObjectStoreBuckets } from "../../constants"
import { context, db as dbCore, objectStore } from "@budibase/backend-core" import { context, db as dbCore, objectStore } from "@budibase/backend-core"
import { RenameColumn, Row, RowAttachment, Table } from "@budibase/types" import {
FieldType,
RenameColumn,
Row,
RowAttachment,
Table,
} from "@budibase/types"
export class AttachmentCleanup { export class AttachmentCleanup {
static async coreCleanup(fileListFn: () => string[]): Promise<void> { static async coreCleanup(fileListFn: () => string[]): Promise<void> {
@ -28,7 +34,7 @@ export class AttachmentCleanup {
let files: string[] = [] let files: string[] = []
const tableSchema = opts.oldTable?.schema || table.schema const tableSchema = opts.oldTable?.schema || table.schema
for (let [key, schema] of Object.entries(tableSchema)) { for (let [key, schema] of Object.entries(tableSchema)) {
if (schema.type !== FieldTypes.ATTACHMENT) { if (schema.type !== FieldType.ATTACHMENT) {
continue continue
} }
const columnRemoved = opts.oldTable && !table.schema[key] const columnRemoved = opts.oldTable && !table.schema[key]
@ -62,7 +68,7 @@ export class AttachmentCleanup {
return AttachmentCleanup.coreCleanup(() => { return AttachmentCleanup.coreCleanup(() => {
let files: string[] = [] let files: string[] = []
for (let [key, schema] of Object.entries(table.schema)) { for (let [key, schema] of Object.entries(table.schema)) {
if (schema.type !== FieldTypes.ATTACHMENT) { if (schema.type !== FieldType.ATTACHMENT) {
continue continue
} }
rows.forEach(row => { rows.forEach(row => {
@ -79,7 +85,7 @@ export class AttachmentCleanup {
return AttachmentCleanup.coreCleanup(() => { return AttachmentCleanup.coreCleanup(() => {
let files: string[] = [] let files: string[] = []
for (let [key, schema] of Object.entries(table.schema)) { for (let [key, schema] of Object.entries(table.schema)) {
if (schema.type !== FieldTypes.ATTACHMENT) { if (schema.type !== FieldType.ATTACHMENT) {
continue continue
} }
const oldKeys = const oldKeys =

View file

@ -1,10 +1,16 @@
import * as linkRows from "../../db/linkedRows" import * as linkRows from "../../db/linkedRows"
import { FieldTypes, AutoFieldSubTypes } from "../../constants"
import { processFormulas, fixAutoColumnSubType } from "./utils" import { processFormulas, fixAutoColumnSubType } from "./utils"
import { objectStore, utils } from "@budibase/backend-core" import { objectStore, utils } from "@budibase/backend-core"
import { InternalTables } from "../../db/utils" import { InternalTables } from "../../db/utils"
import { TYPE_TRANSFORM_MAP } from "./map" import { TYPE_TRANSFORM_MAP } from "./map"
import { FieldSubtype, Row, RowAttachment, Table } from "@budibase/types" import {
FieldType,
AutoFieldSubType,
FieldSubtype,
Row,
RowAttachment,
Table,
} from "@budibase/types"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { import {
processInputBBReferences, processInputBBReferences,
@ -54,25 +60,25 @@ export function processAutoColumn(
schema = fixAutoColumnSubType(schema) schema = fixAutoColumnSubType(schema)
} }
switch (schema.subtype) { switch (schema.subtype) {
case AutoFieldSubTypes.CREATED_BY: case AutoFieldSubType.CREATED_BY:
if (creating && shouldUpdateUserFields && userId) { if (creating && shouldUpdateUserFields && userId) {
row[key] = [userId] row[key] = [userId]
} }
break break
case AutoFieldSubTypes.CREATED_AT: case AutoFieldSubType.CREATED_AT:
if (creating) { if (creating) {
row[key] = now row[key] = now
} }
break break
case AutoFieldSubTypes.UPDATED_BY: case AutoFieldSubType.UPDATED_BY:
if (shouldUpdateUserFields && userId) { if (shouldUpdateUserFields && userId) {
row[key] = [userId] row[key] = [userId]
} }
break break
case AutoFieldSubTypes.UPDATED_AT: case AutoFieldSubType.UPDATED_AT:
row[key] = now row[key] = now
break break
case AutoFieldSubTypes.AUTO_ID: case AutoFieldSubType.AUTO_ID:
if (creating) { if (creating) {
schema.lastID = !schema.lastID ? BASE_AUTO_ID : schema.lastID + 1 schema.lastID = !schema.lastID ? BASE_AUTO_ID : schema.lastID + 1
row[key] = schema.lastID row[key] = schema.lastID
@ -134,7 +140,7 @@ export async function inputProcessing(
continue continue
} }
// remove any formula values, they are to be generated // remove any formula values, they are to be generated
if (field.type === FieldTypes.FORMULA) { if (field.type === FieldType.FORMULA) {
delete clonedRow[key] delete clonedRow[key]
} }
// otherwise coerce what is there to correct types // otherwise coerce what is there to correct types
@ -143,7 +149,7 @@ export async function inputProcessing(
} }
// remove any attachment urls, they are generated on read // remove any attachment urls, they are generated on read
if (field.type === FieldTypes.ATTACHMENT) { if (field.type === FieldType.ATTACHMENT) {
const attachments = clonedRow[key] const attachments = clonedRow[key]
if (attachments?.length) { if (attachments?.length) {
attachments.forEach((attachment: RowAttachment) => { attachments.forEach((attachment: RowAttachment) => {
@ -152,7 +158,7 @@ export async function inputProcessing(
} }
} }
if (field.type === FieldTypes.BB_REFERENCE && value) { if (field.type === FieldType.BB_REFERENCE && value) {
clonedRow[key] = await processInputBBReferences( clonedRow[key] = await processInputBBReferences(
value, value,
field.subtype as FieldSubtype field.subtype as FieldSubtype
@ -214,7 +220,7 @@ export async function outputProcessing<T extends Row[] | Row>(
// process complex types: attachements, bb references... // process complex types: attachements, bb references...
for (let [property, column] of Object.entries(table.schema)) { for (let [property, column] of Object.entries(table.schema)) {
if (column.type === FieldTypes.ATTACHMENT) { if (column.type === FieldType.ATTACHMENT) {
for (let row of enriched) { for (let row of enriched) {
if (row[property] == null || !Array.isArray(row[property])) { if (row[property] == null || !Array.isArray(row[property])) {
continue continue
@ -227,7 +233,7 @@ export async function outputProcessing<T extends Row[] | Row>(
} }
} else if ( } else if (
!opts.skipBBReferences && !opts.skipBBReferences &&
column.type == FieldTypes.BB_REFERENCE column.type == FieldType.BB_REFERENCE
) { ) {
for (let row of enriched) { for (let row of enriched) {
row[property] = await processOutputBBReferences( row[property] = await processOutputBBReferences(

View file

@ -1,7 +1,6 @@
// @ts-nocheck import { FieldType } from "@budibase/types"
import { FieldTypes } from "../../constants"
const parseArrayString = value => { const parseArrayString = (value: any) => {
if (typeof value === "string") { if (typeof value === "string") {
if (value === "") { if (value === "") {
return [] return []
@ -21,11 +20,13 @@ const parseArrayString = value => {
* A map of how we convert various properties in rows to each other based on the row type. * A map of how we convert various properties in rows to each other based on the row type.
*/ */
export const TYPE_TRANSFORM_MAP: any = { export const TYPE_TRANSFORM_MAP: any = {
[FieldTypes.LINK]: { [FieldType.LINK]: {
"": [], "": [],
//@ts-ignore
[null]: [], [null]: [],
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
parse: link => { parse: (link: any) => {
if (Array.isArray(link) && typeof link[0] === "object") { if (Array.isArray(link) && typeof link[0] === "object") {
return link.map(el => (el && el._id ? el._id : el)) return link.map(el => (el && el._id ? el._id : el))
} }
@ -35,75 +36,97 @@ export const TYPE_TRANSFORM_MAP: any = {
return link return link
}, },
}, },
[FieldTypes.OPTIONS]: { [FieldType.OPTIONS]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
}, },
[FieldTypes.ARRAY]: { [FieldType.ARRAY]: {
//@ts-ignore
[null]: [], [null]: [],
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
parse: parseArrayString, parse: parseArrayString,
}, },
[FieldTypes.STRING]: { [FieldType.STRING]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
}, },
[FieldTypes.BARCODEQR]: { [FieldType.BARCODEQR]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
}, },
[FieldTypes.FORMULA]: { [FieldType.FORMULA]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
}, },
[FieldTypes.LONGFORM]: { [FieldType.LONGFORM]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
}, },
[FieldTypes.NUMBER]: { [FieldType.NUMBER]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
parse: n => parseFloat(n), parse: (n: any) => parseFloat(n),
}, },
[FieldTypes.BIGINT]: { [FieldType.BIGINT]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
}, },
[FieldTypes.DATETIME]: { [FieldType.DATETIME]: {
"": null, "": null,
[undefined]: undefined, //@ts-ignore
[null]: null, [null]: null,
parse: date => { //@ts-ignore
[undefined]: undefined,
parse: (date: any) => {
if (date instanceof Date) { if (date instanceof Date) {
return date.toISOString() return date.toISOString()
} }
return date return date
}, },
}, },
[FieldTypes.ATTACHMENT]: { [FieldType.ATTACHMENT]: {
//@ts-ignore
[null]: [], [null]: [],
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
parse: parseArrayString, parse: parseArrayString,
}, },
[FieldTypes.BOOLEAN]: { [FieldType.BOOLEAN]: {
"": null, "": null,
//@ts-ignore
[null]: null, [null]: null,
//@ts-ignore
[undefined]: undefined, [undefined]: undefined,
true: true, true: true,
false: false, false: false,
}, },
[FieldTypes.AUTO]: { [FieldType.AUTO]: {
parse: () => undefined, parse: () => undefined,
}, },
[FieldTypes.JSON]: { [FieldType.JSON]: {
parse: input => { parse: (input: any) => {
try { try {
if (input === "") { if (input === "") {
return undefined return undefined

View file

@ -1,6 +1,11 @@
import { fixAutoColumnSubType } from "../utils" import { fixAutoColumnSubType } from "../utils"
import { AutoFieldDefaultNames, AutoFieldSubTypes } from "../../../constants" import { AutoFieldDefaultNames } from "../../../constants"
import { FieldSchema, FieldType, RelationshipType } from "@budibase/types" import {
AutoFieldSubType,
FieldSchema,
FieldType,
RelationshipType,
} from "@budibase/types"
describe("rowProcessor utility", () => { describe("rowProcessor utility", () => {
describe("fixAutoColumnSubType", () => { describe("fixAutoColumnSubType", () => {
@ -20,37 +25,37 @@ describe("rowProcessor utility", () => {
it("updates the schema with the correct subtype", async () => { it("updates the schema with the correct subtype", async () => {
schema.name = AutoFieldDefaultNames.CREATED_BY schema.name = AutoFieldDefaultNames.CREATED_BY
expect(fixAutoColumnSubType(schema).subtype).toEqual( expect(fixAutoColumnSubType(schema).subtype).toEqual(
AutoFieldSubTypes.CREATED_BY AutoFieldSubType.CREATED_BY
) )
schema.subtype = undefined schema.subtype = undefined
schema.name = AutoFieldDefaultNames.UPDATED_BY schema.name = AutoFieldDefaultNames.UPDATED_BY
expect(fixAutoColumnSubType(schema).subtype).toEqual( expect(fixAutoColumnSubType(schema).subtype).toEqual(
AutoFieldSubTypes.UPDATED_BY AutoFieldSubType.UPDATED_BY
) )
schema.subtype = undefined schema.subtype = undefined
schema.name = AutoFieldDefaultNames.CREATED_AT schema.name = AutoFieldDefaultNames.CREATED_AT
expect(fixAutoColumnSubType(schema).subtype).toEqual( expect(fixAutoColumnSubType(schema).subtype).toEqual(
AutoFieldSubTypes.CREATED_AT AutoFieldSubType.CREATED_AT
) )
schema.subtype = undefined schema.subtype = undefined
schema.name = AutoFieldDefaultNames.UPDATED_AT schema.name = AutoFieldDefaultNames.UPDATED_AT
expect(fixAutoColumnSubType(schema).subtype).toEqual( expect(fixAutoColumnSubType(schema).subtype).toEqual(
AutoFieldSubTypes.UPDATED_AT AutoFieldSubType.UPDATED_AT
) )
schema.subtype = undefined schema.subtype = undefined
schema.name = AutoFieldDefaultNames.AUTO_ID schema.name = AutoFieldDefaultNames.AUTO_ID
expect(fixAutoColumnSubType(schema).subtype).toEqual( expect(fixAutoColumnSubType(schema).subtype).toEqual(
AutoFieldSubTypes.AUTO_ID AutoFieldSubType.AUTO_ID
) )
schema.subtype = undefined schema.subtype = undefined
}) })
it("returns the column if subtype exists", async () => { it("returns the column if subtype exists", async () => {
schema.subtype = AutoFieldSubTypes.CREATED_BY schema.subtype = AutoFieldSubType.CREATED_BY
schema.name = AutoFieldDefaultNames.CREATED_AT schema.name = AutoFieldDefaultNames.CREATED_AT
expect(fixAutoColumnSubType(schema)).toEqual(schema) expect(fixAutoColumnSubType(schema)).toEqual(schema)
}) })

View file

@ -1,15 +1,13 @@
import { import { AutoFieldDefaultNames } from "../../constants"
AutoFieldDefaultNames,
AutoFieldSubTypes,
FieldTypes,
FormulaTypes,
} from "../../constants"
import { processStringSync } from "@budibase/string-templates" import { processStringSync } from "@budibase/string-templates"
import { import {
AutoColumnFieldMetadata, AutoColumnFieldMetadata,
FieldSchema, FieldSchema,
Row, Row,
Table, Table,
FormulaType,
AutoFieldSubType,
FieldType,
} from "@budibase/types" } from "@budibase/types"
import tracer from "dd-trace" import tracer from "dd-trace"
@ -30,15 +28,15 @@ export function fixAutoColumnSubType(
} }
// the columns which get auto generated // the columns which get auto generated
if (column.name.endsWith(AutoFieldDefaultNames.CREATED_BY)) { if (column.name.endsWith(AutoFieldDefaultNames.CREATED_BY)) {
column.subtype = AutoFieldSubTypes.CREATED_BY column.subtype = AutoFieldSubType.CREATED_BY
} else if (column.name.endsWith(AutoFieldDefaultNames.UPDATED_BY)) { } else if (column.name.endsWith(AutoFieldDefaultNames.UPDATED_BY)) {
column.subtype = AutoFieldSubTypes.UPDATED_BY column.subtype = AutoFieldSubType.UPDATED_BY
} else if (column.name.endsWith(AutoFieldDefaultNames.CREATED_AT)) { } else if (column.name.endsWith(AutoFieldDefaultNames.CREATED_AT)) {
column.subtype = AutoFieldSubTypes.CREATED_AT column.subtype = AutoFieldSubType.CREATED_AT
} else if (column.name.endsWith(AutoFieldDefaultNames.UPDATED_AT)) { } else if (column.name.endsWith(AutoFieldDefaultNames.UPDATED_AT)) {
column.subtype = AutoFieldSubTypes.UPDATED_AT column.subtype = AutoFieldSubType.UPDATED_AT
} else if (column.name.endsWith(AutoFieldDefaultNames.AUTO_ID)) { } else if (column.name.endsWith(AutoFieldDefaultNames.AUTO_ID)) {
column.subtype = AutoFieldSubTypes.AUTO_ID column.subtype = AutoFieldSubType.AUTO_ID
} }
return column return column
} }
@ -57,11 +55,11 @@ export function processFormulas<T extends Row | Row[]>(
const rows = Array.isArray(inputRows) ? inputRows : [inputRows] const rows = Array.isArray(inputRows) ? inputRows : [inputRows]
if (rows) { if (rows) {
for (let [column, schema] of Object.entries(table.schema)) { for (let [column, schema] of Object.entries(table.schema)) {
if (schema.type !== FieldTypes.FORMULA) { if (schema.type !== FieldType.FORMULA) {
continue continue
} }
const isStatic = schema.formulaType === FormulaTypes.STATIC const isStatic = schema.formulaType === FormulaType.STATIC
if ( if (
schema.formula == null || schema.formula == null ||
@ -100,7 +98,7 @@ export function processDates<T extends Row | Row[]>(
let rows = Array.isArray(inputRows) ? inputRows : [inputRows] let rows = Array.isArray(inputRows) ? inputRows : [inputRows]
let datesWithTZ: string[] = [] let datesWithTZ: string[] = []
for (let [column, schema] of Object.entries(table.schema)) { for (let [column, schema] of Object.entries(table.schema)) {
if (schema.type !== FieldTypes.DATETIME) { if (schema.type !== FieldType.DATETIME) {
continue continue
} }
if (!schema.timeOnly && !schema.ignoreTimezones) { if (!schema.timeOnly && !schema.ignoreTimezones) {

View file

@ -1,12 +1,11 @@
import { FieldSubtype } from "@budibase/types" import { FieldType, FieldSubtype } from "@budibase/types"
import { FieldTypes } from "../constants"
import { ValidColumnNameRegex, utils } from "@budibase/shared-core" import { ValidColumnNameRegex, utils } from "@budibase/shared-core"
import { db } from "@budibase/backend-core" import { db } from "@budibase/backend-core"
import { parseCsvExport } from "../api/controllers/view/exporters" import { parseCsvExport } from "../api/controllers/view/exporters"
interface SchemaColumn { interface SchemaColumn {
readonly name: string readonly name: string
readonly type: FieldTypes readonly type: FieldType
readonly subtype: FieldSubtype readonly subtype: FieldSubtype
readonly autocolumn?: boolean readonly autocolumn?: boolean
readonly constraints?: { readonly constraints?: {
@ -36,13 +35,13 @@ interface ValidationResults {
} }
const PARSERS: any = { const PARSERS: any = {
[FieldTypes.NUMBER]: (attribute?: string) => { [FieldType.NUMBER]: (attribute?: string) => {
if (!attribute) { if (!attribute) {
return attribute return attribute
} }
return Number(attribute) return Number(attribute)
}, },
[FieldTypes.DATETIME]: (attribute?: string) => { [FieldType.DATETIME]: (attribute?: string) => {
if (!attribute) { if (!attribute) {
return attribute return attribute
} }
@ -60,7 +59,7 @@ export function isSchema(schema: any): schema is Schema {
column !== null && column !== null &&
typeof column === "object" && typeof column === "object" &&
typeof column.type === "string" && typeof column.type === "string" &&
Object.values(FieldTypes).includes(column.type as FieldTypes) Object.values(FieldType).includes(column.type as FieldType)
) )
}) })
) )
@ -110,20 +109,17 @@ export function validate(rows: Rows, schema: Schema): ValidationResults {
isAutoColumn isAutoColumn
) { ) {
return return
} else if ( } else if (columnType === FieldType.NUMBER && isNaN(Number(columnData))) {
columnType === FieldTypes.NUMBER &&
isNaN(Number(columnData))
) {
// If provided must be a valid number // If provided must be a valid number
results.schemaValidation[columnName] = false results.schemaValidation[columnName] = false
} else if ( } else if (
// If provided must be a valid date // If provided must be a valid date
columnType === FieldTypes.DATETIME && columnType === FieldType.DATETIME &&
isNaN(new Date(columnData).getTime()) isNaN(new Date(columnData).getTime())
) { ) {
results.schemaValidation[columnName] = false results.schemaValidation[columnName] = false
} else if ( } else if (
columnType === FieldTypes.BB_REFERENCE && columnType === FieldType.BB_REFERENCE &&
!isValidBBReference(columnData, columnSubtype) !isValidBBReference(columnData, columnSubtype)
) { ) {
results.schemaValidation[columnName] = false results.schemaValidation[columnName] = false
@ -155,15 +151,15 @@ export function parse(rows: Rows, schema: Schema): Rows {
const columnType = schema[columnName].type const columnType = schema[columnName].type
const columnSubtype = schema[columnName].subtype const columnSubtype = schema[columnName].subtype
if (columnType === FieldTypes.NUMBER) { if (columnType === FieldType.NUMBER) {
// If provided must be a valid number // If provided must be a valid number
parsedRow[columnName] = columnData ? Number(columnData) : columnData parsedRow[columnName] = columnData ? Number(columnData) : columnData
} else if (columnType === FieldTypes.DATETIME) { } else if (columnType === FieldType.DATETIME) {
// If provided must be a valid date // If provided must be a valid date
parsedRow[columnName] = columnData parsedRow[columnName] = columnData
? new Date(columnData).toISOString() ? new Date(columnData).toISOString()
: columnData : columnData
} else if (columnType === FieldTypes.BB_REFERENCE) { } else if (columnType === FieldType.BB_REFERENCE) {
const parsedValues = const parsedValues =
!!columnData && parseCsvExport<{ _id: string }[]>(columnData) !!columnData && parseCsvExport<{ _id: string }[]>(columnData)
if (!parsedValues) { if (!parsedValues) {

View file

@ -8,7 +8,7 @@ export enum AutoReason {
FOREIGN_KEY = "foreign_key", FOREIGN_KEY = "foreign_key",
} }
export enum AutoFieldSubTypes { export enum AutoFieldSubType {
CREATED_BY = "createdBy", CREATED_BY = "createdBy",
CREATED_AT = "createdAt", CREATED_AT = "createdAt",
UPDATED_BY = "updatedBy", UPDATED_BY = "updatedBy",
@ -16,7 +16,7 @@ export enum AutoFieldSubTypes {
AUTO_ID = "autoID", AUTO_ID = "autoID",
} }
export enum FormulaTypes { export enum FormulaType {
STATIC = "static", STATIC = "static",
DYNAMIC = "dynamic", DYNAMIC = "dynamic",
} }

View file

@ -2,9 +2,9 @@
// column size, position and whether it can be viewed // column size, position and whether it can be viewed
import { FieldSubtype, FieldType } from "../row" import { FieldSubtype, FieldType } from "../row"
import { import {
AutoFieldSubTypes, AutoFieldSubType,
AutoReason, AutoReason,
FormulaTypes, FormulaType,
RelationshipType, RelationshipType,
} from "./constants" } from "./constants"
@ -22,7 +22,7 @@ interface BaseRelationshipFieldMetadata
fieldName: string fieldName: string
tableId: string tableId: string
tableRev?: string tableRev?: string
subtype?: AutoFieldSubTypes.CREATED_BY | AutoFieldSubTypes.UPDATED_BY subtype?: AutoFieldSubType.CREATED_BY | AutoFieldSubType.UPDATED_BY
} }
// External tables use junction tables, internal tables don't require them // External tables use junction tables, internal tables don't require them
@ -62,7 +62,7 @@ export interface AutoColumnFieldMetadata
extends Omit<BaseFieldSchema, "subtype"> { extends Omit<BaseFieldSchema, "subtype"> {
type: FieldType.AUTO type: FieldType.AUTO
autocolumn: true autocolumn: true
subtype?: AutoFieldSubTypes subtype?: AutoFieldSubType
lastID?: number lastID?: number
// if the column was turned to an auto-column for SQL, explains why (primary, foreign etc) // if the column was turned to an auto-column for SQL, explains why (primary, foreign etc)
autoReason?: AutoReason autoReason?: AutoReason
@ -70,7 +70,7 @@ export interface AutoColumnFieldMetadata
export interface NumberFieldMetadata extends Omit<BaseFieldSchema, "subtype"> { export interface NumberFieldMetadata extends Omit<BaseFieldSchema, "subtype"> {
type: FieldType.NUMBER type: FieldType.NUMBER
subtype?: AutoFieldSubTypes.AUTO_ID subtype?: AutoFieldSubType.AUTO_ID
lastID?: number lastID?: number
autoReason?: AutoReason.FOREIGN_KEY autoReason?: AutoReason.FOREIGN_KEY
// used specifically when Budibase generates external tables, this denotes if a number field // used specifically when Budibase generates external tables, this denotes if a number field
@ -85,7 +85,7 @@ export interface DateFieldMetadata extends Omit<BaseFieldSchema, "subtype"> {
type: FieldType.DATETIME type: FieldType.DATETIME
ignoreTimezones?: boolean ignoreTimezones?: boolean
timeOnly?: boolean timeOnly?: boolean
subtype?: AutoFieldSubTypes.CREATED_AT | AutoFieldSubTypes.UPDATED_AT subtype?: AutoFieldSubType.CREATED_AT | AutoFieldSubType.UPDATED_AT
} }
export interface LongFormFieldMetadata extends BaseFieldSchema { export interface LongFormFieldMetadata extends BaseFieldSchema {
@ -96,7 +96,7 @@ export interface LongFormFieldMetadata extends BaseFieldSchema {
export interface FormulaFieldMetadata extends BaseFieldSchema { export interface FormulaFieldMetadata extends BaseFieldSchema {
type: FieldType.FORMULA type: FieldType.FORMULA
formula: string formula: string
formulaType?: FormulaTypes formulaType?: FormulaType
} }
export interface BBReferenceFieldMetadata export interface BBReferenceFieldMetadata