From afa67b3d3b6097e32d9a82fb92ce6c10534576cf Mon Sep 17 00:00:00 2001 From: Max Nullov Date: Sun, 9 Feb 2025 16:38:49 +0300 Subject: [PATCH] Feature | web api created --- DatabaseRepository.cs | 121 ++++++++++++++++++++++++++++++++++++++++++ README.md | 13 +++-- RestySqlite.csproj | 1 + Utils.cs | 21 ++++++++ WebApi.cs | 58 ++++++++++++++++---- conf.toml | 8 +++ test.db | Bin 8192 -> 8192 bytes 7 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 DatabaseRepository.cs create mode 100644 Utils.cs create mode 100644 conf.toml diff --git a/DatabaseRepository.cs b/DatabaseRepository.cs new file mode 100644 index 0000000..32319f5 --- /dev/null +++ b/DatabaseRepository.cs @@ -0,0 +1,121 @@ +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Mvc; + +namespace RestySqlite +{ + public class DatabaseRepository + { + private DatabaseWrapper _db; + + public DatabaseRepository(DatabaseWrapper db) + { + _db = db; + } + + public async Task>?> ListTables() + { + return await Task.Run(() => { + try + { + return _db.MapColumns(); + } + catch (Exception e) + { + Console.WriteLine(e); + return null; + } + + }); + + } + + public async Task>?> ListColumns(string table) + { + return await Task.Run(() => { + try + { + var scheme = _db.MapColumns(); + var filtered = from tbl in scheme.Keys where tbl == table select scheme[tbl]; + + Dictionary> result = new(); + foreach (var column in filtered.Single()) + { + result.Add(column, _db.MapColumn(column, table)); + } + + return result; + } + catch (Exception e) + { + Console.WriteLine(e); + return null; + } + }); + + + } + + public async Task?> ListColumnValues(string table, string column) + { + return await Task.Run(() => { + var values = _db.MapColumn(column, table); + return values; + }); + + } + + public async Task?> FetchValue(string table, int id) + { + return await Task.Run(() => { + try + { + var reader = _db.GetReader($"SELECT * FROM {table} WHERE id = {id}"); + /* var sqlCommand = "SELECT * FROM $table WHERE id = $id"; + var reader = _db.GetReader(sqlCommand, + new Parameter("$table", table), + new Parameter("$id", id) + ); */ + Dictionary result = new(); + using (reader) + { + while (reader.Read()) + { + foreach (var column in _db.MapColumns()[table]) + { + if (!result.ContainsKey(column)) + { + result.Add(column, reader[column].ToString()); + continue; + } + result[column] = reader[column].ToString(); + + } + } + } + return result; + } + catch (Exception e) + { + Console.WriteLine(e); + return null; + } + }); + } + + public async Task ProcessCommand(string sqlCommand) + { + return await Task.Run(() => { + try + { + _db.ExecuteCommand(sqlCommand); + return "succses"; + } + catch (Exception e) + { + return e.Message; + } + + }); + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 1fac037..96cc054 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ WIP online sqlite database managment system -- WebAPI is not implemented yet. +- WebAPI implemented. - Database abstraction is almost done ## How it will work? @@ -12,13 +12,16 @@ easy database manipulation. ### Example endpoints -`GET:localhost/table_name/column_name/` - will provide json of objects inside column +`GET:localhost/api"` - will provide json of tables inside database -`GET:localhost/table_name/column_name/id` - will provide json object specific to this id +`GET:localhost/table_name/` - will provide json of columns inside table -`POST:localhost/` - will allow execute global query to database. For example creating new table. +`GET:localhost/api/table_name/column_name/` - will provide json of objects inside column + +`GET:localhost/api/table_name/id` - will provide json object specific to this id + +`POST:localhost/api/sqlcommand` - will allow execute global query to database. For example creating new table. -`POST:localhost/table_name` - will allow execute query on specific table. For example add new field. ### Manifest of goals diff --git a/RestySqlite.csproj b/RestySqlite.csproj index 985dc23..b120f1f 100644 --- a/RestySqlite.csproj +++ b/RestySqlite.csproj @@ -9,6 +9,7 @@ + diff --git a/Utils.cs b/Utils.cs new file mode 100644 index 0000000..30985f5 --- /dev/null +++ b/Utils.cs @@ -0,0 +1,21 @@ +using Tommy; + +namespace RestySqlite +{ + public class Utils + { + public static dynamic ReadConfig(string key, string? category = null) + { + using(StreamReader reader = File.OpenText("conf.toml")) + { + TomlTable table = TOML.Parse(reader); + + if (category != null) + { + return table[category][key]; + } + return table[key]; + } + } + } +} \ No newline at end of file diff --git a/WebApi.cs b/WebApi.cs index f16491d..f439d07 100644 --- a/WebApi.cs +++ b/WebApi.cs @@ -1,24 +1,62 @@ +using Microsoft.AspNetCore.Mvc; + namespace RestySqlite { public class WebApi { + struct Command + { + public string Sql; + } public static void Main() { - DatabaseWrapper db = new("test"); + string dbName = Utils.ReadConfig("database", "sql"); + if (dbName.Length == 0) + { + Console.WriteLine("You should specify database name in conf.toml!"); + return; + } - //string createTableSql = "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"; - /* string insertSql = "INSERT INTO users (name, email) VALUES (@name, @email)"; + string handle = Utils.ReadConfig("handle", "api"); + int port = Utils.ReadConfig("port", "api"); + + var builder = WebApplication.CreateBuilder(); + + builder.WebHost.ConfigureKestrel(serverOptions => + { + serverOptions.Listen(System.Net.IPAddress.Any, port); // Listen on all network interfaces on port 5000 + }); + + var app = builder.Build(); + + var repo = new DatabaseRepository(new DatabaseWrapper(dbName)); + var group = app.MapGroup(handle); - db.ExecuteCommand(insertSql, new Parameter("@name", "Max Nullov"), - new Parameter("@email", "[not specified]")); - */ + group.MapGet($"{handle}/", async() => { return await repo.ListTables(); }); + + group.MapGet("/{tableName}", async(string tableName) => + { return await repo.ListColumns(tableName); }); + + group.MapGet("/{tableName}/{columnName}", async(string tableName, string columnName) => + { return await repo.ListColumnValues(tableName, columnName); } ); - db.MapColumns(); + group.MapGet("/{tableName}/{id:int}", async(string tableName, int id) => + { return await repo.FetchValue(tableName, id); }); + + group.MapPost("/sqlcommand", async(HttpContext context) => + { + using var reader = new StreamReader(context.Request.Body); + string command = await reader.ReadToEndAsync(); + + return await repo.ProcessCommand(command); + + }); + + app.Run(); + } + - var usersnames = db.MapColumn("name", "users"); - usersnames.ForEach(name => Console.WriteLine(name)); - } } } \ No newline at end of file diff --git a/conf.toml b/conf.toml new file mode 100644 index 0000000..fe52cca --- /dev/null +++ b/conf.toml @@ -0,0 +1,8 @@ +title = "Configuration file for API" + +[api] + port=5417 + handle="api" + +[sql] + database="test" \ No newline at end of file diff --git a/test.db b/test.db index e2d340052f0b1e6fa1e9ea7a42ca0432aaf37b45..14ac18bdd3e86b1c9328b53dd95a7cbe423375a7 100644 GIT binary patch delta 59 zcmZp0XmFSy&B#7c#+i|QW5Nc0CjN}gf&yXuveK+942tR@sl_Fg3Lvrsh#f$LUUGi! I