SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO IF OBJECT_ID(N'dbo.SceneLocationSuggestions', N'U') IS NULL BEGIN CREATE TABLE dbo.SceneLocationSuggestions ( SceneLocationSuggestionID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_SceneLocationSuggestions PRIMARY KEY, SceneID int NOT NULL, LocationID int NOT NULL, SuggestionSource nvarchar(50) NOT NULL CONSTRAINT DF_SceneLocationSuggestions_Source DEFAULT (N'Word Companion'), DetectedUtc datetime2 NOT NULL CONSTRAINT DF_SceneLocationSuggestions_DetectedUtc DEFAULT SYSUTCDATETIME(), Status nvarchar(20) NOT NULL CONSTRAINT DF_SceneLocationSuggestions_Status DEFAULT (N'Pending'), Confidence nvarchar(20) NOT NULL CONSTRAINT DF_SceneLocationSuggestions_Confidence DEFAULT (N'High'), Reason nvarchar(200) NULL, CreatedByUserID int NOT NULL, ReviewedByUserID int NULL, ReviewedUtc datetime2 NULL, CONSTRAINT FK_SceneLocationSuggestions_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID), CONSTRAINT FK_SceneLocationSuggestions_Locations FOREIGN KEY (LocationID) REFERENCES dbo.Locations(LocationID), CONSTRAINT FK_SceneLocationSuggestions_CreatedByUser FOREIGN KEY (CreatedByUserID) REFERENCES dbo.AppUser(UserID), CONSTRAINT FK_SceneLocationSuggestions_ReviewedByUser FOREIGN KEY (ReviewedByUserID) REFERENCES dbo.AppUser(UserID), CONSTRAINT CK_SceneLocationSuggestions_Status CHECK (Status IN (N'Pending', N'Accepted', N'Rejected', N'Dismissed')), CONSTRAINT CK_SceneLocationSuggestions_Confidence CHECK (Confidence IN (N'High', N'Medium', N'Low')) ); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_SceneLocationSuggestions_Pending' AND object_id = OBJECT_ID(N'dbo.SceneLocationSuggestions')) CREATE UNIQUE INDEX UX_SceneLocationSuggestions_Pending ON dbo.SceneLocationSuggestions(SceneID, LocationID) WHERE Status = N'Pending'; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneLocationSuggestions_SceneStatus' AND object_id = OBJECT_ID(N'dbo.SceneLocationSuggestions')) CREATE INDEX IX_SceneLocationSuggestions_SceneStatus ON dbo.SceneLocationSuggestions(SceneID, Status, LocationID); GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Runtime_LocationSuggestions_Create @UserID int, @DocumentGuid uniqueidentifier, @SceneID int, @LocationIds nvarchar(max) AS BEGIN SET NOCOUNT ON; IF @DocumentGuid IS NULL OR @DocumentGuid = '00000000-0000-0000-0000-000000000000' OR @SceneID <= 0 RETURN; DECLARE @ProjectID int; DECLARE @ManuscriptDocumentID int; SELECT @ProjectID = b.ProjectID, @ManuscriptDocumentID = md.ManuscriptDocumentID FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ManuscriptDocuments md ON md.BookID = b.BookID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = b.ProjectID WHERE s.SceneID = @SceneID AND s.IsArchived = 0 AND c.IsArchived = 0 AND b.IsArchived = 0 AND p.IsArchived = 0 AND md.DocumentGuid = @DocumentGuid AND md.IsActive = 1 AND s.IsLinkedToManuscript = 1 AND s.ManuscriptDocumentID = md.ManuscriptDocumentID AND pua.UserID = @UserID AND pua.IsActive = 1; IF @ProjectID IS NULL RETURN; DECLARE @Requested table (LocationID int NOT NULL PRIMARY KEY); INSERT @Requested (LocationID) SELECT DISTINCT TRY_CONVERT(int, LTRIM(RTRIM(value))) FROM STRING_SPLIT(COALESCE(@LocationIds, N''), N',') WHERE TRY_CONVERT(int, LTRIM(RTRIM(value))) IS NOT NULL AND TRY_CONVERT(int, LTRIM(RTRIM(value))) > 0; IF NOT EXISTS (SELECT 1 FROM @Requested) BEGIN SELECT @SceneID AS SceneId, 0 AS CreatedCount, 0 AS SkippedCount, N'No location suggestions detected.' AS Message; RETURN; END; IF EXISTS ( SELECT 1 FROM @Requested requested WHERE NOT EXISTS ( SELECT 1 FROM dbo.Locations location WHERE location.LocationID = requested.LocationID AND location.ProjectID = @ProjectID AND location.IsArchived = 0 AND location.ExcludeFromCompanionDetection = 0 ) ) RETURN; DECLARE @Inserted table (LocationID int NOT NULL PRIMARY KEY); INSERT dbo.SceneLocationSuggestions (SceneID, LocationID, SuggestionSource, Status, Confidence, Reason, CreatedByUserID) OUTPUT inserted.LocationID INTO @Inserted SELECT @SceneID, requested.LocationID, N'Word Companion', N'Pending', N'High', N'Detected in manuscript text', @UserID FROM @Requested requested WHERE NOT EXISTS (SELECT 1 FROM dbo.Scenes s WHERE s.SceneID = @SceneID AND s.PrimaryLocationID = requested.LocationID) AND NOT EXISTS (SELECT 1 FROM dbo.WordCompanionSceneLocations wcsl WHERE wcsl.SceneID = @SceneID AND wcsl.LocationID = requested.LocationID) AND NOT EXISTS (SELECT 1 FROM dbo.SceneLocationSuggestions suggestion WHERE suggestion.SceneID = @SceneID AND suggestion.LocationID = requested.LocationID); SELECT @SceneID AS SceneId, (SELECT COUNT(*) FROM @Inserted) AS CreatedCount, (SELECT COUNT(*) FROM @Requested) - (SELECT COUNT(*) FROM @Inserted) AS SkippedCount, CASE WHEN (SELECT COUNT(*) FROM @Inserted) = 1 THEN N'1 location suggestion detected.' WHEN (SELECT COUNT(*) FROM @Inserted) > 1 THEN CONCAT((SELECT COUNT(*) FROM @Inserted), N' location suggestions detected.') ELSE N'No new location suggestions.' END AS Message; END; GO