Skip to content

Commit

Permalink
add question entities and methods
Browse files Browse the repository at this point in the history
  • Loading branch information
mdemrulkayes committed Apr 2, 2024
1 parent 9f72601 commit f3f1bbb
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/API/Quizzer.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Reflection;
using Modules.Identity;
using Modules.Question.Infrastructure;
using Quizzer.Api.Exceptions;
using Quizzer.Api.Services;
using Serilog;
Expand Down Expand Up @@ -37,6 +38,9 @@

builder.Services.RegisterSharedInfrastructureModule();
builder.Services.RegisterIdentityModule(builder.Configuration, logger, mediatRAssemblies);

builder.Services.RegisterQuestionModuleInfrastructure(logger, builder.Configuration, mediatRAssemblies);

builder.Services.RegisterEndpoints(mediatRAssemblies);

#endregion
Expand Down
2 changes: 2 additions & 0 deletions src/API/Quizzer.Api/Quizzer.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@

<ItemGroup>
<ProjectReference Include="..\..\Modules\Identity\Modules.Identity\Modules.Identity.csproj" />
<ProjectReference Include="..\..\Modules\Question\Modules.Question.Application\Modules.Question.Application.csproj" />
<ProjectReference Include="..\..\Modules\Question\Modules.Question.Infrastructure\Modules.Question.Infrastructure.csproj" />
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion src/API/Quizzer.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
},
"ConnectionStrings": {
"IdentityModuleDbContext": "Server=localhost,1401;database=Quizzer;User Id=sa;Password=Pass@word;Encrypt=false"
"IdentityModuleDbContext": "Server=localhost,1401;database=Quizzer;User Id=sa;Password=Pass@word;Encrypt=false",
"QuestionModuleDbContext": "Server=localhost,1401;database=Quizzer;User Id=sa;Password=Pass@word;Encrypt=false"
},
"JwtConfiguration": {
"JwtIssuer": "https://quizzer.api",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
public sealed class QuestionModuleConstants
{
public const string SchemaName = "Question";
public static string MigrationHistoryTableName = "__QuestionModuleMigrationHistory";
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,31 @@ public sealed class Question : BaseAuditableEntity
public string AskedQuestion { get; private set; }
public string Discussion { get; private set; }

public int QuestionMark { get; private set; }
public int? QuestionMark { get; private set; }

public long QuestionSetId { get; private set; }
public QuestionSet QuestionSet { get; private set; }

public IReadOnlyCollection<QuestionOption> Options => new ReadOnlyCollection<QuestionOption>(QuestionOptions);
public IReadOnlyCollection<QuestionOption> Options => new ReadOnlyCollection<QuestionOption>(_questionOptions);

internal List<QuestionOption> QuestionOptions = [];
internal List<QuestionOption> _questionOptions = [];

private Question(string askedQuestion, string discussion = "", int? questionMark = null)

Check warning on line 20 in src/Modules/Question/Modules.Question.Core/QuestionAggregate/Question.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'QuestionSet' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{
AskedQuestion = askedQuestion;
Discussion = discussion;
QuestionMark = questionMark;
}

public static Result<Question> Create(string askedQuestion, string discussion = "", int? mark = null)
{
return new Question(askedQuestion, discussion, mark);
}

public void AddQuestionOptions(string optionText, bool isAnswer = false)
{
var questionOption = QuestionOption.AddQuestionOption(optionText, isAnswer).Value;
if (questionOption != null)
_questionOptions.Add(questionOption);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,15 @@ public sealed class QuestionOption : BaseAuditableEntity
public bool IsAnswer { get; private set; }

public Question Question { get; private set; }

private QuestionOption(string optionText, bool isAnswer = false)

Check warning on line 13 in src/Modules/Question/Modules.Question.Core/QuestionAggregate/QuestionOption.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Question' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{
OptionText = optionText;
IsAnswer = isAnswer;
}

public static Result<QuestionOption> AddQuestionOption(string text, bool isAnswer)
{
return new QuestionOption(text, isAnswer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,37 @@ public sealed class QuestionSet : BaseAuditableEntity, IAggregateRoot
public string? SetCode { get; private set; }
public string? Details { get; private set; }

public IReadOnlyCollection<QuestionSetTag> Tags => new ReadOnlyCollection<QuestionSetTag>(QuestionSetTags);
public IReadOnlyCollection<QuestionSetTag> QuestionSetTags => new ReadOnlyCollection<QuestionSetTag>(_questionSetTags);

internal List<QuestionSetTag> QuestionSetTags = [];
internal List<QuestionSetTag> _questionSetTags = [];

public IReadOnlyCollection<Question> Questions => new ReadOnlyCollection<Question>(_questions);

internal List<Question> _questions = [];

private QuestionSet(string name, string setCode = "", string details = "")
{
Name = name;
SetCode = setCode;
Details = details;
}

public static Result<QuestionSet> Create(string name, string setCode, string details)
{
return new QuestionSet(name, setCode, details);
}

public void AddQuestion(string askedQuestion, Dictionary<string, bool> options,string discussion = "", int? mark = null)
{
var addedQuestion = Question.Create(askedQuestion, discussion, mark);

if (addedQuestion.Value == null) return;

var question = addedQuestion.Value;
foreach (var option in options)
{
question.AddQuestionOptions(option.Key, option.Value);
}
_questions.Add(question);
}
}
5 changes: 4 additions & 1 deletion src/Modules/Question/Modules.Question.Core/Tag/Tag.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SharedKernel.Core;
using Modules.Question.Core.QuestionAggregate;
using SharedKernel.Core;

namespace Modules.Question.Core.Tag;
public sealed class Tag : BaseAuditableEntity
Expand All @@ -7,6 +8,8 @@ public sealed class Tag : BaseAuditableEntity
public string Name { get; private set; }
public string? Description { get; private set; }

public IEnumerable<QuestionSetTag> QuestionSetTags { get; private set; } = new List<QuestionSetTag>();

private Tag(string name, string? description)
{
Name = name;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Modules.Question.Infrastructure.Data.Configuration;
internal sealed class QuestionConfiguration : IEntityTypeConfiguration<Core.QuestionAggregate.Question>
{
public void Configure(EntityTypeBuilder<Core.QuestionAggregate.Question> builder)
{
builder.Property(x => x.QuestionId)
.ValueGeneratedOnAdd();

builder.Property(x => x.AskedQuestion)
.HasMaxLength(300)
.IsRequired();

builder.Property(x => x.Discussion)
.HasMaxLength(600);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Modules.Question.Core.QuestionAggregate;

namespace Modules.Question.Infrastructure.Data.Configuration;
internal sealed class QuestionOptionConfiguration : IEntityTypeConfiguration<QuestionOption>
{
public void Configure(EntityTypeBuilder<QuestionOption> builder)
{
builder.Property(x => x.QuestionId)
.ValueGeneratedOnAdd();

builder.Property(x => x.OptionText)
.HasMaxLength(200)
.IsRequired();

builder.HasQueryFilter(x => x.DeletedDate == null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,17 @@ public void Configure(EntityTypeBuilder<QuestionSet> builder)
.Property(x => x.Name)
.HasMaxLength(50)
.IsRequired();

builder.Property(x => x.Details)
.HasMaxLength(200);

builder.Property(x => x.SetCode)
.HasMaxLength(10);

builder.HasMany(x => x.Questions)
.WithOne(x => x.QuestionSet)
.HasForeignKey(x => x.QuestionSetId);

builder.HasQueryFilter(x => x.DeletedDate == null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Modules.Question.Core.QuestionAggregate;

namespace Modules.Question.Infrastructure.Data.Configuration;
internal sealed class QuestionSetTagConfiguration : IEntityTypeConfiguration<QuestionSetTag>
{
public void Configure(EntityTypeBuilder<QuestionSetTag> builder)
{
builder
.HasKey(x => new { x.QuestionSetId, x.TagId });

builder.HasOne(x => x.QuestionSet)
.WithMany(x => x.QuestionSetTags)
.HasForeignKey(x => x.QuestionSetId);

builder.HasOne(x => x.Tag)
.WithMany(x => x.QuestionSetTags)
.HasForeignKey(x => x.TagId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ internal sealed class QuestionModuleDbContext(DbContextOptions<QuestionModuleDbC
{
public DbSet<QuestionSet> QuestionSets { get; set; }
public DbSet<QuestionCore> Questions { get; set; }
public DbSet<QuestionOption> QuestionOptions { get; set; }
public DbSet<QuestionSetTag> QuestionSetTags { get; set; }

public DbSet<Tag> Tags { get; set; }

protected override void OnModelCreating(ModelBuilder builder)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Modules.Question.Application.Common;
using Modules.Question.Infrastructure.Data;
using Serilog;
using System.Reflection;

namespace Modules.Question.Infrastructure;
public static class ServiceCollectionExtensions
{
public static IServiceCollection RegisterQuestionModuleInfrastructure(this IServiceCollection services,
ILogger logger,
IConfiguration configuration,
List<Assembly> mediatRAssembly)
{
mediatRAssembly.Add(typeof(ServiceCollectionExtensions).Assembly);
services.AddDbContext<QuestionModuleDbContext>((sp, opt) =>
{
opt.UseSqlServer(configuration.GetConnectionString("QuestionModuleDbContext"), optBuilder =>
{
optBuilder.EnableRetryOnFailure(10);
optBuilder.MigrationsHistoryTable(QuestionModuleConstants.MigrationHistoryTableName,
QuestionModuleConstants.SchemaName);
optBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
});
});
logger.Information("Question module db context registered");
return services;
}

public static IApplicationBuilder MigrateQuestionModuleDatabase(this IApplicationBuilder app)
{
var scopedService = app.ApplicationServices.CreateScope();
var dbContext = scopedService.ServiceProvider.GetRequiredService<QuestionModuleDbContext>();

if (dbContext.Database.IsSqlServer())
{
dbContext.Database.Migrate();
}

return app;
}
}

0 comments on commit f3f1bbb

Please sign in to comment.