Files
raven/server/AyaNova/util/AySchema.cs
2018-08-28 20:12:51 +00:00

299 lines
11 KiB
C#

using System;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using AyaNova.Models;
namespace AyaNova.Util
{
//Key generator controller
public static class AySchema
{
private static ILogger log;
private static AyContext ct;
/////////////////////////////////////////////////////////////////
/////////// CHANGE THIS ON NEW SCHEMA UPDATE ////////////////////
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 9;
internal const long EXPECTED_COLUMN_COUNT = 75;
internal const long EXPECTED_INDEX_COUNT = 15;
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!!
/////////////////////////////////////////////////////////////////
static int startingSchema = -1;
public static int currentSchema = -1;
//check and update schema
public static void CheckAndUpdate(AyContext context, ILogger logger)
{
ct = context;
log = logger;
//Check if ayschemaversion table exists
bool aySchemaVersionExists = false;
using (var command = ct.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "SELECT * FROM information_schema.tables WHERE table_name = 'aschemaversion'";
ct.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
if (result.HasRows)
{
aySchemaVersionExists = true;
}
ct.Database.CloseConnection();
}
}
//Create schema table (v1)
if (!aySchemaVersionExists)
{
log.LogDebug("aschemaversion table not found, creating now");
//nope, no schema table, add it now and set to v1
using (var cm = ct.Database.GetDbConnection().CreateCommand())
{
ct.Database.OpenConnection();
cm.CommandText = "CREATE TABLE aschemaversion (schema INTEGER NOT NULL);";
cm.ExecuteNonQuery();
cm.CommandText = "insert into aschemaversion (schema) values (1);";
cm.ExecuteNonQuery();
ct.Database.CloseConnection();
startingSchema = 1;
currentSchema = 1;
}
}
else
{
//get current schema level
using (var cm = ct.Database.GetDbConnection().CreateCommand())
{
log.LogDebug("Fetching current schema version");
cm.CommandText = "SELECT schema FROM aschemaversion;";
ct.Database.OpenConnection();
using (var result = cm.ExecuteReader())
{
if (result.HasRows)
{
result.Read();
currentSchema = startingSchema = result.GetInt32(0);
ct.Database.CloseConnection();
log.LogDebug("AyaNova schema version is " + currentSchema.ToString());
}
else
{
ct.Database.CloseConnection();
throw new System.Exception("AyaNova->AySchema->CheckAndUpdate: Error reading schema version");
}
}
}
}
//Bail early no update?
if (currentSchema == DESIRED_SCHEMA_LEVEL)
{
log.LogDebug("Current schema is at required schema version " + currentSchema.ToString());
return;
}
log.LogInformation("AyaNova database needs to be updated from schema version {0} to version {1}", currentSchema, DESIRED_SCHEMA_LEVEL);
//************* SCHEMA UPDATES ******************
//////////////////////////////////////////////////
// USER table locale text and default data
if (currentSchema < 2)
{
LogUpdateMessage(log);
//create locale text tables
exec("CREATE TABLE alocale (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, name varchar(255) not null, stock bool, created timestamp not null)");
exec("CREATE UNIQUE INDEX localename_idx ON alocale (name)");
exec("CREATE TABLE alocaleitem (id BIGSERIAL PRIMARY KEY, localeid bigint not null REFERENCES alocale (id), key text not null, display text not null)");
exec("CREATE INDEX localeitemlid_key_idx ON alocaleitem (localeid,key)");
//create aevent biz event log table
exec("CREATE TABLE aevent (id BIGSERIAL PRIMARY KEY, created timestamp not null, ownerid bigint not null," +
"ayid bigint not null, aytype integer not null, ayevent integer not null, textra varchar(255))");
//TODO: do I *really* need these or do they bloat unnecessarily? Need to test with big dataset
//index for quick searching
// exec("CREATE INDEX ayid_idx ON aevent (ayid);");
// exec("CREATE INDEX aytype_idx ON aevent (aytype);");
//Prime the db with the default LOCALES
AyaNova.Biz.PrimeData.PrimeLocales(ct);
//Add user table
exec("CREATE TABLE auser (id BIGSERIAL PRIMARY KEY, created timestamp not null, ownerid bigint not null, name varchar(255) not null, " +
"login text not null, password text not null, salt text not null, roles integer not null, localeid bigint REFERENCES alocale (id), " +
"dlkey text, dlkeyexpire timestamp)");
//Prime the db with the default MANAGER account
AyaNova.Biz.PrimeData.PrimeManagerAccount(ct);
setSchemaLevel(++currentSchema);
}
//////////////////////////////////////////////////
//LICENSE table
if (currentSchema < 3)
{
LogUpdateMessage(log);
//Add user table
exec("CREATE TABLE alicense (id BIGSERIAL PRIMARY KEY, key text not null)");
setSchemaLevel(++currentSchema);
}
//////////////////////////////////////////////////
//WIDGET table for development testing
if (currentSchema < 4)
{
LogUpdateMessage(log);
//Add widget table
//id, text, longtext, boolean, currency,
exec("CREATE TABLE awidget (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, name varchar(255) not null, " +
"startdate timestamp, enddate timestamp, dollaramount money, active bool, roles int4)");
setSchemaLevel(++currentSchema);
}
//////////////////////////////////////////////////
// FileAttachment table
if (currentSchema < 5)
{
LogUpdateMessage(log);
exec("CREATE TABLE afileattachment (id BIGSERIAL PRIMARY KEY, created timestamp not null, ownerid bigint not null," +
"attachtoobjectid bigint not null, attachtoobjecttype integer not null, " +
"storedfilename text not null, displayfilename text not null, contenttype text, notes text)");
//index required for ops that need to check if file already in db (delete, count refs etc)
exec("CREATE INDEX storedfilename_idx ON afileattachment (storedfilename);");
setSchemaLevel(++currentSchema);
}
//////////////////////////////////////////////////
//TAG tables
if (currentSchema < 6)
{
LogUpdateMessage(log);
exec("CREATE TABLE atag (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, name varchar(35) not null, created timestamp not null)");
exec("CREATE UNIQUE INDEX tagname_idx ON atag (name);");
exec("CREATE TABLE atagmap (id BIGSERIAL PRIMARY KEY, created timestamp not null, ownerid bigint not null," +
"tagid bigint not null REFERENCES atag (id), tagtoobjectid bigint not null, tagtoobjecttype integer not null)");
setSchemaLevel(++currentSchema);
}
//////////////////////////////////////////////////
// OPS LRO tables
if (currentSchema < 7)
{
LogUpdateMessage(log);
exec("CREATE TABLE aopsjob (gid uuid PRIMARY KEY, ownerid bigint not null, name text not null, created timestamp not null, exclusive bool not null, " +
"startafter timestamp not null, jobtype integer not null, objectid bigint null, objecttype integer null, jobstatus integer not null, jobinfo text null)");
exec("CREATE TABLE aopsjoblog (gid uuid PRIMARY KEY, jobid uuid not null REFERENCES aopsjob (gid), created timestamp not null, statustext text not null)");
setSchemaLevel(++currentSchema);
}
//////////////////////////////////////////////////
//LICENSE table new columns
//TODO: DO I need this anymore???
if (currentSchema < 8)
{
LogUpdateMessage(log);
//Add license related stuff
exec("ALTER TABLE alicense ADD COLUMN dbid uuid");
exec("ALTER TABLE alicense ADD COLUMN LastFetchStatus integer");
exec("ALTER TABLE alicense ADD COLUMN LastFetchMessage text");
setSchemaLevel(++currentSchema);
}
//////////////////////////////////////////////////
// FUTURE
// if (currentSchema < 9)
// {
// LogUpdateMessage(log);
// setSchemaLevel(++currentSchema);
// }
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!!
log.LogInformation("Finished updating database schema to version {0}", currentSchema);
//*************************************************************************************
}//eofunction
private static void setSchemaLevel(int nCurrentSchema)
{
exec("UPDATE aschemaversion SET schema=" + nCurrentSchema.ToString());
}
//execute command query
private static void exec(string q)
{
using (var cm = ct.Database.GetDbConnection().CreateCommand())
{
ct.Database.OpenConnection();
cm.CommandText = q;
cm.ExecuteNonQuery();
ct.Database.CloseConnection();
}
}
private static void LogUpdateMessage(ILogger log)
{
log.LogDebug($"Updating database to schema version {currentSchema + 1}");
}
//eoclass
}
//eons
}