refatoração LivroRepository

This commit is contained in:
Gabriel Almeida Bueno 2025-05-08 08:42:58 -03:00
parent 734b66090a
commit c98b329df3
7 changed files with 1142 additions and 47 deletions

View File

@ -30,7 +30,7 @@ Content-Type: application/json
### Obtém um livro individual ### Obtém um livro individual
GET {{url}}/livros/abc1 GET {{url}}/livros/a
Accept: application/json Accept: application/json
### Remove um livro ### Remove um livro

View File

@ -2,6 +2,7 @@ namespace Biblioteca.Models;
public class Livro public class Livro
{ {
public long Id { get; set; }
public string? Isbn { get; set; } public string? Isbn { get; set; }
public string? Titulo { get; set; } public string? Titulo { get; set; }
public string? Autor { get; set; } public string? Autor { get; set; }

View File

@ -24,29 +24,29 @@ app.MapPost("/livros", async (Livro livro) =>
}); });
// Edita um livro. // Edita um livro.
app.MapPut("/livros/{isbn}", async (string isbn, Livro livro) => app.MapPut("/livros/{id}", async (long id, Livro livro) =>
{ {
var repo = new LivroRepository(); var repo = new LivroRepository();
var res = await repo.Editar(isbn, livro); var res = await repo.Editar(id, livro);
return res; return res;
}); });
// Obtém os dados de um livro individual. // Obtém os dados de um livro individual.
app.MapGet("/livros/{isbn}", async (string isbn) => app.MapGet("/livros/{id}", async (long id) =>
{ {
var repo = new LivroRepository(); var repo = new LivroRepository();
var res = await repo.Obter(isbn); var res = await repo.Obter(id);
return res; return res;
}); });
// Remove um livro. // Remove um livro.
app.MapDelete("/livros/{isbn}", async (string isbn) => app.MapDelete("/livros/{id}", async (long id) =>
{ {
var repo = new LivroRepository(); var repo = new LivroRepository();
await repo.Desativar(isbn); await repo.Desativar(id);
}); });
app.Run(); app.Run();

View File

@ -18,7 +18,7 @@ public class LivroRepository
var offset = take * Math.Max(pagina-1, 0); var offset = take * Math.Max(pagina-1, 0);
var lista = new List<Livro>(); var lista = new List<Livro>();
cmd.CommandText = "SELECT Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro ORDER BY CriadoEm LIMIT @offset,@take"; cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro ORDER BY CriadoEm LIMIT @offset,@take";
cmd.Parameters.AddWithValue("offset", offset); cmd.Parameters.AddWithValue("offset", offset);
cmd.Parameters.AddWithValue("take", take); cmd.Parameters.AddWithValue("take", take);
@ -28,16 +28,17 @@ public class LivroRepository
{ {
lista.Add(new() lista.Add(new()
{ {
Isbn = reader.GetString(0), Id = reader.GetInt64(0),
Titulo = reader.GetString(1), Isbn = reader.GetString(1),
Autor = reader.GetString(2), Titulo = reader.GetString(2),
Genero = reader.GetString(3), Autor = reader.GetString(3),
Descricao = reader.GetString(4), Genero = reader.GetString(4),
Foto = reader.GetString(5), Descricao = reader.GetString(5),
Keywords = reader.GetString(6), Foto = reader.GetString(6),
Ativo = reader.GetBoolean(7), Keywords = reader.GetString(7),
CriadoEm = reader.GetDateTime(8), Ativo = reader.GetBoolean(8),
AtualizadoEm = reader.GetDateTime(9), CriadoEm = reader.GetDateTime(9),
AtualizadoEm = reader.GetDateTime(10),
}); });
} }
@ -49,15 +50,15 @@ public class LivroRepository
/// </summary> /// </summary>
/// <param name="isbn"></param> /// <param name="isbn"></param>
/// <returns></returns> /// <returns></returns>
public async Task<Livro> Obter(string isbn) public async Task<Livro> Obter(long id)
{ {
using var conn = new MySqlConnection(ConnString); using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand(); using var cmd = conn.CreateCommand();
await conn.OpenAsync(); await conn.OpenAsync();
cmd.CommandText = "SELECT Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro WHERE Isbn=@isbn"; cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro WHERE Id=@id";
cmd.Parameters.AddWithValue("isbn", isbn); cmd.Parameters.AddWithValue("id", id);
using var reader = await cmd.ExecuteReaderAsync(); using var reader = await cmd.ExecuteReaderAsync();
@ -65,21 +66,22 @@ public class LivroRepository
if (!existe) if (!existe)
{ {
throw new Exception($"Livro com ISBN {isbn} não encontrado"); throw new Exception($"Livro {id} não encontrado");
} }
return new() return new()
{ {
Isbn = reader.GetString(0), Id = reader.GetInt64(0),
Titulo = reader.GetString(1), Isbn = reader.GetString(1),
Autor = reader.GetString(2), Titulo = reader.GetString(2),
Genero = reader.GetString(3), Autor = reader.GetString(3),
Descricao = reader.GetString(4), Genero = reader.GetString(4),
Foto = reader.GetString(5), Descricao = reader.GetString(5),
Keywords = reader.GetString(6), Foto = reader.GetString(6),
Ativo = reader.GetBoolean(7), Keywords = reader.GetString(7),
CriadoEm = reader.GetDateTime(8), Ativo = reader.GetBoolean(8),
AtualizadoEm = reader.GetDateTime(9), CriadoEm = reader.GetDateTime(9),
AtualizadoEm = reader.GetDateTime(10),
}; };
} }
@ -104,11 +106,6 @@ public class LivroRepository
AtualizadoEm = default, AtualizadoEm = default,
}; };
if (livro.Isbn == "")
{
throw new Exception("O ISBN do livro é obrigatório.");
}
if (livro.Titulo == "") if (livro.Titulo == "")
{ {
throw new Exception("O título do livro é obrigatório."); throw new Exception("O título do livro é obrigatório.");
@ -138,14 +135,14 @@ public class LivroRepository
return livro; return livro;
} }
public async Task<Livro> Editar(string isbn, Livro dados) public async Task<Livro> Editar(long id, Livro dados)
{ {
using var conn = new MySqlConnection(ConnString); using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand(); using var cmd = conn.CreateCommand();
await conn.OpenAsync(); await conn.OpenAsync();
var livro = await Obter(isbn); var livro = await Obter(id);
livro.Titulo = dados.Titulo?.Trim() ?? ""; livro.Titulo = dados.Titulo?.Trim() ?? "";
livro.Autor = dados.Autor?.Trim() ?? ""; livro.Autor = dados.Autor?.Trim() ?? "";
@ -159,10 +156,10 @@ public class LivroRepository
@" @"
UPDATE Livro SET UPDATE Livro SET
Titulo=@titulo, Autor=@autor, Genero=@genero, Descricao=@descricao, Foto=@foto, Keywords=@keywords, AtualizadoEm=@atualizadoem Titulo=@titulo, Autor=@autor, Genero=@genero, Descricao=@descricao, Foto=@foto, Keywords=@keywords, AtualizadoEm=@atualizadoem
WHERE Isbn=@isbn WHERE Id=@id
"; ";
cmd.Parameters.AddWithValue("isbn", isbn); cmd.Parameters.AddWithValue("id", id);
cmd.Parameters.AddWithValue("titulo", livro.Titulo); cmd.Parameters.AddWithValue("titulo", livro.Titulo);
cmd.Parameters.AddWithValue("autor", livro.Autor); cmd.Parameters.AddWithValue("autor", livro.Autor);
cmd.Parameters.AddWithValue("genero", livro.Genero); cmd.Parameters.AddWithValue("genero", livro.Genero);
@ -176,15 +173,15 @@ public class LivroRepository
return livro; return livro;
} }
public async Task Desativar(string isbn) public async Task Desativar(long id)
{ {
using var conn = new MySqlConnection(ConnString); using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand(); using var cmd = conn.CreateCommand();
await conn.OpenAsync(); await conn.OpenAsync();
cmd.CommandText = "UPDATE Livro SET Ativo=false WHERE Isbn=@isbn"; cmd.CommandText = "UPDATE Livro SET Ativo=false WHERE Id=@id";
cmd.Parameters.AddWithValue("isbn", isbn); cmd.Parameters.AddWithValue("id", id);
await cmd.ExecuteNonQueryAsync(); await cmd.ExecuteNonQueryAsync();
} }

71
scripts/books.py Normal file
View File

@ -0,0 +1,71 @@
#
# books.py
# Gera um arquivo .sql com INSERTs de livros obtidos do Project Gutemberg
# https://gutendex.com/
#
import http.client
import json
import time
from urllib.parse import urlparse
API_URL = "https://gutendex.com/books/"
BOOKS_COUNT = 1000
FETCH_DELAY = 1#s
OUTPUT = "./books.sql"
def fetch(resource):
url = urlparse(resource)
client = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
conn = client(url.netloc)
conn.request("GET", f"{url.path}?{url.query}")
res = conn.getresponse()
if res.status < 200 or res.status > 299:
return {}
return json.loads(res.read())
def write_inserts(file, page):
data = fetch(f"{API_URL}?page={page}")
books = data["results"]
lines = []
esc = lambda str: str.replace('"', '\\"')
for book in books:
summaries = book["summaries"]
imgs = [book["formats"][f] for f in book["formats"] if f.startswith("image/")]
isbn = ""
titulo = book["title"]
autor = ",".join([a["name"] for a in book["authors"]])
genero = ",".join(book["subjects"])
descricao = summaries[0] if len(summaries) > 0 else ""
foto = imgs[0] if len(imgs) > 0 else ""
keywords = ",".join(book["bookshelves"])
lines.append(f'("{esc(isbn)}", "{esc(titulo)}", "{esc(autor)}", "{esc(genero)}", "{esc(descricao)}", "{esc(foto)}", "{esc(keywords)}", true, NOW(), NOW())')
values = ",\n".join(lines)
insert = f"INSERT INTO Livro (Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm) VALUES {values};\n"
file.write(insert)
return len(lines)
def collect(n, file, _page=1):
if n <= 0:
return
written = write_inserts(file, _page)
time.sleep(FETCH_DELAY)
collect(n-written, file, _page+1)
def run():
with open(OUTPUT, "w") as file:
collect(BOOKS_COUNT, file)
run()

1024
scripts/books.sql Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
CREATE TABLE Livro ( CREATE TABLE Livro (
Isbn VARCHAR(255) PRIMARY KEY NOT NULL, Id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
Isbn VARCHAR(255) NOT NULL,
Titulo VARCHAR(512) NOT NULL, Titulo VARCHAR(512) NOT NULL,
Autor TEXT NOT NULL, Autor TEXT NOT NULL,
Genero TEXT NOT NULL, Genero TEXT NOT NULL,
@ -10,6 +11,7 @@ CREATE TABLE Livro (
CriadoEm DATETIME NOT NULL, CriadoEm DATETIME NOT NULL,
AtualizadoEm DATETIME NOT NULL, AtualizadoEm DATETIME NOT NULL,
FULLTEXT (Titulo, Autor, Genero, Descricao, Keywords), INDEX (Isbn),
INDEX (CriadoEm) INDEX (CriadoEm),
FULLTEXT (Titulo, Autor, Genero, Descricao, Keywords)
); );