From 48f9e7d132b0f9b4250ffbf386746d9945a47689 Mon Sep 17 00:00:00 2001 From: Maurice Date: Wed, 7 Oct 2026 16:56:58 +0200 Subject: [PATCH] perf(db): index every foreign-key column 86 foreign-key columns had no index. SQLite does not add one by itself, so every cascading delete of a trip or a user scanned each such child table in full, inside the transaction, while every other request waited on the one connection. One migration adds them all, and the entities are regenerated to match. --- .../entities/AssignmentParticipants.entity.ts | 4 +- server/src/db/entities/AuditLog.entity.ts | 4 +- server/src/db/entities/BucketList.entity.ts | 4 +- .../db/entities/BudgetItemPayers.entity.ts | 4 +- server/src/db/entities/BudgetItems.entity.ts | 12 +- .../db/entities/BudgetSettlements.entity.ts | 12 +- server/src/db/entities/Categories.entity.ts | 4 +- server/src/db/entities/CollabLinks.entity.ts | 4 +- .../entities/CollabMessageReactions.entity.ts | 4 +- .../src/db/entities/CollabMessages.entity.ts | 8 +- server/src/db/entities/CollabNotes.entity.ts | 4 +- .../src/db/entities/CollabPollVotes.entity.ts | 4 +- server/src/db/entities/CollabPolls.entity.ts | 4 +- .../entities/CollectionPlaceRatings.entity.ts | 4 +- .../db/entities/CollectionPlaces.entity.ts | 12 +- server/src/db/entities/Collections.entity.ts | 4 +- .../DawarichVisitSuggestions.entity.ts | 12 +- .../db/entities/DayAccommodations.entity.ts | 4 +- server/src/db/entities/DayNotes.entity.ts | 4 +- .../db/entities/DocumentConnections.entity.ts | 4 +- .../db/entities/DocumentSyncItems.entity.ts | 4 +- server/src/db/entities/FileLinks.entity.ts | 12 +- .../src/db/entities/IdempotencyKeys.entity.ts | 4 +- server/src/db/entities/InviteTokens.entity.ts | 8 +- server/src/db/entities/JourneyBooks.entity.ts | 8 +- .../src/db/entities/JourneyEntries.entity.ts | 8 +- .../src/db/entities/JourneyPhotos.entity.ts | 4 +- .../db/entities/JourneyShareTokens.entity.ts | 4 +- server/src/db/entities/JourneyTrips.entity.ts | 4 +- server/src/db/entities/McpTokens.entity.ts | 4 +- .../src/db/entities/Notifications.entity.ts | 4 +- .../src/db/entities/OauthConsents.entity.ts | 4 +- server/src/db/entities/OauthTokens.entity.ts | 4 +- server/src/db/entities/PackingBags.entity.ts | 8 +- .../PackingCategoryAssignees.entity.ts | 4 +- .../PackingItemContributors.entity.ts | 4 +- server/src/db/entities/PackingItems.entity.ts | 8 +- .../PackingTemplateCategories.entity.ts | 4 +- .../entities/PackingTemplateItems.entity.ts | 4 +- .../db/entities/PackingTemplates.entity.ts | 4 +- server/src/db/entities/PlaceRatings.entity.ts | 4 +- .../ReservationDayPositions.entity.ts | 4 +- server/src/db/entities/Reservations.entity.ts | 12 +- .../entities/RoadtripDayBoundaries.entity.ts | 8 +- server/src/db/entities/ShareTokens.entity.ts | 8 +- server/src/db/entities/Tags.entity.ts | 4 +- .../entities/TodoCategoryAssignees.entity.ts | 4 +- server/src/db/entities/TodoItems.entity.ts | 4 +- .../src/db/entities/TripAlbumLinks.entity.ts | 4 +- .../db/entities/TripDocumentLinks.entity.ts | 8 +- server/src/db/entities/TripFiles.entity.ts | 16 +-- .../db/entities/TripInviteTokens.entity.ts | 4 +- server/src/db/entities/TripMembers.entity.ts | 4 +- server/src/db/entities/TripPhotos.entity.ts | 8 +- server/src/db/entities/VacayEntries.entity.ts | 4 +- .../entities/VacayHolidayCalendars.entity.ts | 4 +- .../db/entities/VacayPlanMembers.entity.ts | 4 +- .../src/db/entities/VacayUserColors.entity.ts | 4 +- .../src/db/entities/VacayUserYears.entity.ts | 4 +- .../db/entities/WebauthnChallenges.entity.ts | 4 +- ...101042200_an_index_on_every_foreign_key.ts | 105 ++++++++++++++++++ server/tests/unit/db/legacy-baseline.test.ts | 1 + 62 files changed, 276 insertions(+), 170 deletions(-) create mode 100644 server/src/db/migrations/Migration20200101042200_an_index_on_every_foreign_key.ts diff --git a/server/src/db/entities/AssignmentParticipants.entity.ts b/server/src/db/entities/AssignmentParticipants.entity.ts index d1b4dd36a..156033abc 100644 --- a/server/src/db/entities/AssignmentParticipants.entity.ts +++ b/server/src/db/entities/AssignmentParticipants.entity.ts @@ -20,7 +20,7 @@ export const AssignmentParticipantsSchema = defineEntity({ id: p.integer().primary(), assignment: () => p.manyToOne(DayAssignments).ref().deleteRule('cascade').hidden().index('idx_assignment_participants_assignment'), assignment_id: p.integer().persist(false).index('idx_assignment_participants_assignment'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_assignment_participants_user_id'), + user_id: p.integer().persist(false).index('idx_assignment_participants_user_id'), }, }); diff --git a/server/src/db/entities/AuditLog.entity.ts b/server/src/db/entities/AuditLog.entity.ts index 696b57a0a..0385ca0d6 100644 --- a/server/src/db/entities/AuditLog.entity.ts +++ b/server/src/db/entities/AuditLog.entity.ts @@ -21,8 +21,8 @@ export const AuditLogSchema = defineEntity({ properties: { id: p.integer().primary(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`).index('idx_audit_log_created'), - user: () => p.manyToOne(Users).ref().nullable().hidden(), - user_id: p.integer().nullable().persist(false), + user: () => p.manyToOne(Users).ref().nullable().hidden().index('idx_audit_log_user_id'), + user_id: p.integer().nullable().persist(false).index('idx_audit_log_user_id'), action: p.text(), resource: p.text().nullable(), details: p.text().nullable(), diff --git a/server/src/db/entities/BucketList.entity.ts b/server/src/db/entities/BucketList.entity.ts index 3fa087617..6b4cd019c 100644 --- a/server/src/db/entities/BucketList.entity.ts +++ b/server/src/db/entities/BucketList.entity.ts @@ -28,8 +28,8 @@ export const BucketListSchema = defineEntity({ repository: () => BucketListRepository, properties: { id: p.integer().primary(), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_bucket_list_user_id'), + user_id: p.integer().persist(false).index('idx_bucket_list_user_id'), name: p.text(), lat: p.double().nullable(), lng: p.double().nullable(), diff --git a/server/src/db/entities/BudgetItemPayers.entity.ts b/server/src/db/entities/BudgetItemPayers.entity.ts index 5897e81f4..b61de3d46 100644 --- a/server/src/db/entities/BudgetItemPayers.entity.ts +++ b/server/src/db/entities/BudgetItemPayers.entity.ts @@ -21,8 +21,8 @@ export const BudgetItemPayersSchema = defineEntity({ id: p.integer().primary(), budgetItem: () => p.manyToOne(BudgetItems).ref().deleteRule('cascade').hidden().index('idx_budget_item_payers_item'), budget_item_id: p.integer().persist(false).index('idx_budget_item_payers_item'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_budget_item_payers_user_id'), + user_id: p.integer().persist(false).index('idx_budget_item_payers_user_id'), amount: p.double().defaultRaw(`0`), }, }); diff --git a/server/src/db/entities/BudgetItems.entity.ts b/server/src/db/entities/BudgetItems.entity.ts index ad9b2bcc6..5eded9cb1 100644 --- a/server/src/db/entities/BudgetItems.entity.ts +++ b/server/src/db/entities/BudgetItems.entity.ts @@ -52,16 +52,16 @@ export const BudgetItemsSchema = defineEntity({ note: p.text().nullable(), sort_order: p.integer().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - paidByUser: () => p.manyToOne(Users).ref().deleteRule('no action').nullable().hidden(), - paid_by_user_id: p.integer().nullable().persist(false), + paidByUser: () => p.manyToOne(Users).ref().deleteRule('no action').nullable().hidden().index('idx_budget_items_paid_by_user_id'), + paid_by_user_id: p.integer().nullable().persist(false).index('idx_budget_items_paid_by_user_id'), expense_date: p.text().nullable().defaultRaw(`NULL`), - reservation: () => p.manyToOne(Reservations).ref().nullable().hidden().defaultRaw(`NULL`), - reservation_id: p.integer().nullable().persist(false).defaultRaw(`NULL`), + reservation: () => p.manyToOne(Reservations).ref().nullable().hidden().defaultRaw(`NULL`).index('idx_budget_items_reservation_id'), + reservation_id: p.integer().nullable().persist(false).defaultRaw(`NULL`).index('idx_budget_items_reservation_id'), currency: p.text().nullable(), exchange_rate: p.double().defaultRaw(`1`), ticket_json: p.text().nullable(), - place: () => p.manyToOne(Places).ref().nullable().hidden().defaultRaw(`NULL`), - place_id: p.integer().nullable().persist(false).defaultRaw(`NULL`), + place: () => p.manyToOne(Places).ref().nullable().hidden().defaultRaw(`NULL`).index('idx_budget_items_place_id'), + place_id: p.integer().nullable().persist(false).defaultRaw(`NULL`).index('idx_budget_items_place_id'), budget_item_members_collection: () => p.oneToMany(BudgetItemMembers).mappedBy('budgetItem').hidden(), budget_item_payers_collection: () => p.oneToMany(BudgetItemPayers).mappedBy('budgetItem').hidden(), file_links_collection: () => p.oneToMany(FileLinks).mappedBy('budgetItem').hidden(), diff --git a/server/src/db/entities/BudgetSettlements.entity.ts b/server/src/db/entities/BudgetSettlements.entity.ts index c0543b20a..e8454f936 100644 --- a/server/src/db/entities/BudgetSettlements.entity.ts +++ b/server/src/db/entities/BudgetSettlements.entity.ts @@ -30,14 +30,14 @@ export const BudgetSettlementsSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_budget_settlements_trip'), trip_id: p.integer().persist(false).index('idx_budget_settlements_trip'), - fromUser: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - from_user_id: p.integer().persist(false), - toUser: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - to_user_id: p.integer().persist(false), + fromUser: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_budget_settlements_from_user_id'), + from_user_id: p.integer().persist(false).index('idx_budget_settlements_from_user_id'), + toUser: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_budget_settlements_to_user_id'), + to_user_id: p.integer().persist(false).index('idx_budget_settlements_to_user_id'), amount: p.double().defaultRaw(`0`), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - createdByUser: () => p.manyToOne(Users).ref().deleteRule('no action').nullable().hidden(), - created_by_user_id: p.integer().nullable().persist(false), + createdByUser: () => p.manyToOne(Users).ref().deleteRule('no action').nullable().hidden().index('idx_budget_settlements_created_by_user_id'), + created_by_user_id: p.integer().nullable().persist(false).index('idx_budget_settlements_created_by_user_id'), currency: p.text().nullable(), exchange_rate: p.double().defaultRaw(`1`), settled_at: p.text().nullable(), diff --git a/server/src/db/entities/Categories.entity.ts b/server/src/db/entities/Categories.entity.ts index f087532bf..aa9258a4e 100644 --- a/server/src/db/entities/Categories.entity.ts +++ b/server/src/db/entities/Categories.entity.ts @@ -26,8 +26,8 @@ export const CategoriesSchema = defineEntity({ name: p.text(), color: p.text().nullable(), icon: p.text().nullable(), - user: () => p.manyToOne(Users).ref().nullable().hidden(), - user_id: p.integer().nullable().persist(false), + user: () => p.manyToOne(Users).ref().nullable().hidden().index('idx_categories_user_id'), + user_id: p.integer().nullable().persist(false).index('idx_categories_user_id'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), collection_places_collection: () => p.oneToMany(CollectionPlaces).mappedBy('category').hidden(), places_collection: () => p.oneToMany(Places).mappedBy('category').hidden(), diff --git a/server/src/db/entities/CollabLinks.entity.ts b/server/src/db/entities/CollabLinks.entity.ts index 9351f216b..119a653a1 100644 --- a/server/src/db/entities/CollabLinks.entity.ts +++ b/server/src/db/entities/CollabLinks.entity.ts @@ -25,8 +25,8 @@ export const CollabLinksSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_collab_links_trip'), trip_id: p.integer().persist(false).index('idx_collab_links_trip'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collab_links_user_id'), + user_id: p.integer().persist(false).index('idx_collab_links_user_id'), title: p.text(), url: p.text(), pinned: p.integer().nullable(), diff --git a/server/src/db/entities/CollabMessageReactions.entity.ts b/server/src/db/entities/CollabMessageReactions.entity.ts index 03a08475f..71f41303f 100644 --- a/server/src/db/entities/CollabMessageReactions.entity.ts +++ b/server/src/db/entities/CollabMessageReactions.entity.ts @@ -23,8 +23,8 @@ export const CollabMessageReactionsSchema = defineEntity({ id: p.integer().primary(), message: () => p.manyToOne(CollabMessages).ref().deleteRule('cascade').hidden().index('idx_collab_reactions_msg'), message_id: p.integer().persist(false).index('idx_collab_reactions_msg'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collab_message_reactions_user_id'), + user_id: p.integer().persist(false).index('idx_collab_message_reactions_user_id'), emoji: p.text(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, diff --git a/server/src/db/entities/CollabMessages.entity.ts b/server/src/db/entities/CollabMessages.entity.ts index 9b6865bd6..8774c8174 100644 --- a/server/src/db/entities/CollabMessages.entity.ts +++ b/server/src/db/entities/CollabMessages.entity.ts @@ -30,13 +30,13 @@ export const CollabMessagesSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_collab_messages_trip'), trip_id: p.integer().persist(false).index('idx_collab_messages_trip'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collab_messages_user_id'), + user_id: p.integer().persist(false).index('idx_collab_messages_user_id'), text: p.text(), - reply_to: p.integer().nullable().persist(false), + reply_to: p.integer().nullable().persist(false).index('idx_collab_messages_reply_to'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), deleted: p.integer().nullable(), - replyToRef: () => p.manyToOne(CollabMessages).ref().joinColumn('reply_to').nullable().hidden(), + replyToRef: () => p.manyToOne(CollabMessages).ref().joinColumn('reply_to').nullable().hidden().index('idx_collab_messages_reply_to'), collab_message_reactions_collection: () => p.oneToMany(CollabMessageReactions).mappedBy('message').hidden(), collab_messages_collection: () => p.oneToMany(CollabMessages).mappedBy('replyToRef').hidden(), trip_files_collection: () => p.oneToMany(TripFiles).mappedBy('message').hidden(), diff --git a/server/src/db/entities/CollabNotes.entity.ts b/server/src/db/entities/CollabNotes.entity.ts index 4784161f7..1da2a82ea 100644 --- a/server/src/db/entities/CollabNotes.entity.ts +++ b/server/src/db/entities/CollabNotes.entity.ts @@ -30,8 +30,8 @@ export const CollabNotesSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_collab_notes_trip'), trip_id: p.integer().persist(false).index('idx_collab_notes_trip'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collab_notes_user_id'), + user_id: p.integer().persist(false).index('idx_collab_notes_user_id'), category: p.text().nullable(), title: p.text(), content: p.text().nullable(), diff --git a/server/src/db/entities/CollabPollVotes.entity.ts b/server/src/db/entities/CollabPollVotes.entity.ts index 45f877865..ef4c1b1f7 100644 --- a/server/src/db/entities/CollabPollVotes.entity.ts +++ b/server/src/db/entities/CollabPollVotes.entity.ts @@ -23,8 +23,8 @@ export const CollabPollVotesSchema = defineEntity({ id: p.integer().primary(), poll: () => p.manyToOne(CollabPolls).ref().deleteRule('cascade').hidden(), poll_id: p.integer().persist(false), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collab_poll_votes_user_id'), + user_id: p.integer().persist(false).index('idx_collab_poll_votes_user_id'), option_index: p.integer(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, diff --git a/server/src/db/entities/CollabPolls.entity.ts b/server/src/db/entities/CollabPolls.entity.ts index 080d40195..5e80a5568 100644 --- a/server/src/db/entities/CollabPolls.entity.ts +++ b/server/src/db/entities/CollabPolls.entity.ts @@ -28,8 +28,8 @@ export const CollabPollsSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_collab_polls_trip'), trip_id: p.integer().persist(false).index('idx_collab_polls_trip'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collab_polls_user_id'), + user_id: p.integer().persist(false).index('idx_collab_polls_user_id'), question: p.text(), options: p.text(), multiple: p.integer().nullable(), diff --git a/server/src/db/entities/CollectionPlaceRatings.entity.ts b/server/src/db/entities/CollectionPlaceRatings.entity.ts index 0ebef9482..7713f023f 100644 --- a/server/src/db/entities/CollectionPlaceRatings.entity.ts +++ b/server/src/db/entities/CollectionPlaceRatings.entity.ts @@ -23,8 +23,8 @@ export const CollectionPlaceRatingsSchema = defineEntity({ id: p.integer().primary(), collectionPlace: () => p.manyToOne(CollectionPlaces).ref().deleteRule('cascade').hidden().index('idx_collection_place_ratings_place'), collection_place_id: p.integer().persist(false).index('idx_collection_place_ratings_place'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collection_place_ratings_user_id'), + user_id: p.integer().persist(false).index('idx_collection_place_ratings_user_id'), rating: p.integer(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, diff --git a/server/src/db/entities/CollectionPlaces.entity.ts b/server/src/db/entities/CollectionPlaces.entity.ts index 2d76ca8ee..430ce2602 100644 --- a/server/src/db/entities/CollectionPlaces.entity.ts +++ b/server/src/db/entities/CollectionPlaces.entity.ts @@ -52,16 +52,16 @@ export const CollectionPlacesSchema = defineEntity({ id: p.integer().primary(), collection: () => p.manyToOne(Collections).ref().deleteRule('cascade').hidden().index('idx_collection_places_collection'), collection_id: p.integer().persist(false).index('idx_collection_places_collection'), - owner: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - owner_id: p.integer().persist(false), - saved_by: p.integer().nullable().persist(false), + owner: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collection_places_owner_id'), + owner_id: p.integer().persist(false).index('idx_collection_places_owner_id'), + saved_by: p.integer().nullable().persist(false).index('idx_collection_places_saved_by'), name: p.text(), description: p.text().nullable(), lat: p.double().nullable(), lng: p.double().nullable(), address: p.text().nullable(), - category: () => p.manyToOne(Categories).ref().nullable().hidden(), - category_id: p.integer().nullable().persist(false), + category: () => p.manyToOne(Categories).ref().nullable().hidden().index('idx_collection_places_category_id'), + category_id: p.integer().nullable().persist(false).index('idx_collection_places_category_id'), price: p.double().nullable(), currency: p.text().nullable(), notes: p.text().nullable(), @@ -78,7 +78,7 @@ export const CollectionPlacesSchema = defineEntity({ sort_order: p.integer().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), updated_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - savedByRef: () => p.manyToOne(Users).ref().joinColumn('saved_by').nullable().hidden(), + savedByRef: () => p.manyToOne(Users).ref().joinColumn('saved_by').nullable().hidden().index('idx_collection_places_saved_by'), collection_place_labels: () => p.manyToMany(CollectionLabels).pivotTable('collection_place_labels').joinColumn('collection_place_id').inverseJoinColumn('label_id').hidden(), collection_place_tags: () => p.manyToMany(Tags).pivotTable('collection_place_tags').joinColumn('collection_place_id').inverseJoinColumn('tag_id').hidden(), collection_place_ratings_collection: () => p.oneToMany(CollectionPlaceRatings).mappedBy('collectionPlace').hidden(), diff --git a/server/src/db/entities/Collections.entity.ts b/server/src/db/entities/Collections.entity.ts index b7718755f..a11dc4da9 100644 --- a/server/src/db/entities/Collections.entity.ts +++ b/server/src/db/entities/Collections.entity.ts @@ -30,8 +30,8 @@ export const CollectionsSchema = defineEntity({ repository: () => CollectionsRepository, properties: { id: p.integer().primary(), - owner: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - owner_id: p.integer().persist(false), + owner: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_collections_owner_id'), + owner_id: p.integer().persist(false).index('idx_collections_owner_id'), name: p.text(), description: p.text().nullable(), color: p.text().nullable(), diff --git a/server/src/db/entities/DawarichVisitSuggestions.entity.ts b/server/src/db/entities/DawarichVisitSuggestions.entity.ts index 07b6198ca..6cba6a2f7 100644 --- a/server/src/db/entities/DawarichVisitSuggestions.entity.ts +++ b/server/src/db/entities/DawarichVisitSuggestions.entity.ts @@ -70,13 +70,13 @@ export const DawarichVisitSuggestionsSchema = defineEntity({ country_code: p.text().nullable(), state: p.text().default('new'), target: p.text().nullable(), - acceptedPlace: () => p.manyToOne(Places).ref().nullable().hidden(), - accepted_place_id: p.integer().nullable().persist(false), + acceptedPlace: () => p.manyToOne(Places).ref().nullable().hidden().index('idx_dawarich_visit_suggestions_accepted_place_id'), + accepted_place_id: p.integer().nullable().persist(false).index('idx_dawarich_visit_suggestions_accepted_place_id'), accepted_journal_entry_id: p.integer().nullable(), - acceptedBucketListItem: () => p.manyToOne(BucketList).ref().nullable().hidden(), - accepted_bucket_list_item_id: p.integer().nullable().persist(false), - matchedBucketListItem: () => p.manyToOne(BucketList).ref().nullable().hidden(), - matched_bucket_list_item_id: p.integer().nullable().persist(false), + acceptedBucketListItem: () => p.manyToOne(BucketList).ref().nullable().hidden().index('idx_dawarich_visit_suggestions_accepted_bucket_list_item_id'), + accepted_bucket_list_item_id: p.integer().nullable().persist(false).index('idx_dawarich_visit_suggestions_accepted_bucket_list_item_id'), + matchedBucketListItem: () => p.manyToOne(BucketList).ref().nullable().hidden().index('idx_dawarich_visit_suggestions_matched_bucket_list_item_id'), + matched_bucket_list_item_id: p.integer().nullable().persist(false).index('idx_dawarich_visit_suggestions_matched_bucket_list_item_id'), source_hash: p.text(), accepted_hash: p.text().nullable(), source_missing_at: p.text().nullable(), diff --git a/server/src/db/entities/DayAccommodations.entity.ts b/server/src/db/entities/DayAccommodations.entity.ts index 71a86ea1e..82a5bc86c 100644 --- a/server/src/db/entities/DayAccommodations.entity.ts +++ b/server/src/db/entities/DayAccommodations.entity.ts @@ -31,8 +31,8 @@ export const DayAccommodationsSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_day_accommodations_trip_id'), trip_id: p.integer().persist(false).index('idx_day_accommodations_trip_id'), - place: () => p.manyToOne(Places).ref().nullable().hidden(), - place_id: p.integer().nullable().persist(false), + place: () => p.manyToOne(Places).ref().nullable().hidden().index('idx_day_accommodations_place_id'), + place_id: p.integer().nullable().persist(false).index('idx_day_accommodations_place_id'), startDay: () => p.manyToOne(Days).ref().deleteRule('cascade').hidden().index('idx_day_accommodations_start_day_id'), start_day_id: p.integer().persist(false).index('idx_day_accommodations_start_day_id'), endDay: () => p.manyToOne(Days).ref().deleteRule('cascade').hidden().index('idx_day_accommodations_end_day_id'), diff --git a/server/src/db/entities/DayNotes.entity.ts b/server/src/db/entities/DayNotes.entity.ts index 603ec3dff..f8b2d9566 100644 --- a/server/src/db/entities/DayNotes.entity.ts +++ b/server/src/db/entities/DayNotes.entity.ts @@ -26,8 +26,8 @@ export const DayNotesSchema = defineEntity({ id: p.integer().primary(), day: () => p.manyToOne(Days).ref().deleteRule('cascade').hidden().index('idx_day_notes_day_id'), day_id: p.integer().persist(false).index('idx_day_notes_day_id'), - trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden(), - trip_id: p.integer().persist(false), + trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_day_notes_trip_id'), + trip_id: p.integer().persist(false).index('idx_day_notes_trip_id'), text: p.text(), time: p.text().nullable(), icon: p.text().nullable(), diff --git a/server/src/db/entities/DocumentConnections.entity.ts b/server/src/db/entities/DocumentConnections.entity.ts index 62e2b1f98..f199f0769 100644 --- a/server/src/db/entities/DocumentConnections.entity.ts +++ b/server/src/db/entities/DocumentConnections.entity.ts @@ -36,8 +36,8 @@ export const DocumentConnectionsSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_document_connections_trip'), trip_id: p.integer().persist(false).index('idx_document_connections_trip'), - provider: () => p.manyToOne(DocumentProviders).ref().deleteRule('cascade').hidden(), - provider_id: p.text().persist(false), + provider: () => p.manyToOne(DocumentProviders).ref().deleteRule('cascade').hidden().index('idx_document_connections_provider_id'), + provider_id: p.text().persist(false).index('idx_document_connections_provider_id'), ownerUser: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_document_connections_owner'), owner_user_id: p.integer().persist(false).index('idx_document_connections_owner'), base_url: p.text(), diff --git a/server/src/db/entities/DocumentSyncItems.entity.ts b/server/src/db/entities/DocumentSyncItems.entity.ts index c5f6af221..07eee59ca 100644 --- a/server/src/db/entities/DocumentSyncItems.entity.ts +++ b/server/src/db/entities/DocumentSyncItems.entity.ts @@ -71,8 +71,8 @@ export const DocumentSyncItemsSchema = defineEntity({ link_id: p.integer().persist(false), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden(), trip_id: p.integer().persist(false), - file: () => p.manyToOne(TripFiles).ref().nullable().hidden(), - file_id: p.integer().nullable().persist(false), + file: () => p.manyToOne(TripFiles).ref().nullable().hidden().index('idx_document_sync_items_file_id'), + file_id: p.integer().nullable().persist(false).index('idx_document_sync_items_file_id'), trek_doc_uid: p.text(), remote_id: p.text().nullable(), remote_name: p.text().nullable(), diff --git a/server/src/db/entities/FileLinks.entity.ts b/server/src/db/entities/FileLinks.entity.ts index a324b82e8..52f7a5844 100644 --- a/server/src/db/entities/FileLinks.entity.ts +++ b/server/src/db/entities/FileLinks.entity.ts @@ -39,12 +39,12 @@ export const FileLinksSchema = defineEntity({ id: p.integer().primary(), file: () => p.manyToOne(TripFiles).ref().deleteRule('cascade').hidden(), file_id: p.integer().persist(false), - reservation: () => p.manyToOne(Reservations).ref().deleteRule('cascade').nullable().hidden(), - reservation_id: p.integer().nullable().persist(false), - assignment: () => p.manyToOne(DayAssignments).ref().deleteRule('cascade').nullable().hidden(), - assignment_id: p.integer().nullable().persist(false), - place: () => p.manyToOne(Places).ref().deleteRule('cascade').nullable().hidden(), - place_id: p.integer().nullable().persist(false), + reservation: () => p.manyToOne(Reservations).ref().deleteRule('cascade').nullable().hidden().index('idx_file_links_reservation_id'), + reservation_id: p.integer().nullable().persist(false).index('idx_file_links_reservation_id'), + assignment: () => p.manyToOne(DayAssignments).ref().deleteRule('cascade').nullable().hidden().index('idx_file_links_assignment_id'), + assignment_id: p.integer().nullable().persist(false).index('idx_file_links_assignment_id'), + place: () => p.manyToOne(Places).ref().deleteRule('cascade').nullable().hidden().index('idx_file_links_place_id'), + place_id: p.integer().nullable().persist(false).index('idx_file_links_place_id'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), budgetItem: () => p.manyToOne(BudgetItems).ref().nullable().hidden().index('idx_file_links_budget_item_id'), budget_item_id: p.integer().nullable().persist(false).index('idx_file_links_budget_item_id'), diff --git a/server/src/db/entities/IdempotencyKeys.entity.ts b/server/src/db/entities/IdempotencyKeys.entity.ts index 4cb740b6a..cada8fa6b 100644 --- a/server/src/db/entities/IdempotencyKeys.entity.ts +++ b/server/src/db/entities/IdempotencyKeys.entity.ts @@ -21,8 +21,8 @@ export const IdempotencyKeysSchema = defineEntity({ uniques: [{ properties: ['key', 'user', 'method', 'path'] }], properties: { key: p.text().primary(), - user: () => p.manyToOne(Users).primary().ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).primary().ref().deleteRule('cascade').hidden().index('idx_idempotency_keys_user_id'), + user_id: p.integer().persist(false).index('idx_idempotency_keys_user_id'), method: p.text().primary(), path: p.text().primary(), status_code: p.integer(), diff --git a/server/src/db/entities/InviteTokens.entity.ts b/server/src/db/entities/InviteTokens.entity.ts index dbfcf7bef..1d775e41f 100644 --- a/server/src/db/entities/InviteTokens.entity.ts +++ b/server/src/db/entities/InviteTokens.entity.ts @@ -28,10 +28,10 @@ export const InviteTokensSchema = defineEntity({ max_uses: p.integer().default(1), used_count: p.integer().default(0), expires_at: p.text().nullable(), - created_by: p.integer().persist(false), + created_by: p.integer().persist(false).index('idx_invite_tokens_created_by'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - trip: () => p.manyToOne(Trips).ref().nullable().hidden(), - trip_id: p.integer().nullable().persist(false), - createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').deleteRule('cascade').hidden(), + trip: () => p.manyToOne(Trips).ref().nullable().hidden().index('idx_invite_tokens_trip_id'), + trip_id: p.integer().nullable().persist(false).index('idx_invite_tokens_trip_id'), + createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').deleteRule('cascade').hidden().index('idx_invite_tokens_created_by'), }, }); diff --git a/server/src/db/entities/JourneyBooks.entity.ts b/server/src/db/entities/JourneyBooks.entity.ts index 29bcdb362..9af416208 100644 --- a/server/src/db/entities/JourneyBooks.entity.ts +++ b/server/src/db/entities/JourneyBooks.entity.ts @@ -30,11 +30,11 @@ export const JourneyBooksSchema = defineEntity({ title: p.text().default(''), document: p.text(), version: p.integer().default(1), - created_by: p.integer().nullable().persist(false), - updated_by: p.integer().nullable().persist(false), + created_by: p.integer().nullable().persist(false).index('idx_journey_books_created_by'), + updated_by: p.integer().nullable().persist(false).index('idx_journey_books_updated_by'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), updated_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - updatedByRef: () => p.manyToOne(Users).ref().joinColumn('updated_by').nullable().hidden(), - createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').nullable().hidden(), + updatedByRef: () => p.manyToOne(Users).ref().joinColumn('updated_by').nullable().hidden().index('idx_journey_books_updated_by'), + createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').nullable().hidden().index('idx_journey_books_created_by'), }, }); diff --git a/server/src/db/entities/JourneyEntries.entity.ts b/server/src/db/entities/JourneyEntries.entity.ts index ee24b7b41..0240f66df 100644 --- a/server/src/db/entities/JourneyEntries.entity.ts +++ b/server/src/db/entities/JourneyEntries.entity.ts @@ -62,12 +62,12 @@ export const JourneyEntriesSchema = defineEntity({ id: p.integer().primary(), journey: () => p.manyToOne(Journeys).ref().deleteRule('cascade').hidden(), journey_id: p.integer().persist(false), - sourceTrip: () => p.manyToOne(Trips).ref().nullable().hidden(), - source_trip_id: p.integer().nullable().persist(false), + sourceTrip: () => p.manyToOne(Trips).ref().nullable().hidden().index('idx_journey_entries_source_trip_id'), + source_trip_id: p.integer().nullable().persist(false).index('idx_journey_entries_source_trip_id'), sourcePlace: () => p.manyToOne(Places).ref().nullable().hidden().index('idx_journey_entries_source'), source_place_id: p.integer().nullable().persist(false).index('idx_journey_entries_source'), - author: () => p.manyToOne(Users).ref().hidden(), - author_id: p.integer().persist(false), + author: () => p.manyToOne(Users).ref().hidden().index('idx_journey_entries_author_id'), + author_id: p.integer().persist(false).index('idx_journey_entries_author_id'), type: p.text(), title: p.text().nullable(), story: p.text().nullable(), diff --git a/server/src/db/entities/JourneyPhotos.entity.ts b/server/src/db/entities/JourneyPhotos.entity.ts index 590e21679..f81d30be9 100644 --- a/server/src/db/entities/JourneyPhotos.entity.ts +++ b/server/src/db/entities/JourneyPhotos.entity.ts @@ -29,8 +29,8 @@ export const JourneyPhotosSchema = defineEntity({ id: p.integer().primary(), journey: () => p.manyToOne(Journeys).ref().deleteRule('cascade').hidden().index('idx_journey_photos_journey'), journey_id: p.integer().persist(false).index('idx_journey_photos_journey'), - photo: () => p.manyToOne(TrekPhotos).ref().deleteRule('cascade').hidden(), - photo_id: p.integer().persist(false), + photo: () => p.manyToOne(TrekPhotos).ref().deleteRule('cascade').hidden().index('idx_journey_photos_photo_id'), + photo_id: p.integer().persist(false).index('idx_journey_photos_photo_id'), caption: p.text().nullable(), shared: p.integer().nullable(), sort_order: p.integer().nullable(), diff --git a/server/src/db/entities/JourneyShareTokens.entity.ts b/server/src/db/entities/JourneyShareTokens.entity.ts index ecc9d9117..f38899e15 100644 --- a/server/src/db/entities/JourneyShareTokens.entity.ts +++ b/server/src/db/entities/JourneyShareTokens.entity.ts @@ -28,12 +28,12 @@ export const JourneyShareTokensSchema = defineEntity({ journey: () => p.oneToOne(Journeys).ref().deleteRule('cascade').hidden().unique('idx_journey_share_journey'), journey_id: p.integer().persist(false).unique('idx_journey_share_journey'), token: p.text(), - created_by: p.integer().persist(false), + created_by: p.integer().persist(false).index('idx_journey_share_tokens_created_by'), share_timeline: p.integer().nullable(), share_gallery: p.integer().nullable(), share_map: p.integer().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), newest_first: p.integer().default(0), - createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').hidden(), + createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').hidden().index('idx_journey_share_tokens_created_by'), }, }); diff --git a/server/src/db/entities/JourneyTrips.entity.ts b/server/src/db/entities/JourneyTrips.entity.ts index a55b1ac54..bea185604 100644 --- a/server/src/db/entities/JourneyTrips.entity.ts +++ b/server/src/db/entities/JourneyTrips.entity.ts @@ -20,8 +20,8 @@ export const JourneyTripsSchema = defineEntity({ properties: { journey: () => p.manyToOne(Journeys).primary().ref().hidden().index('idx_journey_trips_journey'), journey_id: p.integer().persist(false).index('idx_journey_trips_journey'), - trip: () => p.manyToOne(Trips).primary().ref().hidden(), - trip_id: p.integer().persist(false), + trip: () => p.manyToOne(Trips).primary().ref().hidden().index('idx_journey_trips_trip_id'), + trip_id: p.integer().persist(false).index('idx_journey_trips_trip_id'), added_at: p.integer(), }, }); diff --git a/server/src/db/entities/McpTokens.entity.ts b/server/src/db/entities/McpTokens.entity.ts index d3c8421c2..485e5ace6 100644 --- a/server/src/db/entities/McpTokens.entity.ts +++ b/server/src/db/entities/McpTokens.entity.ts @@ -23,8 +23,8 @@ export const McpTokensSchema = defineEntity({ repository: () => McpTokensRepository, properties: { id: p.integer().primary(), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_mcp_tokens_user_id'), + user_id: p.integer().persist(false).index('idx_mcp_tokens_user_id'), name: p.text(), token_hash: p.text().unique('idx_mcp_tokens_hash'), token_prefix: p.text(), diff --git a/server/src/db/entities/Notifications.entity.ts b/server/src/db/entities/Notifications.entity.ts index 775075d67..92fe54d5a 100644 --- a/server/src/db/entities/Notifications.entity.ts +++ b/server/src/db/entities/Notifications.entity.ts @@ -47,8 +47,8 @@ export const NotificationsSchema = defineEntity({ type: p.text(), scope: p.text(), target: p.integer(), - sender: () => p.manyToOne(Users).ref().nullable().hidden(), - sender_id: p.integer().nullable().persist(false), + sender: () => p.manyToOne(Users).ref().nullable().hidden().index('idx_notifications_sender_id'), + sender_id: p.integer().nullable().persist(false).index('idx_notifications_sender_id'), recipient: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), recipient_id: p.integer().persist(false), title_key: p.text(), diff --git a/server/src/db/entities/OauthConsents.entity.ts b/server/src/db/entities/OauthConsents.entity.ts index 71d867469..d0730273f 100644 --- a/server/src/db/entities/OauthConsents.entity.ts +++ b/server/src/db/entities/OauthConsents.entity.ts @@ -23,8 +23,8 @@ export const OauthConsentsSchema = defineEntity({ id: p.integer().primary(), client: () => p.manyToOne(OauthClients).ref().name('client_id').deleteRule('cascade').hidden().referencedColumnNames('client_id'), client_id: p.text().persist(false), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_oauth_consents_user_id'), + user_id: p.integer().persist(false).index('idx_oauth_consents_user_id'), scopes: p.text().default('[]'), updated_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, diff --git a/server/src/db/entities/OauthTokens.entity.ts b/server/src/db/entities/OauthTokens.entity.ts index b7e912614..0b2b7bdb0 100644 --- a/server/src/db/entities/OauthTokens.entity.ts +++ b/server/src/db/entities/OauthTokens.entity.ts @@ -33,8 +33,8 @@ export const OauthTokensSchema = defineEntity({ ], properties: { id: p.integer().primary(), - client: () => p.manyToOne(OauthClients).ref().name('client_id').deleteRule('cascade').hidden().referencedColumnNames('client_id'), - client_id: p.text().persist(false), + client: () => p.manyToOne(OauthClients).ref().name('client_id').deleteRule('cascade').hidden().index('idx_oauth_tokens_client_id').referencedColumnNames('client_id'), + client_id: p.text().persist(false).index('idx_oauth_tokens_client_id'), user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_oauth_tokens_user'), user_id: p.integer().persist(false).index('idx_oauth_tokens_user'), access_token_hash: p.text().unique('idx_oauth_tokens_access'), diff --git a/server/src/db/entities/PackingBags.entity.ts b/server/src/db/entities/PackingBags.entity.ts index 815907046..0eb6f250f 100644 --- a/server/src/db/entities/PackingBags.entity.ts +++ b/server/src/db/entities/PackingBags.entity.ts @@ -26,15 +26,15 @@ export const PackingBagsSchema = defineEntity({ repository: () => PackingBagsRepository, properties: { id: p.integer().primary(), - trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden(), - trip_id: p.integer().persist(false), + trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_packing_bags_trip_id'), + trip_id: p.integer().persist(false).index('idx_packing_bags_trip_id'), name: p.text(), color: p.text().default('#6366f1'), weight_limit_grams: p.integer().nullable(), sort_order: p.integer().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - user: () => p.manyToOne(Users).ref().nullable().hidden().defaultRaw(`NULL`), - user_id: p.integer().nullable().persist(false).defaultRaw(`NULL`), + user: () => p.manyToOne(Users).ref().nullable().hidden().defaultRaw(`NULL`).index('idx_packing_bags_user_id'), + user_id: p.integer().nullable().persist(false).defaultRaw(`NULL`).index('idx_packing_bags_user_id'), packing_bag_members: () => p.manyToMany(Users).pivotTable('packing_bag_members').joinColumn('bag_id').inverseJoinColumn('user_id').hidden(), packing_items_collection: () => p.oneToMany(PackingItems).mappedBy('bag').hidden(), }, diff --git a/server/src/db/entities/PackingCategoryAssignees.entity.ts b/server/src/db/entities/PackingCategoryAssignees.entity.ts index d88548fef..816df7ee5 100644 --- a/server/src/db/entities/PackingCategoryAssignees.entity.ts +++ b/server/src/db/entities/PackingCategoryAssignees.entity.ts @@ -22,7 +22,7 @@ export const PackingCategoryAssigneesSchema = defineEntity({ trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden(), trip_id: p.integer().persist(false), category_name: p.text(), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_packing_category_assignees_user_id'), + user_id: p.integer().persist(false).index('idx_packing_category_assignees_user_id'), }, }); diff --git a/server/src/db/entities/PackingItemContributors.entity.ts b/server/src/db/entities/PackingItemContributors.entity.ts index 315927fcb..4624be3aa 100644 --- a/server/src/db/entities/PackingItemContributors.entity.ts +++ b/server/src/db/entities/PackingItemContributors.entity.ts @@ -22,8 +22,8 @@ export const PackingItemContributorsSchema = defineEntity({ properties: { item: () => p.manyToOne(PackingItems).primary().ref().hidden(), item_id: p.integer().persist(false), - user: () => p.manyToOne(Users).primary().ref().hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).primary().ref().hidden().index('idx_packing_item_contributors_user_id'), + user_id: p.integer().persist(false).index('idx_packing_item_contributors_user_id'), status: p.text().default('accepted'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, diff --git a/server/src/db/entities/PackingItems.entity.ts b/server/src/db/entities/PackingItems.entity.ts index 94b422f2b..67460d250 100644 --- a/server/src/db/entities/PackingItems.entity.ts +++ b/server/src/db/entities/PackingItems.entity.ts @@ -43,13 +43,13 @@ export const PackingItemsSchema = defineEntity({ sort_order: p.integer().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), weight_grams: p.integer().nullable(), - bag: () => p.manyToOne(PackingBags).ref().nullable().hidden(), - bag_id: p.integer().nullable().persist(false), + bag: () => p.manyToOne(PackingBags).ref().nullable().hidden().index('idx_packing_items_bag_id'), + bag_id: p.integer().nullable().persist(false).index('idx_packing_items_bag_id'), quantity: p.integer().default(1), updated_at: p.type(DbTimestampType).nullable(), is_private: p.integer().default(0), - owner: () => p.manyToOne(Users).ref().nullable().hidden(), - owner_id: p.integer().nullable().persist(false), + owner: () => p.manyToOne(Users).ref().nullable().hidden().index('idx_packing_items_owner_id'), + owner_id: p.integer().nullable().persist(false).index('idx_packing_items_owner_id'), packed_quantity: p.integer().nullable(), packing_item_contributors: () => p.manyToMany(Users).pivotTable('packing_item_contributors').pivotEntity(() => PackingItemContributors).joinColumn('item_id').inverseJoinColumn('user_id').hidden(), packing_item_recipients: () => p.manyToMany(Users).pivotTable('packing_item_recipients').joinColumn('item_id').inverseJoinColumn('user_id').hidden(), diff --git a/server/src/db/entities/PackingTemplateCategories.entity.ts b/server/src/db/entities/PackingTemplateCategories.entity.ts index 748f4d3d0..75e434e3f 100644 --- a/server/src/db/entities/PackingTemplateCategories.entity.ts +++ b/server/src/db/entities/PackingTemplateCategories.entity.ts @@ -18,8 +18,8 @@ export const PackingTemplateCategoriesSchema = defineEntity({ repository: () => PackingTemplateCategoriesRepository, properties: { id: p.integer().primary(), - template: () => p.manyToOne(PackingTemplates).ref().deleteRule('cascade').hidden(), - template_id: p.integer().persist(false), + template: () => p.manyToOne(PackingTemplates).ref().deleteRule('cascade').hidden().index('idx_packing_template_categories_template_id'), + template_id: p.integer().persist(false).index('idx_packing_template_categories_template_id'), name: p.text(), sort_order: p.integer().default(0), packing_template_items_collection: () => p.oneToMany(PackingTemplateItems).mappedBy('category').hidden(), diff --git a/server/src/db/entities/PackingTemplateItems.entity.ts b/server/src/db/entities/PackingTemplateItems.entity.ts index 891ee4baa..6fd962af7 100644 --- a/server/src/db/entities/PackingTemplateItems.entity.ts +++ b/server/src/db/entities/PackingTemplateItems.entity.ts @@ -19,8 +19,8 @@ export const PackingTemplateItemsSchema = defineEntity({ repository: () => PackingTemplateItemsRepository, properties: { id: p.integer().primary(), - category: () => p.manyToOne(PackingTemplateCategories).ref().deleteRule('cascade').hidden(), - category_id: p.integer().persist(false), + category: () => p.manyToOne(PackingTemplateCategories).ref().deleteRule('cascade').hidden().index('idx_packing_template_items_category_id'), + category_id: p.integer().persist(false).index('idx_packing_template_items_category_id'), name: p.text(), sort_order: p.integer().default(0), weight_grams: p.integer().nullable(), diff --git a/server/src/db/entities/PackingTemplates.entity.ts b/server/src/db/entities/PackingTemplates.entity.ts index fc35b6231..8a47a69ad 100644 --- a/server/src/db/entities/PackingTemplates.entity.ts +++ b/server/src/db/entities/PackingTemplates.entity.ts @@ -20,9 +20,9 @@ export const PackingTemplatesSchema = defineEntity({ properties: { id: p.integer().primary(), name: p.text(), - created_by: p.integer().persist(false), + created_by: p.integer().persist(false).index('idx_packing_templates_created_by'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').deleteRule('cascade').hidden(), + createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').deleteRule('cascade').hidden().index('idx_packing_templates_created_by'), packing_template_categories_collection: () => p.oneToMany(PackingTemplateCategories).mappedBy('template').hidden(), }, }); diff --git a/server/src/db/entities/PlaceRatings.entity.ts b/server/src/db/entities/PlaceRatings.entity.ts index dbaa519d7..5bc3488e0 100644 --- a/server/src/db/entities/PlaceRatings.entity.ts +++ b/server/src/db/entities/PlaceRatings.entity.ts @@ -23,8 +23,8 @@ export const PlaceRatingsSchema = defineEntity({ id: p.integer().primary(), place: () => p.manyToOne(Places).ref().deleteRule('cascade').hidden().index('idx_place_ratings_place'), place_id: p.integer().persist(false).index('idx_place_ratings_place'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_place_ratings_user_id'), + user_id: p.integer().persist(false).index('idx_place_ratings_user_id'), rating: p.integer(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, diff --git a/server/src/db/entities/ReservationDayPositions.entity.ts b/server/src/db/entities/ReservationDayPositions.entity.ts index 5dddf729e..19f94d78b 100644 --- a/server/src/db/entities/ReservationDayPositions.entity.ts +++ b/server/src/db/entities/ReservationDayPositions.entity.ts @@ -20,8 +20,8 @@ export const ReservationDayPositionsSchema = defineEntity({ properties: { reservation: () => p.manyToOne(Reservations).primary().ref().hidden(), reservation_id: p.integer().persist(false), - day: () => p.manyToOne(Days).primary().ref().hidden(), - day_id: p.integer().persist(false), + day: () => p.manyToOne(Days).primary().ref().hidden().index('idx_reservation_day_positions_day_id'), + day_id: p.integer().persist(false).index('idx_reservation_day_positions_day_id'), position: p.double(), }, }); diff --git a/server/src/db/entities/Reservations.entity.ts b/server/src/db/entities/Reservations.entity.ts index 8c946b908..2240fc19c 100644 --- a/server/src/db/entities/Reservations.entity.ts +++ b/server/src/db/entities/Reservations.entity.ts @@ -69,12 +69,12 @@ export const ReservationsSchema = defineEntity({ trip_id: p.integer().persist(false).index('idx_reservations_trip_id'), day: () => p.manyToOne(Days).ref().nullable().hidden().index('idx_reservations_day_id'), day_id: p.integer().nullable().persist(false).index('idx_reservations_day_id'), - endDay: () => p.manyToOne(Days).ref().nullable().hidden(), - end_day_id: p.integer().nullable().persist(false), - place: () => p.manyToOne(Places).ref().nullable().hidden(), - place_id: p.integer().nullable().persist(false), - assignment: () => p.manyToOne(DayAssignments).ref().nullable().hidden(), - assignment_id: p.integer().nullable().persist(false), + endDay: () => p.manyToOne(Days).ref().nullable().hidden().index('idx_reservations_end_day_id'), + end_day_id: p.integer().nullable().persist(false).index('idx_reservations_end_day_id'), + place: () => p.manyToOne(Places).ref().nullable().hidden().index('idx_reservations_place_id'), + place_id: p.integer().nullable().persist(false).index('idx_reservations_place_id'), + assignment: () => p.manyToOne(DayAssignments).ref().nullable().hidden().index('idx_reservations_assignment_id'), + assignment_id: p.integer().nullable().persist(false).index('idx_reservations_assignment_id'), title: p.text(), accommodation_id: p.text().nullable(), reservation_time: p.text().nullable(), diff --git a/server/src/db/entities/RoadtripDayBoundaries.entity.ts b/server/src/db/entities/RoadtripDayBoundaries.entity.ts index 1edce45ea..2366582d6 100644 --- a/server/src/db/entities/RoadtripDayBoundaries.entity.ts +++ b/server/src/db/entities/RoadtripDayBoundaries.entity.ts @@ -34,10 +34,10 @@ export const RoadtripDayBoundariesSchema = defineEntity({ trip: () => p.manyToOne(Trips).primary().ref().deleteRule('cascade').hidden(), trip_id: p.integer().persist(false), day_number: p.integer().primary(), - fromAssignment: () => p.manyToOne(DayAssignments).ref().deleteRule('cascade').hidden(), - from_assignment_id: p.integer().persist(false), - toAssignment: () => p.manyToOne(DayAssignments).ref().deleteRule('cascade').nullable().hidden(), - to_assignment_id: p.integer().nullable().persist(false), + fromAssignment: () => p.manyToOne(DayAssignments).ref().deleteRule('cascade').hidden().index('idx_roadtrip_day_boundaries_from_assignment_id'), + from_assignment_id: p.integer().persist(false).index('idx_roadtrip_day_boundaries_from_assignment_id'), + toAssignment: () => p.manyToOne(DayAssignments).ref().deleteRule('cascade').nullable().hidden().index('idx_roadtrip_day_boundaries_to_assignment_id'), + to_assignment_id: p.integer().nullable().persist(false).index('idx_roadtrip_day_boundaries_to_assignment_id'), fraction: p.double(), }, }); diff --git a/server/src/db/entities/ShareTokens.entity.ts b/server/src/db/entities/ShareTokens.entity.ts index 2ac1b161e..076a55ebb 100644 --- a/server/src/db/entities/ShareTokens.entity.ts +++ b/server/src/db/entities/ShareTokens.entity.ts @@ -29,10 +29,10 @@ export const ShareTokensSchema = defineEntity({ uniques: [{ properties: ['token'] }], properties: { id: p.integer().primary(), - trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden(), - trip_id: p.integer().persist(false), + trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_share_tokens_trip_id'), + trip_id: p.integer().persist(false).index('idx_share_tokens_trip_id'), token: p.text().index('idx_share_tokens_token'), - created_by: p.integer().persist(false), + created_by: p.integer().persist(false).index('idx_share_tokens_created_by'), share_map: p.integer().nullable(), share_bookings: p.integer().nullable(), share_packing: p.integer().nullable(), @@ -42,6 +42,6 @@ export const ShareTokensSchema = defineEntity({ expires_at: p.text().nullable(), share_travel_only: p.integer().default(0), share_hide_images: p.integer().default(0), - createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').hidden(), + createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').hidden().index('idx_share_tokens_created_by'), }, }); diff --git a/server/src/db/entities/Tags.entity.ts b/server/src/db/entities/Tags.entity.ts index 7c58f8e7e..c74fc3943 100644 --- a/server/src/db/entities/Tags.entity.ts +++ b/server/src/db/entities/Tags.entity.ts @@ -22,8 +22,8 @@ export const TagsSchema = defineEntity({ repository: () => TagsRepository, properties: { id: p.integer().primary(), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_tags_user_id'), + user_id: p.integer().persist(false).index('idx_tags_user_id'), name: p.text(), color: p.text().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), diff --git a/server/src/db/entities/TodoCategoryAssignees.entity.ts b/server/src/db/entities/TodoCategoryAssignees.entity.ts index 76003274d..82afd544e 100644 --- a/server/src/db/entities/TodoCategoryAssignees.entity.ts +++ b/server/src/db/entities/TodoCategoryAssignees.entity.ts @@ -22,7 +22,7 @@ export const TodoCategoryAssigneesSchema = defineEntity({ trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden(), trip_id: p.integer().persist(false), category_name: p.text(), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_todo_category_assignees_user_id'), + user_id: p.integer().persist(false).index('idx_todo_category_assignees_user_id'), }, }); diff --git a/server/src/db/entities/TodoItems.entity.ts b/server/src/db/entities/TodoItems.entity.ts index 206b2331e..564c89489 100644 --- a/server/src/db/entities/TodoItems.entity.ts +++ b/server/src/db/entities/TodoItems.entity.ts @@ -35,8 +35,8 @@ export const TodoItemsSchema = defineEntity({ sort_order: p.integer().nullable(), due_date: p.text().nullable(), description: p.text().nullable(), - assignedUser: () => p.manyToOne(Users).ref().nullable().hidden(), - assigned_user_id: p.integer().nullable().persist(false), + assignedUser: () => p.manyToOne(Users).ref().nullable().hidden().index('idx_todo_items_assigned_user_id'), + assigned_user_id: p.integer().nullable().persist(false).index('idx_todo_items_assigned_user_id'), priority: p.integer().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), reminded_at: p.type(DbTimestampType).nullable(), diff --git a/server/src/db/entities/TripAlbumLinks.entity.ts b/server/src/db/entities/TripAlbumLinks.entity.ts index df41280c2..1caad3b46 100644 --- a/server/src/db/entities/TripAlbumLinks.entity.ts +++ b/server/src/db/entities/TripAlbumLinks.entity.ts @@ -30,8 +30,8 @@ export const TripAlbumLinksSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_trip_album_links_trip'), trip_id: p.integer().persist(false).index('idx_trip_album_links_trip'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_trip_album_links_user_id'), + user_id: p.integer().persist(false).index('idx_trip_album_links_user_id'), provider: p.text(), album_id: p.text(), album_name: p.text().default(''), diff --git a/server/src/db/entities/TripDocumentLinks.entity.ts b/server/src/db/entities/TripDocumentLinks.entity.ts index c366ad487..8122be357 100644 --- a/server/src/db/entities/TripDocumentLinks.entity.ts +++ b/server/src/db/entities/TripDocumentLinks.entity.ts @@ -59,8 +59,8 @@ export const TripDocumentLinksSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_trip_document_links_trip'), trip_id: p.integer().persist(false).index('idx_trip_document_links_trip'), - connection: () => p.manyToOne(DocumentConnections).ref().deleteRule('cascade').hidden(), - connection_id: p.integer().persist(false), + connection: () => p.manyToOne(DocumentConnections).ref().deleteRule('cascade').hidden().index('idx_trip_document_links_connection_id'), + connection_id: p.integer().persist(false).index('idx_trip_document_links_connection_id'), provider_id: p.text(), remote_scope_key: p.text(), remote_root_id: p.text().nullable(), @@ -79,10 +79,10 @@ export const TripDocumentLinksSchema = defineEntity({ last_sync_error: p.text().nullable(), failure_count: p.integer().default(0), next_attempt_at: p.text().nullable(), - created_by: p.integer().nullable().persist(false), + created_by: p.integer().nullable().persist(false).index('idx_trip_document_links_created_by'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), updated_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').nullable().hidden(), + createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').nullable().hidden().index('idx_trip_document_links_created_by'), document_sync_items_collection: () => p.oneToMany(DocumentSyncItems).mappedBy('link').hidden(), }, }); diff --git a/server/src/db/entities/TripFiles.entity.ts b/server/src/db/entities/TripFiles.entity.ts index 2a8493ce3..a170af543 100644 --- a/server/src/db/entities/TripFiles.entity.ts +++ b/server/src/db/entities/TripFiles.entity.ts @@ -44,24 +44,24 @@ export const TripFilesSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_trip_files_trip_id'), trip_id: p.integer().persist(false).index('idx_trip_files_trip_id'), - place: () => p.manyToOne(Places).ref().nullable().hidden(), - place_id: p.integer().nullable().persist(false), - reservation: () => p.manyToOne(Reservations).ref().nullable().hidden(), - reservation_id: p.integer().nullable().persist(false), + place: () => p.manyToOne(Places).ref().nullable().hidden().index('idx_trip_files_place_id'), + place_id: p.integer().nullable().persist(false).index('idx_trip_files_place_id'), + reservation: () => p.manyToOne(Reservations).ref().nullable().hidden().index('idx_trip_files_reservation_id'), + reservation_id: p.integer().nullable().persist(false).index('idx_trip_files_reservation_id'), filename: p.text(), original_name: p.text(), file_size: p.integer().nullable(), mime_type: p.text().nullable(), description: p.text().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - note: () => p.manyToOne(CollabNotes).ref().nullable().hidden(), - note_id: p.integer().nullable().persist(false), - uploaded_by: p.integer().nullable().persist(false), + note: () => p.manyToOne(CollabNotes).ref().nullable().hidden().index('idx_trip_files_note_id'), + note_id: p.integer().nullable().persist(false).index('idx_trip_files_note_id'), + uploaded_by: p.integer().nullable().persist(false).index('idx_trip_files_uploaded_by'), starred: p.integer().nullable(), deleted_at: p.text().nullable(), message: () => p.manyToOne(CollabMessages).ref().deleteRule('cascade').nullable().hidden().index('idx_trip_files_message_id'), message_id: p.integer().nullable().persist(false).index('idx_trip_files_message_id'), - uploadedByRef: () => p.manyToOne(Users).ref().joinColumn('uploaded_by').nullable().hidden(), + uploadedByRef: () => p.manyToOne(Users).ref().joinColumn('uploaded_by').nullable().hidden().index('idx_trip_files_uploaded_by'), document_sync_items_collection: () => p.oneToMany(DocumentSyncItems).mappedBy('file').hidden(), file_links_collection: () => p.oneToMany(FileLinks).mappedBy('file').hidden(), }, diff --git a/server/src/db/entities/TripInviteTokens.entity.ts b/server/src/db/entities/TripInviteTokens.entity.ts index b669c2514..9c8a23c8d 100644 --- a/server/src/db/entities/TripInviteTokens.entity.ts +++ b/server/src/db/entities/TripInviteTokens.entity.ts @@ -25,9 +25,9 @@ export const TripInviteTokensSchema = defineEntity({ trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden(), trip_id: p.integer().persist(false), token: p.text().index('idx_trip_invite_tokens_token'), - created_by: p.integer().nullable().persist(false), + created_by: p.integer().nullable().persist(false).index('idx_trip_invite_tokens_created_by'), expires_at: p.text().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').nullable().hidden(), + createdByRef: () => p.manyToOne(Users).ref().joinColumn('created_by').nullable().hidden().index('idx_trip_invite_tokens_created_by'), }, }); diff --git a/server/src/db/entities/TripMembers.entity.ts b/server/src/db/entities/TripMembers.entity.ts index a08f68207..9ba326619 100644 --- a/server/src/db/entities/TripMembers.entity.ts +++ b/server/src/db/entities/TripMembers.entity.ts @@ -26,8 +26,8 @@ export const TripMembersSchema = defineEntity({ trip_id: p.integer().persist(false).index('idx_trip_members_trip_id'), user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_trip_members_user_id'), user_id: p.integer().persist(false).index('idx_trip_members_user_id'), - invited_by: p.integer().nullable().persist(false), + invited_by: p.integer().nullable().persist(false).index('idx_trip_members_invited_by'), added_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), - invitedByRef: () => p.manyToOne(Users).ref().joinColumn('invited_by').deleteRule('no action').nullable().hidden(), + invitedByRef: () => p.manyToOne(Users).ref().joinColumn('invited_by').deleteRule('no action').nullable().hidden().index('idx_trip_members_invited_by'), }, }); diff --git a/server/src/db/entities/TripPhotos.entity.ts b/server/src/db/entities/TripPhotos.entity.ts index 25e6384d9..5b1ce0d84 100644 --- a/server/src/db/entities/TripPhotos.entity.ts +++ b/server/src/db/entities/TripPhotos.entity.ts @@ -29,13 +29,13 @@ export const TripPhotosSchema = defineEntity({ id: p.integer().primary(), trip: () => p.manyToOne(Trips).ref().deleteRule('cascade').hidden().index('idx_trip_photos_trip'), trip_id: p.integer().persist(false).index('idx_trip_photos_trip'), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_trip_photos_user_id'), + user_id: p.integer().persist(false).index('idx_trip_photos_user_id'), photo: () => p.manyToOne(TrekPhotos).ref().deleteRule('cascade').hidden().index('idx_trip_photos_photo'), photo_id: p.integer().persist(false).index('idx_trip_photos_photo'), shared: p.integer().default(1), - albumLink: () => p.manyToOne(TripAlbumLinks).ref().nullable().hidden(), - album_link_id: p.integer().nullable().persist(false), + albumLink: () => p.manyToOne(TripAlbumLinks).ref().nullable().hidden().index('idx_trip_photos_album_link_id'), + album_link_id: p.integer().nullable().persist(false).index('idx_trip_photos_album_link_id'), added_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, }); diff --git a/server/src/db/entities/VacayEntries.entity.ts b/server/src/db/entities/VacayEntries.entity.ts index 75260d407..cccac02d7 100644 --- a/server/src/db/entities/VacayEntries.entity.ts +++ b/server/src/db/entities/VacayEntries.entity.ts @@ -22,8 +22,8 @@ export const VacayEntriesSchema = defineEntity({ uniques: [{ properties: ['user', 'plan', 'date'] }], properties: { id: p.integer().primary(), - plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden(), - plan_id: p.integer().persist(false), + plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden().index('idx_vacay_entries_plan_id'), + plan_id: p.integer().persist(false).index('idx_vacay_entries_plan_id'), user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), user_id: p.integer().persist(false), date: p.text(), diff --git a/server/src/db/entities/VacayHolidayCalendars.entity.ts b/server/src/db/entities/VacayHolidayCalendars.entity.ts index 67e9e2af4..23f70ed03 100644 --- a/server/src/db/entities/VacayHolidayCalendars.entity.ts +++ b/server/src/db/entities/VacayHolidayCalendars.entity.ts @@ -19,8 +19,8 @@ export const VacayHolidayCalendarsSchema = defineEntity({ repository: () => VacayHolidayCalendarsRepository, properties: { id: p.integer().primary(), - plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden(), - plan_id: p.integer().persist(false), + plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden().index('idx_vacay_holiday_calendars_plan_id'), + plan_id: p.integer().persist(false).index('idx_vacay_holiday_calendars_plan_id'), type: p.text().default('public_holiday'), region: p.text(), label: p.text().nullable(), diff --git a/server/src/db/entities/VacayPlanMembers.entity.ts b/server/src/db/entities/VacayPlanMembers.entity.ts index f211ed439..59a0534b9 100644 --- a/server/src/db/entities/VacayPlanMembers.entity.ts +++ b/server/src/db/entities/VacayPlanMembers.entity.ts @@ -23,8 +23,8 @@ export const VacayPlanMembersSchema = defineEntity({ id: p.integer().primary(), plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden(), plan_id: p.integer().persist(false), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), - user_id: p.integer().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden().index('idx_vacay_plan_members_user_id'), + user_id: p.integer().persist(false).index('idx_vacay_plan_members_user_id'), status: p.text().nullable(), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), }, diff --git a/server/src/db/entities/VacayUserColors.entity.ts b/server/src/db/entities/VacayUserColors.entity.ts index f251f3b60..c20d614f7 100644 --- a/server/src/db/entities/VacayUserColors.entity.ts +++ b/server/src/db/entities/VacayUserColors.entity.ts @@ -21,8 +21,8 @@ export const VacayUserColorsSchema = defineEntity({ id: p.integer().primary(), user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), user_id: p.integer().persist(false), - plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden(), - plan_id: p.integer().persist(false), + plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden().index('idx_vacay_user_colors_plan_id'), + plan_id: p.integer().persist(false).index('idx_vacay_user_colors_plan_id'), color: p.text().nullable(), }, }); diff --git a/server/src/db/entities/VacayUserYears.entity.ts b/server/src/db/entities/VacayUserYears.entity.ts index 5bc9b4569..2575c2c1d 100644 --- a/server/src/db/entities/VacayUserYears.entity.ts +++ b/server/src/db/entities/VacayUserYears.entity.ts @@ -23,8 +23,8 @@ export const VacayUserYearsSchema = defineEntity({ id: p.integer().primary(), user: () => p.manyToOne(Users).ref().deleteRule('cascade').hidden(), user_id: p.integer().persist(false), - plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden(), - plan_id: p.integer().persist(false), + plan: () => p.manyToOne(VacayPlans).ref().deleteRule('cascade').hidden().index('idx_vacay_user_years_plan_id'), + plan_id: p.integer().persist(false).index('idx_vacay_user_years_plan_id'), year: p.integer(), vacation_days: p.integer().nullable(), carried_over: p.integer().nullable(), diff --git a/server/src/db/entities/WebauthnChallenges.entity.ts b/server/src/db/entities/WebauthnChallenges.entity.ts index 9b677277b..ee20788c7 100644 --- a/server/src/db/entities/WebauthnChallenges.entity.ts +++ b/server/src/db/entities/WebauthnChallenges.entity.ts @@ -21,8 +21,8 @@ export const WebauthnChallengesSchema = defineEntity({ properties: { id: p.integer().primary(), challenge: p.text(), - user: () => p.manyToOne(Users).ref().deleteRule('cascade').nullable().hidden(), - user_id: p.integer().nullable().persist(false), + user: () => p.manyToOne(Users).ref().deleteRule('cascade').nullable().hidden().index('idx_webauthn_challenges_user_id'), + user_id: p.integer().nullable().persist(false).index('idx_webauthn_challenges_user_id'), type: p.text(), expires_at: p.integer().index('idx_webauthn_challenges_expires'), created_at: p.type(DbTimestampType).nullable().defaultRaw(`CURRENT_TIMESTAMP`), diff --git a/server/src/db/migrations/Migration20200101042200_an_index_on_every_foreign_key.ts b/server/src/db/migrations/Migration20200101042200_an_index_on_every_foreign_key.ts new file mode 100644 index 000000000..ad2ede96e --- /dev/null +++ b/server/src/db/migrations/Migration20200101042200_an_index_on_every_foreign_key.ts @@ -0,0 +1,105 @@ +import { Migration } from '@mikro-orm/migrations'; + +/** + * An index on every foreign-key column that had none (86 of them). + * + * SQLite does not index a foreign key by itself, and every ON DELETE CASCADE + * or SET NULL has to find the child rows: deleting a trip or a user scanned + * each unindexed child table in full, once per parent row, inside the delete's + * transaction, while every other request waited on the one connection. The + * lookups by these columns (a trip's files, a user's tokens) get faster too. + * + * `IF NOT EXISTS`, so an install that added one by hand keeps it. + */ +export class Migration20200101042200_an_index_on_every_foreign_key extends Migration { + override name = 'Migration20200101042200_an_index_on_every_foreign_key'; + + override up(): void { + this.addSql('CREATE INDEX IF NOT EXISTS idx_webauthn_challenges_user_id ON webauthn_challenges(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_categories_user_id ON categories(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_tags_user_id ON tags(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_place_ratings_user_id ON place_ratings(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_items_owner_id ON packing_items(owner_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_items_bag_id ON packing_items(bag_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_files_uploaded_by ON trip_files(uploaded_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_files_note_id ON trip_files(note_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_files_reservation_id ON trip_files(reservation_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_files_place_id ON trip_files(place_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_reservations_assignment_id ON reservations(assignment_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_reservations_place_id ON reservations(place_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_reservations_end_day_id ON reservations(end_day_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_members_invited_by ON trip_members(invited_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_day_notes_trip_id ON day_notes(trip_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_budget_items_place_id ON budget_items(place_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_budget_items_reservation_id ON budget_items(reservation_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_budget_items_paid_by_user_id ON budget_items(paid_by_user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_vacay_plan_members_user_id ON vacay_plan_members(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_vacay_user_colors_plan_id ON vacay_user_colors(plan_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_vacay_user_years_plan_id ON vacay_user_years(plan_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_vacay_entries_plan_id ON vacay_entries(plan_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_vacay_holiday_calendars_plan_id ON vacay_holiday_calendars(plan_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collections_owner_id ON collections(owner_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collection_places_category_id ON collection_places(category_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collection_places_saved_by ON collection_places(saved_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collection_places_owner_id ON collection_places(owner_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collection_place_ratings_user_id ON collection_place_ratings(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collab_notes_user_id ON collab_notes(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collab_polls_user_id ON collab_polls(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collab_poll_votes_user_id ON collab_poll_votes(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collab_messages_reply_to ON collab_messages(reply_to)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collab_messages_user_id ON collab_messages(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_assignment_participants_user_id ON assignment_participants(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_audit_log_user_id ON audit_log(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_notifications_sender_id ON notifications(sender_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collab_message_reactions_user_id ON collab_message_reactions(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_invite_tokens_trip_id ON invite_tokens(trip_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_invite_tokens_created_by ON invite_tokens(created_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_category_assignees_user_id ON packing_category_assignees(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_templates_created_by ON packing_templates(created_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_template_categories_template_id ON packing_template_categories(template_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_template_items_category_id ON packing_template_items(category_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_bags_user_id ON packing_bags(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_bags_trip_id ON packing_bags(trip_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_bucket_list_user_id ON bucket_list(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_file_links_place_id ON file_links(place_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_file_links_assignment_id ON file_links(assignment_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_file_links_reservation_id ON file_links(reservation_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_share_tokens_created_by ON share_tokens(created_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_share_tokens_trip_id ON share_tokens(trip_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_mcp_tokens_user_id ON mcp_tokens(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_album_links_user_id ON trip_album_links(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_todo_items_assigned_user_id ON todo_items(assigned_user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_todo_category_assignees_user_id ON todo_category_assignees(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_bag_members_user_id ON packing_bag_members(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_reservation_day_positions_day_id ON reservation_day_positions(day_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_oauth_consents_user_id ON oauth_consents(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_oauth_tokens_client_id ON oauth_tokens(client_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_journey_trips_trip_id ON journey_trips(trip_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_journey_entries_author_id ON journey_entries(author_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_journey_entries_source_trip_id ON journey_entries(source_trip_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_journey_share_tokens_created_by ON journey_share_tokens(created_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_photos_album_link_id ON trip_photos(album_link_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_photos_user_id ON trip_photos(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_idempotency_keys_user_id ON idempotency_keys(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_day_accommodations_place_id ON day_accommodations(place_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_journey_photos_photo_id ON journey_photos(photo_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_budget_item_payers_user_id ON budget_item_payers(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_budget_settlements_created_by_user_id ON budget_settlements(created_by_user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_budget_settlements_to_user_id ON budget_settlements(to_user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_budget_settlements_from_user_id ON budget_settlements(from_user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_packing_item_contributors_user_id ON packing_item_contributors(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_invite_tokens_created_by ON trip_invite_tokens(created_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_journey_books_updated_by ON journey_books(updated_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_journey_books_created_by ON journey_books(created_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_collab_links_user_id ON collab_links(user_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_dawarich_visit_suggestions_matched_bucket_list_item_id ON dawarich_visit_suggestions(matched_bucket_list_item_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_dawarich_visit_suggestions_accepted_bucket_list_item_id ON dawarich_visit_suggestions(accepted_bucket_list_item_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_dawarich_visit_suggestions_accepted_place_id ON dawarich_visit_suggestions(accepted_place_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_document_connections_provider_id ON document_connections(provider_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_document_links_created_by ON trip_document_links(created_by)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_trip_document_links_connection_id ON trip_document_links(connection_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_document_sync_items_file_id ON document_sync_items(file_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_roadtrip_day_boundaries_to_assignment_id ON roadtrip_day_boundaries(to_assignment_id)'); + this.addSql('CREATE INDEX IF NOT EXISTS idx_roadtrip_day_boundaries_from_assignment_id ON roadtrip_day_boundaries(from_assignment_id)'); + } +} diff --git a/server/tests/unit/db/legacy-baseline.test.ts b/server/tests/unit/db/legacy-baseline.test.ts index 8907e17f2..696ef05fc 100644 --- a/server/tests/unit/db/legacy-baseline.test.ts +++ b/server/tests/unit/db/legacy-baseline.test.ts @@ -33,6 +33,7 @@ const UNNUMBERED = [ 'Migration20200101040200_trek_photo_cache_meta_cache_key_not_null', 'Migration20200101042000_tours', 'Migration20200101042100_a_trip_reminder_remembers_it_was_sent', + 'Migration20200101042200_an_index_on_every_foreign_key', ]; // The last step the positional runner ever had; planLegacyBaseline refuses a // schema_version past it.