diff --git a/prisma/migrations/20251107090000_add_my_reviews_indexes/migration.sql b/prisma/migrations/20251107090000_add_my_reviews_indexes/migration.sql index c71d518..5a09bb0 100644 --- a/prisma/migrations/20251107090000_add_my_reviews_indexes/migration.sql +++ b/prisma/migrations/20251107090000_add_my_reviews_indexes/migration.sql @@ -1,13 +1,66 @@ -- Add indexes to support faster `/v6/my-reviews` queries. -CREATE EXTENSION IF NOT EXISTS pg_trgm; +CREATE SCHEMA IF NOT EXISTS skills; +CREATE SCHEMA IF NOT EXISTS reviews; + +CREATE EXTENSION IF NOT EXISTS fuzzystrmatch WITH SCHEMA skills; +CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA pg_catalog; +CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA reviews; +CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA skills; CREATE INDEX IF NOT EXISTS "challenge_status_type_track_created_at_idx" ON "Challenge" ("status", "typeId", "trackId", "createdAt" DESC); +DROP INDEX IF EXISTS "challenge_name_idx"; + +CREATE INDEX IF NOT EXISTS "challenge_name_trgm_idx" + ON "Challenge" USING gin ("name" pg_catalog.gin_trgm_ops); + +DO +$$ +DECLARE + challenge_phase_schema TEXT; +BEGIN + SELECT n.nspname + INTO challenge_phase_schema + FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE c.relname = 'ChallengePhase' + AND c.relkind = 'r' + LIMIT 1; + + IF challenge_phase_schema IS NULL THEN + RETURN; + END IF; + + IF NOT EXISTS ( + SELECT 1 + FROM pg_class idx + JOIN pg_namespace ns ON ns.oid = idx.relnamespace + WHERE idx.relname = 'challenge_phase_order_idx' + AND ns.nspname = challenge_phase_schema + ) + AND EXISTS ( + SELECT 1 + FROM pg_class idx + JOIN pg_namespace ns ON ns.oid = idx.relnamespace + WHERE idx.relname = 'challenge_phase_challenge_open_end_idx' + AND ns.nspname = challenge_phase_schema + AND pg_get_indexdef(idx.oid) LIKE '%("challengeId", "isOpen", "scheduledEndDate", "actualEndDate", name)%' + ) + THEN + EXECUTE format( + 'ALTER INDEX %I.%I RENAME TO %I', + challenge_phase_schema, + 'challenge_phase_challenge_open_end_idx', + 'challenge_phase_order_idx' + ); + END IF; +END +$$ LANGUAGE plpgsql; + CREATE INDEX IF NOT EXISTS "challenge_phase_challenge_open_end_idx" ON "ChallengePhase" ("challengeId", "isOpen", "scheduledEndDate", "actualEndDate"); -CREATE INDEX IF NOT EXISTS "challenge_name_trgm_idx" - ON "Challenge" - USING gin ("name" pg_catalog.gin_trgm_ops); +CREATE INDEX IF NOT EXISTS "challenge_phase_order_idx" + ON "ChallengePhase" ("challengeId", "isOpen", "scheduledEndDate", "actualEndDate", "name"); diff --git a/prisma/migrations/20251107194833_default_reviewer_aiworkflowid/migration.sql b/prisma/migrations/20251107194833_default_reviewer_aiworkflowid/migration.sql new file mode 100644 index 0000000..e37a074 --- /dev/null +++ b/prisma/migrations/20251107194833_default_reviewer_aiworkflowid/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - You are about to drop the column `isAIReviewer` on the `DefaultChallengeReviewer` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "DefaultChallengeReviewer" DROP COLUMN "isAIReviewer", +ADD COLUMN "aiWorkflowId" VARCHAR(14); diff --git a/prisma/migrations/20251110230435_aiworkflowid_changes_with_migration_fix/migration.sql b/prisma/migrations/20251110230435_aiworkflowid_changes_with_migration_fix/migration.sql new file mode 100644 index 0000000..9861834 --- /dev/null +++ b/prisma/migrations/20251110230435_aiworkflowid_changes_with_migration_fix/migration.sql @@ -0,0 +1,8 @@ +-- DropIndex +DROP INDEX "challenges"."challenge_name_trgm_idx"; + +-- DropIndex +DROP INDEX "challenges"."challenge_phase_order_idx"; + +-- CreateIndex +CREATE INDEX "challenge_name_trgm_idx" ON "Challenge" USING GIN ("name" pg_catalog.gin_trgm_ops); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 19235cf..7887b6a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -645,7 +645,7 @@ model DefaultChallengeReviewer { baseCoefficient Float? incrementalCoefficient Float? opportunityType ReviewOpportunityTypeEnum? - isAIReviewer Boolean + aiWorkflowId String? @db.VarChar(14) shouldOpenOpportunity Boolean @default(true) // Relations diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index 7830690..6f600b0 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -280,7 +280,6 @@ async function getDefaultReviewers(currentUser, criteria) { incrementalCoefficient: r.incrementalCoefficient, type: r.opportunityType, aiWorkflowId: r.aiWorkflowId, - isAIReviewer: r.isAIReviewer, shouldOpenOpportunity: _.isBoolean(r.shouldOpenOpportunity) ? r.shouldOpenOpportunity : true, })); } @@ -302,7 +301,6 @@ async function setDefaultReviewers(currentUser, data) { Joi.object().keys({ scorecardId: Joi.string().required(), isMemberReview: Joi.boolean().required(), - isAIReviewer: Joi.boolean().default(false), shouldOpenOpportunity: Joi.boolean().default(true), memberReviewerCount: Joi.when("isMemberReview", { is: true, @@ -383,7 +381,7 @@ async function setDefaultReviewers(currentUser, data) { timelineTemplateId: _.isNil(value.timelineTemplateId) ? null : value.timelineTemplateId, scorecardId: String(r.scorecardId), isMemberReview: !!r.isMemberReview, - isAIReviewer: !!r.isAIReviewer, + aiWorkflowId:_.isNil(r.aiWorkflowId) ? null : r.aiWorkflowId, memberReviewerCount: _.isNil(r.memberReviewerCount) ? null : Number(r.memberReviewerCount), @@ -394,7 +392,6 @@ async function setDefaultReviewers(currentUser, data) { ? null : Number(r.incrementalCoefficient), opportunityType: r.type ? _.toUpper(r.type) : null, - aiWorkflowId: r.aiWorkflowId, shouldOpenOpportunity: _.isNil(r.shouldOpenOpportunity) ? true : !!r.shouldOpenOpportunity, @@ -1492,7 +1489,6 @@ async function createChallenge(currentUser, challenge, userToken) { incrementalCoefficient: r.incrementalCoefficient, type: r.opportunityType, aiWorkflowId: r.aiWorkflowId, - isAIReviewer: r.isAIReviewer ?? false, shouldOpenOpportunity: _.isBoolean(r.shouldOpenOpportunity) ? r.shouldOpenOpportunity : true, @@ -1660,7 +1656,6 @@ createChallenge.schema = { Joi.object().keys({ scorecardId: Joi.string().required(), isMemberReview: Joi.boolean().required(), - isAIReviewer: Joi.boolean().default(false), shouldOpenOpportunity: Joi.boolean().default(true), memberReviewerCount: Joi.when("isMemberReview", { is: true, @@ -2855,7 +2850,6 @@ updateChallenge.schema = { Joi.object().keys({ scorecardId: Joi.string().required(), isMemberReview: Joi.boolean().required(), - isAIReviewer: Joi.boolean().default(false), shouldOpenOpportunity: Joi.boolean().default(true), memberReviewerCount: Joi.when("isMemberReview", { is: true, @@ -3335,7 +3329,6 @@ function sanitizeChallenge(challenge) { _.pick(rv, [ "scorecardId", "isMemberReview", - "isAIReviewer", "memberReviewerCount", "phaseId", "fixedAmount", diff --git a/src/services/DefaultChallengeReviewerService.js b/src/services/DefaultChallengeReviewerService.js index 3a82a70..eddae32 100644 --- a/src/services/DefaultChallengeReviewerService.js +++ b/src/services/DefaultChallengeReviewerService.js @@ -262,8 +262,9 @@ function normalizePayload(data = {}, isPartial = false) { } else if (!isPartial && _.isNil(data.opportunityType)) { normalized.opportunityType = null; } - if (shouldAssign(data.isAIReviewer)) { - normalized.isAIReviewer = data.isAIReviewer; + + if (shouldAssign(data.aiWorkflowId)) { + normalized.aiWorkflowId = data.aiWorkflowId; } if (shouldAssign(data.shouldOpenOpportunity)) { normalized.shouldOpenOpportunity = data.shouldOpenOpportunity; @@ -338,7 +339,11 @@ createDefaultChallengeReviewer.schema = { baseCoefficient: Joi.number().min(0).max(1).allow(null), incrementalCoefficient: Joi.number().min(0).max(1).allow(null), opportunityType: Joi.string().valid(..._.values(ReviewOpportunityTypeEnum)).insensitive(), - isAIReviewer: Joi.boolean().required(), + aiWorkflowId: Joi.when("isMemberReview", { + is: false, + then: Joi.string().required(), + otherwise: Joi.valid(null), + }), shouldOpenOpportunity: Joi.boolean().required(), }) .required(), @@ -417,7 +422,11 @@ fullyUpdateDefaultChallengeReviewer.schema = { baseCoefficient: Joi.number().min(0).max(1).allow(null), incrementalCoefficient: Joi.number().min(0).max(1).allow(null), opportunityType: Joi.string().valid(..._.values(ReviewOpportunityTypeEnum)).insensitive(), - isAIReviewer: Joi.boolean().required(), + aiWorkflowId: Joi.when("isMemberReview", { + is: false, + then: Joi.string().required(), + otherwise: Joi.valid(null), + }), shouldOpenOpportunity: Joi.boolean().required(), }) .required(), @@ -516,7 +525,7 @@ partiallyUpdateDefaultChallengeReviewer.schema = { .valid(..._.values(ReviewOpportunityTypeEnum)) .insensitive() .allow(null), - isAIReviewer: Joi.boolean(), + aiWorkflowId: Joi.string(), shouldOpenOpportunity: Joi.boolean(), }) .required(),