From eabd4b03f6ea9dcb1ec18d316ee7fbdd81de69f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Wu=C3=9Fmann?= Date: Tue, 13 Feb 2024 00:04:26 +0100 Subject: [PATCH 1/3] Fix creating indexes --- src/components/nav/search/NavSearchBar.tsx | 13 +++- .../settings/TeamSettings/TeamMemberRow.tsx | 4 +- .../settings/TeamSettings/TeamMemberTable.tsx | 4 +- src/server/api/routers/team.ts | 2 +- src/server/lib/applicationContext.ts | 7 +- .../lib/asset-types/assetTypeService.ts | 13 +++- .../lib/search/abstractSearchService.ts | 36 +++++++--- src/server/lib/search/assetSearchService.ts | 68 +++++++------------ .../lib/search/assetTypeSearchService.ts | 52 ++++++-------- src/server/lib/search/searchService.ts | 24 +++++-- src/server/lib/search/tagSearchService.ts | 53 ++++++--------- src/server/lib/user/member.ts | 2 +- src/server/lib/user/team.ts | 1 + 13 files changed, 145 insertions(+), 134 deletions(-) create mode 100644 src/server/lib/user/team.ts diff --git a/src/components/nav/search/NavSearchBar.tsx b/src/components/nav/search/NavSearchBar.tsx index 390b1dc..1613e16 100644 --- a/src/components/nav/search/NavSearchBar.tsx +++ b/src/components/nav/search/NavSearchBar.tsx @@ -106,6 +106,10 @@ export const NavSearchBar = ({ hideShortcut }: { hideShortcut?: true }) => { "rgba(255, 255, 255, 0.8)", "rgba(0, 0, 0, 0.8)" ); + const selectedSearchResultBackgroundColor = useColorModeValue( + "gray.100", + "gray.600" + ); useSearchShortcut(onToggle); @@ -260,9 +264,14 @@ export const NavSearchBar = ({ hideShortcut }: { hideShortcut?: true }) => { {searchResults.map((result, index) => ( openResult(result)} > diff --git a/src/components/settings/TeamSettings/TeamMemberRow.tsx b/src/components/settings/TeamSettings/TeamMemberRow.tsx index 43c6a74..8207f68 100644 --- a/src/components/settings/TeamSettings/TeamMemberRow.tsx +++ b/src/components/settings/TeamSettings/TeamMemberRow.tsx @@ -14,12 +14,12 @@ import { useDisclosure, useToast, } from "@chakra-ui/react"; -import { UserTeamMembership, UserTeamMembershipRole } from "@prisma/client"; +import { type UserTeamMembership, UserTeamMembershipRole } from "@prisma/client"; import { useState } from "react"; import { DeleteIconButton } from "~/components/common/DeleteIconButton"; import { useTeam } from "~/lib/SelectedTeamProvider"; import { useErrorHandlingMutation } from "~/lib/useErrorHandling"; -import { Member } from "~/server/lib/user/member"; +import { type Member } from "~/server/lib/user/member"; import { api } from "~/utils/api"; type TeamMemberRowProps = { diff --git a/src/components/settings/TeamSettings/TeamMemberTable.tsx b/src/components/settings/TeamSettings/TeamMemberTable.tsx index dac87d6..5f9d6b4 100644 --- a/src/components/settings/TeamSettings/TeamMemberTable.tsx +++ b/src/components/settings/TeamSettings/TeamMemberTable.tsx @@ -1,7 +1,7 @@ import { Flex, Progress, Table, Tbody, Th, Thead, Tr } from "@chakra-ui/react"; import { - Team, - UserTeamMembership, + type Team, + type UserTeamMembership, UserTeamMembershipRole, } from "@prisma/client"; import { api } from "~/utils/api"; diff --git a/src/server/api/routers/team.ts b/src/server/api/routers/team.ts index a801023..2b1c096 100644 --- a/src/server/api/routers/team.ts +++ b/src/server/api/routers/team.ts @@ -1,4 +1,4 @@ -import { Team } from "@prisma/client"; +import { type Team } from "@prisma/client"; import { z } from "zod"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { teamAddMemberRequest } from "~/server/lib/user/teamAddMemberRequest"; diff --git a/src/server/lib/applicationContext.ts b/src/server/lib/applicationContext.ts index 1b7ec8f..6b85501 100644 --- a/src/server/lib/applicationContext.ts +++ b/src/server/lib/applicationContext.ts @@ -32,8 +32,7 @@ export class ApplicationContext { ); public readonly assetTypeSearchService = new AssetTypeSearchService( this.logger.child({ name: "AssetTypeSearchService" }), - this.meiliSearch, - this.teamService + this.meiliSearch ); public readonly assetTypeService = new AssetTypeService( this.logger.child({ name: "AssetTypeService" }), @@ -44,13 +43,11 @@ export class ApplicationContext { public readonly assetSearchService = new AssetSearchService( this.logger.child({ name: "AssetSearchService" }), this.meiliSearch, - this.teamService, this.assetTypeService ); public readonly tagSearchService = new TagSearchService( this.logger.child({ name: "TagSearchService" }), - this.meiliSearch, - this.teamService + this.meiliSearch ); public readonly assetService = new AssetService( this.logger.child({ name: "AssetService" }), diff --git a/src/server/lib/asset-types/assetTypeService.ts b/src/server/lib/asset-types/assetTypeService.ts index fa537bf..2041048 100644 --- a/src/server/lib/asset-types/assetTypeService.ts +++ b/src/server/lib/asset-types/assetTypeService.ts @@ -11,6 +11,7 @@ import { type Logger } from "winston"; import { type AssetTypeSearchService } from "../search/assetTypeSearchService"; import { type TeamService } from "../user/teamService"; import slugify from "slugify"; +import { type TeamId } from "../user/team"; export class AssetTypeService { constructor( @@ -458,6 +459,14 @@ export class AssetTypeService { ); }; - public getSearchableCustomFields = async (): Promise => - this.prisma.customField.findMany(); + public getSearchableCustomFields = async ( + teamIds: TeamId[] + ): Promise => + this.prisma.customField.findMany({ + where: { + teamId: { + in: teamIds, + }, + }, + }); } diff --git a/src/server/lib/search/abstractSearchService.ts b/src/server/lib/search/abstractSearchService.ts index e662226..ad2621a 100644 --- a/src/server/lib/search/abstractSearchService.ts +++ b/src/server/lib/search/abstractSearchService.ts @@ -1,6 +1,6 @@ -import { type Team } from "@prisma/client"; import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; +import { type TeamId } from "../user/team"; type TeamOwnedIdentifiable = { id: string; @@ -11,17 +11,29 @@ export abstract class AbstractSearchService< TDoc extends object, TEntity extends TeamOwnedIdentifiable > { + private initialized = false; constructor( protected readonly logger: Logger, protected readonly meilisearch: MeiliSearch, private readonly indexBaseName: string ) {} - abstract initialize: () => Promise; + public initialize = async (teamIds: TeamId[]) => { + if (this.initialized) { + this.logger.debug("Search service already initialized"); + return; + } + this.logger.debug("Initializing search service"); + await this.onInitialize(teamIds); + this.initialized = true; + this.logger.debug("Search service initialized"); + }; - public getIndexName = (teamId: string) => `${this.indexBaseName}_${teamId}`; + protected abstract onInitialize: (teamIds: TeamId[]) => Promise; - public deleteIndex = async (teamId: string) => { + public getIndexName = (teamId: TeamId) => `${this.indexBaseName}_${teamId}`; + + public deleteIndex = async (teamId: TeamId) => { this.logger.info("Deleting search index", { teamId }); const index = this.meilisearch.index(this.getIndexName(teamId)); await index.delete(); @@ -30,28 +42,31 @@ export abstract class AbstractSearchService< protected abstract mapToSearchDocument: (entity: TEntity) => TDoc; - public rebuildIndex = async (team: Team, entities: TEntity[]) => { - this.logger.debug("Rebuilding index", { teamId: team.id }); + public rebuildIndex = async (teamId: TeamId, entities: TEntity[]) => { + this.logger.debug("Rebuilding index", { teamId }); try { const index = await this.meilisearch.getIndex( - this.getIndexName(team.id) + this.getIndexName(teamId) ); await index.deleteAllDocuments(); const documents = entities.map(this.mapToSearchDocument); await index.addDocuments(documents, { primaryKey: "id" }); this.logger.info("Rebuilding index done", { - teamId: team.id, + teamId, documentCount: documents.length, }); } catch (error) { this.logger.error( "Rebuilding index failed. This may be fine if no index exists.", - { teamId: team.id, error } + { teamId, error } ); } }; public delete = async (entity: TeamOwnedIdentifiable) => { + if (entity.teamId) { + await this.initialize([entity.teamId]); + } this.logger.debug("Deleting document from search", { id: entity.id }); if (!entity.teamId) { return; @@ -67,6 +82,9 @@ export abstract class AbstractSearchService< }; public add = async (entity: TEntity) => { + if (entity.teamId) { + await this.initialize([entity.teamId]); + } this.logger.debug("Indexing entity", { id: entity.id }); if (!entity.teamId) { return; diff --git a/src/server/lib/search/assetSearchService.ts b/src/server/lib/search/assetSearchService.ts index 95dd657..1f172fe 100644 --- a/src/server/lib/search/assetSearchService.ts +++ b/src/server/lib/search/assetSearchService.ts @@ -3,11 +3,10 @@ import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; import { z } from "zod"; import { type AssetTypeService } from "../asset-types/assetTypeService"; -import { type Team } from "@prisma/client"; import { type AssetWithFields } from "../assets/asset"; import { waitForTasks } from "../user/meiliSearchUtils"; -import { type TeamService } from "../user/teamService"; import { AbstractSearchService } from "./abstractSearchService"; +import { type TeamId } from "../user/team"; export const assetDocumentSchema = z.record( z.union([z.string(), z.number(), z.boolean(), z.null()]) @@ -30,51 +29,35 @@ export class AssetSearchService extends AbstractSearchService< constructor( readonly logger: Logger, readonly meilisearch: MeiliSearch, - private readonly teamService: TeamService, private readonly assetTypeService: AssetTypeService ) { super(logger, meilisearch, "assets"); } - public initialize = async () => { - this.logger.debug("Initializing asset search indexes"); - - const teams = await this.teamService.getAllTeams(); - await this.createMissingIndexes(teams); - await this.syncFilterableAttributes(teams); - - this.logger.debug("Initializing asset search indexes done"); + protected onInitialize = async (teamIds: TeamId[]) => { + await this.createMissingIndexes(teamIds); + await this.syncFilterableAttributes(teamIds); }; - private createMissingIndexes = async (teams: Team[]) => { + private createMissingIndexes = async (teamIds: TeamId[]) => { const { results: indexes } = await this.meilisearch.getIndexes({ limit: Number.MAX_SAFE_INTEGER, }); - const indexesMissing = teams.filter((team) => { - const exists = indexes.some((index: Index) => { - const compare = index.uid === this.getIndexName(team.id); - this.logger.debug("Index compare", { - indexId: index.uid, - compare, - name: this.getIndexName(team.id), - }); - return compare; - }); - this.logger.debug("Index existance", { - teamId: team.id, - exists, - name: this.getIndexName(team.id), - }); + const indexesMissing = teamIds.filter((teamId) => { + const exists = indexes.some( + (index: Index) => + index.uid === this.getIndexName(teamId) + ); return !exists; }); await waitForTasks( this.meilisearch, - indexesMissing.map(async (team) => { - this.logger.info("Creating missing index", { teamId: team.id }); - return this.meilisearch.createIndex(this.getIndexName(team.id), { + indexesMissing.map(async (teamId) => { + this.logger.info("Creating missing index", { teamId }); + return this.meilisearch.createIndex(this.getIndexName(teamId), { primaryKey: "id", }); }) @@ -82,17 +65,18 @@ export class AssetSearchService extends AbstractSearchService< this.logger.debug("Creating missing indexes done"); }; - public syncFilterableAttributes = async (teams: Team[]) => { - const customFields = - await this.assetTypeService.getSearchableCustomFields(); + public syncFilterableAttributes = async (teamIds: TeamId[]) => { + const customFields = await this.assetTypeService.getSearchableCustomFields( + teamIds + ); await Promise.all( - teams.map(async (team) => { + teamIds.map(async (teamId) => { const index = this.meilisearch.index( - this.getIndexName(team.id) + this.getIndexName(teamId) ); const customFieldsForTeam = customFields.filter( - (field) => field.teamId === team.id + (field) => field.teamId === teamId ); const customFieldsAndBaseAttributes = [ ...baseAttributes, @@ -118,16 +102,16 @@ export class AssetSearchService extends AbstractSearchService< this.logger.info( "Filterable attributes have changed. Applying new config now. This may take a while!", { - teamId: team.id, + teamId, } ); this.logger.debug("New filterable attributes", { - teamId: team.id, + teamId, attributes: notYetFilterableAttributes.map((attr) => attr.slug), }); await index.updateFilterableAttributes(customFieldsAndBaseAttributes); this.logger.info("Applying filterable attributes done", { - teamId: team.id, + teamId, }); } @@ -135,16 +119,16 @@ export class AssetSearchService extends AbstractSearchService< this.logger.info( "Sortable attributes have changed. Applying new config now. This may take a while!", { - teamId: team.id, + teamId, } ); this.logger.debug("New sortable attributes", { - teamId: team.id, + teamId, attributes: notYetSortableAttributes.map((attr) => attr.slug), }); await index.updateSortableAttributes(customFieldsAndBaseAttributes); this.logger.info("Applying sortable attributes done", { - teamId: team.id, + teamId, }); } }) diff --git a/src/server/lib/search/assetTypeSearchService.ts b/src/server/lib/search/assetTypeSearchService.ts index 9e722f0..c0473e5 100644 --- a/src/server/lib/search/assetTypeSearchService.ts +++ b/src/server/lib/search/assetTypeSearchService.ts @@ -1,12 +1,11 @@ import { type Index } from "meilisearch"; import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; -import { type Team } from "@prisma/client"; import { z } from "zod"; import { type AssetType } from "../asset-types/assetType"; import { waitForTasks } from "../user/meiliSearchUtils"; -import { type TeamService } from "../user/teamService"; import { AbstractSearchService } from "./abstractSearchService"; +import { type TeamId } from "../user/team"; export const assetTypeSearchDocument = z.object({ id: z.string(), @@ -28,42 +27,33 @@ export class AssetTypeSearchService extends AbstractSearchService< AssetTypeSearchDocument, AssetType > { - constructor( - readonly logger: Logger, - readonly meilisearch: MeiliSearch, - private readonly teamService: TeamService - ) { + constructor(readonly logger: Logger, readonly meilisearch: MeiliSearch) { super(logger, meilisearch, "asset_types"); } - public initialize = async () => { - this.logger.debug("Initializing asset type search indexes"); - - const teams = await this.teamService.getAllTeams(); - await this.createMissingIndexes(teams); - await this.syncFilterableAttributes(teams); - - this.logger.debug("Initializing asset type search indexes done"); + protected onInitialize = async (teamIds: TeamId[]) => { + await this.createMissingIndexes(teamIds); + await this.syncFilterableAttributes(teamIds); }; - private createMissingIndexes = async (teams: Team[]) => { + private createMissingIndexes = async (teamIds: TeamId[]) => { const { results: indexes } = await this.meilisearch.getIndexes({ limit: Number.MAX_SAFE_INTEGER, }); - const indexesMissing = teams.filter( - (team) => + const indexesMissing = teamIds.filter( + (teamId) => !indexes.some( (index: Index) => - index.uid === this.getIndexName(team.id) + index.uid === this.getIndexName(teamId) ) ); await waitForTasks( this.meilisearch, - indexesMissing.map(async (team) => { - this.logger.info("Creating missing index", { teamId: team.id }); - return this.meilisearch.createIndex(this.getIndexName(team.id), { + indexesMissing.map(async (teamId) => { + this.logger.info("Creating missing index", { teamId }); + return this.meilisearch.createIndex(this.getIndexName(teamId), { primaryKey: "id", }); }) @@ -71,11 +61,11 @@ export class AssetTypeSearchService extends AbstractSearchService< this.logger.debug("Creating missing indexes done"); }; - public syncFilterableAttributes = async (teams: Team[]) => { + public syncFilterableAttributes = async (teamIds: TeamId[]) => { await Promise.all( - teams.map(async (team) => { + teamIds.map(async (teamId) => { const index = this.meilisearch.index( - this.getIndexName(team.id) + this.getIndexName(teamId) ); const currentlyFilterableAttributes = await index.getFilterableAttributes(); @@ -92,16 +82,16 @@ export class AssetTypeSearchService extends AbstractSearchService< this.logger.info( "Filterable attributes have changed. Applying new config now. This may take a while!", { - teamId: team.id, + teamId, } ); this.logger.debug("New filterable attributes", { - teamId: team.id, + teamId, attributes: baseAttributes, }); await index.updateFilterableAttributes(baseAttributes); this.logger.info("Applying filterable attributes done", { - teamId: team.id, + teamId, }); } @@ -109,16 +99,16 @@ export class AssetTypeSearchService extends AbstractSearchService< this.logger.info( "Sortable attributes have changed. Applying new config now. This may take a while!", { - teamId: team.id, + teamId, } ); this.logger.debug("New sortable attributes", { - teamId: team.id, + teamId, attributes: baseAttributes, }); await index.updateSortableAttributes(baseAttributes); this.logger.info("Applying sortable attributes done", { - teamId: team.id, + teamId, }); } }) diff --git a/src/server/lib/search/searchService.ts b/src/server/lib/search/searchService.ts index 27fc976..428a1b4 100644 --- a/src/server/lib/search/searchService.ts +++ b/src/server/lib/search/searchService.ts @@ -22,6 +22,8 @@ import { type TeamService } from "../user/teamService"; import { type AssetWithFields } from "../assets/asset"; export class SearchService { + private initialized = false; + constructor( private readonly logger: Logger, private readonly meiliSearch: MeiliSearch, @@ -35,10 +37,17 @@ export class SearchService { ) {} public waitForInitialization = async () => { + if (this.initialized) { + this.logger.debug("Search service already initialized"); + return; + } this.logger.debug("Waiting for search services to initialize"); - await this.assetSearchService.initialize(); - await this.tagSearchService.initialize(); - await this.assetTypeSearchService.initialize(); + const teamIds = (await this.teamService.getAllTeams()).map((t) => t.id); + await Promise.all([ + await this.assetSearchService.initialize(teamIds), + await this.tagSearchService.initialize(teamIds), + await this.assetTypeSearchService.initialize(teamIds), + ]); this.logger.debug("All search services initialized"); const { results: tasks } = await this.meiliSearch.getTasks({ @@ -57,6 +66,7 @@ export class SearchService { } else { this.logger.debug("Meilisearch has no tasks to wait for"); } + this.initialized = true; }; public rebuildIndexes = async (teamId: string) => { @@ -68,17 +78,17 @@ export class SearchService { } await Promise.all([ this.assetSearchService.rebuildIndex( - team, + teamId, (await this.assetService.getSearchableAssets( team.id )) as unknown as AssetWithFields[] ), this.tagSearchService.rebuildIndex( - team, + teamId, await this.tagService.getSearchableTags(team.id) ), this.assetTypeSearchService.rebuildIndex( - team, + teamId, await this.assetTypeService.getSearchableAsssetTypes(team.id) ), ]); @@ -99,6 +109,7 @@ export class SearchService { }; public getTasks = async (userId: string, teamId: string) => { + await this.waitForInitialization(); await this.teamService.requireTeamMembership(userId, teamId); const { results: tasks } = await this.meiliSearch.getTasks({ limit: 20, @@ -116,6 +127,7 @@ export class SearchService { userId: string, search: SearchRequest ): Promise => { + await this.waitForInitialization(); this.logger.debug("Searching for query", { search }); await this.teamService.requireTeamMembership(userId, search.teamId); const parsedQuery = parseQuery(search.query); diff --git a/src/server/lib/search/tagSearchService.ts b/src/server/lib/search/tagSearchService.ts index da359ed..965db60 100644 --- a/src/server/lib/search/tagSearchService.ts +++ b/src/server/lib/search/tagSearchService.ts @@ -1,11 +1,11 @@ import { type Index } from "meilisearch"; import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; -import { type TeamService } from "../user/teamService"; -import { type Team, type Tag } from "@prisma/client"; +import { type Tag } from "@prisma/client"; import { z } from "zod"; import { waitForTasks } from "../user/meiliSearchUtils"; import { AbstractSearchService } from "./abstractSearchService"; +import { type TeamId } from "../user/team"; export const tagSearchDocument = z.object({ id: z.string(), @@ -29,42 +29,33 @@ export class TagSearchService extends AbstractSearchService< TagSearchDocument, Tag > { - constructor( - readonly logger: Logger, - readonly meilisearch: MeiliSearch, - private readonly teamService: TeamService - ) { + constructor(readonly logger: Logger, readonly meilisearch: MeiliSearch) { super(logger, meilisearch, "tags"); } - public initialize = async () => { - this.logger.debug("Initializing tag search indexes"); - - const teams = await this.teamService.getAllTeams(); - await this.createMissingIndexes(teams); - await this.syncFilterableAttributes(teams); - - this.logger.debug("Initializing tag search indexes done"); + protected onInitialize = async (teamIds: TeamId[]) => { + await this.createMissingIndexes(teamIds); + await this.syncFilterableAttributes(teamIds); }; - private createMissingIndexes = async (teams: Team[]) => { + private createMissingIndexes = async (teamIds: TeamId[]) => { const { results: indexes } = await this.meilisearch.getIndexes({ limit: Number.MAX_SAFE_INTEGER, }); - const indexesMissing = teams.filter( - (team) => + const indexesMissing = teamIds.filter( + (teamId) => !indexes.some( (index: Index) => - index.uid === this.getIndexName(team.id) + index.uid === this.getIndexName(teamId) ) ); await waitForTasks( this.meilisearch, - indexesMissing.map(async (team) => { - this.logger.info("Creating missing index", { teamId: team.id }); - return this.meilisearch.createIndex(this.getIndexName(team.id), { + indexesMissing.map(async (teamId) => { + this.logger.info("Creating missing index", { teamId }); + return this.meilisearch.createIndex(this.getIndexName(teamId), { primaryKey: "id", }); }) @@ -72,11 +63,11 @@ export class TagSearchService extends AbstractSearchService< this.logger.debug("Creating missing indexes done"); }; - public syncFilterableAttributes = async (teams: Team[]) => { + public syncFilterableAttributes = async (teamIds: TeamId[]) => { await Promise.all( - teams.map(async (team) => { + teamIds.map(async (teamId) => { const index = this.meilisearch.index( - this.getIndexName(team.id) + this.getIndexName(teamId) ); const currentlyFilterableAttributes = await index.getFilterableAttributes(); @@ -93,16 +84,16 @@ export class TagSearchService extends AbstractSearchService< this.logger.info( "Filterable attributes have changed. Applying new config now. This may take a while!", { - teamId: team.id, + teamId, } ); this.logger.debug("New filterable attributes", { - teamId: team.id, + teamId, attributes: baseAttributes, }); await index.updateFilterableAttributes(baseAttributes); this.logger.info("Applying filterable attributes done", { - teamId: team.id, + teamId, }); } @@ -110,16 +101,16 @@ export class TagSearchService extends AbstractSearchService< this.logger.info( "Sortable attributes have changed. Applying new config now. This may take a while!", { - teamId: team.id, + teamId, } ); this.logger.debug("New sortable attributes", { - teamId: team.id, + teamId, attributes: baseAttributes, }); await index.updateSortableAttributes(baseAttributes); this.logger.info("Applying sortable attributes done", { - teamId: team.id, + teamId, }); } }) diff --git a/src/server/lib/user/member.ts b/src/server/lib/user/member.ts index e0dadfc..d5b6842 100644 --- a/src/server/lib/user/member.ts +++ b/src/server/lib/user/member.ts @@ -1,4 +1,4 @@ -import { UserTeamMembershipRole } from "@prisma/client"; +import { type UserTeamMembershipRole } from "@prisma/client"; export type Member = { id: string; diff --git a/src/server/lib/user/team.ts b/src/server/lib/user/team.ts new file mode 100644 index 0000000..0a12694 --- /dev/null +++ b/src/server/lib/user/team.ts @@ -0,0 +1 @@ +export type TeamId = string; From 6f6124408a92145b3feb7ca2942afc59cb5d462b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Wu=C3=9Fmann?= Date: Tue, 13 Feb 2024 00:07:41 +0100 Subject: [PATCH 2/3] Move createMissingIndexes to abstract parent --- .../lib/search/abstractSearchService.ts | 28 +++++++++++++++++++ src/server/lib/search/assetSearchService.ts | 27 ------------------ .../lib/search/assetTypeSearchService.ts | 26 ----------------- src/server/lib/search/tagSearchService.ts | 26 ----------------- 4 files changed, 28 insertions(+), 79 deletions(-) diff --git a/src/server/lib/search/abstractSearchService.ts b/src/server/lib/search/abstractSearchService.ts index ad2621a..0ba8678 100644 --- a/src/server/lib/search/abstractSearchService.ts +++ b/src/server/lib/search/abstractSearchService.ts @@ -1,6 +1,8 @@ import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; import { type TeamId } from "../user/team"; +import { type Index } from "meilisearch"; +import { waitForTasks } from "../user/meiliSearchUtils"; type TeamOwnedIdentifiable = { id: string; @@ -24,11 +26,37 @@ export abstract class AbstractSearchService< return; } this.logger.debug("Initializing search service"); + await this.createMissingIndexes(teamIds); await this.onInitialize(teamIds); this.initialized = true; this.logger.debug("Search service initialized"); }; + private createMissingIndexes = async (teamIds: TeamId[]) => { + const { results: indexes } = await this.meilisearch.getIndexes({ + limit: Number.MAX_SAFE_INTEGER, + }); + + const indexesMissing = teamIds.filter((teamId) => { + const exists = indexes.some( + (index: Index) => index.uid === this.getIndexName(teamId) + ); + + return !exists; + }); + + await waitForTasks( + this.meilisearch, + indexesMissing.map(async (teamId) => { + this.logger.info("Creating missing index", { teamId }); + return this.meilisearch.createIndex(this.getIndexName(teamId), { + primaryKey: "id", + }); + }) + ); + this.logger.debug("Creating missing indexes done"); + }; + protected abstract onInitialize: (teamIds: TeamId[]) => Promise; public getIndexName = (teamId: TeamId) => `${this.indexBaseName}_${teamId}`; diff --git a/src/server/lib/search/assetSearchService.ts b/src/server/lib/search/assetSearchService.ts index 1f172fe..25d065c 100644 --- a/src/server/lib/search/assetSearchService.ts +++ b/src/server/lib/search/assetSearchService.ts @@ -35,36 +35,9 @@ export class AssetSearchService extends AbstractSearchService< } protected onInitialize = async (teamIds: TeamId[]) => { - await this.createMissingIndexes(teamIds); await this.syncFilterableAttributes(teamIds); }; - private createMissingIndexes = async (teamIds: TeamId[]) => { - const { results: indexes } = await this.meilisearch.getIndexes({ - limit: Number.MAX_SAFE_INTEGER, - }); - - const indexesMissing = teamIds.filter((teamId) => { - const exists = indexes.some( - (index: Index) => - index.uid === this.getIndexName(teamId) - ); - - return !exists; - }); - - await waitForTasks( - this.meilisearch, - indexesMissing.map(async (teamId) => { - this.logger.info("Creating missing index", { teamId }); - return this.meilisearch.createIndex(this.getIndexName(teamId), { - primaryKey: "id", - }); - }) - ); - this.logger.debug("Creating missing indexes done"); - }; - public syncFilterableAttributes = async (teamIds: TeamId[]) => { const customFields = await this.assetTypeService.getSearchableCustomFields( teamIds diff --git a/src/server/lib/search/assetTypeSearchService.ts b/src/server/lib/search/assetTypeSearchService.ts index c0473e5..4e9dc43 100644 --- a/src/server/lib/search/assetTypeSearchService.ts +++ b/src/server/lib/search/assetTypeSearchService.ts @@ -32,35 +32,9 @@ export class AssetTypeSearchService extends AbstractSearchService< } protected onInitialize = async (teamIds: TeamId[]) => { - await this.createMissingIndexes(teamIds); await this.syncFilterableAttributes(teamIds); }; - private createMissingIndexes = async (teamIds: TeamId[]) => { - const { results: indexes } = await this.meilisearch.getIndexes({ - limit: Number.MAX_SAFE_INTEGER, - }); - - const indexesMissing = teamIds.filter( - (teamId) => - !indexes.some( - (index: Index) => - index.uid === this.getIndexName(teamId) - ) - ); - - await waitForTasks( - this.meilisearch, - indexesMissing.map(async (teamId) => { - this.logger.info("Creating missing index", { teamId }); - return this.meilisearch.createIndex(this.getIndexName(teamId), { - primaryKey: "id", - }); - }) - ); - this.logger.debug("Creating missing indexes done"); - }; - public syncFilterableAttributes = async (teamIds: TeamId[]) => { await Promise.all( teamIds.map(async (teamId) => { diff --git a/src/server/lib/search/tagSearchService.ts b/src/server/lib/search/tagSearchService.ts index 965db60..ee14803 100644 --- a/src/server/lib/search/tagSearchService.ts +++ b/src/server/lib/search/tagSearchService.ts @@ -34,35 +34,9 @@ export class TagSearchService extends AbstractSearchService< } protected onInitialize = async (teamIds: TeamId[]) => { - await this.createMissingIndexes(teamIds); await this.syncFilterableAttributes(teamIds); }; - private createMissingIndexes = async (teamIds: TeamId[]) => { - const { results: indexes } = await this.meilisearch.getIndexes({ - limit: Number.MAX_SAFE_INTEGER, - }); - - const indexesMissing = teamIds.filter( - (teamId) => - !indexes.some( - (index: Index) => - index.uid === this.getIndexName(teamId) - ) - ); - - await waitForTasks( - this.meilisearch, - indexesMissing.map(async (teamId) => { - this.logger.info("Creating missing index", { teamId }); - return this.meilisearch.createIndex(this.getIndexName(teamId), { - primaryKey: "id", - }); - }) - ); - this.logger.debug("Creating missing indexes done"); - }; - public syncFilterableAttributes = async (teamIds: TeamId[]) => { await Promise.all( teamIds.map(async (teamId) => { From 44149251ce1daa58d5af1864d809fc8df8854c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenneth=20Wu=C3=9Fmann?= Date: Tue, 13 Feb 2024 00:08:26 +0100 Subject: [PATCH 3/3] Remove unused imports --- src/server/lib/search/assetSearchService.ts | 2 -- src/server/lib/search/assetTypeSearchService.ts | 2 -- src/server/lib/search/tagSearchService.ts | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/server/lib/search/assetSearchService.ts b/src/server/lib/search/assetSearchService.ts index 25d065c..67de36c 100644 --- a/src/server/lib/search/assetSearchService.ts +++ b/src/server/lib/search/assetSearchService.ts @@ -1,10 +1,8 @@ -import { type Index } from "meilisearch"; import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; import { z } from "zod"; import { type AssetTypeService } from "../asset-types/assetTypeService"; import { type AssetWithFields } from "../assets/asset"; -import { waitForTasks } from "../user/meiliSearchUtils"; import { AbstractSearchService } from "./abstractSearchService"; import { type TeamId } from "../user/team"; diff --git a/src/server/lib/search/assetTypeSearchService.ts b/src/server/lib/search/assetTypeSearchService.ts index 4e9dc43..9aa36b9 100644 --- a/src/server/lib/search/assetTypeSearchService.ts +++ b/src/server/lib/search/assetTypeSearchService.ts @@ -1,9 +1,7 @@ -import { type Index } from "meilisearch"; import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; import { z } from "zod"; import { type AssetType } from "../asset-types/assetType"; -import { waitForTasks } from "../user/meiliSearchUtils"; import { AbstractSearchService } from "./abstractSearchService"; import { type TeamId } from "../user/team"; diff --git a/src/server/lib/search/tagSearchService.ts b/src/server/lib/search/tagSearchService.ts index ee14803..464d7e4 100644 --- a/src/server/lib/search/tagSearchService.ts +++ b/src/server/lib/search/tagSearchService.ts @@ -1,9 +1,7 @@ -import { type Index } from "meilisearch"; import type MeiliSearch from "meilisearch"; import { type Logger } from "winston"; import { type Tag } from "@prisma/client"; import { z } from "zod"; -import { waitForTasks } from "../user/meiliSearchUtils"; import { AbstractSearchService } from "./abstractSearchService"; import { type TeamId } from "../user/team";