2023-05-18 01:27:11 +02:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Threading.Tasks ;
using Dapper ;
using Microsoft.Data.Sqlite ;
using Serilog ;
using SharpRss.Models ;
namespace SharpRss.Services
{
2023-05-18 20:15:31 +02:00
internal class DatabaseService : IDisposable
2023-05-18 01:27:11 +02:00
{
internal DatabaseService ( )
{
_sqlConn = new SqliteConnection ( _connectionString ) ;
InitializeDb ( ) ;
}
private readonly SqliteConnection _sqlConn ;
2023-05-20 00:04:45 +02:00
private readonly string _connectionString = $"Data Source={Path.Combine(Environment.CurrentDirectory, " sharp_rss . sqlite ")};" ;
private readonly string _groupTable = "group_data" ;
private readonly string _feedTable = "feed_data" ;
private readonly string _feedItemTable = "feed_item_data" ;
2023-05-18 01:27:11 +02:00
2023-05-20 00:04:45 +02:00
public async Task RemoveGroupFromFeedsAsync ( string groupId )
{
await _sqlConn . QueryAsync ( "UPDATE feed_data SET group_id=NULL WHERE group_id=@GroupId" , new { GroupId = groupId } ) ;
}
public async Task < bool > AddCategoriesAsync ( HashSet < GroupModel > categories )
2023-05-18 01:27:11 +02:00
{
bool result = true ;
_sqlConn . Open ( ) ;
foreach ( var categoryModel in categories )
{
2023-05-18 20:15:31 +02:00
await _sqlConn . QueryAsync ( "INSERT INTO category_data (name, hex_color, path_icon, category_id) VALUES(@catName, @hexColor, @pathIcon, @categoryId) ON CONFLICT(name) DO UPDATE SET hex_color=@hexColor, path_icon=@pathIcon" ,
2023-05-20 00:04:45 +02:00
new { catName = categoryModel . Name , hexColor = categoryModel . HexColor , pathIcon = categoryModel . Icon , categoryId = categoryModel . Id } ) ;
2023-05-18 01:27:11 +02:00
}
_sqlConn . Close ( ) ;
return result ;
}
public async Task < bool > AddFeedsAsync ( HashSet < FeedModel > feeds )
{
bool result = true ;
_sqlConn . Open ( ) ;
foreach ( var feedModel in feeds )
{
2023-05-20 00:35:43 +02:00
await _sqlConn . QueryAsync ( "INSERT OR REPLACE INTO feed_data(url, feed_id, category_id) VALUES(@url, @feedId, @categoryId) ON CONFLICT(url) DO UPDATE SET category_id=@categoryId" , new { url = feedModel . FeedUrl , feedId = feedModel . FeedId , categoryId = feedModel . GroupId } ) ;
2023-05-18 01:27:11 +02:00
}
_sqlConn . Close ( ) ;
return result ;
}
2023-05-20 00:04:45 +02:00
public async Task < HashSet < GroupModel > > GetCategoriesAsync ( )
2023-05-18 01:27:11 +02:00
{
2023-05-20 00:04:45 +02:00
HashSet < GroupModel > categories = new HashSet < GroupModel > ( ) ;
2023-05-18 01:27:11 +02:00
_sqlConn . Open ( ) ;
SqliteCommand cmd = _sqlConn . CreateCommand ( ) ;
cmd . CommandText = "SELECT * FROM category_data" ;
await using SqliteDataReader reader = await cmd . ExecuteReaderAsync ( ) ;
while ( reader . Read ( ) )
2023-05-20 00:04:45 +02:00
{
//categories.Add(GroupModel.Create(reader["name"].ToString(), reader["hex_color"].ToString(), reader["category_id"].ToString()));
}
2023-05-18 01:27:11 +02:00
_sqlConn . Close ( ) ;
return categories ;
}
public async Task < HashSet < FeedModel > > GetFeedsAsync ( string? categoryId = null )
{
HashSet < FeedModel > feeds = new HashSet < FeedModel > ( ) ;
_sqlConn . Open ( ) ;
SqliteCommand cmd = _sqlConn . CreateCommand ( ) ;
cmd . CommandText = categoryId = = null ? "SELECT * FROM feed_data" : "SELECT * FROM feed_data WHERE category_id=@categoryId" ;
if ( categoryId ! = null )
cmd . Parameters . Add ( new SqliteParameter ( "categoryId" , categoryId ) ) ;
await using SqliteDataReader reader = await cmd . ExecuteReaderAsync ( ) ;
while ( reader . Read ( ) )
2023-05-20 00:04:45 +02:00
{
//feeds.Add(FeedModel.Create(reader["url"].ToString(), reader["feed_id"].ToString(), reader["category_id"].ToString()));
}
2023-05-18 01:27:11 +02:00
_sqlConn . Close ( ) ;
return feeds ;
}
private async void InitializeDb ( )
{
Log . Verbose ( "Checking database..." ) ;
2023-05-19 14:40:57 +02:00
HashSet < string > failed = new HashSet < string > ( ) ;
2023-05-18 01:27:11 +02:00
_sqlConn . Open ( ) ;
2023-05-20 00:04:45 +02:00
Log . Verbose ( "Checking table: {Table}" , _groupTable ) ;
var queryResponse = await _sqlConn . QueryAsync ( $"CREATE TABLE IF NOT EXISTS {_groupTable} (name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING, id STRING PRIMARY KEY, CONSTRAINT name UNIQUE (name))" ) ;
2023-05-19 14:40:57 +02:00
if ( queryResponse . Any ( ) ) failed . Add ( "category_data" ) ;
2023-05-20 00:04:45 +02:00
Log . Verbose ( "Checking table: {Table}" , _feedTable ) ;
queryResponse = await _sqlConn . QueryAsync ( $"CREATE TABLE IF NOT EXISTS {_feedTable} (url STRING NOT NULL, id STRING PRIMARY KEY, group_id STRING DEFAULT NULL, CONSTRAINT url, UNIQUE (url))" ) ;
2023-05-19 14:40:57 +02:00
if ( queryResponse . Any ( ) ) failed . Add ( "feed_data" ) ;
2023-05-20 00:04:45 +02:00
Log . Verbose ( "Checking table: {Table}" , _feedItemTable ) ;
queryResponse = await _sqlConn . QueryAsync ( $"CREATE TABLE IF NOT EXISTS {_feedItemTable} (id STRING PRIMARY KEY, feed_id STRING NOT NULL)" ) ;
if ( queryResponse . Any ( ) ) failed . Add ( "feed_item_data" ) ;
2023-05-19 14:40:57 +02:00
_sqlConn . Close ( ) ;
if ( failed . Any ( ) )
2023-05-18 01:27:11 +02:00
{
2023-05-19 14:40:57 +02:00
var joined = string . Join ( ',' , failed ) ;
Log . Error ( "Failed to initialize table(s): {TableNames}" , joined ) ;
2023-05-18 01:27:11 +02:00
}
2023-05-19 14:40:57 +02:00
else
Log . Verbose ( "Checking database done!" ) ;
2023-05-18 01:27:11 +02:00
}
public void Dispose ( )
{
_sqlConn . Dispose ( ) ;
}
}
}