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

View File

@ -138,3 +138,19 @@ export const RelationshipTypes = {
ONE_TO_MANY: "one-to-many", ONE_TO_MANY: "one-to-many",
MANY_TO_ONE: "many-to-one", 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 { views, queries, datasources } from "./"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import api from "builderStore/api" import api from "builderStore/api"
import { SWITCHABLE_TYPES } from "../../constants/backend"
export function createTablesStore() { export function createTablesStore() {
const store = writable({}) const store = writable({})
@ -47,7 +48,11 @@ export function createTablesStore() {
const field = updatedTable.schema[key] const field = updatedTable.schema[key]
const oldField = oldTable?.schema[key] const oldField = oldTable?.schema[key]
// if the type has changed then revert back to the old field // 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 updatedTable.schema[key] = oldField
} }
// field has been renamed // field has been renamed

View File

@ -8,6 +8,7 @@ const {
generateForeignKey, generateForeignKey,
generateJunctionTableName, generateJunctionTableName,
foreignKeyStructure, foreignKeyStructure,
hasTypeChanged,
} = require("./utils") } = require("./utils")
const { const {
DataSourceOperation, DataSourceOperation,
@ -172,6 +173,10 @@ exports.save = async function (ctx) {
oldTable = await getTable(appId, ctx.request.body._id) 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 db = new CouchDB(appId)
const datasource = await db.get(datasourceId) const datasource = await db.get(datasourceId)
const oldTables = cloneDeep(datasource.entities) const oldTables = cloneDeep(datasource.entities)

View File

@ -2,7 +2,7 @@ const CouchDB = require("../../../db")
const linkRows = require("../../../db/linkedRows") const linkRows = require("../../../db/linkedRows")
const { getRowParams, generateTableID } = require("../../../db/utils") const { getRowParams, generateTableID } = require("../../../db/utils")
const { FieldTypes } = require("../../../constants") const { FieldTypes } = require("../../../constants")
const { TableSaveFunctions } = require("./utils") const { TableSaveFunctions, hasTypeChanged } = require("./utils")
exports.save = async function (ctx) { exports.save = async function (ctx) {
const appId = ctx.appId const appId = ctx.appId
@ -21,6 +21,10 @@ exports.save = async function (ctx) {
oldTable = await db.get(ctx.request.body._id) 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 // 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 // has been broken out into a utility to make it more obvious/easier to manipulate
const tableSaveFunctions = new TableSaveFunctions({ const tableSaveFunctions = new TableSaveFunctions({

View File

@ -8,7 +8,7 @@ const {
const { isEqual } = require("lodash/fp") const { isEqual } = require("lodash/fp")
const { AutoFieldSubTypes, FieldTypes } = require("../../../constants") const { AutoFieldSubTypes, FieldTypes } = require("../../../constants")
const { inputProcessing } = require("../../../utilities/rowProcessor") const { inputProcessing } = require("../../../utilities/rowProcessor")
const { USERS_TABLE_SCHEMA } = require("../../../constants") const { USERS_TABLE_SCHEMA, SwitchableTypes } = require("../../../constants")
const { const {
isExternalTable, isExternalTable,
breakExternalTableId, breakExternalTableId,
@ -335,4 +335,21 @@ exports.foreignKeyStructure = (keyName, meta = null) => {
return structure 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 exports.TableSaveFunctions = TableSaveFunctions

View File

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

View File

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