Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4a1c81d
chore: criando arquivo tarefa-orm.md #197
anderson-gpc Oct 15, 2025
b87fc7e
chore: adicionando depedências iniciais #197
anderson-gpc Oct 15, 2025
9aea693
chore: criando resumo de ORM e start da aplicação #197
anderson-gpc Oct 15, 2025
b22ce47
feat: definindo os mapeamentos dos objetos #197
anderson-gpc Oct 15, 2025
1f3c3ea
feat: definindo o relacionamento de projeto com o funcionario #197
anderson-gpc Oct 15, 2025
cea02a0
feat: criando classe de repository para 'Atividade' #197
anderson-gpc Oct 15, 2025
2907a53
chore: adicionando a biblioteca zod #197
anderson-gpc Oct 15, 2025
89ddbf4
feat: adicionando funcionalidade de criação de atividade #197
anderson-gpc Oct 15, 2025
4436d68
feat: adicionando schema para atividade #197
anderson-gpc Oct 15, 2025
de596ae
feat: criando classe de repository para funcionario #197
anderson-gpc Oct 15, 2025
e42d7bd
feat: criando esquema para query de mudança de líder #197
anderson-gpc Oct 15, 2025
d55ef00
feat: criando classe de funcionario #197
anderson-gpc Oct 15, 2025
a895c33
feat: criando método para mudar líder do projeto #197
anderson-gpc Oct 15, 2025
af4722a
chore: renomeando métodos para português
anderson-gpc Oct 15, 2025
f138166
chore: adicionando link no README.md principal
anderson-gpc Oct 15, 2025
799cd95
chore: delete README.md
anderson-gpc Oct 15, 2025
b0fb4cf
chore: update tarefa-orm.md
anderson-gpc Oct 15, 2025
cb69030
chore: adicionando types do node #197
anderson-gpc Oct 15, 2025
73c3cea
feat: execução de funções para testes #197
anderson-gpc Oct 15, 2025
99de6ba
chore: update tarefa-orm.md #197
anderson-gpc Oct 15, 2025
63c25d2
chore: update tarefa-orm.md
anderson-gpc Oct 15, 2025
ca2d879
fix: especificando atributos do projeto #197
anderson-gpc Oct 15, 2025
7c2a0f6
chore: update tarefa-orm.md #197
anderson-gpc Oct 15, 2025
845f237
chore: adicionando o node-odbc #197
anderson-gpc Oct 15, 2025
e03be07
feat: função para fazer conexão com a base de dados #197
anderson-gpc Oct 15, 2025
544f1fc
feat: método que traz todas as atividades e projetos #197
anderson-gpc Oct 15, 2025
abb2016
chore: ajuste de export default de classe #197
anderson-gpc Oct 15, 2025
8778dbb
feat: criando classe de repositório de funcionário #197
anderson-gpc Oct 15, 2025
98ffd1b
feat: criando classe para de repositorio para projeto #197
anderson-gpc Oct 15, 2025
f1d14f3
refactor: utilizando atributos da clase #197
anderson-gpc Oct 15, 2025
c1d5a59
fix: fechando conexão no try catch #197
anderson-gpc Oct 15, 2025
eae32cd
refactor: modificando visibilidade do método #197
anderson-gpc Oct 15, 2025
d4eb211
refactor: criando método de pegar conexão #197
anderson-gpc Oct 15, 2025
76dd3af
feat: criando schema para atividade #197
anderson-gpc Oct 15, 2025
71f3d36
feat: criando método de adicionar nova tarefa #197
anderson-gpc Oct 15, 2025
7a4998f
chore: rename path #197
anderson-gpc Oct 15, 2025
65dd97e
fix: adicionando left join para ver atividade com projeto null #197
anderson-gpc Oct 15, 2025
e9e8afa
feat: criando minis-crus #197
anderson-gpc Oct 15, 2025
b82d2ee
chore: update tarefa-orm.md #197
anderson-gpc Oct 15, 2025
adde1af
chore: adicionando scripts sql em tarefa-orm.md #197
anderson-gpc Oct 15, 2025
b33f40a
chore: update tarefa-orm.md #197
anderson-gpc Oct 16, 2025
582edfa
chore: mudança de path #197
anderson-gpc Oct 16, 2025
332a243
chore: update README.md
anderson-gpc Oct 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Link para tarefa-orm.md
[Ir para arquivo](https://github.com/anderson-gpc/bsi-tasks/blob/main/database/20252/tarefas/Anderson_Gabriel/orm/tarefa-orm.md)


# BSI Tasks

Repositório para Auxílio no Ensino de Banco de Dados Engenharia de Software, Teste de Software e Programação Web do curso de Bacharelado em Sistemas de Informação CERES/UFRN - Caicó RN
Expand Down
2 changes: 2 additions & 0 deletions database/20252/tarefas/Anderson_Gabriel/orm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.env
68 changes: 68 additions & 0 deletions database/20252/tarefas/Anderson_Gabriel/orm/odbc/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import readline from "readline";
import AtividadeRepository from "./repository/AtividadeRepository";
import ProjetoRepository from "./repository/ProjetoRepository";

async function pegarTodasAtividades() {
const atividades = await AtividadeRepository.pegarTodasAtividades();
console.log("\n=== Atividades ===");
console.log(atividades);
}

async function atualizarLiderProjeto(data: { codigo: number, responsavel: number }) {
const projeto = await ProjetoRepository.mudarLiderProjeto(data.codigo, data.responsavel);
console.log("\n=== Projeto atualizado ===");
console.log(projeto);
}

async function criarAtividade(data: { descricao: string, data_inicio: string, data_fim: string }) {
const atividade = await AtividadeRepository.criarAtividade(data);
console.log("\n=== Atividade criada ===");
console.log(atividade);
}

const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

function perguntar(query: string): Promise<string> {
return new Promise(resolve => rl.question(query, resolve));
}

async function menu() {
console.log("\n=== Menu ===");
console.log("1 - Ver todas as atividades");
console.log("2 - Atualizar líder de projeto");
console.log("3 - Criar atividade");
console.log("0 - Sair");

const opcao = await perguntar("Escolha uma opção: ");

switch (opcao) {
case "1":
await pegarTodasAtividades();
break;
case "2":
const codigo = parseInt(await perguntar("Digite o código do projeto: "));
const responsavel = parseInt(await perguntar("Digite o ID do novo responsável: "));
await atualizarLiderProjeto({ codigo, responsavel });
break;
case "3":
const descricao = await perguntar("Digite a descrição da atividade: ");
const data_inicio = await perguntar("Digite a data de início (YYYY-MM-DD): ");
const data_fim = await perguntar("Digite a data de fim (YYYY-MM-DD): ");
await criarAtividade({ descricao, data_inicio, data_fim });
break;
case "0":
console.log("Saindo...");
rl.close();
return;
default:
console.log("Opção inválida!");
}


menu();
}

menu();
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { atividadeSchema } from "../schema/atividade.shcema";
import conexaoODBC from "../service/server";
import ProjetoRepository from "./ProjetoRepository";

class AtividadeRepository {
private conexao: any | null;

async pegarTodasAtividades() {
this.conexao = await conexaoODBC();
try {
const resultado = await this.conexao.query(`SELECT
a.codigo,
a.descricao AS atividade_descricao,
a.projeto AS projeto_codigo,
a.data_inicio,
a.data_fim,
p.nome AS projeto_nome,
p.descricao AS projeto_descricao
FROM atividade a
LEFT JOIN projeto p ON p.codigo = a.projeto;`);
return resultado.filter((key: any) => key != "columns");
} catch (error) {
console.error("Erro de conexão ou query:", error);
return [];
} finally {
if (this.conexao) await this.conexao.close();
}
}

async criarAtividade(data: any) {
const parsed = atividadeSchema.safeParse(data);
if (!parsed.success) {
return { success: false, message: "Dados inválidos." };
}

const { descricao, projeto, data_fim, data_inicio } = parsed.data;
this.conexao = await conexaoODBC();

try {
let codProjeto: number | null = null;

if (projeto !== undefined && projeto !== null) {
const projetoExiste = await this.projetoExiste(projeto);
if (!projetoExiste) {
throw new Error("Projeto informado não existe.");
}
codProjeto = projeto;
}

await this.conexao.query(
`INSERT INTO atividade (descricao, projeto, data_fim, data_inicio)
VALUES (?, ?, ?, ?)`,
[descricao, codProjeto, data_fim, data_inicio]
);

return { success: true, message: "Atividade criada com sucesso!" };
} catch (error: any) {
console.error("Erro de conexão ou query:", error);
return { success: false, message: error.message };
} finally {
if (this.conexao) await this.conexao.close();
}
}

async projetoExiste(projeto: number): Promise<boolean> {
const codProjeto = await ProjetoRepository.projetoExiste(projeto);
return !!codProjeto;
}
}

export default new AtividadeRepository();
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export class FuncionarioRepository {
private conexao: any | null;
private codigo: number;

constructor(conexao: any, codigo: number) {
this.conexao = conexao;
this.codigo = codigo;
}

async fucionarioExiste(): Promise<any> {
const [funcionario] = await this.conexao.query(
"SELECT 1 FROM funcionario WHERE codigo = ?",
[this.codigo]
);
return funcionario;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import conexaoODBC from "../service/server";
import { FuncionarioRepository } from "./FuncionarioRepository";

class ProjetoRepository {
private conexao: any | null = null;

private async getConexao() {
if (!this.conexao) {
this.conexao = await conexaoODBC();
}
return this.conexao;
}

async mudarLiderProjeto(codigo: number, responsavel: number) {
const conexao = await this.getConexao();

try {
await conexao.beginTransaction();

const projeto = await this.projetoExiste(codigo);
if (!projeto) throw new Error("Projeto não encontrado.");

const funcionario = await this.funcionarioExiste(responsavel);
if (!funcionario) throw new Error("Responsável não encontrado.");

await conexao.query(
"UPDATE projeto SET responsavel = ? WHERE codigo = ?",
[responsavel, codigo]
);

await conexao.commit();
return { success: true, message: "Líder atualizado com sucesso!" };
} catch (error: any) {
await conexao.rollback();
console.error("Erro ao mudar líder:", error.message);
return { success: false, message: error.message };
} finally {
if (this.conexao) await this.conexao.close();
this.conexao = null;
}
}

async projetoExiste(codigo: number): Promise<any> {
const conexao = await this.getConexao();
const [projeto] = await conexao.query(
"SELECT 1 FROM projeto WHERE codigo = ?",
[codigo]
);
return projeto;
}

private async funcionarioExiste(responsavel: number): Promise<any> {
const conexao = await this.getConexao();
const funcionarioRepo = new FuncionarioRepository(conexao, responsavel);
const funcionario = await funcionarioRepo.fucionarioExiste();
return funcionario;
}
}

export default new ProjetoRepository();
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { z } from "zod";

export const atividadeSchema = z.object({
descricao: z.string().min(1, "Descrição obrigatória."),
projeto: z.number().optional(),
data_inicio: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Data inválida (AAAA-MM-DD)."),
data_fim: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Data inválida (AAAA-MM-DD).")
});
11 changes: 11 additions & 0 deletions database/20252/tarefas/Anderson_Gabriel/orm/odbc/service/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import odbc from "odbc";

async function conexaoODBC(): Promise<odbc.Connection> {
try {
return await odbc.connect("DSN=MeuPostgres");
} catch {
throw new Error('Erro ao solicitar a conexão!');
}
}

export default conexaoODBC;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { DataTypes } from "sequelize";
import { sequelize } from "../sequelize";
import { Projeto } from "./projeto.model";

export const Atividade = sequelize.define(
"atividade",
{
codigo: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
descricao: { type: DataTypes.STRING(250) },
data_inicio: { type: DataTypes.DATE },
data_fim: { type: DataTypes.DATE },
},
{
tableName: "atividade",
freezeTableName: false,
timestamps: false,
}
);

Atividade.belongsTo(Projeto, {
foreignKey: "projeto",
as: "projetoAssociado",
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { DataTypes } from "sequelize";
import { sequelize } from "../sequelize";

export const Funcionario = sequelize.define(
"funcionario",
{
codigo: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
nome: { type: DataTypes.STRING(150), allowNull: false },
sexo: { type: DataTypes.CHAR(1) },
dt_nasc: { type: DataTypes.DATE },
salario: { type: DataTypes.DECIMAL },
supervisor: { type: DataTypes.INTEGER, allowNull: true },
depto: { type: DataTypes.INTEGER, allowNull: true },
},
{
tableName: "funcionario",
freezeTableName: false,
timestamps: false,
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// projeto.model.ts
import { DataTypes } from "sequelize";
import { sequelize } from "../sequelize";
import { Funcionario } from "./funcionario.model";

export const Projeto = sequelize.define(
"projeto",
{
codigo: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
nome: { type: DataTypes.STRING(50), unique: true },
descricao: { type: DataTypes.STRING(250) },
depto: { type: DataTypes.INTEGER, allowNull: true },
data_inicio: { type: DataTypes.DATE },
data_fim: { type: DataTypes.DATE },
},
{
tableName: "projeto",
freezeTableName: true,
timestamps: false,
}
);

Projeto.belongsTo(Funcionario, {
foreignKey: 'responsavel',
as: 'funcionarioAssociado'
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Sequelize } from "sequelize";

export const sequelize = new Sequelize("atividade_db", "admin", "senha", {
dialect: "postgres",
host: "localhost",
});
Loading