This commit is contained in:
2026-03-04 18:33:32 -03:00
parent 3af14ab957
commit 841dfadde5
6 changed files with 156 additions and 78 deletions
+61 -22
View File
@@ -1,6 +1,22 @@
use crate::domain::entities::layout::{Layout, LayoutCsv, LayoutXlsx};
use rusqlite::{params, Connection, Result};
/// Converte o char delimitador para string legível no banco.
fn delim_para_str(c: char) -> String {
match c {
'\t' => "tab".to_string(),
c => c.to_string(),
}
}
/// Converte a string armazenada no banco de volta para char delimitador.
fn str_para_delim(s: &str) -> char {
match s {
"tab" => '\t',
s => s.chars().next().unwrap_or(';'),
}
}
/// Salva um layout no banco. Retorna o id gerado.
pub fn salvar(conn: &Connection, layout: &Layout) -> Result<i64> {
match layout {
@@ -13,7 +29,7 @@ pub fn salvar(conn: &Connection, layout: &Layout) -> Result<i64> {
VALUES (?1, 'csv', ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
params![
nome,
config.delimitador.to_string(),
delim_para_str(config.delimitador),
config.encoding,
config.linha_cabecalho as i64,
config.indice_numero as i64,
@@ -47,6 +63,7 @@ pub fn salvar(conn: &Connection, layout: &Layout) -> Result<i64> {
}
/// Atualiza um layout existente no banco.
/// Zera explicitamente os campos do tipo oposto para evitar dados órfãos.
pub fn atualizar(conn: &Connection, layout: &Layout) -> Result<()> {
let id = layout
.id()
@@ -58,11 +75,13 @@ pub fn atualizar(conn: &Connection, layout: &Layout) -> Result<()> {
"UPDATE layouts SET
nome = ?1, delimitador = ?2, encoding = ?3,
linha_cabecalho = ?4, indice_numero = ?5, indice_serie = ?6,
indice_valor = ?7, indice_data = ?8, indice_documento_tipo = ?9
indice_valor = ?7, indice_data = ?8, indice_documento_tipo = ?9,
aba = NULL, pos_numero = NULL, pos_serie = NULL,
pos_valor = NULL, pos_data = NULL, pos_documento_tipo = NULL
WHERE id = ?10",
params![
nome,
config.delimitador.to_string(),
delim_para_str(config.delimitador),
config.encoding,
config.linha_cabecalho as i64,
config.indice_numero as i64,
@@ -78,7 +97,10 @@ pub fn atualizar(conn: &Connection, layout: &Layout) -> Result<()> {
conn.execute(
"UPDATE layouts SET
nome = ?1, aba = ?2, pos_numero = ?3, pos_serie = ?4,
pos_valor = ?5, pos_data = ?6, pos_documento_tipo = ?7
pos_valor = ?5, pos_data = ?6, pos_documento_tipo = ?7,
delimitador = NULL, encoding = NULL, linha_cabecalho = NULL,
indice_numero = NULL, indice_serie = NULL, indice_valor = NULL,
indice_data = NULL, indice_documento_tipo = NULL
WHERE id = ?8",
params![
nome,
@@ -109,25 +131,31 @@ pub fn listar(conn: &Connection) -> Result<Vec<Layout>> {
let layouts: Result<Vec<Layout>> = stmt
.query_map([], |row| {
let id: i64 = row.get(0)?;
let nome: String = row.get(1)?;
let tipo: String = row.get(2)?;
let id: i64 = row.get("id")?;
let nome: String = row.get("nome")?;
let tipo: String = row.get("tipo")?;
if tipo == "csv" {
let delim_str: String = row.get(3)?;
let delimitador = delim_str.chars().next().unwrap_or(';');
let delim_str: String = row.get("delimitador")?;
let delimitador = str_para_delim(&delim_str);
Ok(Layout::Csv {
id: Some(id),
nome,
config: LayoutCsv {
delimitador,
encoding: row.get(4)?,
linha_cabecalho: row.get::<_, i64>(5)? as usize,
indice_numero: row.get::<_, i64>(6)? as usize,
indice_serie: row.get::<_, i64>(7)? as usize,
indice_valor: row.get::<_, Option<i64>>(8)?.map(|v| v as usize),
indice_data: row.get::<_, Option<i64>>(9)?.map(|v| v as usize),
indice_documento_tipo: row.get::<_, Option<i64>>(15)?.map(|v| v as usize),
encoding: row.get("encoding")?,
linha_cabecalho: row.get::<_, i64>("linha_cabecalho")? as usize,
indice_numero: row.get::<_, i64>("indice_numero")? as usize,
indice_serie: row.get::<_, i64>("indice_serie")? as usize,
indice_valor: row
.get::<_, Option<i64>>("indice_valor")?
.map(|v| v as usize),
indice_data: row
.get::<_, Option<i64>>("indice_data")?
.map(|v| v as usize),
indice_documento_tipo: row
.get::<_, Option<i64>>("indice_documento_tipo")?
.map(|v| v as usize),
},
})
} else {
@@ -135,12 +163,12 @@ pub fn listar(conn: &Connection) -> Result<Vec<Layout>> {
id: Some(id),
nome,
config: LayoutXlsx {
aba: row.get(10)?,
pos_numero: row.get(11)?,
pos_serie: row.get(12)?,
pos_valor: row.get(13)?,
pos_data: row.get(14)?,
pos_documento_tipo: row.get(16)?,
aba: row.get("aba")?,
pos_numero: row.get("pos_numero")?,
pos_serie: row.get("pos_serie")?,
pos_valor: row.get("pos_valor")?,
pos_data: row.get("pos_data")?,
pos_documento_tipo: row.get("pos_documento_tipo")?,
},
})
}
@@ -165,3 +193,14 @@ pub fn existe_nome(conn: &Connection, nome: &str) -> Result<bool> {
)?;
Ok(count > 0)
}
/// Verifica se existe um layout com o nome fornecido, excluindo o registro com o id dado.
/// Usado para validar conflito de nome ao renomear um layout existente.
pub fn existe_nome_excluindo_id(conn: &Connection, nome: &str, id: i64) -> Result<bool> {
let count: i64 = conn.query_row(
"SELECT COUNT(*) FROM layouts WHERE nome = ?1 AND id != ?2",
params![nome, id],
|row| row.get(0),
)?;
Ok(count > 0)
}