PlotDirector/PlotLine/Sql/185_Phase27L_ManualCharacterEnrichment.sql

352 lines
13 KiB
Transact-SQL

SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
IF COL_LENGTH(N'dbo.CharacterEnrichmentRuns', N'CharacterID') IS NULL
BEGIN
ALTER TABLE dbo.CharacterEnrichmentRuns ADD CharacterID int NULL;
END;
GO
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_CharacterEnrichmentRuns_Characters')
BEGIN
ALTER TABLE dbo.CharacterEnrichmentRuns
ADD CONSTRAINT FK_CharacterEnrichmentRuns_Characters FOREIGN KEY (CharacterID) REFERENCES dbo.Characters(CharacterID);
END;
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_CharacterEnrichmentRuns_ActiveCharacter' AND object_id = OBJECT_ID(N'dbo.CharacterEnrichmentRuns'))
BEGIN
CREATE UNIQUE INDEX UX_CharacterEnrichmentRuns_ActiveCharacter
ON dbo.CharacterEnrichmentRuns(BookID, CharacterID)
WHERE CharacterID IS NOT NULL AND IsCurrent = 1 AND Status IN (N'Queued', N'Running');
END;
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_CharacterEnrichmentRuns_Character_Current' AND object_id = OBJECT_ID(N'dbo.CharacterEnrichmentRuns'))
BEGIN
CREATE INDEX IX_CharacterEnrichmentRuns_Character_Current
ON dbo.CharacterEnrichmentRuns(CharacterID, IsCurrent, UpdatedUtc DESC)
INCLUDE (BookID, UserID, Status, CompletedUtc);
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterEnrichmentRun_QueueCharacter
@CharacterID int,
@UserID int,
@BookID int = NULL
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @ProjectID int, @ResolvedBookID int, @PipelineID int, @ExistingID int, @Version nvarchar(120), @WasCoalesced bit = 1;
SELECT TOP (1)
@ProjectID = c.ProjectID,
@ResolvedBookID = ch.BookID
FROM dbo.Characters c
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = c.ProjectID
INNER JOIN dbo.SceneCharacters sc ON sc.CharacterID = c.CharacterID
INNER JOIN dbo.Scenes s ON s.SceneID = sc.SceneID AND s.IsArchived = 0
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID AND ch.IsArchived = 0
INNER JOIN dbo.SceneManuscriptSources sms ON sms.SceneID = s.SceneID
WHERE c.CharacterID = @CharacterID
AND c.IsArchived = 0
AND pua.UserID = @UserID
AND pua.AccessRole = N'Owner'
AND pua.IsActive = 1
AND (@BookID IS NULL OR ch.BookID = @BookID)
ORDER BY ch.SortOrder, ch.ChapterNumber, s.SortOrder, s.SceneNumber, s.SceneID;
IF @ProjectID IS NULL OR @ResolvedBookID IS NULL
THROW 52221, 'Character could not be queued for enrichment for this user and book.', 1;
SELECT TOP (1) @PipelineID = StoryIntelligenceBookPipelineID
FROM dbo.StoryIntelligenceBookPipelines
WHERE ProjectID = @ProjectID AND BookID = @ResolvedBookID
ORDER BY StoryIntelligenceBookPipelineID DESC;
SET @Version = CONCAT(N'ManualCharacter:', @CharacterID, N':Book:', @ResolvedBookID);
BEGIN TRANSACTION;
SELECT TOP (1) @ExistingID = CharacterEnrichmentRunID
FROM dbo.CharacterEnrichmentRuns WITH (UPDLOCK, HOLDLOCK)
WHERE BookID = @ResolvedBookID
AND CharacterID = @CharacterID
AND IsCurrent = 1
AND Status IN (N'Queued', N'Running')
ORDER BY CharacterEnrichmentRunID DESC;
IF @ExistingID IS NULL
BEGIN
UPDATE dbo.CharacterEnrichmentRuns
SET IsCurrent = 0,
Status = N'Superseded',
UpdatedUtc = SYSUTCDATETIME()
WHERE BookID = @ResolvedBookID
AND CharacterID = @CharacterID
AND IsCurrent = 1;
INSERT dbo.CharacterEnrichmentRuns
(ProjectID, BookID, UserID, CharacterID, StoryIntelligenceBookPipelineID, CharacterResolutionVersion, Status, TotalCharacters, CurrentStage, CurrentMessage)
VALUES
(@ProjectID, @ResolvedBookID, @UserID, @CharacterID, @PipelineID, @Version, N'Queued', 1, N'Queued', N'Character reanalysis is queued.');
SET @ExistingID = CAST(SCOPE_IDENTITY() AS int);
SET @WasCoalesced = 0;
END;
COMMIT TRANSACTION;
SELECT runRows.*, WasCoalesced = @WasCoalesced
FROM dbo.CharacterEnrichmentRuns runRows
WHERE runRows.CharacterEnrichmentRunID = @ExistingID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterEnrichmentRun_Retry
@BookID int,
@UserID int
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @PreviousID int, @ProjectID int, @PipelineID int, @Version nvarchar(120);
SELECT TOP (1)
@PreviousID = CharacterEnrichmentRunID,
@ProjectID = ProjectID,
@PipelineID = StoryIntelligenceBookPipelineID,
@Version = CharacterResolutionVersion
FROM dbo.CharacterEnrichmentRuns
WHERE BookID = @BookID AND UserID = @UserID AND CharacterID IS NULL AND IsCurrent = 1 AND Status = N'Failed'
ORDER BY CharacterEnrichmentRunID DESC;
IF @PreviousID IS NULL
BEGIN
SELECT TOP (0) * FROM dbo.CharacterEnrichmentRuns;
RETURN;
END;
UPDATE dbo.CharacterEnrichmentRuns
SET IsCurrent = 0,
Status = N'Superseded',
UpdatedUtc = SYSUTCDATETIME()
WHERE CharacterEnrichmentRunID = @PreviousID;
EXEC dbo.CharacterEnrichmentRun_Queue
@ProjectID = @ProjectID,
@BookID = @BookID,
@UserID = @UserID,
@StoryIntelligenceBookPipelineID = @PipelineID,
@CharacterResolutionVersion = @Version;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterEnrichmentRun_GetCurrentByBook
@BookID int
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP (1) *
FROM dbo.CharacterEnrichmentRuns
WHERE BookID = @BookID AND CharacterID IS NULL AND IsCurrent = 1
ORDER BY CharacterEnrichmentRunID DESC;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterEnrichmentRun_GetCurrentByCharacter
@CharacterID int,
@UserID int
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP (1) runRows.*
FROM dbo.CharacterEnrichmentRuns runRows
INNER JOIN dbo.Characters c ON c.CharacterID = @CharacterID AND c.ProjectID = runRows.ProjectID
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = c.ProjectID
WHERE runRows.CharacterID = @CharacterID
AND runRows.UserID = @UserID
AND runRows.IsCurrent = 1
AND pua.UserID = @UserID
AND pua.AccessRole = N'Owner'
AND pua.IsActive = 1
ORDER BY runRows.CharacterEnrichmentRunID DESC;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterEnrichment_ContextGet
@ProjectID int,
@BookID int,
@CharacterID int = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT
BookTitle = CASE WHEN NULLIF(LTRIM(RTRIM(b.Subtitle)), N'') IS NULL THEN b.BookTitle ELSE CONCAT(b.BookTitle, N': ', b.Subtitle) END,
b.StoryEra,
SeriesStartDate = CAST(NULL AS date)
FROM dbo.Books b
WHERE b.BookID = @BookID AND b.ProjectID = @ProjectID AND b.IsArchived = 0;
SELECT DISTINCT
c.CharacterID,
c.CharacterName,
c.BirthDate,
c.AgeAtSeriesStart,
c.Height,
c.EyeColour,
c.DefaultDescription
FROM dbo.Characters c
INNER JOIN dbo.SceneCharacters sc ON sc.CharacterID = c.CharacterID
INNER JOIN dbo.Scenes s ON s.SceneID = sc.SceneID AND s.IsArchived = 0
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID AND ch.IsArchived = 0
INNER JOIN dbo.SceneManuscriptSources sms ON sms.SceneID = s.SceneID
WHERE c.ProjectID = @ProjectID
AND c.IsArchived = 0
AND ch.BookID = @BookID
AND (@CharacterID IS NULL OR c.CharacterID = @CharacterID)
ORDER BY c.CharacterName;
SELECT alias.CharacterID, alias.Alias
FROM dbo.CharacterAliases alias
INNER JOIN dbo.Characters c ON c.CharacterID = alias.CharacterID
WHERE c.ProjectID = @ProjectID
AND c.IsArchived = 0
AND (@CharacterID IS NULL OR c.CharacterID = @CharacterID)
ORDER BY alias.CharacterID, alias.SortOrder, alias.Alias;
SELECT
sc.CharacterID,
s.SceneID,
ch.ChapterID,
ch.ChapterNumber,
ch.ChapterTitle,
s.SceneNumber,
s.SceneTitle,
sms.SourceText
FROM dbo.SceneCharacters sc
INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID AND c.ProjectID = @ProjectID AND c.IsArchived = 0
INNER JOIN dbo.Scenes s ON s.SceneID = sc.SceneID AND s.IsArchived = 0
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID AND ch.BookID = @BookID AND ch.IsArchived = 0
INNER JOIN dbo.SceneManuscriptSources sms ON sms.SceneID = s.SceneID
WHERE @CharacterID IS NULL OR sc.CharacterID = @CharacterID
ORDER BY sc.CharacterID, ch.SortOrder, ch.ChapterNumber, s.SortOrder, s.SceneNumber, s.SceneID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterEnrichmentCharacterStatus_Get
@CharacterID int,
@UserID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ProjectID int;
SELECT @ProjectID = c.ProjectID
FROM dbo.Characters c
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = c.ProjectID
WHERE c.CharacterID = @CharacterID
AND c.IsArchived = 0
AND pua.UserID = @UserID
AND pua.AccessRole = N'Owner'
AND pua.IsActive = 1;
IF @ProjectID IS NULL
BEGIN
SELECT TOP (0)
CharacterID = CAST(NULL AS int),
BookID = CAST(NULL AS int),
CharacterEnrichmentRunID = CAST(NULL AS int),
Status = CAST(NULL AS nvarchar(30)),
CurrentStage = CAST(NULL AS nvarchar(120)),
CurrentMessage = CAST(NULL AS nvarchar(300)),
LastAnalysedUtc = CAST(NULL AS datetime2),
ErrorMessage = CAST(NULL AS nvarchar(max)),
Summary = CAST(NULL AS nvarchar(max)),
DateOfBirth = CAST(NULL AS nvarchar(500)),
AgeAtStartOfSeries = CAST(NULL AS nvarchar(500)),
Height = CAST(NULL AS nvarchar(500)),
EyeColour = CAST(NULL AS nvarchar(500)),
UpdatedUtc = CAST(NULL AS datetime2);
RETURN;
END;
DECLARE @Attempt TABLE
(
CharacterEnrichmentRunID int NULL,
BookID int NULL,
Status nvarchar(30) NULL,
CurrentStage nvarchar(120) NULL,
CurrentMessage nvarchar(300) NULL,
ErrorMessage nvarchar(max) NULL,
UpdatedUtc datetime2 NULL
);
INSERT @Attempt
SELECT TOP (1)
runRows.CharacterEnrichmentRunID,
runRows.BookID,
runRows.Status,
runRows.CurrentStage,
runRows.CurrentMessage,
runRows.ErrorMessage,
runRows.UpdatedUtc
FROM dbo.CharacterEnrichmentRuns runRows
WHERE runRows.UserID = @UserID
AND runRows.ProjectID = @ProjectID
AND runRows.CharacterID = @CharacterID
AND runRows.IsCurrent = 1
ORDER BY CASE runRows.Status WHEN N'Queued' THEN 0 WHEN N'Running' THEN 0 WHEN N'Failed' THEN 1 WHEN N'Completed' THEN 2 ELSE 9 END,
runRows.UpdatedUtc DESC,
runRows.CharacterEnrichmentRunID DESC;
DECLARE @SuccessRunID int, @SuccessBookID int, @LastAnalysedUtc datetime2;
SELECT TOP (1)
@SuccessRunID = runRows.CharacterEnrichmentRunID,
@SuccessBookID = runRows.BookID,
@LastAnalysedUtc = runRows.CompletedUtc
FROM dbo.CharacterEnrichmentRuns runRows
WHERE runRows.UserID = @UserID
AND runRows.ProjectID = @ProjectID
AND runRows.Status = N'Completed'
AND runRows.CompletedUtc IS NOT NULL
AND (
runRows.CharacterID = @CharacterID
OR EXISTS
(
SELECT 1
FROM dbo.CharacterEnrichmentEvidence evidence
WHERE evidence.CharacterEnrichmentRunID = runRows.CharacterEnrichmentRunID
AND evidence.CharacterID = @CharacterID
)
)
ORDER BY runRows.CompletedUtc DESC, runRows.CharacterEnrichmentRunID DESC;
SELECT
CharacterID = @CharacterID,
BookID = COALESCE((SELECT TOP (1) BookID FROM @Attempt), @SuccessBookID),
CharacterEnrichmentRunID = COALESCE((SELECT TOP (1) CharacterEnrichmentRunID FROM @Attempt), @SuccessRunID),
Status = COALESCE((SELECT TOP (1) Status FROM @Attempt), CASE WHEN @SuccessRunID IS NULL THEN N'Not analysed' ELSE N'Completed' END),
CurrentStage = (SELECT TOP (1) CurrentStage FROM @Attempt),
CurrentMessage = (SELECT TOP (1) CurrentMessage FROM @Attempt),
LastAnalysedUtc = @LastAnalysedUtc,
ErrorMessage = (SELECT TOP (1) ErrorMessage FROM @Attempt),
Summary = MAX(CASE WHEN evidence.FieldName = N'Summary' THEN evidence.Value END),
DateOfBirth = MAX(CASE WHEN evidence.FieldName = N'DateOfBirth' THEN evidence.Value END),
AgeAtStartOfSeries = MAX(CASE WHEN evidence.FieldName = N'AgeAtStartOfSeries' THEN evidence.Value END),
Height = MAX(CASE WHEN evidence.FieldName = N'Height' THEN evidence.Value END),
EyeColour = MAX(CASE WHEN evidence.FieldName = N'EyeColour' THEN evidence.Value END),
UpdatedUtc = COALESCE((SELECT TOP (1) UpdatedUtc FROM @Attempt), @LastAnalysedUtc, SYSUTCDATETIME())
FROM (SELECT 1 AS Anchor) anchor
LEFT JOIN dbo.CharacterEnrichmentEvidence evidence
ON evidence.CharacterEnrichmentRunID = @SuccessRunID
AND evidence.CharacterID = @CharacterID;
END;
GO