Handle singleattachment on AttachmentCleanup
This commit is contained in:
parent
28d10ec086
commit
b2ab4e022e
|
@ -25,6 +25,27 @@ export class AttachmentCleanup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static extractAttachmentKeys(
|
||||||
|
type: FieldType,
|
||||||
|
rowData: any
|
||||||
|
): string[] {
|
||||||
|
if (
|
||||||
|
type !== FieldType.ATTACHMENTS &&
|
||||||
|
type !== FieldType.ATTACHMENT_SINGLE
|
||||||
|
) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rowData) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === FieldType.ATTACHMENTS) {
|
||||||
|
return rowData.map((attachment: any) => attachment.key)
|
||||||
|
}
|
||||||
|
return [rowData.key]
|
||||||
|
}
|
||||||
|
|
||||||
private static async tableChange(
|
private static async tableChange(
|
||||||
table: Table,
|
table: Table,
|
||||||
rows: Row[],
|
rows: Row[],
|
||||||
|
@ -34,16 +55,20 @@ 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 !== FieldType.ATTACHMENTS) {
|
if (
|
||||||
|
schema.type !== FieldType.ATTACHMENTS &&
|
||||||
|
schema.type !== FieldType.ATTACHMENT_SINGLE
|
||||||
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnRemoved = opts.oldTable && !table.schema[key]
|
const columnRemoved = opts.oldTable && !table.schema[key]
|
||||||
const renaming = opts.rename?.old === key
|
const renaming = opts.rename?.old === key
|
||||||
// old table had this column, new table doesn't - delete it
|
// old table had this column, new table doesn't - delete it
|
||||||
if ((columnRemoved && !renaming) || opts.deleting) {
|
if ((columnRemoved && !renaming) || opts.deleting) {
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
files = files.concat(
|
files = files.concat(
|
||||||
(row[key] || []).map((attachment: any) => attachment.key)
|
AttachmentCleanup.extractAttachmentKeys(schema.type, row[key])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -68,15 +93,15 @@ 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 !== FieldType.ATTACHMENTS) {
|
if (
|
||||||
|
schema.type !== FieldType.ATTACHMENTS &&
|
||||||
|
schema.type !== FieldType.ATTACHMENT_SINGLE
|
||||||
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
if (!Array.isArray(row[key])) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
files = files.concat(
|
files = files.concat(
|
||||||
row[key].map((attachment: any) => attachment.key)
|
AttachmentCleanup.extractAttachmentKeys(schema.type, row[key])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -88,16 +113,21 @@ 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 !== FieldType.ATTACHMENTS) {
|
if (
|
||||||
|
schema.type !== FieldType.ATTACHMENTS &&
|
||||||
|
schema.type !== FieldType.ATTACHMENT_SINGLE
|
||||||
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const oldKeys =
|
|
||||||
opts.oldRow[key]?.map(
|
const oldKeys = AttachmentCleanup.extractAttachmentKeys(
|
||||||
(attachment: RowAttachment) => attachment.key
|
schema.type,
|
||||||
) || []
|
opts.oldRow[key]
|
||||||
const newKeys =
|
)
|
||||||
opts.row[key]?.map((attachment: RowAttachment) => attachment.key) ||
|
const newKeys = AttachmentCleanup.extractAttachmentKeys(
|
||||||
[]
|
schema.type,
|
||||||
|
opts.row[key]
|
||||||
|
)
|
||||||
files = files.concat(
|
files = files.concat(
|
||||||
oldKeys.filter((key: string) => newKeys.indexOf(key) === -1)
|
oldKeys.filter((key: string) => newKeys.indexOf(key) === -1)
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,23 +25,15 @@ const mockedDeleteFiles = objectStore.deleteFiles as jest.MockedFunction<
|
||||||
typeof objectStore.deleteFiles
|
typeof objectStore.deleteFiles
|
||||||
>
|
>
|
||||||
|
|
||||||
function table(): Table {
|
const rowGenerators: [
|
||||||
return {
|
string,
|
||||||
name: "table",
|
FieldType.ATTACHMENT_SINGLE | FieldType.ATTACHMENTS,
|
||||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
(fileKey?: string) => Row
|
||||||
sourceType: TableSourceType.INTERNAL,
|
][] = [
|
||||||
type: "table",
|
[
|
||||||
schema: {
|
"row with a attachment list column",
|
||||||
attach: {
|
FieldType.ATTACHMENTS,
|
||||||
name: "attach",
|
function rowWithAttachments(fileKey: string = FILE_NAME): Row {
|
||||||
type: FieldType.ATTACHMENTS,
|
|
||||||
constraints: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function row(fileKey: string = FILE_NAME): Row {
|
|
||||||
return {
|
return {
|
||||||
attach: [
|
attach: [
|
||||||
{
|
{
|
||||||
|
@ -51,95 +43,137 @@ function row(fileKey: string = FILE_NAME): Row {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"row with a single attachment column",
|
||||||
|
FieldType.ATTACHMENT_SINGLE,
|
||||||
|
function rowWithAttachments(fileKey: string = FILE_NAME): Row {
|
||||||
|
return {
|
||||||
|
attach: {
|
||||||
|
size: 1,
|
||||||
|
extension: "jpg",
|
||||||
|
key: fileKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
describe.each(rowGenerators)(
|
||||||
|
"attachment cleanup",
|
||||||
|
(_, attachmentFieldType, rowGenerator) => {
|
||||||
|
function tableGenerator(): Table {
|
||||||
|
return {
|
||||||
|
name: "table",
|
||||||
|
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||||
|
sourceType: TableSourceType.INTERNAL,
|
||||||
|
type: "table",
|
||||||
|
schema: {
|
||||||
|
attach: {
|
||||||
|
name: "attach",
|
||||||
|
type: attachmentFieldType,
|
||||||
|
constraints: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe("attachment cleanup", () => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockedDeleteFiles.mockClear()
|
mockedDeleteFiles.mockClear()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to cleanup a table update", async () => {
|
it("should be able to cleanup a table update", async () => {
|
||||||
const originalTable = table()
|
const originalTable = tableGenerator()
|
||||||
delete originalTable.schema["attach"]
|
delete originalTable.schema["attach"]
|
||||||
await AttachmentCleanup.tableUpdate(originalTable, [row()], {
|
await AttachmentCleanup.tableUpdate(originalTable, [rowGenerator()], {
|
||||||
oldTable: table(),
|
oldTable: tableGenerator(),
|
||||||
})
|
})
|
||||||
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to cleanup a table deletion", async () => {
|
it("should be able to cleanup a table deletion", async () => {
|
||||||
await AttachmentCleanup.tableDelete(table(), [row()])
|
await AttachmentCleanup.tableDelete(tableGenerator(), [rowGenerator()])
|
||||||
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle table column renaming", async () => {
|
it("should handle table column renaming", async () => {
|
||||||
const updatedTable = table()
|
const updatedTable = tableGenerator()
|
||||||
updatedTable.schema.attach2 = updatedTable.schema.attach
|
updatedTable.schema.attach2 = updatedTable.schema.attach
|
||||||
delete updatedTable.schema.attach
|
delete updatedTable.schema.attach
|
||||||
await AttachmentCleanup.tableUpdate(updatedTable, [row()], {
|
await AttachmentCleanup.tableUpdate(updatedTable, [rowGenerator()], {
|
||||||
oldTable: table(),
|
oldTable: tableGenerator(),
|
||||||
rename: { old: "attach", updated: "attach2" },
|
rename: { old: "attach", updated: "attach2" },
|
||||||
})
|
})
|
||||||
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("shouldn't cleanup if no table changes", async () => {
|
it("shouldn't cleanup if no table changes", async () => {
|
||||||
await AttachmentCleanup.tableUpdate(table(), [row()], { oldTable: table() })
|
await AttachmentCleanup.tableUpdate(tableGenerator(), [rowGenerator()], {
|
||||||
|
oldTable: tableGenerator(),
|
||||||
|
})
|
||||||
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle row updates", async () => {
|
it("should handle row updates", async () => {
|
||||||
const updatedRow = row()
|
const updatedRow = rowGenerator()
|
||||||
delete updatedRow.attach
|
delete updatedRow.attach
|
||||||
await AttachmentCleanup.rowUpdate(table(), {
|
await AttachmentCleanup.rowUpdate(tableGenerator(), {
|
||||||
row: updatedRow,
|
row: updatedRow,
|
||||||
oldRow: row(),
|
oldRow: rowGenerator(),
|
||||||
})
|
})
|
||||||
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle row deletion", async () => {
|
it("should handle row deletion", async () => {
|
||||||
await AttachmentCleanup.rowDelete(table(), [row()])
|
await AttachmentCleanup.rowDelete(tableGenerator(), [rowGenerator()])
|
||||||
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [FILE_NAME])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle row deletion and not throw when attachments are undefined", async () => {
|
it("should handle row deletion and not throw when attachments are undefined", async () => {
|
||||||
await AttachmentCleanup.rowDelete(table(), [
|
await AttachmentCleanup.rowDelete(tableGenerator(), [
|
||||||
{
|
{
|
||||||
attach: undefined,
|
multipleAttachments: undefined,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("shouldn't cleanup attachments if row not updated", async () => {
|
it("shouldn't cleanup attachments if row not updated", async () => {
|
||||||
await AttachmentCleanup.rowUpdate(table(), { row: row(), oldRow: row() })
|
await AttachmentCleanup.rowUpdate(tableGenerator(), {
|
||||||
|
row: rowGenerator(),
|
||||||
|
oldRow: rowGenerator(),
|
||||||
|
})
|
||||||
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to cleanup a column and not throw when attachments are undefined", async () => {
|
it("should be able to cleanup a column and not throw when attachments are undefined", async () => {
|
||||||
const originalTable = table()
|
const originalTable = tableGenerator()
|
||||||
delete originalTable.schema["attach"]
|
delete originalTable.schema["attach"]
|
||||||
await AttachmentCleanup.tableUpdate(
|
await AttachmentCleanup.tableUpdate(
|
||||||
originalTable,
|
originalTable,
|
||||||
[row("file 1"), { attach: undefined }, row("file 2")],
|
[rowGenerator("file 1"), { attach: undefined }, rowGenerator("file 2")],
|
||||||
{
|
{
|
||||||
oldTable: table(),
|
oldTable: tableGenerator(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(mockedDeleteFiles).toHaveBeenCalledTimes(1)
|
expect(mockedDeleteFiles).toHaveBeenCalledTimes(1)
|
||||||
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, ["file 1", "file 2"])
|
expect(mockedDeleteFiles).toHaveBeenCalledWith(BUCKET, [
|
||||||
|
"file 1",
|
||||||
|
"file 2",
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to cleanup a column and not throw when ALL attachments are undefined", async () => {
|
it("should be able to cleanup a column and not throw when ALL attachments are undefined", async () => {
|
||||||
const originalTable = table()
|
const originalTable = tableGenerator()
|
||||||
delete originalTable.schema["attach"]
|
delete originalTable.schema["attach"]
|
||||||
await AttachmentCleanup.tableUpdate(
|
await AttachmentCleanup.tableUpdate(
|
||||||
originalTable,
|
originalTable,
|
||||||
[{}, { attach: undefined }],
|
[{}, { attach: undefined }],
|
||||||
{
|
{
|
||||||
oldTable: table(),
|
oldTable: tableGenerator(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
expect(mockedDeleteFiles).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue