diff --git a/src/modules/cards/infrastructure/repositories/schema/card.sql.ts b/src/modules/cards/infrastructure/repositories/schema/card.sql.ts index 8881c24a..f0350cee 100644 --- a/src/modules/cards/infrastructure/repositories/schema/card.sql.ts +++ b/src/modules/cards/infrastructure/repositories/schema/card.sql.ts @@ -7,6 +7,7 @@ import { integer, index, type PgTableWithColumns, + sql, } from 'drizzle-orm/pg-core'; import { publishedRecords } from './publishedRecord.sql'; @@ -33,6 +34,16 @@ export const cards: PgTableWithColumns = pgTable( // For general card queries by author authorIdIdx: index('cards_author_id_idx').on(table.authorId), + + // Performance indexes + typeUpdatedAtIdx: index('idx_cards_type_updated_at') + .on(table.type, table.updatedAt.desc()), + urlTypeIdx: index('idx_cards_url_type') + .on(table.url, table.type) + .include(table.id), + parentTypeIdx: index('idx_cards_parent_type') + .on(table.parentCardId, table.type) + .where(sql`type = 'NOTE'`), }; }, ); diff --git a/src/modules/cards/infrastructure/repositories/schema/collection.sql.ts b/src/modules/cards/infrastructure/repositories/schema/collection.sql.ts index 48c092fc..5c0ab7c2 100644 --- a/src/modules/cards/infrastructure/repositories/schema/collection.sql.ts +++ b/src/modules/cards/infrastructure/repositories/schema/collection.sql.ts @@ -72,6 +72,13 @@ export const collectionCards = pgTable( collectionIdIdx: index('collection_cards_collection_id_idx').on( table.collectionId, ), + // Performance indexes + collectionAddedIdx: index('idx_collection_cards_collection_added') + .on(table.collectionId, table.addedAt.desc()) + .include(table.cardId), + cardCollectionIdx: index('idx_collection_cards_card_collection') + .on(table.cardId) + .include(table.collectionId), }; }, ); diff --git a/src/modules/cards/infrastructure/repositories/schema/libraryMembership.sql.ts b/src/modules/cards/infrastructure/repositories/schema/libraryMembership.sql.ts index c5a695c4..59a28f4a 100644 --- a/src/modules/cards/infrastructure/repositories/schema/libraryMembership.sql.ts +++ b/src/modules/cards/infrastructure/repositories/schema/libraryMembership.sql.ts @@ -26,6 +26,10 @@ export const libraryMemberships = pgTable( pk: primaryKey({ columns: [table.cardId, table.userId] }), userCardsIdx: index('idx_user_cards').on(table.userId), cardUsersIdx: index('idx_card_users').on(table.cardId), + // Performance indexes + userTypeCoveringIdx: index('idx_library_memberships_user_type_covering') + .on(table.userId, table.addedAt.desc()) + .include(table.cardId), }; }, ); diff --git a/src/modules/cards/tests/test-utils/createTestSchema.ts b/src/modules/cards/tests/test-utils/createTestSchema.ts index 1855b462..d296e966 100644 --- a/src/modules/cards/tests/test-utils/createTestSchema.ts +++ b/src/modules/cards/tests/test-utils/createTestSchema.ts @@ -92,6 +92,39 @@ export async function createTestSchema(db: PostgresJsDatabase) { await db.execute( sql`CREATE INDEX IF NOT EXISTS idx_card_users ON library_memberships(card_id)`, ); + + // Performance indexes + await db.execute(sql` + CREATE INDEX IF NOT EXISTS idx_library_memberships_user_type_covering + ON library_memberships(user_id, added_at DESC) + INCLUDE (card_id) + `); + + await db.execute(sql` + CREATE INDEX IF NOT EXISTS idx_cards_type_updated_at + ON cards(type, updated_at DESC) + `); + + await db.execute(sql` + CREATE INDEX IF NOT EXISTS idx_cards_url_type + ON cards(url, type) INCLUDE (id) + `); + + await db.execute(sql` + CREATE INDEX IF NOT EXISTS idx_collection_cards_collection_added + ON collection_cards(collection_id, added_at DESC) + INCLUDE (card_id) + `); + + await db.execute(sql` + CREATE INDEX IF NOT EXISTS idx_cards_parent_type + ON cards(parent_card_id, type) WHERE type = 'NOTE' + `); + + await db.execute(sql` + CREATE INDEX IF NOT EXISTS idx_collection_cards_card_collection + ON collection_cards(card_id) INCLUDE (collection_id) + `); await db.execute(sql` CREATE INDEX IF NOT EXISTS idx_feed_activities_created_at ON feed_activities(created_at DESC); `);