Skip to content

Commit

Permalink
* fix all violations of Roslyn analyzer rules @ crawler
Browse files Browse the repository at this point in the history
* disable Roslyn analyzer rule `SA1015:Closing generic brackets should be spaced correctly`: DotNetAnalyzers/StyleCopAnalyzers#3856 @ GlobalSuppressions.cs
@ c#
  • Loading branch information
n0099 committed May 31, 2024
1 parent e3db14a commit 44a35a8
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 43 deletions.
1 change: 1 addition & 0 deletions c#/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,4 @@
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:Closing parenthesis should be spaced correctly")]
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1012:Opening braces should be spaced correctly")]
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1013:Closing braces should be spaced correctly")]
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1015:Closing generic brackets should be spaced correctly", Justification = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3856")]
6 changes: 2 additions & 4 deletions c#/crawler/src/Db/Revision/Splitting/RevisionWithSplitting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ public ModelBuilder HasBaseTable<TRevision>() where TRevision : TBaseRevision
{
var visitor = new ReplaceParameterTypeVisitor<TBaseRevision, TRevision>();
_ = builder.Entity<TRevision>().ToTable(baseTableName)
.HasKey((Expression<Func<TRevision, object?>>)
visitor.Visit(keySelector));
.HasKey((Expression<Func<TRevision, object?>>)visitor.Visit(keySelector));
return this;
}

Expand All @@ -44,8 +43,7 @@ public ModelBuilder SplitToTable<TRevisionWithSplitting>(string tableNameSuffix)
_ = builder.Entity<TRevisionWithSplitting>()
.Ignore(e => e.NullFieldsBitMask)
.ToTable($"{baseTableName}_{tableNameSuffix}")
.HasKey((Expression<Func<TRevisionWithSplitting, object?>>)
visitor.Visit(keySelector));
.HasKey((Expression<Func<TRevisionWithSplitting, object?>>)visitor.Visit(keySelector));
return this;
}
}
Expand Down
2 changes: 2 additions & 0 deletions c#/crawler/src/ReplaceParameterTypeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
namespace tbm.Crawler;

/// <see>https://stackoverflow.com/questions/38316519/replace-parameter-type-in-lambda-expression/38345590#38345590</see>
#pragma warning disable SA1618 // Generic type parameters should be documented
public class ReplaceParameterTypeVisitor<TSource, TTarget> : ExpressionVisitor
#pragma warning restore SA1618 // Generic type parameters should be documented
{
private ReadOnlyCollection<ParameterExpression>? _parameters;

Expand Down
14 changes: 7 additions & 7 deletions c#/crawler/src/Tieba/Crawl/Saver/Post/ReplySaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ public class ReplySaver(
: PostSaver<ReplyPost, BaseReplyRevision, Pid>(
logger, posts, authorRevisionSaverFactory, PostType.Reply)
{
private Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>? _addSplitRevisionsDelegatesKeyByEntityType;

public delegate ReplySaver New(ConcurrentDictionary<PostId, ReplyPost> posts);

private Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>? _addSplitRevisionsDelegatesKeyByEntityType;
protected override Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>
AddSplitRevisionsDelegatesKeyByEntityType =>
_addSplitRevisionsDelegatesKeyByEntityType ??= new(() => new()
Expand All @@ -21,17 +22,11 @@ protected override Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>
{typeof(ReplyRevision.SplitAgreeCount), AddSplitRevisions<ReplyRevision.SplitAgreeCount>}
});

protected override Pid RevisionEntityIdSelector(BaseReplyRevision entity) => entity.Pid;
protected override Expression<Func<BaseReplyRevision, bool>>
IsRevisionEntityIdEqualsExpression(BaseReplyRevision newRevision) =>
existingRevision => existingRevision.Pid == newRevision.Pid;

public override bool UserFieldUpdateIgnorance(string propName, object? oldValue, object? newValue) => propName switch
{ // FansNickname in reply response will always be null
nameof(User.FansNickname) when newValue is null && oldValue is not null => true,
_ => false
};

public override bool UserFieldRevisionIgnorance(string propName, object? oldValue, object? newValue) => propName switch
{ // user icon will be null after UserParser.ResetUsersIcon() get invoked
nameof(User.Icon) when newValue is not null && oldValue is null => true,
Expand All @@ -51,6 +46,11 @@ public override SaverChangeSet<ReplyPost> Save(CrawlerDbContext db)
return changeSet;
}

protected override Pid RevisionEntityIdSelector(BaseReplyRevision entity) => entity.Pid;
protected override Expression<Func<BaseReplyRevision, bool>>
IsRevisionEntityIdEqualsExpression(BaseReplyRevision newRevision) =>
existingRevision => existingRevision.Pid == newRevision.Pid;

protected override bool FieldUpdateIgnorance
(string propName, object? oldValue, object? newValue) => propName switch
{ // possible randomly respond with null
Expand Down
13 changes: 7 additions & 6 deletions c#/crawler/src/Tieba/Crawl/Saver/Post/SubReplySaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ public class SubReplySaver(
: PostSaver<SubReplyPost, BaseSubReplyRevision, Spid>(
logger, posts, authorRevisionSaverFactory, PostType.SubReply)
{
private Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>? _addSplitRevisionsDelegatesKeyByEntityType;

public delegate SubReplySaver New(ConcurrentDictionary<PostId, SubReplyPost> posts);

private Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>? _addSplitRevisionsDelegatesKeyByEntityType;
protected override Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>
AddSplitRevisionsDelegatesKeyByEntityType =>
_addSplitRevisionsDelegatesKeyByEntityType ??= new(() => new()
Expand All @@ -18,11 +19,6 @@ protected override Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>
{typeof(SubReplyRevision.SplitDisagreeCount), AddSplitRevisions<SubReplyRevision.SplitDisagreeCount>},
});

protected override Spid RevisionEntityIdSelector(BaseSubReplyRevision entity) => entity.Spid;
protected override Expression<Func<BaseSubReplyRevision, bool>>
IsRevisionEntityIdEqualsExpression(BaseSubReplyRevision newRevision) =>
existingRevision => existingRevision.Spid == newRevision.Spid;

public override bool UserFieldUpdateIgnorance
(string propName, object? oldValue, object? newValue) => propName switch
{ // always ignore updates on iconinfo due to some rare user will show some extra icons
Expand All @@ -47,5 +43,10 @@ public override SaverChangeSet<SubReplyPost> Save(CrawlerDbContext db)
return changeSet;
}

protected override Spid RevisionEntityIdSelector(BaseSubReplyRevision entity) => entity.Spid;
protected override Expression<Func<BaseSubReplyRevision, bool>>
IsRevisionEntityIdEqualsExpression(BaseSubReplyRevision newRevision) =>
existingRevision => existingRevision.Spid == newRevision.Spid;

protected override NullFieldsBitMask GetRevisionNullFieldBitMask(string fieldName) => 0;
}
13 changes: 7 additions & 6 deletions c#/crawler/src/Tieba/Crawl/Saver/Post/ThreadSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,17 @@ public class ThreadSaver(
: PostSaver<ThreadPost, BaseThreadRevision, Tid>(
logger, posts, authorRevisionSaverFactory, PostType.Thread)
{
private Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>? _addSplitRevisionsDelegatesKeyByEntityType;

public delegate ThreadSaver New(ConcurrentDictionary<Tid, ThreadPost> posts);

private Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>? _addSplitRevisionsDelegatesKeyByEntityType;
protected override Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>
AddSplitRevisionsDelegatesKeyByEntityType =>
_addSplitRevisionsDelegatesKeyByEntityType ??= new(() => new()
{
{typeof(ThreadRevision.SplitViewCount), AddSplitRevisions<ThreadRevision.SplitViewCount>}
});

protected override Tid RevisionEntityIdSelector(BaseThreadRevision entity) => entity.Tid;
protected override Expression<Func<BaseThreadRevision, bool>>
IsRevisionEntityIdEqualsExpression(BaseThreadRevision newRevision) =>
existingRevision => existingRevision.Tid == newRevision.Tid;

public override bool UserFieldUpdateIgnorance
(string propName, object? oldValue, object? newValue) => propName switch
{ // Icon.SpriteInfo will be an empty array and the icon url is a smaller one
Expand All @@ -39,6 +35,11 @@ public override SaverChangeSet<ThreadPost> Save(CrawlerDbContext db) =>
th => new ThreadRevision {TakenAt = th.UpdatedAt ?? th.CreatedAt, Tid = th.Tid},
PredicateBuilder.New<ThreadPost>(th => Posts.Keys.Contains(th.Tid)));

protected override Tid RevisionEntityIdSelector(BaseThreadRevision entity) => entity.Tid;
protected override Expression<Func<BaseThreadRevision, bool>>
IsRevisionEntityIdEqualsExpression(BaseThreadRevision newRevision) =>
existingRevision => existingRevision.Tid == newRevision.Tid;

protected override bool FieldUpdateIgnorance
(string propName, object? oldValue, object? newValue) => propName switch
{ // will be updated by ThreadLateCrawler and ThreadLateCrawlFacade
Expand Down
40 changes: 20 additions & 20 deletions c#/crawler/src/Tieba/Crawl/Saver/SaverWithRevision.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,22 @@ public abstract partial class SaverWithRevision<TBaseRevision, TEntityId>(
protected abstract Lazy<Dictionary<Type, AddSplitRevisionsDelegate>>
AddSplitRevisionsDelegatesKeyByEntityType { get; }

protected abstract NullFieldsBitMask GetRevisionNullFieldBitMask(string fieldName);

protected abstract TEntityId RevisionEntityIdSelector(TBaseRevision entity);
protected abstract Expression<Func<TBaseRevision, bool>>
IsRevisionEntityIdEqualsExpression(TBaseRevision newRevision);

protected virtual bool ShouldIgnoreEntityRevision(string propName, PropertyEntry propEntry, EntityEntry entityEntry) => false;
protected virtual bool FieldUpdateIgnorance(string propName, object? oldValue, object? newValue) => false;
protected virtual bool FieldRevisionIgnorance(string propName, object? oldValue, object? newValue) => false;
private static bool GlobalFieldUpdateIgnorance(string propName, object? oldValue, object? newValue) => propName switch
{ // possible rarely respond with the protoBuf default value 0
nameof(BasePost.AuthorUid) when newValue is 0L && oldValue is not null => true,
_ => false
};

protected void AddSplitRevisions<TRevision>(CrawlerDbContext db, IEnumerable<TBaseRevision> revisions)
where TRevision : TBaseRevision
{
var newRevisions = revisions.OfType<TRevision>().ToList();
var dbSet = db.Set<TRevision>();
var visitor = new ReplaceParameterTypeVisitor<TBaseRevision, TRevision>();

// https://github.com/npgsql/npgsql/issues/4437
// https://github.com/dotnet/efcore/issues/32092
var existingRevisions = dbSet
.Where(newRevisions.Aggregate(

// https://github.com/npgsql/npgsql/issues/4437
// https://github.com/dotnet/efcore/issues/32092
LinqKit.PredicateBuilder.New<TRevision>(),
(predicate, newRevision) => predicate.Or(LinqKit.PredicateBuilder
.New<TRevision>(existingRevision => existingRevision.TakenAt == newRevision.TakenAt)
.And((Expression<Func<TRevision, bool>>)
visitor.Visit(IsRevisionEntityIdEqualsExpression(newRevision))))))
.And((Expression<Func<TRevision, bool>>)visitor
.Visit(IsRevisionEntityIdEqualsExpression(newRevision))))))
.ToList();
(from existingRevision in existingRevisions
join newRevision in newRevisions
Expand All @@ -51,6 +36,21 @@ on RevisionEntityIdSelector(existingRevision) equals RevisionEntityIdSelector(ne
t.newRevision.DuplicateIndex = (ushort)(t.existingRevision.DuplicateIndex + 1));
dbSet.AddRange(newRevisions);
}

protected abstract NullFieldsBitMask GetRevisionNullFieldBitMask(string fieldName);

protected abstract TEntityId RevisionEntityIdSelector(TBaseRevision entity);
protected abstract Expression<Func<TBaseRevision, bool>>
IsRevisionEntityIdEqualsExpression(TBaseRevision newRevision);

protected virtual bool ShouldIgnoreEntityRevision(string propName, PropertyEntry propEntry, EntityEntry entityEntry) => false;
protected virtual bool FieldUpdateIgnorance(string propName, object? oldValue, object? newValue) => false;
protected virtual bool FieldRevisionIgnorance(string propName, object? oldValue, object? newValue) => false;
private static bool GlobalFieldUpdateIgnorance(string propName, object? oldValue, object? newValue) => propName switch
{ // possible rarely respond with the protoBuf default value 0
nameof(BasePost.AuthorUid) when newValue is 0L && oldValue is not null => true,
_ => false
};
}
public abstract partial class SaverWithRevision<TBaseRevision, TEntityId>
{
Expand Down

0 comments on commit 44a35a8

Please sign in to comment.