Skip to content

aceitadev/aMySQL-Node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📦 aMySQL for Node.js

Uma biblioteca de persistência de dados para Node.js e TypeScript que implementa o padrão Active Record, permitindo uma interação fluida, assíncrona e intuitiva com o banco de dados MySQL.

O aMySQL foi projetado para alta performance e facilidade de uso, utilizando o pool de conexões do mysql2, um Query Builder fluente e um sistema de migração automática de schema, que elimina a necessidade de escrever SQL para a maioria das operações de CRUD e gerenciamento de tabelas.

🚀 Funcionalidades

  • Padrão Active Record: Manipule registros do banco de dados como objetos, chamando métodos como .save() e .delete() diretamente nas instâncias do modelo.
  • Pool de Conexões de Alta Performance: Utiliza o pool de conexões do mysql2 para um gerenciamento de conexões rápido e eficiente.
  • Operações Assíncronas: Todos os métodos de I/O com o banco (save(), delete(), find()) retornam Promises, ideais para o ambiente async/await do Node.js.
  • Query Builder Fluente: Construa consultas SELECT de forma segura e legível encadeando métodos como .where(), .orderBy() e .first().
  • Gerenciamento Automático de Schema: As tabelas e colunas são criadas e atualizadas automaticamente com base nos seus modelos ao executar o SchemaManager.
  • Mapeamento Customizado com ColumnAdapter: Converta tipos complexos (como Date ou outros objetos) para tipos que o banco de dados entende (como TIMESTAMP ou string).
  • Suporte a Relacionamentos: Mapeie relacionamentos entre objetos de forma declarativa usando o decorator @Column.
  • Decorators Poderosos: Configure tabelas, colunas, valores únicos, limites de VARCHAR e nulidade com decorators intuitivos do TypeScript.

📚 Instalação

Para utilizar o aMySQL, instale o pacote via npm e certifique-se de ter os pacotes mysql2 e reflect-metadata instalados.

npm install @aceitadev/amysql mysql2 reflect-metadata

Importante: Você precisa importar o reflect-metadata uma única vez no ponto de entrada da sua aplicação para que os decorators funcionem corretamente.

// no topo do seu arquivo principal (ex: index.ts)
import "reflect-metadata";

🛠️ Como Usar (Básico)

O ciclo de vida básico de um objeto no banco de dados.

1. Inicialização

Configure as credenciais do banco, registre suas classes de modelo e execute o migrador de schema.

// src/index.ts
import "reflect-metadata";
import { init } from "./MySQL";
import { SchemaManager } from "./SchemaManager";
import { Player } from "./models/Player";
import { PlayerProfile } from "./models/PlayerProfile";

async function main() {
    // 1. Configurar as credenciais
    await init({
        host: "localhost",
        port: 3306,
        database: "meu_banco",
        user: "root",
        password: "password"
    });

    // 2. Registrar modelos e migrar o schema
    const schema = new SchemaManager([Player, PlayerProfile]);
    await schema.migrate();

    console.log("Banco de dados inicializado e migrado!");
    // ... aqui começa a lógica da sua aplicação
}

main();

2. Criando a Classe de Modelo

Crie sua classe estendendo ActiveRecord. Todos os campos a serem persistidos devem ser anotados com @Column ou @Id.

// src/models/Player.ts
import { ActiveRecord } from "../ActiveRecord";
import { Table } from "../decorators/Table";
import { Id } from "../decorators/Id";
import { Column } from "../decorators/Column";

@Table("players")
export class Player extends ActiveRecord {
    @Id()
    id!: number;

    @Column({ unique: true }) // Garante que cada nome de usuário será único
    username!: string;

    @Column({ name: "last_seen" }) // Coluna 'last_seen' com tipo TIMESTAMP
    lastSeen!: Date;

    constructor(username?: string, lastSeen?: Date) {
        super();
        if (username) this.username = username;
        if (lastSeen) this.lastSeen = lastSeen;
    }
}

3. Salvar, Buscar e Deletar

Use async/await para interagir com o banco.

async function runExample() {
    // Salvar
    const player = new Player("Steve", new Date());
    await player.save();
    console.log(`Jogador salvo com o ID: ${player.id}`);

    // Buscar
    const foundPlayer = await Player.find<Player>()
                                    .where("username", "=", "Steve")
                                    .first();

    // Atualizar
    if (foundPlayer) {
        foundPlayer.username = "Steve 2.0";
        await foundPlayer.save();
        console.log("Jogador atualizado!");
    }

    // Deletar
    if (foundPlayer) {
        await foundPlayer.delete();
        console.log("Jogador deletado!");
    }
}

✨ Mapeamento Avançado

Mapeando Relacionamentos (Chave Estrangeira)

Para criar um relacionamento, anote o campo com @Column. O aMySQL detectará que o tipo do campo (ex: Player) é outra entidade com @Table e criará uma coluna de chave estrangeira (ex: player_id) automaticamente.

// src/models/PlayerProfile.ts
import { ActiveRecord } from "../ActiveRecord";
import { Table } from "../decorators/Table";
import { Id } from "../decorators/Id";
import { Column } from "../decorators/Column";
import { Player } from "./Player";

@Table("player_profiles")
export class PlayerProfile extends ActiveRecord {
    @Id()
    id!: number;

    // É obrigatório usar @Column para que o campo seja persistido.
    // aMySQL detecta o relacionamento e cria a coluna 'player_id'.
    @Column()
    player!: Player;

    @Column()
    bio!: string;
}

Como usar:

const player = await Player.find<Player>().where("username", "=", "Steve 2.0").first();

if (player) {
    const profile = new PlayerProfile();
    profile.player = player;
    profile.bio = "Apenas um jogador comum.";
    await profile.save();

    // Ao buscar o perfil, o objeto 'player' virá preenchido (apenas com o ID)
    const foundProfile = await PlayerProfile.find<PlayerProfile>()
                                            .where("player", "=", player)
                                            .first();

    if (foundProfile) {
        // Para carregar o objeto completo, você precisaria de uma busca adicional
        console.log(`Bio do jogador com ID: ${foundProfile.player.id}`);
    }
}

Mapeamento Customizado com ColumnAdapter

O ColumnAdapter permite que você defina como serializar e desserializar um campo com um tipo que não é nativo do MySQL.

1. Crie seu ColumnAdapter

// src/adapters/DateToTimestampAdapter.ts
import { ColumnAdapter } from "../ColumnAdapter";

// Converte um objeto Date do JS para um número (timestamp UNIX) para o DB e vice-versa
export class DateToTimestampAdapter implements ColumnAdapter<Date, number> {
    serialize(date: Date): number {
        return date ? Math.floor(date.getTime() / 1000) : null;
    }

    deserialize(timestamp: number): Date {
        return timestamp ? new Date(timestamp * 1000) : null;
    }
}

2. Use o Adapter no seu Modelo

// Em uma classe de modelo...
import { DateToTimestampAdapter } from "../adapters/DateToTimestampAdapter";

// ...
@Column({ adapter: DateToTimestampAdapter })
creationDate!: Date; // Será armazenado como INT (timestamp) no banco

✨ Decorators Disponíveis

  • @Table("table_name"): (Obrigatório) Define a classe como uma entidade e especifica o nome da tabela.
  • @Id(): (Obrigatório) Marca uma propriedade como a chave primária (INT, PRIMARY KEY, AUTO_INCREMENT).
  • @Nullable(): (Opcional) Permite que a coluna correspondente seja NULL. Por padrão, as colunas são NOT NULL.
  • @Column(options?): (Obrigatório para campos persistíveis) Mapeia uma propriedade para uma coluna no banco de dados.
    • name: "column_name": Define um nome customizado para a coluna. Se omitido, usa o nome da propriedade.
    • unique: true: Adiciona uma restrição UNIQUE à coluna.
    • limit: 255: Define o tamanho para colunas VARCHAR.
    • adapter: MyAdapter: Especifica um ColumnAdapter para serialização/desserialização customizada.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published