-- Write SQL scripts that:
-- a. modify the type of a column;
-- b. add / remove a column;
-- c. add / remove a DEFAULT constraint;
-- d. add / remove a primary key;
-- e. add / remove a candidate key;
-- f. add / remove a foreign key;
-- g. create / drop a table.

-- For each of the scripts above, write another one that reverts the operation. Place each script in a stored procedure. Use a simple, intuitive naming convention.

-- a. modify the type of a column;

CREATE PROCEDURE setNameToVarChar100
AS
BEGIN
    ALTER TABLE Decks
    ALTER COLUMN name VARCHAR(100)
END

GO

CREATE PROCEDURE setNameToVarChar255
AS
BEGIN
    ALTER TABLE Decks
    ALTER COLUMN name VARCHAR(255)
END

GO
-- b. add / remove a column;

CREATE PROCEDURE addColumnDescription
AS
BEGIN
    ALTER TABLE Decks
    ADD description VARCHAR(255)
END

GO

CREATE PROCEDURE removeColumnDescription
AS
BEGIN
    ALTER TABLE Decks
    DROP COLUMN description
END

GO
-- c. add / remove a DEFAULT constraint;

CREATE PROCEDURE addDefaultToDescription
AS
BEGIN
    ALTER TABLE Decks
    ADD CONSTRAINT DF_Decks_description DEFAULT 'No description' FOR description
END

GO

CREATE PROCEDURE removeDefaultFromDescription
AS
BEGIN
    ALTER TABLE Decks
    DROP CONSTRAINT DF_Decks_description
END

GO

-- d. add / remove a primary key;

CREATE PROCEDURE removePrimaryKeyFromJournalProgress
AS
BEGIN
    ALTER TABLE JourneyProgress
    DROP CONSTRAINT PK__JourneyP__2FA1EA2E0A91C8BD
END

GO

CREATE PROCEDURE addPrimaryKeyToJournalProgress
AS
BEGIN
    ALTER TABLE JourneyProgress
    ADD CONSTRAINT PK__JourneyP__2FA1EA2E0A91C8BD PRIMARY KEY(hJourney, hPlayer)
END

GO

-- e. add / remove a candidate key;

CREATE PROCEDURE addCandidateKeyToDecks
AS
BEGIN
    ALTER TABLE Decks
    ADD CONSTRAINT CK_Decks_name UNIQUE(name)
END

GO

CREATE PROCEDURE removeCandidateKeyFromDecks
AS
BEGIN
    ALTER TABLE Decks
    DROP CONSTRAINT CK_Decks_name
END

GO

-- f. add / remove a foreign key;

CREATE PROCEDURE removeForeignKeyFromJourneyProgress
AS
BEGIN
    ALTER TABLE JourneyProgress
    DROP CONSTRAINT  FK__JourneyPr__hPlay__031C6FA4 
END

GO

CREATE PROCEDURE addForeignKeyToJourneyProgress
AS
BEGIN
    ALTER TABLE JourneyProgress
    ADD CONSTRAINT FK__JourneyPr__hPlay__031C6FA4 FOREIGN KEY(hPlayer) REFERENCES Players(hmy)
END

GO

-- g. create / drop a table.

CREATE PROCEDURE createTableSkillTree
AS
BEGIN
    CREATE TABLE SkillTree(
        hmy INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        description VARCHAR(8000) NOT NULL,
        hFaction INT NOT NULL references Factions(hmy),
        hPlayer INT NOT NULL references Players(hmy),
    )
END

GO

CREATE PROCEDURE dropTableSkillTree
AS
BEGIN
    DROP TABLE SkillTree
END

GO

CREATE TABLE versionTable(
    version INT NOT NULL
)

CREATE TABLE proceduresTable(
    fromVersion INT NOT NULL,
    toVersion INT NOT NULL,
    procedureName VARCHAR(255) NOT NULL
    PRIMARY KEY(fromVersion, toVersion)
)

INSERT INTO versionTable(version) VALUES(1)

INSERT INTO proceduresTable(fromVersion, toVersion, procedureName) 
VALUES
(1, 2, 'setNameToVarChar100'),
(2, 1, 'setNameToVarChar255'),
(2, 3, 'addColumnDescription'),
(3, 2, 'removeColumnDescription'),
(3, 4, 'addDefaultToDescription'),
(4, 3, 'removeDefaultFromDescription'),
(4, 5, 'removePrimaryKeyFromJournalProgress'),
(5, 4, 'addPrimaryKeyToJournalProgress'),
(5, 6, 'addCandidateKeyToDecks'),
(6, 5, 'removeCandidateKeyFromDecks'),
(6, 7, 'removeForeignKeyFromJourneyProgress'),
(7, 6, 'addForeignKeyToJourneyProgress'),
(7, 8, 'createTableSkillTree'),
(8, 7, 'dropTableSkillTree')

GO

CREATE PROCEDURE VersionSelector(@newVersion int)
AS
BEGIN TRANSACTION versionControl
BEGIN TRY
    DECLARE @currentVersion int
    DECLARE @procedureName VARCHAR(255)
    SET @currentVersion = (SELECT version FROM versionTable)
    IF @newVersion > (SELECT MAX(toVersion) FROM proceduresTable)
        RAISERROR('Invalid version', 16, 1)
    IF @newVersion < (SELECT MIN(toVersion) FROM proceduresTable)
        RAISERROR('Invalid version', 16, 1)
    WHILE @currentVersion > @newVersion
    BEGIN
        SET @procedureName = (SELECT procedureName FROM proceduresTable WHERE fromVersion = @currentVersion AND toVersion = @currentVersion - 1)
        EXEC @procedureName
        SET @currentVersion = @currentVersion - 1
    END
    WHILE @currentVersion < @newVersion
    BEGIN
        SET @procedureName = (SELECT procedureName FROM proceduresTable WHERE fromVersion = @currentVersion AND toVersion = @currentVersion + 1)
        EXEC @procedureName
        SET @currentVersion = @currentVersion + 1
    END
    UPDATE versionTable SET version = @newVersion
    COMMIT TRANSACTION versionControl
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION versionControl
    PRINT ERROR_PROCEDURE()
    PRINT ERROR_MESSAGE()
END CATCH

EXECUTE VersionSelector 1