Merge pull request #3317 from Budibase/feature/switchable-types

Allow switching between string <-> options, number <-> boolean
This commit is contained in:
Michael Drury 2021-11-10 18:18:49 +00:00 committed by GitHub
commit e3358780f4
8 changed files with 75 additions and 6 deletions

View File

@ -18,6 +18,11 @@
FIELDS,
AUTO_COLUMN_SUB_TYPES,
RelationshipTypes,
ALLOWABLE_STRING_OPTIONS,
ALLOWABLE_NUMBER_OPTIONS,
ALLOWABLE_STRING_TYPES,
ALLOWABLE_NUMBER_TYPES,
SWITCHABLE_TYPES,
} from "constants/backend"
import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils"
import { notifications } from "@budibase/bbui"
@ -92,6 +97,9 @@
opt.type === table.type &&
table.sourceId === opt.sourceId
)
$: typeEnabled =
!originalName ||
(originalName && SWITCHABLE_TYPES.indexOf(field.type) !== -1)
async function saveColumn() {
if (field.type === AUTO_TYPE) {
@ -204,7 +212,14 @@
}
function getAllowedTypes() {
if (!external) {
if (originalName && ALLOWABLE_STRING_TYPES.indexOf(field.type) !== -1) {
return ALLOWABLE_STRING_OPTIONS
} else if (
originalName &&
ALLOWABLE_NUMBER_TYPES.indexOf(field.type) !== -1
) {
return ALLOWABLE_NUMBER_OPTIONS
} else if (!external) {
return [
...Object.values(fieldDefinitions),
{ name: "Auto Column", type: AUTO_TYPE },
@ -259,7 +274,7 @@
/>
<Select
disabled={originalName}
disabled={!typeEnabled}
label="Type"
bind:value={field.type}
on:change={handleTypeChange}

View File

@ -138,3 +138,19 @@ export const RelationshipTypes = {
ONE_TO_MANY: "one-to-many",
MANY_TO_ONE: "many-to-one",
}
export const ALLOWABLE_STRING_OPTIONS = [FIELDS.STRING, FIELDS.OPTIONS]
export const ALLOWABLE_STRING_TYPES = ALLOWABLE_STRING_OPTIONS.map(
opt => opt.type
)
export const ALLOWABLE_NUMBER_OPTIONS = [FIELDS.NUMBER, FIELDS.BOOLEAN]
export const ALLOWABLE_NUMBER_TYPES = ALLOWABLE_NUMBER_OPTIONS.map(
opt => opt.type
)
export const SWITCHABLE_TYPES = ALLOWABLE_NUMBER_TYPES.concat(
ALLOWABLE_STRING_TYPES
)

View File

@ -2,6 +2,7 @@ import { writable, get } from "svelte/store"
import { views, queries, datasources } from "./"
import { cloneDeep } from "lodash/fp"
import api from "builderStore/api"
import { SWITCHABLE_TYPES } from "../../constants/backend"
export function createTablesStore() {
const store = writable({})
@ -47,7 +48,11 @@ export function createTablesStore() {
const field = updatedTable.schema[key]
const oldField = oldTable?.schema[key]
// if the type has changed then revert back to the old field
if (oldField != null && oldField?.type !== field.type) {
if (
oldField != null &&
oldField?.type !== field.type &&
SWITCHABLE_TYPES.indexOf(oldField?.type) === -1
) {
updatedTable.schema[key] = oldField
}
// field has been renamed

View File

@ -8,6 +8,7 @@ const {
generateForeignKey,
generateJunctionTableName,
foreignKeyStructure,
hasTypeChanged,
} = require("./utils")
const {
DataSourceOperation,
@ -172,6 +173,10 @@ exports.save = async function (ctx) {
oldTable = await getTable(appId, ctx.request.body._id)
}
if (hasTypeChanged(tableToSave, oldTable)) {
ctx.throw(400, "A column type has changed.")
}
const db = new CouchDB(appId)
const datasource = await db.get(datasourceId)
const oldTables = cloneDeep(datasource.entities)

View File

@ -2,7 +2,7 @@ const CouchDB = require("../../../db")
const linkRows = require("../../../db/linkedRows")
const { getRowParams, generateTableID } = require("../../../db/utils")
const { FieldTypes } = require("../../../constants")
const { TableSaveFunctions } = require("./utils")
const { TableSaveFunctions, hasTypeChanged } = require("./utils")
exports.save = async function (ctx) {
const appId = ctx.appId
@ -21,6 +21,10 @@ exports.save = async function (ctx) {
oldTable = await db.get(ctx.request.body._id)
}
if (hasTypeChanged(tableToSave, oldTable)) {
ctx.throw(400, "A column type has changed.")
}
// saving a table is a complex operation, involving many different steps, this
// has been broken out into a utility to make it more obvious/easier to manipulate
const tableSaveFunctions = new TableSaveFunctions({

View File

@ -8,7 +8,7 @@ const {
const { isEqual } = require("lodash/fp")
const { AutoFieldSubTypes, FieldTypes } = require("../../../constants")
const { inputProcessing } = require("../../../utilities/rowProcessor")
const { USERS_TABLE_SCHEMA } = require("../../../constants")
const { USERS_TABLE_SCHEMA, SwitchableTypes } = require("../../../constants")
const {
isExternalTable,
breakExternalTableId,
@ -335,4 +335,21 @@ exports.foreignKeyStructure = (keyName, meta = null) => {
return structure
}
exports.hasTypeChanged = (table, oldTable) => {
if (!oldTable) {
return false
}
for (let [key, field] of Object.entries(oldTable.schema)) {
const oldType = field.type
if (!table.schema[key]) {
continue
}
const newType = table.schema[key].type
if (oldType !== newType && SwitchableTypes.indexOf(oldType) === -1) {
return true
}
}
return false
}
exports.TableSaveFunctions = TableSaveFunctions

View File

@ -45,6 +45,13 @@ exports.FieldTypes = {
INTERNAL: "internal",
}
exports.SwitchableTypes = [
exports.FieldTypes.STRING,
exports.FieldTypes.OPTIONS,
exports.FieldTypes.NUMBER,
exports.FieldTypes.BOOLEAN,
]
exports.RelationshipTypes = {
ONE_TO_MANY: "one-to-many",
MANY_TO_ONE: "many-to-one",

View File

@ -30,7 +30,7 @@ function generateSchema(
// skip things that are already correct
const oldColumn = oldTable ? oldTable.schema[key] : null
if (
(oldColumn && oldColumn.type === column.type) ||
(oldColumn && oldColumn.type) ||
(primaryKey === key && !isJunction)
) {
continue