Add book queries
This commit is contained in:
parent
146f8f6ff4
commit
db9f7348fa
12 changed files with 176 additions and 83 deletions
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
version: '3.8'
|
||||
services:
|
||||
db:
|
||||
image: mysql:8.0
|
||||
cap_add:
|
||||
- SYS_NICE
|
||||
restart: always
|
||||
environment:
|
||||
- MYSQL_DATABASE=library
|
||||
- MYSQL_ROOT_PASSWORD=libraryDbPassword
|
||||
ports:
|
||||
- '3306:3306'
|
||||
volumes:
|
||||
- db:/var/lib/mysql
|
||||
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
volumes:
|
||||
db:
|
||||
driver: local
|
30
src/GitHubActionsDemo.Api/Controllers/AuthorsController.cs
Normal file
30
src/GitHubActionsDemo.Api/Controllers/AuthorsController.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using GitHubActionsDemo.Api.Models;
|
||||
using GitHubActionsDemo.Api.Mappers;
|
||||
using GitHubActionsDemo.Service;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GitHubActionsDemo.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class AuthorsController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<AuthorsController> _logger;
|
||||
private readonly ILibraryService _libraryService;
|
||||
|
||||
public AuthorsController(
|
||||
ILogger<AuthorsController> logger,
|
||||
ILibraryService libraryService
|
||||
)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_libraryService = libraryService ?? throw new ArgumentNullException(nameof(libraryService));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<AuthorResponse> AddAuthorAsync(AuthorRequest authorRequest)
|
||||
{
|
||||
var author = await _libraryService.AddAuthorAsync(authorRequest.Map());
|
||||
return author.Map();
|
||||
}
|
||||
}
|
|
@ -7,13 +7,13 @@ namespace GitHubActionsDemo.Api.Controllers;
|
|||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class LibraryController : ControllerBase
|
||||
public class BooksController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<LibraryController> _logger;
|
||||
private readonly ILogger<BooksController> _logger;
|
||||
private readonly ILibraryService _libraryService;
|
||||
|
||||
public LibraryController(
|
||||
ILogger<LibraryController> logger,
|
||||
public BooksController(
|
||||
ILogger<BooksController> logger,
|
||||
ILibraryService libraryService
|
||||
)
|
||||
{
|
||||
|
@ -21,31 +21,24 @@ public class LibraryController : ControllerBase
|
|||
_libraryService = libraryService ?? throw new ArgumentNullException(nameof(libraryService));
|
||||
}
|
||||
|
||||
[HttpGet(Name = "GetBooks")]
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<BookResponse>> GetBooksAsync(int page = 0, int pageSize = 10)
|
||||
{
|
||||
var books = await _libraryService.GetBooksAsync(page, pageSize);
|
||||
return books.Select(x => x.Map());
|
||||
}
|
||||
|
||||
[HttpGet(Name = "GetBook")]
|
||||
[HttpGet("{bookId}")]
|
||||
public async Task<BookResponse> GetBookAsync(int bookId)
|
||||
{
|
||||
var book = await _libraryService.GetBookAsync(bookId);
|
||||
return book.Map();
|
||||
}
|
||||
|
||||
[HttpPost(Name = "AddBook")]
|
||||
[HttpPost]
|
||||
public async Task<BookResponse> AddBookAsync(BookRequest bookRequest)
|
||||
{
|
||||
var book = await _libraryService.AddBookAsync(bookRequest.Map());
|
||||
return book.Map();
|
||||
}
|
||||
|
||||
[HttpPost(Name = "AddAuthor")]
|
||||
public async Task<AuthorResponse> AddAuthorAsync(AuthorRequest authorRequest)
|
||||
{
|
||||
var author = await _libraryService.AddAuthorAsync(authorRequest.Map());
|
||||
return author.Map();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"DbSettings": {
|
||||
"ConnectionString": "Server=localhost; Database=library; Uid=root; Pwd=libraryDbPassword;",
|
||||
"ConnectionString": "Server=localhost:3306; Database=library; Uid=root; Pwd=libraryDbPassword;",
|
||||
"Database": "library"
|
||||
},
|
||||
"Logging": {
|
||||
|
|
|
@ -44,13 +44,13 @@ public class DbContext : IDbContext
|
|||
async Task _initAuthors()
|
||||
{
|
||||
var sql = """
|
||||
CREATE TABLE IF NOT EXISTS Authors (
|
||||
AuthorId INT NOT NULL AUTO_INCREMENT,
|
||||
FirstName VARCHAR(255) NOT NULL,
|
||||
LastName VARCHAR(255) NOT NULL,
|
||||
DateCreated DATETIME NOT NULL,
|
||||
DateModified DATETIME NOT NULL,
|
||||
PRIMARY KEY (AuthorId)
|
||||
CREATE TABLE IF NOT EXISTS authors (
|
||||
author_id INT NOT NULL AUTO_INCREMENT,
|
||||
first_name VARCHAR(255) NOT NULL,
|
||||
last_name VARCHAR(255) NOT NULL,
|
||||
date_created DATETIME NOT NULL,
|
||||
date_modified DATETIME NOT NULL,
|
||||
PRIMARY KEY (author_id)
|
||||
);
|
||||
""";
|
||||
await connection.ExecuteAsync(sql);
|
||||
|
@ -59,16 +59,16 @@ public class DbContext : IDbContext
|
|||
async Task _initBooks()
|
||||
{
|
||||
var sql = """
|
||||
CREATE TABLE IF NOT EXISTS Books(
|
||||
BookId INT NOT NULL AUTO_INCREMENT,
|
||||
Title VARCHAR(255),
|
||||
AuthorId INT NOT NULL,
|
||||
Isbn VARCHAR(13) NOT NULL,
|
||||
DatePublished DATETIME NOT NULL,
|
||||
DateCreated DATETIME NOT NULL,
|
||||
DateModified DATETIME NOT NULL,
|
||||
PRIMARY KEY(BookId),
|
||||
FOREIGN KEY(AuthorId) REFERENCES Authors(AuthorId)
|
||||
CREATE TABLE IF NOT EXISTS books(
|
||||
book_id INT NOT NULL AUTO_INCREMENT,
|
||||
title VARCHAR(255),
|
||||
author_id INT NOT NULL,
|
||||
isbn VARCHAR(13) NOT NULL,
|
||||
date_published DATETIME NOT NULL,
|
||||
date_created DATETIME NOT NULL,
|
||||
date_modified DATETIME NOT NULL,
|
||||
PRIMARY KEY(book_id),
|
||||
FOREIGN KEY(author_id) REFERENCES authors(author_id)
|
||||
);
|
||||
""";
|
||||
await connection.ExecuteAsync(sql);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.0.143" />
|
||||
<PackageReference Include="Dapper.FluentMap" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
|
||||
<PackageReference Include="MySql.Data" Version="8.0.33" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Dapper.FluentMap;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
@ -16,5 +17,11 @@ public static class InfrastructureExtensions
|
|||
using var scope = app.Services.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<IDbContext>();
|
||||
await context.Init();
|
||||
|
||||
FluentMapper.Initialize(config =>
|
||||
{
|
||||
config.AddMap(new AuthorDbMap());
|
||||
config.AddMap(new BookDbMap());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
using GitHubActionsDemo.Persistance.Models;
|
||||
using System;
|
||||
using Dapper;
|
||||
using GitHubActionsDemo.Persistance.Models;
|
||||
|
||||
namespace GitHubActionsDemo.Persistance;
|
||||
|
||||
public class LibraryRespository : ILibraryRespository
|
||||
{
|
||||
public LibraryRespository()
|
||||
private readonly IDbContext _dbContext;
|
||||
public LibraryRespository(IDbContext dbContext)
|
||||
{
|
||||
|
||||
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
|
||||
}
|
||||
|
||||
public async Task<AuthorDb> AddAuthorAsync(NewAuthorDb author)
|
||||
|
@ -26,11 +29,64 @@ public class LibraryRespository : ILibraryRespository
|
|||
|
||||
public async Task<BookDb> GetBookAsync(int bookId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var sql = @$"SELECT
|
||||
b.book_id AS {nameof(BookDb.BookId)},
|
||||
b.title AS {nameof(BookDb.Title)},
|
||||
b.isbn AS {nameof(BookDb.Isbn)},
|
||||
b.date_published AS {nameof(BookDb.DatePublished)},
|
||||
b.date_created AS Book{nameof(BookDb.DateCreated)},
|
||||
b.date_modified AS Book{nameof(BookDb.DateModified)},
|
||||
a.author_id AS {nameof(AuthorDb.AuthorId)},
|
||||
a.first_name AS {nameof(AuthorDb.FirstName)},
|
||||
a.last_name AS {nameof(AuthorDb.LastName)},
|
||||
a.date_created AS Author{nameof(AuthorDb.DateCreated)},
|
||||
a.date_modified AS Author{nameof(AuthorDb.DateModified)}
|
||||
FROM books b
|
||||
INNER JOIN authors a ON a.author_id = b.author_id
|
||||
WHERE b.book_id = @BookId;";
|
||||
|
||||
var param = new
|
||||
{
|
||||
BookId = bookId
|
||||
};
|
||||
|
||||
using (var connection = _dbContext.CreateConnection())
|
||||
{
|
||||
var books = await connection.QueryAsync<BookDb, AuthorDb, BookDb>(sql, (book, author) =>
|
||||
{
|
||||
book.Author = author;
|
||||
return book;
|
||||
}, param, splitOn: nameof(AuthorDb.AuthorId));
|
||||
|
||||
return books?.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<BookDb>> GetBooksAsync(int page, int pageSize)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var sql = @$"SELECT
|
||||
b.book_id AS {nameof(BookDb.BookId)},
|
||||
b.title AS {nameof(BookDb.Title)},
|
||||
b.isbn AS {nameof(BookDb.Isbn)},
|
||||
b.date_published AS {nameof(BookDb.DatePublished)},
|
||||
b.date_created AS Book{nameof(BookDb.DateCreated)},
|
||||
b.date_modified AS Book{nameof(BookDb.DateModified)},
|
||||
a.author_id AS {nameof(AuthorDb.AuthorId)},
|
||||
a.first_name AS {nameof(AuthorDb.FirstName)},
|
||||
a.last_name AS {nameof(AuthorDb.LastName)},
|
||||
a.date_created AS Author{nameof(AuthorDb.DateCreated)},
|
||||
a.date_modified AS Author{nameof(AuthorDb.DateModified)}
|
||||
FROM books b
|
||||
INNER JOIN authors a ON a.author_id = b.author_id
|
||||
ORDER BY b.book_id;";
|
||||
|
||||
using (var connection = _dbContext.CreateConnection())
|
||||
{
|
||||
return await connection.QueryAsync<BookDb, AuthorDb, BookDb>(sql, (book, author) =>
|
||||
{
|
||||
book.Author = author;
|
||||
return book;
|
||||
}, splitOn: nameof(AuthorDb.AuthorId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
11
src/GitHubActionsDemo.Persistance/Mappings/AuthorDbMap.cs
Normal file
11
src/GitHubActionsDemo.Persistance/Mappings/AuthorDbMap.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using Dapper.FluentMap.Mapping;
|
||||
using GitHubActionsDemo.Persistance.Models;
|
||||
|
||||
internal class AuthorDbMap : EntityMap<AuthorDb>
|
||||
{
|
||||
internal AuthorDbMap()
|
||||
{
|
||||
Map(u => u.DateCreated).ToColumn($"Author{nameof(AuthorDb.DateCreated)}");
|
||||
Map(u => u.DateModified).ToColumn($"Author{nameof(AuthorDb.DateModified)}");
|
||||
}
|
||||
}
|
11
src/GitHubActionsDemo.Persistance/Mappings/BookDbMap.cs
Normal file
11
src/GitHubActionsDemo.Persistance/Mappings/BookDbMap.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using Dapper.FluentMap.Mapping;
|
||||
using GitHubActionsDemo.Persistance.Models;
|
||||
|
||||
internal class BookDbMap : EntityMap<BookDb>
|
||||
{
|
||||
internal BookDbMap()
|
||||
{
|
||||
Map(u => u.DateCreated).ToColumn($"Book{nameof(BookDb.DateCreated)}");
|
||||
Map(u => u.DateModified).ToColumn($"Book{nameof(BookDb.DateModified)}");
|
||||
}
|
||||
}
|
|
@ -2,24 +2,9 @@ namespace GitHubActionsDemo.Persistance.Models;
|
|||
|
||||
public class AuthorDb
|
||||
{
|
||||
public AuthorDb(
|
||||
int authorId,
|
||||
string firstName,
|
||||
string lastName,
|
||||
DateTime dateCreated,
|
||||
DateTime dateModified
|
||||
)
|
||||
{
|
||||
AuthorId = authorId;
|
||||
FirstName = firstName;
|
||||
LastName = lastName;
|
||||
DateCreated = dateCreated;
|
||||
DateModified = dateModified;
|
||||
}
|
||||
|
||||
public int AuthorId { get; }
|
||||
public string FirstName { get; }
|
||||
public string LastName { get; }
|
||||
public DateTime DateCreated { get; }
|
||||
public DateTime DateModified { get; }
|
||||
public int AuthorId { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public DateTime DateCreated { get; set; }
|
||||
public DateTime DateModified { get; set; }
|
||||
}
|
||||
|
|
|
@ -2,30 +2,11 @@ namespace GitHubActionsDemo.Persistance.Models;
|
|||
|
||||
public class BookDb
|
||||
{
|
||||
public BookDb(
|
||||
int bookId,
|
||||
string title,
|
||||
AuthorDb author,
|
||||
string isbn,
|
||||
DateOnly datePublished,
|
||||
DateTime dateCreated,
|
||||
DateTime dateModified
|
||||
)
|
||||
{
|
||||
BookId = bookId;
|
||||
Title = title;
|
||||
Author = author;
|
||||
Isbn = isbn;
|
||||
DatePublished = datePublished;
|
||||
DateCreated = dateCreated;
|
||||
DateModified = dateModified;
|
||||
}
|
||||
|
||||
public int BookId { get; }
|
||||
public string Title { get; }
|
||||
public AuthorDb Author { get; }
|
||||
public string Isbn { get; }
|
||||
public DateOnly DatePublished { get; }
|
||||
public DateTime DateCreated { get; }
|
||||
public DateTime DateModified { get; }
|
||||
public int BookId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public AuthorDb Author { get; set; }
|
||||
public string Isbn { get; set; }
|
||||
public DateOnly DatePublished { get; set; }
|
||||
public DateTime DateCreated { get; set; }
|
||||
public DateTime DateModified { get; set; }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue