fix: delete unused attachments by using filter

This commit is contained in:
Johnny 2026-01-05 22:43:57 +08:00
parent 4b110d0d38
commit d68ca84832
4 changed files with 36 additions and 4 deletions

View File

@ -207,6 +207,17 @@ func (r *renderer) renderScalarComparison(field Field, op ComparisonOperator, ri
}
columnExpr := field.columnExpr(r.dialect)
if lit == nil {
switch op {
case CompareEq:
return renderResult{sql: fmt.Sprintf("%s IS NULL", columnExpr)}, nil
case CompareNeq:
return renderResult{sql: fmt.Sprintf("%s IS NOT NULL", columnExpr)}, nil
default:
return renderResult{}, errors.Errorf("operator %s not supported for null comparison", op)
}
}
placeholder := ""
switch field.Type {
case FieldTypeString:

View File

@ -297,7 +297,7 @@ func NewAttachmentSchema() Schema {
cel.Variable("filename", cel.StringType),
cel.Variable("mime_type", cel.StringType),
cel.Variable("create_time", cel.IntType),
cel.Variable("memo_id", cel.IntType),
cel.Variable("memo_id", cel.AnyType),
nowFunction,
}

View File

@ -328,9 +328,18 @@ func TestAttachmentFilterNullMemoId(t *testing.T) {
tc.CreateAttachment(NewAttachmentBuilder(tc.CreatorID).Filename("with_memo.png").MimeType("image/png").MemoID(&memo.ID))
tc.CreateAttachment(NewAttachmentBuilder(tc.CreatorID).Filename("no_memo.png").MimeType("image/png"))
attachments := tc.ListWithFilter(`memo_id == ` + formatInt32(memo.ID))
// Test: memo_id == null
attachments := tc.ListWithFilter(`memo_id == null`)
require.Len(t, attachments, 1)
require.Equal(t, "no_memo.png", attachments[0].Filename)
require.Nil(t, attachments[0].MemoID)
// Test: memo_id != null
attachments = tc.ListWithFilter(`memo_id != null`)
require.Len(t, attachments, 1)
require.Equal(t, "with_memo.png", attachments[0].Filename)
require.NotNil(t, attachments[0].MemoID)
require.Equal(t, memo.ID, *attachments[0].MemoID)
}
func TestAttachmentFilterEmptyFilename(t *testing.T) {

View File

@ -156,7 +156,19 @@ const Attachments = () => {
// Delete all unused attachments
const handleDeleteUnusedAttachments = useCallback(async () => {
try {
await Promise.all(unusedAttachments.map((attachment) => deleteAttachment(attachment.name)));
let allUnusedAttachments: Attachment[] = [];
let nextPageToken = "";
do {
const response = await attachmentServiceClient.listAttachments({
pageSize: 1000,
pageToken: nextPageToken,
filter: "memo_id == null",
});
allUnusedAttachments = [...allUnusedAttachments, ...response.attachments];
nextPageToken = response.nextPageToken;
} while (nextPageToken);
await Promise.all(allUnusedAttachments.map((attachment) => deleteAttachment(attachment.name)));
toast.success(t("resource.delete-all-unused-success"));
} catch (error) {
handleError(error, toast.error, {
@ -166,7 +178,7 @@ const Attachments = () => {
} finally {
await handleRefetch();
}
}, [unusedAttachments, t, handleRefetch, deleteAttachment]);
}, [t, handleRefetch, deleteAttachment]);
// Handle search input change
const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {