Skip to content

feat: implement soft-delete of extensions#1866

Open
gnugomez wants to merge 6 commits into
eclipse-openvsx:mainfrom
gnugomez:gnugomez/main/soft-delete-extensions
Open

feat: implement soft-delete of extensions#1866
gnugomez wants to merge 6 commits into
eclipse-openvsx:mainfrom
gnugomez:gnugomez/main/soft-delete-extensions

Conversation

@gnugomez

Copy link
Copy Markdown
Member

Right now every time an extension version gets deleted we don't preserve a record in the database, we instead hard-delete it. This way we can keep track of it properly.

This PR is a follow-up of #1859

@gnugomez gnugomez force-pushed the gnugomez/main/soft-delete-extensions branch from 0cc6c78 to 699014a Compare June 17, 2026 09:20
gnugomez added 6 commits June 17, 2026 11:30
Adds an explicit lifecycle state to ExtensionVersion (ACTIVE/INACTIVE/DELETED)
alongside a lastUpdated timestamp. Backing migration V1_69 backfills the new
columns from the existing active flag and current timestamp. State and
lastUpdated form the foundation for soft-deleting extension versions.
Reads isActive() from state == ACTIVE and routes setActive() through
setState(), keeping the persisted active column in sync as a mirror. This
makes State the single source of truth so soft-delete (State.DELETED) can
participate in the same get/set contract without breaking active-based
queries.
Extracts baseExtensionVersionQuery() so all extension-version selects (full,
latest-by-platform, and the remaining standalone selects) project the new
state/active/lastUpdated columns, and centralizes mapping in
toExtensionVersionFull(). Required so every code path reading
ExtensionVersion will see state-based filtering once soft-delete lands.
setState() now throws IllegalStateException when attempting to move from
DELETED back to ACTIVE or INACTIVE, guaranteeing soft-deletion is terminal
and preventing accidental revival via setActive() (which also routes through
setState). Adds entity-level tests covering the transitions.
Replaces entityManager.remove(ExtensionVersion) with setState(DELETED) in
ExtensionService and AdminService so version deletions become recoverable
soft-deletes. Adds:

- countNonDeleted / countAllVersions and STATE != DELETED conditions in
  the JOOQ repo so existence checks and delete-all-versions logic skip
  tombstoned rows.
- findVersion(...AndStateNot DELETED) variants and matching
  findVersionIncludingDeleted methods, used by publish to reject reuse of
  deleted coordinates with a clear error.
- findBundled/Dependencies references filtered to non-DELETED, and
  findActiveVersionsSorted backed by an active=true index variant.
- Scan-completion guard to never reactivate a DELETED version.
- Similarity check switched to countAllVersions (the only call site that
  legitimately needs tombstoned rows included).

Assisted-By: github:gpt-5.3-codex
@gnugomez gnugomez force-pushed the gnugomez/main/soft-delete-extensions branch from 699014a to d67473a Compare June 17, 2026 09:55
}

entityManager.remove(extension);
search.removeSearchEntry(extension);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I'm removing this here since ExtensionService::updateExtension already removes the search entry if the active value is false

@gnugomez gnugomez marked this pull request as ready for review June 17, 2026 10:58
@gnugomez gnugomez requested a review from netomi June 17, 2026 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant