refactor to use service and repository pattern - #493
Conversation
📝 WalkthroughWalkthroughThe registry module, init_db, and TrowStorageBackend are removed and replaced by FileStorage, a new repositories module wrapping read/write SQLite pools with domain models, and a services module (admission, health, catalog, blob, blob-upload, manifest, referrers, proxy, gc) that route handlers now delegate to via TrowServerState.services. ChangesService-Oriented Architecture Refactor
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant BlobUploadRoute
participant BlobUploadService
participant Repositories
participant FileStorage
Client->>BlobUploadRoute: PATCH /blob_upload
BlobUploadRoute->>BlobUploadService: patch_upload(repo, uuid, range, data)
BlobUploadService->>FileStorage: write_blob_stream(part)
BlobUploadService->>Repositories: update_offset(uuid, offset)
BlobUploadService-->>BlobUploadRoute: UploadInfo
BlobUploadRoute-->>Client: 202 Accepted
sequenceDiagram
participant ManifestRoute
participant ManifestService
participant ProxyService
participant Repositories
ManifestRoute->>ManifestService: get_manifest(repo, reference, namespace)
alt non-localhost registry
ManifestService->>ProxyService: download_image(reference, proxy_config)
ProxyService->>Repositories: insert manifest and associations
ProxyService-->>ManifestService: digest
else localhost
ManifestService->>Repositories: resolve tag or digest
end
ManifestService-->>ManifestRoute: ManifestPayload
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a major architectural refactoring to separate concerns by establishing a dedicated Repository layer for database metadata access and a Service layer for business logic orchestration. Direct database queries are moved out of route handlers into specialized repositories, and services are introduced to manage operations like blob uploads, manifest handling, and garbage collection. The feedback highlights several critical issues: first, multiple read-only database queries incorrectly use the write connection pool (which is limited to a single connection), risking connection starvation; second, a panic risk exists in the upload service due to an assertion on user-provided repository names; and third, leaky database abstractions returning nested options should be simplified to return booleans, which would significantly clean up conditional checks in the service layer.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (4)
src/routes/manifest.rs (1)
51-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant
Ok(... ?)wrapping.Both handlers wrap
Ok(expr.await?)while the function already returnsResult<_, Error>. This trips Clippy'sneedless_question_mark, which fails the build under-D warnings. You can return the future's result directly.♻️ Proposed simplification
- Ok(state - .services - .manifest - .put_manifest(repo_name, reference, host, body) - .await?) + state + .services + .manifest + .put_manifest(repo_name, reference, host, body) + .await- Ok(state - .services - .manifest - .delete_manifest(repo, reference) - .await?) + state + .services + .manifest + .delete_manifest(repo, reference) + .awaitAlso applies to: 72-76
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/routes/manifest.rs` around lines 51 - 55, The manifest route handlers are redundantly wrapping awaited results in Ok(...?), which triggers Clippy’s needless_question_mark in the handler functions. Update the manifest endpoint returns in the handler(s) around put_manifest and the other matching route to return the awaited service result directly from state.services.manifest instead of wrapping it in Ok, keeping the Result<_, Error> signature intact.src/test_utilities.rs (1)
36-51: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDeduplicate
repos_in_memoryby reusingpool_in_memory.Both helpers construct identical
SqliteConnectOptions, create a pool withmax_connections(1), and run migrations.repos_in_memorycan delegate topool_in_memoryand wrap the result, eliminating the duplicated setup logic.♻️ Proposed refactor
pub async fn repos_in_memory() -> Arc<Repositories> { - let options = SqliteConnectOptions::new() - .filename(":memory:") - .synchronous(SqliteSynchronous::Normal) - .journal_mode(SqliteJournalMode::Wal) - .foreign_keys(true); - - let pool = SqlitePoolOptions::new() - .max_connections(1) - .connect_with(options) - .await - .unwrap(); - - sqlx::migrate!().run(&pool).await.unwrap(); + let pool = pool_in_memory().await; Arc::new(Repositories::from_pools(pool.clone(), pool)) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test_utilities.rs` around lines 36 - 51, The repos_in_memory helper duplicates the same SQLite setup and migration logic already handled by pool_in_memory. Refactor repos_in_memory to call pool_in_memory() instead of rebuilding SqliteConnectOptions, creating the pool, and running sqlx::migrate! again, then wrap the returned pool in Repositories::from_pools so the behavior stays the same while removing duplicated setup code.src/repositories/tag_repository.rs (1)
66-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSpecify column names explicitly in the INSERT statement.
INSERT INTO tag VALUES ($1, $2, $3)relies on the table's implicit column order. If a column is added or reordered in a future migration, this could silently insert values into wrong columns. The inline comment already acknowledges the non-obvious parameter mapping, which is a sign this should be more explicit.♻️ Proposed refactor
INSERT INTO tag + (tag, repo, manifest_digest) VALUES ($1, $2, $3) ON CONFLICT (repo, tag) DO UPDATE SET manifest_digest = EXCLUDED.manifest_digest🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/repositories/tag_repository.rs` around lines 66 - 76, The INSERT in tag_repository::insert_tag relies on implicit table column order, so update the sqlx::query! statement to name the target columns explicitly and keep the existing repo/tag/manifest_digest mapping clear. Use the same tag_repository code path and the ON CONFLICT (repo, tag) handling, but make the INSERT clause list the columns so future schema changes do not break the parameter ordering.src/repositories/models.rs (1)
39-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider deriving
CloneforManifestReferrer.All other domain models in this file derive
Clone, butManifestReferreronly derivesDebug, FromRow. If any service or route handler needs to clone referrer results (e.g., for retry logic or parallel processing), the missingClonewill surface as a compile error. Adding it now keeps the models consistent.♻️ Proposed refactor
-#[derive(Debug, FromRow)] +#[derive(Debug, Clone, FromRow)] pub struct ManifestReferrer {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/repositories/models.rs` around lines 39 - 44, ManifestReferrer is missing Clone while the other models in models.rs already derive it, so update the ManifestReferrer definition to include Clone alongside Debug and FromRow. Keep the change consistent with the surrounding domain structs in this file so any code using ManifestReferrer for retries, parallel processing, or duplication can clone it without compile errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/repositories/blob_repository.rs`:
- Around line 70-78: The blob existence check in the `BlobRepository::exists`
method is using the write pool instead of the read pool. Update this read-only
query to fetch from `db_ro` so concurrent `exists` calls don’t contend with
writes, matching the other read methods in `BlobRepository` and keeping the
`exists` logic otherwise unchanged.
- Around line 81-85: The sum_size method in BlobRepository should handle empty
tables because SQLite returns NULL for SUM on no rows, which breaks callers like
compute_space_to_reclaim. Update the query in sum_size to use COALESCE around
SUM(b.size) so it always returns 0 when there are no blob rows, while keeping
the existing async return type and query_scalar! usage.
In `@src/repositories/blob_upload_repository.rs`:
- Around line 113-117: The `sum_offset` query in `BlobUploadRepository` will
fail on an empty table because `SUM(u.offset)` can return NULL while `as
"size!"` forces a non-null `i64` decode. Update `sum_offset` to handle the
empty-set case the same way as `BlobRepository::sum_size`, so it returns 0
instead of raising a `DecodeError`; keep the fix localized in `sum_offset` and
its `sqlx::query_scalar!` mapping.
In `@src/repositories/manifest_repository.rs`:
- Around line 87-97: The `list_manifests_using_blob` read path is incorrectly
using `self.db_rw` for a SELECT-only query, which adds avoidable contention on
the write pool. Update `ManifestRepository::list_manifests_using_blob` to fetch
from `self.db_ro` instead, matching the repository’s other read methods like
`find` and `list_referrers`, and keep the rest of the query unchanged.
In `@src/repositories/repo_blob_assoc_repository.rs`:
- Around line 56-70: The read-only EXISTS lookup in manifest_exists_in_repo is
using db_rw, which can serialize proxy downloads and contend with writes. Update
this method to query through db_ro instead, matching the other read-only
repository methods, and keep the existing manifest_digest/repo_name parameters
and SQL unchanged.
In `@src/repositories/tag_repository.rs`:
- Around line 42-53: The cursor filter in tag pagination uses a different
collation than the sort, which can skip mixed-case tags between pages. Update
the query in the tag_repository logic that fetches tags so the predicate on
t.tag uses COLLATE NOCASE to match the ORDER BY t.tag COLLATE NOCASE, keeping
the cursor comparison consistent with the sort order.
In `@src/services/blob_upload_service.rs`:
- Around line 62-90: `patch_upload` only checks `exists(&uuid_str)` and can
accept a UUID that belongs to a different repo, so the upload must be validated
against `repo_name` before writing. Update `BlobUploadService::patch_upload` to
fetch the upload using a repo-aware lookup like `find_offset_in_repo` (or `find`
plus explicit repo comparison if needed), and return an error when the UUID does
not belong to the supplied repo instead of proceeding. Keep the
`UploadInfo::new` path unchanged once the repo ownership check passes.
- Around line 92-133: In complete_upload, replace the
assert_eq!(upload_row.repo, repo_name) check with an explicit error return so a
mismatched repo does not panic; use the existing Error type and keep the
validation near the upload_row lookup before proceeding to
write_blob_part_stream, complete_blob_write, and the repo/blob association
inserts. Refer to complete_upload and upload_row.repo/repo_name when updating
the control flow so the function fails gracefully on wrong-repo UUID
submissions.
In `@src/services/catalog_service.rs`:
- Around line 18-30: The pagination limit in list_repositories currently casts
an Option<u64> to i64 with as, which can wrap for values above i64::MAX and
produce invalid SQLite LIMIT behavior. Update list_repositories to validate or
clamp the limit before calling repo_blob_assoc.list_repos, and handle oversized
values explicitly rather than relying on the cast. Keep the fix localized to
list_repositories and its use of limit.unwrap_or(...) so the repository query
always receives a safe nonnegative i64.
In `@src/services/health_service.rs`:
- Around line 36-41: The readiness check in `HealthService::readiness` always
returns an empty `ReadyStatus.message`, even when `storage.is_ready()` fails.
Update `readiness()` to capture the result from `self.storage.is_ready().await`,
and when it returns `Err`, populate `ReadyStatus.message` with the error’s
message while keeping `is_ready` false. Use the existing `ReadyStatus` and
`storage.is_ready()` flow so the success path stays unchanged.
In `@src/services/manifest_service.rs`:
- Around line 145-163: The OCIManifest::V2 validation only checks distributable
layers and misses the config blob, so extend the manifest validation in the V2
branch to also verify the config digest is present in repo_blob_assoc before
accepting the manifest. Update the existing asset-checking logic in
manifest_service::ManifestService so it iterates over both layers and the config
blob, and return the same ManifestInvalid error if the config blob is missing.
Keep the change localized to the OCIManifest::V2 handling and reuse the existing
blob_belongs_to_repo check for consistency.
In `@src/services/proxy_service/oci_client.rs`:
- Around line 59-67: The ECR token parsing in the `get_authorization_token` flow
is using chained unwraps on `authorization_data`, the first entry, and
`authorization_token`, which can panic when the response is incomplete. Update
the token extraction in the OCI client code to handle each missing case
explicitly and return an `EcrPasswordError` instead of unwrapping; add a
missing-token variant if `EcrPasswordError` does not already cover this path.
In `@src/services/referrers_service.rs`:
- Around line 37-41: The manifest digest parsing in referrers_service’s
descriptor creation currently uses Digest::from_str(...).unwrap(), which can
panic on malformed stored data; replace this with explicit parsing error
handling in the referrers lookup path. Update the logic around Descriptor::new
so it maps a failed digest parse to Error::Invalid and propagates that error
instead of unwrapping, keeping the request path safe for bad rows.
---
Nitpick comments:
In `@src/repositories/models.rs`:
- Around line 39-44: ManifestReferrer is missing Clone while the other models in
models.rs already derive it, so update the ManifestReferrer definition to
include Clone alongside Debug and FromRow. Keep the change consistent with the
surrounding domain structs in this file so any code using ManifestReferrer for
retries, parallel processing, or duplication can clone it without compile
errors.
In `@src/repositories/tag_repository.rs`:
- Around line 66-76: The INSERT in tag_repository::insert_tag relies on implicit
table column order, so update the sqlx::query! statement to name the target
columns explicitly and keep the existing repo/tag/manifest_digest mapping clear.
Use the same tag_repository code path and the ON CONFLICT (repo, tag) handling,
but make the INSERT clause list the columns so future schema changes do not
break the parameter ordering.
In `@src/routes/manifest.rs`:
- Around line 51-55: The manifest route handlers are redundantly wrapping
awaited results in Ok(...?), which triggers Clippy’s needless_question_mark in
the handler functions. Update the manifest endpoint returns in the handler(s)
around put_manifest and the other matching route to return the awaited service
result directly from state.services.manifest instead of wrapping it in Ok,
keeping the Result<_, Error> signature intact.
In `@src/test_utilities.rs`:
- Around line 36-51: The repos_in_memory helper duplicates the same SQLite setup
and migration logic already handled by pool_in_memory. Refactor repos_in_memory
to call pool_in_memory() instead of rebuilding SqliteConnectOptions, creating
the pool, and running sqlx::migrate! again, then wrap the returned pool in
Repositories::from_pools so the behavior stays the same while removing
duplicated setup code.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 380d88ef-3928-42b9-9d5e-b6c9c6511e04
📒 Files selected for processing (45)
src/file_storage.rssrc/init_db.rssrc/lib.rssrc/registry/api_types.rssrc/registry/garbage_collect.rssrc/registry/mod.rssrc/registry/proxy/download.rssrc/repositories/blob_repository.rssrc/repositories/blob_upload_repository.rssrc/repositories/manifest_repository.rssrc/repositories/mod.rssrc/repositories/models.rssrc/repositories/repo_blob_assoc_repository.rssrc/repositories/tag_repository.rssrc/routes/admission.rssrc/routes/blob.rssrc/routes/blob_upload.rssrc/routes/catalog.rssrc/routes/health.rssrc/routes/manifest.rssrc/routes/manifest_referrers.rssrc/routes/readiness.rssrc/routes/response/blob_reader.rssrc/routes/response/content_info.rssrc/routes/response/errors.rssrc/routes/response/health.rssrc/routes/response/readiness.rssrc/services/admission_service.rssrc/services/blob_service.rssrc/services/blob_upload_service.rssrc/services/catalog_service.rssrc/services/error.rssrc/services/gc_service.rssrc/services/health_service.rssrc/services/manifest_service.rssrc/services/mod.rssrc/services/proxy_service/errors.rssrc/services/proxy_service/mod.rssrc/services/proxy_service/oci_client.rssrc/services/referrers_service.rssrc/test_utilities.rssrc/utils/manifest.rssrc/utils/mod.rssrc/utils/resolve_reference.rstests/smoke_test_proxy.rs
💤 Files with no reviewable changes (6)
- src/init_db.rs
- src/registry/proxy/download.rs
- src/registry/garbage_collect.rs
- src/utils/mod.rs
- src/registry/api_types.rs
- src/registry/mod.rs
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/repositories/blob_repository.rs (1)
80-86: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
sum_sizestill fails on emptyblobtable —unwrap_or(0)doesn't fix the NULL issue.
SUM(b.size)returnsNULLin SQLite when the table has no rows. The"size!"annotation tells sqlx the column is NOT NULL, soquery_scalar!generatesi64(notOption<i64>). When sqlx tries to decode the NULL result asi64, it returns aDecodeerror that propagates via?—unwrap_or(0)is never reached. This causescompute_space_to_reclaimto fail on fresh installs or after GC removes all blobs.Add
COALESCEto make the column truly NOT NULL:🔧 Proposed fix
pub async fn sum_size(&self) -> Result<usize, sqlx::Error> { - let res = sqlx::query_scalar!(r#"SELECT SUM(b.size) as "size!" FROM blob b"#) + let res = sqlx::query_scalar!(r#"SELECT COALESCE(SUM(b.size), 0) as "size!" FROM blob b"#) .fetch_one(&self.db_ro) .await?; Ok(usize::try_from(res).unwrap_or(0)) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/repositories/blob_repository.rs` around lines 80 - 86, `sum_size` is still decoding a NULL aggregate result as a non-null scalar, so `unwrap_or(0)` never runs on an empty blob table. Update `BlobRepository::sum_size` to make the SQL itself return a non-null value by using `COALESCE` in the `sqlx::query_scalar!` query, keeping the return type and `compute_space_to_reclaim` path working on fresh or fully-garbage-collected databases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@src/repositories/blob_repository.rs`:
- Around line 80-86: `sum_size` is still decoding a NULL aggregate result as a
non-null scalar, so `unwrap_or(0)` never runs on an empty blob table. Update
`BlobRepository::sum_size` to make the SQL itself return a non-null value by
using `COALESCE` in the `sqlx::query_scalar!` query, keeping the return type and
`compute_space_to_reclaim` path working on fresh or fully-garbage-collected
databases.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f3341a82-57b6-49bf-a7a7-9c3ac9fc86de
📒 Files selected for processing (42)
.sqlx/query-0267ad1f011779abdd531fe5a332b7b636fb017c5e935b462a00d89e12ea4fd7.json.sqlx/query-04380a0bd91d3405cfd45eff6b6f2b33b001f0c5e8c3065674ddf046a51bccee.json.sqlx/query-0be73f5f867ae4ec655854a33aceb202ddf91c2eeff83c630672154f309ba1a9.json.sqlx/query-0d94fec6d4492cf2c8e1be688a6e31d1d3389809b63ee2b7636fa345dea58138.json.sqlx/query-11ef1d69ef684e5a1f1207bea26e541640bee4cbe6785441cb86aa25141ddb9a.json.sqlx/query-16ad8411febff0e01175536aa208bcbaa8e2e17a2762a21e59e9539fc13e18b5.json.sqlx/query-38275e6a8bc246702e74bd27deee17d41f0be846b5dee0b4d4b1c215afe89c80.json.sqlx/query-40620d77dbcd8a1543cdaefb7ef02dd372e2c18e8a2bf774a9f4d133f4b3b751.json.sqlx/query-459995dfcba9b3dc20c52e1709534bc260c313951fda246dfee7fdb64be31429.json.sqlx/query-552852975d7cbaf61439d8ad1b2004d8e34ff55915ebd7f418986c68792fbb91.json.sqlx/query-5b2946fbbd9c1f20e7f3e1e531b9036960dbec8eab7f419c3a27ef4ca58b7382.json.sqlx/query-614b5d0c6ad0e1bcef68abe4d49aada513bbd702d6074ce266eb24c5d06f427d.json.sqlx/query-64ff141cd6bfaaca29cfebfe70dd061723e8925b31e6e0d2a6dbc904aa970d7a.json.sqlx/query-666ee67eace7ba2e0a858716c3bd364cd1f15a15bb79652b75c252bd76fe2d79.json.sqlx/query-6a3b3dd4b9aacf35b47cc6441605b16a5a24b6e314c68596d4ba52101d3efddb.json.sqlx/query-70c6f6aa2d8311ad45ddd5cf4961d6d4b89f7e743809dec6bc4319a28bcfd651.json.sqlx/query-77fa684dc88b571e55a7b2f309a86eacb1ca987bd0d8b0b10c995131361c49b2.json.sqlx/query-7b84ccfb9acb6ee086d49e0546c3cbcfe1f9bc8a4fc0d56a0de83d0de20fde03.json.sqlx/query-897f4b82a419c8da99cb707f816f25785784959f03e4b38ade987fa3903920b9.json.sqlx/query-8b5c40aca05a2657eae27a4b37019ce0ff6d9f0c22da8c5f04a9abb2a0103b8c.json.sqlx/query-93c30a9805ea69749c4ee8954273ff4e9fc039053c2dd6303f797e9b6d6e3464.json.sqlx/query-a19a4be40736f440dc27b24cc0f76860cee67616e343d06d3704bfef8fe12328.json.sqlx/query-ae5cbd2998c86a6e412cac73aac2921e117a5f39e8608133401438e32d5240af.json.sqlx/query-b93961bcf07284bc32e2ad7e6fcb1ab2b08bfff393cc6116422a5afa6164e414.json.sqlx/query-c18c3fdfb91cbe3245a5423c3ce21c9c155236ea902db1425b396f786547fb98.json.sqlx/query-c6d231b319e1386d6d16aaaf79a1b177e27564c80cc29ac55c6cc962fb6f753b.json.sqlx/query-c729e8969ca0751f30ec8738b2ef207413399cbc6a9a7b2e4ea65afe22c32547.json.sqlx/query-cc2eee2c57c61963207391adad6e7f1a0f29290843161e2176f157097f91b0b6.json.sqlx/query-d373abe42ea596c62d555c2ccca627381da6e2347b5a9d2590bf97dab4ee3671.json.sqlx/query-dd06315416372c82898ef0e279056575d43271e5bf7895a809de88415b174da4.json.sqlx/query-f53d056f0d6784eccc62730fddd8169cb79bc5c582d070fa182b49fcdc8ceecc.json.sqlx/query-f5d12cf96720c56798f47641f38f39ab24a6b027a5bb919f12af3836ea6a49da.json.sqlx/query-f6f2371924284a1a70e53dae12eaf1c19a372fdf38274b04f9e9f6d7929ed72a.jsonsrc/repositories/blob_repository.rssrc/repositories/blob_upload_repository.rssrc/repositories/manifest_repository.rssrc/repositories/repo_blob_assoc_repository.rssrc/services/blob_upload_service.rssrc/services/gc_service.rssrc/services/health_service.rssrc/services/manifest_service.rssrc/services/proxy_service/mod.rs
💤 Files with no reviewable changes (18)
- .sqlx/query-ae5cbd2998c86a6e412cac73aac2921e117a5f39e8608133401438e32d5240af.json
- .sqlx/query-a19a4be40736f440dc27b24cc0f76860cee67616e343d06d3704bfef8fe12328.json
- .sqlx/query-c6d231b319e1386d6d16aaaf79a1b177e27564c80cc29ac55c6cc962fb6f753b.json
- .sqlx/query-16ad8411febff0e01175536aa208bcbaa8e2e17a2762a21e59e9539fc13e18b5.json
- .sqlx/query-93c30a9805ea69749c4ee8954273ff4e9fc039053c2dd6303f797e9b6d6e3464.json
- .sqlx/query-c18c3fdfb91cbe3245a5423c3ce21c9c155236ea902db1425b396f786547fb98.json
- .sqlx/query-5b2946fbbd9c1f20e7f3e1e531b9036960dbec8eab7f419c3a27ef4ca58b7382.json
- .sqlx/query-666ee67eace7ba2e0a858716c3bd364cd1f15a15bb79652b75c252bd76fe2d79.json
- .sqlx/query-dd06315416372c82898ef0e279056575d43271e5bf7895a809de88415b174da4.json
- .sqlx/query-04380a0bd91d3405cfd45eff6b6f2b33b001f0c5e8c3065674ddf046a51bccee.json
- .sqlx/query-c729e8969ca0751f30ec8738b2ef207413399cbc6a9a7b2e4ea65afe22c32547.json
- .sqlx/query-0267ad1f011779abdd531fe5a332b7b636fb017c5e935b462a00d89e12ea4fd7.json
- .sqlx/query-552852975d7cbaf61439d8ad1b2004d8e34ff55915ebd7f418986c68792fbb91.json
- .sqlx/query-459995dfcba9b3dc20c52e1709534bc260c313951fda246dfee7fdb64be31429.json
- .sqlx/query-6a3b3dd4b9aacf35b47cc6441605b16a5a24b6e314c68596d4ba52101d3efddb.json
- .sqlx/query-0d94fec6d4492cf2c8e1be688a6e31d1d3389809b63ee2b7636fa345dea58138.json
- .sqlx/query-f5d12cf96720c56798f47641f38f39ab24a6b027a5bb919f12af3836ea6a49da.json
- .sqlx/query-7b84ccfb9acb6ee086d49e0546c3cbcfe1f9bc8a4fc0d56a0de83d0de20fde03.json
✅ Files skipped from review due to trivial changes (7)
- .sqlx/query-77fa684dc88b571e55a7b2f309a86eacb1ca987bd0d8b0b10c995131361c49b2.json
- .sqlx/query-b93961bcf07284bc32e2ad7e6fcb1ab2b08bfff393cc6116422a5afa6164e414.json
- .sqlx/query-70c6f6aa2d8311ad45ddd5cf4961d6d4b89f7e743809dec6bc4319a28bcfd651.json
- .sqlx/query-f6f2371924284a1a70e53dae12eaf1c19a372fdf38274b04f9e9f6d7929ed72a.json
- .sqlx/query-614b5d0c6ad0e1bcef68abe4d49aada513bbd702d6074ce266eb24c5d06f427d.json
- .sqlx/query-f53d056f0d6784eccc62730fddd8169cb79bc5c582d070fa182b49fcdc8ceecc.json
- .sqlx/query-64ff141cd6bfaaca29cfebfe70dd061723e8925b31e6e0d2a6dbc904aa970d7a.json
🚧 Files skipped from review as they are similar to previous changes (7)
- src/services/health_service.rs
- src/repositories/manifest_repository.rs
- src/services/proxy_service/mod.rs
- src/repositories/blob_upload_repository.rs
- src/services/blob_upload_service.rs
- src/services/manifest_service.rs
- src/services/gc_service.rs
This adds a lot of boilerplate but makes working with the project way easier and nicer.
Summary by CodeRabbit
New Features
Bug Fixes