PI06 i PI06-1. Docker definitions for MSSQL and Postgres. Data seeder/generator for countries and people. Entity Framework example with variants for Postgres and MSSQL
This commit is contained in:
25
DataAccess/DataAccess.sln
Normal file
25
DataAccess/DataAccess.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.5.11709.299
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EF_Demo", "EF_Demo\EF_Demo.csproj", "{26C4670D-F5D0-420C-8730-F76E53BAA639}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{26C4670D-F5D0-420C-8730-F76E53BAA639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{26C4670D-F5D0-420C-8730-F76E53BAA639}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{26C4670D-F5D0-420C-8730-F76E53BAA639}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{26C4670D-F5D0-420C-8730-F76E53BAA639}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {2C6663EA-3869-40E6-8F2A-0F122E9CDE02}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
32
DataAccess/EF_Demo/DISetup.cs
Normal file
32
DataAccess/EF_Demo/DISetup.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace EF_Demo;
|
||||
|
||||
internal class DISetup
|
||||
{
|
||||
public static ServiceProvider BuildDI()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddUserSecrets<Program>()
|
||||
.Build();
|
||||
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
var provider = services.AddLogging(configure => {
|
||||
configure.AddConfiguration(configuration.GetSection("Logging"));
|
||||
configure.AddConsole();
|
||||
})
|
||||
.AddDbContext<Data.MSSQL.EventsContext>(options => {
|
||||
options.UseSqlServer(configuration.GetConnectionString("EventsMssql"));
|
||||
}, contextLifetime: ServiceLifetime.Transient)
|
||||
.AddDbContext<Data.Postgres.EventsContext>(options => {
|
||||
options.UseNpgsql(configuration.GetConnectionString("EventsPostgres"));
|
||||
}, contextLifetime: ServiceLifetime.Transient)
|
||||
.BuildServiceProvider();
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
143
DataAccess/EF_Demo/Data/MSSQL/EventsContext.cs
Normal file
143
DataAccess/EF_Demo/Data/MSSQL/EventsContext.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using EF_Demo.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EF_Demo.Data.MSSQL;
|
||||
|
||||
public partial class EventsContext : DbContext
|
||||
{
|
||||
public EventsContext(DbContextOptions<EventsContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<Country> Countries { get; set; }
|
||||
|
||||
public virtual DbSet<Event> Events { get; set; }
|
||||
|
||||
public virtual DbSet<Person> People { get; set; }
|
||||
|
||||
public virtual DbSet<Registration> Registrations { get; set; }
|
||||
|
||||
public virtual DbSet<Sport> Sports { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Country>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Code);
|
||||
|
||||
entity.ToTable("Country");
|
||||
|
||||
entity.HasIndex(e => e.Name, "UQ_Country_Name").IsUnique();
|
||||
|
||||
entity.Property(e => e.Code)
|
||||
.HasMaxLength(3)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.Alpha3)
|
||||
.HasMaxLength(3)
|
||||
.IsUnicode(false)
|
||||
.IsFixedLength();
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Event>(entity =>
|
||||
{
|
||||
entity.ToTable("Event");
|
||||
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(150)
|
||||
.IsUnicode(false);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Person>(entity =>
|
||||
{
|
||||
entity.ToTable("Person");
|
||||
|
||||
entity.HasIndex(e => new { e.DocumentNumber, e.CountryCode }, "UQ_Person_DocumentNumber_CountryCode").IsUnique();
|
||||
|
||||
entity.Property(e => e.AddressCountry)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.AddressLine)
|
||||
.HasMaxLength(200)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.City)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.ContactPhone)
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.CountryCode)
|
||||
.HasMaxLength(3)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.DocumentNumber)
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.Email)
|
||||
.HasMaxLength(255)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.FirstName)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.FirstNameTranscription)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.LastName)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.LastNameTranscription)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
entity.Property(e => e.PostalCode)
|
||||
.HasMaxLength(20)
|
||||
.IsUnicode(false);
|
||||
|
||||
entity.HasOne(d => d.CountryCodeNavigation).WithMany(p => p.People)
|
||||
.HasForeignKey(d => d.CountryCode)
|
||||
.OnDelete(DeleteBehavior.ClientSetNull)
|
||||
.HasConstraintName("FK_Person_Country");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Registration>(entity =>
|
||||
{
|
||||
entity.ToTable("Registration");
|
||||
|
||||
entity.HasIndex(e => new { e.PersonId, e.SportId, e.EventId }, "UQ_Registration_PersonId_SportId_EventId").IsUnique();
|
||||
|
||||
entity.Property(e => e.RegisteredAt).HasDefaultValueSql("(sysdatetime())", "DF_Registration_RegisteredAt");
|
||||
|
||||
entity.HasOne(d => d.Event).WithMany(p => p.Registrations)
|
||||
.HasForeignKey(d => d.EventId)
|
||||
.HasConstraintName("FK_Registration_Event");
|
||||
|
||||
entity.HasOne(d => d.Person).WithMany(p => p.Registrations)
|
||||
.HasForeignKey(d => d.PersonId)
|
||||
.HasConstraintName("FK_Registration_Person");
|
||||
|
||||
entity.HasOne(d => d.Sport).WithMany(p => p.Registrations)
|
||||
.HasForeignKey(d => d.SportId)
|
||||
.HasConstraintName("FK_Registration_Sport");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Sport>(entity =>
|
||||
{
|
||||
entity.ToTable("Sport");
|
||||
|
||||
entity.HasIndex(e => e.Name, "UQ_Sport_Name").IsUnique();
|
||||
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false);
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
166
DataAccess/EF_Demo/Data/Postgres/EventsContext.cs
Normal file
166
DataAccess/EF_Demo/Data/Postgres/EventsContext.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using EF_Demo.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EF_Demo.Data.Postgres;
|
||||
|
||||
public partial class EventsContext : DbContext
|
||||
{
|
||||
public EventsContext(DbContextOptions<EventsContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<Country> Countries { get; set; }
|
||||
|
||||
public virtual DbSet<Event> Events { get; set; }
|
||||
|
||||
public virtual DbSet<Person> People { get; set; }
|
||||
|
||||
public virtual DbSet<Registration> Registrations { get; set; }
|
||||
|
||||
public virtual DbSet<Sport> Sports { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Country>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Code).HasName("country_pkey");
|
||||
|
||||
entity.ToTable("country");
|
||||
|
||||
entity.HasIndex(e => e.Name, "country_name_key").IsUnique();
|
||||
|
||||
entity.Property(e => e.Code)
|
||||
.HasMaxLength(3)
|
||||
.HasColumnName("code");
|
||||
entity.Property(e => e.Alpha3)
|
||||
.HasMaxLength(3)
|
||||
.IsFixedLength()
|
||||
.HasColumnName("alpha3");
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("name");
|
||||
entity.Property(e => e.Translations)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("translations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Event>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("event_pkey");
|
||||
|
||||
entity.ToTable("event");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
entity.Property(e => e.EventDate).HasColumnName("event_date");
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(150)
|
||||
.HasColumnName("name");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Person>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("person_pkey");
|
||||
|
||||
entity.ToTable("person");
|
||||
|
||||
entity.HasIndex(e => new { e.DocumentNumber, e.CountryCode }, "person_document_number_country_code_key").IsUnique();
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
entity.Property(e => e.AddressCountry)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("address_country");
|
||||
entity.Property(e => e.AddressLine)
|
||||
.HasMaxLength(200)
|
||||
.HasColumnName("address_line");
|
||||
entity.Property(e => e.BirthDate).HasColumnName("birth_date");
|
||||
entity.Property(e => e.City)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("city");
|
||||
entity.Property(e => e.ContactPhone)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("contact_phone");
|
||||
entity.Property(e => e.CountryCode)
|
||||
.HasMaxLength(3)
|
||||
.HasColumnName("country_code");
|
||||
entity.Property(e => e.DocumentNumber)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("document_number");
|
||||
entity.Property(e => e.Email)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("email");
|
||||
entity.Property(e => e.FirstName)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("first_name");
|
||||
entity.Property(e => e.FirstNameTranscription)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("first_name_transcription");
|
||||
entity.Property(e => e.LastName)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("last_name");
|
||||
entity.Property(e => e.LastNameTranscription)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("last_name_transcription");
|
||||
entity.Property(e => e.PostalCode)
|
||||
.HasMaxLength(20)
|
||||
.HasColumnName("postal_code");
|
||||
|
||||
entity.HasOne(d => d.CountryCodeNavigation).WithMany(p => p.People)
|
||||
.HasForeignKey(d => d.CountryCode)
|
||||
.OnDelete(DeleteBehavior.ClientSetNull)
|
||||
.HasConstraintName("person_country_code_fkey");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Registration>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("registration_pkey");
|
||||
|
||||
entity.ToTable("registration");
|
||||
|
||||
entity.HasIndex(e => new { e.PersonId, e.SportId, e.EventId }, "registration_person_id_sport_id_event_id_key").IsUnique();
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
entity.Property(e => e.EventId).HasColumnName("event_id");
|
||||
entity.Property(e => e.PersonId).HasColumnName("person_id");
|
||||
entity.Property(e => e.RegisteredAt)
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("registered_at");
|
||||
entity.Property(e => e.SportId).HasColumnName("sport_id");
|
||||
|
||||
entity.HasOne(d => d.Event).WithMany(p => p.Registrations)
|
||||
.HasForeignKey(d => d.EventId)
|
||||
.HasConstraintName("registration_event_id_fkey");
|
||||
|
||||
entity.HasOne(d => d.Person).WithMany(p => p.Registrations)
|
||||
.HasForeignKey(d => d.PersonId)
|
||||
.HasConstraintName("registration_person_id_fkey");
|
||||
|
||||
entity.HasOne(d => d.Sport).WithMany(p => p.Registrations)
|
||||
.HasForeignKey(d => d.SportId)
|
||||
.HasConstraintName("registration_sport_id_fkey");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Sport>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("sport_pkey");
|
||||
|
||||
entity.ToTable("sport");
|
||||
|
||||
entity.HasIndex(e => e.Name, "sport_name_key").IsUnique();
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("name");
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
110
DataAccess/EF_Demo/Demo.cs
Normal file
110
DataAccess/EF_Demo/Demo.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
#if POSTGRES
|
||||
using EF_Demo.Data.Postgres;
|
||||
#else
|
||||
using EF_Demo.Data.MSSQL;
|
||||
#endif
|
||||
|
||||
using EF_Demo.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace EF_Demo;
|
||||
|
||||
internal class Demo
|
||||
{
|
||||
internal static int? AddEvent(IServiceProvider serviceProvider, string eventName, DateOnly eventDate)
|
||||
{
|
||||
ILogger logger = serviceProvider.GetRequiredService<ILogger<Demo>>();
|
||||
try
|
||||
{
|
||||
using var ctx = serviceProvider.GetRequiredService<EventsContext>();
|
||||
Event @event = new()
|
||||
{
|
||||
Name = eventName,
|
||||
EventDate = eventDate
|
||||
};
|
||||
ctx.Add(@event); //or ctx.Events.Add(@event) or ctx.Set<Event>().Add(@event);
|
||||
ctx.SaveChanges();
|
||||
logger.LogInformation($"Event {eventName} successfully added with id {@event.Id}");
|
||||
return @event.Id;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
logger.LogError($"Error adding event #{eventName}: {exc.CompleteExceptionMessage()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DeleteEvent(IServiceProvider serviceProvider, int eventId)
|
||||
{
|
||||
ILogger logger = serviceProvider.GetRequiredService<ILogger<Demo>>();
|
||||
try
|
||||
{
|
||||
using var ctx = serviceProvider.GetRequiredService<EventsContext>();
|
||||
Event? @event = ctx.Events.Find(eventId);
|
||||
if (@event != null)
|
||||
{
|
||||
ctx.Remove(@event); //or ctx.Entry(product).State = EntityState.Deleted;
|
||||
ctx.SaveChanges();
|
||||
logger.LogInformation($"Event {@event.Name} deleted");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"Event #{eventId} does not exists");
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
logger.LogError($"Error deleting event #{eventId}: {exc.CompleteExceptionMessage()}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void PostponeEvent(IServiceProvider serviceProvider, int eventId, int days)
|
||||
{
|
||||
ILogger logger = serviceProvider.GetRequiredService<ILogger<Demo>>();
|
||||
try
|
||||
{
|
||||
using var ctx = serviceProvider.GetRequiredService<EventsContext>();
|
||||
Event? @event = ctx.Events.Find(eventId);
|
||||
if (@event != null)
|
||||
{
|
||||
@event.EventDate = @event.EventDate.AddDays(days);
|
||||
ctx.SaveChanges();
|
||||
logger.LogInformation($"Event {@event.Name} postoponed to {@event.EventDate:dd.MM.yyyy.}");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogWarning($"Event #{eventId} does not exists");
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
logger?.LogError($"Error trying to change evenbt #{eventId}: {exc.CompleteExceptionMessage()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print all people born in the provided year, ordered by country, and then by transliterated last name, and first name
|
||||
/// query is projected to an anonymous class
|
||||
/// </summary>
|
||||
internal static void PrintPeople(IServiceProvider serviceProvider, int year)
|
||||
{
|
||||
using var ctx = serviceProvider.GetRequiredService<EventsContext>();
|
||||
var query = ctx.People
|
||||
.Where(p => p.BirthDate.Year == year)
|
||||
.OrderBy(p => p.CountryCodeNavigation.Name)
|
||||
.ThenBy(p => p.LastNameTranscription)
|
||||
.ThenBy(p => p.FirstNameTranscription)
|
||||
.Select(p => new
|
||||
{
|
||||
p.FirstName, p.LastName,
|
||||
p.FirstNameTranscription, p.LastNameTranscription,
|
||||
p.BirthDate,
|
||||
Country = p.CountryCodeNavigation.Name
|
||||
});
|
||||
foreach (var p in query)
|
||||
{
|
||||
Console.WriteLine($"{p.FirstName} {p.LastName} ({p.FirstNameTranscription} {p.LastNameTranscription}), {p.Country} {p.BirthDate:dd.MM.yyyy.}");
|
||||
}
|
||||
}
|
||||
}
|
||||
35
DataAccess/EF_Demo/EF_Demo.csproj
Normal file
35
DataAccess/EF_Demo/EF_Demo.csproj
Normal file
@@ -0,0 +1,35 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<UserSecretsId>PI</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>$(DefineConstants);POSTGRES</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.6">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.6" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
18
DataAccess/EF_Demo/ExceptionExtensions.cs
Normal file
18
DataAccess/EF_Demo/ExceptionExtensions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Text;
|
||||
|
||||
namespace EF_Demo;
|
||||
|
||||
public static class ExceptionExtensions
|
||||
{
|
||||
public static string CompleteExceptionMessage(this Exception exc)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(exc.Message);
|
||||
while (exc.InnerException != null)
|
||||
{
|
||||
exc = exc.InnerException;
|
||||
sb.AppendLine();
|
||||
sb.Append(exc.Message);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
19
DataAccess/EF_Demo/Models/Country.cs
Normal file
19
DataAccess/EF_Demo/Models/Country.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EF_Demo.Models;
|
||||
|
||||
public partial class Country
|
||||
{
|
||||
public string Code { get; set; } = null!;
|
||||
|
||||
public string Alpha3 { get; set; } = null!;
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public string? Translations { get; set; }
|
||||
|
||||
public virtual ICollection<Person> People { get; set; } = new List<Person>();
|
||||
}
|
||||
17
DataAccess/EF_Demo/Models/Event.cs
Normal file
17
DataAccess/EF_Demo/Models/Event.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EF_Demo.Models;
|
||||
|
||||
public partial class Event
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public DateOnly EventDate { get; set; }
|
||||
|
||||
public virtual ICollection<Registration> Registrations { get; set; } = new List<Registration>();
|
||||
}
|
||||
41
DataAccess/EF_Demo/Models/Person.cs
Normal file
41
DataAccess/EF_Demo/Models/Person.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EF_Demo.Models;
|
||||
|
||||
public partial class Person
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string FirstName { get; set; } = null!;
|
||||
|
||||
public string LastName { get; set; } = null!;
|
||||
|
||||
public string FirstNameTranscription { get; set; } = null!;
|
||||
|
||||
public string LastNameTranscription { get; set; } = null!;
|
||||
|
||||
public string AddressLine { get; set; } = null!;
|
||||
|
||||
public string PostalCode { get; set; } = null!;
|
||||
|
||||
public string City { get; set; } = null!;
|
||||
|
||||
public string AddressCountry { get; set; } = null!;
|
||||
|
||||
public string Email { get; set; } = null!;
|
||||
|
||||
public string ContactPhone { get; set; } = null!;
|
||||
|
||||
public DateOnly BirthDate { get; set; }
|
||||
|
||||
public string DocumentNumber { get; set; } = null!;
|
||||
|
||||
public string CountryCode { get; set; } = null!;
|
||||
|
||||
public virtual Country CountryCodeNavigation { get; set; } = null!;
|
||||
|
||||
public virtual ICollection<Registration> Registrations { get; set; } = new List<Registration>();
|
||||
}
|
||||
25
DataAccess/EF_Demo/Models/Registration.cs
Normal file
25
DataAccess/EF_Demo/Models/Registration.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EF_Demo.Models;
|
||||
|
||||
public partial class Registration
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PersonId { get; set; }
|
||||
|
||||
public int SportId { get; set; }
|
||||
|
||||
public int EventId { get; set; }
|
||||
|
||||
public DateTime RegisteredAt { get; set; }
|
||||
|
||||
public virtual Event Event { get; set; } = null!;
|
||||
|
||||
public virtual Person Person { get; set; } = null!;
|
||||
|
||||
public virtual Sport Sport { get; set; } = null!;
|
||||
}
|
||||
15
DataAccess/EF_Demo/Models/Sport.cs
Normal file
15
DataAccess/EF_Demo/Models/Sport.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EF_Demo.Models;
|
||||
|
||||
public partial class Sport
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public virtual ICollection<Registration> Registrations { get; set; } = new List<Registration>();
|
||||
}
|
||||
21
DataAccess/EF_Demo/Program.cs
Normal file
21
DataAccess/EF_Demo/Program.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using EF_Demo;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
||||
|
||||
using ServiceProvider serviceProvider = DISetup.BuildDI();
|
||||
|
||||
Demo.PrintPeople(serviceProvider, 1976);
|
||||
Util.EnterToContinue();
|
||||
|
||||
int? eventId = Demo.AddEvent(serviceProvider, "Spring festival", new DateOnly(2026, 4, 30));
|
||||
Util.EnterToContinue();
|
||||
|
||||
if (eventId.HasValue)
|
||||
{
|
||||
Demo.PostponeEvent(serviceProvider, eventId.Value, days: 5);
|
||||
Util.EnterToContinue();
|
||||
|
||||
Demo.DeleteEvent(serviceProvider, eventId.Value);
|
||||
Util.EnterToContinue(clearConsole: false);
|
||||
}
|
||||
21
DataAccess/EF_Demo/Util.cs
Normal file
21
DataAccess/EF_Demo/Util.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace EF_Demo;
|
||||
|
||||
public static class Util
|
||||
{
|
||||
public static void EnterToContinue(bool clearConsole = true)
|
||||
{
|
||||
Console.WriteLine("ENTER to continue");
|
||||
Console.ReadLine();
|
||||
if (clearConsole)
|
||||
{
|
||||
Console.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static int ReadNumber()
|
||||
{
|
||||
int number;
|
||||
while (!int.TryParse(Console.ReadLine(), out number)) ;
|
||||
return number;
|
||||
}
|
||||
}
|
||||
16
DataAccess/EF_Demo/appsettings.json
Normal file
16
DataAccess/EF_Demo/appsettings.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"EventsMssql": "Data Source=.,3030;Initial Catalog=Events;use-secrets.json-to-set-username-and-password;TrustServerCertificate=True",
|
||||
"EventsPostgres": "Host=localhost;Database=events;use-secrets.json-to-set-username-and-password;Persist Security Info=True"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning",
|
||||
"System": "Error",
|
||||
"Microsoft": "Error",
|
||||
"Microsoft.EntityFrameworkCore.Database.Command": "Information",
|
||||
"EF_Demo.Demo": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
70
DataAccess/EF_Demo/efpt.mssql.config.json
Normal file
70
DataAccess/EF_Demo/efpt.mssql.config.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"CodeGenerationMode": 6,
|
||||
"ContextClassName": "EventsContext",
|
||||
"ContextNamespace": null,
|
||||
"FilterSchemas": false,
|
||||
"IncludeConnectionString": false,
|
||||
"IrregularWords": null,
|
||||
"MinimumProductVersion": "2.6.1465",
|
||||
"ModelNamespace": null,
|
||||
"OutputContextPath": "Data\/MSSQL",
|
||||
"OutputPath": "Models",
|
||||
"PluralRules": null,
|
||||
"PreserveCasingWithRegex": true,
|
||||
"ProjectRootNamespace": "EF_Demo",
|
||||
"Schemas": null,
|
||||
"SelectedHandlebarsLanguage": 2,
|
||||
"SelectedToBeGenerated": 0,
|
||||
"SingularRules": null,
|
||||
"T4TemplatePath": null,
|
||||
"Tables": [
|
||||
{
|
||||
"Name": "[dbo].[Country]",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "[dbo].[Event]",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "[dbo].[Person]",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "[dbo].[Registration]",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "[dbo].[Sport]",
|
||||
"ObjectType": 0
|
||||
}
|
||||
],
|
||||
"UiHint": null,
|
||||
"UncountableWords": null,
|
||||
"UseAsyncStoredProcedureCalls": true,
|
||||
"UseBoolPropertiesWithoutDefaultSql": false,
|
||||
"UseDatabaseNames": false,
|
||||
"UseDatabaseNamesForRoutines": true,
|
||||
"UseDateOnlyTimeOnly": true,
|
||||
"UseDbContextSplitting": false,
|
||||
"UseDecimalDataAnnotationForSprocResult": true,
|
||||
"UseFluentApiOnly": true,
|
||||
"UseHandleBars": false,
|
||||
"UseHierarchyId": false,
|
||||
"UseInflector": true,
|
||||
"UseInternalAccessModifiersForSprocsAndFunctions": false,
|
||||
"UseLegacyPluralizer": false,
|
||||
"UseManyToManyEntity": false,
|
||||
"UseNoDefaultConstructor": true,
|
||||
"UseNoNavigations": false,
|
||||
"UseNoObjectFilter": false,
|
||||
"UseNodaTime": false,
|
||||
"UseNullableReferences": true,
|
||||
"UsePrefixNavigationNaming": false,
|
||||
"UseSchemaFolders": false,
|
||||
"UseSchemaNamespaces": false,
|
||||
"UseSpatial": false,
|
||||
"UseT4": false,
|
||||
"UseT4Split": false,
|
||||
"UseTypedTvpParameters": true
|
||||
}
|
||||
70
DataAccess/EF_Demo/efpt.postgres.config.json
Normal file
70
DataAccess/EF_Demo/efpt.postgres.config.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"CodeGenerationMode": 6,
|
||||
"ContextClassName": "EventsContext",
|
||||
"ContextNamespace": null,
|
||||
"FilterSchemas": false,
|
||||
"IncludeConnectionString": false,
|
||||
"IrregularWords": null,
|
||||
"MinimumProductVersion": "2.6.1465",
|
||||
"ModelNamespace": null,
|
||||
"OutputContextPath": "Data\/Postgres",
|
||||
"OutputPath": "Models",
|
||||
"PluralRules": null,
|
||||
"PreserveCasingWithRegex": true,
|
||||
"ProjectRootNamespace": "EF_Demo",
|
||||
"Schemas": null,
|
||||
"SelectedHandlebarsLanguage": 2,
|
||||
"SelectedToBeGenerated": 0,
|
||||
"SingularRules": null,
|
||||
"T4TemplatePath": null,
|
||||
"Tables": [
|
||||
{
|
||||
"Name": "public.country",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "public.event",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "public.person",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "public.registration",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "public.sport",
|
||||
"ObjectType": 0
|
||||
}
|
||||
],
|
||||
"UiHint": null,
|
||||
"UncountableWords": null,
|
||||
"UseAsyncStoredProcedureCalls": true,
|
||||
"UseBoolPropertiesWithoutDefaultSql": false,
|
||||
"UseDatabaseNames": false,
|
||||
"UseDatabaseNamesForRoutines": true,
|
||||
"UseDateOnlyTimeOnly": true,
|
||||
"UseDbContextSplitting": false,
|
||||
"UseDecimalDataAnnotationForSprocResult": true,
|
||||
"UseFluentApiOnly": true,
|
||||
"UseHandleBars": false,
|
||||
"UseHierarchyId": false,
|
||||
"UseInflector": true,
|
||||
"UseInternalAccessModifiersForSprocsAndFunctions": false,
|
||||
"UseLegacyPluralizer": false,
|
||||
"UseManyToManyEntity": false,
|
||||
"UseNoDefaultConstructor": true,
|
||||
"UseNoNavigations": false,
|
||||
"UseNoObjectFilter": false,
|
||||
"UseNodaTime": false,
|
||||
"UseNullableReferences": true,
|
||||
"UsePrefixNavigationNaming": false,
|
||||
"UseSchemaFolders": false,
|
||||
"UseSchemaNamespaces": false,
|
||||
"UseSpatial": false,
|
||||
"UseT4": false,
|
||||
"UseT4Split": false,
|
||||
"UseTypedTvpParameters": true
|
||||
}
|
||||
10
DefensiveProgramming/Barricades/Barricades.csproj
Normal file
10
DefensiveProgramming/Barricades/Barricades.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
53
DefensiveProgramming/Barricades/Course.cs
Normal file
53
DefensiveProgramming/Barricades/Course.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Barricades;
|
||||
|
||||
class Course(string name)
|
||||
{
|
||||
public string Name { get; private set; } = name;
|
||||
|
||||
//Consider why is dictionary private variable, and why not a property!
|
||||
//indexer serves as a barricade
|
||||
|
||||
private Dictionary<string, int> grades = new Dictionary<string, int>();
|
||||
|
||||
/// <summary>
|
||||
/// Assign the new grade to the student.
|
||||
/// Old value (if had existed) is replaced.
|
||||
/// </summary>
|
||||
/// <param name="name">Student's name</param>
|
||||
/// <returns>The student's grade or -1 if the student does not have a grade</returns>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">Thrown if value is not valid grade [1-5]</exception>
|
||||
public int this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
//what if there is no student's name in the dictionary
|
||||
//throw exception, return special value? See error handling techniques
|
||||
bool exists = grades.TryGetValue(name, out int grade);
|
||||
return exists ? grade : -1;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value < 1 || value > 5)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Invalid grade {value}. It shoud be from 1 to 5");
|
||||
}
|
||||
|
||||
grades[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public double AverageGrade()
|
||||
{
|
||||
int sum = 0;
|
||||
foreach (var pair in grades)
|
||||
{
|
||||
int grade = pair.Value;
|
||||
Debug.Assert(grade >= 1 && grade <= 5,
|
||||
$"Invalid grade in dictionary {pair.Key} = {pair.Value}. This should never happens!");
|
||||
sum += grade;
|
||||
}
|
||||
return grades.Count > 0 ? (double)sum / grades.Count : 0;
|
||||
}
|
||||
}
|
||||
14
DefensiveProgramming/Barricades/Program.cs
Normal file
14
DefensiveProgramming/Barricades/Program.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Barricades;
|
||||
using System.Text;
|
||||
|
||||
Console.OutputEncoding = Encoding.UTF8;
|
||||
|
||||
Course c = new Course("PI");
|
||||
c["Pero"] = 2;
|
||||
c["Ana"] = 5;
|
||||
c["Ivan"] = 5;
|
||||
c["Marko"] = 1;
|
||||
c["Luka"] = 3;
|
||||
//c["Marija"] = -7; //should throw an exception
|
||||
Console.WriteLine("Average grade: " + c.AverageGrade());
|
||||
Console.WriteLine("Šime has grade: " + c["Šime"]); //prints -1
|
||||
14
DefensiveProgramming/Conditional/Conditional.csproj
Normal file
14
DefensiveProgramming/Conditional/Conditional.csproj
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEMO</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
20
DefensiveProgramming/Conditional/Program.cs
Normal file
20
DefensiveProgramming/Conditional/Program.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
#define DEMO2
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
Console.WriteLine("Start");
|
||||
|
||||
#if DEMO
|
||||
Console.WriteLine("Print something...");
|
||||
#endif
|
||||
|
||||
CheckSomething();
|
||||
|
||||
Console.WriteLine("End");
|
||||
|
||||
[Conditional("DEMO")]
|
||||
static void CheckSomething()
|
||||
{
|
||||
Console.WriteLine("Print from CheckSomething method");
|
||||
}
|
||||
|
||||
49
DefensiveProgramming/DefensiveProgramming.sln
Normal file
49
DefensiveProgramming/DefensiveProgramming.sln
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30413.136
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Barricades", "Barricades\Barricades.csproj", "{EC679AD5-7BC4-49E3-B44C-DB4750FBC179}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Conditional", "Conditional\Conditional.csproj", "{997943C5-5BA1-4BC4-A2C9-AAE0CA3BB934}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Using", "Using\Using.csproj", "{227D0323-D09C-44D5-B1CD-C2DD27CFC4DB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logging", "Logging\Logging.csproj", "{F7534F26-8855-4CA0-BEBC-C60ED2D1E7B1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Secrets", "Secrets\Secrets.csproj", "{78BFB6E2-A394-4CA1-A947-0CC2D8CDE421}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EC679AD5-7BC4-49E3-B44C-DB4750FBC179}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EC679AD5-7BC4-49E3-B44C-DB4750FBC179}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EC679AD5-7BC4-49E3-B44C-DB4750FBC179}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EC679AD5-7BC4-49E3-B44C-DB4750FBC179}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{997943C5-5BA1-4BC4-A2C9-AAE0CA3BB934}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{997943C5-5BA1-4BC4-A2C9-AAE0CA3BB934}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{997943C5-5BA1-4BC4-A2C9-AAE0CA3BB934}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{997943C5-5BA1-4BC4-A2C9-AAE0CA3BB934}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{227D0323-D09C-44D5-B1CD-C2DD27CFC4DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{227D0323-D09C-44D5-B1CD-C2DD27CFC4DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{227D0323-D09C-44D5-B1CD-C2DD27CFC4DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{227D0323-D09C-44D5-B1CD-C2DD27CFC4DB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F7534F26-8855-4CA0-BEBC-C60ED2D1E7B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F7534F26-8855-4CA0-BEBC-C60ED2D1E7B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F7534F26-8855-4CA0-BEBC-C60ED2D1E7B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F7534F26-8855-4CA0-BEBC-C60ED2D1E7B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{78BFB6E2-A394-4CA1-A947-0CC2D8CDE421}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{78BFB6E2-A394-4CA1-A947-0CC2D8CDE421}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{78BFB6E2-A394-4CA1-A947-0CC2D8CDE421}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{78BFB6E2-A394-4CA1-A947-0CC2D8CDE421}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0C808F1C-DC45-4A56-8D42-13C593C59A78}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
60
DefensiveProgramming/Logging/DataLoader.cs
Normal file
60
DefensiveProgramming/Logging/DataLoader.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Logging;
|
||||
|
||||
public class DataLoader : IDataLoader
|
||||
{
|
||||
private readonly ILogger<DataLoader> logger;
|
||||
|
||||
public DataLoader(ILogger<DataLoader> logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public List<(string, DateOnly)> LoadData(string filename)
|
||||
{
|
||||
List<(string, DateOnly)> list = new();
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
string message = $"File {filename} does not exist";
|
||||
logger.LogError(message);
|
||||
throw new FileNotFoundException(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
//use File.ReadAllLines for small files
|
||||
using (var reader = new StreamReader(File.OpenRead(filename)))
|
||||
{
|
||||
string? line;
|
||||
while((line = reader.ReadLine()) != null) {
|
||||
string pattern = "[0-3]?[0-9].[0-3]?[0-9].[0-9]{4}.";
|
||||
var match = Regex.Match(line, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
string datetext = line.Substring(match.Index, match.Length);
|
||||
if (DateOnly.TryParseExact(datetext, "d.M.yyyy.", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly date))
|
||||
{
|
||||
var item = (line.Remove(match.Index, match.Length).Trim(), date);
|
||||
logger.LogTrace(item.ToString());
|
||||
list.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Invalid date in line: " + line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("No date found in line: " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
9
DefensiveProgramming/Logging/IDataLoader.cs
Normal file
9
DefensiveProgramming/Logging/IDataLoader.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Logging;
|
||||
|
||||
public interface IDataLoader
|
||||
{
|
||||
List<(string, DateOnly)> LoadData(string filename);
|
||||
}
|
||||
30
DefensiveProgramming/Logging/Logging.csproj
Normal file
30
DefensiveProgramming/Logging/Logging.csproj
Normal file
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.6" />
|
||||
<PackageReference Include="NLog" Version="6.1.2" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="6.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="data.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="nlog.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
45
DefensiveProgramming/Logging/Program.cs
Normal file
45
DefensiveProgramming/Logging/Program.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog.Extensions.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Logging;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
using (var serviceProvider = BuildDI())
|
||||
{
|
||||
var dataLoader = serviceProvider.GetRequiredService<IDataLoader>();
|
||||
var list = dataLoader.LoadData("data.txt");
|
||||
var sortQuery = list.OrderByDescending(t => t.Item2)
|
||||
.ThenBy(t => t.Item1);
|
||||
|
||||
Console.WriteLine("Valid data: ");
|
||||
foreach (var item in sortQuery)
|
||||
{
|
||||
Console.WriteLine($"{item.Item2:yyyy-MM-dd} {item.Item1}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ServiceProvider BuildDI()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.Build();
|
||||
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
var provider = services.AddLogging(configure => {
|
||||
configure.AddConfiguration(configuration.GetSection("Logging"));
|
||||
configure.AddConsole();
|
||||
configure.AddNLog(new NLogProviderOptions { RemoveLoggerFactoryFilter = false });
|
||||
})
|
||||
.AddTransient<IDataLoader, DataLoader>()
|
||||
.BuildServiceProvider();
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
9
DefensiveProgramming/Logging/appsettings.json
Normal file
9
DefensiveProgramming/Logging/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Trace",
|
||||
"System": "Warning",
|
||||
"Microsoft": "Trace"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
DefensiveProgramming/Logging/data.txt
Normal file
5
DefensiveProgramming/Logging/data.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Ana 22.5.1988.
|
||||
01.03.1995. Ivan John
|
||||
Ema
|
||||
Mario 15.13.1980.
|
||||
Klara 11.07.1998.
|
||||
31
DefensiveProgramming/Logging/nlog.config
Normal file
31
DefensiveProgramming/Logging/nlog.config
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
autoReload="true"
|
||||
internalLogLevel="Warn"
|
||||
internalLogFile="logs/internal-nlog.txt">
|
||||
|
||||
<!-- the targets to write to -->
|
||||
<targets>
|
||||
<!-- write logs to file -->
|
||||
<target xsi:type="File" name="allfile" fileName="logs/nlog-all-${shortdate}.log"
|
||||
layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${logger}|${uppercase:${level}}|${message} ${exception}" />
|
||||
|
||||
<!-- another file log, only own logs. Uses some ASP.NET core renderers -->
|
||||
<target xsi:type="File" name="ownFile" fileName="logs/nlog-own-${shortdate}.log"
|
||||
layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${logger}|${uppercase:${level}}| ${message} ${exception}" />
|
||||
|
||||
<!-- write to the void aka just remove -->
|
||||
<target xsi:type="Null" name="blackhole" />
|
||||
</targets>
|
||||
|
||||
<!-- rules to map from logger name to target -->
|
||||
<rules>
|
||||
<!--All logs, including from Microsoft-->
|
||||
<logger name="*" minlevel="Trace" writeTo="allfile" />
|
||||
|
||||
<!--Skip Microsoft logs and so log only own logs-->
|
||||
<logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
|
||||
<logger name="*" minlevel="Information" writeTo="ownFile" />
|
||||
</rules>
|
||||
</nlog>
|
||||
8
DefensiveProgramming/Secrets/Demo.cs
Normal file
8
DefensiveProgramming/Secrets/Demo.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Secrets;
|
||||
|
||||
public class Demo
|
||||
{
|
||||
public int Key0 { get; set; }
|
||||
public string? Key1 { get; set; }
|
||||
public string? Key2 { get; set; }
|
||||
}
|
||||
23
DefensiveProgramming/Secrets/Program.cs
Normal file
23
DefensiveProgramming/Secrets/Program.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Secrets;
|
||||
|
||||
var enumerator = Environment.GetEnvironmentVariables().GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
Console.WriteLine($"{enumerator.Key} = {enumerator.Value}");
|
||||
}
|
||||
Console.WriteLine("----------------------------");
|
||||
IConfiguration configuration = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json") //order is important!
|
||||
.AddJsonFile("missing_one.json", optional: true) //
|
||||
.AddEnvironmentVariables() // include Package Microsoft.Extensions.Configuration.EnvironmentVariables
|
||||
.AddUserSecrets("PI-Secrets") //package Microsoft.Extensions.Configuration.UserSecrets
|
||||
.Build();
|
||||
|
||||
Console.WriteLine($"Custom env variable using configuration = " + configuration["CustomEnvValue"]);
|
||||
Console.WriteLine($"Name = " + configuration["Name"]);
|
||||
Console.WriteLine($"Key0 = " + configuration["Demo:Key0"]); //or Demo__Key0
|
||||
|
||||
Demo? demo = configuration.GetSection("Demo").Get<Demo>(); // package Microsoft.Extensions.Configuration.Binder
|
||||
Console.WriteLine($"Key1 = " + demo?.Key1);
|
||||
Console.WriteLine($"Key2 = " + demo?.Key2);
|
||||
10
DefensiveProgramming/Secrets/Properties/launchSettings.json
Normal file
10
DefensiveProgramming/Secrets/Properties/launchSettings.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Secrets": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"CustomEnvValue": "Demo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
DefensiveProgramming/Secrets/Secrets.csproj
Normal file
23
DefensiveProgramming/Secrets/Secrets.csproj
Normal file
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<UserSecretsId>PI</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
7
DefensiveProgramming/Secrets/appsettings.json
Normal file
7
DefensiveProgramming/Secrets/appsettings.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"Name": "Bob",
|
||||
"Demo": {
|
||||
"Key0": 123,
|
||||
"Key1": "something that should not be publicly available"
|
||||
}
|
||||
}
|
||||
16
DefensiveProgramming/Using/C.cs
Normal file
16
DefensiveProgramming/Using/C.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Using;
|
||||
|
||||
class C : IDisposable
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
Console.WriteLine("** {0} : Dispose **", Id);
|
||||
}
|
||||
|
||||
public C(string id)
|
||||
{
|
||||
Id = id;
|
||||
Console.WriteLine("----> {0} : Ctor", Id);
|
||||
}
|
||||
}
|
||||
20
DefensiveProgramming/Using/Program.cs
Normal file
20
DefensiveProgramming/Using/Program.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Using;
|
||||
|
||||
try
|
||||
{
|
||||
C a1 = new C("A1");
|
||||
|
||||
using (C b2 = new C("B2"))
|
||||
using (C d4 = new C("D4"))
|
||||
{
|
||||
C c3 = new C("C3");
|
||||
throw new Exception("It is time for an exception");
|
||||
}
|
||||
a1.Dispose();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Console.WriteLine("Exc: " + exc.Message);
|
||||
//throw exc;
|
||||
//throw;
|
||||
}
|
||||
10
DefensiveProgramming/Using/Using.csproj
Normal file
10
DefensiveProgramming/Using/Using.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Inheritance\Inheritance.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
49
SomeOfCSharpFeatures/CovarianceContravariance/Program.cs
Normal file
49
SomeOfCSharpFeatures/CovarianceContravariance/Program.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Inheritance;
|
||||
|
||||
namespace CovarianceContravariance;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
List<Car> cars = new List<Car>{
|
||||
new Car("Coupe", 200, 3),
|
||||
new Car("Wagon", 100, 5),
|
||||
new Car("Limousine", 150, 4),
|
||||
new ElectricCar("Electric Hatchback", 148, 5, 40)
|
||||
};
|
||||
PrintVehicles(cars);
|
||||
|
||||
Comparison<Vehicle> comparisonFunction = (a, b) => -a.HorsePower.CompareTo(b.HorsePower);
|
||||
IComparer<Vehicle> comparer = Comparer<Vehicle>.Create(comparisonFunction);
|
||||
|
||||
PrintBetterCar(cars[2], cars[3], comparer);
|
||||
PrintBetterCar(cars.Skip(2).First(), cars.Last(), comparisonFunction);
|
||||
|
||||
PrintBetterCar(cars[2], cars[3], (a, b) => b.Doors - a.Doors);
|
||||
}
|
||||
|
||||
static void PrintVehicles(IEnumerable<Vehicle> vehicles)
|
||||
{
|
||||
foreach (var vehicle in vehicles)
|
||||
{
|
||||
Console.WriteLine("\t " + vehicle.Model);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintBetterCar(Car a, Car b, IComparer<Car> comparer)
|
||||
{
|
||||
int result = comparer.Compare(a, b);
|
||||
string betterModel = result <= 0 ? a.Model : b.Model;
|
||||
string worseModel = result <= 0 ? b.Model : a.Model;
|
||||
Console.WriteLine($"\t{betterModel} is better or equal than {worseModel}");
|
||||
}
|
||||
|
||||
static void PrintBetterCar(Car a, Car b, Comparison<Car> comparer)
|
||||
{
|
||||
int result = comparer(a, b);
|
||||
string betterModel = result <= 0 ? a.Model : b.Model;
|
||||
string worseModel = result <= 0 ? b.Model : a.Model;
|
||||
Console.WriteLine($"\t{betterModel} is better or equal than {worseModel}");
|
||||
}
|
||||
}
|
||||
10
SomeOfCSharpFeatures/Delegates/Delegates.csproj
Normal file
10
SomeOfCSharpFeatures/Delegates/Delegates.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
26
SomeOfCSharpFeatures/Delegates/MathTool.cs
Normal file
26
SomeOfCSharpFeatures/Delegates/MathTool.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Delegates;
|
||||
|
||||
public class MathTool
|
||||
{
|
||||
public static int Sum(int x, int y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
public static int Diff(int x, int y)
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
|
||||
public static void PrintSquare(int x)
|
||||
{
|
||||
Console.WriteLine("x^2 = " + x * x);
|
||||
}
|
||||
|
||||
public static void PrintSquareRoot(int x)
|
||||
{
|
||||
Console.WriteLine("sqrt(x) = " + Math.Sqrt(x));
|
||||
}
|
||||
}
|
||||
31
SomeOfCSharpFeatures/Delegates/Program.cs
Normal file
31
SomeOfCSharpFeatures/Delegates/Program.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace Delegates;
|
||||
|
||||
class Program
|
||||
{
|
||||
public delegate int MathFunction(int a, int b);
|
||||
public delegate void PrintFunction(int n);
|
||||
static void Main(string[] args)
|
||||
{
|
||||
int x = 16, y = 2;
|
||||
MathFunction mf = MathTool.Sum;
|
||||
Console.WriteLine("mf({0}, {1}) = {2}", x, y, mf(x, y));
|
||||
mf = MathTool.Diff;
|
||||
Console.WriteLine("mf({0}, {1}) = {2}", x, y, mf(x, y));
|
||||
PrintFunction pf = MathTool.PrintSquare;
|
||||
pf += MathTool.PrintSquareRoot;
|
||||
pf(x);
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
pf -= MathTool.PrintSquare;
|
||||
#pragma warning restore CS8601 // Possible null reference assignment.
|
||||
Console.WriteLine();
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
pf(y); //instead of pragma pf?.Invoke(y); can be used
|
||||
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
||||
|
||||
Func<int, int, int> func = MathTool.Sum;
|
||||
Console.WriteLine("func({0}, {1}) = {2}", x, y, func(x, y));
|
||||
|
||||
Action<int> action = MathTool.PrintSquare;
|
||||
action(x);
|
||||
}
|
||||
}
|
||||
16
SomeOfCSharpFeatures/Extensions/Activity.cs
Normal file
16
SomeOfCSharpFeatures/Extensions/Activity.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Extensions;
|
||||
|
||||
[Flags]
|
||||
public enum DayPeriod
|
||||
{
|
||||
Morning = 1, Evening = 2, Afternoon = 4, Night = 8
|
||||
}
|
||||
|
||||
public class Activity
|
||||
{
|
||||
public required string Person { get; set; }
|
||||
public int Hours { get; set; }
|
||||
public DayPeriod Period { get; set; }
|
||||
}
|
||||
18
SomeOfCSharpFeatures/Extensions/Extensions.cs
Normal file
18
SomeOfCSharpFeatures/Extensions/Extensions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Extensions;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static V GetOrCreate<K, V>(this Dictionary<K, V> dict, K key)
|
||||
where V : new()
|
||||
where K: notnull
|
||||
{
|
||||
if (!dict.TryGetValue(key, out V? value))
|
||||
{
|
||||
value = new V();
|
||||
dict[key] = value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
10
SomeOfCSharpFeatures/Extensions/Extensions.csproj
Normal file
10
SomeOfCSharpFeatures/Extensions/Extensions.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
61
SomeOfCSharpFeatures/Extensions/Program.cs
Normal file
61
SomeOfCSharpFeatures/Extensions/Program.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
namespace Extensions;
|
||||
|
||||
public enum Days
|
||||
{
|
||||
Monday, Tuesday, Wednesday,
|
||||
Thursday, Friday, Saturday, Sunday
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var dict = new Dictionary<Days, List<Activity>>();
|
||||
Activity a = new Activity
|
||||
{
|
||||
Person = "John",
|
||||
Hours = 3,
|
||||
Period = DayPeriod.Morning
|
||||
};
|
||||
dict.GetOrCreate(Days.Monday).Add(a);
|
||||
|
||||
a = new Activity
|
||||
{
|
||||
Person = "Mary",
|
||||
Hours = 12,
|
||||
Period = DayPeriod.Evening | DayPeriod.Night
|
||||
};
|
||||
dict.GetOrCreate(Days.Monday).Add(a);
|
||||
|
||||
a = new Activity
|
||||
{
|
||||
Person = "Peter",
|
||||
Hours = 8,
|
||||
Period = DayPeriod.Night
|
||||
};
|
||||
dict.GetOrCreate(Days.Tuesday).Add(a);
|
||||
|
||||
a = new Activity
|
||||
{
|
||||
Person = "Lisa",
|
||||
Hours = 5,
|
||||
Period = DayPeriod.Night | DayPeriod.Morning
|
||||
};
|
||||
dict.GetOrCreate(Days.Monday).Add(a);
|
||||
|
||||
int sum = SumNightActivity(dict);
|
||||
Console.WriteLine(sum);
|
||||
|
||||
}
|
||||
|
||||
private static int SumNightActivity(Dictionary<Days, List<Activity>> dict)
|
||||
{
|
||||
int sum = 0;
|
||||
foreach(var list in dict.Values)
|
||||
{
|
||||
sum += list.Where(a => (a.Period & DayPeriod.Night) == DayPeriod.Night)
|
||||
.Sum(a => a.Hours);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
31
SomeOfCSharpFeatures/Inheritance/Car.cs
Normal file
31
SomeOfCSharpFeatures/Inheritance/Car.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace Inheritance;
|
||||
|
||||
public class Car : Vehicle
|
||||
{
|
||||
public int Doors { get; set; }
|
||||
public string Color { get; set; } = "White";
|
||||
|
||||
public Car(string model, double horsePower, int doors)
|
||||
: base(model, horsePower)
|
||||
{
|
||||
Console.WriteLine($"Creating car {model}");
|
||||
this.Doors = doors;
|
||||
}
|
||||
|
||||
public void BuckleSeatBelt()
|
||||
{
|
||||
Console.WriteLine("Car {0} - seat belt buckled", Model);
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
Console.WriteLine("Start Car " + Model);
|
||||
}
|
||||
|
||||
public new void Stop()
|
||||
{
|
||||
Console.WriteLine("Stop Car " + Model);
|
||||
}
|
||||
}
|
||||
13
SomeOfCSharpFeatures/Inheritance/ElectricCar.cs
Normal file
13
SomeOfCSharpFeatures/Inheritance/ElectricCar.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Inheritance;
|
||||
|
||||
public class ElectricCar : Car
|
||||
{
|
||||
public int BatteryCapacity { get; set; }
|
||||
public int? Range { get; set; }
|
||||
|
||||
public ElectricCar(string model, double horsePower, int doors, int batteryCapacity) :
|
||||
base(model, horsePower, doors)
|
||||
{
|
||||
this.BatteryCapacity = batteryCapacity;
|
||||
}
|
||||
}
|
||||
10
SomeOfCSharpFeatures/Inheritance/Inheritance.csproj
Normal file
10
SomeOfCSharpFeatures/Inheritance/Inheritance.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
18
SomeOfCSharpFeatures/Inheritance/Motorbike.cs
Normal file
18
SomeOfCSharpFeatures/Inheritance/Motorbike.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Inheritance;
|
||||
|
||||
public class Motorbike : Vehicle
|
||||
{
|
||||
public bool HasSidecar { get; set; }
|
||||
public Motorbike(string model, double horsePower, bool sidecar)
|
||||
: base(model, horsePower)
|
||||
{
|
||||
Console.WriteLine($"Creating car {model}");
|
||||
this.HasSidecar = sidecar;
|
||||
}
|
||||
public override void Start()
|
||||
{
|
||||
Console.WriteLine("Start Motorbike " + Model);
|
||||
}
|
||||
}
|
||||
39
SomeOfCSharpFeatures/Inheritance/Program.cs
Normal file
39
SomeOfCSharpFeatures/Inheritance/Program.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Inheritance;
|
||||
|
||||
Vehicle v = new Vehicle("BMW Isseta", 9.5);
|
||||
v.Start();
|
||||
|
||||
Car car = new ElectricCar("Nissan Leaf", 148, 5, 40)
|
||||
{
|
||||
Range = 270
|
||||
};
|
||||
Console.WriteLine("car model = " + car.Model);
|
||||
Console.WriteLine("car horse power = " + car.HorsePower);
|
||||
Console.WriteLine("car number of doors = " + car.Doors);
|
||||
if (car is ElectricCar electric)
|
||||
{
|
||||
Console.WriteLine("car battery = " + electric.BatteryCapacity);
|
||||
if (electric.Range.HasValue)
|
||||
{
|
||||
Console.WriteLine("car range = " + electric.Range);
|
||||
}
|
||||
}
|
||||
|
||||
car.BuckleSeatBelt();
|
||||
car.Start();
|
||||
car.Stop();
|
||||
|
||||
((Vehicle)car).Start();
|
||||
((Vehicle)car).Stop();
|
||||
|
||||
// objekt tipa Motocikl
|
||||
Motorbike moto = new Motorbike("Ural", 41, true);
|
||||
Console.WriteLine("motorbike model {0} ", moto.Model);
|
||||
Console.WriteLine("motorbike horse power = " + moto.HorsePower);
|
||||
Console.WriteLine($"motorbike has sidecar? = {moto.HasSidecar}");
|
||||
|
||||
moto.Start();
|
||||
moto.Stop();
|
||||
|
||||
((Vehicle)moto).Start();
|
||||
((Vehicle)moto).Stop();
|
||||
26
SomeOfCSharpFeatures/Inheritance/Vehicle.cs
Normal file
26
SomeOfCSharpFeatures/Inheritance/Vehicle.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Inheritance;
|
||||
|
||||
public class Vehicle
|
||||
{
|
||||
public string Model { get; private set; }
|
||||
public double HorsePower { get; set; }
|
||||
|
||||
public Vehicle(string model, double horsePower)
|
||||
{
|
||||
Console.WriteLine("Creating vehicle " + model);
|
||||
this.Model = model;
|
||||
this.HorsePower = horsePower;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Console.WriteLine("Stop vehicle " + Model);
|
||||
}
|
||||
|
||||
public virtual void Start()
|
||||
{
|
||||
Console.WriteLine("Start vehicle " + Model);
|
||||
}
|
||||
}
|
||||
48
SomeOfCSharpFeatures/PropertiesIndexersRefOut/Program.cs
Normal file
48
SomeOfCSharpFeatures/PropertiesIndexersRefOut/Program.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using PropertiesIndexersRefOut;
|
||||
|
||||
Triple t1 = new Triple
|
||||
{
|
||||
First = 456,
|
||||
Second = 789
|
||||
};
|
||||
|
||||
Triple t2 = new Triple
|
||||
{
|
||||
First = 1000,
|
||||
Second = 2000
|
||||
};
|
||||
|
||||
Console.WriteLine("t1 + t2 = " + (t1 + t2));
|
||||
|
||||
CreateRandomTriple(t1, ref t2, out Triple t3);
|
||||
|
||||
Console.WriteLine("t1 = " + t1);
|
||||
Console.WriteLine("t2 = " + t2);
|
||||
Console.WriteLine("t3 = " + t3);
|
||||
|
||||
Console.WriteLine(t1["A", 1]);
|
||||
Console.WriteLine(t1["B", 2]);
|
||||
Console.WriteLine(t1["B", 3]);
|
||||
|
||||
PrintTriples(t1, t2, t3);
|
||||
|
||||
void PrintTriples(params Triple[] triples)
|
||||
{
|
||||
foreach (var t in triples)
|
||||
{
|
||||
Console.WriteLine(t);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateRandomTriple(Triple t1, ref Triple t2, out Triple t3)
|
||||
{
|
||||
Random r = new Random();
|
||||
t3 = new Triple
|
||||
{
|
||||
First = r.Next(t1.First, t2.Second),
|
||||
Second = r.Next(maxValue: t2.Second, minValue: t1.First)
|
||||
};
|
||||
|
||||
t1 = t3;
|
||||
t2 = t3;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
73
SomeOfCSharpFeatures/PropertiesIndexersRefOut/Triple.cs
Normal file
73
SomeOfCSharpFeatures/PropertiesIndexersRefOut/Triple.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
namespace PropertiesIndexersRefOut;
|
||||
|
||||
public class Triple
|
||||
{
|
||||
private int first;
|
||||
public int First
|
||||
{
|
||||
get
|
||||
{
|
||||
return first;
|
||||
}
|
||||
set
|
||||
{
|
||||
first = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Second { get; set; }
|
||||
|
||||
public int Third => First + Second;
|
||||
public override string ToString()
|
||||
{
|
||||
return $"({First}, {Second}, {Third})";
|
||||
}
|
||||
|
||||
#region Indexer
|
||||
public int this[string s, int position]
|
||||
{
|
||||
get
|
||||
{
|
||||
int num;
|
||||
switch (s)
|
||||
{
|
||||
case "A":
|
||||
num = this.First;
|
||||
break;
|
||||
case "B":
|
||||
num = this.Second;
|
||||
break;
|
||||
case "C":
|
||||
num = this.Third;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Invalid position in triple (should be A, B, or C)");
|
||||
}
|
||||
int digit = 0;
|
||||
while(num > 0 && position > 0)
|
||||
{
|
||||
digit = num % 10;
|
||||
num /= 10;
|
||||
position--;
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Operator overloading
|
||||
public static Triple operator +(Triple x, Triple y)
|
||||
{
|
||||
return new Triple
|
||||
{
|
||||
First = x.First + y.First,
|
||||
Second = x.Second + y.Second
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
55
SomeOfCSharpFeatures/SomeOfCSharpFeatures.sln
Normal file
55
SomeOfCSharpFeatures/SomeOfCSharpFeatures.sln
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.33424.131
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Delegates", "Delegates\Delegates.csproj", "{EABA8FC4-42FB-4DAD-96E9-47A5B1057CFB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extensions", "Extensions\Extensions.csproj", "{47B09D5D-50E4-4827-B954-A40B96052B83}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CovarianceContravariance", "CovarianceContravariance\CovarianceContravariance.csproj", "{007533F4-FE60-4E0C-AF11-004BF8A2C8F8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inheritance", "Inheritance\Inheritance.csproj", "{BEB733F2-BBB4-4170-B530-EFF7C5797559}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PropertiesIndexersRefOut", "PropertiesIndexersRefOut\PropertiesIndexersRefOut.csproj", "{C6F8925F-2947-4A78-8E1A-543D13B7ED6B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ValueTuplesDeconstruction", "ValueTuplesDeconstruction\ValueTuplesDeconstruction.csproj", "{2518859E-D8D5-418A-A92B-411277F86479}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EABA8FC4-42FB-4DAD-96E9-47A5B1057CFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EABA8FC4-42FB-4DAD-96E9-47A5B1057CFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EABA8FC4-42FB-4DAD-96E9-47A5B1057CFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EABA8FC4-42FB-4DAD-96E9-47A5B1057CFB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{47B09D5D-50E4-4827-B954-A40B96052B83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{47B09D5D-50E4-4827-B954-A40B96052B83}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{47B09D5D-50E4-4827-B954-A40B96052B83}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47B09D5D-50E4-4827-B954-A40B96052B83}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{007533F4-FE60-4E0C-AF11-004BF8A2C8F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{007533F4-FE60-4E0C-AF11-004BF8A2C8F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{007533F4-FE60-4E0C-AF11-004BF8A2C8F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{007533F4-FE60-4E0C-AF11-004BF8A2C8F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BEB733F2-BBB4-4170-B530-EFF7C5797559}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BEB733F2-BBB4-4170-B530-EFF7C5797559}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BEB733F2-BBB4-4170-B530-EFF7C5797559}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BEB733F2-BBB4-4170-B530-EFF7C5797559}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C6F8925F-2947-4A78-8E1A-543D13B7ED6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C6F8925F-2947-4A78-8E1A-543D13B7ED6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C6F8925F-2947-4A78-8E1A-543D13B7ED6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C6F8925F-2947-4A78-8E1A-543D13B7ED6B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2518859E-D8D5-418A-A92B-411277F86479}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2518859E-D8D5-418A-A92B-411277F86479}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2518859E-D8D5-418A-A92B-411277F86479}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2518859E-D8D5-418A-A92B-411277F86479}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {88C158C1-838B-42EB-A159-F5F83BF2DDEA}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
22
SomeOfCSharpFeatures/ValueTuplesDeconstruction/Program.cs
Normal file
22
SomeOfCSharpFeatures/ValueTuplesDeconstruction/Program.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//ValueTuples https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/deconstruct
|
||||
|
||||
(int a, int b, int _) t1 = CreateRandomTriple();
|
||||
Console.WriteLine(t1);
|
||||
Console.WriteLine(t1.b);
|
||||
|
||||
var (_, b, _) = CreateRandomTriple();
|
||||
Console.WriteLine(b);
|
||||
|
||||
|
||||
var t2 = CreateRandomTriple();
|
||||
Console.WriteLine(t2);
|
||||
Console.WriteLine(t2.Item2);
|
||||
|
||||
(int, int, int) CreateRandomTriple()
|
||||
{
|
||||
Random r = new Random();
|
||||
var triple = (r.Next(100), r.Next(100), r.Next(100));
|
||||
Console.WriteLine($"Created {triple}");
|
||||
return triple;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
21
docker-definitions/CountrySeedGenerator/README.md
Normal file
21
docker-definitions/CountrySeedGenerator/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# CountrySeedGenerator
|
||||
|
||||
This folder contains the Python helper for generating `04-countries.sql` seed scripts for PostgreSQL and Microsoft SQL Server
|
||||
(defined as Docker containers using docker-compose.yml)
|
||||
|
||||
The commands below assume you are running them from inside the `CountrySeedGenerator` folder.
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```powershell
|
||||
python -m pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Run the generator:
|
||||
|
||||
```powershell
|
||||
python create_countries_sql.py postgres
|
||||
python create_countries_sql.py mssql
|
||||
```
|
||||
|
||||
The script shows the default output path based on the selected target and asks you to confirm it before writing the file.
|
||||
143
docker-definitions/CountrySeedGenerator/create_countries_sql.py
Normal file
143
docker-definitions/CountrySeedGenerator/create_countries_sql.py
Normal file
@@ -0,0 +1,143 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import json
|
||||
import sys
|
||||
|
||||
import pycountry
|
||||
from babel import Locale
|
||||
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
DOCKER_DEFINITIONS_DIR = SCRIPT_DIR.parent
|
||||
MANUAL_COUNTRIES = [
|
||||
{
|
||||
"alpha_2": "XK",
|
||||
"alpha_3": "XKX",
|
||||
"name": "Kosovo",
|
||||
"translations": {
|
||||
"hr": "Kosovo",
|
||||
"mk": "Косово",
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def prompt_target_database(argv: list[str]) -> str:
|
||||
if len(argv) > 1:
|
||||
return parse_target_database(argv[1])
|
||||
|
||||
raw_value = input("Generate schema for [postgres/mssql] (default: mssql): ").strip()
|
||||
return "mssql" if not raw_value else parse_target_database(raw_value)
|
||||
|
||||
|
||||
def parse_target_database(value: str) -> str:
|
||||
normalized = value.strip().lower()
|
||||
|
||||
if normalized in {"postgres", "postgresql", "pg"}:
|
||||
return "postgres"
|
||||
if normalized in {"mssql", "sqlserver", "sql-server", "sql"}:
|
||||
return "mssql"
|
||||
|
||||
raise ValueError(f"Unsupported target database '{value}'. Use 'postgres' or 'mssql'.")
|
||||
|
||||
|
||||
def get_output_path(target_database: str) -> Path:
|
||||
target_folder = "postgres-eventsdb" if target_database == "postgres" else "mssql-eventsdb"
|
||||
return DOCKER_DEFINITIONS_DIR / target_folder / "init" / "04-countries.sql"
|
||||
|
||||
|
||||
def get_insert_target(target_database: str) -> tuple[str, str]:
|
||||
if target_database == "postgres":
|
||||
return "country", "(code, alpha3, name, translations)"
|
||||
|
||||
return "dbo.Country", "(Code, Alpha3, Name, Translations)"
|
||||
|
||||
|
||||
def get_script_prefix(target_database: str) -> str:
|
||||
if target_database == "mssql":
|
||||
return "USE [$(MSSQL_DB)];\nGO\n\n"
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def confirm_output_path(output_path: Path) -> Path:
|
||||
print(f"Output path: {output_path}")
|
||||
raw_value = input("Press Enter to confirm or type a different path: ").strip()
|
||||
|
||||
if not raw_value:
|
||||
return output_path
|
||||
|
||||
custom_path = Path(raw_value)
|
||||
return custom_path if custom_path.is_absolute() else (SCRIPT_DIR / custom_path).resolve()
|
||||
|
||||
|
||||
def generate_minimal_sql(target_database: str) -> None:
|
||||
default_output_path = get_output_path(target_database)
|
||||
output_path = confirm_output_path(default_output_path)
|
||||
table_name, column_list = get_insert_target(target_database)
|
||||
script_prefix = get_script_prefix(target_database)
|
||||
sql_header = f"INSERT INTO {table_name} {column_list} VALUES\n"
|
||||
|
||||
print(f"Generating SQL for {target_database} countries script...")
|
||||
|
||||
try:
|
||||
lang_hr = Locale("hr")
|
||||
lang_mk = Locale("mk")
|
||||
except Exception as exc:
|
||||
print(f"Babel error: {exc}. Check whether you installed the 'Babel' package.")
|
||||
return
|
||||
|
||||
rows: list[str] = []
|
||||
countries = sorted(pycountry.countries, key=lambda country: country.alpha_2)
|
||||
|
||||
for country in countries:
|
||||
code = country.alpha_2
|
||||
alpha3 = country.alpha_3
|
||||
english_name = getattr(country, "common_name", country.name)
|
||||
|
||||
croatian_name = lang_hr.territories.get(code, english_name)
|
||||
macedonian_name = lang_mk.territories.get(code, english_name)
|
||||
|
||||
s_en = english_name.replace("'", "''")
|
||||
s_hr = croatian_name.replace("'", "''")
|
||||
s_mk = macedonian_name.replace("'", "''")
|
||||
|
||||
trans_dict = {
|
||||
"hr": s_hr,
|
||||
"mk": s_mk,
|
||||
}
|
||||
|
||||
trans_json = json.dumps(trans_dict, ensure_ascii=False).replace("'", "''")
|
||||
rows.append(f"('{code}', '{alpha3}', '{s_en}', '{trans_json}')")
|
||||
|
||||
for country in MANUAL_COUNTRIES:
|
||||
code = country["alpha_2"]
|
||||
alpha3 = country["alpha_3"]
|
||||
english_name = country["name"]
|
||||
croatian_name = country["translations"]["hr"]
|
||||
macedonian_name = country["translations"]["mk"]
|
||||
|
||||
s_en = english_name.replace("'", "''")
|
||||
s_hr = croatian_name.replace("'", "''")
|
||||
s_mk = macedonian_name.replace("'", "''")
|
||||
|
||||
trans_dict = {
|
||||
"hr": s_hr,
|
||||
"mk": s_mk,
|
||||
}
|
||||
|
||||
trans_json = json.dumps(trans_dict, ensure_ascii=False).replace("'", "''")
|
||||
rows.append(f"('{code}', '{alpha3}', '{s_en}', '{trans_json}')")
|
||||
|
||||
rows.sort()
|
||||
|
||||
final_sql = script_prefix + sql_header + ",\n".join(rows) + ";"
|
||||
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text(final_sql, encoding="utf-8")
|
||||
print(f"Success! Generated {len(rows)} countries in '{output_path}'.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_minimal_sql(prompt_target_database(sys.argv))
|
||||
2
docker-definitions/CountrySeedGenerator/requirements.txt
Normal file
2
docker-definitions/CountrySeedGenerator/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
pycountry
|
||||
Babel
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bogus" Version="35.6.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.37027.9 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PeopleDataGenerator", "PeopleDataGenerator.csproj", "{08786A49-9D47-4F1D-AE9D-47AB02CE8954}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{08786A49-9D47-4F1D-AE9D-47AB02CE8954}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08786A49-9D47-4F1D-AE9D-47AB02CE8954}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08786A49-9D47-4F1D-AE9D-47AB02CE8954}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08786A49-9D47-4F1D-AE9D-47AB02CE8954}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {EC9B8434-351C-4169-A527-51408CB7ABED}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
230
docker-definitions/PeopleDataGenerator/Program.cs
Normal file
230
docker-definitions/PeopleDataGenerator/Program.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using System.Text;
|
||||
using Bogus;
|
||||
using Bogus.Extensions;
|
||||
|
||||
const int peoplePerCountry = 50;
|
||||
var generatorDirectory = GetGeneratorDirectory();
|
||||
|
||||
Console.OutputEncoding = Encoding.UTF8;
|
||||
|
||||
var targetDatabase = PromptForTargetDatabase(args);
|
||||
var defaultOutputPath = GetDefaultPeopleOutputPath(generatorDirectory, targetDatabase);
|
||||
var outputPath = PromptForPath("Enter people SQL output", defaultOutputPath);
|
||||
var fullOutputPath = Path.GetFullPath(outputPath, Environment.CurrentDirectory);
|
||||
|
||||
var insertStatements = BuildPersonInsertStatements(targetDatabase);
|
||||
var fileContent = BuildOutputContent(targetDatabase, insertStatements);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fullOutputPath)!);
|
||||
await File.WriteAllTextAsync(fullOutputPath, fileContent, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
|
||||
|
||||
Console.WriteLine($"Target database: {targetDatabase.DisplayName()}");
|
||||
Console.WriteLine($"SQL script saved to: {fullOutputPath}");
|
||||
|
||||
static DatabaseTarget PromptForTargetDatabase(string[] args)
|
||||
{
|
||||
if (args.Length > 0)
|
||||
{
|
||||
return ParseTargetDatabase(args[0]);
|
||||
}
|
||||
|
||||
Console.Write("Generate schema for [postgres/mssql] (default: mssql): ");
|
||||
var input = Console.ReadLine();
|
||||
|
||||
return string.IsNullOrWhiteSpace(input) ? DatabaseTarget.MsSql : ParseTargetDatabase(input.Trim());
|
||||
}
|
||||
|
||||
static DatabaseTarget ParseTargetDatabase(string value)
|
||||
{
|
||||
return value.Trim().ToLowerInvariant() switch
|
||||
{
|
||||
"postgres" or "postgresql" or "pg" => DatabaseTarget.Postgres,
|
||||
"mssql" or "sqlserver" or "sql-server" or "sql" => DatabaseTarget.MsSql,
|
||||
_ => throw new ArgumentException($"Unsupported target database '{value}'. Use 'postgres' or 'mssql'.")
|
||||
};
|
||||
}
|
||||
|
||||
static string GetDefaultPeopleOutputPath(string generatorDirectory, DatabaseTarget targetDatabase) =>
|
||||
targetDatabase == DatabaseTarget.Postgres
|
||||
? Path.GetFullPath(@"..\postgres-eventsdb\init\06-people.sql", generatorDirectory)
|
||||
: Path.GetFullPath(@"..\mssql-eventsdb\init\06-people.sql", generatorDirectory);
|
||||
|
||||
static string GetGeneratorDirectory()
|
||||
{
|
||||
var currentDirectory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
|
||||
while (currentDirectory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(currentDirectory.FullName, "PeopleDataGenerator.csproj")))
|
||||
{
|
||||
return currentDirectory.FullName;
|
||||
}
|
||||
|
||||
currentDirectory = currentDirectory.Parent;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Could not locate the PeopleDataGenerator project directory.");
|
||||
}
|
||||
|
||||
static string PromptForPath(string prompt, string defaultPath)
|
||||
{
|
||||
Console.Write($"{prompt} [{defaultPath}]: ");
|
||||
var input = Console.ReadLine();
|
||||
|
||||
return string.IsNullOrWhiteSpace(input) ? defaultPath : input.Trim();
|
||||
}
|
||||
|
||||
static string BuildOutputContent(DatabaseTarget targetDatabase, IReadOnlyList<string> insertStatements)
|
||||
{
|
||||
var content = string.Join("\n", insertStatements) + "\n";
|
||||
|
||||
if (targetDatabase == DatabaseTarget.MsSql)
|
||||
{
|
||||
return $"USE [$(MSSQL_DB)];\nGO\n\n{content}";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
static List<string> BuildPersonInsertStatements(DatabaseTarget targetDatabase)
|
||||
{
|
||||
var statements = new List<string>();
|
||||
var nonLatinLocales = new HashSet<string>
|
||||
{
|
||||
"ar",
|
||||
"el",
|
||||
"fa",
|
||||
"ge",
|
||||
"ne",
|
||||
"ru",
|
||||
"uk"
|
||||
};
|
||||
|
||||
var localeToCountryCode = new (string Locale, string CountryCode)[]
|
||||
{
|
||||
("af_ZA", "ZA"),
|
||||
("ar", "SA"),
|
||||
("az", "AZ"),
|
||||
("cz", "CZ"),
|
||||
("de", "DE"),
|
||||
("de_AT", "AT"),
|
||||
("de_CH", "CH"),
|
||||
("el", "GR"),
|
||||
("en_AU", "AU"),
|
||||
("en_CA", "CA"),
|
||||
("en_GB", "GB"),
|
||||
("en_IE", "IE"),
|
||||
("en_IND", "IN"),
|
||||
("en_NG", "NG"),
|
||||
("en_US", "US"),
|
||||
("es", "ES"),
|
||||
("es_MX", "MX"),
|
||||
("fa", "IR"),
|
||||
("fi", "FI"),
|
||||
("fr", "FR"),
|
||||
("ge", "GE"),
|
||||
("hr", "HR"),
|
||||
("id_ID", "ID"),
|
||||
("it", "IT"),
|
||||
("lv", "LV"),
|
||||
("nb_NO", "NO"),
|
||||
("ne", "NP"),
|
||||
("nl", "NL"),
|
||||
("nl_BE", "BE"),
|
||||
("pl", "PL"),
|
||||
("pt_BR", "BR"),
|
||||
("pt_PT", "PT"),
|
||||
("ro", "RO"),
|
||||
("ru", "RU"),
|
||||
("sk", "SK"),
|
||||
("sv", "SE"),
|
||||
("tr", "TR"),
|
||||
("uk", "UA"),
|
||||
("vi", "VN")
|
||||
};
|
||||
|
||||
foreach (var (locale, countryCode) in localeToCountryCode)
|
||||
{
|
||||
var faker = new Faker(locale);
|
||||
var transliterationLanguage = locale.Split('_')[0];
|
||||
var useTranscriptionForAddress = nonLatinLocales.Contains(transliterationLanguage);
|
||||
|
||||
for (var i = 0; i < peoplePerCountry; i++)
|
||||
{
|
||||
var firstName = faker.Name.FirstName();
|
||||
var lastName = faker.Name.LastName();
|
||||
var firstNameTranscription = firstName.Transliterate(transliterationLanguage);
|
||||
var lastNameTranscription = lastName.Transliterate(transliterationLanguage);
|
||||
var city = NormalizeForStorage(faker.Address.City(), transliterationLanguage, useTranscriptionForAddress);
|
||||
var addressLine = NormalizeForStorage(faker.Address.StreetAddress(), transliterationLanguage, useTranscriptionForAddress);
|
||||
var postalCode = NormalizeForStorage(faker.Address.ZipCode(), transliterationLanguage, useTranscriptionForAddress);
|
||||
var addressCountry = NormalizeForStorage(faker.Address.Country(), transliterationLanguage, useTranscriptionForAddress);
|
||||
var email = faker.Internet.Email(firstNameTranscription, lastNameTranscription);
|
||||
var contactPhone = NormalizePhoneNumber(faker.Phone.PhoneNumber());
|
||||
var birthDate = faker.Date.BetweenDateOnly(new DateOnly(1950, 1, 1), new DateOnly(2010, 12, 31));
|
||||
var documentNumber = $"{countryCode}-{faker.Random.Replace("########")}";
|
||||
|
||||
statements.Add(CreateInsertStatement(
|
||||
targetDatabase,
|
||||
firstName,
|
||||
lastName,
|
||||
firstNameTranscription,
|
||||
lastNameTranscription,
|
||||
addressLine,
|
||||
postalCode,
|
||||
city,
|
||||
addressCountry,
|
||||
email,
|
||||
contactPhone,
|
||||
birthDate,
|
||||
documentNumber,
|
||||
countryCode));
|
||||
}
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
static string CreateInsertStatement(
|
||||
DatabaseTarget targetDatabase,
|
||||
string firstName,
|
||||
string lastName,
|
||||
string firstNameTranscription,
|
||||
string lastNameTranscription,
|
||||
string addressLine,
|
||||
string postalCode,
|
||||
string city,
|
||||
string addressCountry,
|
||||
string email,
|
||||
string contactPhone,
|
||||
DateOnly birthDate,
|
||||
string documentNumber,
|
||||
string countryCode)
|
||||
{
|
||||
var tableName = targetDatabase == DatabaseTarget.Postgres ? "person" : "dbo.Person";
|
||||
var columnList = targetDatabase == DatabaseTarget.Postgres
|
||||
? "(first_name, last_name, first_name_transcription, last_name_transcription, address_line, postal_code, city, address_country, email, contact_phone, birth_date, document_number, country_code)"
|
||||
: "(FirstName, LastName, FirstNameTranscription, LastNameTranscription, AddressLine, PostalCode, City, AddressCountry, Email, ContactPhone, BirthDate, DocumentNumber, CountryCode)";
|
||||
|
||||
return $"INSERT INTO {tableName} {columnList} VALUES ('{EscapeSql(firstName)}', '{EscapeSql(lastName)}', '{EscapeSql(firstNameTranscription)}', '{EscapeSql(lastNameTranscription)}', '{EscapeSql(addressLine)}', '{EscapeSql(postalCode)}', '{EscapeSql(city)}', '{EscapeSql(addressCountry)}', '{EscapeSql(email)}', '{EscapeSql(contactPhone)}', '{birthDate:yyyy-MM-dd}', '{EscapeSql(documentNumber)}', '{countryCode}');";
|
||||
}
|
||||
|
||||
static string EscapeSql(string value) => value.Replace("'", "''");
|
||||
|
||||
static string NormalizeForStorage(string value, string transliterationLanguage, bool useTranscriptionForAddress) =>
|
||||
useTranscriptionForAddress ? value.Transliterate(transliterationLanguage) : value;
|
||||
|
||||
static string NormalizePhoneNumber(string value) =>
|
||||
value.Replace("\r", string.Empty).Replace("\n", " ").Trim();
|
||||
|
||||
enum DatabaseTarget
|
||||
{
|
||||
Postgres,
|
||||
MsSql
|
||||
}
|
||||
|
||||
static class DatabaseTargetExtensions
|
||||
{
|
||||
public static string DisplayName(this DatabaseTarget targetDatabase) =>
|
||||
targetDatabase == DatabaseTarget.Postgres ? "PostgreSQL" : "Microsoft SQL Server";
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"profiles": {
|
||||
"PeopleDataGenerator": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
docker-definitions/PeopleDataGenerator/README.md
Normal file
43
docker-definitions/PeopleDataGenerator/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# PeopleDataGenerator
|
||||
|
||||
`PeopleDataGenerator` contains the .NET helper for generating person seed SQL for both PostgreSQL and Microsoft SQL Server.
|
||||
|
||||
It is used as supporting material for the teaching examples in this repository and helps produce realistic multilingual seed data for the sports-events domain.
|
||||
|
||||
The commands below assume you are running them from inside the `PeopleDataGenerator` folder.
|
||||
|
||||
## What It Does
|
||||
|
||||
- generates fake participant data with locale-specific names and transliterations
|
||||
- asks whether the target should be PostgreSQL or Microsoft SQL Server
|
||||
- writes SQL insert statements to the matching `init` folder
|
||||
|
||||
By default, the people generator writes to:
|
||||
|
||||
```text
|
||||
docker-definitions\postgres-eventsdb\init\06-people.sql
|
||||
docker-definitions\mssql-eventsdb\init\06-people.sql
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- .NET SDK 10.0
|
||||
|
||||
## Running
|
||||
|
||||
```powershell
|
||||
dotnet run --project PeopleDataGenerator.csproj
|
||||
```
|
||||
|
||||
You can also pass the target as the first argument:
|
||||
|
||||
```powershell
|
||||
dotnet run --project PeopleDataGenerator.csproj -- postgres
|
||||
dotnet run --project PeopleDataGenerator.csproj -- mssql
|
||||
```
|
||||
|
||||
The tool asks for the target database when no argument is provided, then asks for the output path. Press `Enter` to accept the default path derived from the `PeopleDataGenerator` folder.
|
||||
|
||||
## Files
|
||||
|
||||
- [Program.cs](Program.cs): .NET generator for `06-people.sql` targeting PostgreSQL or Microsoft SQL Server
|
||||
93
docker-definitions/README.md
Normal file
93
docker-definitions/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Docker Definitions
|
||||
|
||||
This folder contains local Docker-based infrastructure definitions used by the teaching materials in this repository.
|
||||
|
||||
## Available Setups
|
||||
|
||||
- [postgres-eventsdb](docker-definitions/postgres-eventsdb): the main PostgreSQL database for application runs
|
||||
- [mssql-eventsdb](docker-definitions/mssql-eventsdb): the same teaching database adapted for Microsoft SQL Server with Full-Text Search
|
||||
|
||||
## What The Containers Provide
|
||||
|
||||
- initialized PostgreSQL instances
|
||||
- initialized Microsoft SQL Server instances
|
||||
- schema creation through startup scripts in each `init` directory
|
||||
- seed data used by the examples
|
||||
|
||||
## Important Files
|
||||
|
||||
For each PostgreSQL setup:
|
||||
|
||||
- `.env.example`: committed template for local container settings such as ports, usernames, and passwords
|
||||
- `.env`: local copy created from `.env.example`
|
||||
- `docker-compose.yml`: service definitions
|
||||
- `init`: startup scripts copied into `/docker-entrypoint-initdb.d`
|
||||
- `backup`: optional location for backup files
|
||||
|
||||
Before starting a setup for the first time, copy the example file in that folder:
|
||||
|
||||
```powershell
|
||||
Copy-Item docker-definitions\postgres-eventsdb\.env.example docker-definitions\postgres-eventsdb\.env
|
||||
Copy-Item docker-definitions\mssql-eventsdb\.env.example docker-definitions\mssql-eventsdb\.env
|
||||
```
|
||||
|
||||
On Linux and macOS, make sure the shell scripts in each `init` folder are executable before starting the containers:
|
||||
|
||||
```bash
|
||||
chmod +x docker-definitions/postgres-eventsdb/init/*.sh
|
||||
```
|
||||
|
||||
## Running The Main Database
|
||||
|
||||
For normal day-to-day startup, use:
|
||||
|
||||
```powershell
|
||||
docker compose -f docker-definitions\postgres-eventsdb\docker-compose.yml up -d
|
||||
docker compose -f docker-definitions\mssql-eventsdb\docker-compose.yml up -d
|
||||
```
|
||||
|
||||
For `mssql-eventsdb`, use `--build` when you changed the Docker image setup, for example:
|
||||
|
||||
- `Dockerfile`
|
||||
- files in `scripts`
|
||||
- initialization logic that depends on the image contents
|
||||
|
||||
```powershell
|
||||
docker compose -f docker-definitions\mssql-eventsdb\docker-compose.yml up -d --build
|
||||
```
|
||||
|
||||
To stop the containers without deleting named volumes:
|
||||
|
||||
```powershell
|
||||
docker compose -f docker-definitions\postgres-eventsdb\docker-compose.yml down
|
||||
docker compose -f docker-definitions\mssql-eventsdb\docker-compose.yml down
|
||||
```
|
||||
|
||||
To stop the containers and also remove named volumes:
|
||||
|
||||
```powershell
|
||||
docker compose -f docker-definitions\postgres-eventsdb\docker-compose.yml down -v
|
||||
docker compose -f docker-definitions\mssql-eventsdb\docker-compose.yml down -v
|
||||
```
|
||||
|
||||
`-v` removes the named Docker volumes created by the setup, which also deletes the persisted database files. Use it only when you want a clean re-initialization.
|
||||
|
||||
The named database volumes use the `pi_` prefix to reduce the chance of accidental reuse across unrelated Docker setups.
|
||||
|
||||
Default services:
|
||||
|
||||
- PostgreSQL on port `5432`
|
||||
- local PostgreSQL backup folder mounted from `docker-definitions\postgres-eventsdb\backup` to `/backup`
|
||||
- Microsoft SQL Server on port `1433`
|
||||
- local SQL Server backup folder mounted from `docker-definitions\mssql-eventsdb\backup` to `/var/opt/mssql/backup`
|
||||
|
||||
## Configuration Notes
|
||||
|
||||
- review the `.env` files before sharing or reusing the setup outside local teaching and demo environments
|
||||
- application projects connect with the `sport` user created by the initialization scripts
|
||||
- if you change ports or passwords in `.env`, update the matching `dotnet user-secrets` connection strings as well
|
||||
- the SQL Server setup uses `Croatian_100_CI_AS_SC_UTF8` collation and has the Full-Text Search package installed, but no runtime full-text checks, catalogs, or indexes are created by default
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If the database is not initialized as expected, remove the Docker volume and recreate the container so the init scripts run again
|
||||
16
docker-definitions/mssql-eventsdb/.env.example
Normal file
16
docker-definitions/mssql-eventsdb/.env.example
Normal file
@@ -0,0 +1,16 @@
|
||||
# SQL Server admin (sa)
|
||||
ACCEPT_EULA=Y
|
||||
MSSQL_PID=Developer
|
||||
MSSQL_SA_PASSWORD=ChangeMe!123456
|
||||
MSSQL_DB=Events
|
||||
MSSQL_PORT=3030
|
||||
MSSQL_COLLATION=Croatian_100_CI_AS_SC_UTF8
|
||||
|
||||
# App user
|
||||
APP_DB_USER=sport
|
||||
APP_DB_PASSWORD=ChangeMe!123456
|
||||
|
||||
# Local settings for Croatia
|
||||
TZ=Europe/Zagreb
|
||||
LANG=hr_HR.UTF-8
|
||||
LC_ALL=hr_HR.UTF-8
|
||||
33
docker-definitions/mssql-eventsdb/Dockerfile
Normal file
33
docker-definitions/mssql-eventsdb/Dockerfile
Normal file
@@ -0,0 +1,33 @@
|
||||
FROM mcr.microsoft.com/mssql/server:2022-latest
|
||||
|
||||
USER root
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV PATH="/opt/mssql-tools18/bin:${PATH}"
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
gnupg \
|
||||
&& curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | tee /etc/apt/trusted.gpg.d/microsoft.asc >/dev/null \
|
||||
&& curl -fsSL https://packages.microsoft.com/config/ubuntu/22.04/mssql-server-2022.list -o /etc/apt/sources.list.d/mssql-server-2022.list \
|
||||
&& curl -fsSL https://packages.microsoft.com/config/ubuntu/22.04/prod.list -o /etc/apt/sources.list.d/mssql-release.list \
|
||||
&& apt-get update \
|
||||
&& ACCEPT_EULA=Y apt-get install -y --no-install-recommends \
|
||||
locales \
|
||||
mssql-server-fts \
|
||||
mssql-tools18 \
|
||||
tzdata \
|
||||
&& locale-gen hr_HR.UTF-8 \
|
||||
&& update-locale LANG=hr_HR.UTF-8 LC_ALL=hr_HR.UTF-8 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY scripts/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
COPY scripts/configure-db.sh /usr/local/bin/configure-db.sh
|
||||
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/configure-db.sh
|
||||
|
||||
USER mssql
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||
21
docker-definitions/mssql-eventsdb/docker-compose.yml
Normal file
21
docker-definitions/mssql-eventsdb/docker-compose.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
mssql:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: mssql_db
|
||||
restart: unless-stopped
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
ports:
|
||||
- "${MSSQL_PORT}:1433"
|
||||
|
||||
volumes:
|
||||
- mssql_data:/var/opt/mssql
|
||||
- ./backup:/var/opt/mssql/backup
|
||||
- ./init:/docker-entrypoint-initdb.d
|
||||
|
||||
volumes:
|
||||
mssql_data:
|
||||
55
docker-definitions/mssql-eventsdb/init/01-create-db.sql
Normal file
55
docker-definitions/mssql-eventsdb/init/01-create-db.sql
Normal file
@@ -0,0 +1,55 @@
|
||||
IF DB_ID(N'$(MSSQL_DB)') IS NULL
|
||||
BEGIN
|
||||
DECLARE @createDatabase nvarchar(max) =
|
||||
N'CREATE DATABASE [' + REPLACE(N'$(MSSQL_DB)', N']', N']]') + N'] COLLATE $(MSSQL_COLLATION);';
|
||||
|
||||
EXEC (@createDatabase);
|
||||
END;
|
||||
GO
|
||||
|
||||
USE [$(MSSQL_DB)];
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = N'$(APP_DB_USER)')
|
||||
BEGIN
|
||||
DECLARE @createLogin nvarchar(max) =
|
||||
N'CREATE LOGIN [' + REPLACE(N'$(APP_DB_USER)', N']', N']]') + N'] WITH PASSWORD = N''$(APP_DB_PASSWORD)'', CHECK_POLICY = OFF, CHECK_EXPIRATION = OFF;';
|
||||
|
||||
EXEC (@createLogin);
|
||||
END;
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = N'$(APP_DB_USER)')
|
||||
BEGIN
|
||||
DECLARE @createUser nvarchar(max) =
|
||||
N'CREATE USER [' + REPLACE(N'$(APP_DB_USER)', N']', N']]') + N'] FOR LOGIN [' + REPLACE(N'$(APP_DB_USER)', N']', N']]') + N'];';
|
||||
|
||||
EXEC (@createUser);
|
||||
END;
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys.database_role_members drm
|
||||
INNER JOIN sys.database_principals role_principal ON role_principal.principal_id = drm.role_principal_id
|
||||
INNER JOIN sys.database_principals member_principal ON member_principal.principal_id = drm.member_principal_id
|
||||
WHERE role_principal.name = N'db_datareader'
|
||||
AND member_principal.name = N'$(APP_DB_USER)'
|
||||
)
|
||||
BEGIN
|
||||
ALTER ROLE db_datareader ADD MEMBER [$(APP_DB_USER)];
|
||||
END;
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys.database_role_members drm
|
||||
INNER JOIN sys.database_principals role_principal ON role_principal.principal_id = drm.role_principal_id
|
||||
INNER JOIN sys.database_principals member_principal ON member_principal.principal_id = drm.member_principal_id
|
||||
WHERE role_principal.name = N'db_datawriter'
|
||||
AND member_principal.name = N'$(APP_DB_USER)'
|
||||
)
|
||||
BEGIN
|
||||
ALTER ROLE db_datawriter ADD MEMBER [$(APP_DB_USER)];
|
||||
END;
|
||||
GO
|
||||
64
docker-definitions/mssql-eventsdb/init/02-schema.sql
Normal file
64
docker-definitions/mssql-eventsdb/init/02-schema.sql
Normal file
@@ -0,0 +1,64 @@
|
||||
USE [$(MSSQL_DB)];
|
||||
GO
|
||||
|
||||
CREATE TABLE dbo.Country (
|
||||
Code varchar(3) NOT NULL,
|
||||
Alpha3 char(3) NOT NULL,
|
||||
Name varchar(100) NOT NULL,
|
||||
Translations nvarchar(max) NULL,
|
||||
CONSTRAINT PK_Country PRIMARY KEY CLUSTERED (Code),
|
||||
CONSTRAINT UQ_Country_Name UNIQUE (Name),
|
||||
CONSTRAINT CK_Country_Translations_Json CHECK (Translations IS NULL OR ISJSON(Translations) = 1)
|
||||
);
|
||||
GO
|
||||
|
||||
CREATE TABLE dbo.Person (
|
||||
Id int IDENTITY(1,1) NOT NULL,
|
||||
FirstName varchar(100) NOT NULL,
|
||||
LastName varchar(100) NOT NULL,
|
||||
FirstNameTranscription varchar(100) NOT NULL,
|
||||
LastNameTranscription varchar(100) NOT NULL,
|
||||
AddressLine varchar(200) NOT NULL,
|
||||
PostalCode varchar(20) NOT NULL,
|
||||
City varchar(100) NOT NULL,
|
||||
AddressCountry varchar(100) NOT NULL,
|
||||
Email varchar(255) NOT NULL,
|
||||
ContactPhone varchar(50) NOT NULL,
|
||||
BirthDate date NOT NULL,
|
||||
DocumentNumber varchar(50) NOT NULL,
|
||||
CountryCode varchar(3) NOT NULL,
|
||||
CONSTRAINT PK_Person PRIMARY KEY CLUSTERED (Id),
|
||||
CONSTRAINT FK_Person_Country FOREIGN KEY (CountryCode) REFERENCES dbo.Country(Code),
|
||||
CONSTRAINT UQ_Person_DocumentNumber_CountryCode UNIQUE (DocumentNumber, CountryCode)
|
||||
);
|
||||
GO
|
||||
|
||||
CREATE TABLE dbo.Sport (
|
||||
Id int IDENTITY(1,1) NOT NULL,
|
||||
Name varchar(100) NOT NULL,
|
||||
CONSTRAINT PK_Sport PRIMARY KEY CLUSTERED (Id),
|
||||
CONSTRAINT UQ_Sport_Name UNIQUE (Name)
|
||||
);
|
||||
GO
|
||||
|
||||
CREATE TABLE dbo.Event (
|
||||
Id int IDENTITY(1,1) NOT NULL,
|
||||
Name varchar(150) NOT NULL,
|
||||
EventDate date NOT NULL,
|
||||
CONSTRAINT PK_Event PRIMARY KEY CLUSTERED (Id)
|
||||
);
|
||||
GO
|
||||
|
||||
CREATE TABLE dbo.Registration (
|
||||
Id int IDENTITY(1,1) NOT NULL,
|
||||
PersonId int NOT NULL,
|
||||
SportId int NOT NULL,
|
||||
EventId int NOT NULL,
|
||||
RegisteredAt datetime2 NOT NULL CONSTRAINT DF_Registration_RegisteredAt DEFAULT SYSDATETIME(),
|
||||
CONSTRAINT PK_Registration PRIMARY KEY CLUSTERED (Id),
|
||||
CONSTRAINT FK_Registration_Person FOREIGN KEY (PersonId) REFERENCES dbo.Person(Id) ON DELETE CASCADE,
|
||||
CONSTRAINT FK_Registration_Sport FOREIGN KEY (SportId) REFERENCES dbo.Sport(Id) ON DELETE CASCADE,
|
||||
CONSTRAINT FK_Registration_Event FOREIGN KEY (EventId) REFERENCES dbo.Event(Id) ON DELETE CASCADE,
|
||||
CONSTRAINT UQ_Registration_PersonId_SportId_EventId UNIQUE (PersonId, SportId, EventId)
|
||||
);
|
||||
GO
|
||||
8
docker-definitions/mssql-eventsdb/init/03-events.sql
Normal file
8
docker-definitions/mssql-eventsdb/init/03-events.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
USE [$(MSSQL_DB)];
|
||||
GO
|
||||
|
||||
INSERT INTO dbo.Event (Name, EventDate) VALUES
|
||||
('Union Games', '2026-03-12'),
|
||||
('Faculty Meetup', '2026-04-25'),
|
||||
('City Cup', '2026-06-03'),
|
||||
('Research Forum', '2026-09-18');
|
||||
254
docker-definitions/mssql-eventsdb/init/04-countries.sql
Normal file
254
docker-definitions/mssql-eventsdb/init/04-countries.sql
Normal file
@@ -0,0 +1,254 @@
|
||||
USE [$(MSSQL_DB)];
|
||||
GO
|
||||
|
||||
INSERT INTO dbo.Country (Code, Alpha3, Name, Translations) VALUES
|
||||
('AD', 'AND', 'Andorra', '{"hr": "Andora", "mk": "Андора"}'),
|
||||
('AE', 'ARE', 'United Arab Emirates', '{"hr": "Ujedinjeni Arapski Emirati", "mk": "Обединети Арапски Емирати"}'),
|
||||
('AF', 'AFG', 'Afghanistan', '{"hr": "Afganistan", "mk": "Авганистан"}'),
|
||||
('AG', 'ATG', 'Antigua and Barbuda', '{"hr": "Antigva i Barbuda", "mk": "Антига и Барбуда"}'),
|
||||
('AI', 'AIA', 'Anguilla', '{"hr": "Angvila", "mk": "Ангвила"}'),
|
||||
('AL', 'ALB', 'Albania', '{"hr": "Albanija", "mk": "Албанија"}'),
|
||||
('AM', 'ARM', 'Armenia', '{"hr": "Armenija", "mk": "Ерменија"}'),
|
||||
('AO', 'AGO', 'Angola', '{"hr": "Angola", "mk": "Ангола"}'),
|
||||
('AQ', 'ATA', 'Antarctica', '{"hr": "Antarktika", "mk": "Антарктик"}'),
|
||||
('AR', 'ARG', 'Argentina', '{"hr": "Argentina", "mk": "Аргентина"}'),
|
||||
('AS', 'ASM', 'American Samoa', '{"hr": "Američka Samoa", "mk": "Американска Самоа"}'),
|
||||
('AT', 'AUT', 'Austria', '{"hr": "Austrija", "mk": "Австрија"}'),
|
||||
('AU', 'AUS', 'Australia', '{"hr": "Australija", "mk": "Австралија"}'),
|
||||
('AW', 'ABW', 'Aruba', '{"hr": "Aruba", "mk": "Аруба"}'),
|
||||
('AX', 'ALA', 'Åland Islands', '{"hr": "Ålandski otoci", "mk": "Оландски Острови"}'),
|
||||
('AZ', 'AZE', 'Azerbaijan', '{"hr": "Azerbajdžan", "mk": "Азербејџан"}'),
|
||||
('BA', 'BIH', 'Bosnia and Herzegovina', '{"hr": "Bosna i Hercegovina", "mk": "Босна и Херцеговина"}'),
|
||||
('BB', 'BRB', 'Barbados', '{"hr": "Barbados", "mk": "Барбадос"}'),
|
||||
('BD', 'BGD', 'Bangladesh', '{"hr": "Bangladeš", "mk": "Бангладеш"}'),
|
||||
('BE', 'BEL', 'Belgium', '{"hr": "Belgija", "mk": "Белгија"}'),
|
||||
('BF', 'BFA', 'Burkina Faso', '{"hr": "Burkina Faso", "mk": "Буркина Фасо"}'),
|
||||
('BG', 'BGR', 'Bulgaria', '{"hr": "Bugarska", "mk": "Бугарија"}'),
|
||||
('BH', 'BHR', 'Bahrain', '{"hr": "Bahrein", "mk": "Бахреин"}'),
|
||||
('BI', 'BDI', 'Burundi', '{"hr": "Burundi", "mk": "Бурунди"}'),
|
||||
('BJ', 'BEN', 'Benin', '{"hr": "Benin", "mk": "Бенин"}'),
|
||||
('BL', 'BLM', 'Saint Barthélemy', '{"hr": "Saint Barthélemy", "mk": "Свети Вартоломеј"}'),
|
||||
('BM', 'BMU', 'Bermuda', '{"hr": "Bermudi", "mk": "Бермуди"}'),
|
||||
('BN', 'BRN', 'Brunei Darussalam', '{"hr": "Brunej", "mk": "Брунеј"}'),
|
||||
('BO', 'BOL', 'Bolivia', '{"hr": "Bolivija", "mk": "Боливија"}'),
|
||||
('BQ', 'BES', 'Bonaire, Sint Eustatius and Saba', '{"hr": "Karipski otoci Nizozemske", "mk": "Карипска Холандија"}'),
|
||||
('BR', 'BRA', 'Brazil', '{"hr": "Brazil", "mk": "Бразил"}'),
|
||||
('BS', 'BHS', 'Bahamas', '{"hr": "Bahami", "mk": "Бахами"}'),
|
||||
('BT', 'BTN', 'Bhutan', '{"hr": "Butan", "mk": "Бутан"}'),
|
||||
('BV', 'BVT', 'Bouvet Island', '{"hr": "Otok Bouvet", "mk": "Остров Буве"}'),
|
||||
('BW', 'BWA', 'Botswana', '{"hr": "Bocvana", "mk": "Боцвана"}'),
|
||||
('BY', 'BLR', 'Belarus', '{"hr": "Bjelorusija", "mk": "Белорусија"}'),
|
||||
('BZ', 'BLZ', 'Belize', '{"hr": "Belize", "mk": "Белизе"}'),
|
||||
('CA', 'CAN', 'Canada', '{"hr": "Kanada", "mk": "Канада"}'),
|
||||
('CC', 'CCK', 'Cocos (Keeling) Islands', '{"hr": "Kokosovi (Keelingovi) Otoci", "mk": "Кокосови (Килиншки) Острови"}'),
|
||||
('CD', 'COD', 'Congo, The Democratic Republic of the', '{"hr": "Kongo - Kinshasa", "mk": "Конго - Киншаса"}'),
|
||||
('CF', 'CAF', 'Central African Republic', '{"hr": "Srednjoafrička Republika", "mk": "Централноафриканска Република"}'),
|
||||
('CG', 'COG', 'Congo', '{"hr": "Kongo - Brazzaville", "mk": "Конго - Бразавил"}'),
|
||||
('CH', 'CHE', 'Switzerland', '{"hr": "Švicarska", "mk": "Швајцарија"}'),
|
||||
('CI', 'CIV', 'Côte d''Ivoire', '{"hr": "Obala Bjelokosti", "mk": "Брегот на Слоновата Коска"}'),
|
||||
('CK', 'COK', 'Cook Islands', '{"hr": "Cookovi Otoci", "mk": "Кукови Острови"}'),
|
||||
('CL', 'CHL', 'Chile', '{"hr": "Čile", "mk": "Чиле"}'),
|
||||
('CM', 'CMR', 'Cameroon', '{"hr": "Kamerun", "mk": "Камерун"}'),
|
||||
('CN', 'CHN', 'China', '{"hr": "Kina", "mk": "Кина"}'),
|
||||
('CO', 'COL', 'Colombia', '{"hr": "Kolumbija", "mk": "Колумбија"}'),
|
||||
('CR', 'CRI', 'Costa Rica', '{"hr": "Kostarika", "mk": "Костарика"}'),
|
||||
('CU', 'CUB', 'Cuba', '{"hr": "Kuba", "mk": "Куба"}'),
|
||||
('CV', 'CPV', 'Cabo Verde', '{"hr": "Zelenortska Republika", "mk": "Кабо Верде"}'),
|
||||
('CW', 'CUW', 'Curaçao', '{"hr": "Curaçao", "mk": "Курасао"}'),
|
||||
('CX', 'CXR', 'Christmas Island', '{"hr": "Božićni Otok", "mk": "Божиќен Остров"}'),
|
||||
('CY', 'CYP', 'Cyprus', '{"hr": "Cipar", "mk": "Кипар"}'),
|
||||
('CZ', 'CZE', 'Czechia', '{"hr": "Češka", "mk": "Чешка"}'),
|
||||
('DE', 'DEU', 'Germany', '{"hr": "Njemačka", "mk": "Германија"}'),
|
||||
('DJ', 'DJI', 'Djibouti', '{"hr": "Džibuti", "mk": "Џибути"}'),
|
||||
('DK', 'DNK', 'Denmark', '{"hr": "Danska", "mk": "Данска"}'),
|
||||
('DM', 'DMA', 'Dominica', '{"hr": "Dominika", "mk": "Доминика"}'),
|
||||
('DO', 'DOM', 'Dominican Republic', '{"hr": "Dominikanska Republika", "mk": "Доминиканска Република"}'),
|
||||
('DZ', 'DZA', 'Algeria', '{"hr": "Alžir", "mk": "Алжир"}'),
|
||||
('EC', 'ECU', 'Ecuador', '{"hr": "Ekvador", "mk": "Еквадор"}'),
|
||||
('EE', 'EST', 'Estonia', '{"hr": "Estonija", "mk": "Естонија"}'),
|
||||
('EG', 'EGY', 'Egypt', '{"hr": "Egipat", "mk": "Египет"}'),
|
||||
('EH', 'ESH', 'Western Sahara', '{"hr": "Zapadna Sahara", "mk": "Западна Сахара"}'),
|
||||
('ER', 'ERI', 'Eritrea', '{"hr": "Eritreja", "mk": "Еритреја"}'),
|
||||
('ES', 'ESP', 'Spain', '{"hr": "Španjolska", "mk": "Шпанија"}'),
|
||||
('ET', 'ETH', 'Ethiopia', '{"hr": "Etiopija", "mk": "Етиопија"}'),
|
||||
('FI', 'FIN', 'Finland', '{"hr": "Finska", "mk": "Финска"}'),
|
||||
('FJ', 'FJI', 'Fiji', '{"hr": "Fidži", "mk": "Фиџи"}'),
|
||||
('FK', 'FLK', 'Falkland Islands (Malvinas)', '{"hr": "Falklandski Otoci", "mk": "Фолкландски Острови"}'),
|
||||
('FM', 'FSM', 'Micronesia, Federated States of', '{"hr": "Mikronezija", "mk": "Микронезија"}'),
|
||||
('FO', 'FRO', 'Faroe Islands', '{"hr": "Ovčji Otoci", "mk": "Фарски Острови"}'),
|
||||
('FR', 'FRA', 'France', '{"hr": "Francuska", "mk": "Франција"}'),
|
||||
('GA', 'GAB', 'Gabon', '{"hr": "Gabon", "mk": "Габон"}'),
|
||||
('GB', 'GBR', 'United Kingdom', '{"hr": "Ujedinjeno Kraljevstvo", "mk": "Обединето Кралство"}'),
|
||||
('GD', 'GRD', 'Grenada', '{"hr": "Grenada", "mk": "Гренада"}'),
|
||||
('GE', 'GEO', 'Georgia', '{"hr": "Gruzija", "mk": "Грузија"}'),
|
||||
('GF', 'GUF', 'French Guiana', '{"hr": "Francuska Gijana", "mk": "Француска Гвајана"}'),
|
||||
('GG', 'GGY', 'Guernsey', '{"hr": "Guernsey", "mk": "Гернзи"}'),
|
||||
('GH', 'GHA', 'Ghana', '{"hr": "Gana", "mk": "Гана"}'),
|
||||
('GI', 'GIB', 'Gibraltar', '{"hr": "Gibraltar", "mk": "Гибралтар"}'),
|
||||
('GL', 'GRL', 'Greenland', '{"hr": "Grenland", "mk": "Гренланд"}'),
|
||||
('GM', 'GMB', 'Gambia', '{"hr": "Gambija", "mk": "Гамбија"}'),
|
||||
('GN', 'GIN', 'Guinea', '{"hr": "Gvineja", "mk": "Гвинеја"}'),
|
||||
('GP', 'GLP', 'Guadeloupe', '{"hr": "Guadalupe", "mk": "Гвадалупе"}'),
|
||||
('GQ', 'GNQ', 'Equatorial Guinea', '{"hr": "Ekvatorska Gvineja", "mk": "Екваторска Гвинеја"}'),
|
||||
('GR', 'GRC', 'Greece', '{"hr": "Grčka", "mk": "Грција"}'),
|
||||
('GS', 'SGS', 'South Georgia and the South Sandwich Islands', '{"hr": "Južna Georgia i Otoci Južni Sandwich", "mk": "Јужна Џорџија и Јужни Сендвички Острови"}'),
|
||||
('GT', 'GTM', 'Guatemala', '{"hr": "Gvatemala", "mk": "Гватемала"}'),
|
||||
('GU', 'GUM', 'Guam', '{"hr": "Guam", "mk": "Гуам"}'),
|
||||
('GW', 'GNB', 'Guinea-Bissau', '{"hr": "Gvineja Bisau", "mk": "Гвинеја Бисао"}'),
|
||||
('GY', 'GUY', 'Guyana', '{"hr": "Gvajana", "mk": "Гвајана"}'),
|
||||
('HK', 'HKG', 'Hong Kong', '{"hr": "PUP Hong Kong Kina", "mk": "Хонгконг САР Кина"}'),
|
||||
('HM', 'HMD', 'Heard Island and McDonald Islands', '{"hr": "Otoci Heard i McDonald", "mk": "Остров Херд и Острови Мекдоналд"}'),
|
||||
('HN', 'HND', 'Honduras', '{"hr": "Honduras", "mk": "Хондурас"}'),
|
||||
('HR', 'HRV', 'Croatia', '{"hr": "Hrvatska", "mk": "Хрватска"}'),
|
||||
('HT', 'HTI', 'Haiti', '{"hr": "Haiti", "mk": "Хаити"}'),
|
||||
('HU', 'HUN', 'Hungary', '{"hr": "Mađarska", "mk": "Унгарија"}'),
|
||||
('ID', 'IDN', 'Indonesia', '{"hr": "Indonezija", "mk": "Индонезија"}'),
|
||||
('IE', 'IRL', 'Ireland', '{"hr": "Irska", "mk": "Ирска"}'),
|
||||
('IL', 'ISR', 'Israel', '{"hr": "Izrael", "mk": "Израел"}'),
|
||||
('IM', 'IMN', 'Isle of Man', '{"hr": "Otok Man", "mk": "Остров Ман"}'),
|
||||
('IN', 'IND', 'India', '{"hr": "Indija", "mk": "Индија"}'),
|
||||
('IO', 'IOT', 'British Indian Ocean Territory', '{"hr": "Britanski Indijskooceanski Teritorij", "mk": "Британска Индоокеанска Територија"}'),
|
||||
('IQ', 'IRQ', 'Iraq', '{"hr": "Irak", "mk": "Ирак"}'),
|
||||
('IR', 'IRN', 'Iran', '{"hr": "Iran", "mk": "Иран"}'),
|
||||
('IS', 'ISL', 'Iceland', '{"hr": "Island", "mk": "Исланд"}'),
|
||||
('IT', 'ITA', 'Italy', '{"hr": "Italija", "mk": "Италија"}'),
|
||||
('JE', 'JEY', 'Jersey', '{"hr": "Jersey", "mk": "Џерси"}'),
|
||||
('JM', 'JAM', 'Jamaica', '{"hr": "Jamajka", "mk": "Јамајка"}'),
|
||||
('JO', 'JOR', 'Jordan', '{"hr": "Jordan", "mk": "Јордан"}'),
|
||||
('JP', 'JPN', 'Japan', '{"hr": "Japan", "mk": "Јапонија"}'),
|
||||
('KE', 'KEN', 'Kenya', '{"hr": "Kenija", "mk": "Кенија"}'),
|
||||
('KG', 'KGZ', 'Kyrgyzstan', '{"hr": "Kirgistan", "mk": "Киргистан"}'),
|
||||
('KH', 'KHM', 'Cambodia', '{"hr": "Kambodža", "mk": "Камбоџа"}'),
|
||||
('KI', 'KIR', 'Kiribati', '{"hr": "Kiribati", "mk": "Кирибати"}'),
|
||||
('KM', 'COM', 'Comoros', '{"hr": "Komori", "mk": "Коморски Острови"}'),
|
||||
('KN', 'KNA', 'Saint Kitts and Nevis', '{"hr": "Sveti Kristofor i Nevis", "mk": "Свети Китс и Невис"}'),
|
||||
('KP', 'PRK', 'North Korea', '{"hr": "Sjeverna Koreja", "mk": "Северна Кореја"}'),
|
||||
('KR', 'KOR', 'South Korea', '{"hr": "Južna Koreja", "mk": "Јужна Кореја"}'),
|
||||
('KW', 'KWT', 'Kuwait', '{"hr": "Kuvajt", "mk": "Кувајт"}'),
|
||||
('KY', 'CYM', 'Cayman Islands', '{"hr": "Kajmanski Otoci", "mk": "Кајмански Острови"}'),
|
||||
('KZ', 'KAZ', 'Kazakhstan', '{"hr": "Kazahstan", "mk": "Казахстан"}'),
|
||||
('LA', 'LAO', 'Laos', '{"hr": "Laos", "mk": "Лаос"}'),
|
||||
('LB', 'LBN', 'Lebanon', '{"hr": "Libanon", "mk": "Либан"}'),
|
||||
('LC', 'LCA', 'Saint Lucia', '{"hr": "Sveta Lucija", "mk": "Сент Лусија"}'),
|
||||
('LI', 'LIE', 'Liechtenstein', '{"hr": "Lihtenštajn", "mk": "Лихтенштајн"}'),
|
||||
('LK', 'LKA', 'Sri Lanka', '{"hr": "Šri Lanka", "mk": "Шри Ланка"}'),
|
||||
('LR', 'LBR', 'Liberia', '{"hr": "Liberija", "mk": "Либерија"}'),
|
||||
('LS', 'LSO', 'Lesotho', '{"hr": "Lesoto", "mk": "Лесото"}'),
|
||||
('LT', 'LTU', 'Lithuania', '{"hr": "Litva", "mk": "Литванија"}'),
|
||||
('LU', 'LUX', 'Luxembourg', '{"hr": "Luksemburg", "mk": "Луксембург"}'),
|
||||
('LV', 'LVA', 'Latvia', '{"hr": "Latvija", "mk": "Латвија"}'),
|
||||
('LY', 'LBY', 'Libya', '{"hr": "Libija", "mk": "Либија"}'),
|
||||
('MA', 'MAR', 'Morocco', '{"hr": "Maroko", "mk": "Мароко"}'),
|
||||
('MC', 'MCO', 'Monaco', '{"hr": "Monako", "mk": "Монако"}'),
|
||||
('MD', 'MDA', 'Moldova', '{"hr": "Moldavija", "mk": "Молдавија"}'),
|
||||
('ME', 'MNE', 'Montenegro', '{"hr": "Crna Gora", "mk": "Црна Гора"}'),
|
||||
('MF', 'MAF', 'Saint Martin (French part)', '{"hr": "Saint Martin", "mk": "Сент Мартин"}'),
|
||||
('MG', 'MDG', 'Madagascar', '{"hr": "Madagaskar", "mk": "Мадагаскар"}'),
|
||||
('MH', 'MHL', 'Marshall Islands', '{"hr": "Maršalovi Otoci", "mk": "Маршалски Острови"}'),
|
||||
('MK', 'MKD', 'North Macedonia', '{"hr": "Sjeverna Makedonija", "mk": "Северна Македонија"}'),
|
||||
('ML', 'MLI', 'Mali', '{"hr": "Mali", "mk": "Мали"}'),
|
||||
('MM', 'MMR', 'Myanmar', '{"hr": "Mjanmar (Burma)", "mk": "Мјанмар (Бурма)"}'),
|
||||
('MN', 'MNG', 'Mongolia', '{"hr": "Mongolija", "mk": "Монголија"}'),
|
||||
('MO', 'MAC', 'Macao', '{"hr": "PUP Makao Kina", "mk": "Макао САР"}'),
|
||||
('MP', 'MNP', 'Northern Mariana Islands', '{"hr": "Sjevernomarijanski Otoci", "mk": "Северни Маријански Острови"}'),
|
||||
('MQ', 'MTQ', 'Martinique', '{"hr": "Martinik", "mk": "Мартиник"}'),
|
||||
('MR', 'MRT', 'Mauritania', '{"hr": "Mauretanija", "mk": "Мавританија"}'),
|
||||
('MS', 'MSR', 'Montserrat', '{"hr": "Montserrat", "mk": "Монсерат"}'),
|
||||
('MT', 'MLT', 'Malta', '{"hr": "Malta", "mk": "Малта"}'),
|
||||
('MU', 'MUS', 'Mauritius', '{"hr": "Mauricijus", "mk": "Маврициус"}'),
|
||||
('MV', 'MDV', 'Maldives', '{"hr": "Maldivi", "mk": "Малдиви"}'),
|
||||
('MW', 'MWI', 'Malawi', '{"hr": "Malavi", "mk": "Малави"}'),
|
||||
('MX', 'MEX', 'Mexico', '{"hr": "Meksiko", "mk": "Мексико"}'),
|
||||
('MY', 'MYS', 'Malaysia', '{"hr": "Malezija", "mk": "Малезија"}'),
|
||||
('MZ', 'MOZ', 'Mozambique', '{"hr": "Mozambik", "mk": "Мозамбик"}'),
|
||||
('NA', 'NAM', 'Namibia', '{"hr": "Namibija", "mk": "Намибија"}'),
|
||||
('NC', 'NCL', 'New Caledonia', '{"hr": "Nova Kaledonija", "mk": "Нова Каледонија"}'),
|
||||
('NE', 'NER', 'Niger', '{"hr": "Niger", "mk": "Нигер"}'),
|
||||
('NF', 'NFK', 'Norfolk Island', '{"hr": "Otok Norfolk", "mk": "Норфолшки Остров"}'),
|
||||
('NG', 'NGA', 'Nigeria', '{"hr": "Nigerija", "mk": "Нигерија"}'),
|
||||
('NI', 'NIC', 'Nicaragua', '{"hr": "Nikaragva", "mk": "Никарагва"}'),
|
||||
('NL', 'NLD', 'Netherlands', '{"hr": "Nizozemska", "mk": "Холандија"}'),
|
||||
('NO', 'NOR', 'Norway', '{"hr": "Norveška", "mk": "Норвешка"}'),
|
||||
('NP', 'NPL', 'Nepal', '{"hr": "Nepal", "mk": "Непал"}'),
|
||||
('NR', 'NRU', 'Nauru', '{"hr": "Nauru", "mk": "Науру"}'),
|
||||
('NU', 'NIU', 'Niue', '{"hr": "Niue", "mk": "Ниује"}'),
|
||||
('NZ', 'NZL', 'New Zealand', '{"hr": "Novi Zeland", "mk": "Нов Зеланд"}'),
|
||||
('OM', 'OMN', 'Oman', '{"hr": "Oman", "mk": "Оман"}'),
|
||||
('PA', 'PAN', 'Panama', '{"hr": "Panama", "mk": "Панама"}'),
|
||||
('PE', 'PER', 'Peru', '{"hr": "Peru", "mk": "Перу"}'),
|
||||
('PF', 'PYF', 'French Polynesia', '{"hr": "Francuska Polinezija", "mk": "Француска Полинезија"}'),
|
||||
('PG', 'PNG', 'Papua New Guinea', '{"hr": "Papua Nova Gvineja", "mk": "Папуа Нова Гвинеја"}'),
|
||||
('PH', 'PHL', 'Philippines', '{"hr": "Filipini", "mk": "Филипини"}'),
|
||||
('PK', 'PAK', 'Pakistan', '{"hr": "Pakistan", "mk": "Пакистан"}'),
|
||||
('PL', 'POL', 'Poland', '{"hr": "Poljska", "mk": "Полска"}'),
|
||||
('PM', 'SPM', 'Saint Pierre and Miquelon', '{"hr": "Sveti Petar i Mikelon", "mk": "Сент Пјер и Микелан"}'),
|
||||
('PN', 'PCN', 'Pitcairn', '{"hr": "Pitcairnovi Otoci", "mk": "Питкернски Острови"}'),
|
||||
('PR', 'PRI', 'Puerto Rico', '{"hr": "Portoriko", "mk": "Порторико"}'),
|
||||
('PS', 'PSE', 'Palestine, State of', '{"hr": "Palestinsko područje", "mk": "Палестински Територии"}'),
|
||||
('PT', 'PRT', 'Portugal', '{"hr": "Portugal", "mk": "Португалија"}'),
|
||||
('PW', 'PLW', 'Palau', '{"hr": "Palau", "mk": "Палау"}'),
|
||||
('PY', 'PRY', 'Paraguay', '{"hr": "Paragvaj", "mk": "Парагвај"}'),
|
||||
('QA', 'QAT', 'Qatar', '{"hr": "Katar", "mk": "Катар"}'),
|
||||
('RE', 'REU', 'Réunion', '{"hr": "Réunion", "mk": "Рејунион"}'),
|
||||
('RO', 'ROU', 'Romania', '{"hr": "Rumunjska", "mk": "Романија"}'),
|
||||
('RS', 'SRB', 'Serbia', '{"hr": "Srbija", "mk": "Србија"}'),
|
||||
('RU', 'RUS', 'Russian Federation', '{"hr": "Rusija", "mk": "Русија"}'),
|
||||
('RW', 'RWA', 'Rwanda', '{"hr": "Ruanda", "mk": "Руанда"}'),
|
||||
('SA', 'SAU', 'Saudi Arabia', '{"hr": "Saudijska Arabija", "mk": "Саудиска Арабија"}'),
|
||||
('SB', 'SLB', 'Solomon Islands', '{"hr": "Salomonovi Otoci", "mk": "Соломонски Острови"}'),
|
||||
('SC', 'SYC', 'Seychelles', '{"hr": "Sejšeli", "mk": "Сејшели"}'),
|
||||
('SD', 'SDN', 'Sudan', '{"hr": "Sudan", "mk": "Судан"}'),
|
||||
('SE', 'SWE', 'Sweden', '{"hr": "Švedska", "mk": "Шведска"}'),
|
||||
('SG', 'SGP', 'Singapore', '{"hr": "Singapur", "mk": "Сингапур"}'),
|
||||
('SH', 'SHN', 'Saint Helena, Ascension and Tristan da Cunha', '{"hr": "Sveta Helena", "mk": "Света Елена"}'),
|
||||
('SI', 'SVN', 'Slovenia', '{"hr": "Slovenija", "mk": "Словенија"}'),
|
||||
('SJ', 'SJM', 'Svalbard and Jan Mayen', '{"hr": "Svalbard i Jan Mayen", "mk": "Свалбард и Јан Мајен"}'),
|
||||
('SK', 'SVK', 'Slovakia', '{"hr": "Slovačka", "mk": "Словачка"}'),
|
||||
('SL', 'SLE', 'Sierra Leone', '{"hr": "Sijera Leone", "mk": "Сиера Леоне"}'),
|
||||
('SM', 'SMR', 'San Marino', '{"hr": "San Marino", "mk": "Сан Марино"}'),
|
||||
('SN', 'SEN', 'Senegal', '{"hr": "Senegal", "mk": "Сенегал"}'),
|
||||
('SO', 'SOM', 'Somalia', '{"hr": "Somalija", "mk": "Сомалија"}'),
|
||||
('SR', 'SUR', 'Suriname', '{"hr": "Surinam", "mk": "Суринам"}'),
|
||||
('SS', 'SSD', 'South Sudan', '{"hr": "Južni Sudan", "mk": "Јужен Судан"}'),
|
||||
('ST', 'STP', 'Sao Tome and Principe', '{"hr": "Sveti Toma i Princip", "mk": "Саун Томе и Принсип"}'),
|
||||
('SV', 'SLV', 'El Salvador', '{"hr": "Salvador", "mk": "Ел Салвадор"}'),
|
||||
('SX', 'SXM', 'Sint Maarten (Dutch part)', '{"hr": "Sint Maarten", "mk": "Свети Мартин"}'),
|
||||
('SY', 'SYR', 'Syria', '{"hr": "Sirija", "mk": "Сирија"}'),
|
||||
('SZ', 'SWZ', 'Eswatini', '{"hr": "Esvatini", "mk": "Свазиленд"}'),
|
||||
('TC', 'TCA', 'Turks and Caicos Islands', '{"hr": "Otoci Turks i Caicos", "mk": "Острови Туркс и Каикос"}'),
|
||||
('TD', 'TCD', 'Chad', '{"hr": "Čad", "mk": "Чад"}'),
|
||||
('TF', 'ATF', 'French Southern Territories', '{"hr": "Francuski Južni Teritoriji", "mk": "Француски Јужни Територии"}'),
|
||||
('TG', 'TGO', 'Togo', '{"hr": "Togo", "mk": "Того"}'),
|
||||
('TH', 'THA', 'Thailand', '{"hr": "Tajland", "mk": "Тајланд"}'),
|
||||
('TJ', 'TJK', 'Tajikistan', '{"hr": "Tadžikistan", "mk": "Таџикистан"}'),
|
||||
('TK', 'TKL', 'Tokelau', '{"hr": "Tokelau", "mk": "Токелау"}'),
|
||||
('TL', 'TLS', 'Timor-Leste', '{"hr": "Timor-Leste", "mk": "Тимор Лесте"}'),
|
||||
('TM', 'TKM', 'Turkmenistan', '{"hr": "Turkmenistan", "mk": "Туркменистан"}'),
|
||||
('TN', 'TUN', 'Tunisia', '{"hr": "Tunis", "mk": "Тунис"}'),
|
||||
('TO', 'TON', 'Tonga', '{"hr": "Tonga", "mk": "Тонга"}'),
|
||||
('TR', 'TUR', 'Türkiye', '{"hr": "Turska", "mk": "Турција"}'),
|
||||
('TT', 'TTO', 'Trinidad and Tobago', '{"hr": "Trinidad i Tobago", "mk": "Тринидад и Тобаго"}'),
|
||||
('TV', 'TUV', 'Tuvalu', '{"hr": "Tuvalu", "mk": "Тувалу"}'),
|
||||
('TW', 'TWN', 'Taiwan', '{"hr": "Tajvan", "mk": "Тајван"}'),
|
||||
('TZ', 'TZA', 'Tanzania', '{"hr": "Tanzanija", "mk": "Танзанија"}'),
|
||||
('UA', 'UKR', 'Ukraine', '{"hr": "Ukrajina", "mk": "Украина"}'),
|
||||
('UG', 'UGA', 'Uganda', '{"hr": "Uganda", "mk": "Уганда"}'),
|
||||
('UM', 'UMI', 'United States Minor Outlying Islands', '{"hr": "Mali udaljeni otoci SAD-a", "mk": "Американски територии во Пацификот"}'),
|
||||
('US', 'USA', 'United States', '{"hr": "Sjedinjene Američke Države", "mk": "Соединети Американски Држави"}'),
|
||||
('UY', 'URY', 'Uruguay', '{"hr": "Urugvaj", "mk": "Уругвај"}'),
|
||||
('UZ', 'UZB', 'Uzbekistan', '{"hr": "Uzbekistan", "mk": "Узбекистан"}'),
|
||||
('VA', 'VAT', 'Holy See (Vatican City State)', '{"hr": "Vatikan", "mk": "Ватикан"}'),
|
||||
('VC', 'VCT', 'Saint Vincent and the Grenadines', '{"hr": "Sveti Vincent i Grenadini", "mk": "Сент Винсент и Гренадини"}'),
|
||||
('VE', 'VEN', 'Venezuela', '{"hr": "Venezuela", "mk": "Венецуела"}'),
|
||||
('VG', 'VGB', 'Virgin Islands, British', '{"hr": "Britanski Djevičanski Otoci", "mk": "Британски Девствени Острови"}'),
|
||||
('VI', 'VIR', 'Virgin Islands, U.S.', '{"hr": "Američki Djevičanski Otoci", "mk": "Американски Девствени Острови"}'),
|
||||
('VN', 'VNM', 'Vietnam', '{"hr": "Vijetnam", "mk": "Виетнам"}'),
|
||||
('VU', 'VUT', 'Vanuatu', '{"hr": "Vanuatu", "mk": "Вануату"}'),
|
||||
('WF', 'WLF', 'Wallis and Futuna', '{"hr": "Wallis i Futuna", "mk": "Валис и Футуна"}'),
|
||||
('WS', 'WSM', 'Samoa', '{"hr": "Samoa", "mk": "Самоа"}'),
|
||||
('XK', 'XKX', 'Kosovo', '{"hr": "Kosovo", "mk": "Косово"}'),
|
||||
('YE', 'YEM', 'Yemen', '{"hr": "Jemen", "mk": "Јемен"}'),
|
||||
('YT', 'MYT', 'Mayotte', '{"hr": "Mayotte", "mk": "Мајот"}'),
|
||||
('ZA', 'ZAF', 'South Africa', '{"hr": "Južnoafrička Republika", "mk": "Јужноафриканска Република"}'),
|
||||
('ZM', 'ZMB', 'Zambia', '{"hr": "Zambija", "mk": "Замбија"}'),
|
||||
('ZW', 'ZWE', 'Zimbabwe', '{"hr": "Zimbabve", "mk": "Зимбабве"}');
|
||||
13
docker-definitions/mssql-eventsdb/init/05-sports.sql
Normal file
13
docker-definitions/mssql-eventsdb/init/05-sports.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
USE [$(MSSQL_DB)];
|
||||
GO
|
||||
|
||||
INSERT INTO dbo.Sport (Name) VALUES
|
||||
('Running'),
|
||||
('Darts'),
|
||||
('Bowling'),
|
||||
('Table Tennis'),
|
||||
('Chess'),
|
||||
('Pikado'),
|
||||
('Mini Golf'),
|
||||
('Swimming'),
|
||||
('Cycling');
|
||||
1953
docker-definitions/mssql-eventsdb/init/06-people.sql
Normal file
1953
docker-definitions/mssql-eventsdb/init/06-people.sql
Normal file
File diff suppressed because it is too large
Load Diff
52
docker-definitions/mssql-eventsdb/scripts/configure-db.sh
Normal file
52
docker-definitions/mssql-eventsdb/scripts/configure-db.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
sqlcmd_bin="/opt/mssql-tools18/bin/sqlcmd"
|
||||
server_ready=false
|
||||
db_exists=""
|
||||
|
||||
run_sqlcmd_query() {
|
||||
"$sqlcmd_bin" -S localhost -U sa -P "${MSSQL_SA_PASSWORD}" -C "$@"
|
||||
}
|
||||
|
||||
for _ in $(seq 1 60); do
|
||||
if run_sqlcmd_query -Q "SELECT 1" >/dev/null 2>&1; then
|
||||
server_ready=true
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ "$server_ready" != "true" ]; then
|
||||
echo "SQL Server did not become ready in time." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for _ in $(seq 1 30); do
|
||||
if db_exists="$(run_sqlcmd_query -h -1 -W -Q "SET NOCOUNT ON; SELECT CASE WHEN DB_ID(N'${MSSQL_DB}') IS NULL THEN 0 ELSE 1 END;" 2>/dev/null)"; then
|
||||
db_exists="$(echo "$db_exists" | tr -d '[:space:]')"
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ -z "$db_exists" ]; then
|
||||
echo "Could not determine whether database ${MSSQL_DB} exists." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$db_exists" = "1" ]; then
|
||||
echo "Database ${MSSQL_DB} already exists. Skipping initialization."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for sql_file in /docker-entrypoint-initdb.d/*.sql; do
|
||||
echo "Running ${sql_file}"
|
||||
run_sqlcmd_query \
|
||||
-b \
|
||||
-f 65001 \
|
||||
-i "${sql_file}" \
|
||||
-v MSSQL_DB="${MSSQL_DB}" APP_DB_USER="${APP_DB_USER}" APP_DB_PASSWORD="${APP_DB_PASSWORD}" MSSQL_COLLATION="${MSSQL_COLLATION}"
|
||||
done
|
||||
8
docker-definitions/mssql-eventsdb/scripts/entrypoint.sh
Normal file
8
docker-definitions/mssql-eventsdb/scripts/entrypoint.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
/opt/mssql/bin/sqlservr &
|
||||
|
||||
/usr/local/bin/configure-db.sh
|
||||
|
||||
wait
|
||||
9
docker-definitions/postgres-eventsdb/.env.example
Normal file
9
docker-definitions/postgres-eventsdb/.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
# PostgreSQL admin (superuser)
|
||||
POSTGRES_USER=bib
|
||||
POSTGRES_PASSWORD=change-me
|
||||
POSTGRES_DB=events
|
||||
POSTGRES_PORT=5432
|
||||
|
||||
# App user
|
||||
APP_DB_USER=sport
|
||||
APP_DB_PASSWORD=change-me
|
||||
33
docker-definitions/postgres-eventsdb/docker-compose.yml
Normal file
33
docker-definitions/postgres-eventsdb/docker-compose.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:18
|
||||
container_name: postgres_db
|
||||
restart: unless-stopped
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
environment:
|
||||
# custom variables for init scripts (.sh)
|
||||
APP_DB_USER: ${APP_DB_USER}
|
||||
APP_DB_PASSWORD: ${APP_DB_PASSWORD}
|
||||
|
||||
ports:
|
||||
- "${POSTGRES_PORT}:5432"
|
||||
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql
|
||||
- ./backup:/backup
|
||||
#chmod +x init/01-roles.sh on linux?
|
||||
- ./init:/docker-entrypoint-initdb.d
|
||||
|
||||
# if we need periodic backup
|
||||
# entrypoint: >
|
||||
# bash -c "while true; do
|
||||
# pg_dump -h postgres -U ${POSTGRES_USER} ${POSTGRES_DB} > /backup/backup_$$(date +%Y%m%d_%H%M%S).sql;
|
||||
# sleep 86400;
|
||||
# done"
|
||||
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
7
docker-definitions/postgres-eventsdb/init/01-roles.sh
Normal file
7
docker-definitions/postgres-eventsdb/init/01-roles.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
CREATE USER ${APP_DB_USER} WITH PASSWORD '${APP_DB_PASSWORD}';
|
||||
GRANT CONNECT ON DATABASE ${POSTGRES_DB} TO ${APP_DB_USER};
|
||||
EOSQL
|
||||
61
docker-definitions/postgres-eventsdb/init/02-schema.sql
Normal file
61
docker-definitions/postgres-eventsdb/init/02-schema.sql
Normal file
@@ -0,0 +1,61 @@
|
||||
-- COUNTRIES
|
||||
CREATE TABLE country (
|
||||
code VARCHAR(3) PRIMARY KEY,
|
||||
alpha3 CHAR(3) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
translations JSONB,
|
||||
|
||||
UNIQUE (name)
|
||||
);
|
||||
|
||||
-- PERSONS
|
||||
CREATE TABLE person (
|
||||
id SERIAL PRIMARY KEY,
|
||||
first_name VARCHAR(100) NOT NULL,
|
||||
last_name VARCHAR(100) NOT NULL,
|
||||
first_name_transcription VARCHAR(100) NOT NULL,
|
||||
last_name_transcription VARCHAR(100) NOT NULL,
|
||||
address_line VARCHAR(200) NOT NULL,
|
||||
postal_code VARCHAR(20) NOT NULL,
|
||||
city VARCHAR(100) NOT NULL,
|
||||
address_country VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
contact_phone VARCHAR(50) NOT NULL,
|
||||
birth_date DATE NOT NULL,
|
||||
document_number VARCHAR(50) NOT NULL,
|
||||
country_code VARCHAR(3) NOT NULL,
|
||||
|
||||
FOREIGN KEY (country_code) REFERENCES country(code),
|
||||
|
||||
-- UNIQUE dokument po državi
|
||||
UNIQUE (document_number, country_code)
|
||||
);
|
||||
|
||||
-- SPORTS
|
||||
CREATE TABLE sport (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
UNIQUE (name)
|
||||
);
|
||||
|
||||
-- EVENTS
|
||||
CREATE TABLE event (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
event_date DATE NOT NULL
|
||||
);
|
||||
|
||||
-- REGISTRATIONS
|
||||
CREATE TABLE registration (
|
||||
id SERIAL PRIMARY KEY,
|
||||
person_id INT NOT NULL,
|
||||
sport_id INT NOT NULL,
|
||||
event_id INT NOT NULL,
|
||||
registered_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
FOREIGN KEY (person_id) REFERENCES person(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (sport_id) REFERENCES sport(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (event_id) REFERENCES event(id) ON DELETE CASCADE,
|
||||
|
||||
UNIQUE (person_id, sport_id, event_id)
|
||||
);
|
||||
15
docker-definitions/postgres-eventsdb/init/03-permissions.sh
Normal file
15
docker-definitions/postgres-eventsdb/init/03-permissions.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Ova datoteka mora imati LF, a ne CRLF
|
||||
DB_NAME="${POSTGRES_DB}"
|
||||
APP_USER="${APP_DB_USER}"
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$DB_NAME" <<-EOSQL
|
||||
GRANT USAGE ON SCHEMA public TO ${APP_USER};
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO ${APP_USER};
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO ${APP_USER};
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO ${APP_USER};
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO ${APP_USER};
|
||||
EOSQL
|
||||
251
docker-definitions/postgres-eventsdb/init/04-countries.sql
Normal file
251
docker-definitions/postgres-eventsdb/init/04-countries.sql
Normal file
@@ -0,0 +1,251 @@
|
||||
INSERT INTO country (code, alpha3, name, translations) VALUES
|
||||
('AD', 'AND', 'Andorra', '{"hr": "Andora", "mk": "Андора"}'),
|
||||
('AE', 'ARE', 'United Arab Emirates', '{"hr": "Ujedinjeni Arapski Emirati", "mk": "Обединети Арапски Емирати"}'),
|
||||
('AF', 'AFG', 'Afghanistan', '{"hr": "Afganistan", "mk": "Авганистан"}'),
|
||||
('AG', 'ATG', 'Antigua and Barbuda', '{"hr": "Antigva i Barbuda", "mk": "Антига и Барбуда"}'),
|
||||
('AI', 'AIA', 'Anguilla', '{"hr": "Angvila", "mk": "Ангвила"}'),
|
||||
('AL', 'ALB', 'Albania', '{"hr": "Albanija", "mk": "Албанија"}'),
|
||||
('AM', 'ARM', 'Armenia', '{"hr": "Armenija", "mk": "Ерменија"}'),
|
||||
('AO', 'AGO', 'Angola', '{"hr": "Angola", "mk": "Ангола"}'),
|
||||
('AQ', 'ATA', 'Antarctica', '{"hr": "Antarktika", "mk": "Антарктик"}'),
|
||||
('AR', 'ARG', 'Argentina', '{"hr": "Argentina", "mk": "Аргентина"}'),
|
||||
('AS', 'ASM', 'American Samoa', '{"hr": "Američka Samoa", "mk": "Американска Самоа"}'),
|
||||
('AT', 'AUT', 'Austria', '{"hr": "Austrija", "mk": "Австрија"}'),
|
||||
('AU', 'AUS', 'Australia', '{"hr": "Australija", "mk": "Австралија"}'),
|
||||
('AW', 'ABW', 'Aruba', '{"hr": "Aruba", "mk": "Аруба"}'),
|
||||
('AX', 'ALA', 'Åland Islands', '{"hr": "Ålandski otoci", "mk": "Оландски Острови"}'),
|
||||
('AZ', 'AZE', 'Azerbaijan', '{"hr": "Azerbajdžan", "mk": "Азербејџан"}'),
|
||||
('BA', 'BIH', 'Bosnia and Herzegovina', '{"hr": "Bosna i Hercegovina", "mk": "Босна и Херцеговина"}'),
|
||||
('BB', 'BRB', 'Barbados', '{"hr": "Barbados", "mk": "Барбадос"}'),
|
||||
('BD', 'BGD', 'Bangladesh', '{"hr": "Bangladeš", "mk": "Бангладеш"}'),
|
||||
('BE', 'BEL', 'Belgium', '{"hr": "Belgija", "mk": "Белгија"}'),
|
||||
('BF', 'BFA', 'Burkina Faso', '{"hr": "Burkina Faso", "mk": "Буркина Фасо"}'),
|
||||
('BG', 'BGR', 'Bulgaria', '{"hr": "Bugarska", "mk": "Бугарија"}'),
|
||||
('BH', 'BHR', 'Bahrain', '{"hr": "Bahrein", "mk": "Бахреин"}'),
|
||||
('BI', 'BDI', 'Burundi', '{"hr": "Burundi", "mk": "Бурунди"}'),
|
||||
('BJ', 'BEN', 'Benin', '{"hr": "Benin", "mk": "Бенин"}'),
|
||||
('BL', 'BLM', 'Saint Barthélemy', '{"hr": "Saint Barthélemy", "mk": "Свети Вартоломеј"}'),
|
||||
('BM', 'BMU', 'Bermuda', '{"hr": "Bermudi", "mk": "Бермуди"}'),
|
||||
('BN', 'BRN', 'Brunei Darussalam', '{"hr": "Brunej", "mk": "Брунеј"}'),
|
||||
('BO', 'BOL', 'Bolivia', '{"hr": "Bolivija", "mk": "Боливија"}'),
|
||||
('BQ', 'BES', 'Bonaire, Sint Eustatius and Saba', '{"hr": "Karipski otoci Nizozemske", "mk": "Карипска Холандија"}'),
|
||||
('BR', 'BRA', 'Brazil', '{"hr": "Brazil", "mk": "Бразил"}'),
|
||||
('BS', 'BHS', 'Bahamas', '{"hr": "Bahami", "mk": "Бахами"}'),
|
||||
('BT', 'BTN', 'Bhutan', '{"hr": "Butan", "mk": "Бутан"}'),
|
||||
('BV', 'BVT', 'Bouvet Island', '{"hr": "Otok Bouvet", "mk": "Остров Буве"}'),
|
||||
('BW', 'BWA', 'Botswana', '{"hr": "Bocvana", "mk": "Боцвана"}'),
|
||||
('BY', 'BLR', 'Belarus', '{"hr": "Bjelorusija", "mk": "Белорусија"}'),
|
||||
('BZ', 'BLZ', 'Belize', '{"hr": "Belize", "mk": "Белизе"}'),
|
||||
('CA', 'CAN', 'Canada', '{"hr": "Kanada", "mk": "Канада"}'),
|
||||
('CC', 'CCK', 'Cocos (Keeling) Islands', '{"hr": "Kokosovi (Keelingovi) Otoci", "mk": "Кокосови (Килиншки) Острови"}'),
|
||||
('CD', 'COD', 'Congo, The Democratic Republic of the', '{"hr": "Kongo - Kinshasa", "mk": "Конго - Киншаса"}'),
|
||||
('CF', 'CAF', 'Central African Republic', '{"hr": "Srednjoafrička Republika", "mk": "Централноафриканска Република"}'),
|
||||
('CG', 'COG', 'Congo', '{"hr": "Kongo - Brazzaville", "mk": "Конго - Бразавил"}'),
|
||||
('CH', 'CHE', 'Switzerland', '{"hr": "Švicarska", "mk": "Швајцарија"}'),
|
||||
('CI', 'CIV', 'Côte d''Ivoire', '{"hr": "Obala Bjelokosti", "mk": "Брегот на Слоновата Коска"}'),
|
||||
('CK', 'COK', 'Cook Islands', '{"hr": "Cookovi Otoci", "mk": "Кукови Острови"}'),
|
||||
('CL', 'CHL', 'Chile', '{"hr": "Čile", "mk": "Чиле"}'),
|
||||
('CM', 'CMR', 'Cameroon', '{"hr": "Kamerun", "mk": "Камерун"}'),
|
||||
('CN', 'CHN', 'China', '{"hr": "Kina", "mk": "Кина"}'),
|
||||
('CO', 'COL', 'Colombia', '{"hr": "Kolumbija", "mk": "Колумбија"}'),
|
||||
('CR', 'CRI', 'Costa Rica', '{"hr": "Kostarika", "mk": "Костарика"}'),
|
||||
('CU', 'CUB', 'Cuba', '{"hr": "Kuba", "mk": "Куба"}'),
|
||||
('CV', 'CPV', 'Cabo Verde', '{"hr": "Zelenortska Republika", "mk": "Кабо Верде"}'),
|
||||
('CW', 'CUW', 'Curaçao', '{"hr": "Curaçao", "mk": "Курасао"}'),
|
||||
('CX', 'CXR', 'Christmas Island', '{"hr": "Božićni Otok", "mk": "Божиќен Остров"}'),
|
||||
('CY', 'CYP', 'Cyprus', '{"hr": "Cipar", "mk": "Кипар"}'),
|
||||
('CZ', 'CZE', 'Czechia', '{"hr": "Češka", "mk": "Чешка"}'),
|
||||
('DE', 'DEU', 'Germany', '{"hr": "Njemačka", "mk": "Германија"}'),
|
||||
('DJ', 'DJI', 'Djibouti', '{"hr": "Džibuti", "mk": "Џибути"}'),
|
||||
('DK', 'DNK', 'Denmark', '{"hr": "Danska", "mk": "Данска"}'),
|
||||
('DM', 'DMA', 'Dominica', '{"hr": "Dominika", "mk": "Доминика"}'),
|
||||
('DO', 'DOM', 'Dominican Republic', '{"hr": "Dominikanska Republika", "mk": "Доминиканска Република"}'),
|
||||
('DZ', 'DZA', 'Algeria', '{"hr": "Alžir", "mk": "Алжир"}'),
|
||||
('EC', 'ECU', 'Ecuador', '{"hr": "Ekvador", "mk": "Еквадор"}'),
|
||||
('EE', 'EST', 'Estonia', '{"hr": "Estonija", "mk": "Естонија"}'),
|
||||
('EG', 'EGY', 'Egypt', '{"hr": "Egipat", "mk": "Египет"}'),
|
||||
('EH', 'ESH', 'Western Sahara', '{"hr": "Zapadna Sahara", "mk": "Западна Сахара"}'),
|
||||
('ER', 'ERI', 'Eritrea', '{"hr": "Eritreja", "mk": "Еритреја"}'),
|
||||
('ES', 'ESP', 'Spain', '{"hr": "Španjolska", "mk": "Шпанија"}'),
|
||||
('ET', 'ETH', 'Ethiopia', '{"hr": "Etiopija", "mk": "Етиопија"}'),
|
||||
('FI', 'FIN', 'Finland', '{"hr": "Finska", "mk": "Финска"}'),
|
||||
('FJ', 'FJI', 'Fiji', '{"hr": "Fidži", "mk": "Фиџи"}'),
|
||||
('FK', 'FLK', 'Falkland Islands (Malvinas)', '{"hr": "Falklandski Otoci", "mk": "Фолкландски Острови"}'),
|
||||
('FM', 'FSM', 'Micronesia, Federated States of', '{"hr": "Mikronezija", "mk": "Микронезија"}'),
|
||||
('FO', 'FRO', 'Faroe Islands', '{"hr": "Ovčji Otoci", "mk": "Фарски Острови"}'),
|
||||
('FR', 'FRA', 'France', '{"hr": "Francuska", "mk": "Франција"}'),
|
||||
('GA', 'GAB', 'Gabon', '{"hr": "Gabon", "mk": "Габон"}'),
|
||||
('GB', 'GBR', 'United Kingdom', '{"hr": "Ujedinjeno Kraljevstvo", "mk": "Обединето Кралство"}'),
|
||||
('GD', 'GRD', 'Grenada', '{"hr": "Grenada", "mk": "Гренада"}'),
|
||||
('GE', 'GEO', 'Georgia', '{"hr": "Gruzija", "mk": "Грузија"}'),
|
||||
('GF', 'GUF', 'French Guiana', '{"hr": "Francuska Gijana", "mk": "Француска Гвајана"}'),
|
||||
('GG', 'GGY', 'Guernsey', '{"hr": "Guernsey", "mk": "Гернзи"}'),
|
||||
('GH', 'GHA', 'Ghana', '{"hr": "Gana", "mk": "Гана"}'),
|
||||
('GI', 'GIB', 'Gibraltar', '{"hr": "Gibraltar", "mk": "Гибралтар"}'),
|
||||
('GL', 'GRL', 'Greenland', '{"hr": "Grenland", "mk": "Гренланд"}'),
|
||||
('GM', 'GMB', 'Gambia', '{"hr": "Gambija", "mk": "Гамбија"}'),
|
||||
('GN', 'GIN', 'Guinea', '{"hr": "Gvineja", "mk": "Гвинеја"}'),
|
||||
('GP', 'GLP', 'Guadeloupe', '{"hr": "Guadalupe", "mk": "Гвадалупе"}'),
|
||||
('GQ', 'GNQ', 'Equatorial Guinea', '{"hr": "Ekvatorska Gvineja", "mk": "Екваторска Гвинеја"}'),
|
||||
('GR', 'GRC', 'Greece', '{"hr": "Grčka", "mk": "Грција"}'),
|
||||
('GS', 'SGS', 'South Georgia and the South Sandwich Islands', '{"hr": "Južna Georgia i Otoci Južni Sandwich", "mk": "Јужна Џорџија и Јужни Сендвички Острови"}'),
|
||||
('GT', 'GTM', 'Guatemala', '{"hr": "Gvatemala", "mk": "Гватемала"}'),
|
||||
('GU', 'GUM', 'Guam', '{"hr": "Guam", "mk": "Гуам"}'),
|
||||
('GW', 'GNB', 'Guinea-Bissau', '{"hr": "Gvineja Bisau", "mk": "Гвинеја Бисао"}'),
|
||||
('GY', 'GUY', 'Guyana', '{"hr": "Gvajana", "mk": "Гвајана"}'),
|
||||
('HK', 'HKG', 'Hong Kong', '{"hr": "PUP Hong Kong Kina", "mk": "Хонгконг САР Кина"}'),
|
||||
('HM', 'HMD', 'Heard Island and McDonald Islands', '{"hr": "Otoci Heard i McDonald", "mk": "Остров Херд и Острови Мекдоналд"}'),
|
||||
('HN', 'HND', 'Honduras', '{"hr": "Honduras", "mk": "Хондурас"}'),
|
||||
('HR', 'HRV', 'Croatia', '{"hr": "Hrvatska", "mk": "Хрватска"}'),
|
||||
('HT', 'HTI', 'Haiti', '{"hr": "Haiti", "mk": "Хаити"}'),
|
||||
('HU', 'HUN', 'Hungary', '{"hr": "Mađarska", "mk": "Унгарија"}'),
|
||||
('ID', 'IDN', 'Indonesia', '{"hr": "Indonezija", "mk": "Индонезија"}'),
|
||||
('IE', 'IRL', 'Ireland', '{"hr": "Irska", "mk": "Ирска"}'),
|
||||
('IL', 'ISR', 'Israel', '{"hr": "Izrael", "mk": "Израел"}'),
|
||||
('IM', 'IMN', 'Isle of Man', '{"hr": "Otok Man", "mk": "Остров Ман"}'),
|
||||
('IN', 'IND', 'India', '{"hr": "Indija", "mk": "Индија"}'),
|
||||
('IO', 'IOT', 'British Indian Ocean Territory', '{"hr": "Britanski Indijskooceanski Teritorij", "mk": "Британска Индоокеанска Територија"}'),
|
||||
('IQ', 'IRQ', 'Iraq', '{"hr": "Irak", "mk": "Ирак"}'),
|
||||
('IR', 'IRN', 'Iran', '{"hr": "Iran", "mk": "Иран"}'),
|
||||
('IS', 'ISL', 'Iceland', '{"hr": "Island", "mk": "Исланд"}'),
|
||||
('IT', 'ITA', 'Italy', '{"hr": "Italija", "mk": "Италија"}'),
|
||||
('JE', 'JEY', 'Jersey', '{"hr": "Jersey", "mk": "Џерси"}'),
|
||||
('JM', 'JAM', 'Jamaica', '{"hr": "Jamajka", "mk": "Јамајка"}'),
|
||||
('JO', 'JOR', 'Jordan', '{"hr": "Jordan", "mk": "Јордан"}'),
|
||||
('JP', 'JPN', 'Japan', '{"hr": "Japan", "mk": "Јапонија"}'),
|
||||
('KE', 'KEN', 'Kenya', '{"hr": "Kenija", "mk": "Кенија"}'),
|
||||
('KG', 'KGZ', 'Kyrgyzstan', '{"hr": "Kirgistan", "mk": "Киргистан"}'),
|
||||
('KH', 'KHM', 'Cambodia', '{"hr": "Kambodža", "mk": "Камбоџа"}'),
|
||||
('KI', 'KIR', 'Kiribati', '{"hr": "Kiribati", "mk": "Кирибати"}'),
|
||||
('KM', 'COM', 'Comoros', '{"hr": "Komori", "mk": "Коморски Острови"}'),
|
||||
('KN', 'KNA', 'Saint Kitts and Nevis', '{"hr": "Sveti Kristofor i Nevis", "mk": "Свети Китс и Невис"}'),
|
||||
('KP', 'PRK', 'North Korea', '{"hr": "Sjeverna Koreja", "mk": "Северна Кореја"}'),
|
||||
('KR', 'KOR', 'South Korea', '{"hr": "Južna Koreja", "mk": "Јужна Кореја"}'),
|
||||
('KW', 'KWT', 'Kuwait', '{"hr": "Kuvajt", "mk": "Кувајт"}'),
|
||||
('KY', 'CYM', 'Cayman Islands', '{"hr": "Kajmanski Otoci", "mk": "Кајмански Острови"}'),
|
||||
('KZ', 'KAZ', 'Kazakhstan', '{"hr": "Kazahstan", "mk": "Казахстан"}'),
|
||||
('LA', 'LAO', 'Laos', '{"hr": "Laos", "mk": "Лаос"}'),
|
||||
('LB', 'LBN', 'Lebanon', '{"hr": "Libanon", "mk": "Либан"}'),
|
||||
('LC', 'LCA', 'Saint Lucia', '{"hr": "Sveta Lucija", "mk": "Сент Лусија"}'),
|
||||
('LI', 'LIE', 'Liechtenstein', '{"hr": "Lihtenštajn", "mk": "Лихтенштајн"}'),
|
||||
('LK', 'LKA', 'Sri Lanka', '{"hr": "Šri Lanka", "mk": "Шри Ланка"}'),
|
||||
('LR', 'LBR', 'Liberia', '{"hr": "Liberija", "mk": "Либерија"}'),
|
||||
('LS', 'LSO', 'Lesotho', '{"hr": "Lesoto", "mk": "Лесото"}'),
|
||||
('LT', 'LTU', 'Lithuania', '{"hr": "Litva", "mk": "Литванија"}'),
|
||||
('LU', 'LUX', 'Luxembourg', '{"hr": "Luksemburg", "mk": "Луксембург"}'),
|
||||
('LV', 'LVA', 'Latvia', '{"hr": "Latvija", "mk": "Латвија"}'),
|
||||
('LY', 'LBY', 'Libya', '{"hr": "Libija", "mk": "Либија"}'),
|
||||
('MA', 'MAR', 'Morocco', '{"hr": "Maroko", "mk": "Мароко"}'),
|
||||
('MC', 'MCO', 'Monaco', '{"hr": "Monako", "mk": "Монако"}'),
|
||||
('MD', 'MDA', 'Moldova', '{"hr": "Moldavija", "mk": "Молдавија"}'),
|
||||
('ME', 'MNE', 'Montenegro', '{"hr": "Crna Gora", "mk": "Црна Гора"}'),
|
||||
('MF', 'MAF', 'Saint Martin (French part)', '{"hr": "Saint Martin", "mk": "Сент Мартин"}'),
|
||||
('MG', 'MDG', 'Madagascar', '{"hr": "Madagaskar", "mk": "Мадагаскар"}'),
|
||||
('MH', 'MHL', 'Marshall Islands', '{"hr": "Maršalovi Otoci", "mk": "Маршалски Острови"}'),
|
||||
('MK', 'MKD', 'North Macedonia', '{"hr": "Sjeverna Makedonija", "mk": "Северна Македонија"}'),
|
||||
('ML', 'MLI', 'Mali', '{"hr": "Mali", "mk": "Мали"}'),
|
||||
('MM', 'MMR', 'Myanmar', '{"hr": "Mjanmar (Burma)", "mk": "Мјанмар (Бурма)"}'),
|
||||
('MN', 'MNG', 'Mongolia', '{"hr": "Mongolija", "mk": "Монголија"}'),
|
||||
('MO', 'MAC', 'Macao', '{"hr": "PUP Makao Kina", "mk": "Макао САР"}'),
|
||||
('MP', 'MNP', 'Northern Mariana Islands', '{"hr": "Sjevernomarijanski Otoci", "mk": "Северни Маријански Острови"}'),
|
||||
('MQ', 'MTQ', 'Martinique', '{"hr": "Martinik", "mk": "Мартиник"}'),
|
||||
('MR', 'MRT', 'Mauritania', '{"hr": "Mauretanija", "mk": "Мавританија"}'),
|
||||
('MS', 'MSR', 'Montserrat', '{"hr": "Montserrat", "mk": "Монсерат"}'),
|
||||
('MT', 'MLT', 'Malta', '{"hr": "Malta", "mk": "Малта"}'),
|
||||
('MU', 'MUS', 'Mauritius', '{"hr": "Mauricijus", "mk": "Маврициус"}'),
|
||||
('MV', 'MDV', 'Maldives', '{"hr": "Maldivi", "mk": "Малдиви"}'),
|
||||
('MW', 'MWI', 'Malawi', '{"hr": "Malavi", "mk": "Малави"}'),
|
||||
('MX', 'MEX', 'Mexico', '{"hr": "Meksiko", "mk": "Мексико"}'),
|
||||
('MY', 'MYS', 'Malaysia', '{"hr": "Malezija", "mk": "Малезија"}'),
|
||||
('MZ', 'MOZ', 'Mozambique', '{"hr": "Mozambik", "mk": "Мозамбик"}'),
|
||||
('NA', 'NAM', 'Namibia', '{"hr": "Namibija", "mk": "Намибија"}'),
|
||||
('NC', 'NCL', 'New Caledonia', '{"hr": "Nova Kaledonija", "mk": "Нова Каледонија"}'),
|
||||
('NE', 'NER', 'Niger', '{"hr": "Niger", "mk": "Нигер"}'),
|
||||
('NF', 'NFK', 'Norfolk Island', '{"hr": "Otok Norfolk", "mk": "Норфолшки Остров"}'),
|
||||
('NG', 'NGA', 'Nigeria', '{"hr": "Nigerija", "mk": "Нигерија"}'),
|
||||
('NI', 'NIC', 'Nicaragua', '{"hr": "Nikaragva", "mk": "Никарагва"}'),
|
||||
('NL', 'NLD', 'Netherlands', '{"hr": "Nizozemska", "mk": "Холандија"}'),
|
||||
('NO', 'NOR', 'Norway', '{"hr": "Norveška", "mk": "Норвешка"}'),
|
||||
('NP', 'NPL', 'Nepal', '{"hr": "Nepal", "mk": "Непал"}'),
|
||||
('NR', 'NRU', 'Nauru', '{"hr": "Nauru", "mk": "Науру"}'),
|
||||
('NU', 'NIU', 'Niue', '{"hr": "Niue", "mk": "Ниује"}'),
|
||||
('NZ', 'NZL', 'New Zealand', '{"hr": "Novi Zeland", "mk": "Нов Зеланд"}'),
|
||||
('OM', 'OMN', 'Oman', '{"hr": "Oman", "mk": "Оман"}'),
|
||||
('PA', 'PAN', 'Panama', '{"hr": "Panama", "mk": "Панама"}'),
|
||||
('PE', 'PER', 'Peru', '{"hr": "Peru", "mk": "Перу"}'),
|
||||
('PF', 'PYF', 'French Polynesia', '{"hr": "Francuska Polinezija", "mk": "Француска Полинезија"}'),
|
||||
('PG', 'PNG', 'Papua New Guinea', '{"hr": "Papua Nova Gvineja", "mk": "Папуа Нова Гвинеја"}'),
|
||||
('PH', 'PHL', 'Philippines', '{"hr": "Filipini", "mk": "Филипини"}'),
|
||||
('PK', 'PAK', 'Pakistan', '{"hr": "Pakistan", "mk": "Пакистан"}'),
|
||||
('PL', 'POL', 'Poland', '{"hr": "Poljska", "mk": "Полска"}'),
|
||||
('PM', 'SPM', 'Saint Pierre and Miquelon', '{"hr": "Sveti Petar i Mikelon", "mk": "Сент Пјер и Микелан"}'),
|
||||
('PN', 'PCN', 'Pitcairn', '{"hr": "Pitcairnovi Otoci", "mk": "Питкернски Острови"}'),
|
||||
('PR', 'PRI', 'Puerto Rico', '{"hr": "Portoriko", "mk": "Порторико"}'),
|
||||
('PS', 'PSE', 'Palestine, State of', '{"hr": "Palestinsko područje", "mk": "Палестински Територии"}'),
|
||||
('PT', 'PRT', 'Portugal', '{"hr": "Portugal", "mk": "Португалија"}'),
|
||||
('PW', 'PLW', 'Palau', '{"hr": "Palau", "mk": "Палау"}'),
|
||||
('PY', 'PRY', 'Paraguay', '{"hr": "Paragvaj", "mk": "Парагвај"}'),
|
||||
('QA', 'QAT', 'Qatar', '{"hr": "Katar", "mk": "Катар"}'),
|
||||
('RE', 'REU', 'Réunion', '{"hr": "Réunion", "mk": "Рејунион"}'),
|
||||
('RO', 'ROU', 'Romania', '{"hr": "Rumunjska", "mk": "Романија"}'),
|
||||
('RS', 'SRB', 'Serbia', '{"hr": "Srbija", "mk": "Србија"}'),
|
||||
('RU', 'RUS', 'Russian Federation', '{"hr": "Rusija", "mk": "Русија"}'),
|
||||
('RW', 'RWA', 'Rwanda', '{"hr": "Ruanda", "mk": "Руанда"}'),
|
||||
('SA', 'SAU', 'Saudi Arabia', '{"hr": "Saudijska Arabija", "mk": "Саудиска Арабија"}'),
|
||||
('SB', 'SLB', 'Solomon Islands', '{"hr": "Salomonovi Otoci", "mk": "Соломонски Острови"}'),
|
||||
('SC', 'SYC', 'Seychelles', '{"hr": "Sejšeli", "mk": "Сејшели"}'),
|
||||
('SD', 'SDN', 'Sudan', '{"hr": "Sudan", "mk": "Судан"}'),
|
||||
('SE', 'SWE', 'Sweden', '{"hr": "Švedska", "mk": "Шведска"}'),
|
||||
('SG', 'SGP', 'Singapore', '{"hr": "Singapur", "mk": "Сингапур"}'),
|
||||
('SH', 'SHN', 'Saint Helena, Ascension and Tristan da Cunha', '{"hr": "Sveta Helena", "mk": "Света Елена"}'),
|
||||
('SI', 'SVN', 'Slovenia', '{"hr": "Slovenija", "mk": "Словенија"}'),
|
||||
('SJ', 'SJM', 'Svalbard and Jan Mayen', '{"hr": "Svalbard i Jan Mayen", "mk": "Свалбард и Јан Мајен"}'),
|
||||
('SK', 'SVK', 'Slovakia', '{"hr": "Slovačka", "mk": "Словачка"}'),
|
||||
('SL', 'SLE', 'Sierra Leone', '{"hr": "Sijera Leone", "mk": "Сиера Леоне"}'),
|
||||
('SM', 'SMR', 'San Marino', '{"hr": "San Marino", "mk": "Сан Марино"}'),
|
||||
('SN', 'SEN', 'Senegal', '{"hr": "Senegal", "mk": "Сенегал"}'),
|
||||
('SO', 'SOM', 'Somalia', '{"hr": "Somalija", "mk": "Сомалија"}'),
|
||||
('SR', 'SUR', 'Suriname', '{"hr": "Surinam", "mk": "Суринам"}'),
|
||||
('SS', 'SSD', 'South Sudan', '{"hr": "Južni Sudan", "mk": "Јужен Судан"}'),
|
||||
('ST', 'STP', 'Sao Tome and Principe', '{"hr": "Sveti Toma i Princip", "mk": "Саун Томе и Принсип"}'),
|
||||
('SV', 'SLV', 'El Salvador', '{"hr": "Salvador", "mk": "Ел Салвадор"}'),
|
||||
('SX', 'SXM', 'Sint Maarten (Dutch part)', '{"hr": "Sint Maarten", "mk": "Свети Мартин"}'),
|
||||
('SY', 'SYR', 'Syria', '{"hr": "Sirija", "mk": "Сирија"}'),
|
||||
('SZ', 'SWZ', 'Eswatini', '{"hr": "Esvatini", "mk": "Свазиленд"}'),
|
||||
('TC', 'TCA', 'Turks and Caicos Islands', '{"hr": "Otoci Turks i Caicos", "mk": "Острови Туркс и Каикос"}'),
|
||||
('TD', 'TCD', 'Chad', '{"hr": "Čad", "mk": "Чад"}'),
|
||||
('TF', 'ATF', 'French Southern Territories', '{"hr": "Francuski Južni Teritoriji", "mk": "Француски Јужни Територии"}'),
|
||||
('TG', 'TGO', 'Togo', '{"hr": "Togo", "mk": "Того"}'),
|
||||
('TH', 'THA', 'Thailand', '{"hr": "Tajland", "mk": "Тајланд"}'),
|
||||
('TJ', 'TJK', 'Tajikistan', '{"hr": "Tadžikistan", "mk": "Таџикистан"}'),
|
||||
('TK', 'TKL', 'Tokelau', '{"hr": "Tokelau", "mk": "Токелау"}'),
|
||||
('TL', 'TLS', 'Timor-Leste', '{"hr": "Timor-Leste", "mk": "Тимор Лесте"}'),
|
||||
('TM', 'TKM', 'Turkmenistan', '{"hr": "Turkmenistan", "mk": "Туркменистан"}'),
|
||||
('TN', 'TUN', 'Tunisia', '{"hr": "Tunis", "mk": "Тунис"}'),
|
||||
('TO', 'TON', 'Tonga', '{"hr": "Tonga", "mk": "Тонга"}'),
|
||||
('TR', 'TUR', 'Türkiye', '{"hr": "Turska", "mk": "Турција"}'),
|
||||
('TT', 'TTO', 'Trinidad and Tobago', '{"hr": "Trinidad i Tobago", "mk": "Тринидад и Тобаго"}'),
|
||||
('TV', 'TUV', 'Tuvalu', '{"hr": "Tuvalu", "mk": "Тувалу"}'),
|
||||
('TW', 'TWN', 'Taiwan', '{"hr": "Tajvan", "mk": "Тајван"}'),
|
||||
('TZ', 'TZA', 'Tanzania', '{"hr": "Tanzanija", "mk": "Танзанија"}'),
|
||||
('UA', 'UKR', 'Ukraine', '{"hr": "Ukrajina", "mk": "Украина"}'),
|
||||
('UG', 'UGA', 'Uganda', '{"hr": "Uganda", "mk": "Уганда"}'),
|
||||
('UM', 'UMI', 'United States Minor Outlying Islands', '{"hr": "Mali udaljeni otoci SAD-a", "mk": "Американски територии во Пацификот"}'),
|
||||
('US', 'USA', 'United States', '{"hr": "Sjedinjene Američke Države", "mk": "Соединети Американски Држави"}'),
|
||||
('UY', 'URY', 'Uruguay', '{"hr": "Urugvaj", "mk": "Уругвај"}'),
|
||||
('UZ', 'UZB', 'Uzbekistan', '{"hr": "Uzbekistan", "mk": "Узбекистан"}'),
|
||||
('VA', 'VAT', 'Holy See (Vatican City State)', '{"hr": "Vatikan", "mk": "Ватикан"}'),
|
||||
('VC', 'VCT', 'Saint Vincent and the Grenadines', '{"hr": "Sveti Vincent i Grenadini", "mk": "Сент Винсент и Гренадини"}'),
|
||||
('VE', 'VEN', 'Venezuela', '{"hr": "Venezuela", "mk": "Венецуела"}'),
|
||||
('VG', 'VGB', 'Virgin Islands, British', '{"hr": "Britanski Djevičanski Otoci", "mk": "Британски Девствени Острови"}'),
|
||||
('VI', 'VIR', 'Virgin Islands, U.S.', '{"hr": "Američki Djevičanski Otoci", "mk": "Американски Девствени Острови"}'),
|
||||
('VN', 'VNM', 'Vietnam', '{"hr": "Vijetnam", "mk": "Виетнам"}'),
|
||||
('VU', 'VUT', 'Vanuatu', '{"hr": "Vanuatu", "mk": "Вануату"}'),
|
||||
('WF', 'WLF', 'Wallis and Futuna', '{"hr": "Wallis i Futuna", "mk": "Валис и Футуна"}'),
|
||||
('WS', 'WSM', 'Samoa', '{"hr": "Samoa", "mk": "Самоа"}'),
|
||||
('XK', 'XKX', 'Kosovo', '{"hr": "Kosovo", "mk": "Косово"}'),
|
||||
('YE', 'YEM', 'Yemen', '{"hr": "Jemen", "mk": "Јемен"}'),
|
||||
('YT', 'MYT', 'Mayotte', '{"hr": "Mayotte", "mk": "Мајот"}'),
|
||||
('ZA', 'ZAF', 'South Africa', '{"hr": "Južnoafrička Republika", "mk": "Јужноафриканска Република"}'),
|
||||
('ZM', 'ZMB', 'Zambia', '{"hr": "Zambija", "mk": "Замбија"}'),
|
||||
('ZW', 'ZWE', 'Zimbabwe', '{"hr": "Zimbabve", "mk": "Зимбабве"}');
|
||||
10
docker-definitions/postgres-eventsdb/init/05-sports.sql
Normal file
10
docker-definitions/postgres-eventsdb/init/05-sports.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
INSERT INTO sport (name) VALUES
|
||||
('Running'),
|
||||
('Darts'),
|
||||
('Bowling'),
|
||||
('Table Tennis'),
|
||||
('Chess'),
|
||||
('Pikado'),
|
||||
('Mini Golf'),
|
||||
('Swimming'),
|
||||
('Cycling');
|
||||
1950
docker-definitions/postgres-eventsdb/init/06-people.sql
Normal file
1950
docker-definitions/postgres-eventsdb/init/06-people.sql
Normal file
File diff suppressed because it is too large
Load Diff
5
docker-definitions/postgres-eventsdb/init/07-events.sql
Normal file
5
docker-definitions/postgres-eventsdb/init/07-events.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
INSERT INTO event (name, event_date) VALUES
|
||||
('Union Games', '2026-03-12'),
|
||||
('Faculty Meetup', '2026-04-25'),
|
||||
('City Cup', '2026-06-03'),
|
||||
('Research Forum', '2026-09-18');
|
||||
6
docker-definitions/postgres-eventsdb/init/check-db.sh
Normal file
6
docker-definitions/postgres-eventsdb/init/check-db.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Docker init env varovi
|
||||
USER=${POSTGRES_USER:-postgres}
|
||||
DB=${POSTGRES_DB:-postgres}
|
||||
|
||||
pg_isready -U "$USER" -d "$DB"
|
||||
Reference in New Issue
Block a user