PlotDirector/PlotLine/Sql/197_SceneRelationshipDevelopments.sql

93 lines
6.9 KiB
Transact-SQL

-- Reuse canonical relationships and events. Existing author data is not rewritten.
SET XACT_ABORT ON;
GO
IF COL_LENGTH('dbo.RelationshipEvents','SourceReviewKey') IS NULL
ALTER TABLE dbo.RelationshipEvents ADD SourceReviewKey nvarchar(450) NULL;
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id=OBJECT_ID('dbo.RelationshipEvents') AND name='UX_RelationshipEvents_ReviewSource')
CREATE UNIQUE INDEX UX_RelationshipEvents_ReviewSource ON dbo.RelationshipEvents(SceneID,SourceReviewKey) WHERE SourceReviewKey IS NOT NULL;
GO
CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceRelationship_AcceptDevelopment
@ProjectID int, @BookID int, @SceneID int, @SourceReviewKey nvarchar(450),
@CharacterAID int, @CharacterBID int, @RelationshipTypeID int, @RelationshipStateID int,
@IsPermanent bit, @IsReciprocal bit, @IsKnownToOtherCharacter bit,
@Intensity int=NULL, @Description nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF NOT EXISTS(SELECT 1 FROM dbo.Scenes s JOIN dbo.Chapters c ON c.ChapterID=s.ChapterID JOIN dbo.Books b ON b.BookID=c.BookID
WHERE s.SceneID=@SceneID AND b.BookID=@BookID AND b.ProjectID=@ProjectID AND s.IsArchived=0 AND c.IsArchived=0 AND b.IsArchived=0)
THROW 53100,'Invalid scene scope.',1;
IF @CharacterAID=@CharacterBID OR (SELECT COUNT(*) FROM dbo.Characters WHERE CharacterID IN (@CharacterAID,@CharacterBID) AND ProjectID=@ProjectID AND IsArchived=0)<>2
THROW 53101,'Invalid relationship participants.',1;
IF @Intensity NOT BETWEEN 1 AND 10 OR NULLIF(LTRIM(RTRIM(@Description)),N'') IS NULL OR NULLIF(@SourceReviewKey,N'') IS NULL
THROW 53102,'Invalid relationship development.',1;
BEGIN TRANSACTION;
DECLARE @LockResult int;
EXEC @LockResult=sys.sp_getapplock @Resource=N'StoryIntelligenceRelationshipAcceptance',@LockMode=N'Exclusive',@LockOwner=N'Transaction',@LockTimeout=15000;
IF @LockResult<0 THROW 53103,'Relationship acceptance is busy. Retry.',1;
DECLARE @RelationshipID int;
SELECT @RelationshipID=CharacterRelationshipID FROM dbo.RelationshipEvents WHERE SceneID=@SceneID AND SourceReviewKey=@SourceReviewKey;
IF @RelationshipID IS NULL
BEGIN
-- Do not flatten factual ties into changing feelings, or reverse a directional track.
SELECT TOP(1) @RelationshipID=CharacterRelationshipID FROM dbo.CharacterRelationships
WHERE ProjectID=@ProjectID AND IsArchived=0 AND EndSceneID IS NULL
AND RelationshipTypeID=@RelationshipTypeID AND IsPermanent=@IsPermanent AND IsReciprocal=@IsReciprocal
AND ((CharacterAID=@CharacterAID AND CharacterBID=@CharacterBID)
OR (@IsReciprocal=1 AND CharacterAID=@CharacterBID AND CharacterBID=@CharacterAID))
ORDER BY CharacterRelationshipID;
IF @RelationshipID IS NULL
BEGIN
INSERT dbo.CharacterRelationships(ProjectID,CharacterAID,CharacterBID,RelationshipTypeID,IsPermanent,StartSceneID,
IsKnownToReader,Notes,IsInitialRelationship,InitialBookID,ReaderInitiallyKnows,IsReciprocal)
VALUES(@ProjectID,@CharacterAID,@CharacterBID,@RelationshipTypeID,@IsPermanent,@SceneID,1,
N'Imported from Story Intelligence scene relationship review.',0,@BookID,0,@IsReciprocal);
SET @RelationshipID=CONVERT(int,SCOPE_IDENTITY());
END;
INSERT dbo.RelationshipEvents(CharacterRelationshipID,SceneID,RelationshipStateID,Intensity,IsKnownToOtherCharacter,Description,SourceReviewKey)
VALUES(@RelationshipID,@SceneID,@RelationshipStateID,@Intensity,@IsKnownToOtherCharacter,@Description,@SourceReviewKey);
-- A later-reviewed earlier scene must move the start of the track back in story order.
UPDATE r SET StartSceneID=@SceneID FROM dbo.CharacterRelationships r
JOIN dbo.Scenes oldScene ON oldScene.SceneID=r.StartSceneID JOIN dbo.Chapters oldChapter ON oldChapter.ChapterID=oldScene.ChapterID
JOIN dbo.Scenes newScene ON newScene.SceneID=@SceneID JOIN dbo.Chapters newChapter ON newChapter.ChapterID=newScene.ChapterID
WHERE r.CharacterRelationshipID=@RelationshipID AND r.IsInitialRelationship=0 AND oldChapter.BookID=@BookID
AND (newChapter.ChapterNumber<oldChapter.ChapterNumber OR (newChapter.ChapterNumber=oldChapter.ChapterNumber AND
(newScene.SceneNumber<oldScene.SceneNumber OR (newScene.SceneNumber=oldScene.SceneNumber AND newScene.SortOrder<oldScene.SortOrder))));
END;
COMMIT;
SELECT @RelationshipID;
END;
GO
-- Replace only pending legacy pair cards with scene proposals; preserve all author decisions.
CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceReviewCandidate_RefreshPendingRelationships
@BookID int,@GenerationID int,@PayloadJson nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
IF NOT EXISTS(SELECT 1 FROM dbo.StoryIntelligenceReviewCandidateGenerations WITH(UPDLOCK,HOLDLOCK)
WHERE ReviewCandidateGenerationID=@GenerationID AND BookID=@BookID AND Module=N'Relationships' AND IsCurrent=1 AND Status=N'Ready')
THROW 53104,'Review generation changed. Refresh aborted.',1;
-- An accepted/ignored old pair remains an author decision, including its unseen scenes.
SELECT p.value,p.[key] ordinal INTO #Incoming FROM OPENJSON(@PayloadJson) p
WHERE NOT EXISTS(SELECT 1 FROM dbo.StoryIntelligenceReviewCandidates c WHERE c.ReviewCandidateGenerationID=@GenerationID
AND c.DecisionStatus<>N'Pending' AND (c.StableKey=JSON_VALUE(p.value,'$.key') OR
(ISNULL(TRY_CONVERT(int,JSON_VALUE(c.CandidatePayloadJson,'$.reviewRulesVersion')),0)<3
AND ((JSON_VALUE(c.CandidatePayloadJson,'$.characterAName')=JSON_VALUE(p.value,'$.characterAName') AND JSON_VALUE(c.CandidatePayloadJson,'$.characterBName')=JSON_VALUE(p.value,'$.characterBName'))
OR (JSON_VALUE(c.CandidatePayloadJson,'$.characterAName')=JSON_VALUE(p.value,'$.characterBName') AND JSON_VALUE(c.CandidatePayloadJson,'$.characterBName')=JSON_VALUE(p.value,'$.characterAName'))))));
DELETE FROM dbo.StoryIntelligenceReviewCandidates WHERE ReviewCandidateGenerationID=@GenerationID AND DecisionStatus=N'Pending';
INSERT dbo.StoryIntelligenceReviewCandidates(ReviewCandidateGenerationID,ProjectID,BookID,Module,StableKey,CandidateType,DisplayName,SortOrder,ExistingCanonicalID,CandidatePayloadJson)
SELECT @GenerationID,g.ProjectID,@BookID,N'Relationships',JSON_VALUE(p.value,'$.key'),JSON_VALUE(p.value,'$.relationshipType'),
CONCAT(JSON_VALUE(p.value,'$.characterAName'),N' / ',JSON_VALUE(p.value,'$.characterBName')),CONVERT(int,p.ordinal)+1,
TRY_CONVERT(int,JSON_VALUE(p.value,'$.existingRelationshipID')),p.value
FROM #Incoming p JOIN dbo.StoryIntelligenceReviewCandidateGenerations g ON g.ReviewCandidateGenerationID=@GenerationID;
UPDATE g SET CandidateCount=(SELECT COUNT(*) FROM dbo.StoryIntelligenceReviewCandidates WHERE ReviewCandidateGenerationID=@GenerationID),
PendingCount=(SELECT COUNT(*) FROM dbo.StoryIntelligenceReviewCandidates WHERE ReviewCandidateGenerationID=@GenerationID AND DecisionStatus=N'Pending'),UpdatedUtc=SYSUTCDATETIME()
FROM dbo.StoryIntelligenceReviewCandidateGenerations g WHERE ReviewCandidateGenerationID=@GenerationID;
COMMIT;
END;
GO