PlotDirector/PlotLine/Sql/186_Phase27M_AuthoritativeGlobalProgressCompletedScenes.sql

226 lines
9.4 KiB
Transact-SQL

SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_StoryIntelligenceSceneResults_BookSceneRun' AND object_id = OBJECT_ID(N'dbo.StoryIntelligenceSceneResults'))
BEGIN
CREATE INDEX IX_StoryIntelligenceSceneResults_BookSceneRun
ON dbo.StoryIntelligenceSceneResults(BookID, SceneID, StoryIntelligenceRunID)
INCLUDE (ProjectID, ChapterID, CreatedUtc);
END;
GO
CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceRun_ListActiveBookSummaryForUser
@UserID int
AS
BEGIN
SET NOCOUNT ON;
;WITH RunScopes AS
(
SELECT
r.UserID,
r.ProjectID,
r.BookID,
LatestCreatedUtc = MAX(r.CreatedUtc),
LatestUpdatedUtc = MAX(r.UpdatedUtc)
FROM dbo.StoryIntelligenceRuns r
INNER JOIN dbo.Projects p ON p.ProjectID = r.ProjectID AND p.IsArchived = 0
INNER JOIN dbo.Books b ON b.BookID = r.BookID AND b.IsArchived = 0
INNER JOIN dbo.ProjectUserAccess access
ON access.ProjectID = r.ProjectID
AND access.UserID = @UserID
AND access.IsActive = 1
WHERE r.UserID = @UserID
AND r.BookID IS NOT NULL
AND r.Status IN (N'Pending', N'Running')
GROUP BY r.UserID, r.ProjectID, r.BookID
),
PipelineScopes AS
(
SELECT
@UserID AS UserID,
p.ProjectID,
p.BookID,
LatestCreatedUtc = MAX(COALESCE(lastRun.CreatedUtc, p.CreatedUtc)),
LatestUpdatedUtc = MAX(CASE
WHEN lastRun.UpdatedUtc IS NOT NULL AND lastRun.UpdatedUtc > p.UpdatedUtc THEN lastRun.UpdatedUtc
ELSE p.UpdatedUtc
END)
FROM dbo.StoryIntelligenceBookPipelines p
INNER JOIN dbo.Projects project ON project.ProjectID = p.ProjectID AND project.IsArchived = 0
INNER JOIN dbo.Books book ON book.BookID = p.BookID AND book.IsArchived = 0
INNER JOIN dbo.ProjectUserAccess access
ON access.ProjectID = p.ProjectID
AND access.UserID = @UserID
AND access.IsActive = 1
LEFT JOIN dbo.StoryIntelligenceRuns lastRun ON lastRun.StoryIntelligenceRunID = p.LastRunID
WHERE p.Status = N'InProgress'
GROUP BY p.ProjectID, p.BookID
),
ActiveScopes AS
(
SELECT
scopes.UserID,
scopes.ProjectID,
scopes.BookID,
LatestCreatedUtc = MAX(scopes.LatestCreatedUtc),
LatestUpdatedUtc = MAX(scopes.LatestUpdatedUtc)
FROM
(
SELECT UserID, ProjectID, BookID, LatestCreatedUtc, LatestUpdatedUtc FROM RunScopes
UNION ALL
SELECT UserID, ProjectID, BookID, LatestCreatedUtc, LatestUpdatedUtc FROM PipelineScopes
) scopes
GROUP BY scopes.UserID, scopes.ProjectID, scopes.BookID
),
ScopedRuns AS
(
SELECT r.*
FROM dbo.StoryIntelligenceRuns r
INNER JOIN ActiveScopes scope
ON scope.UserID = r.UserID
AND ISNULL(scope.ProjectID, -1) = ISNULL(r.ProjectID, -1)
AND ISNULL(scope.BookID, -1) = ISNULL(r.BookID, -1)
AND r.CreatedUtc >= DATEADD(minute, -30, scope.LatestCreatedUtc)
WHERE r.Status IN (N'Pending', N'Running', N'Completed', N'CompletedWithWarnings', N'Failed', N'Cancelled')
),
CanonicalSceneScope AS
(
SELECT DISTINCT
scope.UserID,
scope.ProjectID,
scope.BookID,
s.SceneID
FROM ActiveScopes scope
INNER JOIN dbo.Chapters c
ON c.BookID = scope.BookID
AND c.IsArchived = 0
INNER JOIN dbo.Scenes s
ON s.ChapterID = c.ChapterID
AND s.IsArchived = 0
),
RunSummary AS
(
SELECT
scope.UserID,
scope.ProjectID,
scope.BookID,
COUNT(r.StoryIntelligenceRunID) AS RunCount,
SUM(CASE WHEN r.Status = N'Pending' THEN 1 ELSE 0 END) AS PendingRunCount,
SUM(CASE WHEN r.Status = N'Running' THEN 1 ELSE 0 END) AS RunningRunCount,
SUM(CASE WHEN r.Status IN (N'Completed', N'CompletedWithWarnings') THEN 1 ELSE 0 END) AS CompletedRunCount,
SUM(CASE WHEN r.Status IN (N'Failed', N'Cancelled') THEN 1 ELSE 0 END) AS FailedRunCount,
SUM(ISNULL(r.TotalDetectedScenes, 0)) AS TotalDetectedScenes,
SUM(ISNULL(r.CompletedScenes, 0)) AS CompletedScenes,
SUM(ISNULL(r.FailedScenes, 0)) AS FailedScenes,
SUM(CASE
WHEN r.Status IN (N'Pending', N'Running')
THEN CASE
WHEN ISNULL(r.TotalDetectedScenes, 0) - ISNULL(r.CompletedScenes, 0) - ISNULL(r.FailedScenes, 0) > 0
THEN ISNULL(r.TotalDetectedScenes, 0) - ISNULL(r.CompletedScenes, 0) - ISNULL(r.FailedScenes, 0)
ELSE 0
END
ELSE 0
END) AS ActiveScenes,
SUM(ISNULL(r.TotalDurationMs, 0)) AS TotalDurationMs,
MIN(COALESCE(r.CreatedUtc, scope.LatestCreatedUtc)) AS FirstCreatedUtc,
MAX(CASE
WHEN r.UpdatedUtc IS NOT NULL AND r.UpdatedUtc > scope.LatestUpdatedUtc THEN r.UpdatedUtc
ELSE scope.LatestUpdatedUtc
END) AS UpdatedUtc
FROM ActiveScopes scope
LEFT JOIN ScopedRuns r
ON r.UserID = scope.UserID
AND ISNULL(r.ProjectID, -1) = ISNULL(scope.ProjectID, -1)
AND ISNULL(r.BookID, -1) = ISNULL(scope.BookID, -1)
GROUP BY scope.UserID, scope.ProjectID, scope.BookID
),
ExpectedSceneSummary AS
(
SELECT
scope.UserID,
scope.ProjectID,
scope.BookID,
COUNT(scope.SceneID) AS TotalExpectedScenes
FROM CanonicalSceneScope scope
GROUP BY scope.UserID, scope.ProjectID, scope.BookID
),
CompletedSceneSummary AS
(
SELECT
scope.UserID,
scope.ProjectID,
scope.BookID,
COUNT(DISTINCT results.SceneID) AS CompletedScenes
FROM CanonicalSceneScope scope
INNER JOIN dbo.StoryIntelligenceSceneResults results
ON results.SceneID = scope.SceneID
INNER JOIN dbo.StoryIntelligenceRuns runRows
ON runRows.StoryIntelligenceRunID = results.StoryIntelligenceRunID
AND runRows.UserID = scope.UserID
AND ISNULL(runRows.ProjectID, -1) = ISNULL(scope.ProjectID, -1)
AND ISNULL(runRows.BookID, -1) = ISNULL(scope.BookID, -1)
GROUP BY scope.UserID, scope.ProjectID, scope.BookID
)
SELECT
summary.UserID,
summary.ProjectID,
p.ProjectName AS ProjectTitle,
summary.BookID,
b.BookTitle,
b.Subtitle AS BookSubtitle,
summary.RunCount,
summary.PendingRunCount,
summary.RunningRunCount,
summary.CompletedRunCount,
summary.FailedRunCount,
COALESCE(expected.TotalExpectedScenes, NULLIF(summary.TotalDetectedScenes, 0), 0) AS TotalExpectedScenes,
summary.TotalDetectedScenes,
COALESCE(completed.CompletedScenes, summary.CompletedScenes, 0) AS CompletedScenes,
summary.FailedScenes,
summary.ActiveScenes,
CASE
WHEN COALESCE(expected.TotalExpectedScenes, NULLIF(summary.TotalDetectedScenes, 0), 0) <= 0 THEN 0
ELSE CONVERT(int, ROUND(COALESCE(completed.CompletedScenes, summary.CompletedScenes, 0) * 100.0 / COALESCE(expected.TotalExpectedScenes, NULLIF(summary.TotalDetectedScenes, 0), 1), 0))
END AS ProgressPercent,
CASE
WHEN pipeline.Status = N'InProgress'
AND summary.RunningRunCount = 0
AND summary.PendingRunCount = 0
THEN N'Finalising'
WHEN pipeline.Status = N'InProgress'
AND COALESCE(expected.TotalExpectedScenes, NULLIF(summary.TotalDetectedScenes, 0), 0) > 0
AND COALESCE(completed.CompletedScenes, summary.CompletedScenes, 0) + summary.FailedScenes >= COALESCE(expected.TotalExpectedScenes, NULLIF(summary.TotalDetectedScenes, 0), 0)
THEN N'Finalising'
WHEN summary.RunningRunCount > 0 THEN N'Running'
WHEN summary.PendingRunCount > 0 THEN N'Pending'
WHEN summary.FailedRunCount > 0 THEN N'Failed'
WHEN summary.FailedScenes > 0 THEN N'CompletedWithWarnings'
ELSE N'Completed'
END AS Status,
summary.TotalDurationMs,
summary.FirstCreatedUtc,
summary.UpdatedUtc
FROM RunSummary summary
LEFT JOIN ExpectedSceneSummary expected
ON expected.UserID = summary.UserID
AND ISNULL(expected.ProjectID, -1) = ISNULL(summary.ProjectID, -1)
AND ISNULL(expected.BookID, -1) = ISNULL(summary.BookID, -1)
LEFT JOIN CompletedSceneSummary completed
ON completed.UserID = summary.UserID
AND ISNULL(completed.ProjectID, -1) = ISNULL(summary.ProjectID, -1)
AND ISNULL(completed.BookID, -1) = ISNULL(summary.BookID, -1)
LEFT JOIN dbo.StoryIntelligenceBookPipelines pipeline
ON pipeline.BookID = summary.BookID
AND pipeline.ProjectID = summary.ProjectID
LEFT JOIN dbo.Projects p ON p.ProjectID = summary.ProjectID
LEFT JOIN dbo.Books b ON b.BookID = summary.BookID
WHERE summary.PendingRunCount > 0
OR summary.RunningRunCount > 0
OR pipeline.Status = N'InProgress'
ORDER BY summary.UpdatedUtc DESC, summary.FirstCreatedUtc;
END;
GO