Update stored procs/udf and update docker config

This commit is contained in:
Aaron Po
2025-11-13 10:18:03 +00:00
parent a200164609
commit b86607e37a
16 changed files with 991 additions and 337 deletions

13
.config/dotnet-tools.json Normal file
View File

@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "1.2.1",
"commands": [
"csharpier"
],
"rollForward": false
}
}
}

View File

@@ -1,3 +0,0 @@
{
"dotnet.defaultSolution": "SeedDB.sln"
}

View File

@@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -1,6 +1,3 @@
namespace DataAccessLayer; namespace DataAccessLayer;
public class Class1 public class Class1 { }
{
}

View File

@@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -7,7 +7,7 @@ IF EXISTS (SELECT name
FROM sys.databases FROM sys.databases
WHERE name = N'Biergarten') WHERE name = N'Biergarten')
BEGIN BEGIN
ALTER DATABASE Biergarten SET SINGLE_USER WITH ROLLBACK IMMEDIATE; ALTER DATABASE Biergarten SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
END END
GO GO
@@ -24,34 +24,34 @@ USE Biergarten;
CREATE TABLE UserAccount CREATE TABLE UserAccount
( (
UserAccountID UNIQUEIDENTIFIER UserAccountID UNIQUEIDENTIFIER
CONSTRAINT DF_UserAccountID DEFAULT NEWID(), CONSTRAINT DF_UserAccountID DEFAULT NEWID(),
Username VARCHAR(64) NOT NULL, Username VARCHAR(64) NOT NULL,
FirstName NVARCHAR(128) NOT NULL, FirstName NVARCHAR(128) NOT NULL,
LastName NVARCHAR(128) NOT NULL, LastName NVARCHAR(128) NOT NULL,
Email VARCHAR(128) NOT NULL, Email VARCHAR(128) NOT NULL,
CreatedAt DATETIME NOT NULL CreatedAt DATETIME NOT NULL
CONSTRAINT DF_UserAccount_CreatedAt DEFAULT GETDATE(), CONSTRAINT DF_UserAccount_CreatedAt DEFAULT GETDATE(),
UpdatedAt DATETIME, UpdatedAt DATETIME,
DateOfBirth DATETIME NOT NULL, DateOfBirth DATETIME NOT NULL,
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_UserAccount CONSTRAINT PK_UserAccount
PRIMARY KEY (UserAccountID), PRIMARY KEY (UserAccountID),
CONSTRAINT AK_Username CONSTRAINT AK_Username
UNIQUE (Username), UNIQUE (Username),
CONSTRAINT AK_Email CONSTRAINT AK_Email
UNIQUE (Email), UNIQUE (Email)
); );
@@ -60,167 +60,167 @@ CREATE TABLE UserAccount
CREATE TABLE Photo -- All photos must be linked to a user account, you cannot delete a user account if they have uploaded photos CREATE TABLE Photo -- All photos must be linked to a user account, you cannot delete a user account if they have uploaded photos
( (
PhotoID UNIQUEIDENTIFIER PhotoID UNIQUEIDENTIFIER
CONSTRAINT DF_PhotoID DEFAULT NEWID(), CONSTRAINT DF_PhotoID DEFAULT NEWID(),
Hyperlink NVARCHAR(256), Hyperlink NVARCHAR(256),
-- storage is handled via filesystem or cloud service -- storage is handled via filesystem or cloud service
UploadedByID UNIQUEIDENTIFIER NOT NULL, UploadedByID UNIQUEIDENTIFIER NOT NULL,
UploadedAt DATETIME NOT NULL UploadedAt DATETIME NOT NULL
CONSTRAINT DF_Photo_UploadedAt DEFAULT GETDATE(), CONSTRAINT DF_Photo_UploadedAt DEFAULT GETDATE(),
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_Photo CONSTRAINT PK_Photo
PRIMARY KEY (PhotoID), PRIMARY KEY (PhotoID),
CONSTRAINT FK_Photo_UploadedBy CONSTRAINT FK_Photo_UploadedBy
FOREIGN KEY (UploadedByID) FOREIGN KEY (UploadedByID)
REFERENCES UserAccount(UserAccountID) REFERENCES UserAccount(UserAccountID)
ON DELETE NO ACTION ON DELETE NO ACTION
); );
CREATE NONCLUSTERED INDEX IX_Photo_UploadedByID CREATE NONCLUSTERED INDEX IX_Photo_UploadedByID
ON Photo(UploadedByID); ON Photo(UploadedByID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE UserAvatar -- delete avatar photo when user account is deleted CREATE TABLE UserAvatar -- delete avatar photo when user account is deleted
( (
UserAvatarID UNIQUEIDENTIFIER UserAvatarID UNIQUEIDENTIFIER
CONSTRAINT DF_UserAvatarID DEFAULT NEWID(), CONSTRAINT DF_UserAvatarID DEFAULT NEWID(),
UserAccountID UNIQUEIDENTIFIER NOT NULL, UserAccountID UNIQUEIDENTIFIER NOT NULL,
PhotoID UNIQUEIDENTIFIER NOT NULL, PhotoID UNIQUEIDENTIFIER NOT NULL,
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_UserAvatar PRIMARY KEY (UserAvatarID), CONSTRAINT PK_UserAvatar PRIMARY KEY (UserAvatarID),
CONSTRAINT FK_UserAvatar_UserAccount CONSTRAINT FK_UserAvatar_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount(UserAccountID) REFERENCES UserAccount(UserAccountID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT FK_UserAvatar_PhotoID CONSTRAINT FK_UserAvatar_PhotoID
FOREIGN KEY (PhotoID) FOREIGN KEY (PhotoID)
REFERENCES Photo(PhotoID), REFERENCES Photo(PhotoID),
CONSTRAINT AK_UserAvatar_UserAccountID CONSTRAINT AK_UserAvatar_UserAccountID
UNIQUE (UserAccountID) UNIQUE (UserAccountID)
) )
CREATE NONCLUSTERED INDEX IX_UserAvatar_UserAccount CREATE NONCLUSTERED INDEX IX_UserAvatar_UserAccount
ON UserAvatar(UserAccountID); ON UserAvatar(UserAccountID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE UserVerification -- delete verification data when user account is deleted CREATE TABLE UserVerification -- delete verification data when user account is deleted
( (
UserVerificationID UNIQUEIDENTIFIER UserVerificationID UNIQUEIDENTIFIER
CONSTRAINT DF_UserVerificationID DEFAULT NEWID(), CONSTRAINT DF_UserVerificationID DEFAULT NEWID(),
UserAccountID UNIQUEIDENTIFIER NOT NULL, UserAccountID UNIQUEIDENTIFIER NOT NULL,
VerificationDateTime DATETIME NOT NULL VerificationDateTime DATETIME NOT NULL
CONSTRAINT DF_VerificationDateTime CONSTRAINT DF_VerificationDateTime
DEFAULT GETDATE(), DEFAULT GETDATE(),
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_UserVerification CONSTRAINT PK_UserVerification
PRIMARY KEY (UserVerificationID), PRIMARY KEY (UserVerificationID),
CONSTRAINT FK_UserVerification_UserAccount CONSTRAINT FK_UserVerification_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount(UserAccountID) REFERENCES UserAccount(UserAccountID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT AK_UserVerification_UserAccountID CONSTRAINT AK_UserVerification_UserAccountID
UNIQUE (UserAccountID) UNIQUE (UserAccountID)
); );
CREATE NONCLUSTERED INDEX IX_UserVerification_UserAccount CREATE NONCLUSTERED INDEX IX_UserVerification_UserAccount
ON UserVerification(UserAccountID); ON UserVerification(UserAccountID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE UserCredential -- delete credentials when user account is deleted CREATE TABLE UserCredential -- delete credentials when user account is deleted
( (
UserCredentialID UNIQUEIDENTIFIER UserCredentialID UNIQUEIDENTIFIER
CONSTRAINT DF_UserCredentialID DEFAULT NEWID(), CONSTRAINT DF_UserCredentialID DEFAULT NEWID(),
UserAccountID UNIQUEIDENTIFIER NOT NULL, UserAccountID UNIQUEIDENTIFIER NOT NULL,
CreatedAt DATETIME CreatedAt DATETIME
CONSTRAINT DF_UserCredential_CreatedAt DEFAULT GETDATE() NOT NULL, CONSTRAINT DF_UserCredential_CreatedAt DEFAULT GETDATE() NOT NULL,
Expiry DATETIME Expiry DATETIME
CONSTRAINT DF_UserCredential_Expiry DEFAULT DATEADD(DAY, 90, GETDATE()) NOT NULL, CONSTRAINT DF_UserCredential_Expiry DEFAULT DATEADD(DAY, 90, GETDATE()) NOT NULL,
Hash NVARCHAR(MAX) NOT NULL, Hash NVARCHAR(MAX) NOT NULL,
-- uses argon2 -- uses argon2
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_UserCredential CONSTRAINT PK_UserCredential
PRIMARY KEY (UserCredentialID), PRIMARY KEY (UserCredentialID),
CONSTRAINT FK_UserCredential_UserAccount CONSTRAINT FK_UserCredential_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount(UserAccountID) REFERENCES UserAccount(UserAccountID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT AK_UserCredential_UserAccountID CONSTRAINT AK_UserCredential_UserAccountID
UNIQUE (UserAccountID) UNIQUE (UserAccountID)
); );
CREATE NONCLUSTERED INDEX IX_UserCredential_UserAccount CREATE NONCLUSTERED INDEX IX_UserCredential_UserAccount
ON UserCredential(UserAccountID); ON UserCredential(UserAccountID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE UserFollow CREATE TABLE UserFollow
( (
UserFollowID UNIQUEIDENTIFIER UserFollowID UNIQUEIDENTIFIER
CONSTRAINT DF_UserFollowID DEFAULT NEWID(), CONSTRAINT DF_UserFollowID DEFAULT NEWID(),
UserAccountID UNIQUEIDENTIFIER NOT NULL, UserAccountID UNIQUEIDENTIFIER NOT NULL,
FollowingID UNIQUEIDENTIFIER NOT NULL, FollowingID UNIQUEIDENTIFIER NOT NULL,
CreatedAt DATETIME CreatedAt DATETIME
CONSTRAINT DF_UserFollow_CreatedAt DEFAULT GETDATE() NOT NULL, CONSTRAINT DF_UserFollow_CreatedAt DEFAULT GETDATE() NOT NULL,
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_UserFollow CONSTRAINT PK_UserFollow
PRIMARY KEY (UserFollowID), PRIMARY KEY (UserFollowID),
CONSTRAINT FK_UserFollow_UserAccount CONSTRAINT FK_UserFollow_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount(UserAccountID), REFERENCES UserAccount(UserAccountID),
CONSTRAINT FK_UserFollow_UserAccountFollowing CONSTRAINT FK_UserFollow_UserAccountFollowing
FOREIGN KEY (FollowingID) FOREIGN KEY (FollowingID)
REFERENCES UserAccount(UserAccountID), REFERENCES UserAccount(UserAccountID),
CONSTRAINT CK_CannotFollowOwnAccount CONSTRAINT CK_CannotFollowOwnAccount
CHECK (UserAccountID != FollowingID) CHECK (UserAccountID != FollowingID)
); );
CREATE NONCLUSTERED INDEX IX_UserFollow_UserAccount_FollowingID CREATE NONCLUSTERED INDEX IX_UserFollow_UserAccount_FollowingID
ON UserFollow(UserAccountID, FollowingID); ON UserFollow(UserAccountID, FollowingID);
CREATE NONCLUSTERED INDEX IX_UserFollow_FollowingID_UserAccount CREATE NONCLUSTERED INDEX IX_UserFollow_FollowingID_UserAccount
ON UserFollow(FollowingID, UserAccountID); ON UserFollow(FollowingID, UserAccountID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
@@ -228,17 +228,20 @@ CREATE NONCLUSTERED INDEX IX_UserFollow_FollowingID_UserAccount
CREATE TABLE Country CREATE TABLE Country
( (
CountryID UNIQUEIDENTIFIER CountryID UNIQUEIDENTIFIER
CONSTRAINT DF_CountryID DEFAULT NEWID(), CONSTRAINT DF_CountryID DEFAULT NEWID(),
CountryName NVARCHAR(100) NOT NULL, CountryName NVARCHAR(100) NOT NULL,
CountryCode CHAR(3) NOT NULL, ISO3616_1 CHAR(2) NOT NULL,
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_Country CONSTRAINT PK_Country
PRIMARY KEY (CountryID), PRIMARY KEY (CountryID),
CONSTRAINT AK_Country_ISO3616_1
UNIQUE (ISO3616_1)
); );
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
@@ -246,107 +249,157 @@ CREATE TABLE Country
CREATE TABLE StateProvince CREATE TABLE StateProvince
( (
StateProvinceID UNIQUEIDENTIFIER StateProvinceID UNIQUEIDENTIFIER
CONSTRAINT DF_StateProvinceID DEFAULT NEWID(), CONSTRAINT DF_StateProvinceID DEFAULT NEWID(),
StateProvinceName NVARCHAR(100) NOT NULL, StateProvinceName NVARCHAR(100) NOT NULL,
CountryID UNIQUEIDENTIFIER NOT NULL, ISO3616_2 CHAR(6) NOT NULL,
-- eg 'US-CA' for California, 'CA-ON' for Ontario
Timer ROWVERSION, CountryID UNIQUEIDENTIFIER NOT NULL,
CONSTRAINT PK_StateProvince Timer ROWVERSION,
PRIMARY KEY (StateProvinceID),
CONSTRAINT FK_StateProvince_Country CONSTRAINT PK_StateProvince
FOREIGN KEY (CountryID) PRIMARY KEY (StateProvinceID),
REFERENCES Country(CountryID)
CONSTRAINT AK_StateProvince_ISO3616_2
UNIQUE (ISO3616_2),
CONSTRAINT FK_StateProvince_Country
FOREIGN KEY (CountryID)
REFERENCES Country(CountryID)
); );
CREATE NONCLUSTERED INDEX IX_StateProvince_Country
ON StateProvince(CountryID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE City CREATE TABLE City
( (
CityID UNIQUEIDENTIFIER CityID UNIQUEIDENTIFIER
CONSTRAINT DF_CityID DEFAULT NEWID(), CONSTRAINT DF_CityID DEFAULT NEWID(),
CityName NVARCHAR(100) NOT NULL, CityName NVARCHAR(100) NOT NULL,
StateProvinceID UNIQUEIDENTIFIER NOT NULL, StateProvinceID UNIQUEIDENTIFIER NOT NULL,
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_City CONSTRAINT PK_City
PRIMARY KEY (CityID), PRIMARY KEY (CityID),
CONSTRAINT FK_City_StateProvince
FOREIGN KEY (StateProvinceID)
REFERENCES StateProvince(StateProvinceID)
); );
CREATE NONCLUSTERED INDEX IX_City_StateProvince
ON City(StateProvinceID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE BreweryPost -- A user cannot be deleted if they have a post CREATE TABLE BreweryPost -- A user cannot be deleted if they have a post
( (
BreweryPostID UNIQUEIDENTIFIER BreweryPostID UNIQUEIDENTIFIER
CONSTRAINT DF_BreweryPostID DEFAULT NEWID(), CONSTRAINT DF_BreweryPostID DEFAULT NEWID(),
PostedByID UNIQUEIDENTIFIER NOT NULL, PostedByID UNIQUEIDENTIFIER NOT NULL,
Description NVARCHAR(512) NOT NULL, Description NVARCHAR(512) NOT NULL,
CreatedAt DATETIME NOT NULL CreatedAt DATETIME NOT NULL
CONSTRAINT DF_BreweryPost_CreatedAt DEFAULT GETDATE(), CONSTRAINT DF_BreweryPost_CreatedAt DEFAULT GETDATE(),
UpdatedAt DATETIME NULL, UpdatedAt DATETIME NULL,
Timer ROWVERSION, Timer ROWVERSION,
CityID UNIQUEIDENTIFIER NOT NULL, CONSTRAINT PK_BreweryPost
PRIMARY KEY (BreweryPostID),
Coordinates GEOGRAPHY NOT NULL, CONSTRAINT FK_BreweryPost_UserAccount
FOREIGN KEY (PostedByID)
REFERENCES UserAccount(UserAccountID)
ON DELETE NO ACTION,
CONSTRAINT PK_BreweryPost
PRIMARY KEY (BreweryPostID),
CONSTRAINT FK_BreweryPost_UserAccount
FOREIGN KEY (PostedByID)
REFERENCES UserAccount(UserAccountID)
ON DELETE NO ACTION
) )
CREATE NONCLUSTERED INDEX IX_BreweryPost_PostedByID CREATE NONCLUSTERED INDEX IX_BreweryPost_PostedByID
ON BreweryPost(PostedByID); ON BreweryPost(PostedByID);
---------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
----------------------------------------------------------------------------
CREATE TABLE BreweryPostLocation (
BreweryPostLocationID UNIQUEIDENTIFIER
CONSTRAINT DF_BreweryPostLocationID DEFAULT NEWID(),
BreweryPostID UNIQUEIDENTIFIER NOT NULL,
AddressLine1 NVARCHAR(256) NOT NULL,
AddressLine2 NVARCHAR(256),
PostalCode NVARCHAR(20) NOT NULL,
CityID UNIQUEIDENTIFIER NOT NULL,
Coordinates GEOGRAPHY NOT NULL,
Timer ROWVERSION,
CONSTRAINT PK_BreweryPostLocation
PRIMARY KEY (BreweryPostLocationID),
CONSTRAINT AK_BreweryPostLocation_BreweryPostID
UNIQUE (BreweryPostID),
CONSTRAINT FK_BreweryPostLocation_BreweryPost
FOREIGN KEY (BreweryPostID)
REFERENCES BreweryPost(BreweryPostID)
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX IX_BreweryPostLocation_BreweryPost
ON BreweryPostLocation(BreweryPostID);
CREATE NONCLUSTERED INDEX IX_BreweryPostLocation_City
ON BreweryPostLocation(CityID);
----------------------------------------------------------------------------
----------------------------------------------------------------------------
CREATE TABLE BreweryPostPhoto -- All photos linked to a post are deleted if the post is deleted CREATE TABLE BreweryPostPhoto -- All photos linked to a post are deleted if the post is deleted
( (
BreweryPostPhotoID UNIQUEIDENTIFIER BreweryPostPhotoID UNIQUEIDENTIFIER
CONSTRAINT DF_BreweryPostPhotoID DEFAULT NEWID(), CONSTRAINT DF_BreweryPostPhotoID DEFAULT NEWID(),
BreweryPostID UNIQUEIDENTIFIER NOT NULL, BreweryPostID UNIQUEIDENTIFIER NOT NULL,
PhotoID UNIQUEIDENTIFIER NOT NULL, PhotoID UNIQUEIDENTIFIER NOT NULL,
LinkedAt DATETIME NOT NULL LinkedAt DATETIME NOT NULL
CONSTRAINT DF_BreweryPostPhoto_LinkedAt DEFAULT GETDATE(), CONSTRAINT DF_BreweryPostPhoto_LinkedAt DEFAULT GETDATE(),
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_BreweryPostPhoto CONSTRAINT PK_BreweryPostPhoto
PRIMARY KEY (BreweryPostPhotoID), PRIMARY KEY (BreweryPostPhotoID),
CONSTRAINT FK_BreweryPostPhoto_BreweryPost CONSTRAINT FK_BreweryPostPhoto_BreweryPost
FOREIGN KEY (BreweryPostID) FOREIGN KEY (BreweryPostID)
REFERENCES BreweryPost(BreweryPostID) REFERENCES BreweryPost(BreweryPostID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT FK_BreweryPostPhoto_Photo CONSTRAINT FK_BreweryPostPhoto_Photo
FOREIGN KEY (PhotoID) FOREIGN KEY (PhotoID)
REFERENCES Photo(PhotoID) REFERENCES Photo(PhotoID)
ON DELETE CASCADE ON DELETE CASCADE
); );
CREATE NONCLUSTERED INDEX IX_BreweryPostPhoto_Photo_BreweryPost CREATE NONCLUSTERED INDEX IX_BreweryPostPhoto_Photo_BreweryPost
@@ -359,20 +412,20 @@ ON BreweryPostPhoto(BreweryPostID, PhotoID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE BeerStyle CREATE TABLE BeerStyle
( (
BeerStyleID UNIQUEIDENTIFIER BeerStyleID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerStyleID DEFAULT NEWID(), CONSTRAINT DF_BeerStyleID DEFAULT NEWID(),
StyleName NVARCHAR(100) NOT NULL, StyleName NVARCHAR(100) NOT NULL,
Description NVARCHAR(MAX), Description NVARCHAR(MAX),
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_BeerStyle CONSTRAINT PK_BeerStyle
PRIMARY KEY (BeerStyleID), PRIMARY KEY (BeerStyleID),
CONSTRAINT AK_BeerStyle_StyleName CONSTRAINT AK_BeerStyle_StyleName
UNIQUE (StyleName) UNIQUE (StyleName)
); );
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
@@ -380,51 +433,51 @@ CREATE TABLE BeerStyle
CREATE TABLE BeerPost CREATE TABLE BeerPost
( (
BeerPostID UNIQUEIDENTIFIER BeerPostID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerPostID DEFAULT NEWID(), CONSTRAINT DF_BeerPostID DEFAULT NEWID(),
Name NVARCHAR(100) NOT NULL, Name NVARCHAR(100) NOT NULL,
Description NVARCHAR(MAX) NOT NULL, Description NVARCHAR(MAX) NOT NULL,
ABV DECIMAL(4,2) NOT NULL, ABV DECIMAL(4,2) NOT NULL,
-- Alcohol By Volume (typically 0-67%) -- Alcohol By Volume (typically 0-67%)
IBU INT NOT NULL, IBU INT NOT NULL,
-- International Bitterness Units (typically 0-100) -- International Bitterness Units (typically 0-100)
PostedByID UNIQUEIDENTIFIER NOT NULL, PostedByID UNIQUEIDENTIFIER NOT NULL,
BeerStyleID UNIQUEIDENTIFIER NOT NULL, BeerStyleID UNIQUEIDENTIFIER NOT NULL,
BrewedByID UNIQUEIDENTIFIER NOT NULL, BrewedByID UNIQUEIDENTIFIER NOT NULL,
CreatedAt DATETIME NOT NULL CreatedAt DATETIME NOT NULL
CONSTRAINT DF_BeerPost_CreatedAt DEFAULT GETDATE(), CONSTRAINT DF_BeerPost_CreatedAt DEFAULT GETDATE(),
UpdatedAt DATETIME, UpdatedAt DATETIME,
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_BeerPost CONSTRAINT PK_BeerPost
PRIMARY KEY (BeerPostID), PRIMARY KEY (BeerPostID),
CONSTRAINT FK_BeerPost_PostedBy CONSTRAINT FK_BeerPost_PostedBy
FOREIGN KEY (PostedByID) FOREIGN KEY (PostedByID)
REFERENCES UserAccount(UserAccountID), REFERENCES UserAccount(UserAccountID),
CONSTRAINT FK_BeerPost_BeerStyle CONSTRAINT FK_BeerPost_BeerStyle
FOREIGN KEY (BeerStyleID) FOREIGN KEY (BeerStyleID)
REFERENCES BeerStyle(BeerStyleID), REFERENCES BeerStyle(BeerStyleID),
CONSTRAINT FK_BeerPost_Brewery CONSTRAINT FK_BeerPost_Brewery
FOREIGN KEY (BrewedByID) FOREIGN KEY (BrewedByID)
REFERENCES BreweryPost(BreweryPostID), REFERENCES BreweryPost(BreweryPostID),
CONSTRAINT CHK_BeerPost_ABV CONSTRAINT CHK_BeerPost_ABV
CHECK (ABV >= 0 AND ABV <= 67), CHECK (ABV >= 0 AND ABV <= 67),
CONSTRAINT CHK_BeerPost_IBU CONSTRAINT CHK_BeerPost_IBU
CHECK (IBU >= 0 AND IBU <= 120) CHECK (IBU >= 0 AND IBU <= 120)
); );
@@ -432,40 +485,40 @@ CREATE NONCLUSTERED INDEX IX_BeerPost_PostedBy
ON BeerPost(PostedByID); ON BeerPost(PostedByID);
CREATE NONCLUSTERED INDEX IX_BeerPost_BeerStyle CREATE NONCLUSTERED INDEX IX_BeerPost_BeerStyle
ON BeerPost(BeerStyleID); ON BeerPost(BeerStyleID);
CREATE NONCLUSTERED INDEX IX_BeerPost_BrewedBy CREATE NONCLUSTERED INDEX IX_BeerPost_BrewedBy
ON BeerPost(BrewedByID); ON BeerPost(BrewedByID);
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
CREATE TABLE BeerPostPhoto -- All photos linked to a beer post are deleted if the post is deleted CREATE TABLE BeerPostPhoto -- All photos linked to a beer post are deleted if the post is deleted
( (
BeerPostPhotoID UNIQUEIDENTIFIER BeerPostPhotoID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerPostPhotoID DEFAULT NEWID(), CONSTRAINT DF_BeerPostPhotoID DEFAULT NEWID(),
BeerPostID UNIQUEIDENTIFIER NOT NULL, BeerPostID UNIQUEIDENTIFIER NOT NULL,
PhotoID UNIQUEIDENTIFIER NOT NULL, PhotoID UNIQUEIDENTIFIER NOT NULL,
LinkedAt DATETIME NOT NULL LinkedAt DATETIME NOT NULL
CONSTRAINT DF_BeerPostPhoto_LinkedAt DEFAULT GETDATE(), CONSTRAINT DF_BeerPostPhoto_LinkedAt DEFAULT GETDATE(),
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_BeerPostPhoto CONSTRAINT PK_BeerPostPhoto
PRIMARY KEY (BeerPostPhotoID), PRIMARY KEY (BeerPostPhotoID),
CONSTRAINT FK_BeerPostPhoto_BeerPost CONSTRAINT FK_BeerPostPhoto_BeerPost
FOREIGN KEY (BeerPostID) FOREIGN KEY (BeerPostID)
REFERENCES BeerPost(BeerPostID) REFERENCES BeerPost(BeerPostID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT FK_BeerPostPhoto_Photo CONSTRAINT FK_BeerPostPhoto_Photo
FOREIGN KEY (PhotoID) FOREIGN KEY (PhotoID)
REFERENCES Photo(PhotoID) REFERENCES Photo(PhotoID)
ON DELETE CASCADE ON DELETE CASCADE
); );
CREATE NONCLUSTERED INDEX IX_BeerPostPhoto_Photo_BeerPost CREATE NONCLUSTERED INDEX IX_BeerPostPhoto_Photo_BeerPost
@@ -479,34 +532,27 @@ ON BeerPostPhoto(BeerPostID, PhotoID);
CREATE TABLE BeerPostComment CREATE TABLE BeerPostComment
( (
BeerPostCommentID UNIQUEIDENTIFIER BeerPostCommentID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerPostComment DEFAULT NEWID(), CONSTRAINT DF_BeerPostComment DEFAULT NEWID(),
Comment NVARCHAR(250) NOT NULL, Comment NVARCHAR(250) NOT NULL,
BeerPostID UNIQUEIDENTIFIER NOT NULL, BeerPostID UNIQUEIDENTIFIER NOT NULL,
Rating INT NOT NULL, Rating INT NOT NULL,
Timer ROWVERSION, Timer ROWVERSION,
CONSTRAINT PK_BeerPostComment CONSTRAINT PK_BeerPostComment
PRIMARY KEY (BeerPostCommentID), PRIMARY KEY (BeerPostCommentID),
CONSTRAINT FK_BeerPostComment_BeerPost CONSTRAINT FK_BeerPostComment_BeerPost
FOREIGN KEY (BeerPostID) REFERENCES BeerPost(BeerPostID) FOREIGN KEY (BeerPostID) REFERENCES BeerPost(BeerPostID)
) )
CREATE NONCLUSTERED INDEX IX_BeerPostComment_BeerPost CREATE NONCLUSTERED INDEX IX_BeerPostComment_BeerPost
ON BeerPostComment(BeerPostID) ON BeerPostComment(BeerPostID)
----------------------------------------------------------------------------- ----------------------------------------------------------------------------
----------------------------------------------------------------------------- ----------------------------------------------------------------------------
-- EOF
USE Biergarten;
SELECT *
FROM UserAccount;
SELECT *
FROM UserCredential;
SELECT *
FROM UserVerification;

View File

@@ -4,7 +4,9 @@ using System.Text;
using Konscious.Security.Cryptography; using Konscious.Security.Cryptography;
using Microsoft.Data.SqlClient; using Microsoft.Data.SqlClient;
string ConnectionString = Environment.GetEnvironmentVariable("SEEDDB_CONNECTION_STRING")!; string ConnectionString = Environment.GetEnvironmentVariable(
"DB_CONNECTION_STRING"
)!;
static async Task BuildSchema(SqlConnection connection) static async Task BuildSchema(SqlConnection connection)
{ {
@@ -13,13 +15,61 @@ static async Task BuildSchema(SqlConnection connection)
Console.WriteLine("Database schema created or updated successfully."); Console.WriteLine("Database schema created or updated successfully.");
} }
static async Task AddStoredProcs(SqlConnection connection) static async Task AddStoredProcsAndFunctions(SqlConnection connection)
{ {
string sql = await File.ReadAllTextAsync( // New approach: load functions first, then procedures, from dedicated folders.
GetScriptPath("SeedStoredProcs.sql") // Fallback to legacy combined file if folders are missing.
string projectRoot = Path.GetFullPath(
Path.Combine(AppContext.BaseDirectory, "..", "..", "..")
); );
await ExecuteScriptAsync(connection, sql);
Console.WriteLine("Stored procedures added or updated successfully."); string functionsDir = Path.Combine(projectRoot, "seed", "functions");
string proceduresDir = Path.Combine(projectRoot, "seed", "procedures");
if (Directory.Exists(functionsDir))
{
foreach (
string file in Directory
.EnumerateFiles(
functionsDir,
"*.sql",
SearchOption.TopDirectoryOnly
)
.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
)
{
string sql = await File.ReadAllTextAsync(file);
await ExecuteScriptAsync(connection, sql);
Console.WriteLine(
$"Executed function script: {Path.GetFileName(file)}"
);
}
}
if (Directory.Exists(proceduresDir))
{
foreach (
string file in Directory
.EnumerateFiles(
proceduresDir,
"*.sql",
SearchOption.TopDirectoryOnly
)
.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
)
{
string sql = await File.ReadAllTextAsync(file);
await ExecuteScriptAsync(connection, sql);
Console.WriteLine(
$"Executed procedure script: {Path.GetFileName(file)}"
);
}
}
Console.WriteLine(
"Functions and stored procedures added or updated successfully."
);
return;
} }
static async Task RunSeedAsync(SqlConnection connection) static async Task RunSeedAsync(SqlConnection connection)
@@ -202,7 +252,7 @@ try
Console.WriteLine("Connection to database established successfully."); Console.WriteLine("Connection to database established successfully.");
await BuildSchema(connection); await BuildSchema(connection);
await AddStoredProcs(connection); await AddStoredProcsAndFunctions(connection);
await RunSeedAsync(connection); await RunSeedAsync(connection);
Console.WriteLine("Seeding complete."); Console.WriteLine("Seeding complete.");
} }

View File

@@ -0,0 +1,19 @@
USE Biergarten;
GO
CREATE OR ALTER FUNCTION dbo.UDF_GetCountryIdByCode
(
@CountryCode NVARCHAR(2)
)
RETURNS UNIQUEIDENTIFIER
AS
BEGIN
DECLARE @CountryId UNIQUEIDENTIFIER;
SELECT @CountryId = CountryID
FROM dbo.Country
WHERE ISO3616_1 = @CountryCode;
RETURN @CountryId;
END;
GO

View File

@@ -0,0 +1,17 @@
USE Biergarten;
GO
CREATE OR ALTER FUNCTION dbo.UDF_GetStateProvinceIdByCode
(
@StateProvinceCode NVARCHAR(6)
)
RETURNS UNIQUEIDENTIFIER
AS
BEGIN
DECLARE @StateProvinceId UNIQUEIDENTIFIER;
SELECT @StateProvinceId = StateProvinceID
FROM dbo.StateProvince
WHERE ISO3616_2 = @StateProvinceCode;
RETURN @StateProvinceId;
END;
GO

View File

@@ -0,0 +1,504 @@
USE Biergarten;
GO
CREATE OR ALTER PROCEDURE dbo.USP_AddLocations
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
-- Countries (alpha-2)
WITH
Countries(CountryName, Alpha2)
AS
(
SELECT 'Canada', 'CA'
UNION ALL
SELECT 'Mexico', 'MX'
UNION ALL
SELECT 'United States', 'US'
)
INSERT INTO dbo.Country
(CountryName, ISO3616_1)
SELECT c.CountryName, c.Alpha2
FROM Countries AS c
WHERE NOT EXISTS (SELECT 1
FROM dbo.Country AS x
WHERE x.ISO3616_1 = c.Alpha2
);
WITH
Regions(StateProvinceName, ISO2, CountryAlpha2)
AS
(
-- United States (50 + DC + territories)
SELECT 'Alabama', 'US-AL', 'US'
UNION ALL
SELECT 'Alaska', 'US-AK', 'US'
UNION ALL
SELECT 'Arizona', 'US-AZ', 'US'
UNION ALL
SELECT 'Arkansas', 'US-AR', 'US'
UNION ALL
SELECT 'California', 'US-CA', 'US'
UNION ALL
SELECT 'Colorado', 'US-CO', 'US'
UNION ALL
SELECT 'Connecticut', 'US-CT', 'US'
UNION ALL
SELECT 'Delaware', 'US-DE', 'US'
UNION ALL
SELECT 'Florida', 'US-FL', 'US'
UNION ALL
SELECT 'Georgia', 'US-GA', 'US'
UNION ALL
SELECT 'Hawaii', 'US-HI', 'US'
UNION ALL
SELECT 'Idaho', 'US-ID', 'US'
UNION ALL
SELECT 'Illinois', 'US-IL', 'US'
UNION ALL
SELECT 'Indiana', 'US-IN', 'US'
UNION ALL
SELECT 'Iowa', 'US-IA', 'US'
UNION ALL
SELECT 'Kansas', 'US-KS', 'US'
UNION ALL
SELECT 'Kentucky', 'US-KY', 'US'
UNION ALL
SELECT 'Louisiana', 'US-LA', 'US'
UNION ALL
SELECT 'Maine', 'US-ME', 'US'
UNION ALL
SELECT 'Maryland', 'US-MD', 'US'
UNION ALL
SELECT 'Massachusetts', 'US-MA', 'US'
UNION ALL
SELECT 'Michigan', 'US-MI', 'US'
UNION ALL
SELECT 'Minnesota', 'US-MN', 'US'
UNION ALL
SELECT 'Mississippi', 'US-MS', 'US'
UNION ALL
SELECT 'Missouri', 'US-MO', 'US'
UNION ALL
SELECT 'Montana', 'US-MT', 'US'
UNION ALL
SELECT 'Nebraska', 'US-NE', 'US'
UNION ALL
SELECT 'Nevada', 'US-NV', 'US'
UNION ALL
SELECT 'New Hampshire', 'US-NH', 'US'
UNION ALL
SELECT 'New Jersey', 'US-NJ', 'US'
UNION ALL
SELECT 'New Mexico', 'US-NM', 'US'
UNION ALL
SELECT 'New York', 'US-NY', 'US'
UNION ALL
SELECT 'North Carolina', 'US-NC', 'US'
UNION ALL
SELECT 'North Dakota', 'US-ND', 'US'
UNION ALL
SELECT 'Ohio', 'US-OH', 'US'
UNION ALL
SELECT 'Oklahoma', 'US-OK', 'US'
UNION ALL
SELECT 'Oregon', 'US-OR', 'US'
UNION ALL
SELECT 'Pennsylvania', 'US-PA', 'US'
UNION ALL
SELECT 'Rhode Island', 'US-RI', 'US'
UNION ALL
SELECT 'South Carolina', 'US-SC', 'US'
UNION ALL
SELECT 'South Dakota', 'US-SD', 'US'
UNION ALL
SELECT 'Tennessee', 'US-TN', 'US'
UNION ALL
SELECT 'Texas', 'US-TX', 'US'
UNION ALL
SELECT 'Utah', 'US-UT', 'US'
UNION ALL
SELECT 'Vermont', 'US-VT', 'US'
UNION ALL
SELECT 'Virginia', 'US-VA', 'US'
UNION ALL
SELECT 'Washington', 'US-WA', 'US'
UNION ALL
SELECT 'West Virginia', 'US-WV', 'US'
UNION ALL
SELECT 'Wisconsin', 'US-WI', 'US'
UNION ALL
SELECT 'Wyoming', 'US-WY', 'US'
UNION ALL
SELECT 'District of Columbia', 'US-DC', 'US'
UNION ALL
SELECT 'Puerto Rico', 'US-PR', 'US'
UNION ALL
SELECT 'U.S. Virgin Islands', 'US-VI', 'US'
UNION ALL
SELECT 'Guam', 'US-GU', 'US'
UNION ALL
SELECT 'Northern Mariana Islands', 'US-MP', 'US'
UNION ALL
SELECT 'American Samoa', 'US-AS', 'US'
-- Canada (10 provinces + 3 territories)
UNION ALL
SELECT 'Ontario', 'CA-ON', 'CA'
UNION ALL
SELECT N'Québec', 'CA-QC', 'CA'
UNION ALL
SELECT 'Nova Scotia', 'CA-NS', 'CA'
UNION ALL
SELECT 'New Brunswick', 'CA-NB', 'CA'
UNION ALL
SELECT 'Manitoba', 'CA-MB', 'CA'
UNION ALL
SELECT 'British Columbia', 'CA-BC', 'CA'
UNION ALL
SELECT 'Prince Edward Island', 'CA-PE', 'CA'
UNION ALL
SELECT 'Saskatchewan', 'CA-SK', 'CA'
UNION ALL
SELECT 'Alberta', 'CA-AB', 'CA'
UNION ALL
SELECT 'Newfoundland and Labrador', 'CA-NL', 'CA'
UNION ALL
SELECT 'Northwest Territories', 'CA-NT', 'CA'
UNION ALL
SELECT 'Yukon', 'CA-YT', 'CA'
UNION ALL
SELECT 'Nunavut', 'CA-NU', 'CA'
-- Mexico (32 states incl. CDMX)
UNION ALL
SELECT 'Aguascalientes', 'MX-AGU', 'MX'
UNION ALL
SELECT 'Baja California', 'MX-BCN', 'MX'
UNION ALL
SELECT 'Baja California Sur', 'MX-BCS', 'MX'
UNION ALL
SELECT 'Campeche', 'MX-CAM', 'MX'
UNION ALL
SELECT 'Chiapas', 'MX-CHP', 'MX'
UNION ALL
SELECT 'Chihuahua', 'MX-CHH', 'MX'
UNION ALL
SELECT 'Coahuila de Zaragoza', 'MX-COA', 'MX'
UNION ALL
SELECT 'Colima', 'MX-COL', 'MX'
UNION ALL
SELECT 'Durango', 'MX-DUR', 'MX'
UNION ALL
SELECT 'Guanajuato', 'MX-GUA', 'MX'
UNION ALL
SELECT 'Guerrero', 'MX-GRO', 'MX'
UNION ALL
SELECT 'Hidalgo', 'MX-HID', 'MX'
UNION ALL
SELECT 'Jalisco', 'MX-JAL', 'MX'
UNION ALL
SELECT N'México State', 'MX-MEX', 'MX'
UNION ALL
SELECT N'Michoacán de Ocampo', 'MX-MIC', 'MX'
UNION ALL
SELECT 'Morelos', 'MX-MOR', 'MX'
UNION ALL
SELECT 'Nayarit', 'MX-NAY', 'MX'
UNION ALL
SELECT N'Nuevo León', 'MX-NLE', 'MX'
UNION ALL
SELECT 'Oaxaca', 'MX-OAX', 'MX'
UNION ALL
SELECT 'Puebla', 'MX-PUE', 'MX'
UNION ALL
SELECT N'Querétaro', 'MX-QUE', 'MX'
UNION ALL
SELECT 'Quintana Roo', 'MX-ROO', 'MX'
UNION ALL
SELECT N'San Luis Potosí', 'MX-SLP', 'MX'
UNION ALL
SELECT 'Sinaloa', 'MX-SIN', 'MX'
UNION ALL
SELECT 'Sonora', 'MX-SON', 'MX'
UNION ALL
SELECT 'Tabasco', 'MX-TAB', 'MX'
UNION ALL
SELECT 'Tamaulipas', 'MX-TAM', 'MX'
UNION ALL
SELECT 'Tlaxcala', 'MX-TLA', 'MX'
UNION ALL
SELECT 'Veracruz de Ignacio de la Llave', 'MX-VER', 'MX'
UNION ALL
SELECT N'Yucatán', 'MX-YUC', 'MX'
UNION ALL
SELECT 'Zacatecas', 'MX-ZAC', 'MX'
UNION ALL
SELECT N'Ciudad de México', 'MX-CMX', 'MX'
)
INSERT INTO dbo.StateProvince
(StateProvinceName, ISO3616_2, CountryID)
SELECT
r.StateProvinceName,
r.ISO2,
dbo.UDF_GetCountryIdByCode(r.CountryAlpha2)
FROM Regions AS r
WHERE NOT EXISTS (
SELECT 1
FROM dbo.StateProvince AS sp
WHERE sp.ISO3616_2 = r.ISO2
);
WITH
Cities(StateProvinceISO2, CityName)
AS
(
-- USA
SELECT 'US-CA', 'Los Angeles'
UNION ALL
SELECT 'US-CA', 'San Diego'
UNION ALL
SELECT 'US-CA', 'San Francisco'
UNION ALL
SELECT 'US-CA', 'Sacramento'
UNION ALL
SELECT 'US-TX', 'Houston'
UNION ALL
SELECT 'US-TX', 'Dallas'
UNION ALL
SELECT 'US-TX', 'Austin'
UNION ALL
SELECT 'US-TX', 'San Antonio'
UNION ALL
SELECT 'US-FL', 'Miami'
UNION ALL
SELECT 'US-FL', 'Orlando'
UNION ALL
SELECT 'US-FL', 'Tampa'
UNION ALL
SELECT 'US-NY', 'New York'
UNION ALL
SELECT 'US-NY', 'Buffalo'
UNION ALL
SELECT 'US-NY', 'Rochester'
UNION ALL
SELECT 'US-IL', 'Chicago'
UNION ALL
SELECT 'US-IL', 'Springfield'
UNION ALL
SELECT 'US-PA', 'Philadelphia'
UNION ALL
SELECT 'US-PA', 'Pittsburgh'
UNION ALL
SELECT 'US-AZ', 'Phoenix'
UNION ALL
SELECT 'US-AZ', 'Tucson'
UNION ALL
SELECT 'US-CO', 'Denver'
UNION ALL
SELECT 'US-CO', 'Colorado Springs'
UNION ALL
SELECT 'US-MA', 'Boston'
UNION ALL
SELECT 'US-MA', 'Worcester'
UNION ALL
SELECT 'US-WA', 'Seattle'
UNION ALL
SELECT 'US-WA', 'Spokane'
UNION ALL
SELECT 'US-GA', 'Atlanta'
UNION ALL
SELECT 'US-GA', 'Savannah'
UNION ALL
SELECT 'US-NV', 'Las Vegas'
UNION ALL
SELECT 'US-NV', 'Reno'
UNION ALL
SELECT 'US-MI', 'Detroit'
UNION ALL
SELECT 'US-MI', 'Grand Rapids'
UNION ALL
SELECT 'US-MN', 'Minneapolis'
UNION ALL
SELECT 'US-MN', 'Saint Paul'
UNION ALL
SELECT 'US-OH', 'Columbus'
UNION ALL
SELECT 'US-OH', 'Cleveland'
UNION ALL
SELECT 'US-OR', 'Portland'
UNION ALL
SELECT 'US-OR', 'Salem'
UNION ALL
SELECT 'US-TN', 'Nashville'
UNION ALL
SELECT 'US-TN', 'Memphis'
UNION ALL
SELECT 'US-VA', 'Richmond'
UNION ALL
SELECT 'US-VA', 'Virginia Beach'
UNION ALL
SELECT 'US-MD', 'Baltimore'
UNION ALL
SELECT 'US-MD', 'Frederick'
UNION ALL
SELECT 'US-DC', 'Washington'
UNION ALL
SELECT 'US-UT', 'Salt Lake City'
UNION ALL
SELECT 'US-UT', 'Provo'
UNION ALL
SELECT 'US-LA', 'New Orleans'
UNION ALL
SELECT 'US-LA', 'Baton Rouge'
UNION ALL
SELECT 'US-KY', 'Louisville'
UNION ALL
SELECT 'US-KY', 'Lexington'
UNION ALL
SELECT 'US-IA', 'Des Moines'
UNION ALL
SELECT 'US-IA', 'Cedar Rapids'
UNION ALL
SELECT 'US-OK', 'Oklahoma City'
UNION ALL
SELECT 'US-OK', 'Tulsa'
UNION ALL
SELECT 'US-NE', 'Omaha'
UNION ALL
SELECT 'US-NE', 'Lincoln'
UNION ALL
SELECT 'US-MO', 'Kansas City'
UNION ALL
SELECT 'US-MO', 'St. Louis'
UNION ALL
SELECT 'US-NC', 'Charlotte'
UNION ALL
SELECT 'US-NC', 'Raleigh'
UNION ALL
SELECT 'US-SC', 'Columbia'
UNION ALL
SELECT 'US-SC', 'Charleston'
UNION ALL
SELECT 'US-WI', 'Milwaukee'
UNION ALL
SELECT 'US-WI', 'Madison'
UNION ALL
SELECT 'US-MN', 'Duluth'
UNION ALL
SELECT 'US-AK', 'Anchorage'
UNION ALL
SELECT 'US-HI', 'Honolulu'
-- Canada
UNION ALL
SELECT 'CA-ON', 'Toronto'
UNION ALL
SELECT 'CA-ON', 'Ottawa'
UNION ALL
SELECT 'CA-QC', N'Montréal'
UNION ALL
SELECT 'CA-QC', N'Québec City'
UNION ALL
SELECT 'CA-BC', 'Vancouver'
UNION ALL
SELECT 'CA-BC', 'Victoria'
UNION ALL
SELECT 'CA-AB', 'Calgary'
UNION ALL
SELECT 'CA-AB', 'Edmonton'
UNION ALL
SELECT 'CA-MB', 'Winnipeg'
UNION ALL
SELECT 'CA-NS', 'Halifax'
UNION ALL
SELECT 'CA-SK', 'Saskatoon'
UNION ALL
SELECT 'CA-SK', 'Regina'
UNION ALL
SELECT 'CA-NB', 'Moncton'
UNION ALL
SELECT 'CA-NB', 'Saint John'
UNION ALL
SELECT 'CA-PE', 'Charlottetown'
UNION ALL
SELECT 'CA-NL', N'St. John''s'
UNION ALL
SELECT 'CA-ON', 'Hamilton'
UNION ALL
SELECT 'CA-ON', 'London'
UNION ALL
SELECT 'CA-QC', 'Gatineau'
UNION ALL
SELECT 'CA-QC', 'Laval'
UNION ALL
SELECT 'CA-BC', 'Kelowna'
UNION ALL
SELECT 'CA-AB', 'Red Deer'
UNION ALL
SELECT 'CA-MB', 'Brandon'
-- MEXICO
UNION ALL
SELECT 'MX-CMX', N'Ciudad de México'
UNION ALL
SELECT 'MX-JAL', 'Guadalajara'
UNION ALL
SELECT 'MX-NLE', 'Monterrey'
UNION ALL
SELECT 'MX-PUE', 'Puebla'
UNION ALL
SELECT 'MX-ROO', N'Cancún'
UNION ALL
SELECT 'MX-GUA', 'Guanajuato'
UNION ALL
SELECT 'MX-MIC', 'Morelia'
UNION ALL
SELECT 'MX-BCN', 'Tijuana'
UNION ALL
SELECT 'MX-JAL', 'Zapopan'
UNION ALL
SELECT 'MX-NLE', N'San Nicolás'
UNION ALL
SELECT 'MX-CAM', 'Campeche'
UNION ALL
SELECT 'MX-TAB', 'Villahermosa'
UNION ALL
SELECT 'MX-VER', 'Veracruz'
UNION ALL
SELECT 'MX-OAX', 'Oaxaca'
UNION ALL
SELECT 'MX-SLP', N'San Luis Potosí'
UNION ALL
SELECT 'MX-CHH', 'Chihuahua'
UNION ALL
SELECT 'MX-AGU', 'Aguascalientes'
UNION ALL
SELECT 'MX-MEX', 'Toluca'
UNION ALL
SELECT 'MX-COA', 'Saltillo'
UNION ALL
SELECT 'MX-BCS', 'La Paz'
UNION ALL
SELECT 'MX-NAY', 'Tepic'
UNION ALL
SELECT 'MX-ZAC', 'Zacatecas'
)
INSERT INTO dbo.City
(StateProvinceID, CityName)
SELECT
dbo.UDF_GetStateProvinceIdByCode(c.StateProvinceISO2),
c.CityName
FROM Cities AS c
WHERE NOT EXISTS (
SELECT 1
FROM dbo.City AS ci
WHERE ci.CityName = c.CityName
AND ci.StateProvinceID = dbo.UDF_GetStateProvinceIdByCode(c.StateProvinceISO2)
);
COMMIT TRANSACTION;
END;
GO

View File

@@ -1,5 +1,4 @@
USE Biergarten;
USE biergarten;
GO GO
CREATE OR ALTER PROCEDURE dbo.USP_AddTestUsers CREATE OR ALTER PROCEDURE dbo.USP_AddTestUsers
@@ -135,65 +134,3 @@ BEGIN
COMMIT TRANSACTION; COMMIT TRANSACTION;
END; END;
GO GO
CREATE TYPE TblUserHashes AS TABLE
(
UserAccountId UNIQUEIDENTIFIER NOT NULL,
Hash NVARCHAR(MAX) NOT NULL
);
GO
-- Stored procedure to insert Argon2 hashes
CREATE OR ALTER PROCEDURE dbo.USP_AddUserCredentials
(
@Hash dbo.TblUserHashes READONLY
)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO dbo.UserCredential
(UserAccountId, Hash)
SELECT
uah.UserAccountId,
uah.Hash
FROM @Hash AS uah;
COMMIT TRANSACTION;
END;
GO
CREATE OR ALTER PROCEDURE dbo.USP_CreateUserVerification
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO dbo.UserVerification
(UserAccountId)
SELECT
ua.UserAccountID
FROM dbo.UserAccount AS ua
WHERE NOT EXISTS
(SELECT 1
FROM dbo.UserVerification AS uv
WHERE uv.UserAccountId = ua.UserAccountID);
IF (SELECT COUNT(*)
FROM dbo.UserVerification) != (SELECT COUNT(*)
FROM dbo.UserAccount)
BEGIN
RAISERROR('UserVerification count does not match UserAccount count after insertion.', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END
COMMIT TRANSACTION;
END
GO

View File

@@ -0,0 +1,33 @@
USE Biergarten;
GO
IF TYPE_ID(N'dbo.TblUserHashes') IS NULL
EXEC('CREATE TYPE dbo.TblUserHashes AS TABLE
(
UserAccountId UNIQUEIDENTIFIER NOT NULL,
Hash NVARCHAR(MAX) NOT NULL
);');
GO
-- Stored procedure to insert Argon2 hashes
CREATE OR ALTER PROCEDURE dbo.USP_AddUserCredentials
(
@Hash dbo.TblUserHashes READONLY
)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO dbo.UserCredential
(UserAccountId, Hash)
SELECT
uah.UserAccountId,
uah.Hash
FROM @Hash AS uah;
COMMIT TRANSACTION;
END;
GO

View File

@@ -0,0 +1,35 @@
USE Biergarten;
GO
CREATE OR ALTER PROCEDURE dbo.USP_CreateUserVerification
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO dbo.UserVerification
(UserAccountId)
SELECT
ua.UserAccountID
FROM dbo.UserAccount AS ua
WHERE NOT EXISTS
(SELECT 1
FROM dbo.UserVerification AS uv
WHERE uv.UserAccountId = ua.UserAccountID);
IF (SELECT COUNT(*)
FROM dbo.UserVerification)
!= (SELECT COUNT(*)
FROM dbo.UserAccount)
BEGIN
RAISERROR('UserVerification count does not match UserAccount count after insertion.', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END
COMMIT TRANSACTION;
END
GO

View File

@@ -16,22 +16,34 @@ app.UseHttpsRedirection();
var summaries = new[] var summaries = new[]
{ {
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" "Freezing",
"Bracing",
"Chilly",
"Cool",
"Mild",
"Warm",
"Balmy",
"Hot",
"Sweltering",
"Scorching",
}; };
app.MapGet("/weatherforecast", () => app.MapGet(
{ "/weatherforecast",
var forecast = Enumerable.Range(1, 5).Select(index => () =>
new WeatherForecast {
( var forecast = Enumerable
DateOnly.FromDateTime(DateTime.Now.AddDays(index)), .Range(1, 5)
Random.Shared.Next(-20, 55), .Select(index => new WeatherForecast(
summaries[Random.Shared.Next(summaries.Length)] DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
)) Random.Shared.Next(-20, 55),
.ToArray(); summaries[Random.Shared.Next(summaries.Length)]
return forecast; ))
}) .ToArray();
.WithName("GetWeatherForecast"); return forecast;
}
)
.WithName("GetWeatherForecast");
app.UseStaticFiles(); app.UseStaticFiles();
app.Run(); app.Run();

View File

@@ -1,5 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@@ -9,5 +8,4 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.11" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.11" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -24,7 +24,7 @@ services:
tty: true tty: true
stdin_open: true stdin_open: true
volumes: volumes:
- ./:/home/dev/projects # bind mount your repo for live code edits - ./:/home/dev/projects
- nuget-cache:/home/dev/.nuget/packages - nuget-cache:/home/dev/.nuget/packages
- ~/.gitconfig:/home/dev/.gitconfig:ro - ~/.gitconfig:/home/dev/.gitconfig:ro
working_dir: /home/dev/projects working_dir: /home/dev/projects
@@ -32,7 +32,7 @@ services:
DOTNET_CLI_TELEMETRY_OPTOUT: "1" DOTNET_CLI_TELEMETRY_OPTOUT: "1"
HOME: /home/dev HOME: /home/dev
USER: dev USER: dev
SEEDDB_CONNECTION_STRING: "Server=sqlserver,1433;User Id=sa;Password=YourStrong!Passw0rd;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;" DB_CONNECTION_STRING: "Server=sqlserver,1433;User Id=sa;Password=YourStrong!Passw0rd;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;"
user: root user: root
networks: networks:
- devnet - devnet