SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO IF OBJECT_ID(N'dbo.ManuscriptDocuments', N'U') IS NULL BEGIN CREATE TABLE dbo.ManuscriptDocuments ( ManuscriptDocumentID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ManuscriptDocuments PRIMARY KEY, BookID int NOT NULL, ProjectID int NOT NULL, DocumentGuid uniqueidentifier NOT NULL, BindingVersion int NOT NULL CONSTRAINT DF_ManuscriptDocuments_BindingVersion DEFAULT (1), CreatedUtc datetime2 NOT NULL CONSTRAINT DF_ManuscriptDocuments_CreatedUtc DEFAULT SYSUTCDATETIME(), LastSyncUtc datetime2 NULL, LastOpenedUtc datetime2 NULL, IsActive bit NOT NULL CONSTRAINT DF_ManuscriptDocuments_IsActive DEFAULT (1), CreatedByUserID int NULL, CONSTRAINT FK_ManuscriptDocuments_Books FOREIGN KEY (BookID) REFERENCES dbo.Books(BookID), CONSTRAINT FK_ManuscriptDocuments_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID), CONSTRAINT FK_ManuscriptDocuments_AppUser FOREIGN KEY (CreatedByUserID) REFERENCES dbo.AppUser(UserID) ); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_ManuscriptDocuments_ActiveBook' AND object_id = OBJECT_ID(N'dbo.ManuscriptDocuments')) CREATE UNIQUE INDEX UX_ManuscriptDocuments_ActiveBook ON dbo.ManuscriptDocuments(BookID) WHERE IsActive = 1; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_ManuscriptDocuments_ActiveGuid' AND object_id = OBJECT_ID(N'dbo.ManuscriptDocuments')) CREATE UNIQUE INDEX UX_ManuscriptDocuments_ActiveGuid ON dbo.ManuscriptDocuments(DocumentGuid) WHERE IsActive = 1; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_ManuscriptDocuments_Project' AND object_id = OBJECT_ID(N'dbo.ManuscriptDocuments')) CREATE INDEX IX_ManuscriptDocuments_Project ON dbo.ManuscriptDocuments(ProjectID, IsActive); GO IF COL_LENGTH(N'dbo.Chapters', N'IsLinkedToManuscript') IS NULL ALTER TABLE dbo.Chapters ADD IsLinkedToManuscript bit NOT NULL CONSTRAINT DF_Chapters_IsLinkedToManuscript DEFAULT (0); GO IF COL_LENGTH(N'dbo.Chapters', N'ManuscriptDocumentID') IS NULL ALTER TABLE dbo.Chapters ADD ManuscriptDocumentID int NULL; GO IF COL_LENGTH(N'dbo.Chapters', N'ExternalReference') IS NULL ALTER TABLE dbo.Chapters ADD ExternalReference nvarchar(100) NULL; GO IF COL_LENGTH(N'dbo.Chapters', N'LinkedUtc') IS NULL ALTER TABLE dbo.Chapters ADD LinkedUtc datetime2 NULL; GO IF COL_LENGTH(N'dbo.Scenes', N'IsLinkedToManuscript') IS NULL ALTER TABLE dbo.Scenes ADD IsLinkedToManuscript bit NOT NULL CONSTRAINT DF_Scenes_IsLinkedToManuscript DEFAULT (0); GO IF COL_LENGTH(N'dbo.Scenes', N'ManuscriptDocumentID') IS NULL ALTER TABLE dbo.Scenes ADD ManuscriptDocumentID int NULL; GO IF COL_LENGTH(N'dbo.Scenes', N'ExternalReference') IS NULL ALTER TABLE dbo.Scenes ADD ExternalReference nvarchar(100) NULL; GO IF COL_LENGTH(N'dbo.Scenes', N'LinkedUtc') IS NULL ALTER TABLE dbo.Scenes ADD LinkedUtc datetime2 NULL; GO IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_Chapters_ManuscriptDocuments') ALTER TABLE dbo.Chapters ADD CONSTRAINT FK_Chapters_ManuscriptDocuments FOREIGN KEY (ManuscriptDocumentID) REFERENCES dbo.ManuscriptDocuments(ManuscriptDocumentID); GO IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_Scenes_ManuscriptDocuments') ALTER TABLE dbo.Scenes ADD CONSTRAINT FK_Scenes_ManuscriptDocuments FOREIGN KEY (ManuscriptDocumentID) REFERENCES dbo.ManuscriptDocuments(ManuscriptDocumentID); GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Chapters_ManuscriptLink' AND object_id = OBJECT_ID(N'dbo.Chapters')) CREATE INDEX IX_Chapters_ManuscriptLink ON dbo.Chapters(ManuscriptDocumentID, IsLinkedToManuscript, ExternalReference); GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Scenes_ManuscriptLink' AND object_id = OBJECT_ID(N'dbo.Scenes')) CREATE INDEX IX_Scenes_ManuscriptLink ON dbo.Scenes(ManuscriptDocumentID, IsLinkedToManuscript, ExternalReference); GO CREATE OR ALTER PROCEDURE dbo.ManuscriptDocument_GetByBook @BookID int, @UserID int AS BEGIN SET NOCOUNT ON; SELECT md.ManuscriptDocumentID, md.BookID, md.ProjectID, md.DocumentGuid, md.BindingVersion, md.CreatedUtc, md.LastSyncUtc, md.LastOpenedUtc, md.IsActive, md.CreatedByUserID FROM dbo.ManuscriptDocuments md INNER JOIN dbo.Books b ON b.BookID = md.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE md.BookID = @BookID AND md.IsActive = 1 AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1; END; GO CREATE OR ALTER PROCEDURE dbo.ManuscriptDocument_GetByGuid @DocumentGuid uniqueidentifier, @UserID int AS BEGIN SET NOCOUNT ON; SELECT md.ManuscriptDocumentID, md.BookID, md.ProjectID, md.DocumentGuid, md.BindingVersion, md.CreatedUtc, md.LastSyncUtc, md.LastOpenedUtc, md.IsActive, md.CreatedByUserID FROM dbo.ManuscriptDocuments md INNER JOIN dbo.Books b ON b.BookID = md.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE md.DocumentGuid = @DocumentGuid AND md.IsActive = 1 AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1; END; GO CREATE OR ALTER PROCEDURE dbo.ManuscriptDocument_Save @BookID int, @DocumentGuid uniqueidentifier, @UserID int AS BEGIN SET NOCOUNT ON; DECLARE @ProjectID int; SELECT @ProjectID = b.ProjectID 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.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1; IF @ProjectID IS NULL RETURN; 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; DECLARE @ManuscriptDocumentID int; SELECT @ManuscriptDocumentID = ManuscriptDocumentID FROM dbo.ManuscriptDocuments WHERE BookID = @BookID AND IsActive = 1; IF @ManuscriptDocumentID IS NULL BEGIN INSERT dbo.ManuscriptDocuments (BookID, ProjectID, DocumentGuid, CreatedByUserID) VALUES (@BookID, @ProjectID, @DocumentGuid, @UserID); SET @ManuscriptDocumentID = CAST(SCOPE_IDENTITY() AS int); END ELSE BEGIN UPDATE dbo.ManuscriptDocuments SET DocumentGuid = @DocumentGuid, ProjectID = @ProjectID WHERE ManuscriptDocumentID = @ManuscriptDocumentID; END; EXEC dbo.ManuscriptDocument_GetByBook @BookID = @BookID, @UserID = @UserID; END; GO CREATE OR ALTER PROCEDURE dbo.ManuscriptDocument_UpdateLastSync @ManuscriptDocumentID int, @UserID int AS BEGIN SET NOCOUNT ON; UPDATE md SET LastSyncUtc = SYSUTCDATETIME() FROM dbo.ManuscriptDocuments md INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = md.ProjectID WHERE md.ManuscriptDocumentID = @ManuscriptDocumentID AND md.IsActive = 1 AND pua.UserID = @UserID AND pua.IsActive = 1; END; GO CREATE OR ALTER PROCEDURE dbo.ManuscriptDocument_UpdateLastOpened @ManuscriptDocumentID int, @UserID int AS BEGIN SET NOCOUNT ON; UPDATE md SET LastOpenedUtc = SYSUTCDATETIME() FROM dbo.ManuscriptDocuments md INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = md.ProjectID WHERE md.ManuscriptDocumentID = @ManuscriptDocumentID AND md.IsActive = 1 AND pua.UserID = @UserID AND pua.IsActive = 1; END; GO CREATE OR ALTER PROCEDURE dbo.Chapter_ListByBook @BookID int AS BEGIN SET NOCOUNT ON; 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, c.ArchivedDate, c.ArchivedReason, c.IsLinkedToManuscript, c.ManuscriptDocumentID, c.ExternalReference, c.LinkedUtc FROM dbo.Chapters c INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID WHERE c.BookID = @BookID AND c.IsArchived = 0 ORDER BY c.SortOrder, c.ChapterNumber, c.ChapterTitle; END; GO CREATE OR ALTER PROCEDURE dbo.Chapter_Get @ChapterID int AS BEGIN SET NOCOUNT ON; 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, c.ArchivedDate, c.ArchivedReason, c.IsLinkedToManuscript, c.ManuscriptDocumentID, c.ExternalReference, c.LinkedUtc FROM dbo.Chapters c INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID WHERE c.ChapterID = @ChapterID AND c.IsArchived = 0; END; GO CREATE OR ALTER PROCEDURE dbo.Scene_ListByChapter @ChapterID int AS BEGIN SET NOCOUNT ON; SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID, s.PrimaryLocationID, s.FloorPlanID, s.InitialFloorPlanFloorID, s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID, du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes, s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived, s.ArchivedDate, s.ArchivedReason, s.IsLinkedToManuscript, s.ManuscriptDocumentID, s.ExternalReference, s.LinkedUtc FROM dbo.Scenes s INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID WHERE s.ChapterID = @ChapterID AND s.IsArchived = 0 ORDER BY s.SortOrder, s.SceneNumber, s.SceneTitle; END; GO CREATE OR ALTER PROCEDURE dbo.Scene_Get @SceneID int AS BEGIN SET NOCOUNT ON; EXEC dbo.SceneMetric_EnsureDefaults @SceneID; SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID, s.PrimaryLocationID, s.FloorPlanID, s.InitialFloorPlanFloorID, location.LocationName AS PrimaryLocationName, location.LocationPath AS PrimaryLocationPath, s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID, du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes, s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived, s.ArchivedDate, s.ArchivedReason, s.IsLinkedToManuscript, s.ManuscriptDocumentID, s.ExternalReference, s.LinkedUtc FROM dbo.Scenes s INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID LEFT JOIN dbo.LocationPaths location ON location.LocationID = s.PrimaryLocationID WHERE s.SceneID = @SceneID AND s.IsArchived = 0; SELECT ScenePurposeTypeID FROM dbo.ScenePurposes WHERE SceneID = @SceneID; EXEC dbo.SceneMetric_ListByScene @SceneID; END; GO CREATE OR ALTER PROCEDURE dbo.Archive_Entity @EntityType nvarchar(80), @EntityID int, @ArchivedReason nvarchar(500) = NULL AS BEGIN SET NOCOUNT ON; IF @EntityType = N'Project' UPDATE dbo.Projects SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE ProjectID = @EntityID; ELSE IF @EntityType = N'Book' UPDATE dbo.Books SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE BookID = @EntityID; ELSE IF @EntityType = N'Chapter' BEGIN IF EXISTS (SELECT 1 FROM dbo.Chapters WHERE ChapterID = @EntityID AND IsLinkedToManuscript = 1) THROW 51000, 'This chapter is linked to a manuscript and cannot be deleted from PlotDirector. Delete the chapter from Microsoft Word to remove it from the manuscript.', 1; UPDATE dbo.Chapters SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE ChapterID = @EntityID; END ELSE IF @EntityType = N'Scene' BEGIN DECLARE @ChapterID int; SELECT @ChapterID = ChapterID FROM dbo.Scenes WHERE SceneID = @EntityID AND IsArchived = 0; IF EXISTS (SELECT 1 FROM dbo.Scenes WHERE SceneID = @EntityID AND IsLinkedToManuscript = 1) THROW 51000, 'This scene is linked to a manuscript and cannot be deleted from PlotDirector. Delete the scene from Microsoft Word to remove it from the manuscript.', 1; IF @ChapterID IS NULL RETURN; IF (SELECT COUNT(*) FROM dbo.Scenes WHERE ChapterID = @ChapterID AND IsArchived = 0) <= 1 THROW 51000, 'A chapter must contain at least one scene.', 1; UPDATE dbo.Scenes SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @EntityID; END ELSE IF @EntityType = N'PlotLine' UPDATE dbo.PlotLines SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE PlotLineID = @EntityID; ELSE IF @EntityType = N'PlotThread' UPDATE dbo.PlotThreads SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE PlotThreadID = @EntityID; ELSE IF @EntityType = N'StoryAsset' UPDATE dbo.StoryAssets SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE StoryAssetID = @EntityID; ELSE IF @EntityType = N'Character' UPDATE dbo.Characters SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE CharacterID = @EntityID; ELSE IF @EntityType = N'Location' UPDATE dbo.Locations SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE LocationID = @EntityID; ELSE IF @EntityType = N'Scenario' UPDATE dbo.Scenarios SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE ScenarioID = @EntityID; ELSE IF @EntityType = N'Relationship' UPDATE dbo.CharacterRelationships SET IsArchived = 1, ArchivedDate = SYSUTCDATETIME(), ArchivedReason = @ArchivedReason, UpdatedDate = SYSUTCDATETIME() WHERE CharacterRelationshipID = @EntityID; END; GO CREATE OR ALTER PROCEDURE dbo.Chapter_Archive @ChapterID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Chapter', @ChapterID, NULL; END; GO CREATE OR ALTER PROCEDURE dbo.Scene_Archive @SceneID int AS BEGIN SET NOCOUNT ON; EXEC dbo.Archive_Entity N'Scene', @SceneID, NULL; END; GO