Converted all inline SQL to stored procedures.
This commit is contained in:
parent
d255407193
commit
a3ce37c66c
@ -24,16 +24,9 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var count = await connection.ExecuteScalarAsync<int>(
|
var count = await connection.ExecuteScalarAsync<int>(
|
||||||
"""
|
"dbo.Project_ExistsByNameForUser",
|
||||||
SELECT COUNT(1)
|
new { ProjectName = projectTitle, UserID = userId },
|
||||||
FROM dbo.Projects p
|
commandType: CommandType.StoredProcedure);
|
||||||
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID
|
|
||||||
WHERE p.IsArchived = 0
|
|
||||||
AND p.ProjectName = @ProjectName
|
|
||||||
AND pua.UserID = @UserID
|
|
||||||
AND pua.IsActive = 1;
|
|
||||||
""",
|
|
||||||
new { ProjectName = projectTitle, UserID = userId });
|
|
||||||
|
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
@ -329,9 +322,10 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
|||||||
if (povCharacterId.HasValue)
|
if (povCharacterId.HasValue)
|
||||||
{
|
{
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"UPDATE dbo.Scenes SET POVCharacterID = @POVCharacterID, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @SceneID;",
|
"dbo.Scene_UpdatePovCharacter",
|
||||||
new { SceneID = sceneId, POVCharacterID = povCharacterId.Value },
|
new { SceneID = sceneId, POVCharacterID = povCharacterId.Value },
|
||||||
transaction);
|
transaction,
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var appearance in BuildSceneAppearances(scene, povCharacterId, characterMap, package.Aliases.Characters))
|
foreach (var appearance in BuildSceneAppearances(scene, povCharacterId, characterMap, package.Aliases.Characters))
|
||||||
@ -666,68 +660,35 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
|||||||
|
|
||||||
private static async Task<ImportLookupIds> GetLookupIdsAsync(IDbConnection connection, IDbTransaction transaction)
|
private static async Task<ImportLookupIds> GetLookupIdsAsync(IDbConnection connection, IDbTransaction transaction)
|
||||||
{
|
{
|
||||||
var revisionStatusId = await connection.QuerySingleOrDefaultAsync<int?>(
|
using var result = await connection.QueryMultipleAsync(
|
||||||
"SELECT TOP (1) RevisionStatusID FROM dbo.RevisionStatuses WHERE StatusName = N'Planned' ORDER BY SortOrder;",
|
"dbo.Import_LookupIds",
|
||||||
transaction: transaction);
|
transaction: transaction,
|
||||||
var timeModeId = await connection.QuerySingleOrDefaultAsync<int?>(
|
commandType: CommandType.StoredProcedure);
|
||||||
"SELECT TOP (1) TimeModeID FROM dbo.TimeModes WHERE TimeModeName = N'Relative' ORDER BY SortOrder;",
|
var requiredLookups = await result.ReadSingleAsync<ImportRequiredLookupRow>();
|
||||||
transaction: transaction);
|
var locationTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
var timeConfidenceId = await connection.QuerySingleOrDefaultAsync<int?>(
|
var roleTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
"SELECT TOP (1) TimeConfidenceID FROM dbo.TimeConfidences WHERE TimeConfidenceName = N'Unknown' ORDER BY SortOrder;",
|
var presenceTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
transaction: transaction);
|
var plotLineTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var plotImportance = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var threadTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var threadStatuses = (await result.ReadAsync<ImportStatusLookupRow>()).ToDictionary(x => x.StatusName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var threadEventTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var sceneDependencyTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var assetKinds = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var assetStates = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var assetEventTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var assetCustodyEventTypes = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var custodyRoles = (await result.ReadAsync<ImportLookupRow>()).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var locationTypes = (await connection.QueryAsync<ImportLookupRow>(
|
if (!requiredLookups.RevisionStatusID.HasValue || !requiredLookups.TimeModeID.HasValue || !requiredLookups.TimeConfidenceID.HasValue)
|
||||||
"SELECT LocationTypeID AS LookupID, TypeName FROM dbo.LocationTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var roleTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT CharacterRoleInSceneTypeID AS LookupID, TypeName FROM dbo.CharacterRoleInSceneTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var presenceTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT PresenceTypeID AS LookupID, TypeName FROM dbo.PresenceTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var plotLineTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT PlotLineTypeID AS LookupID, TypeName FROM dbo.PlotLineTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var plotImportance = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT PlotImportanceID AS LookupID, ImportanceName AS TypeName FROM dbo.PlotImportance WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var threadTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT ThreadTypeID AS LookupID, TypeName FROM dbo.ThreadTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var threadStatuses = (await connection.QueryAsync<ImportStatusLookupRow>(
|
|
||||||
"SELECT ThreadStatusID AS LookupID, StatusName FROM dbo.ThreadStatuses WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.StatusName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var threadEventTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT ThreadEventTypeID AS LookupID, TypeName FROM dbo.ThreadEventTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var sceneDependencyTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT SceneDependencyTypeID AS LookupID, TypeName FROM dbo.SceneDependencyTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var assetKinds = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT AssetKindID AS LookupID, KindName AS TypeName FROM dbo.AssetKinds WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var assetStates = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT AssetStateID AS LookupID, StateName AS TypeName FROM dbo.AssetStates WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var assetEventTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT AssetEventTypeID AS LookupID, TypeName FROM dbo.AssetEventTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var assetCustodyEventTypes = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT AssetCustodyEventTypeID AS LookupID, TypeName FROM dbo.AssetCustodyEventTypes WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
var custodyRoles = (await connection.QueryAsync<ImportLookupRow>(
|
|
||||||
"SELECT CustodyRoleID AS LookupID, RoleName AS TypeName FROM dbo.CustodyRoles WHERE IsActive = 1;",
|
|
||||||
transaction: transaction)).ToDictionary(x => x.TypeName, x => x.LookupID, StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
if (!revisionStatusId.HasValue || !timeModeId.HasValue || !timeConfidenceId.HasValue)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Import lookup values are missing. Run the core database script before importing.");
|
throw new InvalidOperationException("Import lookup values are missing. Run the core database script before importing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ImportLookupIds(
|
return new ImportLookupIds(
|
||||||
revisionStatusId.Value,
|
requiredLookups.RevisionStatusID.Value,
|
||||||
timeModeId.Value,
|
requiredLookups.TimeModeID.Value,
|
||||||
timeConfidenceId.Value,
|
requiredLookups.TimeConfidenceID.Value,
|
||||||
locationTypes,
|
locationTypes,
|
||||||
roleTypes,
|
roleTypes,
|
||||||
presenceTypes,
|
presenceTypes,
|
||||||
@ -1432,6 +1393,13 @@ public sealed class ImportRepository(ISqlConnectionFactory connectionFactory) :
|
|||||||
public string TypeName { get; set; } = string.Empty;
|
public string TypeName { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class ImportRequiredLookupRow
|
||||||
|
{
|
||||||
|
public int? RevisionStatusID { get; set; }
|
||||||
|
public int? TimeModeID { get; set; }
|
||||||
|
public int? TimeConfidenceID { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class ImportStatusLookupRow
|
private sealed class ImportStatusLookupRow
|
||||||
{
|
{
|
||||||
public int LookupID { get; set; }
|
public int LookupID { get; set; }
|
||||||
|
|||||||
@ -81,13 +81,9 @@ public sealed class ProjectBackupRepository(ISqlConnectionFactory connectionFact
|
|||||||
}
|
}
|
||||||
|
|
||||||
var bookMetadata = (await connection.QueryAsync<Book>(
|
var bookMetadata = (await connection.QueryAsync<Book>(
|
||||||
"""
|
"dbo.ProjectBackup_BookMetadata_List",
|
||||||
SELECT BookID, Subtitle, Tagline, ShortDescription, Status, TargetWordCount, WritingStartDate, TargetCompletionDate, PublicationDate
|
new { ProjectID = projectId },
|
||||||
, CoverThumbnailPath, CoverStandardPath
|
commandType: CommandType.StoredProcedure)).ToDictionary(x => x.BookID);
|
||||||
FROM dbo.Books
|
|
||||||
WHERE ProjectID = @ProjectID;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId })).ToDictionary(x => x.BookID);
|
|
||||||
foreach (var book in data.Books)
|
foreach (var book in data.Books)
|
||||||
{
|
{
|
||||||
if (!bookMetadata.TryGetValue(book.BookID, out var metadata))
|
if (!bookMetadata.TryGetValue(book.BookID, out var metadata))
|
||||||
|
|||||||
@ -792,44 +792,9 @@ public sealed class WarningRepository(ISqlConnectionFactory connectionFactory) :
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<ContinuityWarning>(
|
var rows = await connection.QueryAsync<ContinuityWarning>(
|
||||||
"""
|
"dbo.ContinuityWarning_ListDashboardUnresolved",
|
||||||
SELECT TOP (@Count)
|
new { ProjectID = projectId, Count = count },
|
||||||
cw.ContinuityWarningID,
|
commandType: CommandType.StoredProcedure);
|
||||||
cw.ValidationRunID,
|
|
||||||
cw.ProjectID,
|
|
||||||
cw.BookID,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle AS BookSubtitle,
|
|
||||||
cw.ChapterID,
|
|
||||||
c.ChapterNumber,
|
|
||||||
c.ChapterTitle,
|
|
||||||
cw.SceneID,
|
|
||||||
s.SceneNumber,
|
|
||||||
s.SceneTitle,
|
|
||||||
cw.EntityType,
|
|
||||||
cw.EntityID,
|
|
||||||
cw.WarningTypeID,
|
|
||||||
wt.TypeName AS WarningTypeName,
|
|
||||||
cw.WarningSeverityID,
|
|
||||||
ws.SeverityName,
|
|
||||||
cw.Message,
|
|
||||||
cw.Details,
|
|
||||||
cw.IsDismissed,
|
|
||||||
cw.IsIntentional,
|
|
||||||
cw.CreatedDate,
|
|
||||||
cw.LastDetectedDate
|
|
||||||
FROM dbo.ContinuityWarnings cw
|
|
||||||
INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID
|
|
||||||
INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID
|
|
||||||
LEFT JOIN dbo.Books b ON b.BookID = cw.BookID
|
|
||||||
LEFT JOIN dbo.Chapters c ON c.ChapterID = cw.ChapterID
|
|
||||||
LEFT JOIN dbo.Scenes s ON s.SceneID = cw.SceneID
|
|
||||||
WHERE cw.ProjectID = @ProjectID
|
|
||||||
AND cw.IsDismissed = 0
|
|
||||||
AND cw.IsIntentional = 0
|
|
||||||
ORDER BY ws.SortOrder DESC, cw.LastDetectedDate DESC, cw.ContinuityWarningID DESC;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId, Count = count });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1349,45 +1314,9 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<WritingPlanManagementItem>(
|
var rows = await connection.QueryAsync<WritingPlanManagementItem>(
|
||||||
"""
|
"dbo.WritingPlan_ListForManagement",
|
||||||
SELECT wp.WritingPlanID,
|
new { UserID = userId },
|
||||||
wp.UserID,
|
commandType: CommandType.StoredProcedure);
|
||||||
wp.ProjectID,
|
|
||||||
p.ProjectName,
|
|
||||||
wp.BookID,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle AS BookSubtitle,
|
|
||||||
wp.PlanName,
|
|
||||||
wp.GoalType,
|
|
||||||
wp.StartDate,
|
|
||||||
wp.DeadlineDate,
|
|
||||||
wp.AvailableDaysJson,
|
|
||||||
wp.SessionLengthMinutes,
|
|
||||||
wp.IsActive,
|
|
||||||
SUM(CASE WHEN wsi.ScheduleStatus = N'Planned' THEN 1 ELSE 0 END) AS PlannedTaskCount,
|
|
||||||
MAX(CASE WHEN wsi.ScheduleStatus = N'Planned' THEN wsi.ScheduledDate ELSE NULL END) AS ProjectedFinishDate
|
|
||||||
FROM dbo.WritingPlans wp
|
|
||||||
INNER JOIN dbo.Projects p ON p.ProjectID = wp.ProjectID
|
|
||||||
LEFT JOIN dbo.Books b ON b.BookID = wp.BookID
|
|
||||||
LEFT JOIN dbo.WritingScheduleItems wsi ON wsi.WritingPlanID = wp.WritingPlanID
|
|
||||||
WHERE wp.UserID = @UserID
|
|
||||||
GROUP BY wp.WritingPlanID,
|
|
||||||
wp.UserID,
|
|
||||||
wp.ProjectID,
|
|
||||||
p.ProjectName,
|
|
||||||
wp.BookID,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle,
|
|
||||||
wp.PlanName,
|
|
||||||
wp.GoalType,
|
|
||||||
wp.StartDate,
|
|
||||||
wp.DeadlineDate,
|
|
||||||
wp.AvailableDaysJson,
|
|
||||||
wp.SessionLengthMinutes,
|
|
||||||
wp.IsActive
|
|
||||||
ORDER BY wp.IsActive DESC, wp.DeadlineDate, wp.PlanName, wp.WritingPlanID;
|
|
||||||
""",
|
|
||||||
new { UserID = userId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1395,29 +1324,9 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<WritingScheduleScene>(
|
var rows = await connection.QueryAsync<WritingScheduleScene>(
|
||||||
"""
|
"dbo.WritingScheduleScene_ListForPlanning",
|
||||||
SELECT s.SceneID,
|
new { ProjectID = projectId, BookID = bookId, IncludeBlockedScenes = includeBlockedScenes },
|
||||||
rs.StatusName AS RevisionStatusName,
|
commandType: CommandType.StoredProcedure);
|
||||||
sw.EstimatedWordCount,
|
|
||||||
sw.Priority,
|
|
||||||
COALESCE(sw.IsBlocked, 0) AS IsBlocked,
|
|
||||||
b.SortOrder AS BookSortOrder,
|
|
||||||
c.SortOrder AS ChapterSortOrder,
|
|
||||||
s.SortOrder AS SceneSortOrder
|
|
||||||
FROM dbo.Projects p
|
|
||||||
INNER JOIN dbo.Books b ON b.ProjectID = p.ProjectID AND b.IsArchived = 0
|
|
||||||
INNER JOIN dbo.Chapters c ON c.BookID = b.BookID AND c.IsArchived = 0
|
|
||||||
INNER JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID AND s.IsArchived = 0
|
|
||||||
INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
|
|
||||||
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
|
||||||
WHERE p.ProjectID = @ProjectID
|
|
||||||
AND p.IsArchived = 0
|
|
||||||
AND (@BookID IS NULL OR b.BookID = @BookID)
|
|
||||||
AND rs.StatusName IN (N'Outlined', N'Needs Work', N'Revised')
|
|
||||||
AND (@IncludeBlockedScenes = 1 OR COALESCE(sw.IsBlocked, 0) = 0)
|
|
||||||
ORDER BY COALESCE(sw.Priority, 0) DESC, b.SortOrder, c.SortOrder, s.SortOrder, s.SceneID;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId, BookID = bookId, IncludeBlockedScenes = includeBlockedScenes });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1430,25 +1339,15 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"DELETE FROM dbo.WritingScheduleItems WHERE WritingPlanID = @WritingPlanID;",
|
"dbo.WritingScheduleItem_DeleteByPlan",
|
||||||
new { WritingPlanID = writingPlanId },
|
new { WritingPlanID = writingPlanId },
|
||||||
transaction);
|
transaction,
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"""
|
"dbo.CreateScheduleItem",
|
||||||
INSERT dbo.WritingScheduleItems
|
|
||||||
(
|
|
||||||
WritingPlanID, SceneID, ScheduledDate, TaskType, EstimatedMinutes, TargetWords,
|
|
||||||
ScheduleStatus, CompletedDateUtc, Notes
|
|
||||||
)
|
|
||||||
VALUES
|
|
||||||
(
|
|
||||||
@WritingPlanID, @SceneID, @ScheduledDate, @TaskType, @EstimatedMinutes, @TargetWords,
|
|
||||||
@ScheduleStatus, @CompletedDateUtc, @Notes
|
|
||||||
);
|
|
||||||
""",
|
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
item.WritingPlanID,
|
item.WritingPlanID,
|
||||||
@ -1461,7 +1360,8 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
item.CompletedDateUtc,
|
item.CompletedDateUtc,
|
||||||
item.Notes
|
item.Notes
|
||||||
},
|
},
|
||||||
transaction);
|
transaction,
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
@ -1477,25 +1377,9 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<WritingPlanSummary>(
|
var rows = await connection.QueryAsync<WritingPlanSummary>(
|
||||||
"""
|
"dbo.WritingPlanSummary_ListByUser",
|
||||||
SELECT wp.WritingPlanID,
|
new { UserID = userId, ProjectID = projectId },
|
||||||
wp.UserID,
|
commandType: CommandType.StoredProcedure);
|
||||||
wp.ProjectID,
|
|
||||||
p.ProjectName,
|
|
||||||
wp.BookID,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle AS BookSubtitle,
|
|
||||||
wp.PlanName,
|
|
||||||
wp.DeadlineDate,
|
|
||||||
wp.IsActive
|
|
||||||
FROM dbo.WritingPlans wp
|
|
||||||
INNER JOIN dbo.Projects p ON p.ProjectID = wp.ProjectID
|
|
||||||
LEFT JOIN dbo.Books b ON b.BookID = wp.BookID
|
|
||||||
WHERE wp.UserID = @UserID
|
|
||||||
AND (@ProjectID IS NULL OR wp.ProjectID = @ProjectID)
|
|
||||||
ORDER BY wp.IsActive DESC, wp.DeadlineDate, wp.PlanName, wp.WritingPlanID;
|
|
||||||
""",
|
|
||||||
new { UserID = userId, ProjectID = projectId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1503,33 +1387,9 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<WritingSchedulePreviewItem>(
|
var rows = await connection.QueryAsync<WritingSchedulePreviewItem>(
|
||||||
"""
|
"dbo.WritingSchedulePreview_ListByPlan",
|
||||||
SELECT wsi.WritingScheduleItemID,
|
new { WritingPlanID = writingPlanId },
|
||||||
wsi.WritingPlanID,
|
commandType: CommandType.StoredProcedure);
|
||||||
wsi.SceneID,
|
|
||||||
wsi.ScheduledDate,
|
|
||||||
wsi.TaskType,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle AS BookSubtitle,
|
|
||||||
c.ChapterNumber,
|
|
||||||
c.ChapterTitle,
|
|
||||||
s.SceneNumber,
|
|
||||||
s.SceneTitle,
|
|
||||||
sw.Priority,
|
|
||||||
wsi.EstimatedMinutes,
|
|
||||||
wsi.TargetWords,
|
|
||||||
wsi.ScheduleStatus,
|
|
||||||
wsi.Notes,
|
|
||||||
COALESCE(sw.IsBlocked, 0) AS IsBlocked
|
|
||||||
FROM dbo.WritingScheduleItems wsi
|
|
||||||
INNER JOIN dbo.Scenes s ON s.SceneID = wsi.SceneID
|
|
||||||
INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
|
|
||||||
INNER JOIN dbo.Books b ON b.BookID = c.BookID
|
|
||||||
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
|
||||||
WHERE wsi.WritingPlanID = @WritingPlanID
|
|
||||||
ORDER BY wsi.ScheduledDate, wsi.WritingScheduleItemID;
|
|
||||||
""",
|
|
||||||
new { WritingPlanID = writingPlanId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1537,46 +1397,18 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"DELETE FROM dbo.WritingScheduleItems WHERE WritingPlanID = @WritingPlanID;",
|
"dbo.WritingScheduleItem_DeleteByPlan",
|
||||||
new { WritingPlanID = writingPlanId });
|
new { WritingPlanID = writingPlanId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<WritingScheduleDashboardItem>> GetActiveScheduleDashboardItemsAsync(int userId, int? projectId = null)
|
public async Task<IReadOnlyList<WritingScheduleDashboardItem>> GetActiveScheduleDashboardItemsAsync(int userId, int? projectId = null)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<WritingScheduleDashboardItem>(
|
var rows = await connection.QueryAsync<WritingScheduleDashboardItem>(
|
||||||
"""
|
"dbo.WritingScheduleDashboard_ListActive",
|
||||||
SELECT wsi.WritingScheduleItemID,
|
new { UserID = userId, ProjectID = projectId },
|
||||||
wsi.WritingPlanID,
|
commandType: CommandType.StoredProcedure);
|
||||||
wp.PlanName,
|
|
||||||
wsi.SceneID,
|
|
||||||
wsi.ScheduledDate,
|
|
||||||
wsi.TaskType,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle AS BookSubtitle,
|
|
||||||
c.ChapterNumber,
|
|
||||||
c.ChapterTitle,
|
|
||||||
c.SortOrder AS ChapterSortOrder,
|
|
||||||
s.SceneNumber,
|
|
||||||
s.SceneTitle,
|
|
||||||
s.SortOrder AS SceneSortOrder,
|
|
||||||
sw.Priority,
|
|
||||||
wsi.EstimatedMinutes,
|
|
||||||
wsi.TargetWords,
|
|
||||||
wsi.ScheduleStatus,
|
|
||||||
COALESCE(sw.IsBlocked, 0) AS IsBlocked
|
|
||||||
FROM dbo.WritingPlans wp
|
|
||||||
INNER JOIN dbo.WritingScheduleItems wsi ON wsi.WritingPlanID = wp.WritingPlanID
|
|
||||||
INNER JOIN dbo.Scenes s ON s.SceneID = wsi.SceneID
|
|
||||||
INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
|
|
||||||
INNER JOIN dbo.Books b ON b.BookID = c.BookID
|
|
||||||
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
|
||||||
WHERE wp.UserID = @UserID
|
|
||||||
AND wp.IsActive = 1
|
|
||||||
AND (@ProjectID IS NULL OR wp.ProjectID = @ProjectID)
|
|
||||||
ORDER BY wsi.ScheduledDate, wsi.WritingScheduleItemID;
|
|
||||||
""",
|
|
||||||
new { UserID = userId, ProjectID = projectId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1584,59 +1416,24 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
return await connection.ExecuteAsync(
|
return await connection.ExecuteAsync(
|
||||||
"""
|
"dbo.WritingScheduleItem_UpdatePlannedStatusForUser",
|
||||||
UPDATE wsi
|
|
||||||
SET ScheduleStatus = @ScheduleStatus,
|
|
||||||
CompletedDateUtc = @CompletedDateUtc,
|
|
||||||
ModifiedDateUtc = SYSUTCDATETIME()
|
|
||||||
FROM dbo.WritingScheduleItems wsi
|
|
||||||
INNER JOIN dbo.WritingPlans wp ON wp.WritingPlanID = wsi.WritingPlanID
|
|
||||||
WHERE wsi.WritingScheduleItemID = @WritingScheduleItemID
|
|
||||||
AND wp.UserID = @UserID
|
|
||||||
AND wp.IsActive = 1
|
|
||||||
AND wsi.ScheduleStatus = N'Planned';
|
|
||||||
""",
|
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
WritingScheduleItemID = writingScheduleItemId,
|
WritingScheduleItemID = writingScheduleItemId,
|
||||||
UserID = userId,
|
UserID = userId,
|
||||||
ScheduleStatus = scheduleStatus,
|
ScheduleStatus = scheduleStatus,
|
||||||
CompletedDateUtc = completedDateUtc
|
CompletedDateUtc = completedDateUtc
|
||||||
});
|
},
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<WritingPlanSummary>> GetPlansRequiringRebalanceAsync(int userId, DateTime today, int? projectId = null)
|
public async Task<IReadOnlyList<WritingPlanSummary>> GetPlansRequiringRebalanceAsync(int userId, DateTime today, int? projectId = null)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<WritingPlanSummary>(
|
var rows = await connection.QueryAsync<WritingPlanSummary>(
|
||||||
"""
|
"dbo.WritingPlanSummary_ListRequiringRebalance",
|
||||||
SELECT wp.WritingPlanID,
|
new { UserID = userId, Today = today.Date, ProjectID = projectId },
|
||||||
wp.UserID,
|
commandType: CommandType.StoredProcedure);
|
||||||
wp.ProjectID,
|
|
||||||
p.ProjectName,
|
|
||||||
wp.BookID,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle AS BookSubtitle,
|
|
||||||
wp.PlanName,
|
|
||||||
wp.DeadlineDate,
|
|
||||||
wp.IsActive
|
|
||||||
FROM dbo.WritingPlans wp
|
|
||||||
INNER JOIN dbo.Projects p ON p.ProjectID = wp.ProjectID
|
|
||||||
LEFT JOIN dbo.Books b ON b.BookID = wp.BookID
|
|
||||||
WHERE wp.UserID = @UserID
|
|
||||||
AND wp.IsActive = 1
|
|
||||||
AND (@ProjectID IS NULL OR wp.ProjectID = @ProjectID)
|
|
||||||
AND EXISTS
|
|
||||||
(
|
|
||||||
SELECT 1
|
|
||||||
FROM dbo.WritingScheduleItems wsi
|
|
||||||
WHERE wsi.WritingPlanID = wp.WritingPlanID
|
|
||||||
AND wsi.ScheduleStatus = N'Planned'
|
|
||||||
AND wsi.ScheduledDate < @Today
|
|
||||||
)
|
|
||||||
ORDER BY wp.DeadlineDate, wp.PlanName, wp.WritingPlanID;
|
|
||||||
""",
|
|
||||||
new { UserID = userId, Today = today.Date, ProjectID = projectId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1656,21 +1453,15 @@ public sealed class WritingScheduleRepository(ISqlConnectionFactory connectionFa
|
|||||||
foreach (var change in changes)
|
foreach (var change in changes)
|
||||||
{
|
{
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"""
|
"dbo.WritingScheduleItem_UpdatePlannedDate",
|
||||||
UPDATE dbo.WritingScheduleItems
|
|
||||||
SET ScheduledDate = @ScheduledDate,
|
|
||||||
ModifiedDateUtc = SYSUTCDATETIME()
|
|
||||||
WHERE WritingPlanID = @WritingPlanID
|
|
||||||
AND WritingScheduleItemID = @WritingScheduleItemID
|
|
||||||
AND ScheduleStatus = N'Planned';
|
|
||||||
""",
|
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
WritingPlanID = writingPlanId,
|
WritingPlanID = writingPlanId,
|
||||||
change.WritingScheduleItemID,
|
change.WritingScheduleItemID,
|
||||||
ScheduledDate = change.ScheduledDate.Date
|
ScheduledDate = change.ScheduledDate.Date
|
||||||
},
|
},
|
||||||
transaction);
|
transaction,
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
@ -2095,62 +1886,18 @@ public sealed class ProjectRepository(ISqlConnectionFactory connectionFactory) :
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
return await connection.QuerySingleAsync<ProjectDashboardMetrics>(
|
return await connection.QuerySingleAsync<ProjectDashboardMetrics>(
|
||||||
"""
|
"dbo.ProjectDashboard_Metrics",
|
||||||
SELECT
|
new { ProjectID = projectId },
|
||||||
(SELECT COUNT(1) FROM dbo.Characters WHERE ProjectID = @ProjectID AND IsArchived = 0) AS CharacterCount,
|
commandType: CommandType.StoredProcedure);
|
||||||
(SELECT COUNT(1) FROM dbo.Locations WHERE ProjectID = @ProjectID AND IsArchived = 0) AS LocationCount,
|
|
||||||
(
|
|
||||||
SELECT COUNT(1)
|
|
||||||
FROM dbo.PlotThreads pt
|
|
||||||
INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
|
|
||||||
INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
|
|
||||||
WHERE pl.ProjectID = @ProjectID
|
|
||||||
AND pl.IsArchived = 0
|
|
||||||
AND pt.IsArchived = 0
|
|
||||||
AND ts.IsOpenStatus = 1
|
|
||||||
) AS ActivePlotThreadCount,
|
|
||||||
(
|
|
||||||
SELECT COUNT(1)
|
|
||||||
FROM dbo.ContinuityWarnings
|
|
||||||
WHERE ProjectID = @ProjectID
|
|
||||||
AND IsDismissed = 0
|
|
||||||
AND IsIntentional = 0
|
|
||||||
) AS ContinuityWarningCount;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<ProjectDashboardAttentionThread>> ListDashboardAttentionThreadsAsync(int projectId, int count)
|
public async Task<IReadOnlyList<ProjectDashboardAttentionThread>> ListDashboardAttentionThreadsAsync(int projectId, int count)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<ProjectDashboardAttentionThread>(
|
var rows = await connection.QueryAsync<ProjectDashboardAttentionThread>(
|
||||||
"""
|
"dbo.ProjectDashboard_AttentionThreads",
|
||||||
SELECT TOP (@Count)
|
new { ProjectID = projectId, Count = count },
|
||||||
pt.PlotThreadID,
|
commandType: CommandType.StoredProcedure);
|
||||||
pt.ThreadTitle,
|
|
||||||
pt.PlotLineID,
|
|
||||||
pl.PlotLineName,
|
|
||||||
pt.Importance,
|
|
||||||
ts.StatusName AS ThreadStatusName,
|
|
||||||
ts.IsOpenStatus,
|
|
||||||
ts.IsResolvedStatus
|
|
||||||
FROM dbo.PlotThreads pt
|
|
||||||
INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
|
|
||||||
INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
|
|
||||||
WHERE pl.ProjectID = @ProjectID
|
|
||||||
AND pl.IsArchived = 0
|
|
||||||
AND pt.IsArchived = 0
|
|
||||||
AND (
|
|
||||||
ts.StatusName = N'Dormant'
|
|
||||||
OR (ts.IsOpenStatus = 1 AND pt.Importance >= 8)
|
|
||||||
)
|
|
||||||
ORDER BY
|
|
||||||
CASE WHEN ts.StatusName = N'Dormant' THEN 0 ELSE 1 END,
|
|
||||||
pt.Importance DESC,
|
|
||||||
pt.UpdatedDate DESC,
|
|
||||||
pt.PlotThreadID DESC;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId, Count = count });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2333,25 +2080,9 @@ public sealed class ProjectActivityRepository(ISqlConnectionFactory connectionFa
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<ProjectActivity>(
|
var rows = await connection.QueryAsync<ProjectActivity>(
|
||||||
"""
|
"dbo.ProjectActivity_ListRecent",
|
||||||
SELECT TOP (@Count)
|
new { ProjectID = projectId, Count = count },
|
||||||
pa.ProjectActivityID,
|
commandType: CommandType.StoredProcedure);
|
||||||
pa.ProjectID,
|
|
||||||
pa.UserID,
|
|
||||||
u.DisplayName,
|
|
||||||
u.Email,
|
|
||||||
pa.ActivityType,
|
|
||||||
pa.EntityType,
|
|
||||||
pa.EntityID,
|
|
||||||
pa.EntityName,
|
|
||||||
pa.Description,
|
|
||||||
pa.CreatedDateUTC
|
|
||||||
FROM dbo.ProjectActivity pa
|
|
||||||
LEFT JOIN dbo.AppUser u ON u.UserID = pa.UserID
|
|
||||||
WHERE pa.ProjectID = @ProjectID
|
|
||||||
ORDER BY pa.CreatedDateUTC DESC, pa.ProjectActivityID DESC;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId, Count = count });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2393,54 +2124,9 @@ public sealed class BookRepository(ISqlConnectionFactory connectionFactory) : IB
|
|||||||
|
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<Book>(
|
var rows = await connection.QueryAsync<Book>(
|
||||||
"""
|
"dbo.Book_ListByProjects",
|
||||||
SELECT
|
new { ProjectIDs = string.Join(',', ids) },
|
||||||
b.BookID,
|
commandType: CommandType.StoredProcedure);
|
||||||
b.ProjectID,
|
|
||||||
b.BookTitle,
|
|
||||||
b.Subtitle,
|
|
||||||
b.Tagline,
|
|
||||||
b.ShortDescription,
|
|
||||||
b.Status,
|
|
||||||
b.BookNumber,
|
|
||||||
b.Description,
|
|
||||||
b.TargetWordCount,
|
|
||||||
b.WritingStartDate,
|
|
||||||
b.TargetCompletionDate,
|
|
||||||
b.PublicationDate,
|
|
||||||
b.CoverThumbnailPath,
|
|
||||||
b.CoverStandardPath,
|
|
||||||
ISNULL(wordCounts.CurrentWordCount, 0) AS CurrentWordCount,
|
|
||||||
ISNULL(counts.ChapterCount, 0) AS ChapterCount,
|
|
||||||
ISNULL(counts.SceneCount, 0) AS SceneCount,
|
|
||||||
b.SortOrder,
|
|
||||||
b.CreatedDate,
|
|
||||||
b.UpdatedDate,
|
|
||||||
b.IsArchived,
|
|
||||||
b.ArchivedDate,
|
|
||||||
b.ArchivedReason
|
|
||||||
FROM dbo.Books b
|
|
||||||
OUTER APPLY
|
|
||||||
(
|
|
||||||
SELECT
|
|
||||||
COUNT(DISTINCT c.ChapterID) AS ChapterCount,
|
|
||||||
COUNT(s.SceneID) AS SceneCount
|
|
||||||
FROM dbo.Chapters c
|
|
||||||
LEFT JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID AND s.IsArchived = 0
|
|
||||||
WHERE c.BookID = b.BookID AND c.IsArchived = 0
|
|
||||||
) counts
|
|
||||||
OUTER APPLY
|
|
||||||
(
|
|
||||||
SELECT SUM(ISNULL(sw.ActualWordCount, 0)) AS CurrentWordCount
|
|
||||||
FROM dbo.Chapters c
|
|
||||||
INNER JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID AND s.IsArchived = 0
|
|
||||||
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
|
||||||
WHERE c.BookID = b.BookID AND c.IsArchived = 0
|
|
||||||
) wordCounts
|
|
||||||
WHERE b.ProjectID IN @ProjectIDs AND b.IsArchived = 0
|
|
||||||
ORDER BY b.ProjectID, b.SortOrder, b.BookNumber, b.BookTitle;
|
|
||||||
""",
|
|
||||||
new { ProjectIDs = ids });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2454,12 +2140,9 @@ public sealed class BookRepository(ISqlConnectionFactory connectionFactory) : IB
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
return await connection.QuerySingleOrDefaultAsync<Book>(
|
return await connection.QuerySingleOrDefaultAsync<Book>(
|
||||||
"""
|
"dbo.Book_GetCoverPaths",
|
||||||
SELECT BookID, ProjectID, CoverThumbnailPath, CoverStandardPath
|
new { BookID = bookId },
|
||||||
FROM dbo.Books
|
commandType: CommandType.StoredProcedure);
|
||||||
WHERE BookID = @BookID;
|
|
||||||
""",
|
|
||||||
new { BookID = bookId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> SaveAsync(Book book)
|
public async Task<int> SaveAsync(Book book)
|
||||||
@ -2632,17 +2315,9 @@ public sealed class SceneRepository(ISqlConnectionFactory connectionFactory) : I
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"""
|
"dbo.SceneMetric_SaveValue",
|
||||||
MERGE dbo.SceneMetricValues AS target
|
new { SceneID = sceneId, MetricTypeID = metricTypeId, Value = value, Notes = (string?)null },
|
||||||
USING (SELECT @SceneID AS SceneID, @MetricTypeID AS MetricTypeID) AS source
|
commandType: CommandType.StoredProcedure);
|
||||||
ON target.SceneID = source.SceneID AND target.MetricTypeID = source.MetricTypeID
|
|
||||||
WHEN MATCHED THEN
|
|
||||||
UPDATE SET Value = @Value
|
|
||||||
WHEN NOT MATCHED THEN
|
|
||||||
INSERT (SceneID, MetricTypeID, Value, Notes)
|
|
||||||
VALUES (@SceneID, @MetricTypeID, @Value, NULL);
|
|
||||||
""",
|
|
||||||
new { SceneID = sceneId, MetricTypeID = metricTypeId, Value = value });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ArchiveAsync(int sceneId)
|
public async Task ArchiveAsync(int sceneId)
|
||||||
@ -2824,8 +2499,9 @@ public sealed class TimelineRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var targetRows = await connection.QueryAsync<ThreadEventTargetRow>(
|
var targetRows = await connection.QueryAsync<ThreadEventTargetRow>(
|
||||||
"SELECT PlotEventID, PlotLineID FROM dbo.PlotEventTargetPlotLines WHERE PlotEventID IN @ThreadEventIDs;",
|
"dbo.ThreadEventTarget_ListByEvents",
|
||||||
new { ThreadEventIDs = threadEventIds });
|
new { ThreadEventIDs = string.Join(',', threadEventIds) },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
var targetsByEvent = targetRows
|
var targetsByEvent = targetRows
|
||||||
.GroupBy(x => x.PlotEventID)
|
.GroupBy(x => x.PlotEventID)
|
||||||
.ToDictionary(x => x.Key, x => (IReadOnlyList<int>)x.Select(row => row.PlotLineID).ToList());
|
.ToDictionary(x => x.Key, x => (IReadOnlyList<int>)x.Select(row => row.PlotLineID).ToList());
|
||||||
@ -3159,8 +2835,9 @@ public sealed class PlotRepository(ISqlConnectionFactory connectionFactory) : IP
|
|||||||
}
|
}
|
||||||
|
|
||||||
var targetRows = await connection.QueryAsync<ThreadEventTargetRow>(
|
var targetRows = await connection.QueryAsync<ThreadEventTargetRow>(
|
||||||
"SELECT PlotEventID, PlotLineID FROM dbo.PlotEventTargetPlotLines WHERE PlotEventID IN @ThreadEventIDs;",
|
"dbo.ThreadEventTarget_ListByEvents",
|
||||||
new { ThreadEventIDs = threadEventIds });
|
new { ThreadEventIDs = string.Join(',', threadEventIds) },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
var targetsByEvent = targetRows
|
var targetsByEvent = targetRows
|
||||||
.GroupBy(x => x.PlotEventID)
|
.GroupBy(x => x.PlotEventID)
|
||||||
.ToDictionary(x => x.Key, x => (IReadOnlyList<int>)x.Select(row => row.PlotLineID).ToList());
|
.ToDictionary(x => x.Key, x => (IReadOnlyList<int>)x.Select(row => row.PlotLineID).ToList());
|
||||||
@ -3204,17 +2881,9 @@ public sealed class PlotRepository(ISqlConnectionFactory connectionFactory) : IP
|
|||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var targetIds = plotLineIds.Where(id => id > 0).Distinct().ToList();
|
var targetIds = plotLineIds.Where(id => id > 0).Distinct().ToList();
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"DELETE FROM dbo.PlotEventTargetPlotLines WHERE PlotEventID = @ThreadEventID;",
|
"dbo.ThreadEventTarget_SaveForEvent",
|
||||||
new { ThreadEventID = threadEventId });
|
new { ThreadEventID = threadEventId, PlotLineIDs = string.Join(',', targetIds) },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
if (targetIds.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await connection.ExecuteAsync(
|
|
||||||
"INSERT dbo.PlotEventTargetPlotLines (PlotEventID, PlotLineID) VALUES (@ThreadEventID, @PlotLineID);",
|
|
||||||
targetIds.Select(plotLineId => new { ThreadEventID = threadEventId, PlotLineID = plotLineId }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteThreadEventAsync(int threadEventId)
|
public async Task DeleteThreadEventAsync(int threadEventId)
|
||||||
@ -3387,26 +3056,9 @@ public sealed class AssetRepository(ISqlConnectionFactory connectionFactory) : I
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<AssetCustodyCharacter>(
|
var rows = await connection.QueryAsync<AssetCustodyCharacter>(
|
||||||
"""
|
"dbo.AssetCustodyCharacter_ListByProject",
|
||||||
SELECT acec.AssetCustodyEventID,
|
new { ProjectID = projectId },
|
||||||
ace.StoryAssetID,
|
commandType: CommandType.StoredProcedure);
|
||||||
ace.SceneID,
|
|
||||||
acec.CharacterID,
|
|
||||||
c.CharacterName,
|
|
||||||
acec.CharacterNameText,
|
|
||||||
cr.RoleName,
|
|
||||||
ace.UpdatedDate
|
|
||||||
FROM dbo.AssetCustodyEventCharacters acec
|
|
||||||
INNER JOIN dbo.AssetCustodyEvents ace ON ace.AssetCustodyEventID = acec.AssetCustodyEventID
|
|
||||||
INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ace.StoryAssetID
|
|
||||||
LEFT JOIN dbo.Characters c ON c.CharacterID = acec.CharacterID
|
|
||||||
LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = acec.CustodyRoleID
|
|
||||||
WHERE sa.ProjectID = @ProjectID
|
|
||||||
AND sa.IsArchived = 0
|
|
||||||
AND acec.CharacterID IS NOT NULL
|
|
||||||
AND NULLIF(LTRIM(RTRIM(c.CharacterName)), N'') IS NOT NULL;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3419,18 +3071,9 @@ public sealed class AssetRepository(ISqlConnectionFactory connectionFactory) : I
|
|||||||
|
|
||||||
var eventIds = rows.Select(x => x.AssetCustodyEventID).Distinct().ToList();
|
var eventIds = rows.Select(x => x.AssetCustodyEventID).Distinct().ToList();
|
||||||
var validCustodians = await connection.QueryAsync<AssetCustodySummaryRow>(
|
var validCustodians = await connection.QueryAsync<AssetCustodySummaryRow>(
|
||||||
"""
|
"dbo.AssetCustodySummary_ListByEvents",
|
||||||
SELECT acec.AssetCustodyEventID,
|
new { AssetCustodyEventIDs = string.Join(',', eventIds) },
|
||||||
c.CharacterName,
|
commandType: CommandType.StoredProcedure);
|
||||||
cr.RoleName
|
|
||||||
FROM dbo.AssetCustodyEventCharacters acec
|
|
||||||
INNER JOIN dbo.Characters c ON c.CharacterID = acec.CharacterID
|
|
||||||
LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = acec.CustodyRoleID
|
|
||||||
WHERE acec.AssetCustodyEventID IN @AssetCustodyEventIDs
|
|
||||||
AND acec.CharacterID IS NOT NULL
|
|
||||||
AND NULLIF(LTRIM(RTRIM(c.CharacterName)), N'') IS NOT NULL;
|
|
||||||
""",
|
|
||||||
new { AssetCustodyEventIDs = eventIds });
|
|
||||||
|
|
||||||
var summaries = validCustodians
|
var summaries = validCustodians
|
||||||
.GroupBy(x => x.AssetCustodyEventID)
|
.GroupBy(x => x.AssetCustodyEventID)
|
||||||
@ -3565,14 +3208,9 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<CharacterSexValue>(
|
var rows = await connection.QueryAsync<CharacterSexValue>(
|
||||||
"""
|
"dbo.CharacterSexValue_ListForOwner",
|
||||||
SELECT CharacterSexValueID, OwnerUserID, SexName, IsSystem, SortOrder, IsActive
|
new { OwnerUserID = ownerUserId },
|
||||||
FROM dbo.CharacterSexValues
|
commandType: CommandType.StoredProcedure);
|
||||||
WHERE IsActive = 1
|
|
||||||
AND (IsSystem = 1 OR OwnerUserID = @OwnerUserID)
|
|
||||||
ORDER BY IsSystem DESC, SortOrder, SexName;
|
|
||||||
""",
|
|
||||||
new { OwnerUserID = ownerUserId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3580,14 +3218,9 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
return await connection.QuerySingleOrDefaultAsync<CharacterSexValue>(
|
return await connection.QuerySingleOrDefaultAsync<CharacterSexValue>(
|
||||||
"""
|
"dbo.CharacterSexValue_Get",
|
||||||
SELECT CharacterSexValueID, OwnerUserID, SexName, IsSystem, SortOrder, IsActive
|
new { CharacterSexValueID = characterSexValueId, OwnerUserID = ownerUserId },
|
||||||
FROM dbo.CharacterSexValues
|
commandType: CommandType.StoredProcedure);
|
||||||
WHERE CharacterSexValueID = @CharacterSexValueID
|
|
||||||
AND IsActive = 1
|
|
||||||
AND (IsSystem = 1 OR OwnerUserID = @OwnerUserID);
|
|
||||||
""",
|
|
||||||
new { CharacterSexValueID = characterSexValueId, OwnerUserID = ownerUserId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> GetOrCreateSexValueAsync(int ownerUserId, string sexName)
|
public async Task<int> GetOrCreateSexValueAsync(int ownerUserId, string sexName)
|
||||||
@ -3627,13 +3260,9 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<CharacterImage>(
|
var rows = await connection.QueryAsync<CharacterImage>(
|
||||||
"""
|
"dbo.CharacterImage_ListByCharacter",
|
||||||
SELECT CharacterImageID, CharacterID, ProjectID, ImagePath, ThumbnailPath, Caption, SortOrder, UploadedDateUTC, IsDeleted
|
new { CharacterID = characterId },
|
||||||
FROM dbo.CharacterImages
|
commandType: CommandType.StoredProcedure);
|
||||||
WHERE CharacterID = @CharacterID AND IsDeleted = 0
|
|
||||||
ORDER BY SortOrder, UploadedDateUTC, CharacterImageID;
|
|
||||||
""",
|
|
||||||
new { CharacterID = characterId });
|
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3641,26 +3270,16 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
return await connection.QuerySingleOrDefaultAsync<CharacterImage>(
|
return await connection.QuerySingleOrDefaultAsync<CharacterImage>(
|
||||||
"""
|
"dbo.CharacterImage_Get",
|
||||||
SELECT CharacterImageID, CharacterID, ProjectID, ImagePath, ThumbnailPath, Caption, SortOrder, UploadedDateUTC, IsDeleted
|
new { CharacterImageID = characterImageId },
|
||||||
FROM dbo.CharacterImages
|
commandType: CommandType.StoredProcedure);
|
||||||
WHERE CharacterImageID = @CharacterImageID AND IsDeleted = 0;
|
|
||||||
""",
|
|
||||||
new { CharacterImageID = characterImageId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateCharacterImageAsync(CharacterImage image)
|
public async Task<int> CreateCharacterImageAsync(CharacterImage image)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
return await connection.QuerySingleAsync<int>(
|
return await connection.QuerySingleAsync<int>(
|
||||||
"""
|
"dbo.CharacterImage_Create",
|
||||||
DECLARE @SortOrder int = COALESCE(@InputSortOrder, (SELECT ISNULL(MAX(SortOrder), 0) + 1 FROM dbo.CharacterImages WHERE CharacterID = @CharacterID));
|
|
||||||
|
|
||||||
INSERT dbo.CharacterImages (CharacterID, ProjectID, ImagePath, ThumbnailPath, Caption, SortOrder)
|
|
||||||
VALUES (@CharacterID, @ProjectID, @ImagePath, @ThumbnailPath, @Caption, @SortOrder);
|
|
||||||
|
|
||||||
SELECT CAST(SCOPE_IDENTITY() AS int);
|
|
||||||
""",
|
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
image.CharacterID,
|
image.CharacterID,
|
||||||
@ -3669,20 +3288,17 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
image.ThumbnailPath,
|
image.ThumbnailPath,
|
||||||
image.Caption,
|
image.Caption,
|
||||||
InputSortOrder = image.SortOrder == 0 ? (int?)null : image.SortOrder
|
InputSortOrder = image.SortOrder == 0 ? (int?)null : image.SortOrder
|
||||||
});
|
},
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteCharacterImageAsync(int characterImageId)
|
public async Task DeleteCharacterImageAsync(int characterImageId)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
"""
|
"dbo.CharacterImage_Delete",
|
||||||
UPDATE dbo.CharacterImages
|
new { CharacterImageID = characterImageId },
|
||||||
SET IsDeleted = 1,
|
commandType: CommandType.StoredProcedure);
|
||||||
DeletedDateUTC = SYSUTCDATETIME()
|
|
||||||
WHERE CharacterImageID = @CharacterImageID;
|
|
||||||
""",
|
|
||||||
new { CharacterImageID = characterImageId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ArchiveCharacterAsync(int characterId)
|
public async Task ArchiveCharacterAsync(int characterId)
|
||||||
|
|||||||
@ -36,23 +36,9 @@ public sealed class WordCompanionRepository(ISqlConnectionFactory connectionFact
|
|||||||
{
|
{
|
||||||
using var connection = connectionFactory.CreateConnection();
|
using var connection = connectionFactory.CreateConnection();
|
||||||
var rows = await connection.QueryAsync<WordCompanionBookDto>(
|
var rows = await connection.QueryAsync<WordCompanionBookDto>(
|
||||||
"""
|
"dbo.WordCompanion_Book_ListByProject",
|
||||||
SELECT b.BookID AS BookId,
|
|
||||||
b.BookTitle AS Title,
|
|
||||||
b.Subtitle,
|
|
||||||
b.SortOrder
|
|
||||||
FROM dbo.Books b
|
|
||||||
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = b.ProjectID
|
|
||||||
INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID
|
|
||||||
WHERE b.ProjectID = @ProjectID
|
|
||||||
AND pua.UserID = @UserID
|
|
||||||
AND pua.IsActive = 1
|
|
||||||
AND p.IsArchived = 0
|
|
||||||
AND b.IsArchived = 0
|
|
||||||
ORDER BY b.SortOrder, b.BookNumber, b.BookTitle, b.BookID;
|
|
||||||
""",
|
|
||||||
new { ProjectID = projectId, UserID = userId },
|
new { ProjectID = projectId, UserID = userId },
|
||||||
commandType: CommandType.Text);
|
commandType: CommandType.StoredProcedure);
|
||||||
return rows.ToList();
|
return rows.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
619
PlotLine/Sql/088_InlineSqlStoredProcedureRefactor.sql
Normal file
619
PlotLine/Sql/088_InlineSqlStoredProcedureRefactor.sql
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
SET ANSI_NULLS ON;
|
||||||
|
GO
|
||||||
|
SET QUOTED_IDENTIFIER ON;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Project_ExistsByNameForUser
|
||||||
|
@ProjectName nvarchar(200),
|
||||||
|
@UserID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM dbo.Projects p
|
||||||
|
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID
|
||||||
|
WHERE p.IsArchived = 0
|
||||||
|
AND p.ProjectName = @ProjectName
|
||||||
|
AND pua.UserID = @UserID
|
||||||
|
AND pua.IsActive = 1;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Scene_UpdatePovCharacter
|
||||||
|
@SceneID int,
|
||||||
|
@POVCharacterID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
UPDATE dbo.Scenes
|
||||||
|
SET POVCharacterID = @POVCharacterID,
|
||||||
|
UpdatedDate = SYSUTCDATETIME()
|
||||||
|
WHERE SceneID = @SceneID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Import_LookupIds
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
(SELECT TOP (1) RevisionStatusID FROM dbo.RevisionStatuses WHERE StatusName = N'Planned' ORDER BY SortOrder) AS RevisionStatusID,
|
||||||
|
(SELECT TOP (1) TimeModeID FROM dbo.TimeModes WHERE TimeModeName = N'Relative' ORDER BY SortOrder) AS TimeModeID,
|
||||||
|
(SELECT TOP (1) TimeConfidenceID FROM dbo.TimeConfidences WHERE TimeConfidenceName = N'Unknown' ORDER BY SortOrder) AS TimeConfidenceID;
|
||||||
|
|
||||||
|
SELECT LocationTypeID AS LookupID, TypeName FROM dbo.LocationTypes WHERE IsActive = 1;
|
||||||
|
SELECT CharacterRoleInSceneTypeID AS LookupID, TypeName FROM dbo.CharacterRoleInSceneTypes WHERE IsActive = 1;
|
||||||
|
SELECT PresenceTypeID AS LookupID, TypeName FROM dbo.PresenceTypes WHERE IsActive = 1;
|
||||||
|
SELECT PlotLineTypeID AS LookupID, TypeName FROM dbo.PlotLineTypes WHERE IsActive = 1;
|
||||||
|
SELECT PlotImportanceID AS LookupID, ImportanceName AS TypeName FROM dbo.PlotImportance WHERE IsActive = 1;
|
||||||
|
SELECT ThreadTypeID AS LookupID, TypeName FROM dbo.ThreadTypes WHERE IsActive = 1;
|
||||||
|
SELECT ThreadStatusID AS LookupID, StatusName FROM dbo.ThreadStatuses WHERE IsActive = 1;
|
||||||
|
SELECT ThreadEventTypeID AS LookupID, TypeName FROM dbo.ThreadEventTypes WHERE IsActive = 1;
|
||||||
|
SELECT SceneDependencyTypeID AS LookupID, TypeName FROM dbo.SceneDependencyTypes WHERE IsActive = 1;
|
||||||
|
SELECT AssetKindID AS LookupID, KindName AS TypeName FROM dbo.AssetKinds WHERE IsActive = 1;
|
||||||
|
SELECT AssetStateID AS LookupID, StateName AS TypeName FROM dbo.AssetStates WHERE IsActive = 1;
|
||||||
|
SELECT AssetEventTypeID AS LookupID, TypeName FROM dbo.AssetEventTypes WHERE IsActive = 1;
|
||||||
|
SELECT AssetCustodyEventTypeID AS LookupID, TypeName FROM dbo.AssetCustodyEventTypes WHERE IsActive = 1;
|
||||||
|
SELECT CustodyRoleID AS LookupID, RoleName AS TypeName FROM dbo.CustodyRoles WHERE IsActive = 1;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ProjectBackup_BookMetadata_List
|
||||||
|
@ProjectID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT BookID, Subtitle, Tagline, ShortDescription, Status, TargetWordCount, WritingStartDate, TargetCompletionDate, PublicationDate,
|
||||||
|
CoverThumbnailPath, CoverStandardPath
|
||||||
|
FROM dbo.Books
|
||||||
|
WHERE ProjectID = @ProjectID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WordCompanion_Book_ListByProject
|
||||||
|
@ProjectID int,
|
||||||
|
@UserID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT b.BookID AS BookId,
|
||||||
|
b.BookTitle AS Title,
|
||||||
|
b.Subtitle,
|
||||||
|
b.SortOrder
|
||||||
|
FROM dbo.Books b
|
||||||
|
INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = b.ProjectID
|
||||||
|
INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID
|
||||||
|
WHERE b.ProjectID = @ProjectID
|
||||||
|
AND pua.UserID = @UserID
|
||||||
|
AND pua.IsActive = 1
|
||||||
|
AND p.IsArchived = 0
|
||||||
|
AND b.IsArchived = 0
|
||||||
|
ORDER BY b.SortOrder, b.BookNumber, b.BookTitle, b.BookID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ContinuityWarning_ListDashboardUnresolved
|
||||||
|
@ProjectID int,
|
||||||
|
@Count int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT TOP (@Count)
|
||||||
|
cw.ContinuityWarningID,
|
||||||
|
cw.ValidationRunID,
|
||||||
|
cw.ProjectID,
|
||||||
|
cw.BookID,
|
||||||
|
b.BookTitle,
|
||||||
|
b.Subtitle AS BookSubtitle,
|
||||||
|
cw.ChapterID,
|
||||||
|
c.ChapterNumber,
|
||||||
|
c.ChapterTitle,
|
||||||
|
cw.SceneID,
|
||||||
|
s.SceneNumber,
|
||||||
|
s.SceneTitle,
|
||||||
|
cw.EntityType,
|
||||||
|
cw.EntityID,
|
||||||
|
cw.WarningTypeID,
|
||||||
|
wt.TypeName AS WarningTypeName,
|
||||||
|
cw.WarningSeverityID,
|
||||||
|
ws.SeverityName,
|
||||||
|
cw.Message,
|
||||||
|
cw.Details,
|
||||||
|
cw.IsDismissed,
|
||||||
|
cw.IsIntentional,
|
||||||
|
cw.CreatedDate,
|
||||||
|
cw.LastDetectedDate
|
||||||
|
FROM dbo.ContinuityWarnings cw
|
||||||
|
INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID
|
||||||
|
INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID
|
||||||
|
LEFT JOIN dbo.Books b ON b.BookID = cw.BookID
|
||||||
|
LEFT JOIN dbo.Chapters c ON c.ChapterID = cw.ChapterID
|
||||||
|
LEFT JOIN dbo.Scenes s ON s.SceneID = cw.SceneID
|
||||||
|
WHERE cw.ProjectID = @ProjectID
|
||||||
|
AND cw.IsDismissed = 0
|
||||||
|
AND cw.IsIntentional = 0
|
||||||
|
ORDER BY ws.SortOrder DESC, cw.LastDetectedDate DESC, cw.ContinuityWarningID DESC;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingPlan_ListForManagement
|
||||||
|
@UserID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT wp.WritingPlanID, wp.UserID, wp.ProjectID, p.ProjectName, wp.BookID, b.BookTitle, b.Subtitle AS BookSubtitle,
|
||||||
|
wp.PlanName, wp.GoalType, wp.StartDate, wp.DeadlineDate, wp.AvailableDaysJson, wp.SessionLengthMinutes, wp.IsActive,
|
||||||
|
SUM(CASE WHEN wsi.ScheduleStatus = N'Planned' THEN 1 ELSE 0 END) AS PlannedTaskCount,
|
||||||
|
MAX(CASE WHEN wsi.ScheduleStatus = N'Planned' THEN wsi.ScheduledDate ELSE NULL END) AS ProjectedFinishDate
|
||||||
|
FROM dbo.WritingPlans wp
|
||||||
|
INNER JOIN dbo.Projects p ON p.ProjectID = wp.ProjectID
|
||||||
|
LEFT JOIN dbo.Books b ON b.BookID = wp.BookID
|
||||||
|
LEFT JOIN dbo.WritingScheduleItems wsi ON wsi.WritingPlanID = wp.WritingPlanID
|
||||||
|
WHERE wp.UserID = @UserID
|
||||||
|
GROUP BY wp.WritingPlanID, wp.UserID, wp.ProjectID, p.ProjectName, wp.BookID, b.BookTitle, b.Subtitle,
|
||||||
|
wp.PlanName, wp.GoalType, wp.StartDate, wp.DeadlineDate, wp.AvailableDaysJson, wp.SessionLengthMinutes, wp.IsActive
|
||||||
|
ORDER BY wp.IsActive DESC, wp.DeadlineDate, wp.PlanName, wp.WritingPlanID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingScheduleScene_ListForPlanning
|
||||||
|
@ProjectID int,
|
||||||
|
@BookID int = NULL,
|
||||||
|
@IncludeBlockedScenes bit = 0
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT s.SceneID, rs.StatusName AS RevisionStatusName, sw.EstimatedWordCount, sw.Priority,
|
||||||
|
COALESCE(sw.IsBlocked, 0) AS IsBlocked, b.SortOrder AS BookSortOrder,
|
||||||
|
c.SortOrder AS ChapterSortOrder, s.SortOrder AS SceneSortOrder
|
||||||
|
FROM dbo.Projects p
|
||||||
|
INNER JOIN dbo.Books b ON b.ProjectID = p.ProjectID AND b.IsArchived = 0
|
||||||
|
INNER JOIN dbo.Chapters c ON c.BookID = b.BookID AND c.IsArchived = 0
|
||||||
|
INNER JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID AND s.IsArchived = 0
|
||||||
|
INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
|
||||||
|
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
||||||
|
WHERE p.ProjectID = @ProjectID
|
||||||
|
AND p.IsArchived = 0
|
||||||
|
AND (@BookID IS NULL OR b.BookID = @BookID)
|
||||||
|
AND rs.StatusName IN (N'Outlined', N'Needs Work', N'Revised')
|
||||||
|
AND (@IncludeBlockedScenes = 1 OR COALESCE(sw.IsBlocked, 0) = 0)
|
||||||
|
ORDER BY COALESCE(sw.Priority, 0) DESC, b.SortOrder, c.SortOrder, s.SortOrder, s.SceneID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingScheduleItem_DeleteByPlan
|
||||||
|
@WritingPlanID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
DELETE FROM dbo.WritingScheduleItems
|
||||||
|
WHERE WritingPlanID = @WritingPlanID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingPlanSummary_ListByUser
|
||||||
|
@UserID int,
|
||||||
|
@ProjectID int = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT wp.WritingPlanID, wp.UserID, wp.ProjectID, p.ProjectName, wp.BookID, b.BookTitle, b.Subtitle AS BookSubtitle,
|
||||||
|
wp.PlanName, wp.DeadlineDate, wp.IsActive
|
||||||
|
FROM dbo.WritingPlans wp
|
||||||
|
INNER JOIN dbo.Projects p ON p.ProjectID = wp.ProjectID
|
||||||
|
LEFT JOIN dbo.Books b ON b.BookID = wp.BookID
|
||||||
|
WHERE wp.UserID = @UserID
|
||||||
|
AND (@ProjectID IS NULL OR wp.ProjectID = @ProjectID)
|
||||||
|
ORDER BY wp.IsActive DESC, wp.DeadlineDate, wp.PlanName, wp.WritingPlanID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingSchedulePreview_ListByPlan
|
||||||
|
@WritingPlanID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT wsi.WritingScheduleItemID, wsi.WritingPlanID, wsi.SceneID, wsi.ScheduledDate, wsi.TaskType,
|
||||||
|
b.BookTitle, b.Subtitle AS BookSubtitle, c.ChapterNumber, c.ChapterTitle, s.SceneNumber, s.SceneTitle,
|
||||||
|
sw.Priority, wsi.EstimatedMinutes, wsi.TargetWords, wsi.ScheduleStatus, wsi.Notes,
|
||||||
|
COALESCE(sw.IsBlocked, 0) AS IsBlocked
|
||||||
|
FROM dbo.WritingScheduleItems wsi
|
||||||
|
INNER JOIN dbo.Scenes s ON s.SceneID = wsi.SceneID
|
||||||
|
INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
|
||||||
|
INNER JOIN dbo.Books b ON b.BookID = c.BookID
|
||||||
|
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
||||||
|
WHERE wsi.WritingPlanID = @WritingPlanID
|
||||||
|
ORDER BY wsi.ScheduledDate, wsi.WritingScheduleItemID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingScheduleDashboard_ListActive
|
||||||
|
@UserID int,
|
||||||
|
@ProjectID int = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT wsi.WritingScheduleItemID, wsi.WritingPlanID, wp.PlanName, wsi.SceneID, wsi.ScheduledDate, wsi.TaskType,
|
||||||
|
b.BookTitle, b.Subtitle AS BookSubtitle, c.ChapterNumber, c.ChapterTitle, c.SortOrder AS ChapterSortOrder,
|
||||||
|
s.SceneNumber, s.SceneTitle, s.SortOrder AS SceneSortOrder, sw.Priority, wsi.EstimatedMinutes,
|
||||||
|
wsi.TargetWords, wsi.ScheduleStatus, COALESCE(sw.IsBlocked, 0) AS IsBlocked
|
||||||
|
FROM dbo.WritingPlans wp
|
||||||
|
INNER JOIN dbo.WritingScheduleItems wsi ON wsi.WritingPlanID = wp.WritingPlanID
|
||||||
|
INNER JOIN dbo.Scenes s ON s.SceneID = wsi.SceneID
|
||||||
|
INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
|
||||||
|
INNER JOIN dbo.Books b ON b.BookID = c.BookID
|
||||||
|
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
||||||
|
WHERE wp.UserID = @UserID
|
||||||
|
AND wp.IsActive = 1
|
||||||
|
AND (@ProjectID IS NULL OR wp.ProjectID = @ProjectID)
|
||||||
|
ORDER BY wsi.ScheduledDate, wsi.WritingScheduleItemID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingScheduleItem_UpdatePlannedStatusForUser
|
||||||
|
@WritingScheduleItemID int,
|
||||||
|
@UserID int,
|
||||||
|
@ScheduleStatus nvarchar(50),
|
||||||
|
@CompletedDateUtc datetime2 = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
UPDATE wsi
|
||||||
|
SET ScheduleStatus = @ScheduleStatus,
|
||||||
|
CompletedDateUtc = @CompletedDateUtc,
|
||||||
|
ModifiedDateUtc = SYSUTCDATETIME()
|
||||||
|
FROM dbo.WritingScheduleItems wsi
|
||||||
|
INNER JOIN dbo.WritingPlans wp ON wp.WritingPlanID = wsi.WritingPlanID
|
||||||
|
WHERE wsi.WritingScheduleItemID = @WritingScheduleItemID
|
||||||
|
AND wp.UserID = @UserID
|
||||||
|
AND wp.IsActive = 1
|
||||||
|
AND wsi.ScheduleStatus = N'Planned';
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingPlanSummary_ListRequiringRebalance
|
||||||
|
@UserID int,
|
||||||
|
@Today date,
|
||||||
|
@ProjectID int = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT wp.WritingPlanID, wp.UserID, wp.ProjectID, p.ProjectName, wp.BookID, b.BookTitle, b.Subtitle AS BookSubtitle,
|
||||||
|
wp.PlanName, wp.DeadlineDate, wp.IsActive
|
||||||
|
FROM dbo.WritingPlans wp
|
||||||
|
INNER JOIN dbo.Projects p ON p.ProjectID = wp.ProjectID
|
||||||
|
LEFT JOIN dbo.Books b ON b.BookID = wp.BookID
|
||||||
|
WHERE wp.UserID = @UserID
|
||||||
|
AND wp.IsActive = 1
|
||||||
|
AND (@ProjectID IS NULL OR wp.ProjectID = @ProjectID)
|
||||||
|
AND EXISTS
|
||||||
|
(
|
||||||
|
SELECT 1
|
||||||
|
FROM dbo.WritingScheduleItems wsi
|
||||||
|
WHERE wsi.WritingPlanID = wp.WritingPlanID
|
||||||
|
AND wsi.ScheduleStatus = N'Planned'
|
||||||
|
AND wsi.ScheduledDate < @Today
|
||||||
|
)
|
||||||
|
ORDER BY wp.DeadlineDate, wp.PlanName, wp.WritingPlanID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.WritingScheduleItem_UpdatePlannedDate
|
||||||
|
@WritingPlanID int,
|
||||||
|
@WritingScheduleItemID int,
|
||||||
|
@ScheduledDate date
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
UPDATE dbo.WritingScheduleItems
|
||||||
|
SET ScheduledDate = @ScheduledDate,
|
||||||
|
ModifiedDateUtc = SYSUTCDATETIME()
|
||||||
|
WHERE WritingPlanID = @WritingPlanID
|
||||||
|
AND WritingScheduleItemID = @WritingScheduleItemID
|
||||||
|
AND ScheduleStatus = N'Planned';
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ProjectDashboard_Metrics
|
||||||
|
@ProjectID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
(SELECT COUNT(1) FROM dbo.Characters WHERE ProjectID = @ProjectID AND IsArchived = 0) AS CharacterCount,
|
||||||
|
(SELECT COUNT(1) FROM dbo.Locations WHERE ProjectID = @ProjectID AND IsArchived = 0) AS LocationCount,
|
||||||
|
(
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM dbo.PlotThreads pt
|
||||||
|
INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
|
||||||
|
INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
|
||||||
|
WHERE pl.ProjectID = @ProjectID
|
||||||
|
AND pl.IsArchived = 0
|
||||||
|
AND pt.IsArchived = 0
|
||||||
|
AND ts.IsOpenStatus = 1
|
||||||
|
) AS ActivePlotThreadCount,
|
||||||
|
(
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM dbo.ContinuityWarnings
|
||||||
|
WHERE ProjectID = @ProjectID
|
||||||
|
AND IsDismissed = 0
|
||||||
|
AND IsIntentional = 0
|
||||||
|
) AS ContinuityWarningCount;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ProjectDashboard_AttentionThreads
|
||||||
|
@ProjectID int,
|
||||||
|
@Count int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT TOP (@Count) pt.PlotThreadID, pt.ThreadTitle, pt.PlotLineID, pl.PlotLineName,
|
||||||
|
pt.Importance, ts.StatusName AS ThreadStatusName, ts.IsOpenStatus, ts.IsResolvedStatus
|
||||||
|
FROM dbo.PlotThreads pt
|
||||||
|
INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
|
||||||
|
INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
|
||||||
|
WHERE pl.ProjectID = @ProjectID
|
||||||
|
AND pl.IsArchived = 0
|
||||||
|
AND pt.IsArchived = 0
|
||||||
|
AND (ts.StatusName = N'Dormant' OR (ts.IsOpenStatus = 1 AND pt.Importance >= 8))
|
||||||
|
ORDER BY CASE WHEN ts.StatusName = N'Dormant' THEN 0 ELSE 1 END,
|
||||||
|
pt.Importance DESC, pt.UpdatedDate DESC, pt.PlotThreadID DESC;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ProjectActivity_ListRecent
|
||||||
|
@ProjectID int,
|
||||||
|
@Count int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT TOP (@Count) pa.ProjectActivityID, pa.ProjectID, pa.UserID, u.DisplayName, u.Email,
|
||||||
|
pa.ActivityType, pa.EntityType, pa.EntityID, pa.EntityName, pa.Description, pa.CreatedDateUTC
|
||||||
|
FROM dbo.ProjectActivity pa
|
||||||
|
LEFT JOIN dbo.AppUser u ON u.UserID = pa.UserID
|
||||||
|
WHERE pa.ProjectID = @ProjectID
|
||||||
|
ORDER BY pa.CreatedDateUTC DESC, pa.ProjectActivityID DESC;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Book_ListByProjects
|
||||||
|
@ProjectIDs nvarchar(max)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
;WITH ProjectIDs AS
|
||||||
|
(
|
||||||
|
SELECT DISTINCT TRY_CONVERT(int, value) AS ProjectID
|
||||||
|
FROM STRING_SPLIT(COALESCE(@ProjectIDs, N''), N',')
|
||||||
|
WHERE TRY_CONVERT(int, value) IS NOT NULL
|
||||||
|
)
|
||||||
|
SELECT b.BookID, b.ProjectID, b.BookTitle, b.Subtitle, b.Tagline, b.ShortDescription, b.Status, b.BookNumber,
|
||||||
|
b.Description, b.TargetWordCount, b.WritingStartDate, b.TargetCompletionDate, b.PublicationDate,
|
||||||
|
b.CoverThumbnailPath, b.CoverStandardPath, ISNULL(wordCounts.CurrentWordCount, 0) AS CurrentWordCount,
|
||||||
|
ISNULL(counts.ChapterCount, 0) AS ChapterCount, ISNULL(counts.SceneCount, 0) AS SceneCount,
|
||||||
|
b.SortOrder, b.CreatedDate, b.UpdatedDate, b.IsArchived, b.ArchivedDate, b.ArchivedReason
|
||||||
|
FROM dbo.Books b
|
||||||
|
INNER JOIN ProjectIDs ids ON ids.ProjectID = b.ProjectID
|
||||||
|
OUTER APPLY
|
||||||
|
(
|
||||||
|
SELECT COUNT(DISTINCT c.ChapterID) AS ChapterCount, COUNT(s.SceneID) AS SceneCount
|
||||||
|
FROM dbo.Chapters c
|
||||||
|
LEFT JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID AND s.IsArchived = 0
|
||||||
|
WHERE c.BookID = b.BookID AND c.IsArchived = 0
|
||||||
|
) counts
|
||||||
|
OUTER APPLY
|
||||||
|
(
|
||||||
|
SELECT SUM(ISNULL(sw.ActualWordCount, 0)) AS CurrentWordCount
|
||||||
|
FROM dbo.Chapters c
|
||||||
|
INNER JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID AND s.IsArchived = 0
|
||||||
|
LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID
|
||||||
|
WHERE c.BookID = b.BookID AND c.IsArchived = 0
|
||||||
|
) wordCounts
|
||||||
|
WHERE b.IsArchived = 0
|
||||||
|
ORDER BY b.ProjectID, b.SortOrder, b.BookNumber, b.BookTitle;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.Book_GetCoverPaths
|
||||||
|
@BookID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT BookID, ProjectID, CoverThumbnailPath, CoverStandardPath
|
||||||
|
FROM dbo.Books
|
||||||
|
WHERE BookID = @BookID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ThreadEventTarget_ListByEvents
|
||||||
|
@ThreadEventIDs nvarchar(max)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
;WITH ThreadEventIDs AS
|
||||||
|
(
|
||||||
|
SELECT DISTINCT TRY_CONVERT(int, value) AS ThreadEventID
|
||||||
|
FROM STRING_SPLIT(COALESCE(@ThreadEventIDs, N''), N',')
|
||||||
|
WHERE TRY_CONVERT(int, value) IS NOT NULL
|
||||||
|
)
|
||||||
|
SELECT petpl.PlotEventID, petpl.PlotLineID
|
||||||
|
FROM dbo.PlotEventTargetPlotLines petpl
|
||||||
|
INNER JOIN ThreadEventIDs ids ON ids.ThreadEventID = petpl.PlotEventID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.ThreadEventTarget_SaveForEvent
|
||||||
|
@ThreadEventID int,
|
||||||
|
@PlotLineIDs nvarchar(max) = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
DELETE FROM dbo.PlotEventTargetPlotLines
|
||||||
|
WHERE PlotEventID = @ThreadEventID;
|
||||||
|
|
||||||
|
;WITH PlotLineIDs AS
|
||||||
|
(
|
||||||
|
SELECT DISTINCT TRY_CONVERT(int, value) AS PlotLineID
|
||||||
|
FROM STRING_SPLIT(COALESCE(@PlotLineIDs, N''), N',')
|
||||||
|
WHERE TRY_CONVERT(int, value) IS NOT NULL
|
||||||
|
AND TRY_CONVERT(int, value) > 0
|
||||||
|
)
|
||||||
|
INSERT dbo.PlotEventTargetPlotLines (PlotEventID, PlotLineID)
|
||||||
|
SELECT @ThreadEventID, PlotLineID
|
||||||
|
FROM PlotLineIDs;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.AssetCustodyCharacter_ListByProject
|
||||||
|
@ProjectID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT acec.AssetCustodyEventID, ace.StoryAssetID, ace.SceneID, acec.CharacterID, c.CharacterName,
|
||||||
|
acec.CharacterNameText, cr.RoleName, ace.UpdatedDate
|
||||||
|
FROM dbo.AssetCustodyEventCharacters acec
|
||||||
|
INNER JOIN dbo.AssetCustodyEvents ace ON ace.AssetCustodyEventID = acec.AssetCustodyEventID
|
||||||
|
INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ace.StoryAssetID
|
||||||
|
LEFT JOIN dbo.Characters c ON c.CharacterID = acec.CharacterID
|
||||||
|
LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = acec.CustodyRoleID
|
||||||
|
WHERE sa.ProjectID = @ProjectID
|
||||||
|
AND sa.IsArchived = 0
|
||||||
|
AND acec.CharacterID IS NOT NULL
|
||||||
|
AND NULLIF(LTRIM(RTRIM(c.CharacterName)), N'') IS NOT NULL;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.AssetCustodySummary_ListByEvents
|
||||||
|
@AssetCustodyEventIDs nvarchar(max)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
;WITH AssetCustodyEventIDs AS
|
||||||
|
(
|
||||||
|
SELECT DISTINCT TRY_CONVERT(int, value) AS AssetCustodyEventID
|
||||||
|
FROM STRING_SPLIT(COALESCE(@AssetCustodyEventIDs, N''), N',')
|
||||||
|
WHERE TRY_CONVERT(int, value) IS NOT NULL
|
||||||
|
)
|
||||||
|
SELECT acec.AssetCustodyEventID, c.CharacterName, cr.RoleName
|
||||||
|
FROM dbo.AssetCustodyEventCharacters acec
|
||||||
|
INNER JOIN AssetCustodyEventIDs ids ON ids.AssetCustodyEventID = acec.AssetCustodyEventID
|
||||||
|
INNER JOIN dbo.Characters c ON c.CharacterID = acec.CharacterID
|
||||||
|
LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = acec.CustodyRoleID
|
||||||
|
WHERE acec.CharacterID IS NOT NULL
|
||||||
|
AND NULLIF(LTRIM(RTRIM(c.CharacterName)), N'') IS NOT NULL;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.CharacterSexValue_ListForOwner
|
||||||
|
@OwnerUserID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT CharacterSexValueID, OwnerUserID, SexName, IsSystem, SortOrder, IsActive
|
||||||
|
FROM dbo.CharacterSexValues
|
||||||
|
WHERE IsActive = 1
|
||||||
|
AND (IsSystem = 1 OR OwnerUserID = @OwnerUserID)
|
||||||
|
ORDER BY IsSystem DESC, SortOrder, SexName;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.CharacterSexValue_Get
|
||||||
|
@CharacterSexValueID int,
|
||||||
|
@OwnerUserID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT CharacterSexValueID, OwnerUserID, SexName, IsSystem, SortOrder, IsActive
|
||||||
|
FROM dbo.CharacterSexValues
|
||||||
|
WHERE CharacterSexValueID = @CharacterSexValueID
|
||||||
|
AND IsActive = 1
|
||||||
|
AND (IsSystem = 1 OR OwnerUserID = @OwnerUserID);
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.CharacterImage_ListByCharacter
|
||||||
|
@CharacterID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT CharacterImageID, CharacterID, ProjectID, ImagePath, ThumbnailPath, Caption, SortOrder, UploadedDateUTC, IsDeleted
|
||||||
|
FROM dbo.CharacterImages
|
||||||
|
WHERE CharacterID = @CharacterID
|
||||||
|
AND IsDeleted = 0
|
||||||
|
ORDER BY SortOrder, UploadedDateUTC, CharacterImageID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.CharacterImage_Get
|
||||||
|
@CharacterImageID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT CharacterImageID, CharacterID, ProjectID, ImagePath, ThumbnailPath, Caption, SortOrder, UploadedDateUTC, IsDeleted
|
||||||
|
FROM dbo.CharacterImages
|
||||||
|
WHERE CharacterImageID = @CharacterImageID
|
||||||
|
AND IsDeleted = 0;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.CharacterImage_Create
|
||||||
|
@CharacterID int,
|
||||||
|
@ProjectID int,
|
||||||
|
@ImagePath nvarchar(500),
|
||||||
|
@ThumbnailPath nvarchar(500) = NULL,
|
||||||
|
@Caption nvarchar(500) = NULL,
|
||||||
|
@InputSortOrder int = NULL
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
DECLARE @SortOrder int = COALESCE(@InputSortOrder, (SELECT ISNULL(MAX(SortOrder), 0) + 1 FROM dbo.CharacterImages WHERE CharacterID = @CharacterID));
|
||||||
|
|
||||||
|
INSERT dbo.CharacterImages (CharacterID, ProjectID, ImagePath, ThumbnailPath, Caption, SortOrder)
|
||||||
|
VALUES (@CharacterID, @ProjectID, @ImagePath, @ThumbnailPath, @Caption, @SortOrder);
|
||||||
|
|
||||||
|
SELECT CAST(SCOPE_IDENTITY() AS int);
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.CharacterImage_Delete
|
||||||
|
@CharacterImageID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
UPDATE dbo.CharacterImages
|
||||||
|
SET IsDeleted = 1,
|
||||||
|
DeletedDateUTC = SYSUTCDATETIME()
|
||||||
|
WHERE CharacterImageID = @CharacterImageID;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
Loading…
x
Reference in New Issue
Block a user