public void FullCycle() { // First create the controller for the system context using (var controller = DbController.Create(Config)) { Console.Out.WriteLine("A new system controller was created at path {0}", controller.Config.BasePath()); // Then create the database 'testdb' using (var dbSystem = controller.CreateDatabase(testDbName, testDbAdmin, testDbPass)) { Console.Out.WriteLine("The database {0} was created at the path {1}", dbSystem.Config.DatabaseName(), dbSystem.Config.DatabaseFullPath()); Assert.IsTrue(dbSystem.Database.Exists, "The database was created but was not not physically found."); // now open am ADO.NET connection to write data to the database using (var connection = dbSystem.GetConnection(testDbAdmin, testDbPass)) { Assert.IsTrue(connection.State == ConnectionState.Open, "The connection is not open"); using (var transaction = connection.BeginTransaction()) { // Create the table 'people' var command = connection.CreateCommand(); command.CommandText = "CREATE TABLE people (first_name VARCHAR(255), last_name VARCHAR(255), age INT)"; command.ExecuteNonQuery(); Console.Out.WriteLine("The table 'people' was created in the database"); // insert an entry into the table command = connection.CreateCommand(); command.CommandText = "INSERT INTO people (first_name, last_name, age) VALUES ('Antonello', 'Provenzano', 33)"; command.ExecuteNonQuery(); Console.Out.WriteLine("An entry was inserted into the table 'people'."); // assert the entry exists within this context command = connection.CreateCommand(); command.CommandText = "SELECT COUNT(*) FROM people"; var count = (BigNumber)command.ExecuteScalar(); Assert.AreEqual(1, count.ToInt32(), "The number of entries in the table is not coherent."); transaction.Commit(); } } } } // The previous system context was disposed, any reference to the databases within the // context has been released. So create another system controller using (var controller = DbController.Create(Config)) { // Check the database physically exists in the system Assert.IsTrue(controller.DatabaseExists(testDbName), "The database {0} was not physically found at the path {1}", testDbName, Config.BasePath()); } // Open another system context that is isolated from the previous ones. using (var controller = DbController.Create(Config)) { // Open an existing database within the system context. If the database doesn't exist // this will throw an exception. using (var dbSystem = controller.StartDatabase(testDbName)) { // Open a connection to the database using (var connection = dbSystem.GetConnection(testDbAdmin, testDbPass)) { // Assert the connection state is open Assert.IsTrue(connection.State == ConnectionState.Open, "The connection is not open"); // Check the 'people' table and count the items. If the table doesn't physically // exist this will throw an exception var command = connection.CreateCommand(); command.CommandText = "SELECT COUNT(*) FROM people"; // Assert there is exactly one element in the table var count = (BigNumber)command.ExecuteScalar(); Assert.AreEqual(1, count.ToInt32(), "An incorrect number of items was found in the table."); // Now select the entry in the table command = connection.CreateCommand(); command.CommandText = "SELECT * FROM people"; // Assert the data structure is coherent with the one created in // the previous passage var reader = command.ExecuteReader(); Assert.AreEqual(3, reader.FieldCount, "An incorrect number of fields was found in the table."); Assert.AreEqual(0, reader.GetOrdinal("first_name"), "The first field in the table is not 'first_name'"); Assert.AreEqual(1, reader.GetOrdinal("last_name"), "The second field in the table is not 'last_name'"); Assert.AreEqual(2, reader.GetOrdinal("age"), "The third field in the table is not 'age'"); // Assert at least one entry can be read Assert.IsTrue(reader.Read(), "It was not possible to read from the result"); // Assert the entry read is exactly the one created in the previous stage Assert.AreEqual("Antonello", reader.GetString(0), "The value of 'first_name' is not 'Antonello'"); Assert.AreEqual("Provenzano", reader.GetString(1), "The value of 'last_name' is not 'Provenzano'"); Assert.AreEqual(33, reader.GetInt32(2), "The value of 'age' is not 33"); } } } }
/// <summary> /// Creates a new database with the given name and with initial /// configurations. /// </summary> /// <param name="config">The configurations specific for the dataabse /// to create. These will be merged with existing context configurations.</param> /// <param name="name">The name of the database to create.</param> /// <param name="adminUser">The name of the administrator for the database,</param> /// <param name="adminPass">The password used to identify the administrator.</param> /// <returns> /// Returns a <see cref="DbSystem"/> instance used to access the database created. /// </returns> /// <exception cref="ArgumentNullException"> /// If the <paramref name="name"/> of the database is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// If a database with the given <paramref name="name"/> already exists. /// </exception> /// <exception cref="InvalidOperationException"> /// If an error occurred while initializing the database. /// </exception> public DbSystem CreateDatabase(IDbConfig config, string name, string adminUser, string adminPass) { if (name == null) throw new ArgumentNullException("name"); if (config == null) config = DbConfig.Default; if (DatabaseExists(config, name)) throw new ArgumentException("A database '" + name + "' already exists."); config.Parent = Config; StorageType storageType = GetStorageType(config); if (storageType == StorageType.File) { // we ensure that the BasePath points to where we want it to point string path = Path.Combine(config.BasePath(), name); if (Directory.Exists(path)) throw new ApplicationException("Database path '" + name + "' already exists: try opening"); Directory.CreateDirectory(path); config.SetValue(ConfigKeys.DatabasePath, name); string configFile = Path.Combine(path, DefaultConfigFileName); //TODO: support multiple formats? config.Save(configFile); } IDatabase database = CreateDatabase(config, name); try { database.Create(adminUser, adminPass); database.Init(); var callback = new DatabaseShutdownCallback(this, database); database.Context.OnShutdown += (callback.Execute); } catch (Exception e) { database.Context.Logger.Error(this, "Database create failed"); database.Context.Logger.Error(this, e); throw new InvalidOperationException(e.Message, e); } // Return the DbSystem object for the newly created database. databases[name] = database; return new DbSystem(this, name, config, database); }
public bool DeleteDatabase(IDbConfig config, string name, string adminName, string adminPass) { if (String.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); if (config == null) config = DbConfig.Default; if (!DatabaseExists(config, name)) return false; config.Parent = Config; IDatabase database = GetDatabase(name); if (database == null) return false; // TODO: query the db to see if the user is the admin try { //TODO: close all connections to the database try { if (database.IsInitialized) database.Shutdown(); } finally { database.Dispose(); if (databases.ContainsKey(name)) databases.Remove(name); } } catch (Exception ex) { Logger.Error(ex); } StorageType storageType = GetStorageType(config); if (storageType == StorageType.File) { // we ensure that the BasePath points to where we want it to point string path = Path.Combine(config.BasePath(), name); if (!Directory.Exists(path)) return false; Directory.Delete(path, true); } return true; }
/// <summary> /// Creates a new instance of <see cref="DbController"/> to the /// given path on the underlying filesystem. /// </summary> /// <param name="config">The initial configurations that will /// be applied to the subsequent databases within the context.</param> /// <remarks> /// If the given path doesn't point to any valid database context /// this will generate it by creating a configuration file which /// will encapsulate all the default configurations and those /// provided in this method. /// </remarks> /// <returns> /// Returns an instance of <see cref="DbController"/> which points /// to the given path. /// </returns> public static DbController Create(IDbConfig config) { StorageType storageType = GetStorageType(config); if (config == null) config = DbConfig.Default; IDbConfig mainConfig; if (storageType == StorageType.File) { string path = config.BasePath() ?? Environment.CurrentDirectory; string configFile = Path.GetFileName(path); // we only allow the file extension .conf string ext = Path.GetExtension(configFile); if (String.Compare(ext, FileExtension, StringComparison.OrdinalIgnoreCase) == 0) { path = Path.GetDirectoryName(path); } else { configFile = DefaultConfigFileName; } // if the directory doesn't exist we will create one... if (path != null && !Directory.Exists(path)) Directory.CreateDirectory(path); mainConfig = GetConfig(config, path, configFile); mainConfig.BasePath(path); } else { mainConfig = config; } var controller = new DbController(mainConfig); if (storageType == StorageType.File) { // done with the main configuration... now look for the databases... string path = config.BasePath(); string[] subDirs = Directory.GetDirectories(path); foreach (string dir in subDirs) { IDbConfig dbConfig = GetConfig(mainConfig, dir, null); if (dbConfig == null) continue; var dbPath = dir.Substring(dir.LastIndexOf(Path.DirectorySeparatorChar) + 1); string name = dbConfig.DatabaseName(); if (name == null) name = dbPath; dbConfig.DatabasePath(dbPath); if (controller.IsDatabaseRegistered(name)) throw new InvalidOperationException("The database '" + name + "' was already registered."); IDatabase database = CreateDatabase(dbConfig, name); controller.databases[name] = database; if (database.Exists) { var callback = new DatabaseShutdownCallback(controller, database); database.Context.OnShutdown += (callback.Execute); } } } return controller; }