292 lines
9.5 KiB
Transact-SQL
292 lines
9.5 KiB
Transact-SQL
USE [RobotInstaller];
|
|
GO
|
|
|
|
SET ANSI_NULLS ON;
|
|
SET QUOTED_IDENTIFIER ON;
|
|
GO
|
|
|
|
IF OBJECT_ID(N'dbo.ApplicationPackages', N'U') IS NOT NULL
|
|
OR OBJECT_ID(N'dbo.PackageVersions', N'U') IS NOT NULL
|
|
OR OBJECT_ID(N'dbo.Applications', N'U') IS NOT NULL
|
|
OR OBJECT_ID(N'dbo.Packages', N'U') IS NOT NULL
|
|
OR OBJECT_ID(N'dbo.EmailConfirmationTokens', N'U') IS NOT NULL
|
|
OR OBJECT_ID(N'dbo.Users', N'U') IS NOT NULL
|
|
BEGIN
|
|
THROW 50001, 'Schema tables already exist. Review, drop, or migrate existing tables before running 02_schema.sql.', 1;
|
|
END;
|
|
GO
|
|
|
|
CREATE TABLE dbo.Users
|
|
(
|
|
Id UNIQUEIDENTIFIER NOT NULL
|
|
CONSTRAINT PK_Users PRIMARY KEY CLUSTERED
|
|
CONSTRAINT DF_Users_Id DEFAULT NEWSEQUENTIALID(),
|
|
Username NVARCHAR(100) NOT NULL,
|
|
Email NVARCHAR(255) NOT NULL,
|
|
PasswordHash NVARCHAR(500) NOT NULL,
|
|
FullName NVARCHAR(200) NULL,
|
|
Role NVARCHAR(50) NOT NULL
|
|
CONSTRAINT DF_Users_Role DEFAULT N'User',
|
|
IsActive BIT NOT NULL
|
|
CONSTRAINT DF_Users_IsActive DEFAULT 1,
|
|
CreatedAt DATETIME2(3) NOT NULL
|
|
CONSTRAINT DF_Users_CreatedAt DEFAULT SYSUTCDATETIME(),
|
|
UpdatedAt DATETIME2(3) NULL,
|
|
CONSTRAINT CK_Users_Role CHECK (Role IN (N'Admin', N'User')),
|
|
CONSTRAINT CK_Users_Username_NotBlank CHECK (LEN(LTRIM(RTRIM(Username))) > 0),
|
|
CONSTRAINT CK_Users_Email_NotBlank CHECK (LEN(LTRIM(RTRIM(Email))) > 0)
|
|
);
|
|
GO
|
|
|
|
CREATE TABLE dbo.EmailConfirmationTokens
|
|
(
|
|
Id UNIQUEIDENTIFIER NOT NULL
|
|
CONSTRAINT PK_EmailConfirmationTokens PRIMARY KEY CLUSTERED
|
|
CONSTRAINT DF_EmailConfirmationTokens_Id DEFAULT NEWSEQUENTIALID(),
|
|
UserId UNIQUEIDENTIFIER NOT NULL,
|
|
TokenHash CHAR(64) NOT NULL,
|
|
ExpiresAt DATETIME2(3) NOT NULL,
|
|
ConfirmedAt DATETIME2(3) NULL,
|
|
CreatedAt DATETIME2(3) NOT NULL
|
|
CONSTRAINT DF_EmailConfirmationTokens_CreatedAt DEFAULT SYSUTCDATETIME(),
|
|
CONSTRAINT FK_EmailConfirmationTokens_User
|
|
FOREIGN KEY (UserId) REFERENCES dbo.Users(Id) ON DELETE CASCADE
|
|
);
|
|
GO
|
|
|
|
CREATE TABLE dbo.Packages
|
|
(
|
|
Id UNIQUEIDENTIFIER NOT NULL
|
|
CONSTRAINT PK_Packages PRIMARY KEY CLUSTERED
|
|
CONSTRAINT DF_Packages_Id DEFAULT NEWSEQUENTIALID(),
|
|
PackageCode NVARCHAR(100) NOT NULL,
|
|
PackageName NVARCHAR(200) NOT NULL,
|
|
PackageType NVARCHAR(20) NOT NULL,
|
|
Description NVARCHAR(MAX) NULL,
|
|
CreatedByUserId UNIQUEIDENTIFIER NOT NULL,
|
|
CreatedAt DATETIME2(3) NOT NULL
|
|
CONSTRAINT DF_Packages_CreatedAt DEFAULT SYSUTCDATETIME(),
|
|
UpdatedAt DATETIME2(3) NULL,
|
|
IsActive BIT NOT NULL
|
|
CONSTRAINT DF_Packages_IsActive DEFAULT 1,
|
|
CONSTRAINT FK_Packages_CreatedByUser
|
|
FOREIGN KEY (CreatedByUserId) REFERENCES dbo.Users(Id),
|
|
CONSTRAINT CK_Packages_PackageType CHECK (PackageType IN (N'deb', N'docker')),
|
|
CONSTRAINT CK_Packages_PackageCode_NotBlank CHECK (LEN(LTRIM(RTRIM(PackageCode))) > 0),
|
|
CONSTRAINT CK_Packages_PackageName_NotBlank CHECK (LEN(LTRIM(RTRIM(PackageName))) > 0)
|
|
);
|
|
GO
|
|
|
|
CREATE TABLE dbo.PackageVersions
|
|
(
|
|
Id UNIQUEIDENTIFIER NOT NULL
|
|
CONSTRAINT PK_PackageVersions PRIMARY KEY CLUSTERED
|
|
CONSTRAINT DF_PackageVersions_Id DEFAULT NEWSEQUENTIALID(),
|
|
PackageId UNIQUEIDENTIFIER NOT NULL,
|
|
Version NVARCHAR(50) NOT NULL,
|
|
FilePath NVARCHAR(1000) NULL,
|
|
DockerImage NVARCHAR(500) NULL,
|
|
FileChecksumSha256 CHAR(64) NULL,
|
|
FileSizeBytes BIGINT NULL,
|
|
ChangeLog NVARCHAR(MAX) NULL,
|
|
ReleaseDate DATETIME2(3) NOT NULL
|
|
CONSTRAINT DF_PackageVersions_ReleaseDate DEFAULT SYSUTCDATETIME(),
|
|
UploadedAt DATETIME2(3) NOT NULL
|
|
CONSTRAINT DF_PackageVersions_UploadedAt DEFAULT SYSUTCDATETIME(),
|
|
IsLatest BIT NOT NULL
|
|
CONSTRAINT DF_PackageVersions_IsLatest DEFAULT 0,
|
|
IsDeprecated BIT NOT NULL
|
|
CONSTRAINT DF_PackageVersions_IsDeprecated DEFAULT 0,
|
|
CONSTRAINT FK_PackageVersions_Package
|
|
FOREIGN KEY (PackageId) REFERENCES dbo.Packages(Id) ON DELETE CASCADE,
|
|
CONSTRAINT CK_PackageVersions_Version_NotBlank CHECK (LEN(LTRIM(RTRIM(Version))) > 0),
|
|
CONSTRAINT CK_PackageVersions_FileSizeBytes CHECK (FileSizeBytes IS NULL OR FileSizeBytes >= 0),
|
|
CONSTRAINT CK_PackageVersions_FileChecksumSha256 CHECK (
|
|
FileChecksumSha256 IS NULL
|
|
OR FileChecksumSha256 NOT LIKE '%[^0-9A-Fa-f]%'
|
|
)
|
|
);
|
|
GO
|
|
|
|
CREATE TABLE dbo.Applications
|
|
(
|
|
Id UNIQUEIDENTIFIER NOT NULL
|
|
CONSTRAINT PK_Applications PRIMARY KEY CLUSTERED
|
|
CONSTRAINT DF_Applications_Id DEFAULT NEWSEQUENTIALID(),
|
|
AppCode NVARCHAR(100) NOT NULL,
|
|
AppName NVARCHAR(200) NOT NULL,
|
|
AppVersion NVARCHAR(50) NOT NULL
|
|
CONSTRAINT DF_Applications_AppVersion DEFAULT N'1.0.0',
|
|
Description NVARCHAR(MAX) NULL,
|
|
CreatedByUserId UNIQUEIDENTIFIER NOT NULL,
|
|
CreatedAt DATETIME2(3) NOT NULL
|
|
CONSTRAINT DF_Applications_CreatedAt DEFAULT SYSUTCDATETIME(),
|
|
UpdatedAt DATETIME2(3) NULL,
|
|
Status NVARCHAR(50) NOT NULL
|
|
CONSTRAINT DF_Applications_Status DEFAULT N'Draft',
|
|
Notes NVARCHAR(500) NULL,
|
|
CONSTRAINT FK_Applications_CreatedByUser
|
|
FOREIGN KEY (CreatedByUserId) REFERENCES dbo.Users(Id),
|
|
CONSTRAINT CK_Applications_Status CHECK (Status IN (N'Draft', N'Released', N'Archived')),
|
|
CONSTRAINT CK_Applications_AppCode_NotBlank CHECK (LEN(LTRIM(RTRIM(AppCode))) > 0),
|
|
CONSTRAINT CK_Applications_AppName_NotBlank CHECK (LEN(LTRIM(RTRIM(AppName))) > 0),
|
|
CONSTRAINT CK_Applications_AppVersion_NotBlank CHECK (LEN(LTRIM(RTRIM(AppVersion))) > 0)
|
|
);
|
|
GO
|
|
|
|
CREATE TABLE dbo.ApplicationPackages
|
|
(
|
|
Id UNIQUEIDENTIFIER NOT NULL
|
|
CONSTRAINT PK_ApplicationPackages PRIMARY KEY CLUSTERED
|
|
CONSTRAINT DF_ApplicationPackages_Id DEFAULT NEWSEQUENTIALID(),
|
|
ApplicationId UNIQUEIDENTIFIER NOT NULL,
|
|
PackageId UNIQUEIDENTIFIER NOT NULL,
|
|
SelectedVersionId UNIQUEIDENTIFIER NULL,
|
|
AddedAt DATETIME2(3) NOT NULL
|
|
CONSTRAINT DF_ApplicationPackages_AddedAt DEFAULT SYSUTCDATETIME(),
|
|
Notes NVARCHAR(500) NULL,
|
|
CONSTRAINT FK_ApplicationPackages_Application
|
|
FOREIGN KEY (ApplicationId) REFERENCES dbo.Applications(Id) ON DELETE CASCADE,
|
|
CONSTRAINT FK_ApplicationPackages_Package
|
|
FOREIGN KEY (PackageId) REFERENCES dbo.Packages(Id) ON DELETE CASCADE
|
|
);
|
|
GO
|
|
|
|
CREATE UNIQUE INDEX UX_Users_Username ON dbo.Users(Username);
|
|
CREATE UNIQUE INDEX UX_Users_Email ON dbo.Users(Email);
|
|
GO
|
|
|
|
CREATE UNIQUE INDEX UX_EmailConfirmationTokens_TokenHash
|
|
ON dbo.EmailConfirmationTokens(TokenHash);
|
|
|
|
CREATE INDEX IX_EmailConfirmationTokens_UserId
|
|
ON dbo.EmailConfirmationTokens(UserId);
|
|
GO
|
|
|
|
CREATE UNIQUE INDEX UX_Packages_PackageCode ON dbo.Packages(PackageCode);
|
|
CREATE INDEX IX_Packages_CreatedByUserId ON dbo.Packages(CreatedByUserId);
|
|
CREATE INDEX IX_Packages_PackageType ON dbo.Packages(PackageType);
|
|
GO
|
|
|
|
CREATE UNIQUE INDEX UX_PackageVersions_PackageId_Version
|
|
ON dbo.PackageVersions(PackageId, Version);
|
|
|
|
CREATE UNIQUE INDEX UX_PackageVersions_Id_PackageId
|
|
ON dbo.PackageVersions(Id, PackageId);
|
|
|
|
CREATE UNIQUE INDEX UX_PackageVersions_OneLatestPerPackage
|
|
ON dbo.PackageVersions(PackageId)
|
|
WHERE IsLatest = 1;
|
|
|
|
CREATE INDEX IX_PackageVersions_PackageId_ReleaseDate
|
|
ON dbo.PackageVersions(PackageId, ReleaseDate DESC);
|
|
GO
|
|
|
|
CREATE UNIQUE INDEX UX_Applications_AppCode
|
|
ON dbo.Applications(AppCode);
|
|
|
|
CREATE INDEX IX_Applications_CreatedByUserId ON dbo.Applications(CreatedByUserId);
|
|
CREATE INDEX IX_Applications_Status ON dbo.Applications(Status);
|
|
GO
|
|
|
|
CREATE UNIQUE INDEX UX_ApplicationPackages_ApplicationId_PackageId
|
|
ON dbo.ApplicationPackages(ApplicationId, PackageId);
|
|
|
|
CREATE INDEX IX_ApplicationPackages_PackageId
|
|
ON dbo.ApplicationPackages(PackageId);
|
|
|
|
CREATE INDEX IX_ApplicationPackages_SelectedVersionId
|
|
ON dbo.ApplicationPackages(SelectedVersionId);
|
|
GO
|
|
|
|
ALTER TABLE dbo.ApplicationPackages
|
|
ADD CONSTRAINT FK_ApplicationPackages_SelectedVersionBelongsToPackage
|
|
FOREIGN KEY (SelectedVersionId, PackageId)
|
|
REFERENCES dbo.PackageVersions(Id, PackageId);
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.SetLatestPackageVersion
|
|
@PackageVersionId UNIQUEIDENTIFIER
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
SET XACT_ABORT ON;
|
|
|
|
DECLARE @PackageId UNIQUEIDENTIFIER;
|
|
|
|
SELECT @PackageId = PackageId
|
|
FROM dbo.PackageVersions
|
|
WHERE Id = @PackageVersionId;
|
|
|
|
IF @PackageId IS NULL
|
|
BEGIN
|
|
THROW 50002, 'Package version does not exist.', 1;
|
|
END;
|
|
|
|
BEGIN TRANSACTION;
|
|
|
|
UPDATE dbo.PackageVersions
|
|
SET IsLatest = 0
|
|
WHERE PackageId = @PackageId;
|
|
|
|
UPDATE dbo.PackageVersions
|
|
SET IsLatest = 1,
|
|
IsDeprecated = 0
|
|
WHERE Id = @PackageVersionId;
|
|
|
|
COMMIT TRANSACTION;
|
|
END;
|
|
GO
|
|
|
|
CREATE OR ALTER PROCEDURE dbo.DeletePackageVersion
|
|
@PackageVersionId UNIQUEIDENTIFIER
|
|
AS
|
|
BEGIN
|
|
SET NOCOUNT ON;
|
|
SET XACT_ABORT ON;
|
|
|
|
DECLARE @PackageId UNIQUEIDENTIFIER;
|
|
DECLARE @WasLatest BIT;
|
|
|
|
SELECT
|
|
@PackageId = PackageId,
|
|
@WasLatest = IsLatest
|
|
FROM dbo.PackageVersions
|
|
WHERE Id = @PackageVersionId;
|
|
|
|
IF @PackageId IS NULL
|
|
BEGIN
|
|
THROW 50003, 'Package version does not exist.', 1;
|
|
END;
|
|
|
|
BEGIN TRANSACTION;
|
|
|
|
DELETE FROM dbo.ApplicationPackages
|
|
WHERE SelectedVersionId = @PackageVersionId;
|
|
|
|
DELETE FROM dbo.PackageVersions
|
|
WHERE Id = @PackageVersionId;
|
|
|
|
IF @WasLatest = 1
|
|
BEGIN
|
|
DECLARE @NextLatestId UNIQUEIDENTIFIER;
|
|
|
|
SELECT TOP (1) @NextLatestId = Id
|
|
FROM dbo.PackageVersions
|
|
WHERE PackageId = @PackageId
|
|
AND IsDeprecated = 0
|
|
ORDER BY ReleaseDate DESC, UploadedAt DESC;
|
|
|
|
IF @NextLatestId IS NOT NULL
|
|
BEGIN
|
|
EXEC dbo.SetLatestPackageVersion @NextLatestId;
|
|
END;
|
|
END;
|
|
|
|
COMMIT TRANSACTION;
|
|
END;
|
|
GO
|
|
|
|
PRINT N'RobotInstaller schema was created successfully.';
|
|
GO
|