Skip to content
This repository has been archived by the owner on Jun 13, 2020. It is now read-only.

Create tables and initialize with dummy data if required #158

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions Pirat/DatabaseContext/DatabaseInitialization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Npgsql;
using Pirat.Model.Entity.Resource.Common;
using Pirat.Model.Entity.Resource.Stock;

namespace Pirat.DatabaseContext
{

/// <summary>
/// The related tables if an offer is inserted to the database
/// </summary>
public class OfferContext
{
[JsonProperty]
public AddressEntity Address { get; set; }

[JsonProperty]
public OfferEntity Offer { get; set; }

[JsonProperty]
public List<ConsumableEntity> Consumables { get; set; }

[JsonProperty]
public List<DeviceEntity> Devices { get; set; }

[JsonProperty]
public List<PersonalEntity> Personals { get; set; }
}

public class OffersInitialization
{
[JsonProperty]
public List<OfferContext> OfferContexts { get; set; }
}

public static class DatabaseInitialization
{

private static readonly string DatabaseInitializationFilesLocation =
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

/// <summary>
/// Checks if connection to database can be established. Otherwise exception is thrown.
/// </summary>
public static void CheckConnectionToDatabase()
{
var connection = new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION"));
connection.Open();
connection.Dispose();
}

/// <summary>
/// Create new tables in database if not exist so far. Table create commands are read from init.sql.
/// </summary>
public static void InitDatabaseTables()
{
CheckConnectionToDatabase();

var initSqlFile = Path.Combine(DatabaseInitializationFilesLocation, "init.sql");

var commandsInput = File.ReadAllText(initSqlFile, Encoding.UTF8);

var commands = commandsInput.Split(';');

var tablesBefore = FindExistingTables();
Console.Out.WriteLine($"Tables in database:");
foreach (var table in tablesBefore)
{
Console.Out.WriteLine($"{table}");
}

using (NpgsqlConnection connection =
new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION")))
{
connection.Open();

foreach (var command in commands)
{
using NpgsqlCommand sqlCommand = new NpgsqlCommand(command + ";", connection);
sqlCommand.ExecuteNonQuery();
}
}

var tablesAfter = FindExistingTables();
foreach (var table in tablesAfter.Except(tablesBefore))
{
Console.Out.WriteLine($"Created table: {table}");
}
}

/// <summary>
/// The database that is found by using the connection string is initialized with dummy data.
/// Dummy data will only be inserted if associated tables are empty.
/// </summary>
public static async void InitDatabaseWithDummyData()
{
CheckConnectionToDatabase();

DbContextOptions<ResourceContext> options =
new DbContextOptionsBuilder<ResourceContext>().UseNpgsql(Environment.GetEnvironmentVariable("PIRAT_CONNECTION")).Options;

await using var context = new ResourceContext(options);
//Insert only dummy values if offer table empty
if (!context.offer.Any())
{
var dummyData = Path.Combine(DatabaseInitializationFilesLocation, "init_dummy_offers.json");
var content = File.ReadAllText(dummyData);
var offerInit = JsonConvert.DeserializeObject<OffersInitialization>(content);
foreach (var offerContext in offerInit.OfferContexts)
{
var address = (AddressEntity) await offerContext.Address.InsertAsync(context);
offerContext.Offer.address_id = address.Id;
var offer = (OfferEntity) await offerContext.Offer.InsertAsync(context);

if (offerContext.Consumables != null)
{
foreach (var consumable in offerContext.Consumables)
{
consumable.offer_id = offer.id;
await consumable.InsertAsync(context);
}
}

if (offerContext.Devices != null)
{
foreach (var device in offerContext.Devices)
{
device.offer_id = offer.id;
await device.InsertAsync(context);
}
}

if (offerContext.Personals != null)
{
foreach (var personal in offerContext.Personals)
{
personal.offer_id = offer.id;
await personal.InsertAsync(context);
}
}
}
}
//Insert other dummy data contexts here
}

private static List<string> FindExistingTables()
{
var existingTables = new List<string>();
using (NpgsqlConnection connection =
new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION")))
{
connection.Open();
using NpgsqlCommand c = new NpgsqlCommand("SELECT table_name " +
"FROM information_schema.tables " +
"WHERE table_schema = 'public' " +
"AND table_type = 'BASE TABLE';", connection);

using NpgsqlDataReader rdr = c.ExecuteReader();
while (rdr.Read())
{
existingTables.Add(rdr.GetString(0));
}
}

return existingTables;
}
}
}
17 changes: 17 additions & 0 deletions Pirat/Pirat.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,21 @@
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

<ItemGroup>
<Content Include="..\init.sql">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="..\init_dummy_offers.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<Compile Update="Program.cs">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Compile>
</ItemGroup>

</Project>
23 changes: 12 additions & 11 deletions Pirat/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Npgsql;
using Pirat.DatabaseContext;

namespace Pirat
{
Expand All @@ -13,7 +13,13 @@ public class Program
public static void Main(string[] args)
{
CheckEnvironmentVariables();
CheckConnectionToDatabase();

DatabaseInitialization.CheckConnectionToDatabase();
var initTables = Environment.GetEnvironmentVariable("PIRAT_INIT_DB_TABLES_IF_NOT_EXIST")?.Equals("true", StringComparison.Ordinal);
var initData = Environment.GetEnvironmentVariable("PIRAT_INIT_DUMMY_DATA_IF_NOT_EXIST")?.Equals("true", StringComparison.Ordinal);
if (initTables.HasValue) DatabaseInitialization.InitDatabaseTables();
if (initData.HasValue) DatabaseInitialization.InitDatabaseWithDummyData();

CreateHostBuilder(args).Build().Run();
}

Expand All @@ -35,7 +41,10 @@ public static void CheckEnvironmentVariables()

"PIRAT_ADMIN_KEY",
"PIRAT_SWAGGER_PREFIX_PATH",
"PIRAT_WEBAPP_ENVIRONMENT"
"PIRAT_WEBAPP_ENVIRONMENT",

"PIRAT_INIT_DB_TABLES_IF_NOT_EXIST",
"PIRAT_INIT_DUMMY_DATA_IF_NOT_EXIST"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variables should be optional with false being the default. Please also don't forget to edit the README.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see a disadvantage here to let them non optional. At least the developer or the server must initialize the fields with something. It's not much work...

};
foreach (var requiredEnvironmentVariable in requiredEnvironmentVariables)
{
Expand All @@ -46,14 +55,6 @@ public static void CheckEnvironmentVariables()
}
}

public static void CheckConnectionToDatabase()
{
var connection = new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION"));
connection.Open();
connection.Dispose();
}


public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
Expand Down
30 changes: 15 additions & 15 deletions init.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
create table address
create table if not exists address
(
id serial not null
constraint address_pk
Expand All @@ -18,10 +18,10 @@ create table address
country text not null
);

create unique index address_id_uindex
create unique index if not exists address_id_uindex
on address (id);

create table offer
create table if not exists offer
(
id serial not null
constraint offer_pkey
Expand All @@ -40,7 +40,7 @@ create table offer
region text not null
);

create table consumable
create table if not exists consumable
(
id serial not null
constraint consumables_pk
Expand All @@ -59,10 +59,10 @@ create table consumable
is_deleted boolean default false not null
);

create unique index consumables_id_uindex
create unique index if not exists consumables_id_uindex
on consumable (id);

create table device
create table if not exists device
(
category text not null,
name text not null,
Expand All @@ -80,10 +80,10 @@ create table device
is_deleted boolean default false not null
);

create unique index device_id_uindex
create unique index if not exists device_id_uindex
on device (id);

create table personal
create table if not exists personal
(
id serial not null
constraint manpower_pk
Expand All @@ -101,10 +101,10 @@ create table personal
is_deleted boolean default false not null
);

create unique index manpower_id_uindex
create unique index if not exists manpower_id_uindex
on personal (id);

create table region_subscription
create table if not exists region_subscription
(
id serial not null
constraint region_subscription_pk
Expand All @@ -120,7 +120,7 @@ create table region_subscription
region text not null
);

create table change
create table if not exists change
(
id serial not null
constraint change_pk
Expand All @@ -136,7 +136,7 @@ create table change
region text not null
);

create table demand
create table if not exists demand
(
id serial not null
constraint demand_pk
Expand All @@ -153,10 +153,10 @@ create table demand
created_at_timestamp timestamp not null
);

create index demand_token_index
create index if not exists demand_token_index
on demand (token);

create table demand_device
create table if not exists demand_device
(
id serial not null
constraint demand_device_pk
Expand All @@ -174,7 +174,7 @@ create table demand_device
is_deleted boolean not null
);

create table demand_consumable
create table if not exists demand_consumable
(
id serial not null
constraint demand_consumable_pk
Expand Down
Loading