-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
40dd4ba
commit 7eb898c
Showing
16 changed files
with
902 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using Dapper; | ||
using Dapper.Contrib.Extensions; | ||
using GitHubExtension.Helpers; | ||
|
||
namespace GitHubExtension.DataModel; | ||
|
||
[Table("Release")] | ||
public class Release | ||
{ | ||
[Key] | ||
public long Id { get; set; } = DataStore.NoForeignKey; | ||
|
||
public long InternalId { get; set; } = DataStore.NoForeignKey; | ||
|
||
// Repository table | ||
public long RepositoryId { get; set; } = DataStore.NoForeignKey; | ||
|
||
public string Name { get; set; } = string.Empty; | ||
|
||
public string TagName { get; set; } = string.Empty; | ||
|
||
public long Prerelease { get; set; } = DataStore.NoForeignKey; | ||
|
||
public string HtmlUrl { get; set; } = string.Empty; | ||
|
||
public long TimeCreated { get; set; } = DataStore.NoForeignKey; | ||
|
||
public long TimePublished { get; set; } = DataStore.NoForeignKey; | ||
|
||
public long TimeLastObserved { get; set; } = DataStore.NoForeignKey; | ||
|
||
[Write(false)] | ||
private DataStore? DataStore | ||
{ | ||
get; set; | ||
} | ||
|
||
[Write(false)] | ||
[Computed] | ||
public DateTime CreatedAt => TimeCreated.ToDateTime(); | ||
|
||
[Write(false)] | ||
[Computed] | ||
public DateTime? PublishedAt => TimePublished != 0 ? TimePublished.ToDateTime() : null; | ||
|
||
[Write(false)] | ||
[Computed] | ||
public DateTime LastObservedAt => TimeLastObserved.ToDateTime(); | ||
|
||
public override string ToString() => Name; | ||
|
||
public static Release GetOrCreateByOctokitRelease(DataStore dataStore, Octokit.Release okitRelease, Repository repository) | ||
{ | ||
var release = CreateFromOctokitRelease(dataStore, okitRelease, repository); | ||
return AddOrUpdateRelease(dataStore, release); | ||
} | ||
|
||
public static IEnumerable<Release> GetAllForRepository(DataStore dataStore, Repository repository) | ||
{ | ||
var sql = $"SELECT * FROM Release WHERE RepositoryId = @RepositoryId ORDER BY TimePublished DESC;"; | ||
var param = new | ||
{ | ||
RepositoryId = repository.Id, | ||
}; | ||
|
||
Log.Logger()?.ReportDebug(DataStore.GetSqlLogMessage(sql, param)); | ||
var releases = dataStore.Connection!.Query<Release>(sql, param, null) ?? Enumerable.Empty<Release>(); | ||
foreach (var release in releases) | ||
{ | ||
release.DataStore = dataStore; | ||
} | ||
|
||
return releases; | ||
} | ||
|
||
public static Release? GetByInternalId(DataStore dataStore, long internalId) | ||
{ | ||
var sql = $"SELECT * FROM Release WHERE InternalId = @InternalId;"; | ||
var param = new | ||
{ | ||
InternalId = internalId, | ||
}; | ||
|
||
var release = dataStore.Connection!.QueryFirstOrDefault<Release>(sql, param, null); | ||
if (release is not null) | ||
{ | ||
// Add Datastore so this object can make internal queries. | ||
release.DataStore = dataStore; | ||
} | ||
|
||
return release; | ||
} | ||
|
||
public static void DeleteLastObservedBefore(DataStore dataStore, long repositoryId, DateTime date) | ||
{ | ||
// Delete releases older than the time specified for the given repository. | ||
// This is intended to be run after updating a repository's releases so that non-observed | ||
// records will be removed. | ||
var sql = @"DELETE FROM Release WHERE RepositoryId = $RepositoryId AND TimeLastObserved < $Time;"; | ||
var command = dataStore.Connection!.CreateCommand(); | ||
command.CommandText = sql; | ||
command.Parameters.AddWithValue("$Time", date.ToDataStoreInteger()); | ||
command.Parameters.AddWithValue("$RepositoryId", repositoryId); | ||
Log.Logger()?.ReportDebug(DataStore.GetCommandLogMessage(sql, command)); | ||
var rowsDeleted = command.ExecuteNonQuery(); | ||
Log.Logger()?.ReportDebug(DataStore.GetDeletedLogMessage(rowsDeleted)); | ||
} | ||
|
||
private static Release CreateFromOctokitRelease(DataStore dataStore, Octokit.Release okitRelease, Repository repository) | ||
{ | ||
var release = new Release | ||
{ | ||
DataStore = dataStore, | ||
InternalId = okitRelease.Id, | ||
RepositoryId = repository.Id, | ||
Name = okitRelease.Name, | ||
TagName = okitRelease.TagName, | ||
Prerelease = okitRelease.Prerelease ? 1 : 0, | ||
HtmlUrl = okitRelease.HtmlUrl, | ||
TimeCreated = okitRelease.CreatedAt.DateTime.ToDataStoreInteger(), | ||
TimePublished = okitRelease.PublishedAt.HasValue ? okitRelease.PublishedAt.Value.DateTime.ToDataStoreInteger() : 0, | ||
TimeLastObserved = DateTime.UtcNow.ToDataStoreInteger(), | ||
}; | ||
|
||
return release; | ||
} | ||
|
||
private static Release AddOrUpdateRelease(DataStore dataStore, Release release) | ||
{ | ||
// Check for existing release data. | ||
var existing = GetByInternalId(dataStore, release.InternalId); | ||
if (existing is not null) | ||
{ | ||
// Existing releases must be updated and always marked observed. | ||
release.Id = existing.Id; | ||
dataStore.Connection!.Update(release); | ||
release.DataStore = dataStore; | ||
return release; | ||
} | ||
|
||
// No existing release, add it. | ||
release.Id = dataStore.Connection!.Insert(release); | ||
release.DataStore = dataStore; | ||
return release; | ||
} | ||
|
||
public static void DeleteBefore(DataStore dataStore, DateTime date) | ||
{ | ||
// Delete releases older than the date listed. | ||
var sql = @"DELETE FROM Release WHERE TimeLastObserved < $Time;"; | ||
var command = dataStore.Connection!.CreateCommand(); | ||
command.CommandText = sql; | ||
command.Parameters.AddWithValue("$Time", date.ToDataStoreInteger()); | ||
Log.Logger()?.ReportDebug(DataStore.GetCommandLogMessage(sql, command)); | ||
var rowsDeleted = command.ExecuteNonQuery(); | ||
Log.Logger()?.ReportDebug(DataStore.GetDeletedLogMessage(rowsDeleted)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.