Anuncios

Bienvenidos sean a este post, hoy veremos otra forma de almacenar informacion.

Anuncios

En el post anterior vimos como hacer que nuestra aplicacion Notas almacene informacion mediante una base SQL, en este caso sqlite3, pero podemos intentar hacer algo un poco mas divertido como trabajar con ORM pero que es ORM? Es una tecnica que nos permite relacionar los programas orientados a objetos (OOP) con bases relacionales (DBRMS) tales como puede ser SQL pero permitiendo que este programa trabaje directamente sobre las bases sin necesidad de utilizar queries como vimos en el post anterior, para ello vamos a utilizar dos modulos:

  • sequelize
  • yaml
Anuncios

Para instalar estos dos modulos necesitaremos ir al codigo que trabajamos en el post anterior, en caso de no tenerlo les dejo un link para descargarlo:

Anuncios

Una vez descargado simplemente extraigan el directorio en el PC y ya lo tenemos listo para trabajar, nuestro siguiente paso sera ejecutar el siguiente comando desde el directorio notas:

$ npm install sequelize@6.x --save
Anuncios

Este se encarga de instalar el modulo sequelize, el cual usaremos para trabajar con la tabla en nuestra base de datos, despues debemos ejecutar el siguiente comando:

$ npm install js-yaml@3.13.x --save
Anuncios

Este sera el modulo encargado de permitirnos usar archivos YAML, este es un lenguaje de serializacion de datos pero capaz de ser leido por humanos, este es especialmente util para que podamos describir objetos de datos, y ya veremos como lo usaremos.

Anuncios

Con esto instalado y comentado vamos a trabajar con nuestro codigo y para ello vamos a crear un nuevo archivo para poder realizar la conexion y desconexion de la base de datos, en el directorio models crearemos un nuevo archivo con el nombre de sequelizar.mjs y le agregaremos el siguiente codigo:

models/sequelizar.mjs

import { promises as fs } from 'fs';
import { default as jsyaml } from 'js-yaml';
import Sequelize from 'sequelize';

var sequelizar;

export async function conectarDB() {
if (typeof sequelizar === 'undefined') {
const textoyaml = await fs.readFile(
process.env.SEQUELIZE_CONNECT,
'utf8');
const params = jsyaml.safeLoad(textoyaml, 'utf8');

if (typeof process.env.SEQUELIZE_DBNAME !== 'undefined'
&& process.env.SEQUELIZE_DBNAME !== '') {
params.dbname = process.env.SEQUELIZE_DBNAME;
}

if (typeof process.env.SEQUELIZE_DBUSER !== 'undefined'
&& process.env.SEQUELIZE_DBUSER !== '') {
params.username = process.env.SEQUELIZE_DBUSER;
}

if (typeof process.env.SEQUELIZE_DBPASSWD !== 'undefined'
&& process.env.SEQUELIZE_DBPASSWD !== '') {
params.password = process.env.SEQUELIZE_DBPASSWD;
}

if (typeof process.env.SEQUELIZE_DBHOST !== 'undefined'
&& process.env.SEQUELIZE_DBHOST !== '') {
params.params.host = process.env.SEQUELIZE_DBHOST;
}

if (typeof process.env.SEQUELIZE_DBPORT !== 'undefined'
&& process.env.SEQUELIZE_DBPORT !== '') {
params.params.port = process.env.SEQUELIZE_DBPORT;
}

if (typeof process.env.SEQUELIZE_DBDIALECT !== 'undefined'
&& process.env.SEQUELIZE_DBDIALECT !== '') {
params.params.dialect = process.env.SEQUELIZE_DBDIALECT;
}

sequelizar = new Sequelize(params.dbname,
params.username, params.password, {
dialect: params.dialect,
storage: params.storage,
port: params.port,
host: params.host
});

await sequelizar.authenticate();
}
return sequelizar;
}

export async function cerrar() {
if (sequelizar) sequelizar.close();
sequelizar = undefined;
}
Anuncios
Anuncios

En este caso primero importaremos tres modulos, el primero sera para las promesas pero la renombraremos a fs, despues la encargada de manejar los archivos yaml y la ultima sera para usar a sequelize, la primera funcion sera para conectarnos a la base, en esta verificaremos que la variable declarada anteriormente tiene el valor de undefined y en caso de ser verdadero lo primero que haremos sera leer el archivo que le pasemos en esa variable de entorno, y luego mediante otro objeto almacenaremos el contenido del archivo y mediante el metodo safeLoad nos aseguraremos que se carguen bien los datos, despues tenemos una serie de condicionales que son similares pero hacen distintas tareas, en general verifican si una variable de entorno es distinta de undefined o no esta vacia procede a tomar una de las propiedades del objeto params y la reemplaza con el valor de la variable pertinente, despues de esto iniciaremos a la variable que verificamos al comienzo y en este usaremos Sequelize en conjunto con los parametros anteriores para crear el objeto de conexion y luego usaremos el metodo authenticate para verificar que este todo correcto y por ultimo devolvemos este objeto si todo salio bien, por ultimo tenemos la funcion para cerrar la conexion, donde verificamos si el objeto sequelizar existe.

Anuncios

En caso de ser verdadero procedemos a cerrarlo y por ultimo lo definimos como undefined, ahora necesitemos el archivo yaml para pasar los parametros de conexion, para ello en el directorio models crearemos un nuevo archivo con el nombre de sequelizar-sqlite.yaml y le agregaremos el siguiente codigo:

models/sequelizar-sqlite.yaml

dbname: notas
username:
password:
params:
dialect: sqlite
storage: notas-sequelizar.sqlite3
Anuncios
Anuncios

Como pueden ver respetamos varios nombres de los parametros que establecimos anteriormente, como utilizamos a sqlite3 no es necesario un usuario y contraseña, observen que en params especificamos el dialecto, es decir el tipo de engine que nos conectaremos, y luego la base que usaremos para almacenar, con esto ya tenemos una base para nuestra conexion, modificando este archivo o creando con otros parametros podemos tener varias conexiones, nuestro siguiente paso sera crear el modelo de notas para este tipo de conexion para ello en el directorio models crearemos un archivo con el nombre de notas-sequelizar.mjs y le agregaremos este codigo:

models/notas-sequelizar.mjs

import { Nota, AlmacenNotasAbs } from './Notas.mjs';
import Sequelize from 'sequelize';
import { conectarDB as conectarSequlz,
cerrar as cerrarSequlz } from './sequelizar.mjs';
import DBG from 'debug';
const debug = DBG('notas:notas-sequelizar');
const error = DBG('notas:error-sequelizar');

var sequelizar;

export class SQNota extends Sequelize.Model {}

async function conectarDB() {
if (sequelizar) return;
sequelizar = await conectarSequlz();
SQNota.init({
clave: { type: Sequelize.DataTypes.STRING,
primaryKey: true,
unique: true },
titulo: Sequelize.DataTypes.STRING,
cuerpo: Sequelize.DataTypes.TEXT
}, {
sequelize: sequelizar,
modelName: 'SQNota'
});
await SQNota.sync();
}
Anuncios
Anuncios

Como siempre primero importaremos los modulos que necesitaremos, primero sera el encargado de nuestras notas, la siguiente sera para usar a sequelize, luego el modulo que creamos anteriormente, observen que renombramos a los nombres de las funciones en esta y ya veremos porque, despues tenemos las ultimas tres lineas donde importaremos al modulo debug para depuracion y dos lineas para iniciarlas con sus identificadores, observen que definimos una clase vacia pero que sera heredera de Sequelize.Model para utilizar metodos de estas, despues tenemos una funcion que se llamara conectarDB (por esta razon renombramos a los del modulo anterior) y este se encargara de conectar nuestra base, lo primero que haremos sera verificar si existe ese objeto y en caso de ser verdadero sale de la funcion, de no existir este objeto procedemos a definirlo mediante la conexion a la base pero mediante el que comentamos anteriormente, despues tomaremos la clase heredera que creamos anteriormente y mediante el metodo init la iniciaremos, primero pasaremos los tres campos de nuestra tabla y mediante las propiedades definiremos cada uno, en este caso principalmente definimos el tipo de dato que contendra salvo clave que definiremos tambien como primaryKey y que sera unico (unique).

Anuncios

Despues pasamos dos parametros mas, en este caso el primero sequelize y le pasaremos el objeto que definimos anteriormente y luego el nombre del modelo que sera la clase que usamos para finalmente sincronizarla y crear lo que sea necesario, ahora agreguemos el siguiente segmento de codigo:

export default class AlmacenNotasSequlz extends AlmacenNotasAbs {

async cerrar() {
cerrarSequlz();
sequelizar = undefined;
}
}
Anuncios

Esta sera la clase que usaremos para crear las notas mediante esta forma, como siempre usaremos default para que sea devuelto por la fabrica en notas-almacen.mjs y la hacemos heredera de AlmacenNotasAbs, nuestra primera funcion sera para cerrar la conexion, para ello primero llamaremos la funcion para esto que importamos desde sequelizar y por ultimo al objeto lo establecimos como undefined, a esta clase vamos a agregar la siguiente funcion:

        async update(clave, titulo, cuerpo) {
await conectarDB();
const nota = await SQNota.findOne({ where: {clave: clave}});
if (!nota) {
throw new Error(`Nota no encontrada para ${clave}`);
}
await SQNota.update({
titulo: titulo,
cuerpo: cuerpo },
{ where: { clave: clave }});
return this.read(clave);
}
Anuncios
Anuncios

Esta sera la funcion encargada de actualizar/modificar los datos de nuestra tabla, para ello primero nos conectaremos luego definiremos el objeto que contendra la nota y para ello usaremos de la clase SQNota al metodo findOne donde le pasaremos como parametro la propiedad where y la clave para realizar la busqueda, esto basicamente nos devolvera una linea con todos los datos coincidentes, si vamos al post anterior esto equivaldria a usar el metodo get y el siguiente query:

SELECT * from notas where clave='clave a buscar';
Anuncios
Anuncios

En lugar de pasar el query lo usamos directamente mediante una funcion, en todo caso nos devolvera un valor, pero despues tendremos un condicional para verificar si este objeto no posee ningun valor y en caso de ser verdadero procede a lanzar un error informando que no se encontro ninguna nota con esta clave, en caso de no cumplirse procede a usar el metodo update donde pasaremos los datos de titulo y cuerpo para modificar y mediante el where y la clave estableceremos cual debe actualizarse, al igual que en el caso anterior se reemplazar el query con este metodo, y por ultimo devolveremos el resultado de usar a la funcion read que veremos en un momento, con esto comentado agreguemos la siguiente funcion a la clase:

        async create(clave, titulo, cuerpo) {
await conectarDB();
const sqnota = await SQNota.create({
clave: clave,
titulo: titulo,
cuerpo: cuerpo });
return new Nota(sqnota.clave, sqnota.titulo, sqnota.cuerpo);
}
Anuncios

Esta es mas simple y sera para crear la nota, primero nos conectaremos para luego crear un objeto donde aplicaremos el metodo create de SQNota y pasaremos los tres valores recibidos, una vez hecho esto crearemos la nota y a este le pasaremos los valores que agregamos anteriormente, por esta razon pasamos el objeto y la propiedad de cada uno y no el argumento directo, agreguemos la siguiente funcion a la clase:

        async read(clave) {
await conectarDB();
const nota = await SQNota.findOne({ where: {clave: clave}});
if (!nota) {
throw new Error(`Nota no encontrada para ${clave}`);
}
return new Nota(nota.clave, nota.titulo, nota.cuerpo);
}
Anuncios

Este es una mezcla de los dos anteriores porque volvemos a usar la busqueda de la nota como la funcion update y el mismo condicional por si no existe y al final devolveremos un objeto de tipo Nota que sera la nota en si con los valores obtenidos de la base, agreguemos la siguiente funcion a la clase:

        async delete(clave) {
await conectarDB();
await SQNota.destroy({ where: { clave: clave }});
}
Anuncios
Anuncios

Esta se encargara de eliminar los datos de la clave que le pasemos y para ello usa al metodo destroy y como parametro de busqueda le pasamos el where y la clave, como podran ver hasta ahora el trabajar de esta forma nos elimino la necesidad de tener que generar el query correspondiente para realizar las tareas que necesitemos y lo hacemos directamente mediante metodos, con esto comentado agreguemos la siguiente funcion:

        async listarClaves() {
await conectarDB();
const notas = await SQNota.findAll({
attributes: [ 'clave' ] });
const claves = notas.map(nota => nota.clave);
return claves;
}
Anuncios
Anuncios

Esta se encargara de listar todas las claves de nuestra tabla, la primera curiosidad es que usamos a findAll dado que este nos devolvera todas las lineas con el parametro de busqueda que establezcamos, en este caso le pasamos que tome el atributo clave, despues mediante un map sobre el objeto anterior definiremos uno nuevo llamado claves y en este guardaremos todas las claves que obtuvimos anteriormente, por ultimo devolveremos este objeto, pasemos a agregar la ultima funcion:

        async contar() {
await conectarDB();
const contar = await SQNota.count();
return contar;
}
Anuncios

Esta contara todas las notas almacenadas en la tabla, para este usaremos el metodo count que equivales a hacer el siguiente query:

SELECT count(clave) FROM notas;
Anuncios

Y simplemente lo devolveremos, con esto ya tenemos la clase que se encargara de manejar nuestra notas tal como vimos anteriormente en otros posts, nuestro ultimo paso sera ir a la seccion de scripts en package.json y agregar la siguiente linea:

"sequelize-start": "cross-env SEQUELIZE_CONNECT=models/sequelizar-sqlite.yaml MODELO_NOTAS=sequelizar node ./app.mjs"
Anuncios

Con esto podremos iniciar a nuestra aplicacion mediante ORM, observen que pasamos el yaml para que tome la configuracion de conexion y luego el modelo de notas, si lo prueban deberia funcionar de la misma manera como vimos anteriormente y como en los ultimos casos a diferencia de los comienzos las notas no se perderan cada vez que reiniciemos la aplicacion, antes de finalizar mencionemos algunos temas de trabajar de esta forma.

Anuncios

Cuando creamos el archivo sequelizar.mjs lo pensamos para que se conecte a cualquier tipo de base de datos ya que la configuracion la estamos estableciendo en el archivo yaml, vamos a suponer que necesitamos conectarnos a mysql en lugar de sqlite, para ello debemos modificar el archivo de la siguiente manera:

dbname: notas
username: usuario_de_conexion
password: password_de_conexion
params:
host: localhost
port: 3306
dialect: mysql
Anuncios
Anuncios

Observen como ahora si debimos pasar un usuario y contraseña de conexion y luego los parametros de conexion como la direccion y el puerto, asi como tambien dialect para indicarle cual es el protocolo de comunicacion que debe utilizar, como podemos observar de una manera muy simple cambiamos la forma de trabajar dado que no tocamos nada del codigo original, a su vez podemos tener varios archivos donde cada uno tendra su conexion y podremos pasar de uno a otro solamente modificando el archivo, y recuerden que tambien tenemos la opcion de pasar variables de entorno para los distintos datos sin necesidad de generar un archivo, con esto damos por finalizado el tema de hoy y les dejo un link con todos los archivos del proyecto y los trabajado en este post:

Anuncios

En resumen, hoy hemos visto como usar la tecnica ORM en nuestra aplicacion notas, hemos hecho las modificaciones pertinentes para conectarnos a una base sqlite3 mediante sequelize y hemos implementado yaml para poder acceder a archivos de este estilo, y en estos archivos poder tener varias configuraciones, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50