Skip to content

Conversation

@richiemcilroy
Copy link
Member

@richiemcilroy richiemcilroy commented Nov 6, 2025

Introduces a new computed column, effectiveCreatedAt, to the videos table and refactors the codebase to use this column for sorting and querying video creation dates. Additionally, it removes redundant unique indexes from several tables, adds new composite indexes to optimize queries, and updates the schema definitions to match these changes.

Summary by CodeRabbit

  • Refactor
    • Unified video date tracking and sorting across the platform to improve consistency in how videos are ordered in all views and listings.
    • Optimized database performance through index restructuring and schema refinement to enhance query efficiency and system responsiveness.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

Walkthrough

This PR introduces a computed column effectiveCreatedAt to the videos table that combines metadata.customCreatedAt (if available) or falls back to createdAt. Multiple queries across the web app are updated to use this precomputed column instead of inline date calculations. Database indexes are reorganized and redundant unique constraints on primary keys are removed.

Changes

Cohort / File(s) Summary
Query updates
apps/web/actions/spaces/get-user-videos.ts, apps/web/app/(org)/dashboard/caps/page.tsx, apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx, apps/web/lib/folder.ts
Replaced computed effectiveDate from COALESCE/JSON_EXTRACT expressions to direct use of videos.effectiveCreatedAt column; updated ordering logic accordingly.
Database schema declaration
packages/database/schema.ts
Removed redundant unique() constraints from primary-key columns across all tables; added effectiveCreatedAt generated column to videos; reorganized indexes including ownerIdTombstoneIndex for organizations and new composite indexes (org_owner_folder_idx, org_effective_created_idx, video_type_created_idx, spaceIdFolderIdIdx) across tables.
Database migration: index and column changes
packages/database/migrations/0007_public_toxin.sql
Drops unique and non-unique indexes across multiple tables; adds effectiveCreatedAt generated column to videos (STORED, computed as COALESCE of metadata.customCreatedAt or createdAt); creates three new composite indexes for optimized queries.
Database migration: secondary index cleanup
packages/database/migrations/0008_fat_ender_wiggin.sql, packages/database/migrations/0008_secondary_index_cleanup.sql
Drops unique and non-unique indexes on comments, notifications, s3_buckets, auth_api_keys, spaces, shared_videos, and space_members; adds composite indexes video_type_created_idx on comments and space_id_folder_id_idx on space_videos.
Migration metadata
packages/database/migrations/meta/0007_snapshot.json, packages/database/migrations/meta/0008_snapshot.json, packages/database/migrations/meta/_journal.json
Adds complete database schema snapshots (version 5, MySQL-compatible JSON format) for migrations 0007 and 0008; extends migration journal with entries for indices 7 and 8.

Sequence Diagram

sequenceDiagram
    participant Query as Web Query
    participant DB as Database
    participant Videos as videos table
    
    Query->>DB: SELECT effectiveCreatedAt FROM videos ORDER BY effectiveCreatedAt DESC
    DB->>Videos: Compute effectiveCreatedAt = COALESCE(metadata→customCreatedAt, createdAt)
    Videos->>DB: Return computed date value (precomputed in DB)
    DB->>Query: Return ordered results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Schema changes complexity: Multiple exported table declarations modified; systematic removal of unique() from primary keys and addition of new generated columns and composite indexes require verification for consistency.
  • Migration semantics: Two migration files with index reorganization and addition of generated column logic; verify that index drops and creations are executed in correct order and that generated column expression handles edge cases (JSON parsing, NULL fallbacks).
  • Query refactoring patterns: Four web app files follow the same pattern (replacing COALESCE/JSON_EXTRACT with effectiveCreatedAt); spot-check one or two to verify correctness, then confirm pattern consistency.
  • Areas requiring extra attention:
    • SQL generated column expression in migration 0007: Verify JSON extraction with dual datetime formats (%Y-%m-%dT%H:%i:%s.%fZ, %Y-%m-%dT%H:%i:%sZ) handles all existing metadata.customCreatedAt values correctly.
    • Schema.ts index rename: Confirm ownerIdIndexownerIdTombstoneIndex update doesn't break dependent code or queries.
    • Migration journal: Verify breakpoint flags and tag assignments are consistent with actual migration file names.

Possibly related PRs

Suggested reviewers

  • Brendonovich

Poem

🐰 A computed column hops into view,
Dates harmonized, old queries anew.
Indexes dance and constraints fall away,
The schema grows stronger with each SQL play! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: introducing a computed column for video effective dates and optimizing database indexes through refactoring.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch db-optimisations

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx (2)

213-221: Consider adding videos.effectiveCreatedAt to the groupBy clause.

While effectiveCreatedAt is a generated column deterministic on metadata and createdAt (both present in groupBy), explicitly including videos.effectiveCreatedAt in the groupBy clause would improve clarity and prevent potential MySQL version-specific issues when ordering by a selected column.

Apply this diff:

 .groupBy(
   videos.id,
   videos.ownerId,
   videos.name,
   videos.createdAt,
   videos.metadata,
   users.name,
+  videos.effectiveCreatedAt,
 )

307-316: Consider adding videos.effectiveCreatedAt to the groupBy clause.

Similar to the fetchSpaceVideos function, explicitly including videos.effectiveCreatedAt in the groupBy clause would improve clarity and prevent potential MySQL version-specific issues when ordering by a selected column.

Apply this diff:

 .groupBy(
   videos.id,
   videos.ownerId,
   videos.name,
   videos.createdAt,
   videos.metadata,
   users.name,
   videos.duration,
+  videos.effectiveCreatedAt,
 )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6aa4e86 and ace0fe9.

📒 Files selected for processing (11)
  • apps/web/actions/spaces/get-user-videos.ts (3 hunks)
  • apps/web/app/(org)/dashboard/caps/page.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx (4 hunks)
  • apps/web/lib/folder.ts (2 hunks)
  • packages/database/migrations/0007_public_toxin.sql (1 hunks)
  • packages/database/migrations/0008_fat_ender_wiggin.sql (1 hunks)
  • packages/database/migrations/0008_secondary_index_cleanup.sql (1 hunks)
  • packages/database/migrations/meta/0007_snapshot.json (1 hunks)
  • packages/database/migrations/meta/0008_snapshot.json (1 hunks)
  • packages/database/migrations/meta/_journal.json (1 hunks)
  • packages/database/schema.ts (18 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/actions/spaces/get-user-videos.ts
  • apps/web/lib/folder.ts
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • packages/database/schema.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/actions/spaces/get-user-videos.ts
  • apps/web/lib/folder.ts
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • packages/database/schema.ts
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/actions/spaces/get-user-videos.ts
  • apps/web/lib/folder.ts
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-22T14:19:56.010Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-22T14:19:56.010Z
Learning: Applies to **/queries.ts : Do not edit auto-generated files named `queries.ts`.

Applied to files:

  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • packages/database/schema.ts
🧬 Code graph analysis (5)
apps/web/app/(org)/dashboard/caps/page.tsx (1)
packages/database/schema.ts (1)
  • videos (291-360)
apps/web/actions/spaces/get-user-videos.ts (1)
packages/database/schema.ts (1)
  • videos (291-360)
apps/web/lib/folder.ts (1)
packages/database/schema.ts (1)
  • videos (291-360)
apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx (1)
packages/database/schema.ts (1)
  • videos (291-360)
packages/database/schema.ts (5)
packages/database/helpers.ts (1)
  • nanoId (6-9)
packages/web-domain/src/User.ts (2)
  • UserId (10-10)
  • UserId (11-11)
packages/web-domain/src/Folder.ts (3)
  • Folder (37-45)
  • FolderId (11-11)
  • FolderId (12-12)
packages/web-domain/src/Video.ts (3)
  • Video (16-59)
  • VideoId (12-12)
  • VideoId (13-13)
packages/web-domain/src/S3Bucket.ts (3)
  • S3Bucket (7-15)
  • S3BucketId (4-4)
  • S3BucketId (5-5)
🪛 GitHub Actions: Validate Migrations
packages/database/migrations/meta/_journal.json

[error] 2-2: Migration journal version cannot be changed (was: <BASE_VERSION>, now: <CURRENT_VERSION>)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (7)
packages/database/migrations/0008_fat_ender_wiggin.sql (2)

15-16: LGTM! Well-designed composite indexes.

The new composite indexes are well-structured for their intended query patterns:

  • video_type_created_idx efficiently supports filtering comments by video/type and ordering by creation time
  • space_id_folder_id_idx optimizes folder-based queries within spaces

9-14: Verify that queries filtering by spaceId alone on space_members won't suffer performance degradation.

The migration drops space_id_idx and space_id_user_id_idx from space_members without replacement. Multiple queries in the codebase filter by spaceId alone on this table (e.g., delete operations in delete-space.ts and select operations in [spaceId]/page.tsx), which would have benefited from the dropped single-column index. Composite indexes may not be optimal for these lookups if they're not created to cover them.

For notifications, dropping recipient_id_idx is acceptable since recipient_read_idx and recipient_created_idx composite indexes can serve queries filtering by recipientId.

packages/database/migrations/meta/0008_snapshot.json (1)

1-1847: Migration snapshot is correctly generated.

This auto-generated snapshot file accurately reflects the schema state after migrations 0007 and 0008, including:

  • The effectiveCreatedAt generated column on videos
  • New composite indexes (video_type_created_idx, space_id_folder_id_idx)
  • Removal of redundant unique constraints on primary key columns
packages/database/migrations/0007_public_toxin.sql (2)

19-21: LGTM! Indexes are well-designed for the query patterns.

The new indexes effectively support:

  • Tombstone-aware organization queries (owner_id_tombstone_idx)
  • Folder-based video filtering within organizations (org_owner_folder_idx)
  • Efficient ordering by the computed effective creation date (org_effective_created_idx)

These indexes align well with the query patterns observed in the web application.


14-18: Timestamp-to-datetime conversion is a real type mismatch that requires a fix.

The videos.createdAt column is defined as timestamp (UTC-stored, session-timezone-converted), while effectiveCreatedAt is datetime (literal storage, no conversion). When createdAt serves as the fallback in the COALESCE expression, any subsequent changes to the MySQL session timezone will cause sorting and display inconsistencies—older rows won't update their stored datetime values, but new rows will reflect the new timezone interpretation.

Since effectiveCreatedAt is actively used for sorting, display, and indexing across the application, this type mismatch should be corrected:

  • Change effectiveCreatedAt to timestamp to ensure consistent timezone behavior, OR
  • Implement timezone-aware handling in the application layer to guarantee consistency
packages/database/migrations/meta/0007_snapshot.json (1)

1-1906: Migration snapshot correctly represents state after 0007.

This auto-generated snapshot accurately reflects the intermediate schema state after migration 0007, including:

  • The new effectiveCreatedAt generated column
  • New indexes: owner_id_tombstone_idx, org_owner_folder_idx, org_effective_created_idx
  • Indexes and constraints that will be modified in migration 0008 are still present
packages/database/migrations/meta/_journal.json (1)

2-2: The version field was not modified—it remains "5" before and after this change.

The git diff confirms that the version field at line 2 of _journal.json is unchanged (still "5"). The two new migration entries (idx 7 and 8) also correctly include "version": "5", consistent with all existing entries. No drizzle-orm version changes were detected in package.json. The migration entries follow the proper format with sequential indexing and valid timestamps. The pipeline failure is unrelated to this file's changes.

@richiemcilroy richiemcilroy merged commit a0e007c into main Nov 6, 2025
16 of 17 checks passed
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.

2 participants