/// <summary> /// Update/Insert the given input object /// </summary> /// <typeparam name="T"></typeparam> /// <param name="input"></param> /// <returns></returns> public T UpsertRecord <T>(T input) where T : IStaticType, new() { var actualType = input.GetType(); var entityName = actualType.Name; var type = _dataType.FromType(actualType); if (type == null) { throw new ArgumentException("Given entityName does not exists."); } input.__updatedAt = DateTime.Now; if (input.Id == 0) { input.__createdAt = DateTime.Now; NancyBlackDatabase.ObjectCreating(this, entityName, input); _db.Insert(input, actualType); NancyBlackDatabase.ObjectCreated(this, entityName, input); } else { NancyBlackDatabase.ObjectUpdating(this, entityName, input); _db.Update(input, actualType); NancyBlackDatabase.ObjectUpdated(this, entityName, input); } return(input); }
/// <summary> /// Delay Insert the specified item /// </summary> /// <param name="item"></param> public static void DelayedInsert(this NancyBlackDatabase db, dynamic item) { var t = item.GetType(); dynamic buffer; if (_buffers.TryGetValue(t, out buffer) == false) { buffer = DelayedInsertExt.CreateBuffer(db.DatabaseFileName, t); _buffers.AddOrUpdate(t, buffer, new Func <Type, object, object>((tin, o) => o)); } buffer.Add(item); }
/// <summary> /// Changes the delay time for /// </summary> /// <param name="t"></param> /// <param name="delay"></param> public static void SetFlushDelay(this NancyBlackDatabase db, Type t, TimeSpan delay) { dynamic buffer; if (_buffers.TryGetValue(t, out buffer)) { buffer.FlushDelay = delay; } else { buffer = DelayedInsertExt.CreateBuffer(db.DatabaseFileName, t); } }
/// <summary> /// Gets site database from given Context /// </summary> /// <param name="hostName"></param> /// <returns></returns> public static NancyBlackDatabase GetSiteDatabase(string rootPath, NancyContext context = null) { var path = Path.Combine(rootPath, "Site"); var fileName = Path.Combine(path, "data.sqlite"); var db = new SQLiteConnection(fileName, true); var ndb = new NancyBlackDatabase(db, context); ndb.DatabaseFileName = fileName; ndb.DatabaseDirectory = path; return(ndb); }
/// <summary> /// Deletes the record /// </summary> /// <typeparam name="T"></typeparam> /// <param name="input"></param> public void DeleteRecord <T>(T input) where T : IStaticType, new() { var actualType = input.GetType(); var entityName = actualType.Name; var deleting = this.GetById <T>(input.Id); // get the object out before delete NancyBlackDatabase.ObjectDeleting(this, entityName, deleting); _db.Delete(deleting); NancyBlackDatabase.ObjectDeleted(this, entityName, deleting); }
/// <summary> /// Update Record FAST, this will directly update the record to database /// </summary> /// <param name="entityName"></param> /// <param name="inputObject"></param> /// <returns></returns> public dynamic UpsertStaticRecord(string entityName, dynamic inputObject) { var type = _dataType.FromName(entityName); if (type == null) { throw new ArgumentException("Given entityName does not exists."); } var actualType = type.GetCompiledType(); if (inputObject is JObject) { inputObject = ((JObject)inputObject).ToObject(actualType); } if (inputObject.Id == 0) { inputObject.__createdAt = DateTime.Now; inputObject.__updatedAt = DateTime.Now; NancyBlackDatabase.ObjectCreating(this, entityName, inputObject); _db.Insert((object)inputObject, actualType); NancyBlackDatabase.ObjectCreated(this, entityName, inputObject); } else { inputObject.__updatedAt = DateTime.Now; NancyBlackDatabase.ObjectUpdating(this, entityName, inputObject); _db.Update((object)inputObject, actualType); NancyBlackDatabase.ObjectUpdated(this, entityName, inputObject); } return(inputObject); }
/// <summary> /// Generates the view. /// </summary> /// <param name="db">The database.</param> /// <param name="templatePath">The target template path.</param> /// <param name="table_name">The table_name.</param> /// <param name="replace">if set to <c>true</c>, view will be replaced.</param> /// <exception cref="System.InvalidOperationException">Entity: + table_name + does not exists, Insert some sample data before running this page.</exception> protected void GenerateView(NancyBlackDatabase db, string templatePath, string table_name, string layout, bool replace = false, string fileName = null) { if (fileName == null) { fileName = table_name; } var templateFile = Path.Combine( templatePath, fileName + ".cshtml"); if (File.Exists(templateFile) && replace == false) { return; } var type = db.DataType.FromName(table_name); if (type == null) { throw new InvalidOperationException("Entity:" + table_name + " does not exists, Insert some sample data before running this page."); } var template = File.ReadAllText(Path.Combine(this.RootPath, "NancyBlack", "Modules", "DatabaseSystem", "Views", "_backendtemplate.cshtml")); var code = Razor.Parse <ViewModel>(template, new ViewModel() { DataType = type, Layout = layout }, null); Directory.CreateDirectory(templatePath); File.WriteAllText(templateFile, code); }
/// <summary> /// Deletes the specified entity name. /// </summary> /// <param name="entityName">Name of the entity.</param> /// <param name="inputObject">The input object.</param> /// <exception cref="System.InvalidOperationException"> /// Entity: + entityName + does not exists /// or /// Id of inputObject is not set or has default value /// </exception> public void DeleteRecord(string entityName, dynamic inputObject) { var type = _dataType.FromName(entityName); int?id = inputObject.Id == null ? null : inputObject.Id; if (type == null) { throw new InvalidOperationException("Entity: " + entityName + " does not exists"); } if (id == null || id == 0) { throw new InvalidOperationException("Id of inputObject is not set or has default value"); } var deleting = this.GetById(entityName, id.Value); // get the object out before delete NancyBlackDatabase.ObjectDeleting(this, entityName, deleting); _db.Delete(deleting); NancyBlackDatabase.ObjectDeleted(this, entityName, deleting); }
/// <summary> /// Performs the regular backup /// </summary> public void PerformBackup(dynamic backupOptions = null) { if (DateTime.Now.Subtract(_LastBackupCheck).TotalMinutes > 30) { _LastBackupCheck = DateTime.Now; } else { // No Need to do the backup now return; } #if DEBUG Debugger.Break(); #endif Action cleanUp = null; var compression = 1; var mode = "hourly"; var databaseFile = this.DatabaseFileName; string backupPath = Path.Combine(this.DatabaseDirectory, "Backups"); if (backupOptions != null) { if (backupOptions.compression != null) { compression = (int)backupOptions.compression; } if (backupOptions.uncpath != null) { var existed = DriveInfo.GetDrives().ToDictionary(d => d.Name); var chosen = '\0'; for (char i = 'A'; i < 'Z'; i++) { if (existed.ContainsKey(i + @":\") == false) { chosen = i; break; } } if (chosen != '\0') { string command = string.Empty; if (backupOptions.username != null && backupOptions.password != null) { command = string.Format("use {0}: {1} /u:{2} {3}", chosen, backupOptions.uncpath, backupOptions.username, backupOptions.password); } else { command = string.Format("use {0}: {1}", chosen, backupOptions.uncpath); } var process = Process.Start("net.exe", command); process.WaitForExit(); if (process.ExitCode == 0) { cleanUp = () => { string cmd = string.Format("use {0}: /delete", chosen); var p2 = Process.Start("net.exe", cmd); p2.WaitForExit(); }; backupPath = chosen + ":\\"; } } } if (backupOptions.sitename != null) { backupPath = Path.Combine(backupPath, (string)backupOptions.sitename); } } try { if (mode == "hourly") { backupPath = Path.Combine(backupPath, "DatabaseBackup-Hourly"); Directory.CreateDirectory(backupPath); // create hourly backup var backupFile = Path.Combine(backupPath, string.Format("hourlybackup-{0:HH}.sqlite.bz2", DateTime.Now)); if (File.Exists(backupFile) == false) { NancyBlackDatabase.BZip(databaseFile, backupFile); } else { // check modified date if (File.GetLastWriteTime(backupFile).Date < DateTime.Now.Date) { // it was the yesterday's file, replace it NancyBlackDatabase.BZip(databaseFile, backupFile); } } } if (mode == "daily") { backupPath = Path.Combine(backupPath, "DatabaseBackup-Hourly"); Directory.CreateDirectory(backupPath); var dailybackupFile = Path.Combine(backupPath, string.Format("dailybackup-{0:dd-MM-yyyy}.sqlite.bz2", DateTime.Now)); if (File.Exists(dailybackupFile) == false) { NancyBlackDatabase.BZip(databaseFile, dailybackupFile, 9); // max compression for daily backup } var backupFiles = Directory.GetFiles(backupPath, "dailybackup-*.sqlite.bz2"); var now = DateTime.Now; var maxDay = 30; if (backupOptions.dailyretention != null) { maxDay = (int)backupOptions.dailyretention; } foreach (var file in backupFiles) { if (now.Subtract(File.GetCreationTime(file)).TotalDays > maxDay) { try { File.Delete(file); // delete backup older than 30 days } catch (Exception) { } } } } } catch (Exception) { // retry backup again _LastBackupCheck = DateTime.MinValue; } finally { if (cleanUp != null) { cleanUp(); } } }
/// <summary> /// Upserts the specified entity name. /// </summary> /// <param name="entityName">Name of the entity.</param> /// <param name="input">Data to be saved, can be anything including anonymous type. But Anonymous Type must include Id parameter</param> public JObject UpsertRecord(string entityName, object inputObject) { var type = _dataType.FromName(entityName); if (type is StaticDataType) { return(JObject.FromObject(this.UpsertStaticRecord(entityName, inputObject))); } JObject jObject = inputObject as JObject; if (jObject == null) { jObject = JObject.FromObject(inputObject); } List <JProperty> removed = new List <JProperty>(); // converts complex properties to Json foreach (var prop in jObject.Properties().ToList()) // to-list to allow us to add property { if (prop.Value.Type == JTokenType.Array || prop.Value.Type == JTokenType.Object) { // array or objects are converted to JSON when stored in table jObject["js_" + prop.Name] = prop.Value.ToString(Formatting.None); prop.Remove(); removed.Add(prop); } } type = _dataType.FromJObject(entityName, jObject); var actualType = type.GetCompiledType(); jObject["__updatedAt"] = DateTime.Now; int id = 0; if (jObject.Property("id") != null) // try to get Id { id = (int)jObject["id"]; jObject["Id"] = id; jObject.Remove("id"); } if (jObject.Property("Id") != null) { id = (int)jObject["Id"]; } if (id == 0) { jObject["__createdAt"] = DateTime.Now; // needs to convert to object to get Id later dynamic toInsert = jObject.ToObject(actualType); NancyBlackDatabase.ObjectCreating(this, entityName, toInsert); _db.Insert(toInsert, actualType); jObject["Id"] = toInsert.Id; NancyBlackDatabase.ObjectCreated(this, entityName, toInsert); } else { NancyBlackDatabase.ObjectUpdating(this, entityName, jObject); _db.Update(jObject.ToObject(actualType), actualType); NancyBlackDatabase.ObjectUpdated(this, entityName, jObject); } // remove "js_" properties foreach (var prop in jObject.Properties().ToList()) // to-list to allow us to add/remove property { if (prop.Name.StartsWith("js_")) { prop.Remove(); } } // add removed complex properties back foreach (var prop in removed) { jObject.Add(prop.Name, prop.Value); } return(jObject); }
/// <summary> /// Performs the regular backup /// </summary> public void PerformBackup() { if (DateTime.Now.Subtract(_LastBackupCheck).TotalMinutes > 30) { _LastBackupCheck = DateTime.Now; } else { // No Need to do the backup now return; } #if !DEBUG try { var path = this.DatabaseDirectory; var fileName = this.DatabaseFileName; var backupPath = Path.Combine(path, "Backups"); Directory.CreateDirectory(path); Directory.CreateDirectory(backupPath); // create hourly backup var backupFile = Path.Combine(backupPath, string.Format("hourlybackup-{0:HH}.sqlite.bz2", DateTime.Now)); if (File.Exists(backupFile) == false) { NancyBlackDatabase.BZip(fileName, backupFile); } else { // check modified date if (File.GetLastWriteTime(backupFile).Date < DateTime.Now.Date) { // it was the yesterday's file, replace it NancyBlackDatabase.BZip(fileName, backupFile); } } // create daily backup var dailybackupFile = Path.Combine(backupPath, string.Format("dailybackup-{0:dd-MM-yyyy}.sqlite.bz2", DateTime.Now)); if (File.Exists(dailybackupFile) == false) { NancyBlackDatabase.BZip(fileName, dailybackupFile, 9); // max compression for daily backup } var backupFiles = Directory.GetFiles(backupPath, "dailybackup-*.sqlite.bz2"); var now = DateTime.Now; foreach (var file in backupFiles) { if (now.Subtract(File.GetCreationTime(file)).TotalDays > 30) { try { File.Delete(file); // delete backup older than 30 days } catch (Exception) { } } } } catch (Exception) { // retry backup again _LastBackupCheck = DateTime.MinValue; } #endif }