Skip to content

feat: serve samples from the typescript server - #1257

Merged
igboyes merged 11 commits into
mainfrom
igboyes/vir-2807-convert-sample-api-calls-to-server-functions
Jul 27, 2026
Merged

feat: serve samples from the typescript server#1257
igboyes merged 11 commits into
mainfrom
igboyes/vir-2807-convert-sample-api-calls-to-server-functions

Conversation

@igboyes

@igboyes igboyes commented Jul 23, 2026

Copy link
Copy Markdown
Member

Summary

  • Move the six sample endpoints (list, detail, create, update, delete, rights) from the Python REST API onto TanStack Start server functions, with the shared has_sample_right predicate exported for the Analyses work to reuse.
  • Expand the legacy_samples Drizzle mirror and move sample wire shapes into @virtool/contracts; add createJob / reserveUploads so sample creation can schedule its job and hold its uploads.
  • Migrate every sample and dependent analysis test from the nock-based tests/api/samples.ts fakes to tests/server-fn/samples.ts stubs, and mark Samples as Built in docs/database.md.

@linear-code

linear-code Bot commented Jul 23, 2026

Copy link
Copy Markdown

VIR-2807

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @igboyes, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f82844edb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/web/src/server/samples/data.ts Outdated
Comment thread apps/web/src/server/uploads/data.ts Outdated
Comment thread apps/web/src/server/samples/data.ts Outdated
@igboyes

igboyes commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

Addressed the two Codex review threads (resolved):

  • Reads/artifacts on legacy samples (b089888): getReads and getArtifacts now resolve the storage id from legacy_id and OR against the text sample column, matching the delete path, so legacy rows with a null sample_id are found.
  • Reserving non-reads files (d6bd64a): reserveUploads now requires each id to resolve to a visible reads upload (type = reads, ready, not removed) before reserving; a reference/subtraction, unfinished, or removed upload is rejected as UploadNotFoundError so none is reserved.

(Replied here rather than inline because there's a pending review on the PR that would otherwise swallow the replies.)

Comment thread apps/web/src/server/samples/data.ts
Comment thread apps/web/src/server/samples/data.ts
Comment thread apps/web/src/server/samples/data.ts
Comment thread packages/contracts/src/samples.ts Outdated
Comment thread packages/contracts/src/samples.ts Outdated
Comment thread packages/contracts/src/samples.ts Outdated
Comment thread packages/contracts/src/samples.ts
Comment thread packages/contracts/src/samples.ts
igboyes added 11 commits July 27, 2026 10:43
The sample detail queries for reads and artifacts filtered on sample_id
only, so a legacy sample whose file rows are keyed by the text storage id
(with sample_id null) appeared to have no read or artifact files. Match
the delete path and OR against the storage id resolved from legacy_id.
reserveUploads only checked that each supplied upload existed and was
unreserved, so a create-sample request could reserve reference or
subtraction uploads, unfinished uploads, or removed ones — consuming
unrelated files and scheduling a job that cannot process its inputs.
Require each id to resolve to a visible reads upload (type reads, ready,
not removed) before reserving.
The samples server functions were the last to use snake_case wire fields,
inconsistent with the camelCase shapes every other migrated feature
returns (references, jobs). Rename the sample, read, artifact, and rights
fields to camelCase across the contract, the server data/functions layer,
and the client consumers, and fold the search envelope onto the shared
SearchResultV2.

Consolidate the sample-specific job types too: a shared JobNested and
JobState now live in @virtool/contracts, and a sample's embedded job is
JobNested narrowed to the create_sample workflow that built it.
getSample and findSamples resolved the owner's handle in a second pass — a
select over users keyed by the ids collected from the page — and getSample
fetched the group with its own query. Both are one-to-one relationships, so
join them onto the sample row instead, dropping getUsersByIds and getGroup.
The collection relationships (labels, subtractions, reads, artifacts, and the
workflow tags) stay as separate result sets.
user_id is nullable on legacy_samples, so a sample can exist with no
creating user — an invalid state that getSample and getSampleOwnerId
silently degraded to a blank, id-0 owner. Reading one now throws so the
integrity violation surfaces instead of propagating a bogus owner. The
sample list stays tolerant, so a single corrupt row cannot fail a whole
page.
Drop the per-feature `types.ts` re-export shim for samples and
references wire shapes; components now import Sample, Reference, and
friends straight from @virtool/contracts instead of through a feature
re-export. The shim only bought call-site stability during the earlier
migration and cost a second place every contract type had to be listed.

Also:
- rename sample test mock helpers to match the server functions they
  stub (mockUpdateSample, mockDeleteSample, mockFindSamples,
  mockFindSamplePages, mockGetSample)
- drop the dead `patchSample` wrapper and single-use `SampleID` type in
  samples/queries.ts and samples/types.ts
- update docs/architecture.md and AGENTS.md to describe the new
  convention
The one-line summary said not to suffix exports with their layer but
never mentioned how to resolve the collision that forces the question
in the first place, which is the root cause `auth/functions.ts` drifted
into `loginFn`-style exports instead of aliasing the colliding import.
…omain fn

The prior commit had this backwards. loginFn established the actual
convention first: a createServerFn export is an RPC call, not a plain
function, so it keeps the Fn suffix to mark that at every call site.
The plain name belongs to the domain function it wraps, which never
crosses the network. getSample, getGroup, and the ~60 other exported
server functions across src/server/*/functions.ts are the drift from
this, not loginFn.
Every createServerFn-wrapped export now ends in Fn (getUser -> getUserFn,
createSample -> createSampleFn, etc.) across all 15 src/server/*/functions.ts
files that hadn't yet adopted the convention auth/functions.ts and
getPasswordPolicyFn already followed. The suffix marks an RPC call at every
call site; the domain function each one wraps keeps its plain name.

Updates every call site (queries.ts modules, route guards, jobs/refresh.ts),
every tests/server-fn/*.ts mock object and its consumers, and the
functions.test.ts call()/callServerFn() string literals and
authorization.test.ts's hardcoded exception list.
@igboyes
igboyes force-pushed the igboyes/vir-2807-convert-sample-api-calls-to-server-functions branch from bbebd95 to 8e423a2 Compare July 27, 2026 17:52
@igboyes
igboyes merged commit 0f8594f into main Jul 27, 2026
15 checks passed
@igboyes
igboyes deleted the igboyes/vir-2807-convert-sample-api-calls-to-server-functions branch July 27, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant