494 lines
23 KiB
Transact-SQL
494 lines
23 KiB
Transact-SQL
SET ANSI_NULLS ON;
|
|
GO
|
|
SET QUOTED_IDENTIFIER ON;
|
|
GO
|
|
|
|
IF OBJECT_ID(N'dbo.Scenarios', N'U') IS NULL
|
|
BEGIN
|
|
CREATE TABLE dbo.Scenarios
|
|
(
|
|
ScenarioID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Scenarios PRIMARY KEY,
|
|
ProjectID int NOT NULL,
|
|
BookID int NULL,
|
|
ScenarioName nvarchar(200) NOT NULL,
|
|
Description nvarchar(max) NULL,
|
|
BaseCreatedDate datetime2 NOT NULL CONSTRAINT DF_Scenarios_BaseCreatedDate DEFAULT SYSUTCDATETIME(),
|
|
IsAppliedToMain bit NOT NULL CONSTRAINT DF_Scenarios_IsAppliedToMain DEFAULT 0,
|
|
IsArchived bit NOT NULL CONSTRAINT DF_Scenarios_IsArchived DEFAULT 0,
|
|
CreatedDate datetime2 NOT NULL CONSTRAINT DF_Scenarios_CreatedDate DEFAULT SYSUTCDATETIME(),
|
|
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_Scenarios_UpdatedDate DEFAULT SYSUTCDATETIME(),
|
|
CONSTRAINT FK_Scenarios_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
|
|
CONSTRAINT FK_Scenarios_Books FOREIGN KEY (BookID) REFERENCES dbo.Books(BookID)
|
|
);
|
|
END;
|
|
GO
|
|
|
|
IF OBJECT_ID(N'dbo.ScenarioSceneOrder', N'U') IS NULL
|
|
BEGIN
|
|
CREATE TABLE dbo.ScenarioSceneOrder
|
|
(
|
|
ScenarioSceneOrderID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ScenarioSceneOrder PRIMARY KEY,
|
|
ScenarioID int NOT NULL,
|
|
SceneID int NOT NULL,
|
|
ProposedChapterID int NULL,
|
|
ProposedSortOrder int NOT NULL,
|
|
Notes nvarchar(max) NULL,
|
|
CreatedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioSceneOrder_CreatedDate DEFAULT SYSUTCDATETIME(),
|
|
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioSceneOrder_UpdatedDate DEFAULT SYSUTCDATETIME(),
|
|
CONSTRAINT FK_ScenarioSceneOrder_Scenarios FOREIGN KEY (ScenarioID) REFERENCES dbo.Scenarios(ScenarioID),
|
|
CONSTRAINT FK_ScenarioSceneOrder_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
|
|
CONSTRAINT FK_ScenarioSceneOrder_Chapters FOREIGN KEY (ProposedChapterID) REFERENCES dbo.Chapters(ChapterID),
|
|
CONSTRAINT UQ_ScenarioSceneOrder_ScenarioScene UNIQUE (ScenarioID, SceneID)
|
|
);
|
|
END;
|
|
GO
|
|
|
|
IF OBJECT_ID(N'dbo.ScenarioValidationRuns', N'U') IS NULL
|
|
BEGIN
|
|
CREATE TABLE dbo.ScenarioValidationRuns
|
|
(
|
|
ScenarioValidationRunID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ScenarioValidationRuns PRIMARY KEY,
|
|
ScenarioID int NOT NULL,
|
|
StartedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioValidationRuns_StartedDate DEFAULT SYSUTCDATETIME(),
|
|
CompletedDate datetime2 NULL,
|
|
WarningCount int NOT NULL CONSTRAINT DF_ScenarioValidationRuns_WarningCount DEFAULT 0,
|
|
CONSTRAINT FK_ScenarioValidationRuns_Scenarios FOREIGN KEY (ScenarioID) REFERENCES dbo.Scenarios(ScenarioID)
|
|
);
|
|
END;
|
|
GO
|
|
|
|
IF OBJECT_ID(N'dbo.ScenarioWarnings', N'U') IS NULL
|
|
BEGIN
|
|
CREATE TABLE dbo.ScenarioWarnings
|
|
(
|
|
ScenarioWarningID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ScenarioWarnings PRIMARY KEY,
|
|
ScenarioValidationRunID int NOT NULL,
|
|
ScenarioID int NOT NULL,
|
|
SceneID int NULL,
|
|
EntityType nvarchar(80) NOT NULL,
|
|
EntityID int NULL,
|
|
WarningTypeName nvarchar(150) NOT NULL,
|
|
SeverityName nvarchar(50) NOT NULL,
|
|
Message nvarchar(500) NOT NULL,
|
|
Details nvarchar(max) NULL,
|
|
CreatedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioWarnings_CreatedDate DEFAULT SYSUTCDATETIME(),
|
|
CONSTRAINT FK_ScenarioWarnings_Runs FOREIGN KEY (ScenarioValidationRunID) REFERENCES dbo.ScenarioValidationRuns(ScenarioValidationRunID),
|
|
CONSTRAINT FK_ScenarioWarnings_Scenarios FOREIGN KEY (ScenarioID) REFERENCES dbo.Scenarios(ScenarioID),
|
|
CONSTRAINT FK_ScenarioWarnings_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID)
|
|
);
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_List
|
|
@ProjectID int
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
SELECT sc.ScenarioID, sc.ProjectID, sc.BookID, sc.ScenarioName, sc.Description, sc.BaseCreatedDate,
|
|
sc.IsAppliedToMain, sc.IsArchived, sc.CreatedDate, sc.UpdatedDate,
|
|
p.ProjectName, b.BookTitle,
|
|
COUNT(DISTINCT sso.SceneID) AS SceneCount,
|
|
COUNT(DISTINCT sw.ScenarioWarningID) AS WarningCount
|
|
FROM dbo.Scenarios sc
|
|
INNER JOIN dbo.Projects p ON p.ProjectID = sc.ProjectID
|
|
LEFT JOIN dbo.Books b ON b.BookID = sc.BookID
|
|
LEFT JOIN dbo.ScenarioSceneOrder sso ON sso.ScenarioID = sc.ScenarioID
|
|
LEFT JOIN dbo.ScenarioWarnings sw ON sw.ScenarioID = sc.ScenarioID
|
|
WHERE sc.ProjectID = @ProjectID AND sc.IsArchived = 0
|
|
GROUP BY sc.ScenarioID, sc.ProjectID, sc.BookID, sc.ScenarioName, sc.Description, sc.BaseCreatedDate,
|
|
sc.IsAppliedToMain, sc.IsArchived, sc.CreatedDate, sc.UpdatedDate, p.ProjectName, b.BookTitle
|
|
ORDER BY sc.UpdatedDate DESC, sc.ScenarioName;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_Get
|
|
@ScenarioID int
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
SELECT sc.ScenarioID, sc.ProjectID, sc.BookID, sc.ScenarioName, sc.Description, sc.BaseCreatedDate,
|
|
sc.IsAppliedToMain, sc.IsArchived, sc.CreatedDate, sc.UpdatedDate,
|
|
p.ProjectName, b.BookTitle,
|
|
(SELECT COUNT(*) FROM dbo.ScenarioSceneOrder WHERE ScenarioID = sc.ScenarioID) AS SceneCount,
|
|
(SELECT COUNT(*) FROM dbo.ScenarioWarnings WHERE ScenarioID = sc.ScenarioID) AS WarningCount
|
|
FROM dbo.Scenarios sc
|
|
INNER JOIN dbo.Projects p ON p.ProjectID = sc.ProjectID
|
|
LEFT JOIN dbo.Books b ON b.BookID = sc.BookID
|
|
WHERE sc.ScenarioID = @ScenarioID AND sc.IsArchived = 0;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_Create
|
|
@ProjectID int,
|
|
@BookID int = NULL,
|
|
@ScenarioName nvarchar(200),
|
|
@Description nvarchar(max) = NULL
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
INSERT dbo.Scenarios (ProjectID, BookID, ScenarioName, Description)
|
|
VALUES (@ProjectID, @BookID, @ScenarioName, @Description);
|
|
|
|
DECLARE @ScenarioID int = CAST(SCOPE_IDENTITY() AS int);
|
|
|
|
INSERT dbo.ScenarioSceneOrder (ScenarioID, SceneID, ProposedChapterID, ProposedSortOrder)
|
|
SELECT @ScenarioID, nso.SceneID, nso.ChapterID,
|
|
ROW_NUMBER() OVER (ORDER BY nso.GlobalSceneIndex) * 10
|
|
FROM dbo.NarrativeSceneOrder nso
|
|
WHERE nso.ProjectID = @ProjectID AND (@BookID IS NULL OR nso.BookID = @BookID)
|
|
ORDER BY nso.GlobalSceneIndex;
|
|
|
|
SELECT @ScenarioID;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_Timeline
|
|
@ScenarioID int
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
DECLARE @ProjectID int = (SELECT ProjectID FROM dbo.Scenarios WHERE ScenarioID = @ScenarioID);
|
|
DECLARE @BookID int = (SELECT BookID FROM dbo.Scenarios WHERE ScenarioID = @ScenarioID);
|
|
|
|
SELECT BookID, ProjectID, BookTitle, BookNumber, Description, SortOrder, CreatedDate, UpdatedDate, IsArchived
|
|
FROM dbo.Books
|
|
WHERE ProjectID = @ProjectID AND IsArchived = 0 AND (@BookID IS NULL OR BookID = @BookID)
|
|
ORDER BY SortOrder, BookNumber;
|
|
|
|
SELECT c.ChapterID, c.BookID, c.ChapterNumber, c.ChapterTitle, c.POVCharacterID, c.Summary, c.SortOrder,
|
|
c.RevisionStatusID, rs.StatusName AS RevisionStatusName, c.CreatedDate, c.UpdatedDate, c.IsArchived
|
|
FROM dbo.Chapters c
|
|
INNER JOIN dbo.Books b ON b.BookID = c.BookID
|
|
INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID
|
|
WHERE b.ProjectID = @ProjectID AND c.IsArchived = 0 AND b.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
|
|
ORDER BY b.SortOrder, c.SortOrder, c.ChapterNumber;
|
|
|
|
SELECT sso.ScenarioSceneOrderID, sso.ScenarioID, sso.SceneID, s.ChapterID AS OriginalChapterID,
|
|
ISNULL(sso.ProposedChapterID, s.ChapterID) AS ProposedChapterID, sso.ProposedSortOrder, sso.Notes,
|
|
ch.ChapterNumber, ch.ChapterTitle, s.SceneNumber, s.SceneTitle, s.Summary, rs.StatusName AS RevisionStatusName,
|
|
COALESCE(NULLIF(s.RelativeTimeText, N''), CONVERT(nvarchar(20), s.StartDateTime, 106), tm.TimeModeName) AS TimeLabel,
|
|
threadData.ThreadLabels, assetData.AssetLabels, characterData.CharacterLabels, loc.LocationPath AS LocationLabel,
|
|
(SELECT COUNT(*) FROM dbo.ScenarioWarnings sw WHERE sw.ScenarioID = @ScenarioID AND sw.SceneID = s.SceneID) AS WarningCount
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
|
INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
|
|
INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID
|
|
LEFT JOIN dbo.LocationPaths loc ON loc.LocationID = s.PrimaryLocationID
|
|
OUTER APPLY
|
|
(
|
|
SELECT STRING_AGG(CONVERT(nvarchar(max), pt.ThreadTitle), N', ') AS ThreadLabels
|
|
FROM dbo.ThreadEvents te INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
|
|
WHERE te.SceneID = s.SceneID
|
|
) threadData
|
|
OUTER APPLY
|
|
(
|
|
SELECT STRING_AGG(CONVERT(nvarchar(max), sa.AssetName), N', ') AS AssetLabels
|
|
FROM dbo.AssetEvents ae INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ae.StoryAssetID
|
|
WHERE ae.SceneID = s.SceneID
|
|
) assetData
|
|
OUTER APPLY
|
|
(
|
|
SELECT STRING_AGG(CONVERT(nvarchar(max), c.CharacterName), N', ') AS CharacterLabels
|
|
FROM dbo.SceneCharacters sc INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID
|
|
WHERE sc.SceneID = s.SceneID
|
|
) characterData
|
|
WHERE sso.ScenarioID = @ScenarioID
|
|
ORDER BY ch.SortOrder, ch.ChapterNumber, sso.ProposedSortOrder, s.SceneID;
|
|
|
|
SELECT ScenarioWarningID, ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details, CreatedDate
|
|
FROM dbo.ScenarioWarnings
|
|
WHERE ScenarioID = @ScenarioID
|
|
ORDER BY CASE SeverityName WHEN N'Critical' THEN 4 WHEN N'Warning' THEN 3 WHEN N'Info' THEN 2 ELSE 1 END DESC, CreatedDate DESC;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_MoveScene
|
|
@ScenarioID int,
|
|
@SceneID int,
|
|
@AnchorSceneID int = NULL,
|
|
@TargetChapterID int = NULL,
|
|
@Position nvarchar(20)
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
DECLARE @ChapterID int;
|
|
DECLARE @NewSortOrder int;
|
|
DECLARE @AnchorSortOrder int;
|
|
|
|
IF @AnchorSceneID IS NOT NULL
|
|
BEGIN
|
|
SELECT @ChapterID = ISNULL(ProposedChapterID, s.ChapterID), @AnchorSortOrder = ProposedSortOrder
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
WHERE sso.ScenarioID = @ScenarioID AND sso.SceneID = @AnchorSceneID;
|
|
|
|
IF @Position = N'Before'
|
|
SELECT @NewSortOrder = ISNULL(MAX(ProposedSortOrder), @AnchorSortOrder - 20) + ((@AnchorSortOrder - ISNULL(MAX(ProposedSortOrder), @AnchorSortOrder - 20)) / 2)
|
|
FROM dbo.ScenarioSceneOrder
|
|
WHERE ScenarioID = @ScenarioID AND ISNULL(ProposedChapterID, 0) = ISNULL(@ChapterID, 0) AND ProposedSortOrder < @AnchorSortOrder;
|
|
ELSE
|
|
SELECT @NewSortOrder = (@AnchorSortOrder + ISNULL(MIN(ProposedSortOrder), @AnchorSortOrder + 20)) / 2
|
|
FROM dbo.ScenarioSceneOrder
|
|
WHERE ScenarioID = @ScenarioID AND ISNULL(ProposedChapterID, 0) = ISNULL(@ChapterID, 0) AND ProposedSortOrder > @AnchorSortOrder;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
SET @ChapterID = @TargetChapterID;
|
|
SELECT @NewSortOrder = ISNULL(MAX(ProposedSortOrder), 0) + 10
|
|
FROM dbo.ScenarioSceneOrder
|
|
WHERE ScenarioID = @ScenarioID AND ProposedChapterID = @ChapterID;
|
|
END;
|
|
|
|
UPDATE dbo.ScenarioSceneOrder
|
|
SET ProposedChapterID = @ChapterID,
|
|
ProposedSortOrder = ISNULL(@NewSortOrder, ProposedSortOrder),
|
|
UpdatedDate = SYSUTCDATETIME()
|
|
WHERE ScenarioID = @ScenarioID AND SceneID = @SceneID;
|
|
|
|
;WITH ordered AS
|
|
(
|
|
SELECT ScenarioSceneOrderID,
|
|
ROW_NUMBER() OVER (PARTITION BY ProposedChapterID ORDER BY ProposedSortOrder, ScenarioSceneOrderID) * 10 AS NextSortOrder
|
|
FROM dbo.ScenarioSceneOrder
|
|
WHERE ScenarioID = @ScenarioID
|
|
)
|
|
UPDATE sso
|
|
SET ProposedSortOrder = ordered.NextSortOrder,
|
|
UpdatedDate = SYSUTCDATETIME()
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN ordered ON ordered.ScenarioSceneOrderID = sso.ScenarioSceneOrderID;
|
|
|
|
UPDATE dbo.Scenarios SET UpdatedDate = SYSUTCDATETIME() WHERE ScenarioID = @ScenarioID;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_Validate
|
|
@ScenarioID int
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
DELETE FROM dbo.ScenarioWarnings WHERE ScenarioID = @ScenarioID;
|
|
|
|
INSERT dbo.ScenarioValidationRuns (ScenarioID)
|
|
VALUES (@ScenarioID);
|
|
|
|
DECLARE @RunID int = CAST(SCOPE_IDENTITY() AS int);
|
|
|
|
;WITH ScenarioOrder AS
|
|
(
|
|
SELECT sso.SceneID, sso.ScenarioID, ISNULL(sso.ProposedChapterID, s.ChapterID) AS ChapterID,
|
|
ch.BookID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex,
|
|
s.SceneTitle, s.StartDateTime
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
|
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
|
WHERE sso.ScenarioID = @ScenarioID
|
|
)
|
|
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
|
SELECT @RunID, @ScenarioID, targetScene.SceneID, N'SceneDependency', sd.SceneDependencyID, N'Scene Dependency Broken', N'Warning',
|
|
N'Scenario warning: a required scene dependency is out of order.',
|
|
CONCAT(sourceScene.SceneTitle, N' should occur before ', targetScene.SceneTitle, N'.')
|
|
FROM dbo.SceneDependencies sd
|
|
INNER JOIN dbo.SceneDependencyTypes sdt ON sdt.SceneDependencyTypeID = sd.SceneDependencyTypeID
|
|
INNER JOIN ScenarioOrder sourceScene ON sourceScene.SceneID = sd.SourceSceneID
|
|
INNER JOIN ScenarioOrder targetScene ON targetScene.SceneID = sd.TargetSceneID
|
|
WHERE sd.IsArchived = 0 AND sdt.TypeName = N'Must Occur Before' AND sourceScene.ScenarioIndex >= targetScene.ScenarioIndex;
|
|
|
|
;WITH ScenarioOrder AS
|
|
(
|
|
SELECT sso.SceneID, sso.ScenarioID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex,
|
|
s.SceneTitle, s.StartDateTime
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
|
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
|
WHERE sso.ScenarioID = @ScenarioID
|
|
)
|
|
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
|
SELECT @RunID, @ScenarioID, later.SceneID, N'Scene', later.SceneID, N'Date / Order Conflict', N'Info',
|
|
N'Scenario warning: an exact scene date appears earlier than a previous scenario scene.',
|
|
CONCAT(later.SceneTitle, N' is dated before ', earlier.SceneTitle, N'.')
|
|
FROM ScenarioOrder earlier
|
|
INNER JOIN ScenarioOrder later ON later.ScenarioIndex = earlier.ScenarioIndex + 1
|
|
WHERE earlier.StartDateTime IS NOT NULL AND later.StartDateTime IS NOT NULL AND later.StartDateTime < earlier.StartDateTime;
|
|
|
|
;WITH ScenarioOrder AS
|
|
(
|
|
SELECT sso.SceneID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
|
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
|
WHERE sso.ScenarioID = @ScenarioID
|
|
),
|
|
ThreadEventsOrdered AS
|
|
(
|
|
SELECT te.PlotThreadID, te.ThreadEventID, te.SceneID, pt.ThreadTitle, tet.TypeName,
|
|
so.ScenarioIndex,
|
|
MIN(CASE WHEN tet.TypeName LIKE N'%Setup%' THEN so.ScenarioIndex END) OVER (PARTITION BY te.PlotThreadID) AS FirstSetupIndex
|
|
FROM dbo.ThreadEvents te
|
|
INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
|
|
INNER JOIN dbo.ThreadEventTypes tet ON tet.ThreadEventTypeID = te.EventTypeID
|
|
INNER JOIN ScenarioOrder so ON so.SceneID = te.SceneID
|
|
)
|
|
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
|
SELECT @RunID, @ScenarioID, SceneID, N'PlotThread', PlotThreadID, N'Plot Thread Order', N'Warning',
|
|
N'Scenario warning: a reveal or payoff may occur before its setup.',
|
|
CONCAT(ThreadTitle, N' has ', TypeName, N' before the first setup beat.')
|
|
FROM ThreadEventsOrdered
|
|
WHERE (TypeName LIKE N'%Reveal%' OR TypeName LIKE N'%Payoff%')
|
|
AND FirstSetupIndex IS NOT NULL AND ScenarioIndex < FirstSetupIndex;
|
|
|
|
;WITH ScenarioOrder AS
|
|
(
|
|
SELECT sso.SceneID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
|
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
|
WHERE sso.ScenarioID = @ScenarioID
|
|
),
|
|
AssetFirstSeen AS
|
|
(
|
|
SELECT ae.StoryAssetID, MIN(so.ScenarioIndex) AS FirstSeenIndex
|
|
FROM dbo.AssetEvents ae
|
|
INNER JOIN ScenarioOrder so ON so.SceneID = ae.SceneID
|
|
GROUP BY ae.StoryAssetID
|
|
)
|
|
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
|
SELECT @RunID, @ScenarioID, NULL, N'AssetDependency', ad.AssetDependencyID, N'Asset Dependency Order', N'Info',
|
|
N'Scenario warning: an asset appears before a validating dependency source appears.',
|
|
CONCAT(target.AssetName, N' appears before ', source.AssetName, N'.')
|
|
FROM dbo.AssetDependencies ad
|
|
INNER JOIN dbo.AssetDependencyTypes adt ON adt.AssetDependencyTypeID = ad.AssetDependencyTypeID
|
|
INNER JOIN dbo.StoryAssets source ON source.StoryAssetID = ad.SourceAssetID
|
|
INNER JOIN dbo.StoryAssets target ON target.StoryAssetID = ad.TargetAssetID
|
|
INNER JOIN AssetFirstSeen sourceSeen ON sourceSeen.StoryAssetID = ad.SourceAssetID
|
|
INNER JOIN AssetFirstSeen targetSeen ON targetSeen.StoryAssetID = ad.TargetAssetID
|
|
WHERE ad.IsArchived = 0 AND adt.IsValidatingDependency = 1 AND targetSeen.FirstSeenIndex < sourceSeen.FirstSeenIndex;
|
|
|
|
;WITH ScenarioOrder AS
|
|
(
|
|
SELECT sso.SceneID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
|
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
|
WHERE sso.ScenarioID = @ScenarioID
|
|
),
|
|
MetricSteps AS
|
|
(
|
|
SELECT smv.SceneID, smt.MetricName, smv.Value, so.ScenarioIndex,
|
|
LAG(smv.Value) OVER (PARTITION BY smt.MetricName ORDER BY so.ScenarioIndex) AS PreviousValue
|
|
FROM dbo.SceneMetricValues smv
|
|
INNER JOIN dbo.SceneMetricTypes smt ON smt.MetricTypeID = smv.MetricTypeID
|
|
INNER JOIN ScenarioOrder so ON so.SceneID = smv.SceneID
|
|
WHERE smt.MetricName IN (N'Overall Intensity', N'Tension', N'Emotional Weight')
|
|
)
|
|
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
|
SELECT @RunID, @ScenarioID, SceneID, N'Scene', SceneID, N'Pacing Jump', N'Info',
|
|
N'Scenario warning: a pacing/emotional metric changes sharply after this move.',
|
|
CONCAT(MetricName, N' changes from ', PreviousValue, N' to ', Value, N'.')
|
|
FROM MetricSteps
|
|
WHERE PreviousValue IS NOT NULL AND ABS(Value - PreviousValue) >= 6;
|
|
|
|
DECLARE @WarningCount int = (SELECT COUNT(*) FROM dbo.ScenarioWarnings WHERE ScenarioValidationRunID = @RunID);
|
|
UPDATE dbo.ScenarioValidationRuns SET CompletedDate = SYSUTCDATETIME(), WarningCount = @WarningCount WHERE ScenarioValidationRunID = @RunID;
|
|
SELECT @WarningCount;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_Compare
|
|
@ScenarioID int
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
;WITH MainOrder AS
|
|
(
|
|
SELECT nso.SceneID, nso.GlobalSceneIndex,
|
|
CONCAT(nso.BookTitle, N' / Ch ', nso.ChapterNumber, N' / Scene ', nso.SceneNumber) AS MainPosition
|
|
FROM dbo.NarrativeSceneOrder nso
|
|
INNER JOIN dbo.ScenarioSceneOrder sso ON sso.SceneID = nso.SceneID AND sso.ScenarioID = @ScenarioID
|
|
),
|
|
ScenarioOrder AS
|
|
(
|
|
SELECT sso.SceneID,
|
|
ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex,
|
|
CONCAT(b.BookTitle, N' / Ch ', ch.ChapterNumber, N' / Scene ', s.SceneNumber) AS ScenarioPosition,
|
|
s.SceneTitle
|
|
FROM dbo.ScenarioSceneOrder sso
|
|
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
|
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
|
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
|
WHERE sso.ScenarioID = @ScenarioID
|
|
)
|
|
SELECT so.SceneID, so.SceneTitle, mo.MainPosition, so.ScenarioPosition,
|
|
mo.GlobalSceneIndex AS MainIndex, so.ScenarioIndex, CAST(CASE WHEN mo.GlobalSceneIndex <> so.ScenarioIndex OR mo.MainPosition <> so.ScenarioPosition THEN 1 ELSE 0 END AS bit) AS HasMoved
|
|
FROM ScenarioOrder so
|
|
INNER JOIN MainOrder mo ON mo.SceneID = so.SceneID
|
|
WHERE mo.GlobalSceneIndex <> so.ScenarioIndex OR mo.MainPosition <> so.ScenarioPosition
|
|
ORDER BY so.ScenarioIndex;
|
|
|
|
SELECT ScenarioWarningID, ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details, CreatedDate
|
|
FROM dbo.ScenarioWarnings
|
|
WHERE ScenarioID = @ScenarioID
|
|
ORDER BY CASE SeverityName WHEN N'Critical' THEN 4 WHEN N'Warning' THEN 3 WHEN N'Info' THEN 2 ELSE 1 END DESC, CreatedDate DESC;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_ApplyToMain
|
|
@ScenarioID int
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
|
|
UPDATE s
|
|
SET ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID),
|
|
SortOrder = sso.ProposedSortOrder,
|
|
UpdatedDate = SYSUTCDATETIME()
|
|
FROM dbo.Scenes s
|
|
INNER JOIN dbo.ScenarioSceneOrder sso ON sso.SceneID = s.SceneID
|
|
WHERE sso.ScenarioID = @ScenarioID;
|
|
|
|
;WITH affected AS
|
|
(
|
|
SELECT DISTINCT ChapterID FROM dbo.Scenes s INNER JOIN dbo.ScenarioSceneOrder sso ON sso.SceneID = s.SceneID WHERE sso.ScenarioID = @ScenarioID
|
|
),
|
|
ordered AS
|
|
(
|
|
SELECT s.SceneID, ROW_NUMBER() OVER (PARTITION BY s.ChapterID ORDER BY s.SortOrder, s.SceneID) * 10 AS NextSortOrder
|
|
FROM dbo.Scenes s
|
|
INNER JOIN affected a ON a.ChapterID = s.ChapterID
|
|
WHERE s.IsArchived = 0
|
|
)
|
|
UPDATE s
|
|
SET SortOrder = ordered.NextSortOrder,
|
|
UpdatedDate = SYSUTCDATETIME()
|
|
FROM dbo.Scenes s
|
|
INNER JOIN ordered ON ordered.SceneID = s.SceneID;
|
|
|
|
UPDATE dbo.Scenarios
|
|
SET IsAppliedToMain = 1,
|
|
UpdatedDate = SYSUTCDATETIME()
|
|
WHERE ScenarioID = @ScenarioID;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.Scenario_Archive
|
|
@ScenarioID int
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
UPDATE dbo.Scenarios SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME() WHERE ScenarioID = @ScenarioID;
|
|
END;
|
|
GO
|