Fix table updates wiping out view calculation fields.
This commit is contained in:
parent
4c0bd812c1
commit
28c22e9aa7
|
@ -1904,6 +1904,59 @@ describe.each([
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("calculation views", () => {
|
||||||
|
it("should not remove calculation columns when modifying table schema", async () => {
|
||||||
|
let table = await config.api.table.save(
|
||||||
|
saveTableRequest({
|
||||||
|
schema: {
|
||||||
|
name: {
|
||||||
|
name: "name",
|
||||||
|
type: FieldType.STRING,
|
||||||
|
},
|
||||||
|
age: {
|
||||||
|
name: "age",
|
||||||
|
type: FieldType.NUMBER,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
let view = await config.api.viewV2.create({
|
||||||
|
tableId: table._id!,
|
||||||
|
name: generator.guid(),
|
||||||
|
type: ViewV2Type.CALCULATION,
|
||||||
|
schema: {
|
||||||
|
sum: {
|
||||||
|
visible: true,
|
||||||
|
calculationType: CalculationType.SUM,
|
||||||
|
field: "age",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
table = await config.api.table.get(table._id!)
|
||||||
|
await config.api.table.save({
|
||||||
|
...table,
|
||||||
|
schema: {
|
||||||
|
...table.schema,
|
||||||
|
name: {
|
||||||
|
name: "name",
|
||||||
|
type: FieldType.STRING,
|
||||||
|
constraints: { presence: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
view = await config.api.viewV2.get(view.id)
|
||||||
|
expect(Object.keys(view.schema!).sort()).toEqual([
|
||||||
|
"age",
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"sum",
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("row operations", () => {
|
describe("row operations", () => {
|
||||||
|
|
|
@ -20,29 +20,28 @@ const OPTIONAL_NUMBER = Joi.number().optional().allow(null)
|
||||||
const OPTIONAL_BOOLEAN = Joi.boolean().optional().allow(null)
|
const OPTIONAL_BOOLEAN = Joi.boolean().optional().allow(null)
|
||||||
const APP_NAME_REGEX = /^[\w\s]+$/
|
const APP_NAME_REGEX = /^[\w\s]+$/
|
||||||
|
|
||||||
const validateViewSchemas: CustomValidator<Table> = (table, helpers) => {
|
const validateViewSchemas: CustomValidator<Table> = (table, joiHelpers) => {
|
||||||
if (table.views && Object.entries(table.views).length) {
|
if (!table.views || Object.keys(table.views).length === 0) {
|
||||||
const requiredFields = Object.entries(table.schema)
|
return table
|
||||||
.filter(([_, v]) => isRequired(v.constraints))
|
}
|
||||||
|
const required = Object.keys(table.schema).filter(key =>
|
||||||
|
isRequired(table.schema[key].constraints)
|
||||||
|
)
|
||||||
|
if (required.length === 0) {
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
for (const view of Object.values(table.views)) {
|
||||||
|
if (!sdk.views.isV2(view) || helpers.views.isCalculationView(view)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const editable = Object.entries(view.schema || {})
|
||||||
|
.filter(([_, f]) => f.visible && !f.readonly)
|
||||||
.map(([key]) => key)
|
.map(([key]) => key)
|
||||||
if (requiredFields.length) {
|
const missingField = required.find(f => !editable.includes(f))
|
||||||
for (const view of Object.values(table.views)) {
|
if (missingField) {
|
||||||
if (!sdk.views.isV2(view)) {
|
return joiHelpers.message({
|
||||||
continue
|
custom: `To make field "${missingField}" required, this field must be present and writable in views: ${view.name}.`,
|
||||||
}
|
})
|
||||||
|
|
||||||
const editableViewFields = Object.entries(view.schema || {})
|
|
||||||
.filter(([_, f]) => f.visible && !f.readonly)
|
|
||||||
.map(([key]) => key)
|
|
||||||
const missingField = requiredFields.find(
|
|
||||||
f => !editableViewFields.includes(f)
|
|
||||||
)
|
|
||||||
if (missingField) {
|
|
||||||
return helpers.message({
|
|
||||||
custom: `To make field "${missingField}" required, this field must be present and writable in views: ${view.name}.`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return table
|
return table
|
||||||
|
|
|
@ -96,6 +96,13 @@ async function guardCalculationViewSchema(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!schema.field) {
|
||||||
|
throw new HTTPError(
|
||||||
|
`Calculation field "${name}" is missing a "field" property`,
|
||||||
|
400
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const targetSchema = table.schema[schema.field]
|
const targetSchema = table.schema[schema.field]
|
||||||
if (!targetSchema) {
|
if (!targetSchema) {
|
||||||
throw new HTTPError(
|
throw new HTTPError(
|
||||||
|
@ -371,7 +378,8 @@ export function syncSchema(
|
||||||
|
|
||||||
if (view.schema) {
|
if (view.schema) {
|
||||||
for (const fieldName of Object.keys(view.schema)) {
|
for (const fieldName of Object.keys(view.schema)) {
|
||||||
if (!schema[fieldName]) {
|
const viewSchema = view.schema[fieldName]
|
||||||
|
if (!helpers.views.isCalculationField(viewSchema) && !schema[fieldName]) {
|
||||||
delete view.schema[fieldName]
|
delete view.schema[fieldName]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue