PlotDirector/PlotLine/Sql/113_Phase20F_OnboardingManuscriptBuild.sql

297 lines
18 KiB
Transact-SQL

SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
IF OBJECT_ID(N'dbo.OnboardingManuscriptBuilds', N'U') IS NULL
BEGIN
CREATE TABLE dbo.OnboardingManuscriptBuilds
(
OnboardingManuscriptBuildID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_OnboardingManuscriptBuilds PRIMARY KEY,
PreviewID uniqueidentifier NOT NULL,
UserID int NOT NULL,
ProjectID int NOT NULL,
BookID int NOT NULL,
ManuscriptDocumentID int NULL,
Status nvarchar(40) NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_Status DEFAULT N'Built',
MarkerStatus nvarchar(40) NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_MarkerStatus DEFAULT N'Pending',
ChaptersCreated int NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_ChaptersCreated DEFAULT 0,
ScenesCreated int NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_ScenesCreated DEFAULT 0,
CharactersCreated int NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_CharactersCreated DEFAULT 0,
CharactersReused int NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_CharactersReused DEFAULT 0,
SceneAppearancesCreated int NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_SceneAppearancesCreated DEFAULT 0,
CreatedUtc datetime2 NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_CreatedUtc DEFAULT SYSUTCDATETIME(),
UpdatedUtc datetime2 NOT NULL CONSTRAINT DF_OnboardingManuscriptBuilds_UpdatedUtc DEFAULT SYSUTCDATETIME(),
CONSTRAINT UQ_OnboardingManuscriptBuilds_PreviewID UNIQUE (PreviewID),
CONSTRAINT FK_OnboardingManuscriptBuilds_AppUser FOREIGN KEY (UserID) REFERENCES dbo.AppUser(UserID),
CONSTRAINT FK_OnboardingManuscriptBuilds_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
CONSTRAINT FK_OnboardingManuscriptBuilds_Books FOREIGN KEY (BookID) REFERENCES dbo.Books(BookID),
CONSTRAINT FK_OnboardingManuscriptBuilds_ManuscriptDocuments FOREIGN KEY (ManuscriptDocumentID) REFERENCES dbo.ManuscriptDocuments(ManuscriptDocumentID)
);
END;
GO
IF OBJECT_ID(N'dbo.OnboardingManuscriptBuildChapterMap', N'U') IS NULL
BEGIN
CREATE TABLE dbo.OnboardingManuscriptBuildChapterMap
(
OnboardingManuscriptBuildID int NOT NULL,
TemporaryChapterKey nvarchar(80) NOT NULL,
ChapterID int NOT NULL,
CONSTRAINT PK_OnboardingManuscriptBuildChapterMap PRIMARY KEY (OnboardingManuscriptBuildID, TemporaryChapterKey),
CONSTRAINT FK_OnboardingManuscriptBuildChapterMap_Build FOREIGN KEY (OnboardingManuscriptBuildID) REFERENCES dbo.OnboardingManuscriptBuilds(OnboardingManuscriptBuildID),
CONSTRAINT FK_OnboardingManuscriptBuildChapterMap_Chapters FOREIGN KEY (ChapterID) REFERENCES dbo.Chapters(ChapterID)
);
END;
GO
IF OBJECT_ID(N'dbo.OnboardingManuscriptBuildSceneMap', N'U') IS NULL
BEGIN
CREATE TABLE dbo.OnboardingManuscriptBuildSceneMap
(
OnboardingManuscriptBuildID int NOT NULL,
TemporarySceneKey nvarchar(80) NOT NULL,
SceneID int NOT NULL,
CONSTRAINT PK_OnboardingManuscriptBuildSceneMap PRIMARY KEY (OnboardingManuscriptBuildID, TemporarySceneKey),
CONSTRAINT FK_OnboardingManuscriptBuildSceneMap_Build FOREIGN KEY (OnboardingManuscriptBuildID) REFERENCES dbo.OnboardingManuscriptBuilds(OnboardingManuscriptBuildID),
CONSTRAINT FK_OnboardingManuscriptBuildSceneMap_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID)
);
END;
GO
IF OBJECT_ID(N'dbo.OnboardingManuscriptBuildCharacterMap', N'U') IS NULL
BEGIN
CREATE TABLE dbo.OnboardingManuscriptBuildCharacterMap
(
OnboardingManuscriptBuildID int NOT NULL,
TemporaryCharacterKey nvarchar(80) NOT NULL,
CharacterID int NOT NULL,
Created bit NOT NULL,
CONSTRAINT PK_OnboardingManuscriptBuildCharacterMap PRIMARY KEY (OnboardingManuscriptBuildID, TemporaryCharacterKey),
CONSTRAINT FK_OnboardingManuscriptBuildCharacterMap_Build FOREIGN KEY (OnboardingManuscriptBuildID) REFERENCES dbo.OnboardingManuscriptBuilds(OnboardingManuscriptBuildID),
CONSTRAINT FK_OnboardingManuscriptBuildCharacterMap_Characters FOREIGN KEY (CharacterID) REFERENCES dbo.Characters(CharacterID)
);
END;
GO
CREATE OR ALTER PROCEDURE dbo.Onboarding_ManuscriptBuild_Create
@UserID int,
@PreviewID uniqueidentifier,
@ProjectID int,
@BookID int,
@DocumentGuid uniqueidentifier,
@BindingVersion int = 1,
@ChaptersJson nvarchar(max),
@ScenesJson nvarchar(max),
@CharactersJson nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF @DocumentGuid IS NULL OR @DocumentGuid = '00000000-0000-0000-0000-000000000000'
SET @DocumentGuid = NEWID();
DECLARE @ExistingBuildID int;
SELECT @ExistingBuildID = OnboardingManuscriptBuildID
FROM dbo.OnboardingManuscriptBuilds
WHERE PreviewID = @PreviewID AND UserID = @UserID;
IF @ExistingBuildID IS NOT NULL
BEGIN
SELECT OnboardingManuscriptBuildID AS BuildID, PreviewID, ProjectID, BookID, ManuscriptDocumentID, Status, MarkerStatus,
ChaptersCreated, ScenesCreated, CharactersCreated, CharactersReused, SceneAppearancesCreated,
CAST(1 AS bit) AS AlreadyBuilt,
N'This manuscript has already been built into PlotDirector.' AS Message
FROM dbo.OnboardingManuscriptBuilds
WHERE OnboardingManuscriptBuildID = @ExistingBuildID;
SELECT TemporaryChapterKey, ChapterID FROM dbo.OnboardingManuscriptBuildChapterMap WHERE OnboardingManuscriptBuildID = @ExistingBuildID ORDER BY TemporaryChapterKey;
SELECT TemporarySceneKey, SceneID FROM dbo.OnboardingManuscriptBuildSceneMap WHERE OnboardingManuscriptBuildID = @ExistingBuildID ORDER BY TemporarySceneKey;
SELECT TemporaryCharacterKey, CharacterID, Created FROM dbo.OnboardingManuscriptBuildCharacterMap WHERE OnboardingManuscriptBuildID = @ExistingBuildID ORDER BY TemporaryCharacterKey;
RETURN;
END;
IF NOT EXISTS
(
SELECT 1
FROM dbo.Books b
INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID
WHERE b.BookID = @BookID
AND b.ProjectID = @ProjectID
AND b.IsArchived = 0
AND p.IsArchived = 0
AND pua.UserID = @UserID
AND pua.IsActive = 1
)
RETURN;
DECLARE @Chapters table (TemporaryChapterKey nvarchar(80) NOT NULL PRIMARY KEY, Title nvarchar(200) NOT NULL, SortOrder int NOT NULL, WordCount int NOT NULL);
DECLARE @Scenes table (TemporarySceneKey nvarchar(80) NOT NULL PRIMARY KEY, TemporaryChapterKey nvarchar(80) NOT NULL, Title nvarchar(200) NOT NULL, SortOrder int NOT NULL, WordCount int NOT NULL);
DECLARE @Characters table (TemporaryCharacterKey nvarchar(80) NOT NULL PRIMARY KEY, Name nvarchar(200) NOT NULL, ExistingCharacterID int NULL);
INSERT @Chapters (TemporaryChapterKey, Title, SortOrder, WordCount)
SELECT LEFT(JSON_VALUE(value, '$.TemporaryChapterKey'), 80),
LEFT(LTRIM(RTRIM(JSON_VALUE(value, '$.Title'))), 200),
TRY_CONVERT(int, JSON_VALUE(value, '$.SortOrder')),
COALESCE(TRY_CONVERT(int, JSON_VALUE(value, '$.WordCount')), 0)
FROM OPENJSON(@ChaptersJson)
WHERE NULLIF(JSON_VALUE(value, '$.TemporaryChapterKey'), N'') IS NOT NULL
AND NULLIF(LTRIM(RTRIM(JSON_VALUE(value, '$.Title'))), N'') IS NOT NULL;
INSERT @Scenes (TemporarySceneKey, TemporaryChapterKey, Title, SortOrder, WordCount)
SELECT LEFT(JSON_VALUE(value, '$.TemporarySceneKey'), 80),
LEFT(JSON_VALUE(value, '$.TemporaryChapterKey'), 80),
LEFT(LTRIM(RTRIM(JSON_VALUE(value, '$.Title'))), 200),
TRY_CONVERT(int, JSON_VALUE(value, '$.SortOrder')),
COALESCE(TRY_CONVERT(int, JSON_VALUE(value, '$.WordCount')), 0)
FROM OPENJSON(@ScenesJson)
WHERE NULLIF(JSON_VALUE(value, '$.TemporarySceneKey'), N'') IS NOT NULL
AND NULLIF(JSON_VALUE(value, '$.TemporaryChapterKey'), N'') IS NOT NULL
AND NULLIF(LTRIM(RTRIM(JSON_VALUE(value, '$.Title'))), N'') IS NOT NULL;
INSERT @Characters (TemporaryCharacterKey, Name, ExistingCharacterID)
SELECT LEFT(JSON_VALUE(value, '$.TemporaryCharacterKey'), 80),
LEFT(LTRIM(RTRIM(JSON_VALUE(value, '$.Name'))), 200),
TRY_CONVERT(int, JSON_VALUE(value, '$.ExistingCharacterID'))
FROM OPENJSON(@CharactersJson)
WHERE NULLIF(JSON_VALUE(value, '$.TemporaryCharacterKey'), N'') IS NOT NULL
AND NULLIF(LTRIM(RTRIM(JSON_VALUE(value, '$.Name'))), N'') IS NOT NULL;
IF NOT EXISTS (SELECT 1 FROM @Chapters) OR EXISTS (SELECT 1 FROM @Scenes s WHERE NOT EXISTS (SELECT 1 FROM @Chapters c WHERE c.TemporaryChapterKey = s.TemporaryChapterKey))
RETURN;
IF EXISTS (SELECT 1 FROM @Chapters WHERE SortOrder IS NULL OR SortOrder <= 0 OR WordCount < 0)
RETURN;
IF EXISTS (SELECT 1 FROM @Scenes WHERE SortOrder IS NULL OR SortOrder <= 0 OR WordCount < 0)
RETURN;
DECLARE @PlannedRevisionStatusID int = (SELECT TOP (1) RevisionStatusID FROM dbo.RevisionStatuses WHERE StatusName = N'Planned' ORDER BY SortOrder);
DECLARE @DefaultTimeModeID int = (SELECT TOP (1) TimeModeID FROM dbo.TimeModes ORDER BY CASE WHEN TimeModeName = N'Unknown' THEN 0 ELSE 1 END, SortOrder, TimeModeID);
DECLARE @DefaultTimeConfidenceID int = (SELECT TOP (1) TimeConfidenceID FROM dbo.TimeConfidences ORDER BY CASE WHEN TimeConfidenceName = N'Unknown' THEN 0 ELSE 1 END, SortOrder, TimeConfidenceID);
DECLARE @ChapterMap table (TemporaryChapterKey nvarchar(80) NOT NULL PRIMARY KEY, ChapterID int NOT NULL);
DECLARE @SceneMap table (TemporarySceneKey nvarchar(80) NOT NULL PRIMARY KEY, SceneID int NOT NULL);
DECLARE @CharacterMap table (TemporaryCharacterKey nvarchar(80) NOT NULL PRIMARY KEY, CharacterID int NOT NULL, Created bit NOT NULL);
DECLARE @BuildID int;
DECLARE @ManuscriptDocumentID int;
DECLARE @LinkedUtc datetime2 = SYSUTCDATETIME();
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.ManuscriptDocuments WHERE DocumentGuid = @DocumentGuid AND IsActive = 1 AND BookID <> @BookID)
THROW 51000, 'This manuscript document is already linked to another book.', 1;
SELECT @ManuscriptDocumentID = ManuscriptDocumentID FROM dbo.ManuscriptDocuments WHERE BookID = @BookID AND IsActive = 1;
IF @ManuscriptDocumentID IS NULL
BEGIN
INSERT dbo.ManuscriptDocuments (BookID, ProjectID, DocumentGuid, BindingVersion, CreatedByUserID, LastOpenedUtc, LastSyncUtc)
VALUES (@BookID, @ProjectID, @DocumentGuid, @BindingVersion, @UserID, @LinkedUtc, @LinkedUtc);
SET @ManuscriptDocumentID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.ManuscriptDocuments
SET DocumentGuid = @DocumentGuid, ProjectID = @ProjectID, BindingVersion = @BindingVersion, LastOpenedUtc = @LinkedUtc, LastSyncUtc = @LinkedUtc
WHERE ManuscriptDocumentID = @ManuscriptDocumentID;
END;
INSERT dbo.OnboardingManuscriptBuilds (PreviewID, UserID, ProjectID, BookID, ManuscriptDocumentID)
VALUES (@PreviewID, @UserID, @ProjectID, @BookID, @ManuscriptDocumentID);
SET @BuildID = CAST(SCOPE_IDENTITY() AS int);
DECLARE @TempChapterKey nvarchar(80), @Title nvarchar(200), @SortOrder int, @WordCount int, @ChapterID int, @ChapterNumber decimal(9,2);
DECLARE chapter_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT TemporaryChapterKey, Title, SortOrder, WordCount FROM @Chapters ORDER BY SortOrder, TemporaryChapterKey;
OPEN chapter_cursor;
FETCH NEXT FROM chapter_cursor INTO @TempChapterKey, @Title, @SortOrder, @WordCount;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @ChapterNumber = (SELECT COUNT(*) + 1 FROM @ChapterMap);
INSERT dbo.Chapters (BookID, ChapterNumber, ChapterTitle, Summary, SortOrder, RevisionStatusID, IsLinkedToManuscript, ManuscriptDocumentID, ExternalReference, LinkedUtc)
VALUES (@BookID, @ChapterNumber, @Title, NULL, @SortOrder, @PlannedRevisionStatusID, 1, @ManuscriptDocumentID, @TempChapterKey, @LinkedUtc);
SET @ChapterID = CAST(SCOPE_IDENTITY() AS int);
INSERT @ChapterMap VALUES (@TempChapterKey, @ChapterID);
INSERT dbo.OnboardingManuscriptBuildChapterMap VALUES (@BuildID, @TempChapterKey, @ChapterID);
FETCH NEXT FROM chapter_cursor INTO @TempChapterKey, @Title, @SortOrder, @WordCount;
END;
CLOSE chapter_cursor; DEALLOCATE chapter_cursor;
DECLARE @TempSceneKey nvarchar(80), @TempSceneChapterKey nvarchar(80), @SceneID int, @SceneNumber decimal(9,2);
DECLARE scene_cursor CURSOR LOCAL FAST_FORWARD FOR
SELECT TemporarySceneKey, TemporaryChapterKey, Title, SortOrder, WordCount FROM @Scenes ORDER BY TemporaryChapterKey, SortOrder, TemporarySceneKey;
OPEN scene_cursor;
FETCH NEXT FROM scene_cursor INTO @TempSceneKey, @TempSceneChapterKey, @Title, @SortOrder, @WordCount;
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @ChapterID = ChapterID FROM @ChapterMap WHERE TemporaryChapterKey = @TempSceneChapterKey;
SET @SceneNumber = (SELECT COUNT(*) + 1 FROM @SceneMap sm INNER JOIN @Scenes s ON s.TemporarySceneKey = sm.TemporarySceneKey WHERE s.TemporaryChapterKey = @TempSceneChapterKey);
IF @SceneNumber = 1
BEGIN
SELECT TOP (1) @SceneID = SceneID FROM dbo.Scenes WHERE ChapterID = @ChapterID AND IsArchived = 0 ORDER BY SortOrder, SceneID;
UPDATE dbo.Scenes
SET SceneNumber = @SceneNumber, SceneTitle = @Title, SortOrder = @SortOrder, IsLinkedToManuscript = 1,
ManuscriptDocumentID = @ManuscriptDocumentID, ExternalReference = @TempSceneKey, LinkedUtc = @LinkedUtc, UpdatedDate = SYSUTCDATETIME()
WHERE SceneID = @SceneID;
END
ELSE
BEGIN
INSERT dbo.Scenes (ChapterID, SceneNumber, SceneTitle, Summary, SortOrder, TimeModeID, TimeConfidenceID, RevisionStatusID, IsLinkedToManuscript, ManuscriptDocumentID, ExternalReference, LinkedUtc)
VALUES (@ChapterID, @SceneNumber, @Title, NULL, @SortOrder, @DefaultTimeModeID, @DefaultTimeConfidenceID, @PlannedRevisionStatusID, 1, @ManuscriptDocumentID, @TempSceneKey, @LinkedUtc);
SET @SceneID = CAST(SCOPE_IDENTITY() AS int);
END;
IF EXISTS (SELECT 1 FROM dbo.SceneWorkflow WHERE SceneID = @SceneID)
UPDATE dbo.SceneWorkflow SET ActualWordCount = @WordCount, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @SceneID;
ELSE
INSERT dbo.SceneWorkflow (SceneID, ActualWordCount) VALUES (@SceneID, @WordCount);
INSERT @SceneMap VALUES (@TempSceneKey, @SceneID);
INSERT dbo.OnboardingManuscriptBuildSceneMap VALUES (@BuildID, @TempSceneKey, @SceneID);
FETCH NEXT FROM scene_cursor INTO @TempSceneKey, @TempSceneChapterKey, @Title, @SortOrder, @WordCount;
END;
CLOSE scene_cursor; DEALLOCATE scene_cursor;
DECLARE @TempCharacterKey nvarchar(80), @ExistingCharacterID int, @CharacterID int, @Created bit;
DECLARE character_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT TemporaryCharacterKey, Name, ExistingCharacterID FROM @Characters ORDER BY Name, TemporaryCharacterKey;
OPEN character_cursor;
FETCH NEXT FROM character_cursor INTO @TempCharacterKey, @Title, @ExistingCharacterID;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Created = 0;
SELECT @CharacterID = CharacterID FROM dbo.Characters WHERE CharacterID = @ExistingCharacterID AND ProjectID = @ProjectID AND IsArchived = 0;
IF @CharacterID IS NULL
SELECT TOP (1) @CharacterID = CharacterID FROM dbo.Characters WHERE ProjectID = @ProjectID AND IsArchived = 0 AND UPPER(LTRIM(RTRIM(CharacterName))) = UPPER(@Title);
IF @CharacterID IS NULL
BEGIN
INSERT dbo.Characters (ProjectID, CharacterName, ShortName, CharacterImportance, ShowInQuickAddBar, DefaultDescription)
VALUES (@ProjectID, @Title, NULL, 8, 1, NULL);
SET @CharacterID = CAST(SCOPE_IDENTITY() AS int);
SET @Created = 1;
END;
INSERT @CharacterMap VALUES (@TempCharacterKey, @CharacterID, @Created);
INSERT dbo.OnboardingManuscriptBuildCharacterMap VALUES (@BuildID, @TempCharacterKey, @CharacterID, @Created);
SET @CharacterID = NULL;
FETCH NEXT FROM character_cursor INTO @TempCharacterKey, @Title, @ExistingCharacterID;
END;
CLOSE character_cursor; DEALLOCATE character_cursor;
UPDATE dbo.OnboardingManuscriptBuilds
SET ChaptersCreated = (SELECT COUNT(*) FROM @ChapterMap),
ScenesCreated = (SELECT COUNT(*) FROM @SceneMap),
CharactersCreated = (SELECT COUNT(*) FROM @CharacterMap WHERE Created = 1),
CharactersReused = (SELECT COUNT(*) FROM @CharacterMap WHERE Created = 0),
UpdatedUtc = SYSUTCDATETIME()
WHERE OnboardingManuscriptBuildID = @BuildID;
COMMIT TRANSACTION;
SELECT OnboardingManuscriptBuildID AS BuildID, PreviewID, ProjectID, BookID, ManuscriptDocumentID, Status, MarkerStatus,
ChaptersCreated, ScenesCreated, CharactersCreated, CharactersReused, SceneAppearancesCreated,
CAST(0 AS bit) AS AlreadyBuilt,
N'Your project structure has been created.' AS Message
FROM dbo.OnboardingManuscriptBuilds WHERE OnboardingManuscriptBuildID = @BuildID;
SELECT TemporaryChapterKey, ChapterID FROM dbo.OnboardingManuscriptBuildChapterMap WHERE OnboardingManuscriptBuildID = @BuildID ORDER BY TemporaryChapterKey;
SELECT TemporarySceneKey, SceneID FROM dbo.OnboardingManuscriptBuildSceneMap WHERE OnboardingManuscriptBuildID = @BuildID ORDER BY TemporarySceneKey;
SELECT TemporaryCharacterKey, CharacterID, Created FROM dbo.OnboardingManuscriptBuildCharacterMap WHERE OnboardingManuscriptBuildID = @BuildID ORDER BY TemporaryCharacterKey;
END;
GO