Working on db access

This commit is contained in:
Max Holleman 2023-06-02 10:56:30 +02:00
parent 1f0e8840c1
commit 4ef3b58a20
6 changed files with 117 additions and 76 deletions

View File

@ -4,6 +4,7 @@ using System.Data;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Transactions;
using Argotic.Syndication; using Argotic.Syndication;
using Dapper; using Dapper;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
@ -42,7 +43,7 @@ namespace SharpRss
using SqliteDataReader countReader = await cmdFeedCount.ExecuteReaderAsync(); using SqliteDataReader countReader = await cmdFeedCount.ExecuteReaderAsync();
int count = countReader.Read() ? countReader.GetInt32(0) : 0; int count = countReader.Read() ? countReader.GetInt32(0) : 0;
groups.Add(new CategoryModel() groups.Add(new CategoryModel()
{ {
Name = reader["name"].ToString(), Name = reader["name"].ToString(),
FeedCount = count, FeedCount = count,
@ -78,7 +79,7 @@ namespace SharpRss
bool result = false; bool result = false;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
// Remove the group and remove the feeds that were part of the group. // Remove the group and remove the feeds that were part of the group.
await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {GroupTable} WHERE id=@id; UPDATE {FeedTable} SET group_id=NULL WHERE group_id=@id", dbc) await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {GroupTable} WHERE id=@id; UPDATE {FeedTable} SET group_id=NULL WHERE group_id=@id", dbc)
{ {
Parameters = Parameters =
@ -125,45 +126,86 @@ namespace SharpRss
{ {
Parameters = { new SqliteParameter("Url", url) } Parameters = { new SqliteParameter("Url", url) }
}; };
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); try
if (reader.Read()) {
feed = await ReaderToFeedModel(reader); await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
if (reader.Read())
feed = await ReaderToFeedModel(reader);
}
catch (Exception ex)
{
Log.Error(ex, "Error while fetching feed from db.");
}
return feed; return feed;
} }
public static async Task<FeedModel?> SetFeedsAsync(IEnumerable<FeedModel> feedModels) public static async Task<FeedModel?> SetFeedAsync(FeedModel feedModel)
{ {
//TODO: Implement fetching system!!! FeedModel? feed = null;
FeedModel? resultModel = null;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
await using SqliteTransaction transaction = dbc.BeginTransaction(); await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedTable} (url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (@url, @title, @groupId, @feedType, @description, @language, @copyright, @dateAdded), @lastUpdated, @imageUrl, @originalDoc); SELECT * FROM {FeedTable} WHERE url=@url", dbc)
foreach (var feedModel in feedModels)
{ {
//await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {_feedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {_feedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc); SELECT * FROM {_feedTable} WHERE url=@url", dbc) Parameters =
await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {FeedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {FeedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc)", dbc)
{ {
Parameters = new SqliteParameter("url", feedModel.Url ?? string.Empty),
{ new SqliteParameter("title", feedModel.Title ?? string.Empty),
new SqliteParameter("id", feedModel.Id ?? string.Empty), new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty),
new SqliteParameter("url", feedModel.Url ?? string.Empty), new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty),
new SqliteParameter("title", feedModel.Title ?? string.Empty), new SqliteParameter("description", feedModel.Description ?? string.Empty),
new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty), new SqliteParameter("language", feedModel.Language ?? string.Empty),
new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty), new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty),
new SqliteParameter("description", feedModel.Description ?? string.Empty), new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds()),
new SqliteParameter("language", feedModel.Language ?? string.Empty), new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds()),
new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty), new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty),
new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds()), new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty)
new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds()), }
new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty), };
new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty) try
}, {
Transaction = transaction await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
}; feed = await ReaderToFeedModel(reader);
await cmd.ExecuteNonQueryAsync();
} }
await transaction.CommitAsync(); catch (Exception ex)
await FetchFeedItemsAsync(feedModels.Select(x => x.Url).ToArray()); {
return resultModel; Log.Error(ex, "Database error, adding feed model to database failed!");
return feed;
}
return feed;
/*await using SqliteTransaction transaction = dbc.BeginTransaction();
try
{
foreach (var feedModel in feedModels)
{
//await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {_feedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {_feedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc); SELECT * FROM {_feedTable} WHERE url=@url", dbc)
await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {FeedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {FeedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc)", dbc)
{
Parameters =
{
new SqliteParameter("id", feedModel.Id ?? string.Empty),
new SqliteParameter("url", feedModel.Url ?? string.Empty),
new SqliteParameter("title", feedModel.Title ?? string.Empty),
new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty),
new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty),
new SqliteParameter("description", feedModel.Description ?? string.Empty),
new SqliteParameter("language", feedModel.Language ?? string.Empty),
new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty),
new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds()),
new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds()),
new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty),
new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty)
},
Transaction = transaction
};
await cmd.ExecuteNonQueryAsync();
}
await transaction.CommitAsync();
}
catch (Exception ex)
{
await transaction.RollbackAsync();
Log.Error(ex, "Error on inserting feeds to db.");
return false;
}*/
} }
public static async Task FetchFeedItemsAsync(string[]? feedUrls = null) public static async Task FetchFeedItemsAsync(string[]? feedUrls = null)
@ -188,8 +230,8 @@ namespace SharpRss
{ {
GenericSyndicationFeed syndication = new GenericSyndicationFeed(); GenericSyndicationFeed syndication = new GenericSyndicationFeed();
syndication.Load(dbFeed.OriginalDocument); syndication.Load(dbFeed.OriginalDocument);
//TODO: Get items and add to db
} }
//TODO: Rewrite some stuff...
} }
public static async Task<bool> RemoveFeedAsync(FeedModel feedModel) public static async Task<bool> RemoveFeedAsync(FeedModel feedModel)
@ -197,11 +239,11 @@ namespace SharpRss
bool result = false; bool result = false;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {FeedTable} WHERE id=@id; UPDATE {FeedItemTable} SET feed_id=NULL WHERE feed_id=@id", dbc) await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {FeedTable} WHERE url=@Url; UPDATE {FeedItemTable} SET feed_id=NULL WHERE feed_id=@Url", dbc)
{ {
Parameters = Parameters =
{ {
new SqliteParameter("id", feedModel.Id) new SqliteParameter("Url", feedModel.Url)
} }
}; };
int affected = await cmd.ExecuteNonQueryAsync(); int affected = await cmd.ExecuteNonQueryAsync();
@ -280,10 +322,10 @@ namespace SharpRss
dbc.Open(); dbc.Open();
int affected = await cmd.ExecuteNonQueryAsync(); int affected = await cmd.ExecuteNonQueryAsync();
if (affected == 0) if (affected == 0)
Log.Verbose("Could not set feed item: {FeedLink}", item.Link); Log.Verbose("Could not set feed item: {FeedLink}", item.Link);
else else
result += affected; result += affected;
} }
transaction.Commit(); transaction.Commit();
return result; return result;
} }
@ -326,9 +368,9 @@ namespace SharpRss
} }
private static async Task<FeedModel> ReaderToFeedModel(SqliteDataReader reader) private static async Task<FeedModel> ReaderToFeedModel(SqliteDataReader reader)
{ {
FeedModel fetchedFeed = new FeedModel(reader["url"].ToString()) FeedModel fetchedFeed = new FeedModel()
{ {
Id = reader["id"].ToString(), Url = reader["url"].ToString(),
Title = reader["title"].ToString(), Title = reader["title"].ToString(),
GroupId = reader["group_id"].ToString(), GroupId = reader["group_id"].ToString(),
FeedType = reader["feed_type"].ToString(), FeedType = reader["feed_type"].ToString(),
@ -340,14 +382,15 @@ namespace SharpRss
ImageUrl = reader["image_url"].ToString(), ImageUrl = reader["image_url"].ToString(),
OriginalDocument = reader["original_document"].ToString() OriginalDocument = reader["original_document"].ToString()
}; };
var groupFetch = await GetGroupsAsync(fetchedFeed.GroupId); //TODO: Set group on insert
/*var groupFetch = await GetGroupsAsync(fetchedFeed.GroupId);
if (groupFetch.Any()) if (groupFetch.Any())
fetchedFeed.Group = groupFetch.First(); fetchedFeed.Group = groupFetch.First();
else else
Log.Warning("Could not get group from feed: {FeedId}", fetchedFeed.Id); Log.Warning("Could not get group from feed: {FeedId}", fetchedFeed.Id);*/
return fetchedFeed; return fetchedFeed;
} }
//=== //===
public static async void Initialize() public static async void Initialize()
{ {
@ -359,7 +402,7 @@ namespace SharpRss
Log.Verbose("Checking table: {Table}", "category"); Log.Verbose("Checking table: {Table}", "category");
var queryResponse = await dbc.QueryAsync("CREATE TABLE IF NOT EXISTS category (name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING, id STRING PRIMARY KEY)"); var queryResponse = await dbc.QueryAsync("CREATE TABLE IF NOT EXISTS category (name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING, id STRING PRIMARY KEY)");
if (queryResponse.Any()) failed.Add("category"); if (queryResponse.Any()) failed.Add("category");
Log.Verbose("Checking table: {Table}", "feed"); Log.Verbose("Checking table: {Table}", "feed");
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed (url STRING PRIMARY KEY, title STRING, group_id STRING, feed_type STRING, description STRING, language STRING, copyright STRING, date_added INT, last_updated INT, image_url STRING, original_document STRING)"); queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed (url STRING PRIMARY KEY, title STRING, group_id STRING, feed_type STRING, description STRING, language STRING, copyright STRING, date_added INT, last_updated INT, image_url STRING, original_document STRING)");
if (queryResponse.Any()) failed.Add("feed"); if (queryResponse.Any()) failed.Add("feed");
@ -367,7 +410,7 @@ namespace SharpRss
Log.Verbose("Checking table: {Table}", "feed_item"); Log.Verbose("Checking table: {Table}", "feed_item");
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed_item (id STRING PRIMARY KEY, feed_id STRING, read INT, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, author STRING, categories STRING, content STRING)"); queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed_item (id STRING PRIMARY KEY, feed_id STRING, read INT, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, author STRING, categories STRING, content STRING)");
if (queryResponse.Any()) failed.Add("feed_item"); if (queryResponse.Any()) failed.Add("feed_item");
if (failed.Any()) if (failed.Any())
{ {
var joined = string.Join(',', failed); var joined = string.Join(',', failed);

View File

@ -4,13 +4,11 @@ namespace SharpRss.Models
{ {
public class FeedModel public class FeedModel
{ {
public FeedModel(string rssUrl) public FeedModel()
{ {
Url = rssUrl;
} }
public CategoryModel? Group { get; set; } public CategoryModel? Group { get; set; }
public string? Id { get; set; } public string Url { get; set; }
public string? Url { get; set; }
public string? Title { get; set; } = string.Empty; public string? Title { get; set; } = string.Empty;
public string? GroupId { get; set; } = string.Empty; public string? GroupId { get; set; } = string.Empty;
public string? FeedType { get; set; } = string.Empty; public string? FeedType { get; set; } = string.Empty;

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Argotic.Common; using Argotic.Common;
@ -38,35 +39,33 @@ namespace SharpRss.Services
bool validate = SyndicationDiscoveryUtility.UriExists(new Uri(url)); bool validate = SyndicationDiscoveryUtility.UriExists(new Uri(url));
if (!validate) return false; if (!validate) return false;
// Check if feed exists in db // Check if feed exists in db
FeedModel? dbFeed = await DbAccess.GetFeedAsync(url); FeedModel? fModel = await DbAccess.GetFeedAsync(url);
if (dbFeed == null) // If not exists fetch feed & add.
if (fModel == null)
{ {
GenericSyndicationFeed genFeed = new GenericSyndicationFeed(); GenericSyndicationFeed genFeed = GenericSyndicationFeed.Create(new Uri(url));
switch (genFeed.Format) fModel = FromResource(genFeed.Resource);
{ fModel.GroupId = group?.Id;
case SyndicationContentFormat.Rss: // Add feed
RssFeed rssFeed = (RssFeed)genFeed.Resource; FeedModel? dbFeed = await DbAccess.SetFeedAsync(fModel);
break; // Update/fetch items
case SyndicationContentFormat.Atom: await DbAccess.FetchFeedItemsAsync(new string[] { fModel.Url });
AtomFeed atomFeed = (AtomFeed)genFeed.Resource;
break;
default:
Log.Information("Feed implementation missing!");
break;
}
} }
// Update feed if newer
// Update/fetch items
return false; return false;
} }
private static FeedModel FromResource(ISyndicationResource resource) private static FeedModel FromResource(ISyndicationResource resource)
{ {
FeedModel model = new FeedModel(""); FeedModel model = new FeedModel();
switch (resource) switch (resource.Format)
{ {
case RssFeed rssFeed: case SyndicationContentFormat.Rss:
//TODO: From feed to model RssFeed rssFeed = (RssFeed)resource;
break;
case SyndicationContentFormat.Atom:
AtomFeed atomFeed = (AtomFeed)resource;
break;
default:
Log.Information("Feed implementation missing!");
break; break;
} }
return model; return model;
@ -158,8 +157,9 @@ namespace SharpRss.Services
Log.Error(e, "Error fetching feeds!"); Log.Error(e, "Error fetching feeds!");
throw; throw;
}*/ }*/
var groups = await GetGroupsAsync(); /*var groups = await GetGroupsAsync();
CategoryModel testGroup = groups.Single(x => x.Name == "News"); CategoryModel testGroup = groups.Single(x => x.Name == "News");*/
await AddSubscriptionAsync("https://www.nu.nl/rss/Algemeen");
/*await AddFeedsAsync(new[] /*await AddFeedsAsync(new[]
{ {
"https://www.nu.nl/rss/Algemeen", "https://www.nu.nl/rss/Algemeen",

View File

@ -57,7 +57,7 @@
else if (Gid != null) else if (Gid != null)
{ {
var feeds = await _rssService.GetFeedsAsync(Gid); var feeds = await _rssService.GetFeedsAsync(Gid);
var feedIds = feeds.Select(x => x.Id); var feedIds = feeds.Select(x => x.Url);
var feedItems = await _rssService.GetFeedItemsFromFeedsAsync(feedIds.ToArray()); var feedItems = await _rssService.GetFeedItemsFromFeedsAsync(feedIds.ToArray());
items = feedItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet(); items = feedItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
} }

View File

@ -51,7 +51,7 @@
if (_selectedItem == null) return; if (_selectedItem == null) return;
if (_selectedItem.FeedModel != null) if (_selectedItem.FeedModel != null)
{ {
_navigation.NavigateTo($"/list?fid={_selectedItem.FeedModel.Id}"); _navigation.NavigateTo($"/list?fid={_selectedItem.FeedModel.Url}");
} }
else if (_selectedItem.GroupModel != null) else if (_selectedItem.GroupModel != null)
{ {

Binary file not shown.