Improve and fix test
This commit is contained in:
parent
1732e14353
commit
1685568089
|
@ -5,10 +5,11 @@ import { context, events } from "@budibase/backend-core"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
|
|
||||||
import tk from "timekeeper"
|
import tk from "timekeeper"
|
||||||
import { generator, mocks } from "@budibase/backend-core/tests"
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
import {
|
import {
|
||||||
Datasource,
|
Datasource,
|
||||||
FieldSchema,
|
FieldSchema,
|
||||||
|
FieldSubtype,
|
||||||
FieldType,
|
FieldType,
|
||||||
QueryPreview,
|
QueryPreview,
|
||||||
RelationshipType,
|
RelationshipType,
|
||||||
|
@ -250,7 +251,7 @@ describe("/datasources", () => {
|
||||||
|
|
||||||
const simpleTable = await config.api.table.save(
|
const simpleTable = await config.api.table.save(
|
||||||
tableForDatasource(datasource, {
|
tableForDatasource(datasource, {
|
||||||
name: generator.guid(),
|
name: "simple",
|
||||||
schema: {
|
schema: {
|
||||||
name: {
|
name: {
|
||||||
name: "name",
|
name: "name",
|
||||||
|
@ -259,86 +260,82 @@ describe("/datasources", () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const fullSchema: { [type in FieldType]: FieldSchema & { type: type } } =
|
|
||||||
{
|
|
||||||
[FieldType.STRING]: {
|
|
||||||
name: "string",
|
|
||||||
type: FieldType.STRING,
|
|
||||||
},
|
|
||||||
// [FieldType.LONGFORM]: {
|
|
||||||
// name: "longform",
|
|
||||||
// type: FieldType.LONGFORM,
|
|
||||||
// },
|
|
||||||
// [FieldType.OPTIONS]: {
|
|
||||||
// name: "options",
|
|
||||||
// type: FieldType.OPTIONS,
|
|
||||||
// },
|
|
||||||
[FieldType.NUMBER]: {
|
|
||||||
name: "number",
|
|
||||||
type: FieldType.NUMBER,
|
|
||||||
},
|
|
||||||
[FieldType.BOOLEAN]: {
|
|
||||||
name: "boolean",
|
|
||||||
type: FieldType.BOOLEAN,
|
|
||||||
},
|
|
||||||
// [FieldType.ARRAY]: {
|
|
||||||
// name: "array",
|
|
||||||
// type: FieldType.ARRAY,
|
|
||||||
// },
|
|
||||||
[FieldType.DATETIME]: {
|
|
||||||
name: "datetime",
|
|
||||||
type: FieldType.DATETIME,
|
|
||||||
},
|
|
||||||
// [FieldType.ATTACHMENTS]: {
|
|
||||||
// name: "attachments",
|
|
||||||
// type: FieldType.ATTACHMENTS,
|
|
||||||
// },
|
|
||||||
// [FieldType.ATTACHMENT_SINGLE]: {
|
|
||||||
// name: "attachment_single",
|
|
||||||
// type: FieldType.ATTACHMENT_SINGLE,
|
|
||||||
// },
|
|
||||||
// [FieldType.LINK]: {
|
|
||||||
// name: "link",
|
|
||||||
// type: FieldType.LINK,
|
|
||||||
// tableId: simpleTable._id!,
|
|
||||||
// relationshipType: RelationshipType.ONE_TO_MANY,
|
|
||||||
// fieldName: "link",
|
|
||||||
// foreignKey: "fk",
|
|
||||||
// },
|
|
||||||
// [FieldType.FORMULA]: {
|
|
||||||
// name: "formula",
|
|
||||||
// type: FieldType.FORMULA,
|
|
||||||
// formula: "any formula",
|
|
||||||
// },
|
|
||||||
// [FieldType.AUTO]: {
|
|
||||||
// name: "auto",
|
|
||||||
// type: FieldType.AUTO,
|
|
||||||
// },
|
|
||||||
// [FieldType.JSON]: {
|
|
||||||
// name: "json",
|
|
||||||
// type: FieldType.JSON,
|
|
||||||
// },
|
|
||||||
// [FieldType.INTERNAL]: {
|
|
||||||
// name: "internal",
|
|
||||||
// type: FieldType.INTERNAL,
|
|
||||||
// },
|
|
||||||
[FieldType.BARCODEQR]: {
|
|
||||||
name: "barcodeqr",
|
|
||||||
type: FieldType.BARCODEQR,
|
|
||||||
},
|
|
||||||
// [FieldType.BIGINT]: {
|
|
||||||
// name: "bigint",
|
|
||||||
// type: FieldType.BIGINT,
|
|
||||||
// },
|
|
||||||
// [FieldType.BB_REFERENCE]: {
|
|
||||||
// name: "bb_reference",
|
|
||||||
// type: FieldType.BB_REFERENCE,
|
|
||||||
// },
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullTable = await config.api.table.save(
|
type SupportedTypes =
|
||||||
|
| FieldType.STRING
|
||||||
|
| FieldType.BARCODEQR
|
||||||
|
| FieldType.LONGFORM
|
||||||
|
| FieldType.OPTIONS
|
||||||
|
| FieldType.DATETIME
|
||||||
|
| FieldType.NUMBER
|
||||||
|
| FieldType.BOOLEAN
|
||||||
|
| FieldType.FORMULA
|
||||||
|
| FieldType.BIGINT
|
||||||
|
| FieldType.BB_REFERENCE
|
||||||
|
| FieldType.LINK
|
||||||
|
| FieldType.ARRAY
|
||||||
|
|
||||||
|
const fullSchema: {
|
||||||
|
[type in SupportedTypes]: FieldSchema & { type: type }
|
||||||
|
} = {
|
||||||
|
[FieldType.STRING]: {
|
||||||
|
name: "string",
|
||||||
|
type: FieldType.STRING,
|
||||||
|
},
|
||||||
|
[FieldType.LONGFORM]: {
|
||||||
|
name: "longform",
|
||||||
|
type: FieldType.LONGFORM,
|
||||||
|
},
|
||||||
|
[FieldType.OPTIONS]: {
|
||||||
|
name: "options",
|
||||||
|
type: FieldType.OPTIONS,
|
||||||
|
},
|
||||||
|
[FieldType.NUMBER]: {
|
||||||
|
name: "number",
|
||||||
|
type: FieldType.NUMBER,
|
||||||
|
},
|
||||||
|
[FieldType.BOOLEAN]: {
|
||||||
|
name: "boolean",
|
||||||
|
type: FieldType.BOOLEAN,
|
||||||
|
},
|
||||||
|
[FieldType.ARRAY]: {
|
||||||
|
name: "array",
|
||||||
|
type: FieldType.ARRAY,
|
||||||
|
},
|
||||||
|
[FieldType.DATETIME]: {
|
||||||
|
name: "datetime",
|
||||||
|
type: FieldType.DATETIME,
|
||||||
|
},
|
||||||
|
[FieldType.LINK]: {
|
||||||
|
name: "link",
|
||||||
|
type: FieldType.LINK,
|
||||||
|
tableId: simpleTable._id!,
|
||||||
|
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||||
|
fieldName: "link",
|
||||||
|
},
|
||||||
|
[FieldType.FORMULA]: {
|
||||||
|
name: "formula",
|
||||||
|
type: FieldType.FORMULA,
|
||||||
|
formula: "any formula",
|
||||||
|
},
|
||||||
|
[FieldType.BARCODEQR]: {
|
||||||
|
name: "barcodeqr",
|
||||||
|
type: FieldType.BARCODEQR,
|
||||||
|
},
|
||||||
|
[FieldType.BIGINT]: {
|
||||||
|
name: "bigint",
|
||||||
|
type: FieldType.BIGINT,
|
||||||
|
},
|
||||||
|
[FieldType.BB_REFERENCE]: {
|
||||||
|
name: "bb_reference",
|
||||||
|
type: FieldType.BB_REFERENCE,
|
||||||
|
subtype: FieldSubtype.USERS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
await config.api.table.save(
|
||||||
tableForDatasource(datasource, {
|
tableForDatasource(datasource, {
|
||||||
name: generator.guid(),
|
name: "full",
|
||||||
schema: fullSchema,
|
schema: fullSchema,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -362,9 +359,6 @@ describe("/datasources", () => {
|
||||||
(acc, [fieldName, field]) => {
|
(acc, [fieldName, field]) => {
|
||||||
acc[fieldName] = expect.objectContaining({
|
acc[fieldName] = expect.objectContaining({
|
||||||
...field,
|
...field,
|
||||||
externalType: expect.not.stringMatching(
|
|
||||||
new RegExp(`^${field.externalType || ""}$`)
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
return acc
|
return acc
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,7 +15,28 @@ const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
||||||
const ROW_ID_REGEX = /^\[.*]$/g
|
const ROW_ID_REGEX = /^\[.*]$/g
|
||||||
const ENCODED_SPACE = encodeURIComponent(" ")
|
const ENCODED_SPACE = encodeURIComponent(" ")
|
||||||
|
|
||||||
const SQL_NUMBER_TYPE_MAP = {
|
type PrimitiveTypes =
|
||||||
|
| FieldType.STRING
|
||||||
|
| FieldType.NUMBER
|
||||||
|
| FieldType.BOOLEAN
|
||||||
|
| FieldType.DATETIME
|
||||||
|
| FieldType.JSON
|
||||||
|
| FieldType.BIGINT
|
||||||
|
| FieldType.OPTIONS
|
||||||
|
|
||||||
|
function isPrimitiveType(type: FieldType): type is PrimitiveTypes {
|
||||||
|
return [
|
||||||
|
FieldType.STRING,
|
||||||
|
FieldType.NUMBER,
|
||||||
|
FieldType.BOOLEAN,
|
||||||
|
FieldType.DATETIME,
|
||||||
|
FieldType.JSON,
|
||||||
|
FieldType.BIGINT,
|
||||||
|
FieldType.OPTIONS,
|
||||||
|
].includes(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const SQL_NUMBER_TYPE_MAP: Record<string, PrimitiveTypes> = {
|
||||||
integer: FieldType.NUMBER,
|
integer: FieldType.NUMBER,
|
||||||
int: FieldType.NUMBER,
|
int: FieldType.NUMBER,
|
||||||
decimal: FieldType.NUMBER,
|
decimal: FieldType.NUMBER,
|
||||||
|
@ -35,7 +56,7 @@ const SQL_NUMBER_TYPE_MAP = {
|
||||||
smallmoney: FieldType.NUMBER,
|
smallmoney: FieldType.NUMBER,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SQL_DATE_TYPE_MAP = {
|
const SQL_DATE_TYPE_MAP: Record<string, PrimitiveTypes> = {
|
||||||
timestamp: FieldType.DATETIME,
|
timestamp: FieldType.DATETIME,
|
||||||
time: FieldType.DATETIME,
|
time: FieldType.DATETIME,
|
||||||
datetime: FieldType.DATETIME,
|
datetime: FieldType.DATETIME,
|
||||||
|
@ -46,7 +67,7 @@ const SQL_DATE_TYPE_MAP = {
|
||||||
const SQL_DATE_ONLY_TYPES = ["date"]
|
const SQL_DATE_ONLY_TYPES = ["date"]
|
||||||
const SQL_TIME_ONLY_TYPES = ["time"]
|
const SQL_TIME_ONLY_TYPES = ["time"]
|
||||||
|
|
||||||
const SQL_STRING_TYPE_MAP = {
|
const SQL_STRING_TYPE_MAP: Record<string, PrimitiveTypes> = {
|
||||||
varchar: FieldType.STRING,
|
varchar: FieldType.STRING,
|
||||||
char: FieldType.STRING,
|
char: FieldType.STRING,
|
||||||
nchar: FieldType.STRING,
|
nchar: FieldType.STRING,
|
||||||
|
@ -58,22 +79,22 @@ const SQL_STRING_TYPE_MAP = {
|
||||||
text: FieldType.STRING,
|
text: FieldType.STRING,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SQL_BOOLEAN_TYPE_MAP = {
|
const SQL_BOOLEAN_TYPE_MAP: Record<string, PrimitiveTypes> = {
|
||||||
boolean: FieldType.BOOLEAN,
|
boolean: FieldType.BOOLEAN,
|
||||||
bit: FieldType.BOOLEAN,
|
bit: FieldType.BOOLEAN,
|
||||||
tinyint: FieldType.BOOLEAN,
|
tinyint: FieldType.BOOLEAN,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SQL_OPTIONS_TYPE_MAP = {
|
const SQL_OPTIONS_TYPE_MAP: Record<string, PrimitiveTypes> = {
|
||||||
"user-defined": FieldType.OPTIONS,
|
"user-defined": FieldType.OPTIONS,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SQL_MISC_TYPE_MAP = {
|
const SQL_MISC_TYPE_MAP: Record<string, PrimitiveTypes> = {
|
||||||
json: FieldType.JSON,
|
json: FieldType.JSON,
|
||||||
bigint: FieldType.BIGINT,
|
bigint: FieldType.BIGINT,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SQL_TYPE_MAP = {
|
const SQL_TYPE_MAP: Record<string, PrimitiveTypes> = {
|
||||||
...SQL_NUMBER_TYPE_MAP,
|
...SQL_NUMBER_TYPE_MAP,
|
||||||
...SQL_DATE_TYPE_MAP,
|
...SQL_DATE_TYPE_MAP,
|
||||||
...SQL_STRING_TYPE_MAP,
|
...SQL_STRING_TYPE_MAP,
|
||||||
|
@ -317,6 +338,80 @@ function shouldCopySpecialColumn(
|
||||||
return fetchedIsNumber && column.type === FieldType.BOOLEAN
|
return fetchedIsNumber && column.type === FieldType.BOOLEAN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CopyAction {
|
||||||
|
ALWAYS_KEEP = "alwaysKeep",
|
||||||
|
COPY_IF_TYPE = "copyIfType",
|
||||||
|
}
|
||||||
|
|
||||||
|
SQL_TYPE_MAP
|
||||||
|
|
||||||
|
const SqlCopyTypeByFieldMapping: Record<
|
||||||
|
FieldType,
|
||||||
|
| { action: CopyAction.ALWAYS_KEEP }
|
||||||
|
| { action: CopyAction.COPY_IF_TYPE; types: PrimitiveTypes[] }
|
||||||
|
> = {
|
||||||
|
[FieldType.LINK]: { action: CopyAction.ALWAYS_KEEP },
|
||||||
|
[FieldType.FORMULA]: { action: CopyAction.ALWAYS_KEEP },
|
||||||
|
[FieldType.STRING]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.OPTIONS]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.LONGFORM]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.NUMBER]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.BOOLEAN, FieldType.NUMBER],
|
||||||
|
},
|
||||||
|
[FieldType.BOOLEAN]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.BOOLEAN, FieldType.NUMBER],
|
||||||
|
},
|
||||||
|
[FieldType.ARRAY]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.JSON, FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.DATETIME]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.DATETIME, FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.ATTACHMENTS]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.JSON, FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.ATTACHMENT_SINGLE]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.JSON, FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.AUTO]: {
|
||||||
|
action: CopyAction.ALWAYS_KEEP,
|
||||||
|
},
|
||||||
|
[FieldType.JSON]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.JSON, FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.INTERNAL]: {
|
||||||
|
action: CopyAction.ALWAYS_KEEP,
|
||||||
|
},
|
||||||
|
[FieldType.BARCODEQR]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.STRING],
|
||||||
|
},
|
||||||
|
[FieldType.BIGINT]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.BIGINT, FieldType.NUMBER],
|
||||||
|
},
|
||||||
|
[FieldType.BB_REFERENCE]: {
|
||||||
|
action: CopyAction.COPY_IF_TYPE,
|
||||||
|
types: [FieldType.JSON, FieldType.STRING],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for columns which need to be copied over into the new table definitions, like relationships,
|
* Looks for columns which need to be copied over into the new table definitions, like relationships,
|
||||||
* options types and views.
|
* options types and views.
|
||||||
|
@ -338,6 +433,9 @@ function copyExistingPropsOver(
|
||||||
if (entities[tableName]?.created) {
|
if (entities[tableName]?.created) {
|
||||||
table.created = entities[tableName]?.created
|
table.created = entities[tableName]?.created
|
||||||
}
|
}
|
||||||
|
if (entities[tableName]?.constrained) {
|
||||||
|
table.constrained = entities[tableName]?.constrained
|
||||||
|
}
|
||||||
|
|
||||||
table.views = entities[tableName].views
|
table.views = entities[tableName].views
|
||||||
|
|
||||||
|
@ -351,41 +449,23 @@ function copyExistingPropsOver(
|
||||||
const existingColumnType = column?.type
|
const existingColumnType = column?.type
|
||||||
const updatedColumnType = table.schema[key]?.type
|
const updatedColumnType = table.schema[key]?.type
|
||||||
|
|
||||||
// If the db column type changed to a non-compatible one, we want to re-fetch it
|
const map = SqlCopyTypeByFieldMapping[existingColumnType]
|
||||||
if (
|
|
||||||
updatedColumnType &&
|
let keepExistingSchema = map.action === CopyAction.ALWAYS_KEEP
|
||||||
updatedColumnType !== existingColumnType &&
|
if (map.action === CopyAction.COPY_IF_TYPE) {
|
||||||
!SWITCHABLE_TYPES[updatedColumnType]?.includes(existingColumnType)
|
keepExistingSchema =
|
||||||
) {
|
isPrimitiveType(updatedColumnType) &&
|
||||||
continue
|
table.schema[key] &&
|
||||||
|
map.types?.includes(updatedColumnType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (keepExistingSchema) {
|
||||||
column.type === FieldType.LINK &&
|
table.schema[key] = {
|
||||||
!shouldCopyRelationship(column, tableIds)
|
...existingTableSchema[key],
|
||||||
) {
|
externalType:
|
||||||
continue
|
existingTableSchema[key].externalType ||
|
||||||
}
|
table.schema[key]?.externalType,
|
||||||
|
}
|
||||||
const specialTypes = [
|
|
||||||
FieldType.OPTIONS,
|
|
||||||
FieldType.LONGFORM,
|
|
||||||
FieldType.ARRAY,
|
|
||||||
FieldType.FORMULA,
|
|
||||||
FieldType.BB_REFERENCE,
|
|
||||||
]
|
|
||||||
if (
|
|
||||||
specialTypes.includes(column.type) &&
|
|
||||||
!shouldCopySpecialColumn(column, table.schema[key])
|
|
||||||
) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
table.schema[key] = {
|
|
||||||
...existingTableSchema[key],
|
|
||||||
externalType:
|
|
||||||
existingTableSchema[key].externalType ||
|
|
||||||
table.schema[key]?.externalType,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue